X-Git-Url: https://git.xonotic.org/?p=xonotic%2Fgmqcc.git;a=blobdiff_plain;f=parser.c;h=ea4930f02b79f8d0d4b4f52e4a6e9fdee7d1b94c;hp=71242ac79a81850d57209a2f7234323e478d390f;hb=557ad9da1af1c777f83455a4f86d9703fa297562;hpb=e6bb7697f9d7c25c7b77da1a3b746092ad7f3e9d diff --git a/parser.c b/parser.c index 71242ac..ea4930f 100644 --- a/parser.c +++ b/parser.c @@ -31,8 +31,8 @@ /* beginning of locals */ #define PARSER_HT_LOCALS 2 -#define PARSER_HT_SIZE 128 -#define TYPEDEF_HT_SIZE 16 +#define PARSER_HT_SIZE 512 +#define TYPEDEF_HT_SIZE 512 typedef struct parser_s { lex_file *lex; @@ -49,6 +49,7 @@ typedef struct parser_s { size_t translated; ht ht_imm_string; + ht ht_imm_string_dotranslate; /* must be deleted first, they reference immediates and values */ ast_value **accessors; @@ -104,9 +105,6 @@ typedef struct parser_s { /* collected information */ size_t max_param_count; - - /* code generator */ - code_t *code; } parser_t; static ast_expression * const intrinsic_debug_typestring = (ast_expression*)0x1; @@ -260,17 +258,15 @@ static char *parser_strdup(const char *str) static ast_value* parser_const_string(parser_t *parser, const char *str, bool dotranslate) { - size_t hash = util_hthash(parser->ht_imm_string, str); + ht ht_string = (dotranslate) + ? parser->ht_imm_string_dotranslate + : parser->ht_imm_string; + ast_value *out; - if ( (out = (ast_value*)util_htgeth(parser->ht_imm_string, str, hash)) ) { - if (dotranslate && out->name[0] == '#') { - char name[32]; - util_snprintf(name, sizeof(name), "dotranslate_%lu", (unsigned long)(parser->translated++)); - ast_value_set_name(out, name); - out->expression.flags |= AST_FLAG_INCLUDE_DEF; - } + size_t hash = util_hthash(ht_string, str); + + if ((out = (ast_value*)util_htgeth(ht_string, str, hash))) return out; - } /* for (i = 0; i < vec_size(parser->imm_string); ++i) { if (!strcmp(parser->imm_string[i]->constval.vstring, str)) @@ -284,12 +280,14 @@ static ast_value* parser_const_string(parser_t *parser, const char *str, bool do out->expression.flags |= AST_FLAG_INCLUDE_DEF; } else out = ast_value_new(parser_ctx(parser), "#IMMEDIATE", TYPE_STRING); + out->cvq = CV_CONST; out->hasvalue = true; out->isimm = true; out->constval.vstring = parser_strdup(str); vec_push(parser->imm_string, out); - util_htseth(parser->ht_imm_string, str, hash, out); + util_htseth(ht_string, str, hash, out); + return out; } @@ -952,7 +950,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) if (exprs[1]->vtype != 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 expression: cannot divide tyeps %s and %s", ty1, ty2); + compile_error(ctx, "invalid types used in expression: cannot divide types %s and %s", ty1, ty2); return false; } if (exprs[0]->vtype == TYPE_FLOAT) { @@ -983,7 +981,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) { 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 expression: cannot divide tyeps %s and %s", ty1, ty2); + compile_error(ctx, "invalid types used in expression: cannot divide types %s and %s", ty1, ty2); return false; } break; @@ -1044,20 +1042,20 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) * Further more, the only time it is legal to do XOR otherwise * is when both operand are floats. This nicely crafted if * statement catches them all. - * + * * In the event that the first operand is a vector, two * possible situations can arise, thus, each element of * vector A (operand A) is exclusive-ORed with the corresponding * element of vector B (operand B), If B is scalar, the * scalar value is first replicated for each element. - * + * * The QCVM itself lacks a BITXOR instruction. Thus emulating * the mathematics of it is required. The following equation * is used: (LHS | RHS) & ~(LHS & RHS). However, due to the * QCVM also lacking a BITNEG instruction, we need to emulate * ~FOO with -1 - FOO, the whole process becoming this nicely * crafted expression: (LHS | RHS) & (-1 - (LHS & RHS)). - * + * * When A is not scalar, this process is repeated for all * components of vector A with the value in operand B, * only if operand B is scalar. When A is not scalar, and B @@ -1065,7 +1063,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) * components of the vector A with the components of vector B. * Finally when A is scalar and B is scalar, this process is * simply used once for A and B being LHS and RHS respectfully. - * + * * Yes the semantics are a bit strange (no pun intended). * But then again BITXOR is strange itself, consdering it's * commutative, assocative, and elements of the BITXOR operation @@ -1101,7 +1099,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) ) ); expr->refs = AST_REF_NONE; - + out = (ast_expression*) ast_binary_new( ctx, @@ -1154,7 +1152,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) } } } - + break; case opid2('<','<'): @@ -2059,7 +2057,7 @@ static bool parse_sya_operand(parser_t *parser, shunt *sy, bool with_labels) correct = correct_str(&corr, parser->correct_variables[i], parser_tokval(parser)); if (strcmp(correct, parser_tokval(parser))) { break; - } else if (correct) { + } else { mem_d(correct); correct = NULL; } @@ -2517,7 +2515,8 @@ static ast_expression* process_condition(parser_t *parser, ast_expression *cond, } unary = (ast_unary*)cond; - while (ast_istype(cond, ast_unary) && unary->op == INSTR_NOT_F) + /* ast_istype dereferences cond, should test here for safety */ + while (cond && ast_istype(cond, ast_unary) && unary->op == INSTR_NOT_F) { cond = unary->operand; unary->operand = NULL; @@ -2757,7 +2756,12 @@ static bool parse_dowhile(parser_t *parser, ast_block *block, ast_expression **o if (vec_last(parser->breaks) != label || vec_last(parser->continues) != label) { parseerror(parser, "internal error: label stack corrupted"); rv = false; - ast_delete(*out); + /* + * Test for NULL otherwise ast_delete dereferences null pointer + * and boom. + */ + if (*out) + ast_delete(*out); *out = NULL; } else { @@ -3625,7 +3629,8 @@ static bool parse_goto(parser_t *parser, ast_expression **out) if (!(expression = parse_expression(parser, false, true)) || !(*out = parse_goto_computed(parser, &expression))) { parseerror(parser, "invalid goto expression"); - ast_unref(expression); + if(expression) + ast_unref(expression); return false; } @@ -5887,8 +5892,16 @@ skipvar: if (parser->tok != '{' || var->expression.vtype != TYPE_FUNCTION) { if (parser->tok != '=') { - parseerror(parser, "missing semicolon or initializer, got: `%s`", parser_tokval(parser)); - break; + 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; + } } if (!parser_next(parser)) { @@ -6204,7 +6217,7 @@ static uint16_t progdefs_crc_both(uint16_t old, const char *str) return old; } -static void generate_checksum(parser_t *parser) +static void generate_checksum(parser_t *parser, ir_builder *ir) { uint16_t crc = 0xFFFF; size_t i; @@ -6258,8 +6271,7 @@ static void generate_checksum(parser_t *parser) crc = progdefs_crc_both(crc, ";\n"); } crc = progdefs_crc_both(crc, "} entvars_t;\n\n"); - - parser->code->crc = crc; + ir->code->crc = crc; } parser_t *parser_create() @@ -6274,11 +6286,6 @@ parser_t *parser_create() memset(parser, 0, sizeof(*parser)); - if (!(parser->code = code_init())) { - mem_d(parser); - return NULL; - } - for (i = 0; i < operator_count; ++i) { if (operators[i].id == opid1('=')) { parser->assign_op = operators+i; @@ -6299,13 +6306,15 @@ parser_t *parser_create() parser->aliases = util_htnew(PARSER_HT_SIZE); parser->ht_imm_string = util_htnew(512); + parser->ht_imm_string_dotranslate = util_htnew(512); /* corrector */ vec_push(parser->correct_variables, correct_trie_new()); vec_push(parser->correct_variables_score, NULL); - empty_ctx.file = ""; - empty_ctx.line = 0; + empty_ctx.file = ""; + empty_ctx.line = 0; + empty_ctx.column = 0; parser->nil = ast_value_new(empty_ctx, "nil", TYPE_NIL); parser->nil->cvq = CV_CONST; if (OPTS_FLAG(UNTYPED_NIL)) @@ -6415,6 +6424,7 @@ static void parser_remove_ast(parser_t *parser) vec_free(parser->functions); vec_free(parser->imm_vector); vec_free(parser->imm_string); + util_htdel(parser->ht_imm_string_dotranslate); util_htdel(parser->ht_imm_string); vec_free(parser->imm_float); vec_free(parser->globals); @@ -6453,7 +6463,7 @@ static void parser_remove_ast(parser_t *parser) ast_value_delete(parser->const_vec[0]); ast_value_delete(parser->const_vec[1]); ast_value_delete(parser->const_vec[2]); - + if (parser->reserved_version) ast_value_delete(parser->reserved_version); @@ -6464,8 +6474,6 @@ static void parser_remove_ast(parser_t *parser) void parser_cleanup(parser_t *parser) { parser_remove_ast(parser); - code_cleanup(parser->code); - mem_d(parser); } @@ -6623,7 +6631,8 @@ bool parser_finish(parser_t *parser, const char *output) } } - generate_checksum(parser); + generate_checksum(parser, ir); + if (OPTS_OPTION_BOOL(OPTION_DUMP)) ir_builder_dump(ir, con_out); for (i = 0; i < vec_size(parser->functions); ++i) { @@ -6645,7 +6654,7 @@ bool parser_finish(parser_t *parser, const char *output) if (OPTS_OPTION_BOOL(OPTION_DUMPFIN)) ir_builder_dump(ir, con_out); - if (!ir_builder_generate(parser->code, ir, output)) { + if (!ir_builder_generate(ir, output)) { con_out("*** failed to generate output file\n"); ir_builder_delete(ir); return false;