X-Git-Url: https://git.xonotic.org/?p=xonotic%2Fgmqcc.git;a=blobdiff_plain;f=parser.c;h=b7d4bf56ae560296063261be7609ce112d43cc04;hp=6af6e5e996e6cc41effe4effd818579ef7044171;hb=3e43056f5fb107bc32daacbc75084563977b404e;hpb=0b6637cc67dad84b3e0f357c994ef625528b3e1f diff --git a/parser.c b/parser.c index 6af6e5e..b7d4bf5 100644 --- a/parser.c +++ b/parser.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012, 2013 + * Copyright (C) 2012, 2013, 2014 * Wolfgang Bumiller * Dale Weiler * @@ -1293,7 +1293,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 +1548,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)); @@ -2822,7 +2822,7 @@ static bool parse_qualifiers(parser_t *parser, bool with_local, int *cvq, bool * { "inline", AST_FLAG_INLINE }, { "eraseable", AST_FLAG_ERASEABLE }, { "accumulate", AST_FLAG_ACCUMULATE }, - { "definite", AST_FLAG_FINAL_DECL } + { "last", AST_FLAG_FINAL_DECL } }; *cvq = CV_NONE; @@ -2944,6 +2944,47 @@ static bool parse_qualifiers(parser_t *parser, bool with_local, int *cvq, bool * return false; } } + else if (!strcmp(parser_tokval(parser), "coverage") && !(flags & AST_FLAG_COVERAGE)) { + flags |= AST_FLAG_COVERAGE; + if (!parser_next(parser)) { + error_in_coverage: + parseerror(parser, "parse error in coverage attribute"); + *cvq = CV_WRONG; + return false; + } + if (parser->tok == '(') { + if (!parser_next(parser)) { + bad_coverage_arg: + parseerror(parser, "invalid parameter for coverage() attribute\n" + "valid are: block"); + *cvq = CV_WRONG; + return false; + } + if (parser->tok != ')') { + do { + if (parser->tok != TOKEN_IDENT) + goto bad_coverage_arg; + if (!strcmp(parser_tokval(parser), "block")) + flags |= AST_FLAG_BLOCK_COVERAGE; + else if (!strcmp(parser_tokval(parser), "none")) + flags &= ~(AST_FLAG_COVERAGE_MASK); + else + goto bad_coverage_arg; + if (!parser_next(parser)) + goto error_in_coverage; + if (parser->tok == ',') { + if (!parser_next(parser)) + goto error_in_coverage; + } + } while (parser->tok != ')'); + } + if (parser->tok != ')' || !parser_next(parser)) + goto error_in_coverage; + } else { + /* without parameter [[coverage]] equals [[coverage(block)]] */ + flags |= AST_FLAG_BLOCK_COVERAGE; + } + } else { /* Skip tokens until we hit a ]] */ @@ -3974,69 +4015,83 @@ static bool parse_function_body(parser_t *parser, ast_value *var) } if (has_frame_think) { - lex_ctx_t ctx; - ast_expression *self_frame; - ast_expression *self_nextthink; - ast_expression *self_think; - ast_expression *time_plus_1; - ast_store *store_frame; - ast_store *store_nextthink; - ast_store *store_think; - - ctx = parser_ctx(parser); - self_frame = (ast_expression*)ast_entfield_new(ctx, gbl_self, fld_frame); - self_nextthink = (ast_expression*)ast_entfield_new(ctx, gbl_self, fld_nextthink); - 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, 0.1f)); - - if (!self_frame || !self_nextthink || !self_think || !time_plus_1) { - if (self_frame) ast_delete(self_frame); - if (self_nextthink) ast_delete(self_nextthink); - if (self_think) ast_delete(self_think); - if (time_plus_1) ast_delete(time_plus_1); - retval = false; - } - - if (retval) - { - store_frame = ast_store_new(ctx, INSTR_STOREP_F, self_frame, framenum); - store_nextthink = ast_store_new(ctx, INSTR_STOREP_F, self_nextthink, time_plus_1); - store_think = ast_store_new(ctx, INSTR_STOREP_FNC, self_think, nextthink); - - if (!store_frame) { - ast_delete(self_frame); - retval = false; - } - if (!store_nextthink) { - ast_delete(self_nextthink); - retval = false; - } - if (!store_think) { - ast_delete(self_think); - retval = false; + if (!OPTS_FLAG(EMULATE_STATE)) { + ast_state *state_op = ast_state_new(parser_ctx(parser), framenum, nextthink); + if (!ast_block_add_expr(block, (ast_expression*)state_op)) { + parseerror(parser, "failed to generate state op for [frame,think]"); + ast_unref(nextthink); + ast_unref(framenum); + ast_delete(block); + return false; } - if (!retval) { - if (store_frame) ast_delete(store_frame); - if (store_nextthink) ast_delete(store_nextthink); - if (store_think) ast_delete(store_think); + } else { + /* emulate OP_STATE in code: */ + lex_ctx_t ctx; + ast_expression *self_frame; + ast_expression *self_nextthink; + ast_expression *self_think; + ast_expression *time_plus_1; + ast_store *store_frame; + ast_store *store_nextthink; + ast_store *store_think; + + float frame_delta = 1.0f / (float)OPTS_OPTION_U32(OPTION_STATE_FPS); + + ctx = parser_ctx(parser); + self_frame = (ast_expression*)ast_entfield_new(ctx, gbl_self, fld_frame); + self_nextthink = (ast_expression*)ast_entfield_new(ctx, gbl_self, fld_nextthink); + 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, false)); + + if (!self_frame || !self_nextthink || !self_think || !time_plus_1) { + if (self_frame) ast_delete(self_frame); + if (self_nextthink) ast_delete(self_nextthink); + if (self_think) ast_delete(self_think); + if (time_plus_1) ast_delete(time_plus_1); retval = false; } - if (!ast_block_add_expr(block, (ast_expression*)store_frame) || - !ast_block_add_expr(block, (ast_expression*)store_nextthink) || - !ast_block_add_expr(block, (ast_expression*)store_think)) + + if (retval) { - retval = false; + store_frame = ast_store_new(ctx, INSTR_STOREP_F, self_frame, framenum); + store_nextthink = ast_store_new(ctx, INSTR_STOREP_F, self_nextthink, time_plus_1); + store_think = ast_store_new(ctx, INSTR_STOREP_FNC, self_think, nextthink); + + if (!store_frame) { + ast_delete(self_frame); + retval = false; + } + if (!store_nextthink) { + ast_delete(self_nextthink); + retval = false; + } + if (!store_think) { + ast_delete(self_think); + retval = false; + } + if (!retval) { + if (store_frame) ast_delete(store_frame); + if (store_nextthink) ast_delete(store_nextthink); + if (store_think) ast_delete(store_think); + retval = false; + } + if (!ast_block_add_expr(block, (ast_expression*)store_frame) || + !ast_block_add_expr(block, (ast_expression*)store_nextthink) || + !ast_block_add_expr(block, (ast_expression*)store_think)) + { + retval = false; + } } - } - if (!retval) { - parseerror(parser, "failed to generate code for [frame,think]"); - ast_unref(nextthink); - ast_unref(framenum); - ast_delete(block); - return false; + if (!retval) { + parseerror(parser, "failed to generate code for [frame,think]"); + ast_unref(nextthink); + ast_unref(framenum); + ast_delete(block); + return false; + } } } @@ -4114,7 +4169,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; @@ -4172,7 +4227,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); @@ -4205,7 +4260,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; @@ -4271,7 +4326,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; @@ -4334,7 +4389,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; @@ -4366,6 +4421,7 @@ static bool parser_create_array_accessor(parser_t *parser, ast_value *array, con parseerror(parser, "failed to create accessor function value"); return false; } + fval->expression.flags &= ~(AST_FLAG_COVERAGE_MASK); func = ast_function_new(ast_ctx(array), funcname, fval); if (!func) { @@ -5104,6 +5160,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"); @@ -5163,6 +5220,8 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield } var->cvq = qualifier; + if (qflags & AST_FLAG_COVERAGE) /* specified in QC, drop our default */ + var->expression.flags &= ~(AST_FLAG_COVERAGE_MASK); var->expression.flags |= qflags; /* @@ -5565,6 +5624,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 @@ -5772,15 +5832,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; + + /* 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 (!localblock || is_static) { - cval = (ast_value*)cexp; + 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"); @@ -5828,6 +5917,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: @@ -6201,11 +6297,51 @@ void parser_cleanup(parser_t *parser) mem_d(parser); } +static bool parser_set_coverage_func(parser_t *parser, ir_builder *ir) { + size_t i; + ast_expression *expr; + ast_value *cov; + ast_function *func; + + if (!OPTS_OPTION_BOOL(OPTION_COVERAGE)) + return true; + + func = NULL; + for (i = 0; i != vec_size(parser->functions); ++i) { + if (!strcmp(parser->functions[i]->name, "coverage")) { + func = parser->functions[i]; + break; + } + } + if (!func) { + if (OPTS_OPTION_BOOL(OPTION_COVERAGE)) { + con_out("coverage support requested but no coverage() builtin declared\n"); + ir_builder_delete(ir); + return false; + } + return true; + } + + cov = func->vtype; + expr = (ast_expression*)cov; + + if (expr->vtype != TYPE_FUNCTION || vec_size(expr->params) != 0) { + char ty[1024]; + ast_type_to_string(expr, ty, sizeof(ty)); + con_out("invalid type for coverage(): %s\n", ty); + ir_builder_delete(ir); + return false; + } + + ir->coverage_func = func->ir_func->value; + return true; +} + bool parser_finish(parser_t *parser, const char *output) { - size_t i; - ir_builder *ir; - bool retval = true; + size_t i; + ir_builder *ir; + bool retval = true; if (compile_errors) { con_out("*** there were compile errors\n"); @@ -6287,6 +6423,10 @@ bool parser_finish(parser_t *parser, const char *output) if (!fold_generate(parser->fold, ir)) return false; + /* before generating any functions we need to set the coverage_func */ + if (!parser_set_coverage_func(parser, ir)) + return false; + for (i = 0; i < vec_size(parser->globals); ++i) { ast_value *asvalue; if (!ast_istype(parser->globals[i], ast_value))