X-Git-Url: https://git.xonotic.org/?p=xonotic%2Fgmqcc.git;a=blobdiff_plain;f=parser.c;h=672ce86799044024dfc955d3dfc5aec31d5e4f28;hp=06437436ef9c721dc4d8e4bfeafb2c5cd0e3a857;hb=41a76ab91dc6f872b03cd64f51aba86578f330c0;hpb=b7b60e74683ec62eb62e461f757448b3f1a78744 diff --git a/parser.c b/parser.c index 0643743..672ce86 100644 --- a/parser.c +++ b/parser.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012, 2013, 2014 + * Copyright (C) 2012, 2013, 2014, 2015 * Wolfgang Bumiller * Dale Weiler * @@ -953,6 +953,9 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) } } (void)check_write_to(ctx, exprs[0]); + /* When we're a vector of part of an entity field we use STOREP */ + if (ast_istype(exprs[0], ast_member) && ast_istype(((ast_member*)exprs[0])->owner, ast_entfield)) + assignop = INSTR_STOREP_F; out = (ast_expression*)ast_store_new(ctx, assignop, exprs[0], exprs[1]); break; case opid3('+','+','P'): @@ -1145,6 +1148,22 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) out = (ast_expression*)asbinstore; break; + case opid3('l', 'e', 'n'): + if (exprs[0]->vtype != TYPE_STRING && exprs[0]->vtype != TYPE_ARRAY) { + ast_type_to_string(exprs[0], ty1, sizeof(ty1)); + compile_error(ast_ctx(exprs[0]), "invalid type for length operator: %s", ty1); + return false; + } + /* strings must be const, arrays are statically sized */ + if (exprs[0]->vtype == TYPE_STRING && + !(((ast_value*)exprs[0])->hasvalue && ((ast_value*)exprs[0])->cvq == CV_CONST)) + { + compile_error(ast_ctx(exprs[0]), "operand of length operator not a valid constant expression"); + return false; + } + out = fold_op(parser->fold, op, exprs); + break; + case opid2('~', 'P'): if (exprs[0]->vtype != TYPE_FLOAT && exprs[0]->vtype != TYPE_VECTOR) { ast_type_to_string(exprs[0], ty1, sizeof(ty1)); @@ -1293,7 +1312,7 @@ static bool parser_close_call(parser_t *parser, shunt *sy) if ((fun->flags & AST_FLAG_VARIADIC) && !(/*funval->cvq == CV_CONST && */ funval->hasvalue && funval->constval.vfunc->builtin)) { - call->va_count = (ast_expression*)fold_constgen_float(parser->fold, (qcfloat_t)paramcount); + call->va_count = (ast_expression*)fold_constgen_float(parser->fold, (qcfloat_t)paramcount, false); } } @@ -1548,14 +1567,14 @@ static bool parse_sya_operand(parser_t *parser, shunt *sy, bool with_labels) return true; } else if (parser->tok == TOKEN_FLOATCONST) { - ast_expression *val = fold_constgen_float(parser->fold, (parser_token(parser)->constval.f)); + ast_expression *val = fold_constgen_float(parser->fold, (parser_token(parser)->constval.f), false); if (!val) return false; vec_push(sy->out, syexp(parser_ctx(parser), val)); return true; } else if (parser->tok == TOKEN_INTCONST || parser->tok == TOKEN_CHARCONST) { - ast_expression *val = fold_constgen_float(parser->fold, (qcfloat_t)(parser_token(parser)->constval.i)); + ast_expression *val = fold_constgen_float(parser->fold, (qcfloat_t)(parser_token(parser)->constval.i), false); if (!val) return false; vec_push(sy->out, syexp(parser_ctx(parser), val)); @@ -2569,16 +2588,22 @@ static bool parse_for_go(parser_t *parser, ast_block *block, ast_expression **ou initexpr = parse_expression_leave(parser, false, false, false); if (!initexpr) goto onerr; - } - /* move on to condition */ - if (parser->tok != ';') { - parseerror(parser, "expected semicolon after for-loop initializer"); - goto onerr; - } - if (!parser_next(parser)) { - parseerror(parser, "expected for-loop condition"); - goto onerr; + /* move on to condition */ + if (parser->tok != ';') { + parseerror(parser, "expected semicolon after for-loop initializer"); + goto onerr; + } + + if (!parser_next(parser)) { + parseerror(parser, "expected for-loop condition"); + goto onerr; + } + } else { + if (!parser_next(parser)) { + parseerror(parser, "expected for-loop condition"); + goto onerr; + } } /* parse the condition */ @@ -2587,7 +2612,6 @@ static bool parse_for_go(parser_t *parser, ast_block *block, ast_expression **ou if (!cond) goto onerr; } - /* move on to incrementor */ if (parser->tok != ';') { parseerror(parser, "expected semicolon after for-loop initializer"); @@ -3142,7 +3166,7 @@ static bool parse_switch_go(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) { - if (!parse_variable(parser, block, false, CV_NONE, typevar, false, false, 0, NULL)) { + if (!parse_variable(parser, block, true, CV_NONE, typevar, false, false, 0, NULL)) { ast_delete(switchnode); return false; } @@ -3154,7 +3178,7 @@ static bool parse_switch_go(parser_t *parser, ast_block *block, ast_expression * ast_delete(switchnode); return false; } - if (!parse_variable(parser, block, false, cvq, NULL, noref, is_static, qflags, NULL)) { + if (!parse_variable(parser, block, true, cvq, NULL, noref, is_static, qflags, NULL)) { ast_delete(switchnode); return false; } @@ -3462,7 +3486,7 @@ static bool parse_statement(parser_t *parser, ast_block *block, ast_expression * { if (cvq == CV_WRONG) return false; - return parse_variable(parser, block, true, cvq, NULL, noref, is_static, qflags, vstring); + return parse_variable(parser, block, false, cvq, NULL, noref, is_static, qflags, vstring); } else if (parser->tok == TOKEN_KEYWORD) { @@ -4043,7 +4067,7 @@ static bool parse_function_body(parser_t *parser, ast_value *var) self_think = (ast_expression*)ast_entfield_new(ctx, gbl_self, fld_think); time_plus_1 = (ast_expression*)ast_binary_new(ctx, INSTR_ADD_F, - gbl_time, (ast_expression*)fold_constgen_float(parser->fold, frame_delta)); + gbl_time, (ast_expression*)fold_constgen_float(parser->fold, frame_delta, false)); if (!self_frame || !self_nextthink || !self_think || !time_plus_1) { if (self_frame) ast_delete(self_frame); @@ -4169,7 +4193,7 @@ static bool parse_function_body(parser_t *parser, ast_value *var) goto enderrfn; } func->varargs = varargs; - func->fixedparams = (ast_value*)fold_constgen_float(parser->fold, vec_size(var->expression.params)); + func->fixedparams = (ast_value*)fold_constgen_float(parser->fold, vec_size(var->expression.params), false); } parser->function = func; @@ -4227,7 +4251,7 @@ static ast_expression *array_accessor_split( cmp = ast_binary_new(ctx, INSTR_LT, (ast_expression*)index, - (ast_expression*)fold_constgen_float(parser->fold, middle)); + (ast_expression*)fold_constgen_float(parser->fold, middle, false)); if (!cmp) { ast_delete(left); ast_delete(right); @@ -4260,7 +4284,7 @@ static ast_expression *array_setter_node(parser_t *parser, ast_value *array, ast if (value->expression.vtype == TYPE_FIELD && value->expression.next->vtype == TYPE_VECTOR) assignop = INSTR_STORE_V; - subscript = ast_array_index_new(ctx, (ast_expression*)array, (ast_expression*)fold_constgen_float(parser->fold, from)); + subscript = ast_array_index_new(ctx, (ast_expression*)array, (ast_expression*)fold_constgen_float(parser->fold, from, false)); if (!subscript) return NULL; @@ -4326,7 +4350,7 @@ static ast_expression *array_field_setter_node( if (value->expression.vtype == TYPE_FIELD && value->expression.next->vtype == TYPE_VECTOR) assignop = INSTR_STOREP_V; - subscript = ast_array_index_new(ctx, (ast_expression*)array, (ast_expression*)fold_constgen_float(parser->fold, from)); + subscript = ast_array_index_new(ctx, (ast_expression*)array, (ast_expression*)fold_constgen_float(parser->fold, from, false)); if (!subscript) return NULL; @@ -4389,7 +4413,7 @@ static ast_expression *array_getter_node(parser_t *parser, ast_value *array, ast ast_return *ret; ast_array_index *subscript; - subscript = ast_array_index_new(ctx, (ast_expression*)array, (ast_expression*)fold_constgen_float(parser->fold, from)); + subscript = ast_array_index_new(ctx, (ast_expression*)array, (ast_expression*)fold_constgen_float(parser->fold, from, false)); if (!subscript) return NULL; @@ -4693,12 +4717,17 @@ static ast_value *parse_parameter_list(parser_t *parser, ast_value *var) } if (parser->tok == TOKEN_IDENT) { argcounter = util_strdup(parser_tokval(parser)); + ast_value_set_name(param, argcounter); if (!parser_next(parser) || parser->tok != ')') { parseerror(parser, "`...` must be the last parameter of a variadic function declaration"); goto on_error; } } } + if (OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_FTEQCC && param->name[0] == '<') { + parseerror(parser, "parameter name omitted"); + goto on_error; + } } } @@ -5160,6 +5189,7 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield bool wasarray = false; ast_member *me[3] = { NULL, NULL, NULL }; + ast_member *last_me[3] = { NULL, NULL, NULL }; if (!localblock && is_static) parseerror(parser, "`static` qualifier is not supported in global scope"); @@ -5623,6 +5653,7 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield } } } + memcpy(last_me, me, sizeof(me)); me[0] = me[1] = me[2] = NULL; cleanvar = false; /* Part 2.2 @@ -5830,15 +5861,44 @@ skipvar: } else { ast_expression *cexp; ast_value *cval; + bool folded_const = false; cexp = parse_expression_leave(parser, true, false, false); if (!cexp) break; + cval = ast_istype(cexp, ast_value) ? (ast_value*)cexp : NULL; - if (!localblock || is_static) { - cval = (ast_value*)cexp; + /* deal with foldable constants: */ + if (localblock && + var->cvq == CV_CONST && cval && cval->hasvalue && cval->cvq == CV_CONST && !cval->isfield) + { + /* remove it from the current locals */ + if (isvector) { + for (i = 0; i < 3; ++i) { + vec_pop(parser->_locals); + vec_pop(localblock->collect); + } + } + /* do sanity checking, this function really needs refactoring */ + if (vec_last(parser->_locals) != (ast_expression*)var) + parseerror(parser, "internal error: unexpected change in local variable handling"); + else + vec_pop(parser->_locals); + if (vec_last(localblock->locals) != var) + parseerror(parser, "internal error: unexpected change in local variable handling (2)"); + else + vec_pop(localblock->locals); + /* push it to the to-be-generated globals */ + vec_push(parser->globals, (ast_expression*)var); + if (isvector) + for (i = 0; i < 3; ++i) + vec_push(parser->globals, (ast_expression*)last_me[i]); + folded_const = true; + } + + if (folded_const || !localblock || is_static) { if (cval != parser->nil && - (!ast_istype(cval, ast_value) || ((!cval->hasvalue || cval->cvq != CV_CONST) && !cval->isfield)) + (!cval || ((!cval->hasvalue || cval->cvq != CV_CONST) && !cval->isfield)) ) { parseerror(parser, "initializer is non constant"); @@ -5886,6 +5946,13 @@ skipvar: vec_free(sy.argc); var->cvq = cvq; } + /* a constant initialized to an inexact value should be marked inexact: + * const float x = ; should propagate the inexact flag + */ + if (var->cvq == CV_CONST && var->expression.vtype == TYPE_FLOAT) { + if (cval && cval->hasvalue && cval->cvq == CV_CONST) + var->inexact = cval->inexact; + } } another: @@ -5958,7 +6025,7 @@ static bool parser_global_statement(parser_t *parser) { if (cvq == CV_WRONG) return false; - return parse_variable(parser, NULL, true, cvq, NULL, noref, is_static, qflags, vstring); + return parse_variable(parser, NULL, false, cvq, NULL, noref, is_static, qflags, vstring); } else if (parser->tok == TOKEN_IDENT && !strcmp(parser_tokval(parser), "enum")) {