]> git.xonotic.org Git - xonotic/gmqcc.git/blobdiff - lexer.c
-Wframe-macros, warn about duplicate frame macro definitions, on by default
[xonotic/gmqcc.git] / lexer.c
diff --git a/lexer.c b/lexer.c
index d9483d806e9f2afe1538a9916a77881fc393d4ec..3d217abe3eb574cb252475d3e43fe0f71be1a041 100644 (file)
--- a/lexer.c
+++ b/lexer.c
@@ -27,12 +27,12 @@ void lexerror(lex_file *lex, const char *fmt, ...)
     printf("\n");
 }
 
-void lexwarn(lex_file *lex, int warn, const char *fmt, ...)
+bool lexwarn(lex_file *lex, int warn, const char *fmt, ...)
 {
     va_list ap;
 
     if (!OPTS_WARN(warn))
-        return;
+        return false;
 
     if (lex)
         printf("warning %s:%lu: ", lex->name, (unsigned long)lex->sline);
@@ -44,6 +44,8 @@ void lexwarn(lex_file *lex, int warn, const char *fmt, ...)
     va_end(ap);
 
     printf("\n");
+
+    return opts_werror;
 }
 
 token* token_new()
@@ -146,6 +148,7 @@ lex_file* lex_open(const char *file)
     lex->line = 1; /* we start counting at 1 */
 
     lex->peekpos = 0;
+    lex->eof = false;
 
     lex_filenames_add(lex->name);
 
@@ -397,7 +400,8 @@ static int lex_parse_frame(lex_file *lex)
 static bool lex_finish_frames(lex_file *lex)
 {
     do {
-        int rc;
+        size_t i;
+        int    rc;
         frame_macro m;
 
         rc = lex_parse_frame(lex);
@@ -406,6 +410,15 @@ static bool lex_finish_frames(lex_file *lex)
         if (rc < 0) /* error */
             return false;
 
+        for (i = 0; i < lex->frames_count; ++i) {
+            if (!strcmp(lex->tok->value, lex->frames[i].name)) {
+                lex->frames[i].value = lex->framevalue++;
+                if (lexwarn(lex, WARN_FRAME_MACROS, "duplicate frame macro defined: `%s`", lex->tok->value))
+                    return false;
+                continue;
+            }
+        }
+
         m.value = lex->framevalue++;
         m.name = lex->tok->value;
         lex->tok->value = NULL;
@@ -557,8 +570,13 @@ int lex_do(lex_file *lex)
     lex->tok->ctx.line = lex->sline;
     lex->tok->ctx.file = lex->name;
 
-    if (ch == EOF)
+    if (lex->eof)
+        return (lex->tok->ttype = TOKEN_FATAL);
+
+    if (ch == EOF) {
+        lex->eof = true;
         return (lex->tok->ttype = TOKEN_EOF);
+    }
 
     /* modelgen / spiritgen commands */
     if (ch == '$') {
@@ -768,7 +786,6 @@ int lex_do(lex_file *lex)
             case '^':
             case '~':
             case ',':
-            case '.':
             case '!':
                 if (!lex_tokench(lex, ch) ||
                     !lex_endtoken(lex))
@@ -779,6 +796,37 @@ int lex_do(lex_file *lex)
             default:
                 break;
         }
+
+        if (ch == '.')
+        {
+            if (!lex_tokench(lex, ch))
+                return (lex->tok->ttype = TOKEN_FATAL);
+            /* peak ahead once */
+            nextch = lex_getch(lex);
+            if (nextch != '.') {
+                lex_ungetch(lex, nextch);
+                if (!lex_endtoken(lex))
+                    return (lex->tok->ttype = TOKEN_FATAL);
+                return (lex->tok->ttype = ch);
+            }
+            /* peak ahead again */
+            nextch = lex_getch(lex);
+            if (nextch != '.') {
+                lex_ungetch(lex, nextch);
+                lex_ungetch(lex, nextch);
+                if (!lex_endtoken(lex))
+                    return (lex->tok->ttype = TOKEN_FATAL);
+                return (lex->tok->ttype = ch);
+            }
+            /* fill the token to be "..." */
+            if (!lex_tokench(lex, ch) ||
+                !lex_tokench(lex, ch) ||
+                !lex_endtoken(lex))
+            {
+                return (lex->tok->ttype = TOKEN_FATAL);
+            }
+            return (lex->tok->ttype = TOKEN_DOTS);
+        }
     }
 
     if (ch == ',' || ch == '.') {