]> git.xonotic.org Git - xonotic/gmqcc.git/blobdiff - lexer.c
Allow typedefs to shadow defs of previous scopes
[xonotic/gmqcc.git] / lexer.c
diff --git a/lexer.c b/lexer.c
index 40756c0a4e3d0c93a7f2822ebfa2aa83df1c7b81..d39a0e5633a1a0392cfebdb00ec9e72de9052387 100644 (file)
--- a/lexer.c
+++ b/lexer.c
@@ -1,3 +1,25 @@
+/*
+ * Copyright (C) 2012
+ *     Wolfgang Bumiller
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include "gmqcc.h"
 #include "lexer.h"
 
+/*
+ * List of Keywords
+ */
+
+/* original */
+static const char *keywords_qc[] = {
+    "for", "do", "while",
+    "if", "else",
+    "local",
+    "return",
+    "const"
+};
+static size_t num_keywords_qc = sizeof(keywords_qc) / sizeof(keywords_qc[0]);
+
+/* For fte/gmgqcc */
+static const char *keywords_fg[] = {
+    "switch", "case", "default",
+    "struct", "union",
+    "break", "continue",
+    "typedef"
+};
+static size_t num_keywords_fg = sizeof(keywords_fg) / sizeof(keywords_fg[0]);
+
+/*
+ * Lexer code
+ */
+
 char* *lex_filenames;
 
 void lexerror(lex_file *lex, const char *fmt, ...)
 {
-       va_list ap;
+    va_list ap;
 
-       va_start(ap, fmt);
-       if (lex)
+    va_start(ap, fmt);
+    if (lex)
         con_vprintmsg(LVL_ERROR, lex->name, lex->sline, "parse error", fmt, ap);
     else
         con_vprintmsg(LVL_ERROR, "", 0, "parse error", fmt, ap);
-       va_end(ap);
+    va_end(ap);
 }
 
 bool lexwarn(lex_file *lex, int warntype, const char *fmt, ...)
 {
-       va_list ap;
-       int lvl = LVL_WARNING;
+    va_list ap;
+    int lvl = LVL_WARNING;
 
     if (!OPTS_WARN(warntype))
         return false;
 
     if (opts_werror)
-           lvl = LVL_ERROR;
+        lvl = LVL_ERROR;
 
-       va_start(ap, fmt);
+    va_start(ap, fmt);
     con_vprintmsg(lvl, lex->name, lex->sline, "warning", fmt, ap);
-       va_end(ap);
+    va_end(ap);
 
-       return opts_werror;
+    return opts_werror;
 }
 
 
@@ -405,16 +454,24 @@ static bool lex_try_pragma(lex_file *lex)
         if (!strcmp(param, "line")) {
             if (lex->push_line)
                 lex->push_line--;
+            --line;
         }
         else
             goto unroll;
     }
+    else if (!strcmp(command, "file")) {
+        lex->name = util_strdup(param);
+        vec_push(lex_filenames, lex->name);
+    }
+    else if (!strcmp(command, "line")) {
+        line = strtol(param, NULL, 0)-1;
+    }
     else
         goto unroll;
 
-    while (ch != '\n')
-        ch = lex_getch(lex);
     lex->line = line;
+    while (ch != '\n' && ch != EOF)
+        ch = lex_getch(lex);
     return true;
 
 unroll:
@@ -490,10 +547,8 @@ static int lex_skipwhite(lex_file *lex)
         ch = lex_getch(lex);
         while (ch != EOF && isspace(ch)) {
             if (ch == '\n') {
-                if (lex_try_pragma(lex)) {
-                    ch = lex_getch(lex);
+                if (lex_try_pragma(lex))
                     continue;
-                }
             }
             if (lex->flags.preprocessing) {
                 if (ch == '\n') {
@@ -571,9 +626,13 @@ static int lex_skipwhite(lex_file *lex)
                             }
                             break;
                         }
+                        lex_ungetch(lex, ch);
                     }
                     if (lex->flags.preprocessing) {
-                        lex_tokench(lex, ' '); /* ch); */
+                        if (ch == '\n')
+                            lex_tokench(lex, '\n');
+                        else
+                            lex_tokench(lex, ' '); /* ch); */
                     }
                 }
                 ch = ' '; /* cause TRUE in the isspace check */
@@ -801,7 +860,7 @@ static int GMQCC_WARN lex_finish_digit(lex_file *lex, int lastch)
 
 int lex_do(lex_file *lex)
 {
-    int ch, nextch;
+    int ch, nextch, thirdch;
 
     lex_token_new(lex);
 #if 0
@@ -947,9 +1006,9 @@ int lex_do(lex_file *lex)
 
         if (!strcmp(v, "flush"))
         {
-            size_t frame;
-            for (frame = 0; frame < vec_size(lex->frames); ++frame)
-                mem_d(lex->frames[frame].name);
+            size_t fi;
+            for (fi = 0; fi < vec_size(lex->frames); ++fi)
+                mem_d(lex->frames[fi].name);
             vec_free(lex->frames);
             /* skip line (fteqcc does it too) */
             ch = lex_getch(lex);
@@ -988,6 +1047,8 @@ int lex_do(lex_file *lex)
     {
         case '[':
         case '(':
+        case ':':
+        case '?':
             lex_tokench(lex, ch);
             lex_endtoken(lex);
             if (lex->flags.noops)
@@ -996,7 +1057,6 @@ int lex_do(lex_file *lex)
                 return (lex->tok.ttype = TOKEN_OPERATOR);
         case ')':
         case ';':
-        case ':':
         case '{':
         case '}':
         case ']':
@@ -1080,6 +1140,16 @@ int lex_do(lex_file *lex)
             lex_tokench(lex, nextch);
         } else if (ch == '-' && nextch == '>') {
             lex_tokench(lex, nextch);
+        } else if (ch == '&' && nextch == '~') {
+            thirdch = lex_getch(lex);
+            if (thirdch != '=') {
+                lex_ungetch(lex, thirdch);
+                lex_ungetch(lex, nextch);
+            }
+            else {
+                lex_tokench(lex, nextch);
+                lex_tokench(lex, thirdch);
+            }
         } else
             lex_ungetch(lex, nextch);
 
@@ -1141,29 +1211,17 @@ int lex_do(lex_file *lex)
         } else if (!strcmp(v, "vector")) {
             lex->tok.ttype = TOKEN_TYPENAME;
             lex->tok.constval.t = TYPE_VECTOR;
-        } else if (!strcmp(v, "for")  ||
-                 !strcmp(v, "while")  ||
-                 !strcmp(v, "do")     ||
-                 !strcmp(v, "if")     ||
-                 !strcmp(v, "else")   ||
-                 !strcmp(v, "local")  ||
-                 !strcmp(v, "return") ||
-                 !strcmp(v, "not")    ||
-                 !strcmp(v, "const"))
-        {
-            lex->tok.ttype = TOKEN_KEYWORD;
-        }
-        else if (opts_standard != COMPILER_QCC)
-        {
-            /* other standards reserve these keywords */
-            if (!strcmp(v, "switch") ||
-                !strcmp(v, "struct") ||
-                !strcmp(v, "union")  ||
-                !strcmp(v, "break")  ||
-                !strcmp(v, "continue") ||
-                !strcmp(v, "var"))
-            {
-                lex->tok.ttype = TOKEN_KEYWORD;
+        } else {
+            size_t kw;
+            for (kw = 0; kw < num_keywords_qc; ++kw) {
+                if (!strcmp(v, keywords_qc[kw]))
+                    return (lex->tok.ttype = TOKEN_KEYWORD);
+            }
+            if (opts_standard != COMPILER_QCC) {
+                for (kw = 0; kw < num_keywords_fg; ++kw) {
+                    if (!strcmp(v, keywords_fg[kw]))
+                        return (lex->tok.ttype = TOKEN_KEYWORD);
+                }
             }
         }