X-Git-Url: https://git.xonotic.org/?a=blobdiff_plain;f=parser.c;h=5cbdb16d80c508d8021727d3650006b78b85f1e3;hb=2c0a9d78df46286eb566a1e0fa06e4cfc7605ad2;hp=5e2b160b6b8c5de50267bb2ac53cc75de6458506;hpb=f6a374c1d5ace3470258c7c4f60261c7266b9e62;p=xonotic%2Fgmqcc.git diff --git a/parser.c b/parser.c index 5e2b160..5cbdb16 100644 --- a/parser.c +++ b/parser.c @@ -44,6 +44,7 @@ typedef struct { ast_value **imm_float; ast_value **imm_string; ast_value **imm_vector; + size_t translated; /* must be deleted first, they reference immediates and values */ ast_value **accessors; @@ -241,7 +242,7 @@ static char *parser_strdup(const char *str) return util_strdup(str); } -static ast_value* parser_const_string(parser_t *parser, const char *str) +static ast_value* parser_const_string(parser_t *parser, const char *str, bool dotranslate) { size_t i; ast_value *out; @@ -249,7 +250,12 @@ static ast_value* parser_const_string(parser_t *parser, const char *str) if (!strcmp(parser->imm_string[i]->constval.vstring, str)) return parser->imm_string[i]; } - out = ast_value_new(parser_ctx(parser), "#IMMEDIATE", TYPE_STRING); + if (dotranslate) { + char name[32]; + snprintf(name, sizeof(name), "dotranslate_%lu", (unsigned long)(parser->translated++)); + out = ast_value_new(parser_ctx(parser), name, TYPE_STRING); + } else + out = ast_value_new(parser_ctx(parser), "#IMMEDIATE", TYPE_STRING); out->isconst = true; out->constval.vstring = parser_strdup(str); vec_push(parser->imm_string, out); @@ -1298,7 +1304,40 @@ static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma else parser->memberof = 0; - if (parser->tok == TOKEN_IDENT) + if (OPTS_FLAG(TRANSLATABLE_STRINGS) && + parser->tok == TOKEN_IDENT && !strcmp(parser_tokval(parser), "_")) + { + /* a translatable string */ + ast_value *val; + + if (wantop) { + parseerror(parser, "expected operator or end of statement, got constant"); + goto onerr; + } + + parser->lex->flags.noops = true; + if (!parser_next(parser) || parser->tok != '(') { + parseerror(parser, "use _(\"string\") to create a translatable string constant"); + goto onerr; + } + parser->lex->flags.noops = false; + if (!parser_next(parser) || parser->tok != TOKEN_STRINGCONST) { + parseerror(parser, "expected a constant string in translatable-string extension"); + goto onerr; + } + val = parser_const_string(parser, parser_tokval(parser), true); + wantop = true; + if (!val) + return false; + vec_push(sy.out, syexp(parser_ctx(parser), (ast_expression*)val)); + DEBUGSHUNTDO(con_out("push string\n")); + + if (!parser_next(parser) || parser->tok != ')') { + parseerror(parser, "expected closing paren after translatable string"); + goto onerr; + } + } + else if (parser->tok == TOKEN_IDENT) { ast_expression *var; if (wantop) { @@ -1373,7 +1412,7 @@ static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma goto onerr; } wantop = true; - val = parser_const_string(parser, parser_tokval(parser)); + val = parser_const_string(parser, parser_tokval(parser), false); if (!val) return false; vec_push(sy.out, syexp(parser_ctx(parser), (ast_expression*)val)); @@ -3198,6 +3237,7 @@ static ast_value *parse_typename(parser_t *parser, ast_value **storebase, ast_va const char *name = NULL; bool isfield = false; bool wasarray = false; + size_t morefields = 0; ctx = parser_ctx(parser); @@ -3209,6 +3249,18 @@ static ast_value *parse_typename(parser_t *parser, ast_value **storebase, ast_va parseerror(parser, "expected typename for field definition"); return NULL; } + + /* Further dots are handled seperately because they won't be part of the + * basetype + */ + while (parser->tok == '.') { + ++morefields; + if (!parser_next(parser)) { + parseerror(parser, "expected typename for field definition"); + return NULL; + } + } + if (parser->tok == TOKEN_IDENT) cached_typedef = parser_find_typedef(parser, parser_tokval(parser), 0); if (!cached_typedef && parser->tok != TOKEN_TYPENAME) { @@ -3223,6 +3275,13 @@ static ast_value *parse_typename(parser_t *parser, ast_value **storebase, ast_va ast_value_set_name(var, ""); } else var = ast_value_new(ctx, "", parser_token(parser)->constval.t); + + for (; morefields; --morefields) { + tmp = ast_value_new(ctx, "<.type>", TYPE_FIELD); + tmp->expression.next = (ast_expression*)var; + var = tmp; + } + /* do not yet turn into a field - remember: * .void() foo; is a field too * .void()() foo; is a function @@ -3609,9 +3668,9 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield } } - me[0] = me[1] = me[2] = NULL; - cleanvar = false; } + me[0] = me[1] = me[2] = NULL; + cleanvar = false; /* Part 2.2 * deal with arrays */ @@ -3682,7 +3741,7 @@ skipvar: if (parser->tok != '{') { if (parser->tok != '=') { - parseerror(parser, "missing semicolon or initializer"); + parseerror(parser, "missing semicolon or initializer, got: `%s`", parser_tokval(parser)); break; } @@ -3871,6 +3930,13 @@ static bool parser_global_statement(parser_t *parser) parseerror(parser, "expected variable declaration after 'const'"); return false; } + if (parser->tok == TOKEN_IDENT && !strcmp(parser_tokval(parser), "var")) { + (void)!parsewarning(parser, WARN_CONST_VAR, "ignoring `var` after const qualifier"); + if (!parser_next(parser)) { + parseerror(parser, "expected variable declaration after 'const var'"); + return false; + } + } return parse_variable(parser, NULL, true, true, NULL); } else if (!strcmp(parser_tokval(parser), "typedef")) {