]> git.xonotic.org Git - xonotic/gmqcc.git/blobdiff - lexer.c
Ignore modelgen commands with lex->flags.preprocessing
[xonotic/gmqcc.git] / lexer.c
diff --git a/lexer.c b/lexer.c
index 175d158023dfe47c7a482723af5fbca0b34c1947..5c9b7ee6d145077acf25c24730a5e253be3631bd 100644 (file)
--- a/lexer.c
+++ b/lexer.c
@@ -47,7 +47,10 @@ static const char *keywords_fg[] = {
     "switch", "case", "default",
     "struct", "union",
     "break", "continue",
-    "typedef"
+    "typedef",
+    "goto",
+
+    "__builtin_debug_printtype"
 };
 static size_t num_keywords_fg = sizeof(keywords_fg) / sizeof(keywords_fg[0]);
 
@@ -318,6 +321,11 @@ static int lex_try_digraph(lex_file *lex, int ch)
 {
     int c2;
     c2 = lex_fgetc(lex);
+    /* we just used fgetc() so count lines
+     * need to offset a \n the ungetch would recognize
+     */
+    if (!lex->push_line && c2 == '\n')
+        lex->line++;
     if      (ch == '<' && c2 == ':')
         return '[';
     else if (ch == ':' && c2 == '>')
@@ -445,7 +453,8 @@ static bool lex_try_pragma(lex_file *lex)
     if (!strcmp(command, "push")) {
         if (!strcmp(param, "line")) {
             lex->push_line++;
-            --line;
+            if (lex->push_line == 1)
+                --line;
         }
         else
             goto unroll;
@@ -454,7 +463,8 @@ static bool lex_try_pragma(lex_file *lex)
         if (!strcmp(param, "line")) {
             if (lex->push_line)
                 lex->push_line--;
-            --line;
+            if (lex->push_line == 0)
+                --line;
         }
         else
             goto unroll;
@@ -732,6 +742,7 @@ static bool lex_finish_frames(lex_file *lex)
 static int GMQCC_WARN lex_finish_string(lex_file *lex, int quote)
 {
     int ch = 0;
+    int nextch;
 
     while (ch != EOF)
     {
@@ -768,6 +779,61 @@ static int GMQCC_WARN lex_finish_string(lex_file *lex, int quote)
             case 't':  ch = '\t'; break;
             case 'f':  ch = '\f'; break;
             case 'v':  ch = '\v'; break;
+            case 'x':
+            case 'X':
+                /* same procedure as in fteqcc */
+                ch = 0;
+                nextch = lex_getch(lex);
+                if      (nextch >= '0' && nextch <= '9')
+                    ch += nextch - '0';
+                else if (nextch >= 'a' && nextch <= 'f')
+                    ch += nextch - 'a' + 10;
+                else if (nextch >= 'A' && nextch <= 'F')
+                    ch += nextch - 'A' + 10;
+                else {
+                    lexerror(lex, "bad character code");
+                    lex_ungetch(lex, nextch);
+                    return (lex->tok.ttype = TOKEN_ERROR);
+                }
+
+                ch *= 0x10;
+                nextch = lex_getch(lex);
+                if      (nextch >= '0' && nextch <= '9')
+                    ch += nextch - '0';
+                else if (nextch >= 'a' && nextch <= 'f')
+                    ch += nextch - 'a' + 10;
+                else if (nextch >= 'A' && nextch <= 'F')
+                    ch += nextch - 'A' + 10;
+                else {
+                    lexerror(lex, "bad character code");
+                    lex_ungetch(lex, nextch);
+                    return (lex->tok.ttype = TOKEN_ERROR);
+                }
+                break;
+
+            /* fteqcc support */
+            case '0': case '1': case '2': case '3':
+            case '4': case '5': case '6': case '7':
+            case '8': case '9':
+                ch = 18 + ch - '0';
+                break;
+            case '<':  ch = 29; break;
+            case '-':  ch = 30; break;
+            case '>':  ch = 31; break;
+            case '[':  ch = 16; break;
+            case ']':  ch = 17; break;
+            case '{':
+                ch = 0;
+                for (nextch = lex_getch(lex); nextch != '}'; nextch = lex_getch(lex)) {
+                    ch = ch * 10 + nextch - '0';
+                    if (nextch < '0' || nextch > '9' || ch > 255) {
+                        lexerror(lex, "bad character code");
+                        return (lex->tok.ttype = TOKEN_ERROR);
+                    }
+                }
+                break;
+            case '\n':  ch = '\n'; break;
+
             default:
                 lexwarn(lex, WARN_UNKNOWN_CONTROL_SEQUENCE, "unrecognized control sequence: \\%c", ch);
                 /* so we just add the character plus backslash no matter what it actually is */
@@ -791,7 +857,10 @@ static int GMQCC_WARN lex_finish_digit(lex_file *lex, int lastch)
     int  ch = lastch;
 
     /* parse a number... */
-    lex->tok.ttype = TOKEN_INTCONST;
+    if (ch == '.')
+        lex->tok.ttype = TOKEN_FLOATCONST;
+    else
+        lex->tok.ttype = TOKEN_INTCONST;
 
     lex_tokench(lex, ch);
 
@@ -824,7 +893,7 @@ static int GMQCC_WARN lex_finish_digit(lex_file *lex, int lastch)
         }
     }
     /* NOT else, '.' can come from above as well */
-    if (ch == '.' && !ishex)
+    if (lex->tok.ttype != TOKEN_FLOATCONST && ch == '.' && !ishex)
     {
         /* Allow floating comma in non-hex mode */
         lex->tok.ttype = TOKEN_FLOATCONST;
@@ -900,7 +969,7 @@ int lex_do(lex_file *lex)
     }
 
     /* modelgen / spiritgen commands */
-    if (ch == '$') {
+    if (ch == '$' && !lex->flags.preprocessing) {
         const char *v;
         size_t frame;
 
@@ -1069,6 +1138,18 @@ int lex_do(lex_file *lex)
             break;
     }
 
+    if (ch == '.') {
+        nextch = lex_getch(lex);
+        /* digits starting with a dot */
+        if (isdigit(nextch)) {
+            lex_ungetch(lex, nextch);
+            lex->tok.ttype = lex_finish_digit(lex, ch);
+            lex_endtoken(lex);
+            return lex->tok.ttype;
+        }
+        lex_ungetch(lex, nextch);
+    }
+
     if (lex->flags.noops)
     {
         /* Detect characters early which are normally
@@ -1138,7 +1219,7 @@ int lex_do(lex_file *lex)
         lex_tokench(lex, ch);
 
         nextch = lex_getch(lex);
-        if (nextch == ch || nextch == '=') {
+        if (nextch == '=' || (nextch == ch && ch != '!')) {
             lex_tokench(lex, nextch);
         } else if (ch == '-' && nextch == '>') {
             lex_tokench(lex, nextch);
@@ -1268,6 +1349,7 @@ int lex_do(lex_file *lex)
             lex_tokench(lex, ch);
         lex_endtoken(lex);
 
+        lex->tok.ttype = TOKEN_CHARCONST;
          /* It's a vector if we can successfully scan 3 floats */
 #ifdef WIN32
         if (sscanf_s(lex->tok.value, " %f %f %f ",
@@ -1280,6 +1362,14 @@ int lex_do(lex_file *lex)
         {
              lex->tok.ttype = TOKEN_VECTORCONST;
         }
+        else
+        {
+            if (!lex->flags.preprocessing && strlen(lex->tok.value) > 1) {
+                if (lexwarn(lex, WARN_MULTIBYTE_CHARACTER, "multibyte character: `%s`", lex->tok.value))
+                    return (lex->tok.ttype = TOKEN_ERROR);
+            }
+            lex->tok.constval.i = lex->tok.value[0];
+        }
 
         return lex->tok.ttype;
     }
@@ -1291,6 +1381,12 @@ int lex_do(lex_file *lex)
         return lex->tok.ttype;
     }
 
+    if (lex->flags.preprocessing) {
+        lex_tokench(lex, ch);
+        lex_endtoken(lex);
+        return (lex->tok.ttype = ch);
+    }
+
     lexerror(lex, "unknown token");
     return (lex->tok.ttype = TOKEN_ERROR);
 }