]> git.rm.cloudns.org Git - xonotic/gmqcc.git/commitdiff
Classy Tokens
authorTimePath <andrew.hardaker1995@gmail.com>
Sat, 2 Sep 2017 12:38:52 +0000 (22:38 +1000)
committerTimePath <andrew.hardaker1995@gmail.com>
Sat, 2 Sep 2017 12:38:52 +0000 (22:38 +1000)
ftepp.cpp
gmqcc.h
lexer.cpp
lexer.h
opts.cpp
parser.cpp
parser.h

index 190978fe60045c4df46d0e20c94a9d870367881e..a85d857ee4160182827c07c81072b1fde7871d97 100644 (file)
--- a/ftepp.cpp
+++ b/ftepp.cpp
@@ -14,7 +14,7 @@ struct ppcondition {
 };
 
 struct pptoken {
-    int token;
+    Token token;
     char *value;
     /* a copy from the lexer */
     union {
@@ -37,7 +37,7 @@ struct ppmacro {
 
 struct ftepp_t {
     lex_file *lex;
-    int token;
+    Token token;
     unsigned int errors;
     bool output_on;
     ppcondition *conditions;
@@ -322,7 +322,7 @@ static GMQCC_INLINE void ftepp_macro_delete(ftepp_t *ftepp, const char *name)
     util_htrm(ftepp->macros, name, (void (*)(void*))&ppmacro_delete);
 }
 
-static GMQCC_INLINE int ftepp_next(ftepp_t *ftepp)
+static GMQCC_INLINE Token ftepp_next(ftepp_t *ftepp)
 {
     return (ftepp->token = lex_do(ftepp->lex));
 }
@@ -330,10 +330,10 @@ static GMQCC_INLINE int ftepp_next(ftepp_t *ftepp)
 /* Important: this does not skip newlines! */
 static bool ftepp_skipspace(ftepp_t *ftepp)
 {
-    if (ftepp->token != TOKEN_WHITE)
+    if (ftepp->token != Token::WHITE)
         return true;
-    while (ftepp_next(ftepp) == TOKEN_WHITE) {}
-    if (ftepp->token >= TOKEN_EOF) {
+    while (ftepp_next(ftepp) == Token::WHITE) {}
+    if (ftepp->token >= Token::END) {
         ftepp_error(ftepp, "unexpected end of preprocessor directive");
         return false;
     }
@@ -343,12 +343,12 @@ static bool ftepp_skipspace(ftepp_t *ftepp)
 /* this one skips EOLs as well */
 static bool ftepp_skipallwhite(ftepp_t *ftepp)
 {
-    if (ftepp->token != TOKEN_WHITE && ftepp->token != TOKEN_EOL)
+    if (ftepp->token != Token::WHITE && ftepp->token != Token::EOL)
         return true;
     do {
         ftepp_next(ftepp);
-    } while (ftepp->token == TOKEN_WHITE || ftepp->token == TOKEN_EOL);
-    if (ftepp->token >= TOKEN_EOF) {
+    } while (ftepp->token == Token::WHITE || ftepp->token == Token::EOL);
+    if (ftepp->token >= Token::END) {
         ftepp_error(ftepp, "unexpected end of preprocessor directive");
         return false;
     }
@@ -364,15 +364,15 @@ static bool ftepp_define_params(ftepp_t *ftepp, ppmacro *macro)
         ftepp_next(ftepp);
         if (!ftepp_skipspace(ftepp))
             return false;
-        if (ftepp->token == ')')
+        if (ftepp->token == Token::PAREN_CLOSE)
             break;
         switch (ftepp->token) {
-            case TOKEN_IDENT:
-            case TOKEN_TYPENAME:
-            case TOKEN_KEYWORD:
+            case Token::IDENT:
+            case Token::TYPENAME:
+            case Token::KEYWORD:
                 vec_push(macro->params, util_strdup(ftepp_tokval(ftepp)));
                 break;
-            case TOKEN_DOTS:
+            case Token::DOTS:
                 macro->variadic = true;
                 break;
             default:
@@ -382,13 +382,13 @@ static bool ftepp_define_params(ftepp_t *ftepp, ppmacro *macro)
         ftepp_next(ftepp);
         if (!ftepp_skipspace(ftepp))
             return false;
-        if (macro->variadic && ftepp->token != ')') {
+        if (macro->variadic && ftepp->token != Token::PAREN_CLOSE) {
             ftepp_error(ftepp, "cannot have parameters after the variadic parameters");
             return false;
         }
-    } while (ftepp->token == ',');
+    } while (ftepp->token == Token::COMMA);
 
-    if (ftepp->token != ')') {
+    if (ftepp->token != Token::PAREN_CLOSE) {
         ftepp_error(ftepp, "expected closing paren after macro parameter list");
         return false;
     }
@@ -400,25 +400,25 @@ static bool ftepp_define_params(ftepp_t *ftepp, ppmacro *macro)
 static bool ftepp_define_body(ftepp_t *ftepp, ppmacro *macro)
 {
     pptoken *ptok;
-    while (ftepp->token != TOKEN_EOL && ftepp->token < TOKEN_EOF) {
+    while (ftepp->token != Token::EOL && ftepp->token < Token::END) {
         bool   subscript = false;
         size_t index     = 0;
         if (macro->variadic && !strcmp(ftepp_tokval(ftepp), "__VA_ARGS__")) {
-            subscript = !!(ftepp_next(ftepp) == '#');
+            subscript = !!(ftepp_next(ftepp) == Token::HASH);
 
-            if (subscript && ftepp_next(ftepp) != '#') {
+            if (subscript && ftepp_next(ftepp) != Token::HASH) {
                 ftepp_error(ftepp, "expected `##` in __VA_ARGS__ for subscripting");
                 return false;
             } else if (subscript) {
-                if (ftepp_next(ftepp) == '[') {
-                    if (ftepp_next(ftepp) != TOKEN_INTCONST) {
+                if (ftepp_next(ftepp) == Token::BRACKET_OPEN) {
+                    if (ftepp_next(ftepp) != Token::INTCONST) {
                         ftepp_error(ftepp, "expected index for __VA_ARGS__ subscript");
                         return false;
                     }
 
                     index = (int)strtol(ftepp_tokval(ftepp), nullptr, 10);
 
-                    if (ftepp_next(ftepp) != ']') {
+                    if (ftepp_next(ftepp) != Token::BRACKET_CLOSE) {
                         ftepp_error(ftepp, "expected `]` in __VA_ARGS__ subscript");
                         return false;
                     }
@@ -427,7 +427,7 @@ static bool ftepp_define_body(ftepp_t *ftepp, ppmacro *macro)
                      * mark it as an array to be handled later as such and not
                      * as traditional __VA_ARGS__
                      */
-                    ftepp->token = TOKEN_VA_ARGS_ARRAY;
+                    ftepp->token = Token::VA_ARGS_ARRAY;
                     ptok = pptoken_make(ftepp);
                     ptok->constval.i = index;
                     vec_push(macro->output, ptok);
@@ -437,15 +437,15 @@ static bool ftepp_define_body(ftepp_t *ftepp, ppmacro *macro)
                     return false;
                 }
             } else {
-                int old = ftepp->token;
-                ftepp->token = TOKEN_VA_ARGS;
+                auto old = ftepp->token;
+                ftepp->token = Token::VA_ARGS;
                 ptok = pptoken_make(ftepp);
                 vec_push(macro->output, ptok);
                 ftepp->token = old;
             }
         }
         else if (macro->variadic && !strcmp(ftepp_tokval(ftepp), "__VA_COUNT__")) {
-            ftepp->token = TOKEN_VA_COUNT;
+            ftepp->token = Token::VA_COUNT;
             ptok         = pptoken_make(ftepp);
             vec_push(macro->output, ptok);
             ftepp_next(ftepp);
@@ -456,7 +456,7 @@ static bool ftepp_define_body(ftepp_t *ftepp, ppmacro *macro)
         }
     }
     /* recursive expansion can cause EOFs here */
-    if (ftepp->token != TOKEN_EOL && ftepp->token != TOKEN_EOF) {
+    if (ftepp->token != Token::EOL && ftepp->token != Token::END) {
         ftepp_error(ftepp, "unexpected junk after macro or unexpected end of file");
         return false;
     }
@@ -492,9 +492,9 @@ static bool ftepp_define(ftepp_t *ftepp)
         return false;
 
     switch (ftepp->token) {
-        case TOKEN_IDENT:
-        case TOKEN_TYPENAME:
-        case TOKEN_KEYWORD:
+        case Token::IDENT:
+        case Token::TYPENAME:
+        case Token::KEYWORD:
             if (OPTS_FLAG(FTEPP_MATHDEFS)) {
                 for (i = 0; i < GMQCC_ARRAY_COUNT(ftepp_math_constants); i++) {
                     if (!strcmp(ftepp_math_constants[i][0], ftepp_tokval(ftepp))) {
@@ -528,7 +528,7 @@ static bool ftepp_define(ftepp_t *ftepp)
 
     (void)ftepp_next(ftepp);
 
-    if (ftepp->token == '(') {
+    if (ftepp->token == Token::PAREN_OPEN) {
         macro->has_params = true;
         if (!ftepp_define_params(ftepp, macro)) {
             ppmacro_delete(macro);
@@ -588,34 +588,34 @@ static bool ftepp_macro_call_params(ftepp_t *ftepp, macroparam **out_params)
 
     if (!ftepp_skipallwhite(ftepp))
         return false;
-    while (ftepp->token != ')') {
+    while (ftepp->token != Token::PAREN_CLOSE) {
         mp.tokens = nullptr;
         if (!ftepp_skipallwhite(ftepp))
             return false;
-        while (parens || ftepp->token != ',') {
-            if (ftepp->token == '(')
+        while (parens || ftepp->token != Token::COMMA) {
+            if (ftepp->token == Token::PAREN_OPEN)
                 ++parens;
-            else if (ftepp->token == ')') {
+            else if (ftepp->token == Token::PAREN_CLOSE) {
                 if (!parens)
                     break;
                 --parens;
             }
             ptok = pptoken_make(ftepp);
             vec_push(mp.tokens, ptok);
-            if (ftepp_next(ftepp) >= TOKEN_EOF) {
+            if (ftepp_next(ftepp) >= Token::END) {
                 ftepp_error(ftepp, "unexpected end of file in macro call");
                 goto on_error;
             }
         }
         vec_push(params, mp);
         mp.tokens = nullptr;
-        if (ftepp->token == ')')
+        if (ftepp->token == Token::PAREN_CLOSE)
             break;
-        if (ftepp->token != ',') {
+        if (ftepp->token != Token::COMMA) {
             ftepp_error(ftepp, "expected closing paren or comma in macro call");
             goto on_error;
         }
-        if (ftepp_next(ftepp) >= TOKEN_EOF) {
+        if (ftepp_next(ftepp) >= Token::END) {
             ftepp_error(ftepp, "unexpected end of file in macro call");
             goto on_error;
         }
@@ -650,7 +650,7 @@ static void ftepp_stringify_token(ftepp_t *ftepp, pptoken *token)
     const char *ch;
     chs[1] = 0;
     switch (token->token) {
-        case TOKEN_STRINGCONST:
+        case Token::STRINGCONST:
             ch = token->value;
             while (*ch) {
                 /* in preprocessor mode strings already are string,
@@ -668,10 +668,10 @@ static void ftepp_stringify_token(ftepp_t *ftepp, pptoken *token)
                 ++ch;
             }
             break;
-        /*case TOKEN_WHITE:
+        /*case Token::WHITE:
             ftepp_out(ftepp, " ", false);
             break;*/
-        case TOKEN_EOL:
+        case Token::EOL:
             ftepp_out(ftepp, "\\n", false);
             break;
         default:
@@ -706,7 +706,7 @@ static void ftepp_param_out(ftepp_t *ftepp, macroparam *param)
     pptoken *out;
     for (i = 0; i < vec_size(param->tokens); ++i) {
         out = param->tokens[i];
-        if (out->token == TOKEN_EOL)
+        if (out->token == Token::EOL)
             ftepp_out(ftepp, "\n", false);
         else {
             ppmacro *find = ftepp_macro_find(ftepp, out->value);
@@ -736,7 +736,7 @@ static bool ftepp_macro_expand(ftepp_t *ftepp, ppmacro *macro, macroparam *param
     bool      old_inmacro;
     bool      strip = false;
 
-    int nextok;
+    Token nextok;
 
     if (vararg_start < vec_size(params))
         varargs = vec_size(params) - vararg_start;
@@ -751,9 +751,9 @@ static bool ftepp_macro_expand(ftepp_t *ftepp, ppmacro *macro, macroparam *param
     for (o = 0; o < vec_size(macro->output); ++o) {
         pptoken *out = macro->output[o];
         switch (out->token) {
-            case TOKEN_VA_ARGS:
+            case Token::VA_ARGS:
                 if (!macro->variadic) {
-                    ftepp_error(ftepp, "internal preprocessor error: TOKEN_VA_ARGS in non-variadic macro");
+                    ftepp_error(ftepp, "internal preprocessor error: Token::VA_ARGS in non-variadic macro");
                     vec_free(old_string);
                     return false;
                 }
@@ -768,7 +768,7 @@ static bool ftepp_macro_expand(ftepp_t *ftepp, ppmacro *macro, macroparam *param
                 }
                 break;
 
-            case TOKEN_VA_ARGS_ARRAY:
+            case Token::VA_ARGS_ARRAY:
                 if ((size_t)out->constval.i >= varargs) {
                     ftepp_error(ftepp, "subscript of `[%u]` is out of bounds for `__VA_ARGS__`", out->constval.i);
                     vec_free(old_string);
@@ -778,33 +778,33 @@ static bool ftepp_macro_expand(ftepp_t *ftepp, ppmacro *macro, macroparam *param
                 ftepp_param_out(ftepp, &params[out->constval.i + vararg_start]);
                 break;
 
-            case TOKEN_VA_COUNT:
+            case Token::VA_COUNT:
                 util_asprintf(&buffer, "%d", varargs);
                 ftepp_out(ftepp, buffer, false);
                 mem_d(buffer);
                 break;
 
-            case TOKEN_IDENT:
-            case TOKEN_TYPENAME:
-            case TOKEN_KEYWORD:
+            case Token::IDENT:
+            case Token::TYPENAME:
+            case Token::KEYWORD:
                 if (!macro_params_find(macro, out->value, &pi)) {
                     ftepp_out(ftepp, out->value, false);
                     break;
                 } else
                     ftepp_param_out(ftepp, &params[pi]);
                 break;
-            case '#':
+            case Token::HASH:
                 if (o + 1 < vec_size(macro->output)) {
                     nextok = macro->output[o+1]->token;
-                    if (nextok == '#') {
+                    if (nextok == Token::HASH) {
                         /* raw concatenation */
                         ++o;
                         strip = true;
                         break;
                     }
-                    if ( (nextok == TOKEN_IDENT    ||
-                          nextok == TOKEN_KEYWORD  ||
-                          nextok == TOKEN_TYPENAME) &&
+                    if ( (nextok == Token::IDENT    ||
+                          nextok == Token::KEYWORD  ||
+                          nextok == Token::TYPENAME) &&
                         macro_params_find(macro, macro->output[o+1]->value, &pi))
                     {
                         ++o;
@@ -815,13 +815,13 @@ static bool ftepp_macro_expand(ftepp_t *ftepp, ppmacro *macro, macroparam *param
                 }
                 ftepp_out(ftepp, "#", false);
                 break;
-            case TOKEN_EOL:
+            case Token::EOL:
                 ftepp_out(ftepp, "\n", false);
                 break;
             default:
                 buffer = out->value;
                 #define buffer_stripable(X) ((X) == ' ' || (X) == '\t')
-                if (vec_size(macro->output) > o + 1 && macro->output[o+1]->token == '#' && buffer_stripable(*buffer))
+                if (vec_size(macro->output) > o + 1 && macro->output[o+1]->token == Token::HASH && buffer_stripable(*buffer))
                     buffer++;
                 if (strip) {
                     while (buffer_stripable(*buffer)) buffer++;
@@ -907,7 +907,7 @@ static bool ftepp_macro_call(ftepp_t *ftepp, ppmacro *macro)
     if (!ftepp_skipallwhite(ftepp))
         return false;
 
-    if (ftepp->token != '(') {
+    if (ftepp->token != Token::PAREN_OPEN) {
         ftepp_error(ftepp, "expected macro parameters in parenthesis");
         return false;
     }
@@ -974,14 +974,14 @@ static bool ftepp_if_value(ftepp_t *ftepp, bool *out, double *value_out)
     if (!ftepp_skipspace(ftepp))
         return false;
 
-    while (ftepp->token == '!') {
+    while (ftepp->token == Token::NOT) {
         wasnot = true;
         ftepp_next(ftepp);
         if (!ftepp_skipspace(ftepp))
             return false;
     }
 
-    if (ftepp->token == TOKEN_OPERATOR && !strcmp(ftepp_tokval(ftepp), "-"))
+    if (ftepp->token == Token::OPERATOR && !strcmp(ftepp_tokval(ftepp), "-"))
     {
         wasneg = true;
         ftepp_next(ftepp);
@@ -990,23 +990,23 @@ static bool ftepp_if_value(ftepp_t *ftepp, bool *out, double *value_out)
     }
 
     switch (ftepp->token) {
-        case TOKEN_IDENT:
-        case TOKEN_TYPENAME:
-        case TOKEN_KEYWORD:
+        case Token::IDENT:
+        case Token::TYPENAME:
+        case Token::KEYWORD:
             if (!strcmp(ftepp_tokval(ftepp), "defined")) {
                 ftepp_next(ftepp);
                 if (!ftepp_skipspace(ftepp))
                     return false;
-                if (ftepp->token != '(') {
+                if (ftepp->token != Token::PAREN_OPEN) {
                     ftepp_error(ftepp, "`defined` keyword in #if requires a macro name in parenthesis");
                     return false;
                 }
                 ftepp_next(ftepp);
                 if (!ftepp_skipspace(ftepp))
                     return false;
-                if (ftepp->token != TOKEN_IDENT &&
-                    ftepp->token != TOKEN_TYPENAME &&
-                    ftepp->token != TOKEN_KEYWORD)
+                if (ftepp->token != Token::IDENT &&
+                    ftepp->token != Token::TYPENAME &&
+                    ftepp->token != Token::KEYWORD)
                 {
                     ftepp_error(ftepp, "defined() used on an unexpected token type");
                     return false;
@@ -1016,7 +1016,7 @@ static bool ftepp_if_value(ftepp_t *ftepp, bool *out, double *value_out)
                 ftepp_next(ftepp);
                 if (!ftepp_skipspace(ftepp))
                     return false;
-                if (ftepp->token != ')') {
+                if (ftepp->token != Token::PAREN_CLOSE) {
                     ftepp_error(ftepp, "expected closing paren");
                     return false;
                 }
@@ -1030,11 +1030,11 @@ static bool ftepp_if_value(ftepp_t *ftepp, bool *out, double *value_out)
             } else {
                 /* This does not expand recursively! */
                 switch (macro->output[0]->token) {
-                    case TOKEN_INTCONST:
+                    case Token::INTCONST:
                         *value_out = macro->output[0]->constval.i;
                         *out = !!(macro->output[0]->constval.i);
                         break;
-                    case TOKEN_FLOATCONST:
+                    case Token::FLOATCONST:
                         *value_out = macro->output[0]->constval.f;
                         *out = !!(macro->output[0]->constval.f);
                         break;
@@ -1044,24 +1044,24 @@ static bool ftepp_if_value(ftepp_t *ftepp, bool *out, double *value_out)
                 }
             }
             break;
-        case TOKEN_STRINGCONST:
+        case Token::STRINGCONST:
             *value_out = 0;
             *out = false;
             break;
-        case TOKEN_INTCONST:
+        case Token::INTCONST:
             *value_out = ftepp->lex->tok.constval.i;
             *out = !!(ftepp->lex->tok.constval.i);
             break;
-        case TOKEN_FLOATCONST:
+        case Token::FLOATCONST:
             *value_out = ftepp->lex->tok.constval.f;
             *out = !!(ftepp->lex->tok.constval.f);
             break;
 
-        case '(':
+        case Token::PAREN_OPEN:
             ftepp_next(ftepp);
             if (!ftepp_if_expr(ftepp, out, value_out))
                 return false;
-            if (ftepp->token != ')') {
+            if (ftepp->token != Token::PAREN_CLOSE) {
                 ftepp_error(ftepp, "expected closing paren in #if expression");
                 return false;
             }
@@ -1099,7 +1099,7 @@ static bool ftepp_if_expr(ftepp_t *ftepp, bool *out, double *value_out)
     if (!ftepp_if_op(ftepp))
         return false;
 
-    if (ftepp->token == ')' || ftepp->token != TOKEN_OPERATOR)
+    if (ftepp->token == Token::PAREN_CLOSE || ftepp->token != Token::OPERATOR)
         return true;
 
     /* FTEQCC is all right-associative and no precedence here */
@@ -1111,7 +1111,7 @@ static bool ftepp_if_expr(ftepp_t *ftepp, bool *out, double *value_out)
         double nextvalue;
 
         (void)nextvalue;
-        if (!ftepp_next(ftepp))
+        if (ftepp_next(ftepp) == Token::NONE)
             return false;
         if (!ftepp_if_expr(ftepp, &next, &nextvalue))
             return false;
@@ -1136,7 +1136,7 @@ static bool ftepp_if_expr(ftepp_t *ftepp, bool *out, double *value_out)
         const char opc1 = ftepp_tokval(ftepp)[1];
         double other;
 
-        if (!ftepp_next(ftepp))
+        if (ftepp_next(ftepp) == Token::NONE)
             return false;
         if (!ftepp_if_expr(ftepp, &next, &other))
             return false;
@@ -1173,7 +1173,7 @@ static bool ftepp_if(ftepp_t *ftepp, ppcondition *cond)
 
     if (!ftepp_skipspace(ftepp))
         return false;
-    if (ftepp->token == TOKEN_EOL) {
+    if (ftepp->token == Token::EOL) {
         ftepp_error(ftepp, "expected expression for #if-directive");
         return false;
     }
@@ -1197,9 +1197,9 @@ static bool ftepp_ifdef(ftepp_t *ftepp, ppcondition *cond)
         return false;
 
     switch (ftepp->token) {
-        case TOKEN_IDENT:
-        case TOKEN_TYPENAME:
-        case TOKEN_KEYWORD:
+        case Token::IDENT:
+        case Token::TYPENAME:
+        case Token::KEYWORD:
             macro = ftepp_macro_find(ftepp, ftepp_tokval(ftepp));
             break;
         default:
@@ -1211,7 +1211,7 @@ static bool ftepp_ifdef(ftepp_t *ftepp, ppcondition *cond)
     if (!ftepp_skipspace(ftepp))
         return false;
     /* relaxing this condition
-    if (ftepp->token != TOKEN_EOL && ftepp->token != TOKEN_EOF) {
+    if (ftepp->token != Token::EOL && ftepp->token != Token::END) {
         ftepp_error(ftepp, "stray tokens after #ifdef");
         return false;
     }
@@ -1231,9 +1231,9 @@ static bool ftepp_undef(ftepp_t *ftepp)
 
     if (ftepp->output_on) {
         switch (ftepp->token) {
-            case TOKEN_IDENT:
-            case TOKEN_TYPENAME:
-            case TOKEN_KEYWORD:
+            case Token::IDENT:
+            case Token::TYPENAME:
+            case Token::KEYWORD:
                 ftepp_macro_delete(ftepp, ftepp_tokval(ftepp));
                 break;
             default:
@@ -1246,7 +1246,7 @@ static bool ftepp_undef(ftepp_t *ftepp)
     if (!ftepp_skipspace(ftepp))
         return false;
     /* relaxing this condition
-    if (ftepp->token != TOKEN_EOL && ftepp->token != TOKEN_EOF) {
+    if (ftepp->token != Token::EOL && ftepp->token != Token::END) {
         ftepp_error(ftepp, "stray tokens after #ifdef");
         return false;
     }
@@ -1334,11 +1334,11 @@ static bool ftepp_directive_warning(ftepp_t *ftepp) {
         return false;
 
     /* handle the odd non string constant case so it works like C */
-    if (ftepp->token != TOKEN_STRINGCONST) {
+    if (ftepp->token != Token::STRINGCONST) {
         bool  store   = false;
         vec_append(message, 8, "#warning");
         ftepp_next(ftepp);
-        while (ftepp->token != TOKEN_EOL) {
+        while (ftepp->token != Token::EOL) {
             vec_append(message, strlen(ftepp_tokval(ftepp)), ftepp_tokval(ftepp));
             ftepp_next(ftepp);
         }
@@ -1365,10 +1365,10 @@ static void ftepp_directive_error(ftepp_t *ftepp) {
         return;
 
     /* handle the odd non string constant case so it works like C */
-    if (ftepp->token != TOKEN_STRINGCONST) {
+    if (ftepp->token != Token::STRINGCONST) {
         vec_append(message, 6, "#error");
         ftepp_next(ftepp);
-        while (ftepp->token != TOKEN_EOL) {
+        while (ftepp->token != Token::EOL) {
             vec_append(message, strlen(ftepp_tokval(ftepp)), ftepp_tokval(ftepp));
             ftepp_next(ftepp);
         }
@@ -1393,10 +1393,10 @@ static void ftepp_directive_message(ftepp_t *ftepp) {
         return;
 
     /* handle the odd non string constant case so it works like C */
-    if (ftepp->token != TOKEN_STRINGCONST) {
+    if (ftepp->token != Token::STRINGCONST) {
         vec_append(message, 8, "#message");
         ftepp_next(ftepp);
-        while (ftepp->token != TOKEN_EOL) {
+        while (ftepp->token != Token::EOL) {
             vec_append(message, strlen(ftepp_tokval(ftepp)), ftepp_tokval(ftepp));
             ftepp_next(ftepp);
         }
@@ -1433,7 +1433,7 @@ static bool ftepp_include(ftepp_t *ftepp)
     if (!ftepp_skipspace(ftepp))
         return false;
 
-    if (ftepp->token != TOKEN_STRINGCONST) {
+    if (ftepp->token != Token::STRINGCONST) {
         ppmacro *macro = ftepp_macro_find(ftepp, ftepp_tokval(ftepp));
         if (macro) {
             char *backup = ftepp->output_string;
@@ -1514,7 +1514,7 @@ static bool ftepp_include(ftepp_t *ftepp)
     (void)ftepp_next(ftepp);
     if (!ftepp_skipspace(ftepp))
         return false;
-    if (ftepp->token != TOKEN_EOL) {
+    if (ftepp->token != Token::EOL) {
         ftepp_error(ftepp, "stray tokens after #include");
         return false;
     }
@@ -1553,9 +1553,9 @@ static bool ftepp_hash(ftepp_t *ftepp)
         return false;
 
     switch (ftepp->token) {
-        case TOKEN_KEYWORD:
-        case TOKEN_IDENT:
-        case TOKEN_TYPENAME:
+        case Token::KEYWORD:
+        case Token::IDENT:
+        case Token::TYPENAME:
             if (!strcmp(ftepp_tokval(ftepp), "define")) {
                 ftepp_inmacro(ftepp, "define");
                 return ftepp_define(ftepp);
@@ -1684,16 +1684,16 @@ static bool ftepp_hash(ftepp_t *ftepp)
         default:
             ftepp_error(ftepp, "unexpected preprocessor token: `%s`", ftepp_tokval(ftepp));
             return false;
-        case TOKEN_EOL:
+        case Token::EOL:
             ftepp_errorat(ftepp, ctx, "empty preprocessor directive");
             return false;
-        case TOKEN_EOF:
+        case Token::END:
             ftepp_error(ftepp, "missing newline at end of file", ftepp_tokval(ftepp));
             return false;
 
         /* Builtins! Don't forget the builtins! */
-        case TOKEN_INTCONST:
-        case TOKEN_FLOATCONST:
+        case Token::INTCONST:
+        case Token::FLOATCONST:
             ftepp_out(ftepp, "#", false);
             return true;
     }
@@ -1717,12 +1717,12 @@ static bool ftepp_preprocess(ftepp_t *ftepp)
     ftepp_next(ftepp);
     do
     {
-        if (ftepp->token >= TOKEN_EOF)
+        if (ftepp->token >= Token::END)
             break;
         switch (ftepp->token) {
-            case TOKEN_KEYWORD:
-            case TOKEN_IDENT:
-            case TOKEN_TYPENAME:
+            case Token::KEYWORD:
+            case Token::IDENT:
+            case Token::TYPENAME:
                 /* is it a predef? */
                 if (OPTS_FLAG(FTEPP_PREDEFS)) {
                     char *(*predef)(ftepp_t*) = ftepp_predef(ftepp_tokval(ftepp));
@@ -1747,30 +1747,30 @@ static bool ftepp_preprocess(ftepp_t *ftepp)
                     break;
                 }
                 if (!ftepp_macro_call(ftepp, macro))
-                    ftepp->token = TOKEN_ERROR;
+                    ftepp->token = Token::ERROR;
                 break;
-            case '#':
+            case Token::HASH:
                 if (!newline) {
                     ftepp_out(ftepp, ftepp_tokval(ftepp), false);
                     ftepp_next(ftepp);
                     break;
                 }
                 ftepp->lex->flags.mergelines = true;
-                if (ftepp_next(ftepp) >= TOKEN_EOF) {
+                if (ftepp_next(ftepp) >= Token::END) {
                     ftepp_error(ftepp, "error in preprocessor directive");
-                    ftepp->token = TOKEN_ERROR;
+                    ftepp->token = Token::ERROR;
                     break;
                 }
                 if (!ftepp_hash(ftepp))
-                    ftepp->token = TOKEN_ERROR;
+                    ftepp->token = Token::ERROR;
                 ftepp->lex->flags.mergelines = false;
                 break;
-            case TOKEN_EOL:
+            case Token::EOL:
                 newline = true;
                 ftepp_out(ftepp, "\n", true);
                 ftepp_next(ftepp);
                 break;
-            case TOKEN_WHITE:
+            case Token::WHITE:
                 /* same as default but don't set newline=false */
                 ftepp_out(ftepp, ftepp_tokval(ftepp), true);
                 ftepp_next(ftepp);
@@ -1781,13 +1781,13 @@ static bool ftepp_preprocess(ftepp_t *ftepp)
                 ftepp_next(ftepp);
                 break;
         }
-    } while (!ftepp->errors && ftepp->token < TOKEN_EOF);
+    } while (!ftepp->errors && ftepp->token < Token::END);
 
     /* force a 0 at the end but don't count it as added to the output */
     vec_push(ftepp->output_string, 0);
     vec_shrinkby(ftepp->output_string, 1);
 
-    return (ftepp->token == TOKEN_EOF);
+    return (ftepp->token == Token::END);
 }
 
 /* Like in parser.c - files keep the previous state so we have one global
diff --git a/gmqcc.h b/gmqcc.h
index 520a1cf9000ed101d2b0ca8383824a53f9676c8a..07f8c957caaa56389f8c282761bb4bdc4ec2c874 100644 (file)
--- a/gmqcc.h
+++ b/gmqcc.h
@@ -176,7 +176,7 @@ char *stat_mem_strdup(const char *, bool);
 #define util_islower(a) (((unsigned)(a)-'a') < 26)
 #define util_isupper(a) (((unsigned)(a)-'A') < 26)
 #define util_isprint(a) (((unsigned)(a)-0x20) < 0x5F)
-#define util_isspace(a) (((a) >= 9 && (a) <= 13) || (a) == ' ')
+#define util_isspace(a) (((a) >= 9 && (a) <= 13) || (a) == Token::WS)
 
 bool  util_strupper(const char *);
 bool  util_strdigit(const char *);
@@ -734,14 +734,6 @@ prog_section_def_t* prog_getdef    (qc_program_t *prog, qcint_t off);
 qcany_t*            prog_getedict  (qc_program_t *prog, qcint_t e);
 qcint_t             prog_tempstring(qc_program_t *prog, const char *_str);
 
-
-/* parser.c */
-struct parser_t;
-parser_t *parser_create(void);
-bool parser_compile_file(parser_t &parser, const char *);
-bool parser_compile_string(parser_t &parser, const char *, const char *, size_t);
-bool parser_finish(parser_t &parser, const char *);
-
 /* ftepp.c */
 struct ftepp_t;
 ftepp_t *ftepp_create           (void);
index 34fc71b00bfb3600b4c2bf5ca289e5d2e23f4447..0bc28cbb33c48273a39f5f342d5ca6ee52fcc760 100644 (file)
--- a/lexer.cpp
+++ b/lexer.cpp
@@ -71,8 +71,8 @@ static void lex_token_new(lex_file *lex)
     lex->tok.ctx.column  = lex->column;
 }
 
-static void lex_ungetch(lex_file *lex, int ch);
-static int lex_getch(lex_file *lex);
+static void lex_ungetch(lex_file *lex, Token ch);
+static Token lex_getch(lex_file *lex);
 
 lex_file* lex_open(const char *file)
 {
@@ -103,9 +103,9 @@ lex_file* lex_open(const char *file)
 
     /* handle BOM */
     if ((read = (lex_getch(lex) << 16) | (lex_getch(lex) << 8) | lex_getch(lex)) != 0xEFBBBF) {
-        lex_ungetch(lex, (read & 0x0000FF));
-        lex_ungetch(lex, (read & 0x00FF00) >> 8);
-        lex_ungetch(lex, (read & 0xFF0000) >> 16);
+        lex_ungetch(lex, static_cast<Token>((read & 0x0000FF)));
+        lex_ungetch(lex, static_cast<Token>((read & 0x00FF00) >> 8));
+        lex_ungetch(lex, static_cast<Token>((read & 0xFF0000) >> 16));
     } else {
         /*
          * otherwise the lexer has advanced 3 bytes for the BOM, we need
@@ -175,19 +175,21 @@ void lex_close(lex_file *lex)
 
 
 
-static int lex_fgetc(lex_file *lex)
+static Token lex_fgetc(lex_file *lex)
 {
     if (lex->file) {
         lex->column++;
-        return fgetc(lex->file);
+        auto c = fgetc(lex->file);
+        return c == EOF ? Token::END : static_cast<Token>(c);
     }
     if (lex->open_string) {
         if (lex->open_string_pos >= lex->open_string_length)
-            return EOF;
+            return Token::END;
         lex->column++;
-        return lex->open_string[lex->open_string_pos++];
+        auto c = lex->open_string[lex->open_string_pos++];
+        return static_cast<Token>(c);
     }
-    return EOF;
+    return Token::END;
 }
 
 /* Get or put-back data
@@ -195,36 +197,35 @@ static int lex_fgetc(lex_file *lex)
  * are working on.
  * The are merely wrapping get/put in order to count line numbers.
  */
-static int lex_try_trigraph(lex_file *lex, int old)
+static Token lex_try_trigraph(lex_file *lex, Token old)
 {
-    int c2, c3;
-    c2 = lex_fgetc(lex);
-    if (!lex->push_line && c2 == '\n') {
+    auto c2 = lex_fgetc(lex);
+    if (!lex->push_line && c2 == Token::LF) {
         lex->line++;
         lex->column = 0;
     }
 
-    if (c2 != '?') {
+    if (c2 != Token::QUESTION) {
         lex_ungetch(lex, c2);
         return old;
     }
 
-    c3 = lex_fgetc(lex);
-    if (!lex->push_line && c3 == '\n') {
+    auto c3 = lex_fgetc(lex);
+    if (!lex->push_line && c3 == Token::LF) {
         lex->line++;
         lex->column = 0;
     }
 
     switch (c3) {
-        case '=': return '#';
-        case '/': return '\\';
-        case '\'': return '^';
-        case '(': return '[';
-        case ')': return ']';
-        case '!': return '|';
-        case '<': return '{';
-        case '>': return '}';
-        case '-': return '~';
+        case Token::EQ: return Token::HASH;
+        case Token::DIV: return Token::BACKSLASH;
+        case Token::QUOT_SINGLE: return Token::XOR;
+        case Token::PAREN_OPEN: return Token::BRACKET_OPEN;
+        case Token::PAREN_CLOSE: return Token::BRACKET_CLOSE;
+        case Token::NOT: return Token::OR;
+        case Token::LT: return Token::BRACE_OPEN;
+        case Token::GT: return Token::BRACE_CLOSE;
+        case Token::SUB: return Token::BITNOT;
         default:
             lex_ungetch(lex, c3);
             lex_ungetch(lex, c2);
@@ -232,59 +233,56 @@ static int lex_try_trigraph(lex_file *lex, int old)
     }
 }
 
-static int lex_try_digraph(lex_file *lex, int ch)
+static Token lex_try_digraph(lex_file *lex, Token ch)
 {
-    int c2;
-    c2 = lex_fgetc(lex);
+    auto 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')
+    if (!lex->push_line && c2 == Token::LF)
         lex->line++;
-    if      (ch == '<' && c2 == ':')
-        return '[';
-    else if (ch == ':' && c2 == '>')
-        return ']';
-    else if (ch == '<' && c2 == '%')
-        return '{';
-    else if (ch == '%' && c2 == '>')
-        return '}';
-    else if (ch == '%' && c2 == ':')
-        return '#';
+    if      (ch == Token::LT && c2 == Token::COLON)
+        return Token::BRACKET_OPEN;
+    else if (ch == Token::COLON && c2 == Token::GT)
+        return Token::BRACKET_CLOSE;
+    else if (ch == Token::LT && c2 == Token::MOD)
+        return Token::BRACE_OPEN;
+    else if (ch == Token::MOD && c2 == Token::GT)
+        return Token::BRACE_CLOSE;
+    else if (ch == Token::MOD && c2 == Token::COLON)
+        return Token::HASH;
     lex_ungetch(lex, c2);
     return ch;
 }
 
-static int lex_getch(lex_file *lex)
+static Token lex_getch(lex_file *lex)
 {
-    int ch;
-
     if (lex->peekpos) {
         lex->peekpos--;
-        if (!lex->push_line && lex->peek[lex->peekpos] == '\n') {
+        if (!lex->push_line && lex->peek[lex->peekpos] == Token::LF) {
             lex->line++;
             lex->column = 0;
         }
         return lex->peek[lex->peekpos];
     }
 
-    ch = lex_fgetc(lex);
-    if (!lex->push_line && ch == '\n') {
+    auto ch = lex_fgetc(lex);
+    if (!lex->push_line && ch == Token::LF) {
         lex->line++;
         lex->column = 0;
     }
-    else if (ch == '?')
+    else if (ch == Token::QUESTION)
         return lex_try_trigraph(lex, ch);
-    else if (!lex->flags.nodigraphs && (ch == '<' || ch == ':' || ch == '%'))
+    else if (!lex->flags.nodigraphs && (ch == Token::LT || ch == Token::COLON || ch == Token::MOD))
         return lex_try_digraph(lex, ch);
     return ch;
 }
 
-static void lex_ungetch(lex_file *lex, int ch)
+static void lex_ungetch(lex_file *lex, Token ch)
 {
     lex->peek[lex->peekpos++] = ch;
     lex->column--;
-    if (!lex->push_line && ch == '\n') {
+    if (!lex->push_line && ch == Token::LF) {
         lex->line--;
         lex->column = 0;
     }
@@ -328,7 +326,6 @@ static void lex_endtoken(lex_file *lex)
 
 static bool lex_try_pragma(lex_file *lex)
 {
-    int ch;
     char *pragma  = nullptr;
     char *command = nullptr;
     char *param   = nullptr;
@@ -339,8 +336,8 @@ static bool lex_try_pragma(lex_file *lex)
 
     line = lex->line;
 
-    ch = lex_getch(lex);
-    if (ch != '#') {
+    auto ch = lex_getch(lex);
+    if (ch != Token::HASH) {
         lex_ungetch(lex, ch);
         return false;
     }
@@ -349,7 +346,7 @@ static bool lex_try_pragma(lex_file *lex)
         vec_push(pragma, ch);
     vec_push(pragma, 0);
 
-    if (ch != ' ' || strcmp(pragma, "pragma")) {
+    if (ch != Token::WS|| strcmp(pragma, "pragma")) {
         lex_ungetch(lex, ch);
         goto unroll;
     }
@@ -358,16 +355,16 @@ static bool lex_try_pragma(lex_file *lex)
         vec_push(command, ch);
     vec_push(command, 0);
 
-    if (ch != '(') {
+    if (ch != Token::PAREN_OPEN) {
         lex_ungetch(lex, ch);
         goto unroll;
     }
 
-    for (ch = lex_getch(lex); vec_size(param) < 1024 && ch != ')' && ch != '\n'; ch = lex_getch(lex))
+    for (ch = lex_getch(lex); vec_size(param) < 1024 && ch != Token::PAREN_CLOSE && ch != Token::LF; ch = lex_getch(lex))
         vec_push(param, ch);
     vec_push(param, 0);
 
-    if (ch != ')') {
+    if (ch != Token::PAREN_CLOSE) {
         lex_ungetch(lex, ch);
         goto unroll;
     }
@@ -402,7 +399,7 @@ static bool lex_try_pragma(lex_file *lex)
         goto unroll;
 
     lex->line = line;
-    while (ch != '\n' && ch != EOF)
+    while (ch != Token::LF && ch != Token::END)
         ch = lex_getch(lex);
     vec_free(command);
     vec_free(param);
@@ -413,30 +410,30 @@ unroll:
     if (command) {
         vec_pop(command);
         while (vec_size(command)) {
-            lex_ungetch(lex, (unsigned char)vec_last(command));
+            lex_ungetch(lex, static_cast<Token>(vec_last(command)));
             vec_pop(command);
         }
         vec_free(command);
-        lex_ungetch(lex, ' ');
+        lex_ungetch(lex, Token::WS);
     }
     if (param) {
         vec_pop(param);
         while (vec_size(param)) {
-            lex_ungetch(lex, (unsigned char)vec_last(param));
+            lex_ungetch(lex, static_cast<Token>(vec_last(param)));
             vec_pop(param);
         }
         vec_free(param);
-        lex_ungetch(lex, ' ');
+        lex_ungetch(lex, Token::WS);
     }
     if (pragma) {
         vec_pop(pragma);
         while (vec_size(pragma)) {
-            lex_ungetch(lex, (unsigned char)vec_last(pragma));
+            lex_ungetch(lex, static_cast<Token>(vec_last(pragma)));
             vec_pop(pragma);
         }
         vec_free(pragma);
     }
-    lex_ungetch(lex, '#');
+    lex_ungetch(lex, Token::HASH);
 
     lex->line = line;
     return false;
@@ -474,30 +471,30 @@ printf(   "line one\n"
  *    here is to store the line of the first character after skipping
  *    the initial whitespace in lex->sline, this happens in lex_do.
  */
-static int lex_skipwhite(lex_file *lex, bool hadwhite)
+static Token lex_skipwhite(lex_file *lex, bool hadwhite)
 {
-    int ch = 0;
+    Token ch;
     bool haswhite = hadwhite;
 
     do
     {
         ch = lex_getch(lex);
-        while (ch != EOF && util_isspace(ch)) {
-            if (ch == '\n') {
+        while (ch != Token::END && util_isspace(ch)) {
+            if (ch == Token::LF) {
                 if (lex_try_pragma(lex))
                     continue;
             }
             if (lex->flags.preprocessing) {
-                if (ch == '\n') {
+                if (ch == Token::LF) {
                     /* end-of-line */
                     /* see if there was whitespace first */
                     if (haswhite) { /* (vec_size(lex->tok.value)) { */
                         lex_ungetch(lex, ch);
                         lex_endtoken(lex);
-                        return TOKEN_WHITE;
+                        return Token::WHITE;
                     }
                     /* otherwise return EOL */
-                    return TOKEN_EOL;
+                    return Token::EOL;
                 }
                 haswhite = true;
                 lex_tokench(lex, ch);
@@ -505,75 +502,75 @@ static int lex_skipwhite(lex_file *lex, bool hadwhite)
             ch = lex_getch(lex);
         }
 
-        if (ch == '/') {
+        if (ch == Token::DIV) {
             ch = lex_getch(lex);
-            if (ch == '/')
+            if (ch == Token::DIV)
             {
                 /* one line comment */
                 ch = lex_getch(lex);
 
                 if (lex->flags.preprocessing) {
                     haswhite = true;
-                    lex_tokench(lex, ' ');
-                    lex_tokench(lex, ' ');
+                    lex_tokench(lex, Token::WS);
+                    lex_tokench(lex, Token::WS);
                 }
 
-                while (ch != EOF && ch != '\n') {
+                while (ch != Token::END && ch != Token::LF) {
                     if (lex->flags.preprocessing)
-                        lex_tokench(lex, ' '); /* ch); */
+                        lex_tokench(lex, Token::WS); /* ch); */
                     ch = lex_getch(lex);
                 }
                 if (lex->flags.preprocessing) {
-                    lex_ungetch(lex, '\n');
+                    lex_ungetch(lex, Token::LF);
                     lex_endtoken(lex);
-                    return TOKEN_WHITE;
+                    return Token::WHITE;
                 }
                 continue;
             }
-            if (ch == '*')
+            if (ch == Token::MUL)
             {
                 /* multiline comment */
                 if (lex->flags.preprocessing) {
                     haswhite = true;
-                    lex_tokench(lex, ' ');
-                    lex_tokench(lex, ' ');
+                    lex_tokench(lex, Token::WS);
+                    lex_tokench(lex, Token::WS);
                 }
 
-                while (ch != EOF)
+                while (ch != Token::END)
                 {
                     ch = lex_getch(lex);
-                    if (ch == '*') {
+                    if (ch == Token::MUL) {
                         ch = lex_getch(lex);
-                        if (ch == '/') {
+                        if (ch == Token::DIV) {
                             if (lex->flags.preprocessing) {
-                                lex_tokench(lex, ' ');
-                                lex_tokench(lex, ' ');
+                                lex_tokench(lex, Token::WS);
+                                lex_tokench(lex, Token::WS);
                             }
                             break;
                         }
                         lex_ungetch(lex, ch);
                     }
                     if (lex->flags.preprocessing) {
-                        if (ch == '\n')
-                            lex_tokench(lex, '\n');
+                        if (ch == Token::LF)
+                            lex_tokench(lex, Token::LF);
                         else
-                            lex_tokench(lex, ' ');
+                            lex_tokench(lex, Token::WS);
                     }
                 }
-                ch = ' '; /* cause TRUE in the isspace check */
+                ch = Token::WS; /* cause TRUE in the isspace check */
                 continue;
             }
             /* Otherwise roll back to the slash and break out of the loop */
             lex_ungetch(lex, ch);
-            ch = '/';
+            ch = Token::DIV;
             break;
         }
-    } while (ch != EOF && util_isspace(ch));
+    } while (ch != Token::END && util_isspace(ch));
 
     if (haswhite) {
         lex_endtoken(lex);
         lex_ungetch(lex, ch);
-        return TOKEN_WHITE;
+        return Token::WHITE;
     }
     return ch;
 }
@@ -581,10 +578,8 @@ static int lex_skipwhite(lex_file *lex, bool hadwhite)
 /* Get a token */
 static bool GMQCC_WARN lex_finish_ident(lex_file *lex)
 {
-    int ch;
-
-    ch = lex_getch(lex);
-    while (ch != EOF && isident(ch))
+    auto ch = lex_getch(lex);
+    while (ch != Token::END && isident(ch))
     {
         lex_tokench(lex, ch);
         ch = lex_getch(lex);
@@ -599,15 +594,13 @@ static bool GMQCC_WARN lex_finish_ident(lex_file *lex)
 /* read one ident for the frame list */
 static int lex_parse_frame(lex_file *lex)
 {
-    int ch;
-
     lex_token_new(lex);
 
-    ch = lex_getch(lex);
-    while (ch != EOF && ch != '\n' && util_isspace(ch))
+    auto ch = lex_getch(lex);
+    while (ch != Token::END && ch != Token::LF && util_isspace(ch))
         ch = lex_getch(lex);
 
-    if (ch == '\n')
+    if (ch == Token::LF)
         return 1;
 
     if (!isident_start(ch)) {
@@ -656,38 +649,38 @@ static bool lex_finish_frames(lex_file *lex)
     return false;
 }
 
-static int GMQCC_WARN lex_finish_string(lex_file *lex, int quote)
+static Token GMQCC_WARN lex_finish_string(lex_file *lex, int quote)
 {
     utf8ch_t chr = 0;
     int ch = 0, texttype = 0;
-    int nextch;
+    Token nextch = Token::NONE;
     bool hex;
     bool oct;
     char u8buf[8]; /* way more than enough */
     int  u8len, uc;
 
-    while (ch != EOF)
+    while (ch != Token::END)
     {
         ch = lex_getch(lex);
         if (ch == quote)
-            return TOKEN_STRINGCONST;
+            return Token::STRINGCONST;
 
         if (lex->flags.preprocessing && ch == '\\') {
             lex_tokench(lex, ch);
             ch = lex_getch(lex);
-            if (ch == EOF) {
+            if (ch == Token::END) {
                 lexerror(lex, "unexpected end of file");
-                lex_ungetch(lex, EOF); /* next token to be TOKEN_EOF */
-                return (lex->tok.ttype = TOKEN_ERROR);
+                lex_ungetch(lex, Token::END); /* next token to be Token::END */
+                return (lex->tok.ttype = Token::ERROR);
             }
             lex_tokench(lex, ch);
         }
         else if (ch == '\\') {
             ch = lex_getch(lex);
-            if (ch == EOF) {
+            if (ch == Token::END) {
                 lexerror(lex, "unexpected end of file");
-                lex_ungetch(lex, EOF); /* next token to be TOKEN_EOF */
-                return (lex->tok.ttype = TOKEN_ERROR);
+                lex_ungetch(lex, Token::END); /* next token to be Token::END */
+                return (lex->tok.ttype = Token::ERROR);
             }
 
             switch (ch) {
@@ -714,7 +707,7 @@ static int GMQCC_WARN lex_finish_string(lex_file *lex, int quote)
                 else {
                     lexerror(lex, "bad character code");
                     lex_ungetch(lex, nextch);
-                    return (lex->tok.ttype = TOKEN_ERROR);
+                    return (lex->tok.ttype = Token::ERROR);
                 }
 
                 ch *= 0x10;
@@ -728,7 +721,7 @@ static int GMQCC_WARN lex_finish_string(lex_file *lex, int quote)
                 else {
                     lexerror(lex, "bad character code");
                     lex_ungetch(lex, nextch);
-                    return (lex->tok.ttype = TOKEN_ERROR);
+                    return (lex->tok.ttype = Token::ERROR);
                 }
                 break;
 
@@ -750,13 +743,13 @@ static int GMQCC_WARN lex_finish_string(lex_file *lex, int quote)
                 oct = (nextch == '0');
                 if (!hex && !oct)
                     lex_ungetch(lex, nextch);
-                for (nextch = lex_getch(lex); nextch != '}'; nextch = lex_getch(lex)) {
+                for (nextch = lex_getch(lex); nextch != Token::BRACE_CLOSE; nextch = lex_getch(lex)) {
                     if (!hex && !oct) {
                         if (nextch >= '0' && nextch <= '9')
                             chr = chr * 10 + nextch - '0';
                         else {
                             lexerror(lex, "bad character code");
-                            return (lex->tok.ttype = TOKEN_ERROR);
+                            return (lex->tok.ttype = Token::ERROR);
                         }
                     } else if (!oct) {
                         if (nextch >= '0' && nextch <= '9')
@@ -767,20 +760,20 @@ static int GMQCC_WARN lex_finish_string(lex_file *lex, int quote)
                             chr = chr * 0x10 + nextch - 'A' + 10;
                         else {
                             lexerror(lex, "bad character code");
-                            return (lex->tok.ttype = TOKEN_ERROR);
+                            return (lex->tok.ttype = Token::ERROR);
                         }
                     } else {
                         if (nextch >= '0' && nextch <= '9')
                             chr = chr * 8 + chr - '0';
                         else {
                             lexerror(lex, "bad character code");
-                            return (lex->tok.ttype = TOKEN_ERROR);
+                            return (lex->tok.ttype = Token::ERROR);
                         }
                     }
                     if (chr > 0x10FFFF || (!OPTS_FLAG(UTF8) && chr > 255))
                     {
                         lexerror(lex, "character code out of range");
-                        return (lex->tok.ttype = TOKEN_ERROR);
+                        return (lex->tok.ttype = Token::ERROR);
                     }
                 }
                 if (OPTS_FLAG(UTF8) && chr >= 128) {
@@ -824,26 +817,26 @@ static int GMQCC_WARN lex_finish_string(lex_file *lex, int quote)
             lex_tokench(lex, ch);
     }
     lexerror(lex, "unexpected end of file within string constant");
-    lex_ungetch(lex, EOF); /* next token to be TOKEN_EOF */
-    return (lex->tok.ttype = TOKEN_ERROR);
+    lex_ungetch(lex, Token::END); /* next token to be Token::END */
+    return (lex->tok.ttype = Token::ERROR);
 }
 
-static int GMQCC_WARN lex_finish_digit(lex_file *lex, int lastch)
+static Token GMQCC_WARN lex_finish_digit(lex_file *lex, Token lastch)
 {
     bool ishex = false;
 
-    int  ch = lastch;
+    Token ch = lastch;
 
     /* parse a number... */
-    if (ch == '.')
-        lex->tok.ttype = TOKEN_FLOATCONST;
+    if (ch == Token::DOT)
+        lex->tok.ttype = Token::FLOATCONST;
     else
-        lex->tok.ttype = TOKEN_INTCONST;
+        lex->tok.ttype = Token::INTCONST;
 
     lex_tokench(lex, ch);
 
     ch = lex_getch(lex);
-    if (ch != '.' && !util_isdigit(ch))
+    if (ch != Token::DOT && !util_isdigit(ch))
     {
         if (lastch != '0' || ch != 'x')
         {
@@ -860,7 +853,7 @@ static int GMQCC_WARN lex_finish_digit(lex_file *lex, int lastch)
 
     /* EOF would have been caught above */
 
-    if (ch != '.')
+    if (ch != Token::DOT)
     {
         lex_tokench(lex, ch);
         ch = lex_getch(lex);
@@ -871,10 +864,10 @@ static int GMQCC_WARN lex_finish_digit(lex_file *lex, int lastch)
         }
     }
     /* NOT else, '.' can come from above as well */
-    if (lex->tok.ttype != TOKEN_FLOATCONST && ch == '.' && !ishex)
+    if (lex->tok.ttype != Token::FLOATCONST && ch == Token::DOT && !ishex)
     {
         /* Allow floating comma in non-hex mode */
-        lex->tok.ttype = TOKEN_FLOATCONST;
+        lex->tok.ttype = Token::FLOATCONST;
         lex_tokench(lex, ch);
 
         /* continue digits-only */
@@ -887,27 +880,27 @@ static int GMQCC_WARN lex_finish_digit(lex_file *lex, int lastch)
     }
     /* put back the last character */
     /* but do not put back the trailing 'f' or a float */
-    if (lex->tok.ttype == TOKEN_FLOATCONST && ch == 'f')
+    if (lex->tok.ttype == Token::FLOATCONST && ch == 'f')
         ch = lex_getch(lex);
 
     /* generally we don't want words to follow numbers: */
     if (isident(ch)) {
         lexerror(lex, "unexpected trailing characters after number");
-        return (lex->tok.ttype = TOKEN_ERROR);
+        return (lex->tok.ttype = Token::ERROR);
     }
     lex_ungetch(lex, ch);
 
     lex_endtoken(lex);
-    if (lex->tok.ttype == TOKEN_FLOATCONST)
+    if (lex->tok.ttype == Token::FLOATCONST)
         lex->tok.constval.f = strtod(lex->tok.value, nullptr);
     else
         lex->tok.constval.i = strtol(lex->tok.value, nullptr, 0);
     return lex->tok.ttype;
 }
 
-int lex_do(lex_file *lex)
+Token lex_do(lex_file *lex)
 {
-    int ch, nextch, thirdch;
+    Token ch, nextch, thirdch;
     bool hadwhite = false;
 
     lex_token_new(lex);
@@ -915,22 +908,21 @@ int lex_do(lex_file *lex)
     while (true) {
         ch = lex_skipwhite(lex, hadwhite);
         hadwhite = true;
-        if (!lex->flags.mergelines || ch != '\\')
+        if (!lex->flags.mergelines || ch != Token::BACKSLASH)
             break;
         ch = lex_getch(lex);
-        if (ch == '\r')
+        if (ch == Token::CR)
             ch = lex_getch(lex);
-        if (ch != '\n') {
+        if (ch != Token::LF) {
             lex_ungetch(lex, ch);
-            ch = '\\';
+            ch = Token::BACKSLASH;
             break;
         }
         /* we reached a linemerge */
         lex_tokench(lex, '\n');
-        continue;
     }
 
-    if (lex->flags.preprocessing && (ch == TOKEN_WHITE || ch == TOKEN_EOL || ch == TOKEN_FATAL)) {
+    if (lex->flags.preprocessing && (ch == Token::WHITE || ch == Token::EOL || ch == Token::FATAL)) {
         return (lex->tok.ttype = ch);
     }
 
@@ -939,15 +931,15 @@ int lex_do(lex_file *lex)
     lex->tok.ctx.file = lex->name;
 
     if (lex->eof)
-        return (lex->tok.ttype = TOKEN_FATAL);
+        return (lex->tok.ttype = Token::FATAL);
 
-    if (ch == EOF) {
+    if (ch == Token::END) {
         lex->eof = true;
-        return (lex->tok.ttype = TOKEN_EOF);
+        return (lex->tok.ttype = Token::END);
     }
 
     /* modelgen / spiritgen commands */
-    if (ch == '$' && !lex->flags.preprocessing) {
+    if (ch == Token::DOLLAR && !lex->flags.preprocessing) {
         const char *v;
         size_t frame;
 
@@ -958,7 +950,7 @@ int lex_do(lex_file *lex)
         }
         lex_tokench(lex, ch);
         if (!lex_finish_ident(lex))
-            return (lex->tok.ttype = TOKEN_ERROR);
+            return (lex->tok.ttype = Token::ERROR);
         lex_endtoken(lex);
         /* skip the known commands */
         v = lex->tok.value;
@@ -971,14 +963,14 @@ int lex_do(lex_file *lex)
              * which the parser is unaware of
              */
             if (!lex_finish_frames(lex))
-                 return (lex->tok.ttype = TOKEN_ERROR);
+                 return (lex->tok.ttype = Token::ERROR);
             return lex_do(lex);
         }
 
         if (!strcmp(v, "framevalue"))
         {
             ch = lex_getch(lex);
-            while (ch != EOF && util_isspace(ch) && ch != '\n')
+            while (ch != Token::END && util_isspace(ch) && ch != Token::LF)
                 ch = lex_getch(lex);
 
             if (!util_isdigit(ch)) {
@@ -989,7 +981,7 @@ int lex_do(lex_file *lex)
             lex_token_new(lex);
             lex->tok.ttype = lex_finish_digit(lex, ch);
             lex_endtoken(lex);
-            if (lex->tok.ttype != TOKEN_INTCONST) {
+            if (lex->tok.ttype != Token::INTCONST) {
                 lexerror(lex, "$framevalue requires an integer parameter");
                 return lex_do(lex);
             }
@@ -1010,7 +1002,7 @@ int lex_do(lex_file *lex)
                 return lex_do(lex);
             }
             if (rc < 0)
-                return (lex->tok.ttype = TOKEN_FATAL);
+                return (lex->tok.ttype = Token::FATAL);
 
             v = lex->tok.value;
             for (frame = 0; frame < vec_size(lex->frames); ++frame) {
@@ -1036,7 +1028,7 @@ int lex_do(lex_file *lex)
                 return lex_do(lex);
             }
             if (rc < 0)
-                return (lex->tok.ttype = TOKEN_FATAL);
+                return (lex->tok.ttype = Token::FATAL);
 
             if (lex->modelname) {
                 frame_macro m;
@@ -1058,7 +1050,7 @@ int lex_do(lex_file *lex)
             vec_free(lex->frames);
             /* skip line (fteqcc does it too) */
             ch = lex_getch(lex);
-            while (ch != EOF && ch != '\n')
+            while (ch != Token::END && ch != Token::LF)
                 ch = lex_getch(lex);
             return lex_do(lex);
         }
@@ -1072,7 +1064,7 @@ int lex_do(lex_file *lex)
         {
             /* skip line */
             ch = lex_getch(lex);
-            while (ch != EOF && ch != '\n')
+            while (ch != Token::END && ch != Token::LF)
                 ch = lex_getch(lex);
             return lex_do(lex);
         }
@@ -1080,7 +1072,7 @@ int lex_do(lex_file *lex)
         for (frame = 0; frame < vec_size(lex->frames); ++frame) {
             if (!strcmp(v, lex->frames[frame].name)) {
                 lex->tok.constval.i = lex->frames[frame].value;
-                return (lex->tok.ttype = TOKEN_INTCONST);
+                return (lex->tok.ttype = Token::INTCONST);
             }
         }
 
@@ -1091,44 +1083,44 @@ int lex_do(lex_file *lex)
     /* single-character tokens */
     switch (ch)
     {
-        case '[':
+        case Token::BRACKET_OPEN:
             nextch = lex_getch(lex);
-            if (nextch == '[') {
+            if (nextch == Token::BRACKET_OPEN) {
                 lex_tokench(lex, ch);
                 lex_tokench(lex, nextch);
                 lex_endtoken(lex);
-                return (lex->tok.ttype = TOKEN_ATTRIBUTE_OPEN);
+                return (lex->tok.ttype = Token::ATTRIBUTE_OPEN);
             }
             lex_ungetch(lex, nextch);
             /* FALL THROUGH */
-        case '(':
-        case ':':
-        case '?':
+        case Token::PAREN_OPEN:
+        case Token::COLON:
+        case Token::QUESTION:
             lex_tokench(lex, ch);
             lex_endtoken(lex);
             if (lex->flags.noops)
                 return (lex->tok.ttype = ch);
             else
-                return (lex->tok.ttype = TOKEN_OPERATOR);
+                return (lex->tok.ttype = Token::OPERATOR);
 
-        case ']':
+        case Token::BRACKET_CLOSE:
             if (lex->flags.noops) {
                 nextch = lex_getch(lex);
-                if (nextch == ']') {
+                if (nextch == Token::BRACKET_CLOSE) {
                     lex_tokench(lex, ch);
                     lex_tokench(lex, nextch);
                     lex_endtoken(lex);
-                    return (lex->tok.ttype = TOKEN_ATTRIBUTE_CLOSE);
+                    return (lex->tok.ttype = Token::ATTRIBUTE_CLOSE);
                 }
                 lex_ungetch(lex, nextch);
             }
             /* FALL THROUGH */
-        case ')':
-        case ';':
-        case '{':
-        case '}':
+        case Token::PAREN_CLOSE:
+        case Token::SEMICOLON:
+        case Token::BRACE_OPEN:
+        case Token::BRACE_CLOSE:
 
-        case '#':
+        case Token::HASH:
             lex_tokench(lex, ch);
             lex_endtoken(lex);
             return (lex->tok.ttype = ch);
@@ -1136,7 +1128,7 @@ int lex_do(lex_file *lex)
             break;
     }
 
-    if (ch == '.') {
+    if (ch == Token::DOT) {
         nextch = lex_getch(lex);
         /* digits starting with a dot */
         if (util_isdigit(nextch)) {
@@ -1155,17 +1147,17 @@ int lex_do(lex_file *lex)
          */
         switch (ch)
         {
-            case '*':
-            case '/':
-            case '<':
-            case '>':
-            case '=':
-            case '&':
-            case '|':
-            case '^':
-            case '~':
-            case ',':
-            case '!':
+            case Token::MUL:
+            case Token::DIV:
+            case Token::LT:
+            case Token::GT:
+            case Token::EQ:
+            case Token::AND:
+            case Token::OR:
+            case Token::XOR:
+            case Token::BITNOT:
+            case Token::COMMA:
+            case Token::NOT:
                 lex_tokench(lex, ch);
                 lex_endtoken(lex);
                 return (lex->tok.ttype = ch);
@@ -1174,72 +1166,72 @@ int lex_do(lex_file *lex)
         }
     }
 
-    if (ch == '.')
+    if (ch == Token::DOT)
     {
         lex_tokench(lex, ch);
         /* peak ahead once */
         nextch = lex_getch(lex);
-        if (nextch != '.') {
+        if (nextch != Token::DOT) {
             lex_ungetch(lex, nextch);
             lex_endtoken(lex);
             if (lex->flags.noops)
                 return (lex->tok.ttype = ch);
             else
-                return (lex->tok.ttype = TOKEN_OPERATOR);
+                return (lex->tok.ttype = Token::OPERATOR);
         }
         /* peak ahead again */
         nextch = lex_getch(lex);
-        if (nextch != '.') {
+        if (nextch != Token::DOT) {
             lex_ungetch(lex, nextch);
-            lex_ungetch(lex, '.');
+            lex_ungetch(lex, Token::DOT);
             lex_endtoken(lex);
             if (lex->flags.noops)
                 return (lex->tok.ttype = ch);
             else
-                return (lex->tok.ttype = TOKEN_OPERATOR);
+                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);
+        return (lex->tok.ttype = Token::DOTS);
     }
 
-    if (ch == ',' || ch == '.') {
+    if (ch == Token::COMMA || ch == Token::DOT) {
         lex_tokench(lex, ch);
         lex_endtoken(lex);
-        return (lex->tok.ttype = TOKEN_OPERATOR);
+        return (lex->tok.ttype = Token::OPERATOR);
     }
 
-    if (ch == '+' || ch == '-' || /* ++, --, +=, -=  and -> as well! */
-        ch == '>' || ch == '<' || /* <<, >>, <=, >=  and >< as well! */
-        ch == '=' || ch == '!' || /* <=>, ==, !=                     */
-        ch == '&' || ch == '|' || /* &&, ||, &=, |=                  */
-        ch == '~' || ch == '^'    /* ~=, ~, ^                        */
+    if (ch == Token::ADD || ch == Token::SUB || /* ++, --, +=, -=  and -> as well! */
+        ch == Token::GT || ch == Token::LT|| /* <<, >>, <=, >=  and >< as well! */
+        ch == Token::EQ || ch == Token::NOT || /* <=>, ==, !=                     */
+        ch == Token::AND || ch == Token::OR || /* &&, ||, &=, |=                  */
+        ch == Token::BITNOT || ch == Token::XOR   /* ~=, ~, ^                        */
     )  {
         lex_tokench(lex, ch);
         nextch = lex_getch(lex);
 
-        if ((nextch == '=' && ch != '<') || (nextch == '<' && ch == '>'))
+        if ((nextch == Token::EQ && ch != Token::LT) || (nextch == Token::LT && ch == Token::GT))
             lex_tokench(lex, nextch);
-        else if (nextch == ch && ch != '!') {
+        else if (nextch == ch && ch != Token::NOT) {
             lex_tokench(lex, nextch);
-            if ((thirdch = lex_getch(lex)) == '=')
+            if ((thirdch = lex_getch(lex)) == Token::EQ)
                 lex_tokench(lex, thirdch);
             else
                 lex_ungetch(lex, thirdch);
-        } else if (ch == '<' && nextch == '=') {
+        } else if (ch == Token::LT && nextch == Token::EQ) {
             lex_tokench(lex, nextch);
-            if ((thirdch = lex_getch(lex)) == '>')
+            if ((thirdch = lex_getch(lex)) == Token::GT)
                 lex_tokench(lex, thirdch);
             else
                 lex_ungetch(lex, thirdch);
 
-        } else if (ch == '-' && nextch == '>') {
+        } else if (ch == Token::SUB && nextch == Token::GT) {
             lex_tokench(lex, nextch);
-        } else if (ch == '&' && nextch == '~') {
+        } else if (ch == Token::AND && nextch == Token::BITNOT) {
             thirdch = lex_getch(lex);
-            if (thirdch != '=') {
+            if (thirdch != Token::EQ) {
                 lex_ungetch(lex, thirdch);
                 lex_ungetch(lex, nextch);
             }
@@ -1249,10 +1241,10 @@ int lex_do(lex_file *lex)
             }
         }
         else if (lex->flags.preprocessing &&
-                 ch == '-' && util_isdigit(nextch))
+                 ch == Token::SUB && util_isdigit(nextch))
         {
             lex->tok.ttype = lex_finish_digit(lex, nextch);
-            if (lex->tok.ttype == TOKEN_INTCONST)
+            if (lex->tok.ttype == Token::INTCONST)
                 lex->tok.constval.i = -lex->tok.constval.i;
             else
                 lex->tok.constval.f = -lex->tok.constval.f;
@@ -1263,27 +1255,27 @@ int lex_do(lex_file *lex)
         }
 
         lex_endtoken(lex);
-        return (lex->tok.ttype = TOKEN_OPERATOR);
+        return (lex->tok.ttype = Token::OPERATOR);
     }
 
-    if (ch == '*' || ch == '/') /* *=, /= */
+    if (ch == Token::MUL || ch == Token::DIV) /* *=, /= */
     {
         lex_tokench(lex, ch);
 
         nextch = lex_getch(lex);
-        if (nextch == '=' || nextch == '*') {
+        if (nextch == Token::EQ || nextch == Token::MUL) {
             lex_tokench(lex, nextch);
         } else
             lex_ungetch(lex, nextch);
 
         lex_endtoken(lex);
-        return (lex->tok.ttype = TOKEN_OPERATOR);
+        return (lex->tok.ttype = Token::OPERATOR);
     }
 
-    if (ch == '%') {
+    if (ch == Token::MOD) {
         lex_tokench(lex, ch);
         lex_endtoken(lex);
-        return (lex->tok.ttype = TOKEN_OPERATOR);
+        return (lex->tok.ttype = Token::OPERATOR);
     }
 
     if (isident_start(ch))
@@ -1293,42 +1285,42 @@ int lex_do(lex_file *lex)
         lex_tokench(lex, ch);
         if (!lex_finish_ident(lex)) {
             /* error? */
-            return (lex->tok.ttype = TOKEN_ERROR);
+            return (lex->tok.ttype = Token::ERROR);
         }
         lex_endtoken(lex);
-        lex->tok.ttype = TOKEN_IDENT;
+        lex->tok.ttype = Token::IDENT;
 
         v = lex->tok.value;
         if (!strcmp(v, "void")) {
-            lex->tok.ttype = TOKEN_TYPENAME;
+            lex->tok.ttype = Token::TYPENAME;
             lex->tok.constval.t = TYPE_VOID;
         } else if (!strcmp(v, "int")) {
-            lex->tok.ttype = TOKEN_TYPENAME;
+            lex->tok.ttype = Token::TYPENAME;
             lex->tok.constval.t = TYPE_INTEGER;
         } else if (!strcmp(v, "float")) {
-            lex->tok.ttype = TOKEN_TYPENAME;
+            lex->tok.ttype = Token::TYPENAME;
             lex->tok.constval.t = TYPE_FLOAT;
         } else if (!strcmp(v, "string")) {
-            lex->tok.ttype = TOKEN_TYPENAME;
+            lex->tok.ttype = Token::TYPENAME;
             lex->tok.constval.t = TYPE_STRING;
         } else if (!strcmp(v, "entity")) {
-            lex->tok.ttype = TOKEN_TYPENAME;
+            lex->tok.ttype = Token::TYPENAME;
             lex->tok.constval.t = TYPE_ENTITY;
         } else if (!strcmp(v, "vector")) {
-            lex->tok.ttype = TOKEN_TYPENAME;
+            lex->tok.ttype = Token::TYPENAME;
             lex->tok.constval.t = TYPE_VECTOR;
         } else if (!strcmp(v, "_length")) {
-            lex->tok.ttype = TOKEN_OPERATOR;
+            lex->tok.ttype = Token::OPERATOR;
         } else {
             size_t kw;
             for (kw = 0; kw < GMQCC_ARRAY_COUNT(keywords_qc); ++kw) {
                 if (!strcmp(v, keywords_qc[kw]))
-                    return (lex->tok.ttype = TOKEN_KEYWORD);
+                    return (lex->tok.ttype = Token::KEYWORD);
             }
             if (OPTS_OPTION_U32(OPTION_STANDARD) != COMPILER_QCC) {
                 for (kw = 0; kw < GMQCC_ARRAY_COUNT(keywords_fg); ++kw) {
                     if (!strcmp(v, keywords_fg[kw]))
-                        return (lex->tok.ttype = TOKEN_KEYWORD);
+                        return (lex->tok.ttype = Token::KEYWORD);
                 }
             }
         }
@@ -1336,52 +1328,52 @@ int lex_do(lex_file *lex)
         return lex->tok.ttype;
     }
 
-    if (ch == '"')
+    if (ch == Token::QUOT_DOUBLE)
     {
         lex->flags.nodigraphs = true;
         if (lex->flags.preprocessing)
             lex_tokench(lex, ch);
-        lex->tok.ttype = lex_finish_string(lex, '"');
+        lex->tok.ttype = lex_finish_string(lex, Token::QUOT_DOUBLE);
         if (lex->flags.preprocessing)
             lex_tokench(lex, ch);
-        while (!lex->flags.preprocessing && lex->tok.ttype == TOKEN_STRINGCONST)
+        while (!lex->flags.preprocessing && lex->tok.ttype == Token::STRINGCONST)
         {
             /* Allow c style "string" "continuation" */
             ch = lex_skipwhite(lex, false);
-            if (ch != '"') {
+            if (ch != Token::QUOT_DOUBLE) {
                 lex_ungetch(lex, ch);
                 break;
             }
 
-            lex->tok.ttype = lex_finish_string(lex, '"');
+            lex->tok.ttype = lex_finish_string(lex, Token::QUOT_DOUBLE);
         }
         lex->flags.nodigraphs = false;
         lex_endtoken(lex);
         return lex->tok.ttype;
     }
 
-    if (ch == '\'')
+    if (ch == Token::QUOT_SINGLE)
     {
         /* we parse character constants like string,
-         * but return TOKEN_CHARCONST, or a vector type if it fits...
+         * but return Token::CHARCONST, or a vector type if it fits...
          * Likewise actual unescaping has to be done by the parser.
          * The difference is we don't allow 'char' 'continuation'.
          */
         if (lex->flags.preprocessing)
             lex_tokench(lex, ch);
-        lex->tok.ttype = lex_finish_string(lex, '\'');
+        lex->tok.ttype = lex_finish_string(lex, Token::QUOT_SINGLE);
         if (lex->flags.preprocessing)
             lex_tokench(lex, ch);
         lex_endtoken(lex);
 
-        lex->tok.ttype = TOKEN_CHARCONST;
+        lex->tok.ttype = Token::CHARCONST;
 
         /* It's a vector if we can successfully scan 3 floats */
         if (util_sscanf(lex->tok.value, " %f %f %f ",
                    &lex->tok.constval.v.x, &lex->tok.constval.v.y, &lex->tok.constval.v.z) == 3)
 
         {
-             lex->tok.ttype = TOKEN_VECTORCONST;
+             lex->tok.ttype = Token::VECTORCONST;
         }
         else
         {
@@ -1393,7 +1385,7 @@ int lex_do(lex_file *lex)
                                 ( OPTS_FLAG(UTF8) ? "invalid multibyte character sequence `%s`"
                                                   : "multibyte character: `%s`" ),
                                 lex->tok.value))
-                        return (lex->tok.ttype = TOKEN_ERROR);
+                        return (lex->tok.ttype = Token::ERROR);
                 }
                 else
                     lex->tok.constval.i = u8char;
@@ -1413,11 +1405,11 @@ int lex_do(lex_file *lex)
     }
 
     if (lex->flags.preprocessing) {
-        lex_tokench(lex, ch);
+        lex_tokench(lex, static_cast<int>(ch));
         lex_endtoken(lex);
         return (lex->tok.ttype = ch);
     }
 
     lexerror(lex, "unknown token: `%c`", ch);
-    return (lex->tok.ttype = TOKEN_ERROR);
+    return (lex->tok.ttype = Token::ERROR);
 }
diff --git a/lexer.h b/lexer.h
index 8ed85a97ab39607494378f048cd1ad4429d29d91..94db3d28bbc26dce4b9b7cd2624b0b5d546b4358 100644 (file)
--- a/lexer.h
+++ b/lexer.h
 #define GMQCC_LEXER_HDR
 #include "gmqcc.h"
 
-struct token {
-    int ttype;
-    char *value;
-    union {
-        vec3_t v;
-        int i;
-        qcfloat_t f;
-        qc_type t; /* type */
-    } constval;
-    lex_ctx_t ctx;
-};
-
 /* Lexer
  *
  */
-enum {
+enum Token : int { // todo: enum class
     /* Other tokens which we can return: */
-    TOKEN_NONE = 0,
-    TOKEN_START = 128,
+    NONE = 0,
+
+    CR = '\r',
+    LF = '\n',
+    WS = ' ',
+    BACKSLASH = '\\',
+
+    HASH = '#',
+    DOLLAR = '$',
+
+    DOT = '.',
+    COMMA = ',',
+    COLON = ':',
+    SEMICOLON = ';',
+
+    AND = '&',
+    OR = '|',
+    XOR = '^',
+    BITNOT = '~',
+    NOT = '!',
+
+    LT = '<',
+    GT = '>',
+    EQ = '=',
 
-    TOKEN_IDENT,
+    MUL = '*',
+    DIV = '/',
+    MOD = '%',
 
-    TOKEN_TYPENAME,
+    ADD = '+',
+    SUB = '-',
 
-    TOKEN_OPERATOR,
+    QUOT_SINGLE = '\'',
+    QUOT_DOUBLE = '"',
 
-    TOKEN_KEYWORD, /* loop */
+    QUESTION = '?',
 
-    TOKEN_DOTS, /* 3 dots, ... */
+    BRACE_OPEN = '{', BRACE_CLOSE = '}',
+    BRACKET_OPEN = '[', BRACKET_CLOSE = ']',
+    PAREN_OPEN = '(', PAREN_CLOSE = ')',
 
-    TOKEN_ATTRIBUTE_OPEN,  /* [[ */
-    TOKEN_ATTRIBUTE_CLOSE, /* ]] */
+    START = 128,
 
-    TOKEN_VA_ARGS, /* for the ftepp only */
-    TOKEN_VA_ARGS_ARRAY, /* for the ftepp only */
-    TOKEN_VA_COUNT,     /* to get the count of vaargs */
+    IDENT,
 
-    TOKEN_STRINGCONST, /* not the typename but an actual "string" */
-    TOKEN_CHARCONST,
-    TOKEN_VECTORCONST,
-    TOKEN_INTCONST,
-    TOKEN_FLOATCONST,
+    TYPENAME,
 
-    TOKEN_WHITE,
-    TOKEN_EOL,
+    OPERATOR,
+
+    KEYWORD, /* loop */
+
+    DOTS, /* 3 dots, ... */
+
+    ATTRIBUTE_OPEN,  /* [[ */
+    ATTRIBUTE_CLOSE, /* ]] */
+
+    VA_ARGS, /* for the ftepp only */
+    VA_ARGS_ARRAY, /* for the ftepp only */
+    VA_COUNT,     /* to get the count of vaargs */
+
+    STRINGCONST, /* not the typename but an actual "string" */
+    CHARCONST,
+    VECTORCONST,
+    INTCONST,
+    FLOATCONST,
+
+    WHITE,
+    EOL,
 
     /* if we add additional tokens before this, the exposed API
      * should not be broken anyway, but EOF/ERROR/... should
      * still be at the bottom
      */
-    TOKEN_EOF = 1024,
+    END = 1024,
 
-    /* We use '< TOKEN_ERROR', so TOKEN_FATAL must come after it and any
+    /* We use '< ERROR', so FATAL must come after it and any
      * other error related tokens as well
      */
-    TOKEN_ERROR,
-    TOKEN_FATAL /* internal error, eg out of memory */
+    ERROR,
+    FATAL /* internal error, eg out of memory */
+};
+
+struct token {
+    Token ttype;
+    char *value;
+    union {
+        vec3_t v;
+        int i;
+        qcfloat_t f;
+        qc_type t; /* type */
+    } constval;
+    lex_ctx_t ctx;
 };
 
 struct frame_macro {
@@ -77,7 +117,7 @@ struct lex_file {
     size_t  sline; /* line at the start of a token */
     size_t  column;
 
-    int     peek[256];
+    Token   peek[256];
     size_t  peekpos;
 
     bool    eof;
@@ -101,7 +141,7 @@ struct lex_file {
 lex_file* lex_open (const char *file);
 lex_file* lex_open_string(const char *str, size_t len, const char *name);
 void      lex_close(lex_file   *lex);
-int       lex_do   (lex_file   *lex);
+Token     lex_do   (lex_file   *lex);
 void      lex_cleanup(void);
 
 /* Parser
index c35fd73e2fb23a7752b091993dc021dfce174043..c5014a21fa9f1cf46966f9e56d94316b3509207c 100644 (file)
--- a/opts.cpp
+++ b/opts.cpp
@@ -2,6 +2,7 @@
 #include <stdlib.h>
 
 #include "gmqcc.h"
+#include "lexer.h"
 
 const unsigned int opts_opt_oflag[COUNT_OPTIMIZATIONS+1] = {
 # define GMQCC_TYPE_OPTIMIZATIONS
@@ -210,7 +211,7 @@ static size_t opts_ini_parse (
     char *read_name;
     char *read_value;
 
-    while (util_getline(&line, &linesize, filehandle) != EOF) {
+    while (util_getline(&line, &linesize, filehandle) != Token::END) {
         parse_beg = line;
 
         /* handle BOM */
index 3eefe10ea35b491e3a3e73e05e25b4c52de37bd0..b2957d4ee5294b2cd6e4d93ac986ae76f8db4cd3 100644 (file)
@@ -65,9 +65,9 @@ static bool parser_next(parser_t &parser)
 {
     /* lex_do kills the previous token */
     parser.tok = lex_do(parser.lex);
-    if (parser.tok == TOKEN_EOF)
+    if (parser.tok == Token::END)
         return true;
-    if (parser.tok >= TOKEN_ERROR) {
+    if (parser.tok >= Token::ERROR) {
         parseerror(parser, "lex error");
         return false;
     }
@@ -77,17 +77,6 @@ static bool parser_next(parser_t &parser)
 #define parser_tokval(p) ((p).lex->tok.value)
 #define parser_token(p)  (&((p).lex->tok))
 
-char *parser_strdup(const char *str)
-{
-    if (str && !*str) {
-        /* actually dup empty strings */
-        char *out = (char*)mem_a(1);
-        *out = 0;
-        return out;
-    }
-    return util_strdup(str);
-}
-
 static ast_expression* parser_find_field(parser_t &parser, const char *name) {
     return (ast_expression*)util_htget(parser.htfields, name);
 }
@@ -1427,11 +1416,11 @@ static bool parser_close_paren(parser_t &parser, shunt *sy)
 static void parser_reclassify_token(parser_t &parser)
 {
     size_t i;
-    if (parser.tok >= TOKEN_START)
+    if (parser.tok >= Token::START)
         return;
     for (i = 0; i < operator_count; ++i) {
         if (!strcmp(parser_tokval(parser), operators[i].op)) {
-            parser.tok = TOKEN_OPERATOR;
+            parser.tok = Token::OPERATOR;
             return;
         }
     }
@@ -1473,7 +1462,7 @@ static ast_expression* parse_vararg_do(parser_t &parser)
         return out;
     }
 
-    if (!parser_next(parser) || (parser.tok != TOKEN_IDENT && parser.tok != TOKEN_TYPENAME)) {
+    if (!parser_next(parser) || (parser.tok != Token::IDENT && parser.tok != Token::TYPENAME)) {
         ast_unref(idx);
         parseerror(parser, "expected typename for vararg");
         return nullptr;
@@ -1528,7 +1517,7 @@ bool ftepp_predef_exists(const char *name);
 static bool parse_sya_operand(parser_t &parser, shunt *sy, bool with_labels)
 {
     if (OPTS_FLAG(TRANSLATABLE_STRINGS) &&
-        parser.tok == TOKEN_IDENT &&
+        parser.tok == Token::IDENT &&
         !strcmp(parser_tokval(parser), "_"))
     {
         /* a translatable string */
@@ -1540,7 +1529,7 @@ static bool parse_sya_operand(parser_t &parser, shunt *sy, bool with_labels)
             return false;
         }
         parser.lex->flags.noops = false;
-        if (!parser_next(parser) || parser.tok != TOKEN_STRINGCONST) {
+        if (!parser_next(parser) || parser.tok != Token::STRINGCONST) {
             parseerror(parser, "expected a constant string in translatable-string extension");
             return false;
         }
@@ -1555,7 +1544,7 @@ static bool parse_sya_operand(parser_t &parser, shunt *sy, bool with_labels)
         }
         return true;
     }
-    else if (parser.tok == TOKEN_DOTS)
+    else if (parser.tok == Token::DOTS)
     {
         ast_expression *va;
         if (!OPTS_FLAG(VARIADIC_ARGS)) {
@@ -1568,35 +1557,35 @@ static bool parse_sya_operand(parser_t &parser, shunt *sy, bool with_labels)
         sy->out.push_back(syexp(parser_ctx(parser), va));
         return true;
     }
-    else if (parser.tok == TOKEN_FLOATCONST) {
+    else if (parser.tok == Token::FLOATCONST) {
         ast_expression *val = parser.m_fold.constgen_float((parser_token(parser)->constval.f), false);
         if (!val)
             return false;
         sy->out.push_back(syexp(parser_ctx(parser), val));
         return true;
     }
-    else if (parser.tok == TOKEN_INTCONST || parser.tok == TOKEN_CHARCONST) {
+    else if (parser.tok == Token::INTCONST || parser.tok == Token::CHARCONST) {
         ast_expression *val = parser.m_fold.constgen_float((qcfloat_t)(parser_token(parser)->constval.i), false);
         if (!val)
             return false;
         sy->out.push_back(syexp(parser_ctx(parser), val));
         return true;
     }
-    else if (parser.tok == TOKEN_STRINGCONST) {
+    else if (parser.tok == Token::STRINGCONST) {
         ast_expression *val = parser.m_fold.constgen_string(parser_tokval(parser), false);
         if (!val)
             return false;
         sy->out.push_back(syexp(parser_ctx(parser), val));
         return true;
     }
-    else if (parser.tok == TOKEN_VECTORCONST) {
+    else if (parser.tok == Token::VECTORCONST) {
         ast_expression *val = parser.m_fold.constgen_vector(parser_token(parser)->constval.v);
         if (!val)
             return false;
         sy->out.push_back(syexp(parser_ctx(parser), val));
         return true;
     }
-    else if (parser.tok == TOKEN_IDENT)
+    else if (parser.tok == Token::IDENT)
     {
         const char     *ctoken = parser_tokval(parser);
         ast_expression *prev = sy->out.size() ? sy->out.back().out : nullptr;
@@ -1713,12 +1702,12 @@ static ast_expression* parse_expression_leave(parser_t &parser, bool stopatcomma
 
     while (true)
     {
-        if (parser.tok == TOKEN_TYPENAME) {
+        if (parser.tok == Token::TYPENAME) {
             parseerror(parser, "unexpected typename `%s`", parser_tokval(parser));
             goto onerr;
         }
 
-        if (parser.tok == TOKEN_OPERATOR)
+        if (parser.tok == Token::OPERATOR)
         {
             /* classify the operator */
             const oper_info *op;
@@ -1742,13 +1731,13 @@ static ast_expression* parse_expression_leave(parser_t &parser, bool stopatcomma
             /* when declaring variables, a comma starts a new variable */
             if (op->id == opid1(',') && sy.paren.empty() && stopatcomma) {
                 /* fixup the token */
-                parser.tok = ',';
+                parser.tok = Token::COMMA;
                 break;
             }
 
             /* a colon without a pervious question mark cannot be a ternary */
             if (!ternaries && op->id == opid2(':','?')) {
-                parser.tok = ':';
+                parser.tok = Token::COLON;
                 break;
             }
 
@@ -1924,7 +1913,7 @@ static ast_expression* parse_expression_leave(parser_t &parser, bool stopatcomma
         else {
             /* in this case we might want to allow constant string concatenation */
             bool concatenated = false;
-            if (parser.tok == TOKEN_STRINGCONST && sy.out.size()) {
+            if (parser.tok == Token::STRINGCONST && sy.out.size()) {
                 ast_expression *lexpr = sy.out.back().out;
                 if (ast_istype(lexpr, ast_value)) {
                     ast_value *last = (ast_value*)lexpr;
@@ -2130,7 +2119,7 @@ static bool parse_if(parser_t &parser, ast_block *block, ast_expression **out)
         parseerror(parser, "expected condition or 'not'");
         return false;
     }
-    if (parser.tok == TOKEN_IDENT && !strcmp(parser_tokval(parser), "not")) {
+    if (parser.tok == Token::IDENT && !strcmp(parser_tokval(parser), "not")) {
         ifnot = true;
         if (!parser_next(parser)) {
             parseerror(parser, "expected condition in parenthesis");
@@ -2217,7 +2206,7 @@ static bool parse_while(parser_t &parser, ast_block *block, ast_expression **out
     if (parser.tok == ':') {
         if (!OPTS_FLAG(LOOP_LABELS))
             parseerror(parser, "labeled loops not activated, try using -floop-labels");
-        if (!parser_next(parser) || parser.tok != TOKEN_IDENT) {
+        if (!parser_next(parser) || parser.tok != Token::IDENT) {
             parseerror(parser, "expected loop label");
             return false;
         }
@@ -2318,7 +2307,7 @@ static bool parse_dowhile(parser_t &parser, ast_block *block, ast_expression **o
     if (parser.tok == ':') {
         if (!OPTS_FLAG(LOOP_LABELS))
             parseerror(parser, "labeled loops not activated, try using -floop-labels");
-        if (!parser_next(parser) || parser.tok != TOKEN_IDENT) {
+        if (!parser_next(parser) || parser.tok != Token::IDENT) {
             parseerror(parser, "expected loop label");
             return false;
         }
@@ -2364,7 +2353,7 @@ static bool parse_dowhile_go(parser_t &parser, ast_block *block, ast_expression
         return false;
 
     /* expect the "while" */
-    if (parser.tok != TOKEN_KEYWORD ||
+    if (parser.tok != Token::KEYWORD ||
         strcmp(parser_tokval(parser), "while"))
     {
         parseerror(parser, "expected 'while' and condition");
@@ -2438,7 +2427,7 @@ static bool parse_for(parser_t &parser, ast_block *block, ast_expression **out)
     if (parser.tok == ':') {
         if (!OPTS_FLAG(LOOP_LABELS))
             parseerror(parser, "labeled loops not activated, try using -floop-labels");
-        if (!parser_next(parser) || parser.tok != TOKEN_IDENT) {
+        if (!parser_next(parser) || parser.tok != Token::IDENT) {
             parseerror(parser, "expected loop label");
             return false;
         }
@@ -2497,10 +2486,10 @@ static bool parse_for_go(parser_t &parser, ast_block *block, ast_expression **ou
     }
 
     typevar = nullptr;
-    if (parser.tok == TOKEN_IDENT)
+    if (parser.tok == Token::IDENT)
         typevar = parser_find_typedef(parser, parser_tokval(parser), 0);
 
-    if (typevar || parser.tok == TOKEN_TYPENAME) {
+    if (typevar || parser.tok == Token::TYPENAME) {
         if (!parse_variable(parser, block, true, CV_VAR, typevar, false, false, 0, nullptr))
             goto onerr;
     }
@@ -2709,7 +2698,7 @@ static bool parse_break_continue(parser_t &parser, ast_block *block, ast_express
             parseerror(parser, "`break` can only be used inside loops or switches");
     }
 
-    if (parser.tok == TOKEN_IDENT) {
+    if (parser.tok == Token::IDENT) {
         if (!OPTS_FLAG(LOOP_LABELS))
             parseerror(parser, "labeled loops not activated, try using -floop-labels");
         i = loops.size();
@@ -2771,7 +2760,7 @@ static bool parse_qualifiers(parser_t &parser, bool with_local, int *cvq, bool *
 
     for (;;) {
         size_t i;
-        if (parser.tok == TOKEN_ATTRIBUTE_OPEN) {
+        if (parser.tok == Token::ATTRIBUTE_OPEN) {
             had_attrib = true;
             /* parse an attribute */
             if (!parser_next(parser)) {
@@ -2783,7 +2772,7 @@ static bool parse_qualifiers(parser_t &parser, bool with_local, int *cvq, bool *
             for (i = 0; i < GMQCC_ARRAY_COUNT(attributes); i++) {
                 if (!strcmp(parser_tokval(parser), attributes[i].name)) {
                     flags |= attributes[i].flag;
-                    if (!parser_next(parser) || parser.tok != TOKEN_ATTRIBUTE_CLOSE) {
+                    if (!parser_next(parser) || parser.tok != Token::ATTRIBUTE_CLOSE) {
                         parseerror(parser, "`%s` attribute has no parameters, expected `]]`",
                             attributes[i].name);
                         *cvq = CV_WRONG;
@@ -2799,7 +2788,7 @@ static bool parse_qualifiers(parser_t &parser, bool with_local, int *cvq, bool *
 
             if (!strcmp(parser_tokval(parser), "noref")) {
                 had_noref = true;
-                if (!parser_next(parser) || parser.tok != TOKEN_ATTRIBUTE_CLOSE) {
+                if (!parser_next(parser) || parser.tok != Token::ATTRIBUTE_CLOSE) {
                     parseerror(parser, "`noref` attribute has no parameters, expected `]]`");
                     *cvq = CV_WRONG;
                     return false;
@@ -2815,7 +2804,7 @@ static bool parse_qualifiers(parser_t &parser, bool with_local, int *cvq, bool *
                 }
 
                 if (parser.tok == '(') {
-                    if (!parser_next(parser) || parser.tok != TOKEN_STRINGCONST) {
+                    if (!parser_next(parser) || parser.tok != Token::STRINGCONST) {
                         parseerror(parser, "`alias` attribute missing parameter");
                         goto argerr;
                     }
@@ -2838,7 +2827,7 @@ static bool parse_qualifiers(parser_t &parser, bool with_local, int *cvq, bool *
                     }
                 }
 
-                if (parser.tok != TOKEN_ATTRIBUTE_CLOSE) {
+                if (parser.tok != Token::ATTRIBUTE_CLOSE) {
                     parseerror(parser, "`alias` attribute expected `]]`");
                     goto argerr;
                 }
@@ -2853,7 +2842,7 @@ static bool parse_qualifiers(parser_t &parser, bool with_local, int *cvq, bool *
                 }
 
                 if (parser.tok == '(') {
-                    if (!parser_next(parser) || parser.tok != TOKEN_STRINGCONST) {
+                    if (!parser_next(parser) || parser.tok != Token::STRINGCONST) {
                         parseerror(parser, "`deprecated` attribute missing parameter");
                         goto argerr;
                     }
@@ -2876,7 +2865,7 @@ static bool parse_qualifiers(parser_t &parser, bool with_local, int *cvq, bool *
                     }
                 }
                 /* no message */
-                if (parser.tok != TOKEN_ATTRIBUTE_CLOSE) {
+                if (parser.tok != Token::ATTRIBUTE_CLOSE) {
                     parseerror(parser, "`deprecated` attribute expected `]]`");
 
                     argerr: /* ugly */
@@ -2904,7 +2893,7 @@ static bool parse_qualifiers(parser_t &parser, bool with_local, int *cvq, bool *
                     }
                     if (parser.tok != ')') {
                         do {
-                            if (parser.tok != TOKEN_IDENT)
+                            if (parser.tok != Token::IDENT)
                                 goto bad_coverage_arg;
                             if (!strcmp(parser_tokval(parser), "block"))
                                 flags |= AST_FLAG_BLOCK_COVERAGE;
@@ -2931,7 +2920,7 @@ static bool parse_qualifiers(parser_t &parser, bool with_local, int *cvq, bool *
             {
                 /* Skip tokens until we hit a ]] */
                 (void)!parsewarning(parser, WARN_UNKNOWN_ATTRIBUTE, "unknown attribute starting with `%s`", parser_tokval(parser));
-                while (parser.tok != TOKEN_ATTRIBUTE_CLOSE) {
+                while (parser.tok != Token::ATTRIBUTE_CLOSE) {
                     if (!parser_next(parser)) {
                         parseerror(parser, "error inside attribute");
                         *cvq = CV_WRONG;
@@ -2994,7 +2983,7 @@ static bool parse_switch(parser_t &parser, ast_block *block, ast_expression **ou
     if (parser.tok == ':') {
         if (!OPTS_FLAG(LOOP_LABELS))
             parseerror(parser, "labeled loops not activated, try using -floop-labels");
-        if (!parser_next(parser) || parser.tok != TOKEN_IDENT) {
+        if (!parser_next(parser) || parser.tok != Token::IDENT) {
             parseerror(parser, "expected loop label");
             return false;
         }
@@ -3081,9 +3070,9 @@ static bool parse_switch_go(parser_t &parser, ast_block *block, ast_expression *
     parser_enterblock(parser);
     while (true) {
         typevar = nullptr;
-        if (parser.tok == TOKEN_IDENT)
+        if (parser.tok == Token::IDENT)
             typevar = parser_find_typedef(parser, parser_tokval(parser), 0);
-        if (typevar || parser.tok == TOKEN_TYPENAME) {
+        if (typevar || parser.tok == Token::TYPENAME) {
             if (!parse_variable(parser, block, true, CV_NONE, typevar, false, false, 0, nullptr)) {
                 delete switchnode;
                 return false;
@@ -3215,7 +3204,7 @@ static bool parse_switch_go(parser_t &parser, ast_block *block, ast_expression *
             ast_expression *expr;
             if (parser.tok == '}')
                 break;
-            if (parser.tok == TOKEN_KEYWORD) {
+            if (parser.tok == Token::KEYWORD) {
                 if (!strcmp(parser_tokval(parser), "case") ||
                     !strcmp(parser_tokval(parser), "default"))
                 {
@@ -3295,7 +3284,7 @@ static bool parse_goto(parser_t &parser, ast_expression **out)
     if (!parser_next(parser))
         return false;
 
-    if (parser.tok != TOKEN_IDENT) {
+    if (parser.tok != Token::IDENT) {
         ast_expression *expression;
 
         /* could be an expression i.e computed goto :-) */
@@ -3348,33 +3337,33 @@ static bool parse_skipwhite(parser_t &parser)
     do {
         if (!parser_next(parser))
             return false;
-    } while (parser.tok == TOKEN_WHITE && parser.tok < TOKEN_ERROR);
-    return parser.tok < TOKEN_ERROR;
+    } while (parser.tok == Token::WHITE && parser.tok < Token::ERROR);
+    return parser.tok < Token::ERROR;
 }
 
 static bool parse_eol(parser_t &parser)
 {
     if (!parse_skipwhite(parser))
         return false;
-    return parser.tok == TOKEN_EOL;
+    return parser.tok == Token::EOL;
 }
 
 static bool parse_pragma_do(parser_t &parser)
 {
     if (!parser_next(parser) ||
-        parser.tok != TOKEN_IDENT ||
+        parser.tok != Token::IDENT ||
         strcmp(parser_tokval(parser), "pragma"))
     {
         parseerror(parser, "expected `pragma` keyword after `#`, got `%s`", parser_tokval(parser));
         return false;
     }
-    if (!parse_skipwhite(parser) || parser.tok != TOKEN_IDENT) {
+    if (!parse_skipwhite(parser) || parser.tok != Token::IDENT) {
         parseerror(parser, "expected pragma, got `%s`", parser_tokval(parser));
         return false;
     }
 
     if (!strcmp(parser_tokval(parser), "noref")) {
-        if (!parse_skipwhite(parser) || parser.tok != TOKEN_INTCONST) {
+        if (!parse_skipwhite(parser) || parser.tok != Token::INTCONST) {
             parseerror(parser, "`noref` pragma requires an argument: 0 or 1");
             return false;
         }
@@ -3404,7 +3393,7 @@ static bool parse_pragma(parser_t &parser)
     parser.lex->flags.preprocessing = true;
     parser.lex->flags.mergelines = true;
     auto ret = parse_pragma_do(parser);
-    if (parser.tok != TOKEN_EOL) {
+    if (parser.tok != Token::EOL) {
         parseerror(parser, "junk after pragma");
         ret = false;
     }
@@ -3427,10 +3416,10 @@ static bool parse_statement(parser_t &parser, ast_block *block, ast_expression *
 
     *out = nullptr;
 
-    if (parser.tok == TOKEN_IDENT)
+    if (parser.tok == Token::IDENT)
         typevar = parser_find_typedef(parser, parser_tokval(parser), 0);
 
-    if (typevar || parser.tok == TOKEN_TYPENAME || parser.tok == '.' || parser.tok == TOKEN_DOTS)
+    if (typevar || parser.tok == Token::TYPENAME || parser.tok == '.' || parser.tok == Token::DOTS)
     {
         /* local variable */
         if (!block) {
@@ -3451,7 +3440,7 @@ static bool parse_statement(parser_t &parser, ast_block *block, ast_expression *
             return false;
         return parse_variable(parser, block, false, cvq, nullptr, noref, is_static, qflags, vstring);
     }
-    else if (parser.tok == TOKEN_KEYWORD)
+    else if (parser.tok == Token::KEYWORD)
     {
         if (!strcmp(parser_tokval(parser), "__builtin_debug_printtype"))
         {
@@ -3463,7 +3452,7 @@ static bool parse_statement(parser_t &parser, ast_block *block, ast_expression *
                 return false;
             }
 
-            if (parser.tok == TOKEN_IDENT && (tdef = parser_find_typedef(parser, parser_tokval(parser), 0)))
+            if (parser.tok == Token::IDENT && (tdef = parser_find_typedef(parser, parser_tokval(parser), 0)))
             {
                 ast_type_to_string(tdef, ty, sizeof(ty));
                 con_out("__builtin_debug_printtype: `%s`=`%s`\n", tdef->m_name.c_str(), ty);
@@ -3563,7 +3552,7 @@ static bool parse_statement(parser_t &parser, ast_block *block, ast_expression *
             parseerror(parser, "expected label name");
             return false;
         }
-        if (parser.tok != TOKEN_IDENT) {
+        if (parser.tok != Token::IDENT) {
             parseerror(parser, "label must be an identifier");
             return false;
         }
@@ -3634,7 +3623,7 @@ static bool parse_enum(parser_t &parser)
 
     /* enumeration attributes (can add more later) */
     if (parser.tok == ':') {
-        if (!parser_next(parser) || parser.tok != TOKEN_IDENT){
+        if (!parser_next(parser) || parser.tok != Token::IDENT){
             parseerror(parser, "expected `flag` or `reverse` for enumeration attribute");
             return false;
         }
@@ -3659,7 +3648,7 @@ static bool parse_enum(parser_t &parser)
     }
 
     while (true) {
-        if (!parser_next(parser) || parser.tok != TOKEN_IDENT) {
+        if (!parser_next(parser) || parser.tok != Token::IDENT) {
             if (parser.tok == '}') {
                 /* allow an empty enum */
                 break;
@@ -3758,7 +3747,7 @@ static bool parse_block_into(parser_t &parser, ast_block *block)
         goto cleanup;
     }
 
-    while (parser.tok != TOKEN_EOF && parser.tok < TOKEN_ERROR)
+    while (parser.tok != Token::END && parser.tok < Token::ERROR)
     {
         ast_expression *expr = nullptr;
         if (parser.tok == '}')
@@ -3923,7 +3912,7 @@ static bool parse_function_body(parser_t &parser, ast_value *var)
             return false;
         }
 
-        if (parser.tok == TOKEN_IDENT && !parser_find_var(parser, parser_tokval(parser)))
+        if (parser.tok == Token::IDENT && !parser_find_var(parser, parser_tokval(parser)))
         {
             /* qc allows the use of not-yet-declared functions here
              * - this automatically creates a prototype */
@@ -4634,11 +4623,11 @@ static ast_value *parse_parameter_list(parser_t &parser, ast_value *var)
         if (is_varargs) {
             /* '...' indicates a varargs function */
             variadic = true;
-            if (parser.tok != ')' && parser.tok != TOKEN_IDENT) {
+            if (parser.tok != ')' && parser.tok != Token::IDENT) {
                 parseerror(parser, "`...` must be the last parameter of a variadic function declaration");
                 goto on_error;
             }
-            if (parser.tok == TOKEN_IDENT) {
+            if (parser.tok == Token::IDENT) {
                 argcounter = util_strdup(parser_tokval(parser));
                 if (!parser_next(parser) || parser.tok != ')') {
                     parseerror(parser, "`...` must be the last parameter of a variadic function declaration");
@@ -4654,15 +4643,15 @@ static ast_value *parse_parameter_list(parser_t &parser, ast_value *var)
                 goto on_error;
             }
             /* type-restricted varargs */
-            if (parser.tok == TOKEN_DOTS) {
+            if (parser.tok == Token::DOTS) {
                 variadic = true;
                 varparam = params.back().release();
                 params.pop_back();
-                if (!parser_next(parser) || (parser.tok != ')' && parser.tok != TOKEN_IDENT)) {
+                if (!parser_next(parser) || (parser.tok != ')' && parser.tok != Token::IDENT)) {
                     parseerror(parser, "`...` must be the last parameter of a variadic function declaration");
                     goto on_error;
                 }
-                if (parser.tok == TOKEN_IDENT) {
+                if (parser.tok == Token::IDENT) {
                     argcounter = util_strdup(parser_tokval(parser));
                     param->m_name = argcounter;
                     if (!parser_next(parser) || parser.tok != ')') {
@@ -4808,14 +4797,14 @@ static ast_value *parse_typename(parser_t &parser, ast_value **storebase, ast_va
     bool        wasarray = false;
     size_t      morefields = 0;
 
-    bool        vararg = (parser.tok == TOKEN_DOTS);
+    bool        vararg = (parser.tok == Token::DOTS);
 
     ctx = parser_ctx(parser);
 
     /* types may start with a dot */
-    if (parser.tok == '.' || parser.tok == TOKEN_DOTS) {
+    if (parser.tok == '.' || parser.tok == Token::DOTS) {
         isfield = true;
-        if (parser.tok == TOKEN_DOTS)
+        if (parser.tok == Token::DOTS)
             morefields += 2;
         /* if we parsed a dot we need a typename now */
         if (!parser_next(parser)) {
@@ -4829,7 +4818,7 @@ static ast_value *parse_typename(parser_t &parser, ast_value **storebase, ast_va
         while (true) {
             if (parser.tok == '.')
                 ++morefields;
-            else if (parser.tok == TOKEN_DOTS)
+            else if (parser.tok == Token::DOTS)
                 morefields += 3;
             else
                 break;
@@ -4840,9 +4829,9 @@ static ast_value *parse_typename(parser_t &parser, ast_value **storebase, ast_va
             }
         }
     }
-    if (parser.tok == TOKEN_IDENT)
+    if (parser.tok == Token::IDENT)
         cached_typedef = parser_find_typedef(parser, parser_tokval(parser), 0);
-    if (!cached_typedef && parser.tok != TOKEN_TYPENAME) {
+    if (!cached_typedef && parser.tok != Token::TYPENAME) {
         if (vararg && is_vararg) {
             *is_vararg = true;
             return nullptr;
@@ -4898,10 +4887,10 @@ static ast_value *parse_typename(parser_t &parser, ast_value **storebase, ast_va
     }
 
     /* there may be a name now */
-    if (parser.tok == TOKEN_IDENT || parser.tok == TOKEN_KEYWORD) {
+    if (parser.tok == Token::IDENT || parser.tok == Token::KEYWORD) {
         if (!strcmp(parser_tokval(parser), "break"))
             (void)!parsewarning(parser, WARN_BREAKDEF, "break definition ignored (suggest removing it)");
-        else if (parser.tok == TOKEN_KEYWORD)
+        else if (parser.tok == Token::KEYWORD)
             goto leave;
 
         name = util_strdup(parser_tokval(parser));
@@ -5664,7 +5653,7 @@ skipvar:
 
                 /* we only want the integral part anyways */
                 builtin_num = integral;
-            } else if (parser.tok == TOKEN_INTCONST) {
+            } else if (parser.tok == Token::INTCONST) {
                 builtin_num = parser_token(parser)->constval.i;
             } else {
                 parseerror(parser, "builtin number must be a compile time constant");
@@ -5832,7 +5821,7 @@ another:
                 break;
             }
 
-            if (parser.tok != TOKEN_IDENT) {
+            if (parser.tok != Token::IDENT) {
                 parseerror(parser, "expected another variable");
                 break;
             }
@@ -5878,9 +5867,9 @@ cleanup:
 static bool parser_global_statement(parser_t &parser)
 {
     ast_value *istype    = nullptr;
-    if ((parser.tok == TOKEN_IDENT && (istype = parser_find_typedef(parser, parser_tokval(parser), 0)) != nullptr)
-        || parser.tok == TOKEN_TYPENAME
-        || parser.tok == '.' || parser.tok == TOKEN_DOTS) {
+    if ((parser.tok == Token::IDENT && (istype = parser_find_typedef(parser, parser_tokval(parser), 0)) != nullptr)
+        || parser.tok == Token::TYPENAME
+        || parser.tok == '.' || parser.tok == Token::DOTS) {
         return parse_variable(parser, nullptr, false, CV_NONE, istype, false, false, 0, nullptr);
     }
 
@@ -5895,11 +5884,11 @@ static bool parser_global_statement(parser_t &parser)
         return parse_variable(parser, nullptr, false, cvq, nullptr, noref, is_static, qflags, vstring);
     }
 
-    if (parser.tok == TOKEN_IDENT && strcmp(parser_tokval(parser), "enum") == 0) {
+    if (parser.tok == Token::IDENT && strcmp(parser_tokval(parser), "enum") == 0) {
         return parse_enum(parser);
     }
 
-    if (parser.tok == TOKEN_KEYWORD) {
+    if (parser.tok == Token::KEYWORD) {
         if (strcmp(parser_tokval(parser), "typedef") == 0) {
             if (!parser_next(parser)) {
                 parseerror(parser, "expected type definition after 'typedef'");
@@ -6004,7 +5993,7 @@ static void generate_checksum(parser_t &parser, ir_builder &ir)
 
 parser_t::parser_t()
     : lex(nullptr)
-    , tok(0)
+    , tok(Token::NONE)
     , ast_cleaned(false)
     , translated(0)
     , crc_globals(0)
@@ -6083,9 +6072,9 @@ static bool parser_compile(parser_t &parser)
         compile_errors = true;
         goto cleanup;
     }
-    while (parser.tok != TOKEN_EOF && parser.tok < TOKEN_ERROR) {
+    while (parser.tok != Token::END && parser.tok < Token::ERROR) {
         if (parser_global_statement(parser)) continue;
-        if (parser.tok == TOKEN_EOF) {
+        if (parser.tok == Token::END) {
             parseerror(parser, "unexpected end of file");
         } else if (compile_errors) {
             parseerror(parser, "there have been errors, bailing out");
index 1e45de3c1c2876a34439976af7f2e97e4b0d40c0..4f227b6c2b664ea58e81a8130ce55e075e2801e8 100644 (file)
--- a/parser.h
+++ b/parser.h
@@ -7,8 +7,6 @@
 #include "intrin.h"
 #include "fold.h"
 
-struct parser_t;
-
 #define parser_ctx(p) ((p).lex->tok.ctx)
 
 struct parser_t {
@@ -18,7 +16,7 @@ struct parser_t {
     void remove_ast();
 
     lex_file *lex;
-    int tok;
+    Token tok;
 
     bool ast_cleaned;
 
@@ -76,9 +74,21 @@ struct parser_t {
     intrin m_intrin;
 };
 
-
 /* parser.c */
-char           *parser_strdup     (const char *str);
+inline char *parser_strdup(const char *str)
+{
+    if (str && !*str) {
+        /* actually dup empty strings */
+        auto *out = reinterpret_cast<char*>(mem_a(1));
+        *out = 0;
+        return out;
+    }
+    return util_strdup(str);
+}
 ast_expression *parser_find_global(parser_t &parser, const char *name);
+parser_t *parser_create();
+bool parser_compile_file(parser_t &parser, const char *);
+bool parser_compile_string(parser_t &parser, const char *, const char *, size_t);
+bool parser_finish(parser_t &parser, const char *);
 
 #endif