X-Git-Url: https://git.xonotic.org/?p=xonotic%2Fgmqcc.git;a=blobdiff_plain;f=parser.c;h=7034e64c7314ede34e1d65878c7b71c746efa40e;hp=836f6ca663b82b4e6395b8bbddcc762e43ed992d;hb=aed2b1031c6466a2dbcf909faeac1ac1cff0f6e6;hpb=dc8523c6503e014a463df42520b48f597c7655be diff --git a/parser.c b/parser.c old mode 100755 new mode 100644 index 836f6ca..7034e64 --- a/parser.c +++ b/parser.c @@ -103,6 +103,9 @@ typedef struct parser_s { /* collected information */ size_t max_param_count; + + /* code generator */ + code_t *code; } parser_t; static ast_expression * const intrinsic_debug_typestring = (ast_expression*)0x1; @@ -217,6 +220,7 @@ static ast_value* parser_const_float(parser_t *parser, double d) out = ast_value_new(ctx, "#IMMEDIATE", TYPE_FLOAT); out->cvq = CV_CONST; out->hasvalue = true; + out->isimm = true; out->constval.vfloat = d; vec_push(parser->imm_float, out); return out; @@ -279,6 +283,7 @@ static ast_value* parser_const_string(parser_t *parser, const char *str, bool do out = ast_value_new(parser_ctx(parser), "#IMMEDIATE", TYPE_STRING); out->cvq = CV_CONST; out->hasvalue = true; + out->isimm = true; out->constval.vstring = parser_strdup(str); vec_push(parser->imm_string, out); util_htseth(parser->ht_imm_string, str, hash, out); @@ -296,6 +301,7 @@ static ast_value* parser_const_vector(parser_t *parser, vector v) out = ast_value_new(parser_ctx(parser), "#IMMEDIATE", TYPE_VECTOR); out->cvq = CV_CONST; out->hasvalue = true; + out->isimm = true; out->constval.vvec = v; vec_push(parser->imm_vector, out); return out; @@ -1782,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) && @@ -1888,6 +1897,8 @@ static bool parse_sya_operand(parser_t *parser, shunt *sy, bool with_labels) vec_push(parser->labels, lbl); } } + if (!var && !strcmp(parser_tokval(parser), "__FUNC__")) + var = (ast_expression*)parser_const_string(parser, parser->function->name, false); if (!var) { /* intrinsics */ if (!strcmp(parser_tokval(parser), "__builtin_debug_typestring")) { @@ -1899,8 +1910,6 @@ static bool parse_sya_operand(parser_t *parser, shunt *sy, bool with_labels) */ else if (!strncmp(parser_tokval(parser), "__builtin_", 10)) { var = intrin_func(parser, parser_tokval(parser) + 10 /* skip __builtin */); - } else { - var = intrin_func(parser, parser_tokval(parser)); } if (!var) { @@ -1912,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; } /* @@ -2182,8 +2187,27 @@ static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma wantop = true; } else { - parseerror(parser, "expected operator or end of statement"); - goto onerr; + /* in this case we might want to allow constant string concatenation */ + bool concatenated = false; + if (parser->tok == TOKEN_STRINGCONST && vec_size(sy.out)) { + ast_expression *lexpr = vec_last(sy.out).out; + if (ast_istype(lexpr, ast_value)) { + ast_value *last = (ast_value*)lexpr; + if (last->isimm == true && last->cvq == CV_CONST && + last->hasvalue && last->expression.vtype == TYPE_STRING) + { + char *newstr = NULL; + util_asprintf(&newstr, "%s%s", last->constval.vstring, parser_tokval(parser)); + vec_last(sy.out).out = (ast_expression*)parser_const_string(parser, newstr, false); + mem_d(newstr); + concatenated = true; + } + } + } + if (!concatenated) { + parseerror(parser, "expected operator or end of statement"); + goto onerr; + } } if (!parser_next(parser)) { @@ -5615,7 +5639,11 @@ skipvar: } if (parser->tok == '#') { - ast_function *func = NULL; + ast_function *func = NULL; + ast_value *number = NULL; + float fractional = 0; + float integral = 0; + int builtin_num = 0; if (localblock) { parseerror(parser, "cannot declare builtins within functions"); @@ -5629,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; } @@ -5653,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); @@ -5921,7 +5982,7 @@ static void generate_checksum(parser_t *parser) } crc = progdefs_crc_both(crc, "} entvars_t;\n\n"); - code_crc = crc; + parser->code->crc = crc; } parser_t *parser_create() @@ -5936,6 +5997,12 @@ parser_t *parser_create() memset(parser, 0, sizeof(*parser)); + if (!(parser->code = code_init())) { + mem_d(parser); + return NULL; + } + + for (i = 0; i < operator_count; ++i) { if (operators[i].id == opid1('=')) { parser->assign_op = operators+i; @@ -6291,7 +6358,7 @@ bool parser_finish(parser_t *parser, const char *output) generate_checksum(parser); - if (!ir_builder_generate(ir, output)) { + if (!ir_builder_generate(parser->code, ir, output)) { con_out("*** failed to generate output file\n"); ir_builder_delete(ir); return false;