]> git.xonotic.org Git - xonotic/gmqcc.git/blobdiff - parser.c
Pushing the -fexpressions-for-builtins stuff and the modff for catching fractional...
[xonotic/gmqcc.git] / parser.c
index 8f9d014b8bc241672fbfd881c09fea87ea96b1ce..14cf583647c0a79362691193440f75b0d8761572 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -1788,6 +1788,9 @@ static ast_expression* parse_vararg(parser_t *parser)
     return out;
 }
 
+/* not to be exposed */
+extern 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) &&
@@ -1918,13 +1921,9 @@ static bool parse_sya_operand(parser_t *parser, shunt *sy, bool with_labels)
                  * i've done this thousands of times already myself.  Lets check for
                  * it in the predef table.  And diagnose it better :)
                  */
-                if (!OPTS_FLAG(FTEPP_PREDEFS)) {
-                    for (i = 0; i < sizeof(ftepp_predefs)/sizeof(*ftepp_predefs); i++) {
-                        if (!strcmp(ftepp_predefs[i].name, parser_tokval(parser))) {
-                            parseerror(parser, "unexpected ident: %s (use -fftepp-predef to enable pre-defined macros)", parser_tokval(parser));
-                            return false;
-                        }
-                    }
+                if (!OPTS_FLAG(FTEPP_PREDEFS) && ftepp_predef_exists(parser_tokval(parser))) {
+                    parseerror(parser, "unexpected ident: %s (use -fftepp-predef to enable pre-defined macros)", parser_tokval(parser));
+                    return false;
                 }
 
                 /*
@@ -5640,7 +5639,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");
@@ -5654,12 +5657,40 @@ 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) {
+                parseerror(parser, "builtin number must be a compile time constant");
                 break;
             }
 
@@ -5678,10 +5709,15 @@ skipvar:
                 }
                 vec_push(parser->functions, func);
 
-                func->builtin = -parser_token(parser)->constval.i-1;
+                func->builtin = -((OPTS_FLAG(EXPRESSIONS_FOR_BUILTINS))
+                                    ? builtin_num
+                                    : parser_token(parser)->constval.i) - 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);