X-Git-Url: https://git.xonotic.org/?p=xonotic%2Fgmqcc.git;a=blobdiff_plain;f=parser.c;h=f589d63629361ddc6b48edd09d20299bb93227ef;hp=a54094a841f32beb80f736f756f7b00fee1226f8;hb=b3e87c328009c3c5b1b700d600733906d7792f59;hpb=36c5722273f1ea87603621c6ee20b7178a7a641b diff --git a/parser.c b/parser.c index a54094a..f589d63 100644 --- a/parser.c +++ b/parser.c @@ -51,7 +51,10 @@ typedef struct { ast_value *imm_float_zero; ast_value *imm_float_one; + ast_value *imm_float_neg_one; + ast_value *imm_vector_zero; + ast_value *nil; ast_value *reserved_version; @@ -222,6 +225,12 @@ static ast_value* parser_const_float_0(parser_t *parser) return parser->imm_float_zero; } +static ast_value* parser_const_float_neg1(parser_t *parser) { + if (!parser->imm_float_neg_one) + parser->imm_float_neg_one = parser_const_float(parser, -1); + return parser->imm_float_neg_one; +} + static ast_value* parser_const_float_1(parser_t *parser) { if (!parser->imm_float_one) @@ -440,7 +449,7 @@ static sy_elem syparen(lex_ctx ctx, size_t off) { */ static bool rotate_entfield_array_index_nodes(ast_expression **out) { - ast_array_index *index; + ast_array_index *index, *oldindex; ast_entfield *entfield; ast_value *field; @@ -464,12 +473,16 @@ static bool rotate_entfield_array_index_nodes(ast_expression **out) sub = index->index; entity = entfield->entity; - ast_delete(index); + oldindex = index; index = ast_array_index_new(ctx, (ast_expression*)field, sub); entfield = ast_entfield_new(ctx, entity, (ast_expression*)index); *out = (ast_expression*)entfield; + oldindex->array = NULL; + oldindex->index = NULL; + ast_delete(oldindex); + return true; } @@ -658,8 +671,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) return false; } } - if (!ast_block_set_type(blocks[0], exprs[1])) - return false; + ast_block_set_type(blocks[0], exprs[1]); vec_push(sy->out, syblock(ctx, blocks[0])); return true; @@ -1055,6 +1067,49 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) out = (ast_expression*)ast_ternary_new(ctx, exprs[0], exprs[1], exprs[2]); break; + case opid3('<', '=', '>'): /* -1, 0, or 1 */ + if (NotSameType(TYPE_FLOAT)) { + ast_type_to_string(exprs[0], ty1, sizeof(ty1)); + ast_type_to_string(exprs[1], ty2, sizeof(ty2)); + compile_error(ctx, "invalid types used in comparision: %s and %s", + ty1, ty2); + + return false; + } + + if (CanConstFold(exprs[0], exprs[1])) { + if (ConstF(0) < ConstF(1)) + out = (ast_expression*)parser_const_float_neg1(parser); + else if (ConstF(0) == ConstF(1)) + out = (ast_expression*)parser_const_float_0(parser); + else if (ConstF(0) > ConstF(1)) + out = (ast_expression*)parser_const_float_1(parser); + } else { + ast_binary *eq = ast_binary_new(ctx, INSTR_EQ_F, exprs[0], exprs[1]); + + eq->refs = false; /* references nothing */ + + /* if (lt) { */ + out = (ast_expression*)ast_ternary_new(ctx, + (ast_expression*)ast_binary_new(ctx, INSTR_LT, exprs[0], exprs[1]), + /* out = -1 */ + (ast_expression*)parser_const_float_neg1(parser), + /* } else { */ + /* if (eq) { */ + (ast_expression*)ast_ternary_new(ctx, (ast_expression*)eq, + /* out = 0 */ + (ast_expression*)parser_const_float_0(parser), + /* } else { */ + /* out = 1 */ + (ast_expression*)parser_const_float_1(parser) + /* } */ + ) + /* } */ + ); + + } + break; + case opid1('>'): generated_op += 1; /* INSTR_GT */ case opid1('<'): @@ -1101,7 +1156,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 == VINSTR_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)); @@ -1128,7 +1183,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) assignop = type_store_instr[exprs[0]->expression.vtype]; } - if (assignop == AINSTR_END) { + if (assignop == VINSTR_END) { ast_type_to_string(exprs[0], ty1, sizeof(ty1)); ast_type_to_string(exprs[1], ty2, sizeof(ty2)); compile_error(ctx, "invalid types in assignment: cannot assign %s to %s", ty2, ty1); @@ -1346,6 +1401,19 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) asbinstore->keep_dest = true; out = (ast_expression*)asbinstore; break; + + case opid2('~', 'P'): + if (exprs[0]->expression.vtype != TYPE_FLOAT) { + ast_type_to_string(exprs[0], ty1, sizeof(ty1)); + compile_error(ast_ctx(exprs[0]), "invalid type for bit not: %s", ty1); + return false; + } + + if(CanConstFold1(exprs[0])) + out = (ast_expression*)parser_const_float(parser, ~(qcint)ConstF(0)); + else + out = (ast_expression*)ast_binary_new(ctx, INSTR_SUB_F, (ast_expression*)parser_const_float_neg1(parser), exprs[0]); + break; } #undef NotSameType @@ -1871,8 +1939,8 @@ static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma } } if (o == operator_count) { - /* no operator found... must be the end of the statement */ - break; + compile_error(parser_ctx(parser), "unknown operator: %s", parser_tokval(parser)); + goto onerr; } /* found an operator */ op = &operators[o]; @@ -3292,26 +3360,15 @@ static bool parse_eol(parser_t *parser) return parser->tok == TOKEN_EOL; } -/* - * Traditionally you'd implement warning, error, and message - * directives in the preprocessor. However, like #pragma, these - * shouldn't depend on -fftepp to utilize. So they're instead - * implemented here. - */ -enum { - PARSE_DIRECTIVE_ERROR, - PARSE_DIRECTIVE_MESSAGE, - PARSE_DIRECTIVE_WARNING, - PARSE_DIRECTIVE_COUNT -}; - -static const char *parser_directives[PARSE_DIRECTIVE_COUNT] = { - "error", - "message", - "warning" -}; - -static bool parse_pragma_do(parser_t *parser) { +static bool parse_pragma_do(parser_t *parser) +{ + if (!parser_next(parser) || + parser->tok != TOKEN_IDENT || + strcmp(parser_tokval(parser), "pragma")) + { + parseerror(parser, "expected `pragma` keyword after `#`, got `%s`", parser_tokval(parser)); + return false; + } if (!parse_skipwhite(parser) || parser->tok != TOKEN_IDENT) { parseerror(parser, "expected pragma, got `%s`", parser_tokval(parser)); return false; @@ -3322,99 +3379,35 @@ static bool parse_pragma_do(parser_t *parser) { parseerror(parser, "`noref` pragma requires an argument: 0 or 1"); return false; } - parser->noref = !!parser_token(parser)->constval.i; - if (!parse_eol(parser)) { parseerror(parser, "parse error after `noref` pragma"); return false; } - } else { - (void)!parsewarning(parser, WARN_UNKNOWN_PRAGMAS, "ignoring #pragma %s", parser_tokval(parser)); - return false; } - return true; -} - -static bool parse_directive_or_pragma_do(parser_t *parser, bool *pragma) { - - size_t type = PARSE_DIRECTIVE_COUNT; - - if (!parser_next(parser) || parser->tok != TOKEN_IDENT) { - parseerror(parser, "expected `pragma, error, message, warning` after `#`, got `%s`", - parser_tokval(parser)); - + else + { + (void)!parsewarning(parser, WARN_UNKNOWN_PRAGMAS, "ignoring #pragma %s", parser_tokval(parser)); return false; } - if (!strcmp(parser_tokval(parser), "pragma" )) { - *pragma = true; - - return parse_pragma_do(parser); - } - - if (!strcmp(parser_tokval(parser), "error" )) type = PARSE_DIRECTIVE_ERROR; - if (!strcmp(parser_tokval(parser), "message")) type = PARSE_DIRECTIVE_MESSAGE; - if (!strcmp(parser_tokval(parser), "warning")) type = PARSE_DIRECTIVE_WARNING; - - switch (type) { - case PARSE_DIRECTIVE_ERROR: - case PARSE_DIRECTIVE_MESSAGE: - case PARSE_DIRECTIVE_WARNING: - *pragma = false; - - if (!parse_skipwhite(parser) || parser->tok != TOKEN_STRINGCONST) { - parseerror(parser, "expected %s, got `%`", parser_directives[type], parser_tokval(parser)); - return false; - } - - switch (type) { - case PARSE_DIRECTIVE_ERROR: - con_cprintmsg(&parser->lex->tok.ctx, LVL_ERROR, "error", parser_tokval(parser)); - compile_errors ++; /* hack */ - break; - /*break;*/ - - case PARSE_DIRECTIVE_MESSAGE: - con_cprintmsg(&parser->lex->tok.ctx, LVL_MSG, "message", parser_tokval(parser)); - break; - - case PARSE_DIRECTIVE_WARNING: - con_cprintmsg(&parser->lex->tok.ctx, LVL_WARNING, "warning", parser_tokval(parser)); - break; - } - - if (!parse_eol(parser)) { - parseerror(parser, "parse error after `%` directive", parser_directives[type]); - return false; - } - - return (type != PARSE_DIRECTIVE_ERROR); - } - - parseerror(parser, "invalid directive `%s`", parser_tokval(parser)); - return false; + return true; } -static bool parse_directive_or_pragma(parser_t *parser) +static bool parse_pragma(parser_t *parser) { bool rv; - bool pragma; /* true when parsing pragma */ - parser->lex->flags.preprocessing = true; - parser->lex->flags.mergelines = true; - - rv = parse_directive_or_pragma_do(parser, &pragma); - + parser->lex->flags.mergelines = true; + rv = parse_pragma_do(parser); if (parser->tok != TOKEN_EOL) { - parseerror(parser, "junk after %s", (pragma) ? "pragma" : "directive"); + parseerror(parser, "junk after pragma"); rv = false; } parser->lex->flags.preprocessing = false; - parser->lex->flags.mergelines = false; - + parser->lex->flags.mergelines = false; if (!parser_next(parser)) { - parseerror(parser, "parse error after %s", (pragma) ? "pragma" : "directive"); + parseerror(parser, "parse error after pragma"); rv = false; } return rv; @@ -3899,11 +3892,12 @@ static bool parse_function_body(parser_t *parser, ast_value *var) ast_expression *functype = fld_think->expression.next; thinkfunc = ast_value_new(parser_ctx(parser), parser_tokval(parser), functype->expression.vtype); - if (!thinkfunc || !ast_type_adopt(thinkfunc, functype)) { + if (!thinkfunc) { /* || !ast_type_adopt(thinkfunc, functype)*/ ast_unref(framenum); parseerror(parser, "failed to create implicit prototype for `%s`", parser_tokval(parser)); return false; } + ast_type_adopt(thinkfunc, functype); if (!parser_next(parser)) { ast_unref(framenum); @@ -4029,6 +4023,12 @@ 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; + } + func = ast_function_new(ast_ctx(var), var->name, var); if (!func) { parseerror(parser, "failed to allocate function for `%s`", var->name); @@ -5595,7 +5595,7 @@ static bool parser_global_statement(parser_t *parser) } else if (parser->tok == '#') { - return parse_directive_or_pragma(parser); + return parse_pragma(parser); } else if (parser->tok == '$') { @@ -5606,7 +5606,7 @@ static bool parser_global_statement(parser_t *parser) } else { - parseerror(parser, "unexpected token: %s", parser->lex->tok.value); + parseerror(parser, "unexpected token: `%s`", parser->lex->tok.value); return false; } return true;