X-Git-Url: https://git.xonotic.org/?p=xonotic%2Fgmqcc.git;a=blobdiff_plain;f=parser.c;h=e93c7928e76375d189ff0dd3debad579be76e300;hp=51500eff4859180188f159243ab4f2ff3450782b;hb=793547a132108f09f1baf14a61f8cff0a6b61ba0;hpb=af3ba03a5ba39df60478344faab0b5a3d2bb7cfb diff --git a/parser.c b/parser.c index 51500ef..e93c792 100644 --- a/parser.c +++ b/parser.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 + * Copyright (C) 2012, 2013 * Wolfgang Bumiller * Dale Weiler * @@ -26,6 +26,7 @@ #include "gmqcc.h" #include "lexer.h" +#include "ast.h" /* beginning of locals */ #define PARSER_HT_LOCALS 2 @@ -73,6 +74,10 @@ typedef struct { ht htglobals; ht *typedefs; + /* same as above but for the spelling corrector */ + ht *correct_variables; + size_t ***correct_variables_score; /* vector of vector of size_t* */ + /* not to be used directly, we use the hash table */ ast_expression **_locals; size_t *_blocklocals; @@ -110,8 +115,8 @@ static ast_block* parse_block(parser_t *parser); static bool parse_block_into(parser_t *parser, ast_block *block); static bool parse_statement_or_block(parser_t *parser, ast_expression **out); static bool parse_statement(parser_t *parser, ast_block *block, ast_expression **out, bool allow_cases); -static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma); -static ast_expression* parse_expression(parser_t *parser, bool stopatcomma); +static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma, bool truthvalue, bool with_labels); +static ast_expression* parse_expression(parser_t *parser, bool stopatcomma, bool with_labels); static void parseerror(parser_t *parser, const char *fmt, ...) { @@ -299,6 +304,15 @@ static ast_expression* parser_find_field(parser_t *parser, const char *name) return ( ast_expression*)util_htget(parser->htfields, name); } +static ast_expression* parser_find_label(parser_t *parser, const char *name) +{ + size_t i; + for(i = 0; i < vec_size(parser->labels); i++) + if (!strcmp(parser->labels[i]->name, name)) + return (ast_expression*)parser->labels[i]; + return NULL; +} + static ast_expression* parser_find_global(parser_t *parser, const char *name) { return (ast_expression*)util_htget(parser->htglobals, name); @@ -539,6 +553,16 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) exprs[i] = sy->out[vec_size(sy->out)+i].out; blocks[i] = sy->out[vec_size(sy->out)+i].block; asvalue[i] = (ast_value*)exprs[i]; + + if (exprs[i]->expression.vtype == TYPE_NOEXPR && + !(i != 0 && op->id == opid2('?',':'))) + { + if (ast_istype(exprs[i], ast_label)) + compile_error(ast_ctx(exprs[i]), "expected expression, got an unknown identifier"); + else + compile_error(ast_ctx(exprs[i]), "not an expression"); + (void)!compile_warning(ast_ctx(exprs[i]), WARN_DEBUG, "expression %u\n", (unsigned int)i); + } } if (blocks[0] && !vec_size(blocks[0]->exprs) && op->id != opid1(',')) { @@ -939,7 +963,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) ( (generated_op == INSTR_OR) ? (immediate_is_true(ctx, asvalue[0]) || immediate_is_true(ctx, asvalue[1])) : (immediate_is_true(ctx, asvalue[0]) && immediate_is_true(ctx, asvalue[1])) ) - ? 0 : 1); + ? 1 : 0); } else { @@ -983,14 +1007,14 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) return false; } vec_pop(parser->pot); - if (exprs[1]->expression.vtype != exprs[2]->expression.vtype) { + if (!ast_compare_type(exprs[1], exprs[2])) { ast_type_to_string(exprs[1], ty1, sizeof(ty1)); ast_type_to_string(exprs[2], ty2, sizeof(ty2)); parseerror(parser, "operands of ternary expression must have the same type, got %s and %s", ty1, ty2); return false; } if (CanConstFold1(exprs[0])) - out = (ConstF(0) ? exprs[1] : exprs[2]); + out = (immediate_is_true(ctx, asvalue[0]) ? exprs[1] : exprs[2]); else out = (ast_expression*)ast_ternary_new(ctx, exprs[0], exprs[1], exprs[2]); break; @@ -1041,8 +1065,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) } else assignop = type_storep_instr[exprs[0]->expression.vtype]; - if (assignop == AINSTR_END || - !ast_compare_type(field->expression.next, exprs[1])) + if (assignop == AINSTR_END || !ast_compare_type(field->expression.next, exprs[1])) { ast_type_to_string(field->expression.next, ty1, sizeof(ty1)); ast_type_to_string(exprs[1], ty2, sizeof(ty2)); @@ -1074,8 +1097,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) ast_type_to_string(exprs[1], ty2, sizeof(ty2)); parseerror(parser, "invalid types in assignment: cannot assign %s to %s", ty2, ty1); } - else if (exprs[1]->expression.vtype != TYPE_NIL && - !ast_compare_type(exprs[0], exprs[1])) + else if (!ast_compare_type(exprs[0], exprs[1])) { ast_type_to_string(exprs[0], ty1, sizeof(ty1)); ast_type_to_string(exprs[1], ty2, sizeof(ty2)); @@ -1374,7 +1396,6 @@ static bool parser_close_call(parser_t *parser, shunt *sy) return false; } - if (!fun->expression.next) { parseerror(parser, "could not determine function return type"); return false; @@ -1398,7 +1419,7 @@ static bool parser_close_call(parser_t *parser, shunt *sy) "call to `%s` (deprecated: %s)\n" "-> `%s` declared here: %s:%i", fval->name, fval->desc, fval->name, ast_ctx(fun).file, - ast_ctx(fun).line); + ast_ctx(fun).line); } if (vec_size(fun->expression.params) != paramcount && @@ -1406,35 +1427,18 @@ static bool parser_close_call(parser_t *parser, shunt *sy) vec_size(fun->expression.params) < paramcount)) { const char *fewmany = (vec_size(fun->expression.params) > paramcount) ? "few" : "many"; - if (opts.standard == COMPILER_GMQCC) - { - if (fval) - parseerror(parser, "too %s parameters for call to %s: expected %i, got %i\n" - " -> `%s` has been declared here: %s:%i", - fewmany, fval->name, (int)vec_size(fun->expression.params), (int)paramcount, - fval->name, ast_ctx(fun).file, (int)ast_ctx(fun).line); - else - parseerror(parser, "too %s parameters for function call: expected %i, got %i\n" - " -> it has been declared here: %s:%i", - fewmany, (int)vec_size(fun->expression.params), (int)paramcount, - ast_ctx(fun).file, (int)ast_ctx(fun).line); - return false; - } + if (fval) + return !parsewarning(parser, WARN_INVALID_PARAMETER_COUNT, + "too %s parameters for call to %s: expected %i, got %i\n" + " -> `%s` has been declared here: %s:%i", + fewmany, fval->name, (int)vec_size(fun->expression.params), (int)paramcount, + fval->name, ast_ctx(fun).file, (int)ast_ctx(fun).line); else - { - if (fval) - return !parsewarning(parser, WARN_TOO_FEW_PARAMETERS, - "too %s parameters for call to %s: expected %i, got %i\n" - " -> `%s` has been declared here: %s:%i", - fewmany, fval->name, (int)vec_size(fun->expression.params), (int)paramcount, - fval->name, ast_ctx(fun).file, (int)ast_ctx(fun).line); - else - return !parsewarning(parser, WARN_TOO_FEW_PARAMETERS, - "too %s parameters for function call: expected %i, got %i\n" - " -> it has been declared here: %s:%i", - fewmany, (int)vec_size(fun->expression.params), (int)paramcount, - ast_ctx(fun).file, (int)ast_ctx(fun).line); - } + return !parsewarning(parser, WARN_INVALID_PARAMETER_COUNT, + "too %s parameters for function call: expected %i, got %i\n" + " -> it has been declared here: %s:%i", + fewmany, (int)vec_size(fun->expression.params), (int)paramcount, + ast_ctx(fun).file, (int)ast_ctx(fun).line); } } @@ -1502,12 +1506,16 @@ static void parser_reclassify_token(parser_t *parser) } } -static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma) +static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma, bool truthvalue, bool with_labels) { ast_expression *expr = NULL; shunt sy; bool wantop = false; bool gotmemberof = false; + /* only warn once about an assignment in a truth value because the current code + * would trigger twice on: if(a = b && ...), once for the if-truth-value, once for the && part + */ + bool warn_truthvalue = true; /* count the parens because an if starts with one, so the * end of a condition is an unmatched closing paren @@ -1595,14 +1603,61 @@ static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma if (!var) var = parser_find_field(parser, parser_tokval(parser)); } + if (!var && with_labels) { + var = (ast_expression*)parser_find_label(parser, parser_tokval(parser)); + if (!with_labels) { + ast_label *lbl = ast_label_new(parser_ctx(parser), parser_tokval(parser), true); + var = (ast_expression*)lbl; + vec_push(parser->labels, lbl); + } + } if (!var) { /* intrinsics */ if (!strcmp(parser_tokval(parser), "__builtin_debug_typestring")) { var = (ast_expression*)intrinsic_debug_typestring; - } else { + size_t i; + char *correct = NULL; + + /* + * sometimes people use preprocessing predefs without enabling them + * 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)); + goto onerr; + } + } + } + + /* + * TODO: determine the best score for the identifier: be it + * a variable, a field. + * + * We should also consider adding correction tables for + * other things as well. + */ + if (OPTS_FLAG(ENHANCED_DIAGNOSTICS)) { + for (i = 0; i < vec_size(parser->correct_variables); i++) { + correct = correct_str(parser->correct_variables[i], parser_tokval(parser)); + if (strcmp(correct, parser_tokval(parser))) { + break; + } else if (correct) { + mem_d(correct); + } + } + + if (correct) { + parseerror(parser, "unexpected ident: %s (did you mean %s?)", parser_tokval(parser), correct); + mem_d(correct); + goto onerr; + } + } parseerror(parser, "unexpected ident: %s", parser_tokval(parser)); goto onerr; } @@ -1784,6 +1839,28 @@ static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma if (vec_size(sy.ops) && !vec_last(sy.ops).paren) olast = &operators[vec_last(sy.ops).etype-1]; +#define IsAssignOp(x) (\ + (x) == opid1('=') || \ + (x) == opid2('+','=') || \ + (x) == opid2('-','=') || \ + (x) == opid2('*','=') || \ + (x) == opid2('/','=') || \ + (x) == opid2('%','=') || \ + (x) == opid2('&','=') || \ + (x) == opid2('|','=') || \ + (x) == opid3('&','~','=') \ + ) + if (warn_truthvalue) { + if ( (olast && IsAssignOp(olast->id) && (op->id == opid2('&','&') || op->id == opid2('|','|'))) || + (olast && IsAssignOp(op->id) && (olast->id == opid2('&','&') || olast->id == opid2('|','|'))) || + (truthvalue && !vec_size(parser->pot) && IsAssignOp(op->id)) + ) + { + (void)!parsewarning(parser, WARN_PARENTHESIS, "suggesting parenthesis around assignment used as truth value"); + warn_truthvalue = false; + } + } + while (olast && ( (op->prec < olast->prec) || (op->assoc == ASSOC_LEFT && op->prec <= olast->prec) ) ) @@ -1901,9 +1978,9 @@ onerr: return NULL; } -static ast_expression* parse_expression(parser_t *parser, bool stopatcomma) +static ast_expression* parse_expression(parser_t *parser, bool stopatcomma, bool with_labels) { - ast_expression *e = parse_expression_leave(parser, stopatcomma); + ast_expression *e = parse_expression_leave(parser, stopatcomma, false, with_labels); if (!e) return NULL; if (!parser_next(parser)) { @@ -1920,6 +1997,10 @@ static void parser_enterblock(parser_t *parser) vec_push(parser->typedefs, util_htnew(TYPEDEF_HT_SIZE)); vec_push(parser->_blocktypedefs, vec_size(parser->_typedefs)); vec_push(parser->_block_ctx, parser_ctx(parser)); + + /* corrector */ + vec_push(parser->correct_variables, util_htnew(PARSER_HT_SIZE)); + vec_push(parser->correct_variables_score, NULL); } static bool parser_leaveblock(parser_t *parser) @@ -1933,7 +2014,11 @@ static bool parser_leaveblock(parser_t *parser) } util_htdel(vec_last(parser->variables)); + correct_del(vec_last(parser->correct_variables), vec_last(parser->correct_variables_score)); + vec_pop(parser->variables); + vec_pop(parser->correct_variables); + vec_pop(parser->correct_variables_score); if (!vec_size(parser->_blocklocals)) { parseerror(parser, "internal error: parser_leaveblock with no block (2)"); return false; @@ -1960,6 +2045,7 @@ static bool parser_leaveblock(parser_t *parser) vec_pop(parser->typedefs); vec_pop(parser->_block_ctx); + return rv; } @@ -1967,6 +2053,13 @@ static void parser_addlocal(parser_t *parser, const char *name, ast_expression * { vec_push(parser->_locals, e); util_htset(vec_last(parser->variables), name, (void*)e); + + /* corrector */ + correct_add ( + vec_last(parser->correct_variables), + &vec_last(parser->correct_variables_score), + name + ); } static ast_expression* process_condition(parser_t *parser, ast_expression *cond, bool *_ifnot) @@ -2053,7 +2146,7 @@ static bool parse_if(parser_t *parser, ast_block *block, ast_expression **out) return false; } /* parse the condition */ - cond = parse_expression_leave(parser, false); + cond = parse_expression_leave(parser, false, true, false); if (!cond) return false; /* closing paren */ @@ -2174,7 +2267,7 @@ static bool parse_while_go(parser_t *parser, ast_block *block, ast_expression ** return false; } /* parse the condition */ - cond = parse_expression_leave(parser, false); + cond = parse_expression_leave(parser, false, true, false); if (!cond) return false; /* closing paren */ @@ -2289,7 +2382,7 @@ static bool parse_dowhile_go(parser_t *parser, ast_block *block, ast_expression return false; } /* parse the condition */ - cond = parse_expression_leave(parser, false); + cond = parse_expression_leave(parser, false, true, false); if (!cond) return false; /* closing paren */ @@ -2406,17 +2499,19 @@ static bool parse_for_go(parser_t *parser, ast_block *block, ast_expression **ou typevar = parser_find_typedef(parser, parser_tokval(parser), 0); if (typevar || parser->tok == TOKEN_TYPENAME) { +#if 0 if (opts.standard != COMPILER_GMQCC) { if (parsewarning(parser, WARN_EXTENSIONS, "current standard does not allow variable declarations in for-loop initializers")) goto onerr; } +#endif if (!parse_variable(parser, block, true, CV_VAR, typevar, false, false, 0, NULL)) goto onerr; } else if (parser->tok != ';') { - initexpr = parse_expression_leave(parser, false); + initexpr = parse_expression_leave(parser, false, false, false); if (!initexpr) goto onerr; } @@ -2433,7 +2528,7 @@ static bool parse_for_go(parser_t *parser, ast_block *block, ast_expression **ou /* parse the condition */ if (parser->tok != ';') { - cond = parse_expression_leave(parser, false); + cond = parse_expression_leave(parser, false, true, false); if (!cond) goto onerr; } @@ -2450,7 +2545,7 @@ static bool parse_for_go(parser_t *parser, ast_block *block, ast_expression **ou /* parse the incrementor */ if (parser->tok != ')') { - increment = parse_expression_leave(parser, false); + increment = parse_expression_leave(parser, false, false, false); if (!increment) goto onerr; if (!ast_side_effects(increment)) { @@ -2507,11 +2602,13 @@ static bool parse_return(parser_t *parser, ast_block *block, ast_expression **ou } if (parser->tok != ';') { - exp = parse_expression(parser, false); + exp = parse_expression(parser, false, false); if (!exp) return false; - if (exp->expression.vtype != expected->expression.next->expression.vtype) { + if (exp->expression.vtype != TYPE_NIL && + exp->expression.vtype != expected->expression.next->expression.vtype) + { parseerror(parser, "return with invalid expression"); } @@ -2524,10 +2621,7 @@ static bool parse_return(parser_t *parser, ast_block *block, ast_expression **ou if (!parser_next(parser)) parseerror(parser, "parse error"); if (expected->expression.next->expression.vtype != TYPE_VOID) { - if (opts.standard != COMPILER_GMQCC) - (void)!parsewarning(parser, WARN_MISSING_RETURN_VALUES, "return without value"); - else - parseerror(parser, "return without value"); + (void)!parsewarning(parser, WARN_MISSING_RETURN_VALUES, "return without value"); } ret = ast_return_new(ctx, NULL); } @@ -2794,7 +2888,7 @@ static bool parse_switch_go(parser_t *parser, ast_block *block, ast_expression * return false; } /* parse the operand */ - operand = parse_expression_leave(parser, false); + operand = parse_expression_leave(parser, false, false, false); if (!operand) return false; @@ -2858,7 +2952,7 @@ static bool parse_switch_go(parser_t *parser, ast_block *block, ast_expression * parseerror(parser, "expected expression for case"); return false; } - swcase.value = parse_expression_leave(parser, false); + swcase.value = parse_expression_leave(parser, false, false, false); if (!swcase.value) { ast_delete(switchnode); parseerror(parser, "expected expression for case"); @@ -2949,25 +3043,81 @@ static bool parse_switch_go(parser_t *parser, ast_block *block, ast_expression * return true; } +/* parse computed goto sides */ +static ast_expression *parse_goto_computed(parser_t *parser, ast_expression **side) { + ast_expression *on_true; + ast_expression *on_false; + ast_expression *cond; + + if (!*side) + return NULL; + + if (ast_istype(*side, ast_ternary)) { + ast_ternary *tern = (ast_ternary*)*side; + on_true = parse_goto_computed(parser, &tern->on_true); + on_false = parse_goto_computed(parser, &tern->on_false); + + if (!on_true || !on_false) { + parseerror(parser, "expected label or expression in ternary"); + if (on_true) ast_unref(on_true); + if (on_false) ast_unref(on_false); + return NULL; + } + + cond = tern->cond; + tern->cond = NULL; + ast_delete(tern); + *side = NULL; + return (ast_expression*)ast_ifthen_new(parser_ctx(parser), cond, on_true, on_false); + } else if (ast_istype(*side, ast_label)) { + ast_goto *gt = ast_goto_new(parser_ctx(parser), ((ast_label*)*side)->name); + ast_goto_set_label(gt, ((ast_label*)*side)); + *side = NULL; + return (ast_expression*)gt; + } + return NULL; +} + static bool parse_goto(parser_t *parser, ast_expression **out) { - size_t i; - ast_goto *gt; + ast_goto *gt = NULL; + ast_expression *lbl; - if (!parser_next(parser) || parser->tok != TOKEN_IDENT) { - parseerror(parser, "expected label name after `goto`"); + if (!parser_next(parser)) return false; + + if (parser->tok != TOKEN_IDENT) { + ast_expression *expression; + + /* could be an expression i.e computed goto :-) */ + if (parser->tok != '(') { + parseerror(parser, "expected label name after `goto`"); + return false; + } + + /* failed to parse expression for goto */ + if (!(expression = parse_expression(parser, false, true)) || + !(*out = parse_goto_computed(parser, &expression))) { + parseerror(parser, "invalid goto expression"); + ast_unref(expression); + return false; + } + + return true; } + /* not computed goto */ gt = ast_goto_new(parser_ctx(parser), parser_tokval(parser)); - - for (i = 0; i < vec_size(parser->labels); ++i) { - if (!strcmp(parser->labels[i]->name, parser_tokval(parser))) { - ast_goto_set_label(gt, parser->labels[i]); - break; + lbl = parser_find_label(parser, gt->name); + if (lbl) { + if (!ast_istype(lbl, ast_label)) { + parseerror(parser, "internal error: label is not an ast_label"); + ast_delete(gt); + return false; } + ast_goto_set_label(gt, (ast_label*)lbl); } - if (i == vec_size(parser->labels)) + else vec_push(parser->gotos, gt); if (!parser_next(parser) || parser->tok != ';') { @@ -3202,10 +3352,18 @@ static bool parse_statement(parser_t *parser, ast_block *block, ast_expression * parseerror(parser, "label must be an identifier"); return false; } - label = ast_label_new(parser_ctx(parser), parser_tokval(parser)); - if (!label) - return false; - vec_push(parser->labels, label); + label = (ast_label*)parser_find_label(parser, parser_tokval(parser)); + if (label) { + if (!label->undefined) { + parseerror(parser, "label `%s` already defined", label->name); + return false; + } + label->undefined = false; + } + else { + label = ast_label_new(parser_ctx(parser), parser_tokval(parser), false); + vec_push(parser->labels, label); + } *out = (ast_expression*)label; if (!parser_next(parser)) { parseerror(parser, "parse error after label"); @@ -3230,7 +3388,7 @@ static bool parse_statement(parser_t *parser, ast_block *block, ast_expression * } else { - ast_expression *exp = parse_expression(parser, false); + ast_expression *exp = parse_expression(parser, false, false); if (!exp) return false; *out = exp; @@ -3391,7 +3549,7 @@ static bool parse_function_body(parser_t *parser, ast_value *var) if (!parser_next(parser)) return false; - framenum = parse_expression_leave(parser, true); + framenum = parse_expression_leave(parser, true, false, false); if (!framenum) { parseerror(parser, "expected a framenumber constant in[frame,think] notation"); return false; @@ -3436,10 +3594,11 @@ static bool parse_function_body(parser_t *parser, ast_value *var) vec_push(parser->globals, (ast_expression*)thinkfunc); util_htset(parser->htglobals, thinkfunc->name, thinkfunc); + nextthink = (ast_expression*)thinkfunc; } else { - nextthink = parse_expression_leave(parser, true); + nextthink = parse_expression_leave(parser, true, false, false); if (!nextthink) { ast_unref(framenum); parseerror(parser, "expected a think-function in [frame,think] notation"); @@ -4105,7 +4264,7 @@ static ast_value *parse_arraysize(parser_t *parser, ast_value *var) return NULL; } - cexp = parse_expression_leave(parser, true); + cexp = parse_expression_leave(parser, true, false, false); if (!cexp || !ast_istype(cexp, ast_value)) { if (cexp) @@ -4367,7 +4526,7 @@ static bool parser_check_qualifiers(parser_t *parser, const ast_value *var, cons } av = (var ->expression.flags & AST_FLAG_NORETURN); ao = (proto->expression.flags & AST_FLAG_NORETURN); - if (av != ao) { + if (!av != !ao) { return !parsewarning(parser, WARN_DIFFERENT_ATTRIBUTES, "`%s` declared with different attributes%s\n" " -> previous declaration here: %s:%i", @@ -4554,35 +4713,28 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield { /* other globals */ if (old) { - if (opts.standard == COMPILER_GMQCC) { - parseerror(parser, "global `%s` already declared here: %s:%i", - var->name, ast_ctx(old).file, ast_ctx(old).line); + if (parsewarning(parser, WARN_DOUBLE_DECLARATION, + "global `%s` already declared here: %s:%i", + var->name, ast_ctx(old).file, ast_ctx(old).line)) + { retval = false; goto cleanup; - } else { - if (parsewarning(parser, WARN_DOUBLE_DECLARATION, - "global `%s` already declared here: %s:%i", - var->name, ast_ctx(old).file, ast_ctx(old).line)) - { - retval = false; - goto cleanup; - } - proto = (ast_value*)old; - if (!ast_istype(old, ast_value)) { - parseerror(parser, "internal error: not an ast_value"); - retval = false; - proto = NULL; - goto cleanup; - } - if (!parser_check_qualifiers(parser, var, proto)) { - retval = false; - proto = NULL; - goto cleanup; - } - proto->expression.flags |= var->expression.flags; - ast_delete(var); - var = proto; } + proto = (ast_value*)old; + if (!ast_istype(old, ast_value)) { + parseerror(parser, "internal error: not an ast_value"); + retval = false; + proto = NULL; + goto cleanup; + } + if (!parser_check_qualifiers(parser, var, proto)) { + retval = false; + proto = NULL; + goto cleanup; + } + proto->expression.flags |= var->expression.flags; + ast_delete(var); + var = proto; } if (opts.standard == COMPILER_QCC && (old = parser_find_field(parser, var->name))) @@ -4684,6 +4836,14 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield /* Add it to the local scope */ util_htset(vec_last(parser->variables), var->name, (void*)var); + + /* corrector */ + correct_add ( + vec_last(parser->correct_variables), + &vec_last(parser->correct_variables_score), + var->name + ); + /* now rename the global */ ln = strlen(var->name); vec_append(defname, ln, var->name); @@ -4697,6 +4857,13 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield for (i = 0; i < 3; ++i) { util_htset(vec_last(parser->variables), me[i]->name, (void*)(me[i])); + /* corrector */ + correct_add( + vec_last(parser->correct_variables), + &vec_last(parser->correct_variables_score), + me[i]->name + ); + vec_shrinkto(defname, prefix_len); ln = strlen(me[i]->name); vec_append(defname, ln, me[i]->name); @@ -4878,7 +5045,7 @@ skipvar: ast_expression *cexp; ast_value *cval; - cexp = parse_expression_leave(parser, true); + cexp = parse_expression_leave(parser, true, false, false); if (!cexp) break; @@ -4892,8 +5059,7 @@ skipvar: } else { - if (opts.standard != COMPILER_GMQCC && - !OPTS_FLAG(INITIALIZED_NONCONSTANTS) && + if (!OPTS_FLAG(INITIALIZED_NONCONSTANTS) && qualifier != CV_VAR) { var->cvq = CV_CONST; @@ -5244,6 +5410,17 @@ void parser_cleanup() vec_free(parser->_blocklocals); vec_free(parser->_locals); + /* corrector */ + for (i = 0; i < vec_size(parser->correct_variables); ++i) { + correct_del(parser->correct_variables[i], parser->correct_variables_score[i]); + } + for (i = 0; i < vec_size(parser->correct_variables_score); ++i) { + vec_free(parser->correct_variables_score[i]); + } + vec_free(parser->correct_variables); + vec_free(parser->correct_variables_score); + + for (i = 0; i < vec_size(parser->_typedefs); ++i) ast_delete(parser->_typedefs[i]); vec_free(parser->_typedefs);