X-Git-Url: https://git.xonotic.org/?p=xonotic%2Fgmqcc.git;a=blobdiff_plain;f=parser.c;h=aa536c50ac8161f4cba91617781cfb2603c4aa7e;hp=d64dd2e1de187c2f133b528b07a0a443cf1591a4;hb=e11a17b40805b93e1e2ae80129c9d235b6d6119b;hpb=3d35804a7d79a99527cf785a133aaff0dd24b457 diff --git a/parser.c b/parser.c index d64dd2e..aa536c5 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; } @@ -630,7 +643,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) { #if 0 /* This is not broken in fteqcc anymore */ - if (opts.standard != COMPILER_GMQCC) { + if (OPTS_OPTION_U32(OPTION_STANDARD) != COMPILER_GMQCC) { /* this error doesn't need to make us bail out */ (void)!parsewarning(parser, WARN_EXTENSIONS, "accessing array-field members of an entity without parenthesis\n" @@ -1101,7 +1114,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 +1141,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 +1359,20 @@ 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 @@ -1784,7 +1811,7 @@ static bool parse_sya_operand(parser_t *parser, shunt *sy, bool with_labels) * We should also consider adding correction tables for * other things as well. */ - if (opts.correction) { + if (OPTS_OPTION_BOOL(OPTION_CORRECTION)) { correction_t corr; correct_init(&corr); @@ -2635,7 +2662,7 @@ static bool parse_for_go(parser_t *parser, ast_block *block, ast_expression **ou if (typevar || parser->tok == TOKEN_TYPENAME) { #if 0 - if (opts.standard != COMPILER_GMQCC) { + if (OPTS_OPTION_U32(OPTION_STANDARD) != COMPILER_GMQCC) { if (parsewarning(parser, WARN_EXTENSIONS, "current standard does not allow variable declarations in for-loop initializers")) goto onerr; @@ -3292,26 +3319,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,102 +3338,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); - - default: - 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; @@ -3443,7 +3392,7 @@ static bool parse_statement(parser_t *parser, ast_block *block, ast_expression * parseerror(parser, "cannot declare a variable from here"); return false; } - if (opts.standard == COMPILER_QCC) { + if (OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_QCC) { if (parsewarning(parser, WARN_EXTENSIONS, "missing 'local' keyword when declaring a local variable")) return false; } @@ -3510,7 +3459,7 @@ static bool parse_statement(parser_t *parser, ast_block *block, ast_expression * } else if (!strcmp(parser_tokval(parser), "for")) { - if (opts.standard == COMPILER_QCC) { + if (OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_QCC) { if (parsewarning(parser, WARN_EXTENSIONS, "for loops are not recognized in the original Quake C standard, to enable try an alternate standard --std=?")) return false; } @@ -4112,7 +4061,7 @@ static bool parse_function_body(parser_t *parser, ast_value *var) if (parser->tok == ';') return parser_next(parser); - else if (opts.standard == COMPILER_QCC) + else if (OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_QCC) parseerror(parser, "missing semicolon after function body (mandatory with -std=qcc)"); return retval; @@ -4628,7 +4577,7 @@ static ast_value *parse_parameter_list(parser_t *parser, ast_value *var) vec_free(params); /* sanity check */ - if (vec_size(params) > 8 && opts.standard == COMPILER_QCC) + if (vec_size(params) > 8 && OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_QCC) (void)!parsewarning(parser, WARN_EXTENSIONS, "more than 8 parameters are not supported by this standard"); /* parse-out */ @@ -4842,7 +4791,7 @@ static ast_value *parse_typename(parser_t *parser, ast_value **storebase, ast_va } /* now there may be function parens again */ - if (parser->tok == '(' && opts.standard == COMPILER_QCC) + if (parser->tok == '(' && OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_QCC) parseerror(parser, "C-style function syntax is not allowed in -std=qcc"); if (parser->tok == '(' && wasarray) parseerror(parser, "arrays as part of a return type is not supported"); @@ -4981,7 +4930,7 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield /* Part 0: finish the type */ if (parser->tok == '(') { - if (opts.standard == COMPILER_QCC) + if (OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_QCC) parseerror(parser, "C-style function syntax is not allowed in -std=qcc"); var = parse_parameter_list(parser, var); if (!var) { @@ -5004,7 +4953,7 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield } /* for functions returning functions */ while (parser->tok == '(') { - if (opts.standard == COMPILER_QCC) + if (OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_QCC) parseerror(parser, "C-style function syntax is not allowed in -std=qcc"); var = parse_parameter_list(parser, var); if (!var) { @@ -5074,7 +5023,7 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield goto cleanup; */ } - if ((opts.standard == COMPILER_QCC || opts.standard == COMPILER_FTEQCC) && + if ((OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_QCC || OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_FTEQCC) && (old = parser_find_global(parser, var->name))) { parseerror(parser, "cannot declare a field and a global of the same name with -std=qcc"); @@ -5146,7 +5095,7 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield ast_delete(var); var = proto; } - if (opts.standard == COMPILER_QCC && + if (OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_QCC && (old = parser_find_field(parser, var->name))) { parseerror(parser, "cannot declare a field and a global of the same name with -std=qcc"); @@ -5177,7 +5126,7 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield retval = false; goto cleanup; } - if (opts.standard != COMPILER_GMQCC) { + if (OPTS_OPTION_U32(OPTION_STANDARD) != COMPILER_GMQCC) { ast_delete(var); var = NULL; goto skipvar; @@ -5357,7 +5306,7 @@ skipvar: break; } - if (localblock && opts.standard == COMPILER_QCC) { + if (localblock && OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_QCC) { if (parsewarning(parser, WARN_LOCAL_CONSTANTS, "initializing expression turns variable `%s` into a constant in this standard", var->name) ) @@ -5377,7 +5326,7 @@ skipvar: break; } } - else if (opts.standard == COMPILER_QCC) { + else if (OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_QCC) { parseerror(parser, "expected '=' before function body in this standard"); } @@ -5598,7 +5547,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 == '$') { @@ -5609,7 +5558,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; @@ -5738,7 +5687,7 @@ bool parser_init() parser->const_vec[1] = ast_value_new(empty_ctx, "", TYPE_NOEXPR); parser->const_vec[2] = ast_value_new(empty_ctx, "", TYPE_NOEXPR); - if (opts.add_info) { + if (OPTS_OPTION_BOOL(OPTION_ADD_INFO)) { parser->reserved_version = ast_value_new(empty_ctx, "reserved:version", TYPE_STRING); parser->reserved_version->cvq = CV_CONST; parser->reserved_version->hasvalue = true; @@ -6027,7 +5976,7 @@ bool parser_finish(const char *output) return false; } } - if (opts.dump) + if (OPTS_OPTION_BOOL(OPTION_DUMP)) ir_builder_dump(ir, con_out); for (i = 0; i < vec_size(parser->functions); ++i) { if (!ir_function_finalize(parser->functions[i]->ir_func)) { @@ -6044,7 +5993,7 @@ bool parser_finish(const char *output) } if (retval) { - if (opts.dumpfin) + if (OPTS_OPTION_BOOL(OPTION_DUMPFIN)) ir_builder_dump(ir, con_out); generate_checksum(parser);