X-Git-Url: https://git.xonotic.org/?p=xonotic%2Fgmqcc.git;a=blobdiff_plain;f=parser.c;h=f53116180c5679591dd2bc7ed52d7484367e9852;hp=b5f6fe4d3415c3489f9aee37d12c83e8932b934c;hb=58cd326d85f6eb67d46ecc41c111df086e836837;hpb=353455e1adbe364c76823454f5b0cd442e199d96 diff --git a/parser.c b/parser.c index b5f6fe4..f531161 100644 --- a/parser.c +++ b/parser.c @@ -23,6 +23,7 @@ */ #include #include + #include "parser.h" #define PARSER_HT_LOCALS 2 @@ -43,7 +44,7 @@ static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma static ast_expression* parse_expression(parser_t *parser, bool stopatcomma, bool with_labels); static ast_value* parser_create_array_setter_proto(parser_t *parser, ast_value *array, const char *funcname); static ast_value* parser_create_array_getter_proto(parser_t *parser, ast_value *array, const ast_expression *elemtype, const char *funcname); -static ast_value *parse_typename(parser_t *parser, ast_value **storebase, ast_value *cached_typedef); +static ast_value *parse_typename(parser_t *parser, ast_value **storebase, ast_value *cached_typedef, bool *is_vararg); static void parseerror(parser_t *parser, const char *fmt, ...) { @@ -371,6 +372,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) #define NotSameType(T) \ (exprs[0]->vtype != exprs[1]->vtype || \ exprs[0]->vtype != T) + switch (op->id) { default: @@ -465,15 +467,19 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) out = exprs[0]; break; case opid2('-','P'): - if (!(out = fold_op(parser->fold, op, exprs))) { - if (exprs[0]->vtype != TYPE_FLOAT && - exprs[0]->vtype != TYPE_VECTOR) { - compile_error(ctx, "invalid types used in unary expression: cannot negate type %s", - type_name[exprs[0]->vtype]); - return false; - } - out = (ast_expression*)ast_unary_new(ctx, (VINSTR_NEG_F-TYPE_FLOAT) + exprs[0]->vtype, exprs[0]); + if ((out = fold_op(parser->fold, op, exprs))) + break; + + if (exprs[0]->vtype != TYPE_FLOAT && + exprs[0]->vtype != TYPE_VECTOR) { + compile_error(ctx, "invalid types used in unary expression: cannot negate type %s", + type_name[exprs[0]->vtype]); + return false; } + if (exprs[0]->vtype == TYPE_FLOAT) + out = (ast_expression*)ast_unary_new(ctx, VINSTR_NEG_F, exprs[0]); + else + out = (ast_expression*)ast_unary_new(ctx, VINSTR_NEG_V, exprs[0]); break; case opid2('!','P'): @@ -518,10 +524,10 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) if (!(out = fold_op(parser->fold, op, exprs))) { switch (exprs[0]->vtype) { case TYPE_FLOAT: - out = (ast_expression*)ast_binary_new(ctx, INSTR_ADD_F, exprs[0], exprs[1]); + out = fold_binary(ctx, INSTR_ADD_F, exprs[0], exprs[1]); break; case TYPE_VECTOR: - out = (ast_expression*)ast_binary_new(ctx, INSTR_ADD_V, exprs[0], exprs[1]); + out = fold_binary(ctx, INSTR_ADD_V, exprs[0], exprs[1]); break; default: compile_error(ctx, "invalid types used in expression: cannot add type %s and %s", @@ -543,10 +549,10 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) if (!(out = fold_op(parser->fold, op, exprs))) { switch (exprs[0]->vtype) { case TYPE_FLOAT: - out = (ast_expression*)ast_binary_new(ctx, INSTR_SUB_F, exprs[0], exprs[1]); + out = fold_binary(ctx, INSTR_SUB_F, exprs[0], exprs[1]); break; case TYPE_VECTOR: - out = (ast_expression*)ast_binary_new(ctx, INSTR_SUB_V, exprs[0], exprs[1]); + out = fold_binary(ctx, INSTR_SUB_V, exprs[0], exprs[1]); break; default: compile_error(ctx, "invalid types used in expression: cannot subtract type %s from %s", @@ -573,15 +579,15 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) switch (exprs[0]->vtype) { case TYPE_FLOAT: if (exprs[1]->vtype == TYPE_VECTOR) - out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_FV, exprs[0], exprs[1]); + out = fold_binary(ctx, INSTR_MUL_FV, exprs[0], exprs[1]); else - out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_F, exprs[0], exprs[1]); + out = fold_binary(ctx, INSTR_MUL_F, exprs[0], exprs[1]); break; case TYPE_VECTOR: if (exprs[1]->vtype == TYPE_FLOAT) - out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_VF, exprs[0], exprs[1]); + out = fold_binary(ctx, INSTR_MUL_VF, exprs[0], exprs[1]); else - out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_V, exprs[0], exprs[1]); + out = fold_binary(ctx, INSTR_MUL_V, exprs[0], exprs[1]); break; default: compile_error(ctx, "invalid types used in expression: cannot multiply types %s and %s", @@ -601,7 +607,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) } if (!(out = fold_op(parser->fold, op, exprs))) { if (exprs[0]->vtype == TYPE_FLOAT) - out = (ast_expression*)ast_binary_new(ctx, INSTR_DIV_F, exprs[0], exprs[1]); + out = fold_binary(ctx, INSTR_DIV_F, exprs[0], exprs[1]); else { ast_type_to_string(exprs[0], ty1, sizeof(ty1)); ast_type_to_string(exprs[1], ty2, sizeof(ty2)); @@ -654,7 +660,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) * since scalar ^ vector is not allowed. */ if (exprs[0]->vtype == TYPE_FLOAT) { - out = (ast_expression*)ast_binary_new(ctx, + out = fold_binary(ctx, (op->id == opid1('^') ? VINSTR_BITXOR : op->id == opid1('|') ? INSTR_BITOR : INSTR_BITAND), exprs[0], exprs[1]); } else { @@ -667,11 +673,11 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) * Bitop all the values of the vector components against the * vectors components in question. */ - out = (ast_expression*)ast_binary_new(ctx, + out = fold_binary(ctx, (op->id == opid1('^') ? VINSTR_BITXOR_V : op->id == opid1('|') ? VINSTR_BITOR_V : VINSTR_BITAND_V), exprs[0], exprs[1]); } else { - out = (ast_expression*)ast_binary_new(ctx, + out = fold_binary(ctx, (op->id == opid1('^') ? VINSTR_BITXOR_VF : op->id == opid1('|') ? VINSTR_BITOR_VF : VINSTR_BITAND_VF), exprs[0], exprs[1]); } @@ -681,12 +687,44 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) case opid2('<','<'): case opid2('>','>'): + if (NotSameType(TYPE_FLOAT)) { + compile_error(ctx, "invalid types used in expression: cannot perform shift between types %s and %s", + type_name[exprs[0]->vtype], + type_name[exprs[1]->vtype]); + return false; + } + + if (!(out = fold_op(parser->fold, op, exprs))) { + ast_expression *shift = intrin_func(parser->intrin, (op->id == opid2('<','<')) ? "__builtin_lshift" : "__builtin_rshift"); + ast_call *call = ast_call_new(parser_ctx(parser), shift); + vec_push(call->params, exprs[0]); + vec_push(call->params, exprs[1]); + out = (ast_expression*)call; + } + break; + case opid3('<','<','='): case opid3('>','>','='): - if(!(out = fold_op(parser->fold, op, exprs))) { - compile_error(ast_ctx(exprs[0]), "Not Yet Implemented: bit-shifts"); + if (NotSameType(TYPE_FLOAT)) { + compile_error(ctx, "invalid types used in expression: cannot perform shift operation between types %s and %s", + type_name[exprs[0]->vtype], + type_name[exprs[1]->vtype]); return false; } + + if(!(out = fold_op(parser->fold, op, exprs))) { + ast_expression *shift = intrin_func(parser->intrin, (op->id == opid3('<','<','=')) ? "__builtin_lshift" : "__builtin_rshift"); + ast_call *call = ast_call_new(parser_ctx(parser), shift); + vec_push(call->params, exprs[0]); + vec_push(call->params, exprs[1]); + out = (ast_expression*)ast_store_new( + parser_ctx(parser), + INSTR_STORE_F, + exprs[0], + (ast_expression*)call + ); + } + break; case opid2('|','|'): @@ -724,7 +762,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) } } } - out = (ast_expression*)ast_binary_new(ctx, generated_op, exprs[0], exprs[1]); + out = fold_binary(ctx, generated_op, exprs[0], exprs[1]); } break; @@ -771,7 +809,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) } if (!(out = fold_op(parser->fold, op, exprs))) { - out = (ast_expression*)ast_binary_new( + out = fold_binary( parser_ctx(parser), VINSTR_CROSS, exprs[0], @@ -792,6 +830,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) } if (!(out = fold_op(parser->fold, op, exprs))) { + /* This whole block is NOT fold_binary safe */ ast_binary *eq = ast_binary_new(ctx, INSTR_EQ_F, exprs[0], exprs[1]); eq->refs = AST_REF_NONE; @@ -832,7 +871,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) return false; } if (!(out = fold_op(parser->fold, op, exprs))) - out = (ast_expression*)ast_binary_new(ctx, generated_op, exprs[0], exprs[1]); + out = fold_binary(ctx, generated_op, exprs[0], exprs[1]); break; case opid2('!', '='): if (exprs[0]->vtype != exprs[1]->vtype) { @@ -842,7 +881,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) return false; } if (!(out = fold_op(parser->fold, op, exprs))) - out = (ast_expression*)ast_binary_new(ctx, type_ne_instr[exprs[0]->vtype], exprs[0], exprs[1]); + out = fold_binary(ctx, type_ne_instr[exprs[0]->vtype], exprs[0], exprs[1]); break; case opid2('=', '='): if (exprs[0]->vtype != exprs[1]->vtype) { @@ -852,7 +891,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) return false; } if (!(out = fold_op(parser->fold, op, exprs))) - out = (ast_expression*)ast_binary_new(ctx, type_eq_instr[exprs[0]->vtype], exprs[0], exprs[1]); + out = fold_binary(ctx, type_eq_instr[exprs[0]->vtype], exprs[0], exprs[1]); break; case opid1('='): @@ -966,9 +1005,10 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) } if (!out) return false; - out = (ast_expression*)ast_binary_new(ctx, subop, - out, - (ast_expression*)parser->fold->imm_float[1]); + out = fold_binary(ctx, subop, + out, + (ast_expression*)parser->fold->imm_float[1]); + break; case opid2('+','='): case opid2('-','='): @@ -1032,9 +1072,9 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) out = (ast_expression*)ast_binstore_new(ctx, assignop, INSTR_MUL_VF, exprs[0], exprs[1]); } else { - out = (ast_expression*)ast_binary_new(ctx, INSTR_DIV_F, - (ast_expression*)parser->fold->imm_float[1], - exprs[1]); + out = fold_binary(ctx, INSTR_DIV_F, + (ast_expression*)parser->fold->imm_float[1], + exprs[1]); if (!out) { compile_error(ctx, "internal error: failed to generate division"); return false; @@ -1091,9 +1131,9 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) else assignop = type_store_instr[exprs[0]->vtype]; if (exprs[0]->vtype == TYPE_FLOAT) - out = (ast_expression*)ast_binary_new(ctx, INSTR_BITAND, exprs[0], exprs[1]); + out = fold_binary(ctx, INSTR_BITAND, exprs[0], exprs[1]); else - out = (ast_expression*)ast_binary_new(ctx, VINSTR_BITAND_V, exprs[0], exprs[1]); + out = fold_binary(ctx, VINSTR_BITAND_V, exprs[0], exprs[1]); if (!out) return false; (void)check_write_to(ctx, exprs[0]); @@ -1113,9 +1153,9 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) } if (!(out = fold_op(parser->fold, op, exprs))) { if (exprs[0]->vtype == TYPE_FLOAT) { - out = (ast_expression*)ast_binary_new(ctx, INSTR_SUB_F, (ast_expression*)parser->fold->imm_float[2], exprs[0]); + out = fold_binary(ctx, INSTR_SUB_F, (ast_expression*)parser->fold->imm_float[2], exprs[0]); } else { - out = (ast_expression*)ast_binary_new(ctx, INSTR_SUB_V, (ast_expression*)parser->fold->imm_vector[1], exprs[0]); + out = fold_binary(ctx, INSTR_SUB_V, (ast_expression*)parser->fold->imm_vector[1], exprs[0]); } } break; @@ -1223,7 +1263,7 @@ static bool parser_close_call(parser_t *parser, shunt *sy) * sy->out should I be doing here? */ sy->out[fid] = syexp(foldval->node.context, foldval); - vec_shrinkby(sy->out, 1); + vec_shrinkby(sy->out, paramcount); vec_free(exprs); return true; @@ -1418,7 +1458,7 @@ static ast_expression* parse_vararg_do(parser_t *parser) return NULL; } - typevar = parse_typename(parser, NULL, NULL); + typevar = parse_typename(parser, NULL, NULL, NULL); if (!typevar) { ast_unref(idx); return NULL; @@ -1576,6 +1616,23 @@ static bool parse_sya_operand(parser_t *parser, shunt *sy, bool with_labels) var = intrin_func(parser->intrin, parser_tokval(parser)); } + /* + * Try it again, intrin_func deals with the alias method as well + * the first one masks for __builtin though, we emit warning here. + */ + if (!var) { + if ((var = intrin_func(parser->intrin, parser_tokval(parser)))) { + (void)!compile_warning( + parser_ctx(parser), + WARN_BUILTINS, + "using implicitly defined builtin `__builtin_%s' for `%s'", + parser_tokval(parser), + parser_tokval(parser) + ); + } + } + + if (!var) { char *correct = NULL; size_t i; @@ -2797,6 +2854,22 @@ static bool parse_qualifiers(parser_t *parser, bool with_local, int *cvq, bool * return false; } } + else if (!strcmp(parser_tokval(parser), "accumulate")) { + flags |= AST_FLAG_ACCUMULATE; + if (!parser_next(parser) || parser->tok != TOKEN_ATTRIBUTE_CLOSE) { + parseerror(parser, "`accumulate` attribute has no parameters, expected `]]`"); + *cvq = CV_WRONG; + return false; + } + } + else if (!strcmp(parser_tokval(parser), "final")) { + flags |= AST_FLAG_FINAL_DECL; + if (!parser_next(parser) || parser->tok != TOKEN_ATTRIBUTE_CLOSE) { + parseerror(parser, "`final` attribute has no parameters, expected `]]`"); + *cvq = CV_WRONG; + return false; + } + } else if (!strcmp(parser_tokval(parser), "alias") && !(flags & AST_FLAG_ALIAS)) { flags |= AST_FLAG_ALIAS; *message = NULL; @@ -2901,6 +2974,8 @@ static bool parse_qualifiers(parser_t *parser, bool with_local, int *cvq, bool * had_var = true; else if (!strcmp(parser_tokval(parser), "noref")) had_noref = true; + else if (!strcmp(parser_tokval(parser), "final")) + flags |= AST_FLAG_FINAL_DECL; else if (!had_const && !had_var && !had_noref && !had_attrib && !had_static && !flags) { return false; } @@ -3334,7 +3409,7 @@ static bool parse_statement(parser_t *parser, ast_block *block, ast_expression * if (parser->tok == TOKEN_IDENT) typevar = parser_find_typedef(parser, parser_tokval(parser), 0); - if (typevar || parser->tok == TOKEN_TYPENAME || parser->tok == '.') + if (typevar || parser->tok == TOKEN_TYPENAME || parser->tok == '.' || parser->tok == TOKEN_DOTS) { /* local variable */ if (!block) { @@ -3973,18 +4048,28 @@ static bool parse_function_body(parser_t *parser, ast_value *var) } if (var->hasvalue) { - parseerror(parser, "function `%s` declared with multiple bodies", var->name); - ast_block_delete(block); - goto enderr; - } + if (!(var->expression.flags & AST_FLAG_ACCUMULATE)) { + parseerror(parser, "function `%s` declared with multiple bodies", var->name); + ast_block_delete(block); + goto enderr; + } + func = var->constval.vfunc; - func = ast_function_new(ast_ctx(var), var->name, var); - if (!func) { - parseerror(parser, "failed to allocate function for `%s`", var->name); - ast_block_delete(block); - goto enderr; + if (!func) { + parseerror(parser, "internal error: NULL function: `%s`", var->name); + ast_block_delete(block); + goto enderr; + } + } else { + func = ast_function_new(ast_ctx(var), var->name, var); + + if (!func) { + parseerror(parser, "failed to allocate function for `%s`", var->name); + ast_block_delete(block); + goto enderr; + } + vec_push(parser->functions, func); } - vec_push(parser->functions, func); parser_enterblock(parser); @@ -4011,13 +4096,13 @@ static bool parse_function_body(parser_t *parser, ast_value *var) } } - if (var->argcounter) { + if (var->argcounter && !func->argc) { ast_value *argc = ast_value_new(ast_ctx(var), var->argcounter, TYPE_FLOAT); parser_addlocal(parser, argc->name, (ast_expression*)argc); func->argc = argc; } - if (OPTS_FLAG(VARIADIC_ARGS) && var->expression.flags & AST_FLAG_VARIADIC) { + if (OPTS_FLAG(VARIADIC_ARGS) && var->expression.flags & AST_FLAG_VARIADIC && !func->varargs) { char name[1024]; ast_value *varargs = ast_value_new(ast_ctx(var), "reserved:va_args", TYPE_ARRAY); varargs->expression.flags |= AST_FLAG_IS_VARARG; @@ -4047,7 +4132,6 @@ static bool parse_function_body(parser_t *parser, ast_value *var) vec_push(func->blocks, block); - parser->function = old; if (!parser_leaveblock(parser)) retval = false; @@ -4484,7 +4568,6 @@ static bool parser_create_array_getter(parser_t *parser, ast_value *array, const return parser_create_array_getter_impl(parser, array); } -static ast_value *parse_typename(parser_t *parser, ast_value **storebase, ast_value *cached_typedef); static ast_value *parse_parameter_list(parser_t *parser, ast_value *var) { lex_ctx_t ctx; @@ -4510,6 +4593,8 @@ static ast_value *parse_parameter_list(parser_t *parser, ast_value *var) /* parse variables until we hit a closing paren */ while (parser->tok != ')') { + bool is_varargs = false; + if (!first) { /* there must be commas between them */ if (parser->tok != ',') { @@ -4523,10 +4608,13 @@ static ast_value *parse_parameter_list(parser_t *parser, ast_value *var) } first = false; - if (parser->tok == TOKEN_DOTS) { + param = parse_typename(parser, NULL, NULL, &is_varargs); + if (!param && !is_varargs) + goto on_error; + if (is_varargs) { /* '...' indicates a varargs function */ variadic = true; - if (!parser_next(parser) || (parser->tok != ')' && parser->tok != TOKEN_IDENT)) { + if (parser->tok != ')' && parser->tok != TOKEN_IDENT) { parseerror(parser, "`...` must be the last parameter of a variadic function declaration"); goto on_error; } @@ -4537,13 +4625,7 @@ static ast_value *parse_parameter_list(parser_t *parser, ast_value *var) goto on_error; } } - } - else - { - /* for anything else just parse a typename */ - param = parse_typename(parser, NULL, NULL); - if (!param) - goto on_error; + } else { vec_push(params, param); if (param->expression.vtype >= TYPE_VARIANT) { char tname[1024]; /* typename is reserved in C++ */ @@ -4695,7 +4777,7 @@ static ast_value *parse_arraysize(parser_t *parser, ast_value *var) * void() foo(), bar * then the type-information 'void()' can be stored in 'storebase' */ -static ast_value *parse_typename(parser_t *parser, ast_value **storebase, ast_value *cached_typedef) +static ast_value *parse_typename(parser_t *parser, ast_value **storebase, ast_value *cached_typedef, bool *is_vararg) { ast_value *var, *tmp; lex_ctx_t ctx; @@ -4705,11 +4787,15 @@ static ast_value *parse_typename(parser_t *parser, ast_value **storebase, ast_va bool wasarray = false; size_t morefields = 0; + bool vararg = (parser->tok == TOKEN_DOTS); + ctx = parser_ctx(parser); /* types may start with a dot */ - if (parser->tok == '.') { + if (parser->tok == '.' || parser->tok == TOKEN_DOTS) { isfield = true; + if (parser->tok == TOKEN_DOTS) + morefields += 2; /* if we parsed a dot we need a typename now */ if (!parser_next(parser)) { parseerror(parser, "expected typename for field definition"); @@ -4719,8 +4805,14 @@ static ast_value *parse_typename(parser_t *parser, ast_value **storebase, ast_va /* Further dots are handled seperately because they won't be part of the * basetype */ - while (parser->tok == '.') { - ++morefields; + while (true) { + if (parser->tok == '.') + ++morefields; + else if (parser->tok == TOKEN_DOTS) + morefields += 3; + else + break; + vararg = false; if (!parser_next(parser)) { parseerror(parser, "expected typename for field definition"); return NULL; @@ -4730,6 +4822,10 @@ static ast_value *parse_typename(parser_t *parser, ast_value **storebase, ast_va if (parser->tok == TOKEN_IDENT) cached_typedef = parser_find_typedef(parser, parser_tokval(parser), 0); if (!cached_typedef && parser->tok != TOKEN_TYPENAME) { + if (vararg && is_vararg) { + *is_vararg = true; + return NULL; + } parseerror(parser, "expected typename"); return NULL; } @@ -4781,8 +4877,14 @@ static ast_value *parse_typename(parser_t *parser, ast_value **storebase, ast_va } /* there may be a name now */ - if (parser->tok == TOKEN_IDENT) { + if (parser->tok == TOKEN_IDENT || parser->tok == TOKEN_KEYWORD) { + if (!strcmp(parser_tokval(parser), "break")) + (void)!parsewarning(parser, WARN_BREAKDEF, "break definition ignored (suggest removing it)"); + else if (parser->tok == TOKEN_KEYWORD) + goto leave; + name = util_strdup(parser_tokval(parser)); + /* parse on */ if (!parser_next(parser)) { ast_delete(var); @@ -4792,6 +4894,7 @@ static ast_value *parse_typename(parser_t *parser, ast_value **storebase, ast_va } } + leave: /* now this may be an array */ if (parser->tok == '[') { wasarray = true; @@ -4843,7 +4946,7 @@ static bool parse_typedef(parser_t *parser) ast_value *typevar, *oldtype; ast_expression *old; - typevar = parse_typename(parser, NULL, NULL); + typevar = parse_typename(parser, NULL, NULL, NULL); if (!typevar) return false; @@ -5013,7 +5116,7 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield parseerror(parser, "`static` qualifier is not supported in global scope"); /* get the first complete variable */ - var = parse_typename(parser, &basetype, cached_typedef); + var = parse_typename(parser, &basetype, cached_typedef, NULL); if (!var) { if (basetype) ast_delete(basetype); @@ -5077,6 +5180,13 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield var->expression.flags & AST_FLAG_ALIAS) var->desc = vstring; + if (parser_find_global(parser, var->name) && var->expression.flags & AST_FLAG_ALIAS) { + parseerror(parser, "function aliases cannot be forward declared"); + retval = false; + goto cleanup; + } + + /* Part 1: * check for validity: (end_sys_..., multiple-definitions, prototypes, ...) * Also: if there was a prototype, `var` will be deleted and set to `proto` which @@ -5189,6 +5299,12 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield retval = false; goto cleanup; } + if (old->flags & AST_FLAG_FINAL_DECL) { + parseerror(parser, "cannot redeclare variable `%s`, declared final 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"); @@ -5202,6 +5318,11 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield goto cleanup; } proto->expression.flags |= var->expression.flags; + /* copy the context for finals, + * so the error can show where it was actually made 'final' + */ + if (proto->expression.flags & AST_FLAG_FINAL_DECL) + ast_ctx(old) = ast_ctx(var); ast_delete(var); var = proto; } @@ -5373,6 +5494,7 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield */ char *defname = NULL; size_t prefix_len, ln; + size_t sn, sn_size; ln = strlen(parser->function->name); vec_append(defname, ln, parser->function->name); @@ -5394,6 +5516,24 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield /* now rename the global */ ln = strlen(var->name); vec_append(defname, ln, var->name); + /* if a variable of that name already existed, add the + * counter value. + * The counter is incremented either way. + */ + sn_size = vec_size(parser->function->static_names); + for (sn = 0; sn != sn_size; ++sn) { + if (strcmp(parser->function->static_names[sn], var->name) == 0) + break; + } + if (sn != sn_size) { + char *num = NULL; + int len = util_asprintf(&num, "#%u", parser->function->static_count); + vec_append(defname, len, num); + mem_d(num); + } + else + vec_push(parser->function->static_names, util_strdup(var->name)); + parser->function->static_count++; ast_value_set_name(var, defname); /* push it to the to-be-generated globals */ @@ -5504,16 +5644,8 @@ skipvar: if (parser->tok != '{' || var->expression.vtype != TYPE_FUNCTION) { if (parser->tok != '=') { - if (!strcmp(parser_tokval(parser), "break")) { - if (!parser_next(parser)) { - parseerror(parser, "error parsing break definition"); - break; - } - (void)!parsewarning(parser, WARN_BREAKDEF, "break definition ignored (suggest removing it)"); - } else { - parseerror(parser, "missing semicolon or initializer, got: `%s`", parser_tokval(parser)); - break; - } + parseerror(parser, "missing semicolon or initializer, got: `%s`", parser_tokval(parser)); + break; } if (!parser_next(parser)) { @@ -5652,17 +5784,18 @@ skipvar: if (!cexp) break; - if (!localblock) { + if (!localblock || is_static) { cval = (ast_value*)cexp; if (cval != parser->nil && (!ast_istype(cval, ast_value) || ((!cval->hasvalue || cval->cvq != CV_CONST) && !cval->isfield)) ) { - parseerror(parser, "cannot initialize a global constant variable with a non-constant expression"); + parseerror(parser, "initializer is non constant"); } else { - if (!OPTS_FLAG(INITIALIZED_NONCONSTANTS) && + if (!is_static && + !OPTS_FLAG(INITIALIZED_NONCONSTANTS) && qualifier != CV_VAR) { var->cvq = CV_CONST; @@ -5766,7 +5899,7 @@ static bool parser_global_statement(parser_t *parser) if (parser->tok == TOKEN_IDENT) istype = parser_find_typedef(parser, parser_tokval(parser), 0); - if (istype || parser->tok == TOKEN_TYPENAME || parser->tok == '.') + if (istype || parser->tok == TOKEN_TYPENAME || parser->tok == '.' || parser->tok == TOKEN_DOTS) { return parse_variable(parser, NULL, false, CV_NONE, istype, false, false, 0, NULL); } @@ -5905,7 +6038,7 @@ parser_t *parser_create() } } if (!parser->assign_op) { - printf("internal error: initializing parser: failed to find assign operator\n"); + con_err("internal error: initializing parser: failed to find assign operator\n"); mem_d(parser); return NULL; }