X-Git-Url: https://git.xonotic.org/?p=xonotic%2Fgmqcc.git;a=blobdiff_plain;f=parser.c;h=c6819223cb279d4233ff8af9db6de883d31469ca;hp=8f9d014b8bc241672fbfd881c09fea87ea96b1ce;hb=69b55ccc03b56af1f6c05eb45866ab198307487f;hpb=785ab7c07266d9872aceefc0b9ac63e550a688e3 diff --git a/parser.c b/parser.c index 8f9d014..c681922 100644 --- 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; @@ -1788,6 +1790,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 +1923,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 +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"); @@ -5654,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; } @@ -5678,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);