]> git.xonotic.org Git - xonotic/gmqcc.git/blobdiff - lexer.c
Update doc/specification.tex
[xonotic/gmqcc.git] / lexer.c
diff --git a/lexer.c b/lexer.c
index a2e69d5f17f1c5bce8fb555cfebfeaa77539f928..42b21a1a6cd7de46bd45aa21b227cc412a4fbdec 100644 (file)
--- a/lexer.c
+++ b/lexer.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012
+ * Copyright (C) 2012, 2013
  *     Wolfgang Bumiller
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy of
@@ -291,12 +291,16 @@ static int lex_try_trigraph(lex_file *lex, int old)
 {
     int c2, c3;
     c2 = lex_fgetc(lex);
+    if (!lex->push_line && c2 == '\n')
+        lex->line++;
     if (c2 != '?') {
         lex_ungetch(lex, c2);
         return old;
     }
 
     c3 = lex_fgetc(lex);
+    if (!lex->push_line && c3 == '\n')
+        lex->line++;
     switch (c3) {
         case '=': return '#';
         case '/': return '\\';
@@ -485,7 +489,7 @@ unroll:
     if (command) {
         vec_pop(command);
         while (vec_size(command)) {
-            lex_ungetch(lex, vec_last(command));
+            lex_ungetch(lex, (unsigned char)vec_last(command));
             vec_pop(command);
         }
         vec_free(command);
@@ -494,7 +498,7 @@ unroll:
     if (command) {
         vec_pop(command);
         while (vec_size(command)) {
-            lex_ungetch(lex, vec_last(command));
+            lex_ungetch(lex, (unsigned char)vec_last(command));
             vec_pop(command);
         }
         vec_free(command);
@@ -503,7 +507,7 @@ unroll:
     if (pragma) {
         vec_pop(pragma);
         while (vec_size(pragma)) {
-            lex_ungetch(lex, vec_last(pragma));
+            lex_ungetch(lex, (unsigned char)vec_last(pragma));
             vec_pop(pragma);
         }
         vec_free(pragma);
@@ -736,10 +740,13 @@ static bool lex_finish_frames(lex_file *lex)
         vec_shrinkto(lex->tok.value, 0);
         vec_push(lex->frames, m);
     } while (true);
+
+    return false;
 }
 
 static int GMQCC_WARN lex_finish_string(lex_file *lex, int quote)
 {
+    uchar_t chr;
     int ch = 0;
     int nextch;
     bool hex;
@@ -825,7 +832,7 @@ static int GMQCC_WARN lex_finish_string(lex_file *lex, int quote)
             case '[':  ch = 16; break;
             case ']':  ch = 17; break;
             case '{':
-                ch = 0;
+                chr = 0;
                 nextch = lex_getch(lex);
                 hex = (nextch == 'x');
                 if (!hex)
@@ -833,32 +840,31 @@ static int GMQCC_WARN lex_finish_string(lex_file *lex, int quote)
                 for (nextch = lex_getch(lex); nextch != '}'; nextch = lex_getch(lex)) {
                     if (!hex) {
                         if (nextch >= '0' && nextch <= '9')
-                            ch = ch * 10 + nextch - '0';
+                            chr = chr * 10 + nextch - '0';
                         else {
                             lexerror(lex, "bad character code");
                             return (lex->tok.ttype = TOKEN_ERROR);
                         }
                     } else {
-                        if (nextch >= '0' || nextch <= '9')
-                            ch = ch * 16 + nextch - '0';
+                        if (nextch >= '0' && nextch <= '9')
+                            chr = chr * 0x10 + nextch - '0';
                         else if (nextch >= 'a' && nextch <= 'f')
-                            ch = ch * 16 + nextch - 'a' + 10;
+                            chr = chr * 0x10 + nextch - 'a' + 10;
                         else if (nextch >= 'A' && nextch <= 'F')
-                            ch = ch * 16 + nextch - 'A' + 10;
+                            chr = chr * 0x10 + nextch - 'A' + 10;
                         else {
                             lexerror(lex, "bad character code");
                             return (lex->tok.ttype = TOKEN_ERROR);
                         }
                     }
-                    if ( (!OPTS_FLAG(UTF8) && ch > 255) ||
-                         ( OPTS_FLAG(UTF8) && ch > 0x10FFFF) )
+                    if (chr > 0x10FFFF || (!OPTS_FLAG(UTF8) && chr > 255))
                     {
                         lexerror(lex, "character code out of range");
                         return (lex->tok.ttype = TOKEN_ERROR);
                     }
                 }
-                if (OPTS_FLAG(UTF8) && ch >= 128) {
-                    u8len = u8_fromchar((uchar_t)ch, u8buf, sizeof(u8buf));
+                if (OPTS_FLAG(UTF8) && chr >= 128) {
+                    u8len = u8_fromchar(chr, u8buf, sizeof(u8buf));
                     if (!u8len)
                         ch = 0;
                     else {
@@ -871,6 +877,8 @@ static int GMQCC_WARN lex_finish_string(lex_file *lex, int quote)
                         ch = u8buf[uc];
                     }
                 }
+                else
+                    ch = chr;
                 break;
             case '\n':  ch = '\n'; break;
 
@@ -1240,31 +1248,37 @@ int lex_do(lex_file *lex)
             default:
                 break;
         }
+    }
 
-        if (ch == '.')
-        {
-            lex_tokench(lex, ch);
-            /* peak ahead once */
-            nextch = lex_getch(lex);
-            if (nextch != '.') {
-                lex_ungetch(lex, nextch);
-                lex_endtoken(lex);
-                return (lex->tok.ttype = ch);
-            }
-            /* peak ahead again */
-            nextch = lex_getch(lex);
-            if (nextch != '.') {
-                lex_ungetch(lex, nextch);
-                lex_ungetch(lex, '.');
-                lex_endtoken(lex);
+    if (ch == '.')
+    {
+        lex_tokench(lex, ch);
+        /* peak ahead once */
+        nextch = lex_getch(lex);
+        if (nextch != '.') {
+            lex_ungetch(lex, nextch);
+            lex_endtoken(lex);
+            if (lex->flags.noops)
                 return (lex->tok.ttype = ch);
-            }
-            /* fill the token to be "..." */
-            lex_tokench(lex, ch);
-            lex_tokench(lex, ch);
+            else
+                return (lex->tok.ttype = TOKEN_OPERATOR);
+        }
+        /* peak ahead again */
+        nextch = lex_getch(lex);
+        if (nextch != '.') {
+            lex_ungetch(lex, nextch);
+            lex_ungetch(lex, '.');
             lex_endtoken(lex);
-            return (lex->tok.ttype = TOKEN_DOTS);
+            if (lex->flags.noops)
+                return (lex->tok.ttype = ch);
+            else
+                return (lex->tok.ttype = TOKEN_OPERATOR);
         }
+        /* fill the token to be "..." */
+        lex_tokench(lex, ch);
+        lex_tokench(lex, ch);
+        lex_endtoken(lex);
+        return (lex->tok.ttype = TOKEN_DOTS);
     }
 
     if (ch == ',' || ch == '.') {
@@ -1274,10 +1288,11 @@ int lex_do(lex_file *lex)
     }
 
     if (ch == '+' || ch == '-' || /* ++, --, +=, -=  and -> as well! */
-        ch == '>' || ch == '<' || /* <<, >>, <=, >= */
-        ch == '=' || ch == '!' || /* ==, != */
-        ch == '&' || ch == '|')   /* &&, ||, &=, |= */
-    {
+        ch == '>' || ch == '<' || /* <<, >>, <=, >=                  */
+        ch == '=' || ch == '!' || /* ==, !=                          */
+        ch == '&' || ch == '|' || /* &&, ||, &=, |=                  */
+        ch == '~'                 /* ~=, ~                           */
+    )  {
         lex_tokench(lex, ch);
 
         nextch = lex_getch(lex);
@@ -1295,6 +1310,17 @@ int lex_do(lex_file *lex)
                 lex_tokench(lex, nextch);
                 lex_tokench(lex, thirdch);
             }
+        }
+        else if (lex->flags.preprocessing &&
+                 ch == '-' && isdigit(nextch))
+        {
+            lex->tok.ttype = lex_finish_digit(lex, nextch);
+            if (lex->tok.ttype == TOKEN_INTCONST)
+                lex->tok.constval.i = -lex->tok.constval.i;
+            else
+                lex->tok.constval.f = -lex->tok.constval.f;
+            lex_endtoken(lex);
+            return lex->tok.ttype;
         } else
             lex_ungetch(lex, nextch);
 
@@ -1362,7 +1388,7 @@ int lex_do(lex_file *lex)
                 if (!strcmp(v, keywords_qc[kw]))
                     return (lex->tok.ttype = TOKEN_KEYWORD);
             }
-            if (opts.standard != COMPILER_QCC) {
+            if (OPTS_OPTION_U32(OPTION_STANDARD) != COMPILER_QCC) {
                 for (kw = 0; kw < num_keywords_fg; ++kw) {
                     if (!strcmp(v, keywords_fg[kw]))
                         return (lex->tok.ttype = TOKEN_KEYWORD);
@@ -1459,6 +1485,6 @@ int lex_do(lex_file *lex)
         return (lex->tok.ttype = ch);
     }
 
-    lexerror(lex, "unknown token");
+    lexerror(lex, "unknown token: `%s`", lex->tok.value);
     return (lex->tok.ttype = TOKEN_ERROR);
 }