]> git.xonotic.org Git - xonotic/gmqcc.git/blobdiff - parser.c
gitignore: add gmqcc, gmqpak, qmcvm, testsuite, pak.
[xonotic/gmqcc.git] / parser.c
index c81fd2c4db714d9e410b726accbe3ca19321cf48..c6819223cb279d4233ff8af9db6de883d31469ca 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -266,6 +266,7 @@ static ast_value* parser_const_string(parser_t *parser, const char *str, bool do
             char name[32];
             util_snprintf(name, sizeof(name), "dotranslate_%lu", (unsigned long)(parser->translated++));
             ast_value_set_name(out, name);
+            out->expression.flags |= AST_FLAG_INCLUDE_DEF;
         }
         return out;
     }
@@ -279,6 +280,7 @@ static ast_value* parser_const_string(parser_t *parser, const char *str, bool do
         char name[32];
         util_snprintf(name, sizeof(name), "dotranslate_%lu", (unsigned long)(parser->translated++));
         out = ast_value_new(parser_ctx(parser), name, TYPE_STRING);
+        out->expression.flags |= AST_FLAG_INCLUDE_DEF;
     } else
         out = ast_value_new(parser_ctx(parser), "#IMMEDIATE", TYPE_STRING);
     out->cvq      = CV_CONST;
@@ -5639,7 +5641,11 @@ skipvar:
         }
 
         if (parser->tok == '#') {
-            ast_function *func = NULL;
+            ast_function *func   = NULL;
+            ast_value    *number = NULL;
+            float         fractional;
+            float         integral;
+            int           builtin_num;
 
             if (localblock) {
                 parseerror(parser, "cannot declare builtins within functions");
@@ -5653,12 +5659,42 @@ skipvar:
                 parseerror(parser, "expected builtin number");
                 break;
             }
-            if (parser->tok != TOKEN_INTCONST) {
-                parseerror(parser, "builtin number must be an integer constant");
-                break;
-            }
-            if (parser_token(parser)->constval.i < 0) {
-                parseerror(parser, "builtin number must be an integer greater than zero");
+
+            if (OPTS_FLAG(EXPRESSIONS_FOR_BUILTINS)) {
+                number = (ast_value*)parse_expression_leave(parser, true, false, false);
+                if (!number) {
+                    parseerror(parser, "builtin number expected");
+                    break;
+                }
+                if (!ast_istype(number, ast_value) || !number->hasvalue || number->cvq != CV_CONST)
+                {
+                    ast_unref(number);
+                    parseerror(parser, "builtin number must be a compile time constant");
+                    break;
+                }
+                if (number->expression.vtype == TYPE_INTEGER)
+                    builtin_num = number->constval.vint;
+                else if (number->expression.vtype == TYPE_FLOAT)
+                    builtin_num = number->constval.vfloat;
+                else {
+                    ast_unref(number);
+                    parseerror(parser, "builtin number must be an integer constant");
+                    break;
+                }
+                ast_unref(number);
+
+                fractional = modff(builtin_num, &integral);
+                if (builtin_num < 0 || fractional != 0) {
+                    parseerror(parser, "builtin number must be an integer greater than zero");
+                    break;
+                }
+
+                /* we only want the integral part anyways */
+                builtin_num = integral;
+            } else if (parser->tok == TOKEN_INTCONST) {
+                builtin_num = parser_token(parser)->constval.i;
+            } else {
+                parseerror(parser, "builtin number must be a compile time constant");
                 break;
             }
 
@@ -5677,10 +5713,13 @@ skipvar:
                 }
                 vec_push(parser->functions, func);
 
-                func->builtin = -parser_token(parser)->constval.i-1;
+                func->builtin = -builtin_num-1;
             }
 
-            if (!parser_next(parser)) {
+            if (OPTS_FLAG(EXPRESSIONS_FOR_BUILTINS)
+                    ? (parser->tok != ',' && parser->tok != ';')
+                    : (!parser_next(parser)))
+            {
                 parseerror(parser, "expected comma or semicolon");
                 if (func)
                     ast_function_delete(func);