X-Git-Url: https://git.xonotic.org/?p=xonotic%2Fgmqcc.git;a=blobdiff_plain;f=parser.c;h=cbae8d3cc68aaef87fa7ea14c42d202b379a0c56;hp=90d73bae931ec3c9ceb4ea531c008edd8fc2c353;hb=f8db5a7c6d0ba2e5e9624e1de46bb2da9572bb32;hpb=c41ef65cc92193e9b685cc123ca9d4de9d142756 diff --git a/parser.c b/parser.c index 90d73ba..cbae8d3 100644 --- a/parser.c +++ b/parser.c @@ -2,7 +2,7 @@ * Copyright (C) 2012, 2013 * Wolfgang Bumiller * Dale Weiler - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to @@ -21,8 +21,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -#include -#include +#include +#include #include "gmqcc.h" #include "lexer.h" @@ -34,10 +34,12 @@ #define PARSER_HT_SIZE 128 #define TYPEDEF_HT_SIZE 16 -typedef struct { +typedef struct parser_s { lex_file *lex; int tok; + bool ast_cleaned; + ast_expression **globals; ast_expression **fields; ast_function **functions; @@ -46,6 +48,8 @@ typedef struct { ast_value **imm_vector; size_t translated; + ht ht_imm_string; + /* must be deleted first, they reference immediates and values */ ast_value **accessors; @@ -62,6 +66,7 @@ typedef struct { size_t crc_fields; ast_function *function; + ht aliases; /* All the labels the function defined... * Should they be in ast_function instead? @@ -99,6 +104,9 @@ typedef struct { /* collected information */ size_t max_param_count; + + /* code generator */ + code_t *code; } parser_t; static ast_expression * const intrinsic_debug_typestring = (ast_expression*)0x1; @@ -178,7 +186,7 @@ vector vec3_mulvf(vector a, float b) * parsing */ -bool parser_next(parser_t *parser) +static bool parser_next(parser_t *parser) { /* lex_do kills the previous token */ parser->tok = lex_do(parser->lex); @@ -213,6 +221,7 @@ static ast_value* parser_const_float(parser_t *parser, double d) out = ast_value_new(ctx, "#IMMEDIATE", TYPE_FLOAT); out->cvq = CV_CONST; out->hasvalue = true; + out->isimm = true; out->constval.vfloat = d; vec_push(parser->imm_float, out); return out; @@ -251,22 +260,36 @@ static char *parser_strdup(const char *str) static ast_value* parser_const_string(parser_t *parser, const char *str, bool dotranslate) { - size_t i; + size_t hash = util_hthash(parser->ht_imm_string, str); 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; + } + return out; + } + /* for (i = 0; i < vec_size(parser->imm_string); ++i) { if (!strcmp(parser->imm_string[i]->constval.vstring, str)) return parser->imm_string[i]; } + */ if (dotranslate) { char name[32]; - snprintf(name, sizeof(name), "dotranslate_%lu", (unsigned long)(parser->translated++)); + util_snprintf(name, sizeof(name), "dotranslate_%lu", (unsigned long)(parser->translated++)); out = ast_value_new(parser_ctx(parser), name, TYPE_STRING); + 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); return out; } @@ -281,6 +304,7 @@ static ast_value* parser_const_vector(parser_t *parser, vector v) out = ast_value_new(parser_ctx(parser), "#IMMEDIATE", TYPE_VECTOR); out->cvq = CV_CONST; out->hasvalue = true; + out->isimm = true; out->constval.vvec = v; vec_push(parser->imm_vector, out); return out; @@ -318,6 +342,9 @@ static ast_expression* parser_find_label(parser_t *parser, const char *name) static ast_expression* parser_find_global(parser_t *parser, const char *name) { + ast_expression *var = (ast_expression*)util_htget(parser->aliases, parser_tokval(parser)); + if (var) + return var; return (ast_expression*)util_htget(parser->htglobals, name); } @@ -375,6 +402,9 @@ static ast_value* parser_find_typedef(parser_t *parser, const char *name, size_t return NULL; } +/* include intrinsics */ +#include "intrin.h" + typedef struct { size_t etype; /* 0 = expression, others are operators */ @@ -449,7 +479,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; @@ -473,12 +503,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; } @@ -554,7 +588,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) blocks[i] = sy->out[vec_size(sy->out)+i].block; asvalue[i] = (ast_value*)exprs[i]; - if (exprs[i]->expression.vtype == TYPE_NOEXPR && + if (exprs[i]->vtype == TYPE_NOEXPR && !(i != 0 && op->id == opid2('?',':')) && !(i == 1 && op->id == opid1('.'))) { @@ -572,11 +606,11 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) } #define NotSameType(T) \ - (exprs[0]->expression.vtype != exprs[1]->expression.vtype || \ - exprs[0]->expression.vtype != T) + (exprs[0]->vtype != exprs[1]->vtype || \ + exprs[0]->vtype != T) #define CanConstFold1(A) \ (ast_istype((A), ast_value) && ((ast_value*)(A))->hasvalue && (((ast_value*)(A))->cvq == CV_CONST) &&\ - (A)->expression.vtype != TYPE_FUNCTION) + (A)->vtype != TYPE_FUNCTION) #define CanConstFold(A, B) \ (CanConstFold1(A) && CanConstFold1(B)) #define ConstV(i) (asvalue[(i)]->constval.vvec) @@ -589,8 +623,8 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) return false; case opid1('.'): - if (exprs[0]->expression.vtype == TYPE_VECTOR && - exprs[1]->expression.vtype == TYPE_NOEXPR) + if (exprs[0]->vtype == TYPE_VECTOR && + exprs[1]->vtype == TYPE_NOEXPR) { if (exprs[1] == (ast_expression*)parser->const_vec[0]) out = (ast_expression*)ast_member_new(ctx, exprs[0], 0, NULL); @@ -603,14 +637,14 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) return false; } } - else if (exprs[0]->expression.vtype == TYPE_ENTITY) { - if (exprs[1]->expression.vtype != TYPE_FIELD) { + else if (exprs[0]->vtype == TYPE_ENTITY) { + if (exprs[1]->vtype != TYPE_FIELD) { compile_error(ast_ctx(exprs[1]), "type error: right hand of member-operand should be an entity-field"); return false; } out = (ast_expression*)ast_entfield_new(ctx, exprs[0], exprs[1]); } - else if (exprs[0]->expression.vtype == TYPE_VECTOR) { + else if (exprs[0]->vtype == TYPE_VECTOR) { compile_error(ast_ctx(exprs[1]), "vectors cannot be accessed this way"); return false; } @@ -621,15 +655,15 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) break; case opid1('['): - if (exprs[0]->expression.vtype != TYPE_ARRAY && - !(exprs[0]->expression.vtype == TYPE_FIELD && - exprs[0]->expression.next->expression.vtype == TYPE_ARRAY)) + if (exprs[0]->vtype != TYPE_ARRAY && + !(exprs[0]->vtype == TYPE_FIELD && + exprs[0]->next->vtype == TYPE_ARRAY)) { ast_type_to_string(exprs[0], ty1, sizeof(ty1)); compile_error(ast_ctx(exprs[0]), "cannot index value of type %s", ty1); return false; } - if (exprs[1]->expression.vtype != TYPE_FLOAT) { + if (exprs[1]->vtype != TYPE_FLOAT) { ast_type_to_string(exprs[0], ty1, sizeof(ty1)); compile_error(ast_ctx(exprs[1]), "index must be of type float, not %s", ty1); return false; @@ -667,8 +701,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; @@ -677,7 +710,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) out = exprs[0]; break; case opid2('-','P'): - switch (exprs[0]->expression.vtype) { + switch (exprs[0]->vtype) { case TYPE_FLOAT: if (CanConstFold1(exprs[0])) out = (ast_expression*)parser_const_float(parser, -ConstF(0)); @@ -697,13 +730,13 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) break; default: compile_error(ctx, "invalid types used in expression: cannot negate type %s", - type_name[exprs[0]->expression.vtype]); + type_name[exprs[0]->vtype]); return false; } break; case opid2('!','P'): - switch (exprs[0]->expression.vtype) { + switch (exprs[0]->vtype) { case TYPE_FLOAT: if (CanConstFold1(exprs[0])) out = (ast_expression*)parser_const_float(parser, !ConstF(0)); @@ -739,21 +772,21 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) break; default: compile_error(ctx, "invalid types used in expression: cannot logically negate type %s", - type_name[exprs[0]->expression.vtype]); + type_name[exprs[0]->vtype]); return false; } break; case opid1('+'): - if (exprs[0]->expression.vtype != exprs[1]->expression.vtype || - (exprs[0]->expression.vtype != TYPE_VECTOR && exprs[0]->expression.vtype != TYPE_FLOAT) ) + if (exprs[0]->vtype != exprs[1]->vtype || + (exprs[0]->vtype != TYPE_VECTOR && exprs[0]->vtype != TYPE_FLOAT) ) { compile_error(ctx, "invalid types used in expression: cannot add type %s and %s", - type_name[exprs[0]->expression.vtype], - type_name[exprs[1]->expression.vtype]); + type_name[exprs[0]->vtype], + type_name[exprs[1]->vtype]); return false; } - switch (exprs[0]->expression.vtype) { + switch (exprs[0]->vtype) { case TYPE_FLOAT: if (CanConstFold(exprs[0], exprs[1])) { @@ -770,21 +803,21 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) break; default: compile_error(ctx, "invalid types used in expression: cannot add type %s and %s", - type_name[exprs[0]->expression.vtype], - type_name[exprs[1]->expression.vtype]); + type_name[exprs[0]->vtype], + type_name[exprs[1]->vtype]); return false; }; break; case opid1('-'): - if (exprs[0]->expression.vtype != exprs[1]->expression.vtype || - (exprs[0]->expression.vtype != TYPE_VECTOR && exprs[0]->expression.vtype != TYPE_FLOAT) ) + if (exprs[0]->vtype != exprs[1]->vtype || + (exprs[0]->vtype != TYPE_VECTOR && exprs[0]->vtype != TYPE_FLOAT) ) { compile_error(ctx, "invalid types used in expression: cannot subtract type %s from %s", - type_name[exprs[1]->expression.vtype], - type_name[exprs[0]->expression.vtype]); + type_name[exprs[1]->vtype], + type_name[exprs[0]->vtype]); return false; } - switch (exprs[0]->expression.vtype) { + switch (exprs[0]->vtype) { case TYPE_FLOAT: if (CanConstFold(exprs[0], exprs[1])) out = (ast_expression*)parser_const_float(parser, ConstF(0) - ConstF(1)); @@ -799,27 +832,27 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) break; default: compile_error(ctx, "invalid types used in expression: cannot subtract type %s from %s", - type_name[exprs[1]->expression.vtype], - type_name[exprs[0]->expression.vtype]); + type_name[exprs[1]->vtype], + type_name[exprs[0]->vtype]); return false; }; break; case opid1('*'): - if (exprs[0]->expression.vtype != exprs[1]->expression.vtype && - !(exprs[0]->expression.vtype == TYPE_VECTOR && - exprs[1]->expression.vtype == TYPE_FLOAT) && - !(exprs[1]->expression.vtype == TYPE_VECTOR && - exprs[0]->expression.vtype == TYPE_FLOAT) + if (exprs[0]->vtype != exprs[1]->vtype && + !(exprs[0]->vtype == TYPE_VECTOR && + exprs[1]->vtype == TYPE_FLOAT) && + !(exprs[1]->vtype == TYPE_VECTOR && + exprs[0]->vtype == TYPE_FLOAT) ) { compile_error(ctx, "invalid types used in expression: cannot multiply types %s and %s", - type_name[exprs[1]->expression.vtype], - type_name[exprs[0]->expression.vtype]); + type_name[exprs[1]->vtype], + type_name[exprs[0]->vtype]); return false; } - switch (exprs[0]->expression.vtype) { + switch (exprs[0]->vtype) { case TYPE_FLOAT: - if (exprs[1]->expression.vtype == TYPE_VECTOR) + if (exprs[1]->vtype == TYPE_VECTOR) { if (CanConstFold(exprs[0], exprs[1])) out = (ast_expression*)parser_const_vector(parser, vec3_mulvf(ConstV(1), ConstF(0))); @@ -835,7 +868,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) } break; case TYPE_VECTOR: - if (exprs[1]->expression.vtype == TYPE_FLOAT) + if (exprs[1]->vtype == TYPE_FLOAT) { if (CanConstFold(exprs[0], exprs[1])) out = (ast_expression*)parser_const_vector(parser, vec3_mulvf(ConstV(0), ConstF(1))); @@ -851,7 +884,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) if (!vec.y && !vec.z) { /* 'n 0 0' * v */ ++opts_optimizationcount[OPTIM_VECTOR_COMPONENTS]; out = (ast_expression*)ast_member_new(ctx, exprs[1], 0, NULL); - out->expression.node.keep = false; + out->node.keep = false; ((ast_member*)out)->rvalue = true; if (vec.x != 1) out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_F, (ast_expression*)parser_const_float(parser, vec.x), out); @@ -859,7 +892,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) else if (!vec.x && !vec.z) { /* '0 n 0' * v */ ++opts_optimizationcount[OPTIM_VECTOR_COMPONENTS]; out = (ast_expression*)ast_member_new(ctx, exprs[1], 1, NULL); - out->expression.node.keep = false; + out->node.keep = false; ((ast_member*)out)->rvalue = true; if (vec.y != 1) out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_F, (ast_expression*)parser_const_float(parser, vec.y), out); @@ -867,7 +900,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) else if (!vec.x && !vec.y) { /* '0 n 0' * v */ ++opts_optimizationcount[OPTIM_VECTOR_COMPONENTS]; out = (ast_expression*)ast_member_new(ctx, exprs[1], 2, NULL); - out->expression.node.keep = false; + out->node.keep = false; ((ast_member*)out)->rvalue = true; if (vec.z != 1) out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_F, (ast_expression*)parser_const_float(parser, vec.z), out); @@ -880,7 +913,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) if (!vec.y && !vec.z) { /* v * 'n 0 0' */ ++opts_optimizationcount[OPTIM_VECTOR_COMPONENTS]; out = (ast_expression*)ast_member_new(ctx, exprs[0], 0, NULL); - out->expression.node.keep = false; + out->node.keep = false; ((ast_member*)out)->rvalue = true; if (vec.x != 1) out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_F, out, (ast_expression*)parser_const_float(parser, vec.x)); @@ -888,7 +921,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) else if (!vec.x && !vec.z) { /* v * '0 n 0' */ ++opts_optimizationcount[OPTIM_VECTOR_COMPONENTS]; out = (ast_expression*)ast_member_new(ctx, exprs[0], 1, NULL); - out->expression.node.keep = false; + out->node.keep = false; ((ast_member*)out)->rvalue = true; if (vec.y != 1) out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_F, out, (ast_expression*)parser_const_float(parser, vec.y)); @@ -896,7 +929,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) else if (!vec.x && !vec.y) { /* v * '0 n 0' */ ++opts_optimizationcount[OPTIM_VECTOR_COMPONENTS]; out = (ast_expression*)ast_member_new(ctx, exprs[0], 2, NULL); - out->expression.node.keep = false; + out->node.keep = false; ((ast_member*)out)->rvalue = true; if (vec.z != 1) out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_F, out, (ast_expression*)parser_const_float(parser, vec.z)); @@ -910,25 +943,25 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) break; default: compile_error(ctx, "invalid types used in expression: cannot multiply types %s and %s", - type_name[exprs[1]->expression.vtype], - type_name[exprs[0]->expression.vtype]); + type_name[exprs[1]->vtype], + type_name[exprs[0]->vtype]); return false; }; break; case opid1('/'): - if (exprs[1]->expression.vtype != TYPE_FLOAT) { + 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); return false; } - if (exprs[0]->expression.vtype == TYPE_FLOAT) { + if (exprs[0]->vtype == TYPE_FLOAT) { if (CanConstFold(exprs[0], exprs[1])) out = (ast_expression*)parser_const_float(parser, ConstF(0) / ConstF(1)); else out = (ast_expression*)ast_binary_new(ctx, INSTR_DIV_F, exprs[0], exprs[1]); } - else if (exprs[0]->expression.vtype == TYPE_VECTOR) { + else if (exprs[0]->vtype == TYPE_VECTOR) { if (CanConstFold(exprs[0], exprs[1])) out = (ast_expression*)parser_const_vector(parser, vec3_mulvf(ConstV(0), 1.0/ConstF(1))); else { @@ -954,16 +987,41 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) return false; } break; + case opid1('%'): + if (NotSameType(TYPE_FLOAT)) { + compile_error(ctx, "invalid types used in expression: cannot perform modulo operation between types %s and %s", + type_name[exprs[0]->vtype], + type_name[exprs[1]->vtype]); + return false; + } + if (CanConstFold(exprs[0], exprs[1])) { + out = (ast_expression*)parser_const_float(parser, + (float)(((qcint)ConstF(0)) % ((qcint)ConstF(1)))); + } else { + /* generate a call to __builtin_mod */ + ast_expression *mod = intrin_func(parser, "mod"); + ast_call *call = NULL; + if (!mod) return false; /* can return null for missing floor */ + + call = ast_call_new(parser_ctx(parser), mod); + vec_push(call->params, exprs[0]); + vec_push(call->params, exprs[1]); + + out = (ast_expression*)call; + } + break; + case opid2('%','='): - compile_error(ctx, "qc does not have a modulo operator"); + compile_error(ctx, "%= is unimplemented"); return false; + case opid1('|'): case opid1('&'): if (NotSameType(TYPE_FLOAT)) { compile_error(ctx, "invalid types used in expression: cannot perform bit operations between types %s and %s", - type_name[exprs[0]->expression.vtype], - type_name[exprs[1]->expression.vtype]); + type_name[exprs[0]->vtype], + type_name[exprs[1]->vtype]); return false; } if (CanConstFold(exprs[0], exprs[1])) @@ -983,9 +1041,9 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) case opid2('>','>'): if (CanConstFold(exprs[0], exprs[1]) && ! NotSameType(TYPE_FLOAT)) { if (op->id == opid2('<','<')) - out = (ast_expression*)parser_const_float(parser, (double)((int)(ConstF(0)) << (int)(ConstF(1)))); + out = (ast_expression*)parser_const_float(parser, (double)((unsigned int)(ConstF(0)) << (unsigned int)(ConstF(1)))); else - out = (ast_expression*)parser_const_float(parser, (double)((int)(ConstF(0)) >> (int)(ConstF(1)))); + out = (ast_expression*)parser_const_float(parser, (double)((unsigned int)(ConstF(0)) >> (unsigned int)(ConstF(1)))); break; } case opid3('<','<','='): @@ -1019,7 +1077,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) return false; } for (i = 0; i < 2; ++i) { - if (OPTS_FLAG(CORRECT_LOGIC) && exprs[i]->expression.vtype == TYPE_VECTOR) { + if (OPTS_FLAG(CORRECT_LOGIC) && exprs[i]->vtype == TYPE_VECTOR) { out = (ast_expression*)ast_unary_new(ctx, INSTR_NOT_V, exprs[i]); if (!out) break; out = (ast_expression*)ast_unary_new(ctx, INSTR_NOT_F, out); @@ -1030,7 +1088,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) break; } } - else if (OPTS_FLAG(FALSE_EMPTY_STRINGS) && exprs[i]->expression.vtype == TYPE_STRING) { + else if (OPTS_FLAG(FALSE_EMPTY_STRINGS) && exprs[i]->vtype == TYPE_STRING) { out = (ast_expression*)ast_unary_new(ctx, INSTR_NOT_S, exprs[i]); if (!out) break; out = (ast_expression*)ast_unary_new(ctx, INSTR_NOT_F, out); @@ -1064,6 +1122,69 @@ 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 opid2('*', '*'): + 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 exponentiation: %s and %s", + ty1, ty2); + + return false; + } + + if (CanConstFold(exprs[0], exprs[1])) { + out = (ast_expression*)parser_const_float(parser, powf(ConstF(0), ConstF(1))); + } else { + ast_call *gencall = ast_call_new(parser_ctx(parser), intrin_func(parser, "pow")); + vec_push(gencall->params, exprs[0]); + vec_push(gencall->params, exprs[1]); + out = (ast_expression*)gencall; + } + 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 = (ast_binary_ref)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('<'): @@ -1074,49 +1195,49 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) generated_op += INSTR_LE; if (NotSameType(TYPE_FLOAT)) { compile_error(ctx, "invalid types used in expression: cannot perform comparison between types %s and %s", - type_name[exprs[0]->expression.vtype], - type_name[exprs[1]->expression.vtype]); + type_name[exprs[0]->vtype], + type_name[exprs[1]->vtype]); return false; } out = (ast_expression*)ast_binary_new(ctx, generated_op, exprs[0], exprs[1]); break; case opid2('!', '='): - if (exprs[0]->expression.vtype != exprs[1]->expression.vtype) { + if (exprs[0]->vtype != exprs[1]->vtype) { compile_error(ctx, "invalid types used in expression: cannot perform comparison between types %s and %s", - type_name[exprs[0]->expression.vtype], - type_name[exprs[1]->expression.vtype]); + type_name[exprs[0]->vtype], + type_name[exprs[1]->vtype]); return false; } - out = (ast_expression*)ast_binary_new(ctx, type_ne_instr[exprs[0]->expression.vtype], exprs[0], exprs[1]); + out = (ast_expression*)ast_binary_new(ctx, type_ne_instr[exprs[0]->vtype], exprs[0], exprs[1]); break; case opid2('=', '='): - if (exprs[0]->expression.vtype != exprs[1]->expression.vtype) { + if (exprs[0]->vtype != exprs[1]->vtype) { compile_error(ctx, "invalid types used in expression: cannot perform comparison between types %s and %s", - type_name[exprs[0]->expression.vtype], - type_name[exprs[1]->expression.vtype]); + type_name[exprs[0]->vtype], + type_name[exprs[1]->vtype]); return false; } - out = (ast_expression*)ast_binary_new(ctx, type_eq_instr[exprs[0]->expression.vtype], exprs[0], exprs[1]); + out = (ast_expression*)ast_binary_new(ctx, type_eq_instr[exprs[0]->vtype], exprs[0], exprs[1]); break; case opid1('='): if (ast_istype(exprs[0], ast_entfield)) { ast_expression *field = ((ast_entfield*)exprs[0])->field; if (OPTS_FLAG(ADJUST_VECTOR_FIELDS) && - exprs[0]->expression.vtype == TYPE_FIELD && - exprs[0]->expression.next->expression.vtype == TYPE_VECTOR) + exprs[0]->vtype == TYPE_FIELD && + exprs[0]->next->vtype == TYPE_VECTOR) { assignop = type_storep_instr[TYPE_VECTOR]; } else - assignop = type_storep_instr[exprs[0]->expression.vtype]; - if (assignop == VINSTR_END || !ast_compare_type(field->expression.next, exprs[1])) + assignop = type_storep_instr[exprs[0]->vtype]; + if (assignop == VINSTR_END || !ast_compare_type(field->next, exprs[1])) { - ast_type_to_string(field->expression.next, ty1, sizeof(ty1)); + ast_type_to_string(field->next, ty1, sizeof(ty1)); ast_type_to_string(exprs[1], ty2, sizeof(ty2)); if (OPTS_FLAG(ASSIGN_FUNCTION_TYPES) && - field->expression.next->expression.vtype == TYPE_FUNCTION && - exprs[1]->expression.vtype == TYPE_FUNCTION) + field->next->vtype == TYPE_FUNCTION && + exprs[1]->vtype == TYPE_FUNCTION) { (void)!compile_warning(ctx, WARN_ASSIGN_FUNCTION_TYPES, "invalid types in assignment: cannot assign %s to %s", ty2, ty1); @@ -1128,13 +1249,13 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) else { if (OPTS_FLAG(ADJUST_VECTOR_FIELDS) && - exprs[0]->expression.vtype == TYPE_FIELD && - exprs[0]->expression.next->expression.vtype == TYPE_VECTOR) + exprs[0]->vtype == TYPE_FIELD && + exprs[0]->next->vtype == TYPE_VECTOR) { assignop = type_store_instr[TYPE_VECTOR]; } else { - assignop = type_store_instr[exprs[0]->expression.vtype]; + assignop = type_store_instr[exprs[0]->vtype]; } if (assignop == VINSTR_END) { @@ -1147,8 +1268,8 @@ 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)); if (OPTS_FLAG(ASSIGN_FUNCTION_TYPES) && - exprs[0]->expression.vtype == TYPE_FUNCTION && - exprs[1]->expression.vtype == TYPE_FUNCTION) + exprs[0]->vtype == TYPE_FUNCTION && + exprs[1]->vtype == TYPE_FUNCTION) { (void)!compile_warning(ctx, WARN_ASSIGN_FUNCTION_TYPES, "invalid types in assignment: cannot assign %s to %s", ty2, ty1); @@ -1165,7 +1286,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) case opid3('+','+','P'): case opid3('-','-','P'): /* prefix ++ */ - if (exprs[0]->expression.vtype != TYPE_FLOAT) { + if (exprs[0]->vtype != TYPE_FLOAT) { ast_type_to_string(exprs[0], ty1, sizeof(ty1)); compile_error(ast_ctx(exprs[0]), "invalid type for prefix increment: %s", ty1); return false; @@ -1190,7 +1311,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) case opid3('S','+','+'): case opid3('S','-','-'): /* prefix ++ */ - if (exprs[0]->expression.vtype != TYPE_FLOAT) { + if (exprs[0]->vtype != TYPE_FLOAT) { ast_type_to_string(exprs[0], ty1, sizeof(ty1)); compile_error(ast_ctx(exprs[0]), "invalid type for suffix increment: %s", ty1); return false; @@ -1222,8 +1343,8 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) break; case opid2('+','='): case opid2('-','='): - if (exprs[0]->expression.vtype != exprs[1]->expression.vtype || - (exprs[0]->expression.vtype != TYPE_VECTOR && exprs[0]->expression.vtype != TYPE_FLOAT) ) + if (exprs[0]->vtype != exprs[1]->vtype || + (exprs[0]->vtype != TYPE_VECTOR && exprs[0]->vtype != TYPE_FLOAT) ) { ast_type_to_string(exprs[0], ty1, sizeof(ty1)); ast_type_to_string(exprs[1], ty2, sizeof(ty2)); @@ -1235,10 +1356,10 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) compile_error(ctx, "assignment to constant `%s`", asvalue[0]->name); } if (ast_istype(exprs[0], ast_entfield)) - assignop = type_storep_instr[exprs[0]->expression.vtype]; + assignop = type_storep_instr[exprs[0]->vtype]; else - assignop = type_store_instr[exprs[0]->expression.vtype]; - switch (exprs[0]->expression.vtype) { + assignop = type_store_instr[exprs[0]->vtype]; + switch (exprs[0]->vtype) { case TYPE_FLOAT: out = (ast_expression*)ast_binstore_new(ctx, assignop, (op->id == opid2('+','=') ? INSTR_ADD_F : INSTR_SUB_F), @@ -1251,16 +1372,16 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) break; default: compile_error(ctx, "invalid types used in expression: cannot add or subtract type %s and %s", - type_name[exprs[0]->expression.vtype], - type_name[exprs[1]->expression.vtype]); + type_name[exprs[0]->vtype], + type_name[exprs[1]->vtype]); return false; }; break; case opid2('*','='): case opid2('/','='): - if (exprs[1]->expression.vtype != TYPE_FLOAT || - !(exprs[0]->expression.vtype == TYPE_FLOAT || - exprs[0]->expression.vtype == TYPE_VECTOR)) + if (exprs[1]->vtype != TYPE_FLOAT || + !(exprs[0]->vtype == TYPE_FLOAT || + exprs[0]->vtype == TYPE_VECTOR)) { ast_type_to_string(exprs[0], ty1, sizeof(ty1)); ast_type_to_string(exprs[1], ty2, sizeof(ty2)); @@ -1272,10 +1393,10 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) compile_error(ctx, "assignment to constant `%s`", asvalue[0]->name); } if (ast_istype(exprs[0], ast_entfield)) - assignop = type_storep_instr[exprs[0]->expression.vtype]; + assignop = type_storep_instr[exprs[0]->vtype]; else - assignop = type_store_instr[exprs[0]->expression.vtype]; - switch (exprs[0]->expression.vtype) { + assignop = type_store_instr[exprs[0]->vtype]; + switch (exprs[0]->vtype) { case TYPE_FLOAT: out = (ast_expression*)ast_binstore_new(ctx, assignop, (op->id == opid2('*','=') ? INSTR_MUL_F : INSTR_DIV_F), @@ -1304,8 +1425,8 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) break; default: compile_error(ctx, "invalid types used in expression: cannot add or subtract type %s and %s", - type_name[exprs[0]->expression.vtype], - type_name[exprs[1]->expression.vtype]); + type_name[exprs[0]->vtype], + type_name[exprs[1]->vtype]); return false; }; break; @@ -1322,9 +1443,9 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) compile_error(ctx, "assignment to constant `%s`", asvalue[0]->name); } if (ast_istype(exprs[0], ast_entfield)) - assignop = type_storep_instr[exprs[0]->expression.vtype]; + assignop = type_storep_instr[exprs[0]->vtype]; else - assignop = type_store_instr[exprs[0]->expression.vtype]; + assignop = type_store_instr[exprs[0]->vtype]; out = (ast_expression*)ast_binstore_new(ctx, assignop, (op->id == opid2('&','=') ? INSTR_BITAND : INSTR_BITOR), exprs[0], exprs[1]); @@ -1342,9 +1463,9 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) return false; } if (ast_istype(exprs[0], ast_entfield)) - assignop = type_storep_instr[exprs[0]->expression.vtype]; + assignop = type_storep_instr[exprs[0]->vtype]; else - assignop = type_store_instr[exprs[0]->expression.vtype]; + assignop = type_store_instr[exprs[0]->vtype]; out = (ast_expression*)ast_binary_new(ctx, INSTR_BITAND, exprs[0], exprs[1]); if (!out) return false; @@ -1357,7 +1478,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) break; case opid2('~', 'P'): - if (exprs[0]->expression.vtype != TYPE_FLOAT) { + if (exprs[0]->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; @@ -1366,9 +1487,9 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) 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]); + out = (ast_expression*) + ast_binary_new(ctx, INSTR_SUB_F, (ast_expression*)parser_const_float_neg1(parser), exprs[0]); break; - } #undef NotSameType @@ -1453,7 +1574,7 @@ static bool parser_close_call(parser_t *parser, shunt *sy) if (ast_istype(fun, ast_value)) { funval = (ast_value*)fun; - if ((fun->expression.flags & AST_FLAG_VARIADIC) && + if ((fun->flags & AST_FLAG_VARIADIC) && !(/*funval->cvq == CV_CONST && */ funval->hasvalue && funval->constval.vfunc->builtin)) { call->va_count = (ast_expression*)parser_const_float(parser, (double)paramcount); @@ -1463,18 +1584,18 @@ static bool parser_close_call(parser_t *parser, shunt *sy) /* overwrite fid, the function, with a call */ sy->out[fid] = syexp(call->expression.node.context, (ast_expression*)call); - if (fun->expression.vtype != TYPE_FUNCTION) { - parseerror(parser, "not a function (%s)", type_name[fun->expression.vtype]); + if (fun->vtype != TYPE_FUNCTION) { + parseerror(parser, "not a function (%s)", type_name[fun->vtype]); return false; } - if (!fun->expression.next) { + if (!fun->next) { parseerror(parser, "could not determine function return type"); return false; } else { ast_value *fval = (ast_istype(fun, ast_value) ? ((ast_value*)fun) : NULL); - if (fun->expression.flags & AST_FLAG_DEPRECATED) { + if (fun->flags & AST_FLAG_DEPRECATED) { if (!fval) { return !parsewarning(parser, WARN_DEPRECATED, "call to function (which is marked deprecated)\n", @@ -1494,22 +1615,22 @@ static bool parser_close_call(parser_t *parser, shunt *sy) ast_ctx(fun).line); } - if (vec_size(fun->expression.params) != paramcount && - !((fun->expression.flags & AST_FLAG_VARIADIC) && - vec_size(fun->expression.params) < paramcount)) + if (vec_size(fun->params) != paramcount && + !((fun->flags & AST_FLAG_VARIADIC) && + vec_size(fun->params) < paramcount)) { - const char *fewmany = (vec_size(fun->expression.params) > paramcount) ? "few" : "many"; + const char *fewmany = (vec_size(fun->params) > paramcount) ? "few" : "many"; if (fval) return !parsewarning(parser, WARN_INVALID_PARAMETER_COUNT, "too %s parameters for call to %s: expected %i, got %i\n" " -> `%s` has been declared here: %s:%i", - fewmany, fval->name, (int)vec_size(fun->expression.params), (int)paramcount, + fewmany, fval->name, (int)vec_size(fun->params), (int)paramcount, fval->name, ast_ctx(fun).file, (int)ast_ctx(fun).line); else return !parsewarning(parser, WARN_INVALID_PARAMETER_COUNT, "too %s parameters for function call: expected %i, got %i\n" " -> it has been declared here: %s:%i", - fewmany, (int)vec_size(fun->expression.params), (int)paramcount, + fewmany, (int)vec_size(fun->params), (int)paramcount, ast_ctx(fun).file, (int)ast_ctx(fun).line); } } @@ -1569,6 +1690,8 @@ static bool parser_close_paren(parser_t *parser, shunt *sy) static void parser_reclassify_token(parser_t *parser) { size_t i; + if (parser->tok >= TOKEN_START) + return; for (i = 0; i < operator_count; ++i) { if (!strcmp(parser_tokval(parser), operators[i].op)) { parser->tok = TOKEN_OPERATOR; @@ -1670,6 +1793,9 @@ static ast_expression* parse_vararg(parser_t *parser) return out; } +/* not to be exposed */ +extern bool ftepp_predef_exists(const char *name); + static bool parse_sya_operand(parser_t *parser, shunt *sy, bool with_labels) { if (OPTS_FLAG(TRANSLATABLE_STRINGS) && @@ -1760,7 +1886,7 @@ static bool parse_sya_operand(parser_t *parser, shunt *sy, bool with_labels) /* When adding more intrinsics, fix the above condition */ prev = NULL; } - if (prev && prev->expression.vtype == TYPE_VECTOR && ctoken[0] >= 'x' && ctoken[0] <= 'z' && !ctoken[1]) + if (prev && prev->vtype == TYPE_VECTOR && ctoken[0] >= 'x' && ctoken[0] <= 'z' && !ctoken[1]) { var = (ast_expression*)parser->const_vec[ctoken[0]-'x']; } else { @@ -1776,13 +1902,22 @@ static bool parse_sya_operand(parser_t *parser, shunt *sy, bool with_labels) vec_push(parser->labels, lbl); } } + if (!var && !strcmp(parser_tokval(parser), "__FUNC__")) + var = (ast_expression*)parser_const_string(parser, parser->function->name, false); if (!var) { /* intrinsics */ if (!strcmp(parser_tokval(parser), "__builtin_debug_typestring")) { var = (ast_expression*)intrinsic_debug_typestring; } - else - { + /* now we try for the real intrinsic hashtable. If the string + * begins with __builtin, we simply skip past it, otherwise we + * use the identifier as is. + */ + else if (!strncmp(parser_tokval(parser), "__builtin_", 10)) { + var = intrin_func(parser, parser_tokval(parser) + 10 /* skip __builtin */); + } + + if (!var) { char *correct = NULL; size_t i; @@ -1791,13 +1926,9 @@ static bool parse_sya_operand(parser_t *parser, shunt *sy, bool with_labels) * i've done this thousands of times already myself. Lets check for * it in the predef table. And diagnose it better :) */ - if (!OPTS_FLAG(FTEPP_PREDEFS)) { - for (i = 0; i < sizeof(ftepp_predefs)/sizeof(*ftepp_predefs); i++) { - if (!strcmp(ftepp_predefs[i].name, parser_tokval(parser))) { - parseerror(parser, "unexpected ident: %s (use -fftepp-predef to enable pre-defined macros)", parser_tokval(parser)); - return false; - } - } + if (!OPTS_FLAG(FTEPP_PREDEFS) && ftepp_predef_exists(parser_tokval(parser))) { + parseerror(parser, "unexpected ident: %s (use -fftepp-predef to enable pre-defined macros)", parser_tokval(parser)); + return false; } /* @@ -1807,7 +1938,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_OPTION_BOOL(OPTION_CORRECTION)) { + if (OPTS_OPTION_BOOL(OPTION_CORRECTION) && strlen(parser_tokval(parser)) <= 16) { correction_t corr; correct_init(&corr); @@ -1894,8 +2025,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]; @@ -2061,8 +2192,27 @@ static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma wantop = true; } else { - parseerror(parser, "expected operator or end of statement"); - goto onerr; + /* in this case we might want to allow constant string concatenation */ + bool concatenated = false; + if (parser->tok == TOKEN_STRINGCONST && vec_size(sy.out)) { + ast_expression *lexpr = vec_last(sy.out).out; + if (ast_istype(lexpr, ast_value)) { + ast_value *last = (ast_value*)lexpr; + if (last->isimm == true && last->cvq == CV_CONST && + last->hasvalue && last->expression.vtype == TYPE_STRING) + { + char *newstr = NULL; + util_asprintf(&newstr, "%s%s", last->constval.vstring, parser_tokval(parser)); + vec_last(sy.out).out = (ast_expression*)parser_const_string(parser, newstr, false); + mem_d(newstr); + concatenated = true; + } + } + } + if (!concatenated) { + parseerror(parser, "expected operator or end of statement"); + goto onerr; + } } if (!parser_next(parser)) { @@ -2082,8 +2232,8 @@ static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma } parser->lex->flags.noops = true; - if (!vec_size(sy.out)) { - parseerror(parser, "empty expression"); + if (vec_size(sy.out) != 1) { + parseerror(parser, "expression with not 1 but %lu output values...", (unsigned long) vec_size(sy.out)); expr = NULL; } else expr = sy.out[0].out; @@ -2218,13 +2368,13 @@ static ast_expression* process_condition(parser_t *parser, ast_expression *cond, ast_unary *unary; ast_expression *prev; - if (cond->expression.vtype == TYPE_VOID || cond->expression.vtype >= TYPE_VARIANT) { + if (cond->vtype == TYPE_VOID || cond->vtype >= TYPE_VARIANT) { char ty[1024]; ast_type_to_string(cond, ty, sizeof(ty)); compile_error(ast_ctx(cond), "invalid type for if() condition: %s", ty); } - if (OPTS_FLAG(FALSE_EMPTY_STRINGS) && cond->expression.vtype == TYPE_STRING) + if (OPTS_FLAG(FALSE_EMPTY_STRINGS) && cond->vtype == TYPE_STRING) { prev = cond; cond = (ast_expression*)ast_unary_new(ast_ctx(cond), INSTR_NOT_S, cond); @@ -2235,7 +2385,7 @@ static ast_expression* process_condition(parser_t *parser, ast_expression *cond, } ifnot = !ifnot; } - else if (OPTS_FLAG(CORRECT_LOGIC) && cond->expression.vtype == TYPE_VECTOR) + else if (OPTS_FLAG(CORRECT_LOGIC) && cond->vtype == TYPE_VECTOR) { /* vector types need to be cast to true booleans */ ast_binary *bin = (ast_binary*)cond; @@ -2308,17 +2458,17 @@ static bool parse_if(parser_t *parser, ast_block *block, ast_expression **out) /* closing paren */ if (parser->tok != ')') { parseerror(parser, "expected closing paren after 'if' condition"); - ast_delete(cond); + ast_unref(cond); return false; } /* parse into the 'then' branch */ if (!parser_next(parser)) { parseerror(parser, "expected statement for on-true branch of 'if'"); - ast_delete(cond); + ast_unref(cond); return false; } if (!parse_statement_or_block(parser, &ontrue)) { - ast_delete(cond); + ast_unref(cond); return false; } if (!ontrue) @@ -2329,12 +2479,12 @@ static bool parse_if(parser_t *parser, ast_block *block, ast_expression **out) if (!parser_next(parser)) { parseerror(parser, "expected on-false branch after 'else'"); ast_delete(ontrue); - ast_delete(cond); + ast_unref(cond); return false; } if (!parse_statement_or_block(parser, &onfalse)) { ast_delete(ontrue); - ast_delete(cond); + ast_unref(cond); return false; } } @@ -2431,23 +2581,23 @@ static bool parse_while_go(parser_t *parser, ast_block *block, ast_expression ** /* closing paren */ if (parser->tok != ')') { parseerror(parser, "expected closing paren after 'while' condition"); - ast_delete(cond); + ast_unref(cond); return false; } /* parse into the 'then' branch */ if (!parser_next(parser)) { parseerror(parser, "expected while-loop body"); - ast_delete(cond); + ast_unref(cond); return false; } if (!parse_statement_or_block(parser, &ontrue)) { - ast_delete(cond); + ast_unref(cond); return false; } cond = process_condition(parser, cond, &ifnot); if (!cond) { - ast_delete(ontrue); + ast_unref(ontrue); return false; } aloop = ast_loop_new(ctx, NULL, cond, ifnot, NULL, false, NULL, ontrue); @@ -2547,21 +2697,21 @@ static bool parse_dowhile_go(parser_t *parser, ast_block *block, ast_expression if (parser->tok != ')') { parseerror(parser, "expected closing paren after 'while' condition"); ast_delete(ontrue); - ast_delete(cond); + ast_unref(cond); return false; } /* parse on */ if (!parser_next(parser) || parser->tok != ';') { parseerror(parser, "expected semicolon after condition"); ast_delete(ontrue); - ast_delete(cond); + ast_unref(cond); return false; } if (!parser_next(parser)) { parseerror(parser, "parse error"); ast_delete(ontrue); - ast_delete(cond); + ast_unref(cond); return false; } @@ -2634,7 +2784,6 @@ static bool parse_for_go(parser_t *parser, ast_block *block, ast_expression **ou ast_expression *initexpr, *cond, *increment, *ontrue; ast_value *typevar; - bool retval = true; bool ifnot = false; lex_ctx ctx = parser_ctx(parser); @@ -2734,21 +2883,25 @@ static bool parse_for_go(parser_t *parser, ast_block *block, ast_expression **ou aloop = ast_loop_new(ctx, initexpr, cond, ifnot, NULL, false, increment, ontrue); *out = (ast_expression*)aloop; - if (!parser_leaveblock(parser)) - retval = false; - return retval; + if (!parser_leaveblock(parser)) { + ast_delete(aloop); + return false; + } + return true; onerr: - if (initexpr) ast_delete(initexpr); - if (cond) ast_delete(cond); - if (increment) ast_delete(increment); + if (initexpr) ast_unref(initexpr); + if (cond) ast_unref(cond); + if (increment) ast_unref(increment); (void)!parser_leaveblock(parser); return false; } static bool parse_return(parser_t *parser, ast_block *block, ast_expression **out) { - ast_expression *exp = NULL; - ast_return *ret = NULL; + ast_expression *exp = NULL; + ast_expression *var = NULL; + ast_return *ret = NULL; + ast_value *retval = parser->function->return_value; ast_value *expected = parser->function->vtype; lex_ctx ctx = parser_ctx(parser); @@ -2760,29 +2913,87 @@ static bool parse_return(parser_t *parser, ast_block *block, ast_expression **ou return false; } + /* return assignments */ + if (parser->tok == '=') { + if (!OPTS_FLAG(RETURN_ASSIGNMENTS)) { + parseerror(parser, "return assignments not activated, try using -freturn-assigments"); + return false; + } + + if (type_store_instr[expected->expression.next->vtype] == VINSTR_END) { + char ty1[1024]; + ast_type_to_string(expected->expression.next, ty1, sizeof(ty1)); + parseerror(parser, "invalid return type: `%s'", ty1); + return false; + } + + if (!parser_next(parser)) { + parseerror(parser, "expected return assignment expression"); + return false; + } + + if (!(exp = parse_expression_leave(parser, false, false, false))) + return false; + + /* prepare the return value */ + if (!retval) { + retval = ast_value_new(ctx, "#LOCAL_RETURN", TYPE_VOID); + ast_type_adopt(retval, expected->expression.next); + parser->function->return_value = retval; + } + + if (!ast_compare_type(exp, (ast_expression*)retval)) { + char ty1[1024], ty2[1024]; + ast_type_to_string(exp, ty1, sizeof(ty1)); + ast_type_to_string(&retval->expression, ty2, sizeof(ty2)); + parseerror(parser, "invalid type for return value: `%s', expected `%s'", ty1, ty2); + } + + /* store to 'return' local variable */ + var = (ast_expression*)ast_store_new( + ctx, + type_store_instr[expected->expression.next->vtype], + (ast_expression*)retval, exp); + + if (!var) { + ast_unref(exp); + return false; + } + + if (parser->tok != ';') + parseerror(parser, "missing semicolon after return assignment"); + else if (!parser_next(parser)) + parseerror(parser, "parse error after return assignment"); + + *out = var; + return true; + } + if (parser->tok != ';') { exp = parse_expression(parser, false, false); if (!exp) return false; - if (exp->expression.vtype != TYPE_NIL && - exp->expression.vtype != expected->expression.next->expression.vtype) + if (exp->vtype != TYPE_NIL && + exp->vtype != ((ast_expression*)expected)->next->vtype) { parseerror(parser, "return with invalid expression"); } ret = ast_return_new(ctx, exp); if (!ret) { - ast_delete(exp); + ast_unref(exp); return false; } } else { if (!parser_next(parser)) parseerror(parser, "parse error"); - if (expected->expression.next->expression.vtype != TYPE_VOID) { + + if (!retval && expected->expression.next->vtype != TYPE_VOID) + { (void)!parsewarning(parser, WARN_MISSING_RETURN_VALUES, "return without value"); } - ret = ast_return_new(ctx, NULL); + ret = ast_return_new(ctx, (ast_expression*)retval); } *out = (ast_expression*)ret; return true; @@ -2887,8 +3098,44 @@ static bool parse_qualifiers(parser_t *parser, bool with_local, int *cvq, bool * return false; } } + else if (!strcmp(parser_tokval(parser), "alias") && !(flags & AST_FLAG_ALIAS)) { + flags |= AST_FLAG_ALIAS; + *message = NULL; + if (!parser_next(parser)) { + parseerror(parser, "parse error in attribute"); + goto argerr; + } + if (parser->tok == '(') { + if (!parser_next(parser) || parser->tok != TOKEN_STRINGCONST) { + parseerror(parser, "`alias` attribute missing parameter"); + goto argerr; + } + + *message = util_strdup(parser_tokval(parser)); + + if (!parser_next(parser)) { + parseerror(parser, "parse error in attribute"); + goto argerr; + } + + if (parser->tok != ')') { + parseerror(parser, "`alias` attribute expected `)` after parameter"); + goto argerr; + } + + if (!parser_next(parser)) { + parseerror(parser, "parse error in attribute"); + goto argerr; + } + } + + if (parser->tok != TOKEN_ATTRIBUTE_CLOSE) { + parseerror(parser, "`alias` attribute expected `]]`"); + goto argerr; + } + } else if (!strcmp(parser_tokval(parser), "deprecated") && !(flags & AST_FLAG_DEPRECATED)) { flags |= AST_FLAG_DEPRECATED; *message = NULL; @@ -3494,7 +3741,7 @@ static bool parse_statement(parser_t *parser, ast_block *block, ast_expression * } return parse_typedef(parser); } - parseerror(parser, "Unexpected keyword"); + parseerror(parser, "Unexpected keyword: `%s'", parser_tokval(parser)); return false; } else if (parser->tok == '{') @@ -3569,6 +3816,8 @@ static bool parse_statement(parser_t *parser, ast_block *block, ast_expression * static bool parse_enum(parser_t *parser) { + bool flag = false; + bool reverse = false; qcfloat num = 0; ast_value **values = NULL; ast_value *var = NULL; @@ -3576,11 +3825,37 @@ static bool parse_enum(parser_t *parser) ast_expression *old; - if (!parser_next(parser) || parser->tok != '{') { - parseerror(parser, "expected `{` after `enum` keyword"); + if (!parser_next(parser) || (parser->tok != '{' && parser->tok != ':')) { + parseerror(parser, "expected `{` or `:` after `enum` keyword"); return false; } + /* enumeration attributes (can add more later) */ + if (parser->tok == ':') { + if (!parser_next(parser) || parser->tok != TOKEN_IDENT){ + parseerror(parser, "expected `flag` or `reverse` for enumeration attribute"); + return false; + } + + /* attributes? */ + if (!strcmp(parser_tokval(parser), "flag")) { + num = 1; + flag = true; + } + else if (!strcmp(parser_tokval(parser), "reverse")) { + reverse = true; + } + else { + parseerror(parser, "invalid attribute `%s` for enumeration", parser_tokval(parser)); + return false; + } + + if (!parser_next(parser) || parser->tok != '{') { + parseerror(parser, "expected `{` after enum attribute "); + return false; + } + } + while (true) { if (!parser_next(parser) || parser->tok != TOKEN_IDENT) { if (parser->tok == '}') { @@ -3604,8 +3879,9 @@ static bool parse_enum(parser_t *parser) vec_push(values, var); var->cvq = CV_CONST; var->hasvalue = true; - var->constval.vfloat = num++; + /* for flagged enumerations increment in POTs of TWO */ + var->constval.vfloat = (flag) ? (num *= 2) : (num ++); parser_addglobal(parser, var->name, (ast_expression*)var); if (!parser_next(parser)) { @@ -3644,6 +3920,13 @@ static bool parse_enum(parser_t *parser) } } + /* patch them all (for reversed attribute) */ + if (reverse) { + size_t i; + for (i = 0; i < vec_size(values); i++) + values[i]->constval.vfloat = vec_size(values) - i - 1; + } + if (parser->tok != '}') { parseerror(parser, "internal error: breaking without `}`"); goto onerror; @@ -3775,6 +4058,11 @@ static bool parse_function_body(parser_t *parser, ast_value *var) has_frame_think = false; old = parser->function; + if (var->expression.flags & AST_FLAG_ALIAS) { + parseerror(parser, "function aliases cannot have bodies"); + return false; + } + if (vec_size(parser->gotos) || vec_size(parser->labels)) { parseerror(parser, "gotos/labels leaking"); return false; @@ -3844,14 +4132,15 @@ static bool parse_function_body(parser_t *parser, ast_value *var) /* qc allows the use of not-yet-declared functions here * - this automatically creates a prototype */ ast_value *thinkfunc; - ast_expression *functype = fld_think->expression.next; + ast_expression *functype = fld_think->next; - thinkfunc = ast_value_new(parser_ctx(parser), parser_tokval(parser), functype->expression.vtype); - if (!thinkfunc || !ast_type_adopt(thinkfunc, functype)) { + thinkfunc = ast_value_new(parser_ctx(parser), parser_tokval(parser), functype->vtype); + 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); @@ -3977,6 +4266,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); @@ -3994,7 +4289,7 @@ static bool parse_function_body(parser_t *parser, ast_value *var) if (param->expression.vtype != TYPE_VECTOR && (param->expression.vtype != TYPE_FIELD || - param->expression.next->expression.vtype != TYPE_VECTOR)) + param->expression.next->vtype != TYPE_VECTOR)) { continue; } @@ -4022,13 +4317,13 @@ static bool parse_function_body(parser_t *parser, ast_value *var) varargs->expression.flags |= AST_FLAG_IS_VARARG; varargs->expression.next = (ast_expression*)ast_value_new(ast_ctx(var), NULL, TYPE_VECTOR); varargs->expression.count = 0; - snprintf(name, sizeof(name), "%s##va##SET", var->name); + util_snprintf(name, sizeof(name), "%s##va##SET", var->name); if (!parser_create_array_setter_proto(parser, varargs, name)) { ast_delete(varargs); ast_block_delete(block); goto enderrfn; } - snprintf(name, sizeof(name), "%s##va##GET", var->name); + util_snprintf(name, sizeof(name), "%s##va##GET", var->name); if (!parser_create_array_getter_proto(parser, varargs, varargs->expression.next, name)) { ast_delete(varargs); ast_block_delete(block); @@ -4046,6 +4341,7 @@ static bool parse_function_body(parser_t *parser, ast_value *var) } vec_push(func->blocks, block); + parser->function = old; if (!parser_leaveblock(parser)) @@ -4124,7 +4420,7 @@ static ast_expression *array_setter_node(parser_t *parser, ast_value *array, ast ast_store *st; int assignop = type_store_instr[value->expression.vtype]; - if (value->expression.vtype == TYPE_FIELD && value->expression.next->expression.vtype == TYPE_VECTOR) + 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*)parser_const_float(parser, from)); @@ -4190,7 +4486,7 @@ static ast_expression *array_field_setter_node( ast_store *st; int assignop = type_storep_instr[value->expression.vtype]; - if (value->expression.vtype == TYPE_FIELD && value->expression.next->expression.vtype == TYPE_VECTOR) + 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*)parser_const_float(parser, from)); @@ -4500,6 +4796,7 @@ static ast_value *parse_parameter_list(parser_t *parser, ast_value *var) /* for the sake of less code we parse-in in this function */ if (!parser_next(parser)) { + ast_delete(var); parseerror(parser, "expected parameter list"); return NULL; } @@ -4599,6 +4896,8 @@ static ast_value *parse_parameter_list(parser_t *parser, ast_value *var) on_error: if (argcounter) mem_d(argcounter); + if (varparam) + ast_delete(varparam); ast_delete(var); for (i = 0; i < vec_size(params); ++i) ast_delete(params[i]); @@ -4765,6 +5064,7 @@ static ast_value *parse_typename(parser_t *parser, ast_value **storebase, ast_va /* parse on */ if (!parser_next(parser)) { ast_delete(var); + mem_d(name); parseerror(parser, "error after variable or field declaration"); return NULL; } @@ -4774,8 +5074,10 @@ static ast_value *parse_typename(parser_t *parser, ast_value **storebase, ast_va if (parser->tok == '[') { wasarray = true; var = parse_arraysize(parser, var); - if (!var) + if (!var) { + if (name) mem_d(name); return NULL; + } } /* This is the point where we can turn it into a field */ @@ -4794,8 +5096,7 @@ static ast_value *parse_typename(parser_t *parser, ast_value **storebase, ast_va while (parser->tok == '(') { var = parse_parameter_list(parser, var); if (!var) { - if (name) - mem_d((void*)name); + if (name) mem_d(name); return NULL; } } @@ -4804,11 +5105,12 @@ static ast_value *parse_typename(parser_t *parser, ast_value **storebase, ast_va if (name) { if (!ast_value_set_name(var, name)) { ast_delete(var); + mem_d(name); parseerror(parser, "internal error: failed to set name"); return NULL; } /* free the name, ast_value_set_name duplicates */ - mem_d((void*)name); + mem_d(name); } return var; @@ -4907,7 +5209,7 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield bool cleanvar = true; bool wasarray = false; - ast_member *me[3]; + ast_member *me[3] = { NULL, NULL, NULL }; if (!localblock && is_static) parseerror(parser, "`static` qualifier is not supported in global scope"); @@ -4960,7 +5262,13 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield var->cvq = qualifier; var->expression.flags |= qflags; - if (var->expression.flags & AST_FLAG_DEPRECATED) + + /* + * store the vstring back to var for alias and + * deprecation messages. + */ + if (var->expression.flags & AST_FLAG_DEPRECATED || + var->expression.flags & AST_FLAG_ALIAS) var->desc = vstring; /* Part 1: @@ -5033,7 +5341,7 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield { /* deal with other globals */ old = parser_find_global(parser, var->name); - if (old && var->expression.vtype == TYPE_FUNCTION && old->expression.vtype == TYPE_FUNCTION) + if (old && var->expression.vtype == TYPE_FUNCTION && old->vtype == TYPE_FUNCTION) { /* This is a function which had a prototype */ if (!ast_istype(old, ast_value)) { @@ -5055,7 +5363,7 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield ast_value_set_name(proto->expression.params[i], var->expression.params[i]->name); if (!parser_check_qualifiers(parser, var, proto)) { retval = false; - if (proto->desc) + if (proto->desc) mem_d(proto->desc); proto = NULL; goto cleanup; @@ -5141,7 +5449,7 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield if (var->expression.vtype == TYPE_VECTOR) isvector = true; else if (var->expression.vtype == TYPE_FIELD && - var->expression.next->expression.vtype == TYPE_VECTOR) + var->expression.next->vtype == TYPE_VECTOR) isvector = true; if (isvector) { @@ -5165,10 +5473,85 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield } } else { - parser_addglobal(parser, var->name, (ast_expression*)var); - if (isvector) { - for (i = 0; i < 3; ++i) { - parser_addglobal(parser, me[i]->name, (ast_expression*)me[i]); + if (!(var->expression.flags & AST_FLAG_ALIAS)) { + parser_addglobal(parser, var->name, (ast_expression*)var); + if (isvector) { + for (i = 0; i < 3; ++i) { + parser_addglobal(parser, me[i]->name, (ast_expression*)me[i]); + } + } + } else { + ast_expression *find = parser_find_global(parser, var->desc); + + if (!find) { + compile_error(parser_ctx(parser), "undeclared variable `%s` for alias `%s`", var->desc, var->name); + return false; + } + + if (var->expression.vtype != find->vtype) { + char ty1[1024]; + char ty2[1024]; + + ast_type_to_string(find, ty1, sizeof(ty1)); + ast_type_to_string((ast_expression*)var, ty2, sizeof(ty2)); + + compile_error(parser_ctx(parser), "incompatible types `%s` and `%s` for alias `%s`", + ty1, ty2, var->name + ); + return false; + } + + /* + * add alias to aliases table and to corrector + * so corrections can apply for aliases as well. + */ + util_htset(parser->aliases, var->name, find); + + /* + * add to corrector so corrections can work + * even for aliases too. + */ + correct_add ( + vec_last(parser->correct_variables), + &vec_last(parser->correct_variables_score), + var->name + ); + + /* generate aliases for vector components */ + if (isvector) { + char *buffer[3]; + + util_asprintf(&buffer[0], "%s_x", var->desc); + util_asprintf(&buffer[1], "%s_y", var->desc); + util_asprintf(&buffer[2], "%s_z", var->desc); + + util_htset(parser->aliases, me[0]->name, parser_find_global(parser, buffer[0])); + util_htset(parser->aliases, me[1]->name, parser_find_global(parser, buffer[1])); + util_htset(parser->aliases, me[2]->name, parser_find_global(parser, buffer[2])); + + mem_d(buffer[0]); + mem_d(buffer[1]); + mem_d(buffer[2]); + + /* + * add to corrector so corrections can work + * even for aliases too. + */ + correct_add ( + vec_last(parser->correct_variables), + &vec_last(parser->correct_variables_score), + me[0]->name + ); + correct_add ( + vec_last(parser->correct_variables), + &vec_last(parser->correct_variables_score), + me[1]->name + ); + correct_add ( + vec_last(parser->correct_variables), + &vec_last(parser->correct_variables_score), + me[2]->name + ); } } } @@ -5245,16 +5628,16 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield */ if (var->expression.vtype == TYPE_ARRAY) { char name[1024]; - snprintf(name, sizeof(name), "%s##SET", var->name); + util_snprintf(name, sizeof(name), "%s##SET", var->name); if (!parser_create_array_setter(parser, var, name)) goto cleanup; - snprintf(name, sizeof(name), "%s##GET", var->name); + util_snprintf(name, sizeof(name), "%s##GET", var->name); if (!parser_create_array_getter(parser, var, var->expression.next, name)) goto cleanup; } else if (!localblock && !nofields && var->expression.vtype == TYPE_FIELD && - var->expression.next->expression.vtype == TYPE_ARRAY) + var->expression.next->vtype == TYPE_ARRAY) { char name[1024]; ast_expression *telem; @@ -5266,14 +5649,14 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield goto cleanup; } - snprintf(name, sizeof(name), "%s##SETF", var->name); + util_snprintf(name, sizeof(name), "%s##SETF", var->name); if (!parser_create_array_field_setter(parser, array, name)) goto cleanup; telem = ast_type_copy(ast_ctx(var), array->expression.next); tfield = ast_value_new(ast_ctx(var), "<.type>", TYPE_FIELD); tfield->expression.next = telem; - snprintf(name, sizeof(name), "%s##GETFP", var->name); + util_snprintf(name, sizeof(name), "%s##GETFP", var->name); if (!parser_create_array_getter(parser, array, (ast_expression*)tfield, name)) { ast_delete(tfield); goto cleanup; @@ -5311,7 +5694,7 @@ skipvar: } } - if (parser->tok != '{') { + if (parser->tok != '{' || var->expression.vtype != TYPE_FUNCTION) { if (parser->tok != '=') { parseerror(parser, "missing semicolon or initializer, got: `%s`", parser_tokval(parser)); break; @@ -5327,7 +5710,11 @@ skipvar: } if (parser->tok == '#') { - ast_function *func = NULL; + ast_function *func = NULL; + ast_value *number = NULL; + float fractional; + float integral; + int builtin_num; if (localblock) { parseerror(parser, "cannot declare builtins within functions"); @@ -5341,12 +5728,42 @@ skipvar: parseerror(parser, "expected builtin number"); break; } - if (parser->tok != TOKEN_INTCONST) { - parseerror(parser, "builtin number must be an integer constant"); - break; - } - if (parser_token(parser)->constval.i < 0) { - parseerror(parser, "builtin number must be an integer greater than zero"); + + if (OPTS_FLAG(EXPRESSIONS_FOR_BUILTINS)) { + number = (ast_value*)parse_expression_leave(parser, true, false, false); + if (!number) { + parseerror(parser, "builtin number expected"); + break; + } + if (!ast_istype(number, ast_value) || !number->hasvalue || number->cvq != CV_CONST) + { + ast_unref(number); + parseerror(parser, "builtin number must be a compile time constant"); + break; + } + if (number->expression.vtype == TYPE_INTEGER) + builtin_num = number->constval.vint; + else if (number->expression.vtype == TYPE_FLOAT) + builtin_num = number->constval.vfloat; + else { + ast_unref(number); + parseerror(parser, "builtin number must be an integer constant"); + break; + } + ast_unref(number); + + fractional = modff(builtin_num, &integral); + if (builtin_num < 0 || fractional != 0) { + parseerror(parser, "builtin number must be an integer greater than zero"); + break; + } + + /* we only want the integral part anyways */ + builtin_num = integral; + } else if (parser->tok == TOKEN_INTCONST) { + builtin_num = parser_token(parser)->constval.i; + } else { + parseerror(parser, "builtin number must be a compile time constant"); break; } @@ -5365,10 +5782,13 @@ skipvar: } vec_push(parser->functions, func); - func->builtin = -parser_token(parser)->constval.i-1; + func->builtin = -builtin_num-1; } - if (!parser_next(parser)) { + if (OPTS_FLAG(EXPRESSIONS_FOR_BUILTINS) + ? (parser->tok != ',' && parser->tok != ';') + : (!parser_next(parser))) + { parseerror(parser, "expected comma or semicolon"); if (func) ast_function_delete(func); @@ -5376,7 +5796,22 @@ skipvar: break; } } - else if (parser->tok == '{' || parser->tok == '[') + else if (var->expression.vtype == TYPE_ARRAY && parser->tok == '{') + { + if (localblock) { + /* Note that fteqcc and most others don't even *have* + * local arrays, so this is not a high priority. + */ + parseerror(parser, "TODO: initializers for local arrays"); + break; + } + /* +static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma, bool truthvalue, bool with_labels); +*/ + parseerror(parser, "TODO: initializing global arrays is not supported yet!"); + break; + } + else if (var->expression.vtype == TYPE_FUNCTION && (parser->tok == '{' || parser->tok == '[')) { if (localblock) { parseerror(parser, "cannot declare functions within functions"); @@ -5449,6 +5884,7 @@ skipvar: } vec_free(sy.out); vec_free(sy.ops); + vec_free(sy.argc); var->cvq = cvq; } } @@ -5619,7 +6055,7 @@ static void generate_checksum(parser_t *parser) if (!ast_istype(parser->fields[i], ast_value)) continue; value = (ast_value*)(parser->fields[i]); - switch (value->expression.next->expression.vtype) { + switch (value->expression.next->vtype) { case TYPE_FLOAT: crc = progdefs_crc_both(crc, "\tfloat\t"); break; case TYPE_VECTOR: crc = progdefs_crc_both(crc, "\tvec3_t\t"); break; case TYPE_STRING: crc = progdefs_crc_both(crc, "\tstring_t\t"); break; @@ -5633,22 +6069,26 @@ static void generate_checksum(parser_t *parser) } crc = progdefs_crc_both(crc, "} entvars_t;\n\n"); - code_crc = crc; + parser->code->crc = crc; } -static parser_t *parser; - -bool parser_init() +parser_t *parser_create() { + parser_t *parser; lex_ctx empty_ctx; size_t i; parser = (parser_t*)mem_a(sizeof(parser_t)); if (!parser) - return false; + return NULL; 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; @@ -5658,7 +6098,7 @@ bool parser_init() if (!parser->assign_op) { printf("internal error: initializing parser: failed to find assign operator\n"); mem_d(parser); - return false; + return NULL; } vec_push(parser->variables, parser->htfields = util_htnew(PARSER_HT_SIZE)); @@ -5666,6 +6106,10 @@ bool parser_init() vec_push(parser->typedefs, util_htnew(TYPEDEF_HT_SIZE)); vec_push(parser->_blocktypedefs, 0); + parser->aliases = util_htnew(PARSER_HT_SIZE); + + parser->ht_imm_string = util_htnew(512); + /* corrector */ vec_push(parser->correct_variables, correct_trie_new()); vec_push(parser->correct_variables_score, NULL); @@ -5692,10 +6136,11 @@ bool parser_init() } else { parser->reserved_version = NULL; } - return true; + + return parser; } -bool parser_compile() +static bool parser_compile(parser_t *parser) { /* initial lexer/parser state */ parser->lex->flags.noops = true; @@ -5727,29 +6172,32 @@ bool parser_compile() return !compile_errors; } -bool parser_compile_file(const char *filename) +bool parser_compile_file(parser_t *parser, const char *filename) { parser->lex = lex_open(filename); if (!parser->lex) { con_err("failed to open file \"%s\"\n", filename); return false; } - return parser_compile(); + return parser_compile(parser); } -bool parser_compile_string(const char *name, const char *str, size_t len) +bool parser_compile_string(parser_t *parser, const char *name, const char *str, size_t len) { parser->lex = lex_open_string(str, len, name); if (!parser->lex) { con_err("failed to create lexer for string \"%s\"\n", name); return false; } - return parser_compile(); + return parser_compile(parser); } -void parser_cleanup() +static void parser_remove_ast(parser_t *parser) { size_t i; + if (parser->ast_cleaned) + return; + parser->ast_cleaned = true; for (i = 0; i < vec_size(parser->accessors); ++i) { ast_delete(parser->accessors[i]->constval.vfunc); parser->accessors[i]->constval.vfunc = NULL; @@ -5777,6 +6225,7 @@ void parser_cleanup() vec_free(parser->functions); vec_free(parser->imm_vector); vec_free(parser->imm_string); + util_htdel(parser->ht_imm_string); vec_free(parser->imm_float); vec_free(parser->globals); vec_free(parser->fields); @@ -5816,10 +6265,19 @@ void parser_cleanup() ast_value_delete(parser->const_vec[1]); ast_value_delete(parser->const_vec[2]); + util_htdel(parser->aliases); + intrin_intrinsics_destroy(parser); +} + +void parser_cleanup(parser_t *parser) +{ + parser_remove_ast(parser); + code_cleanup(parser->code); + mem_d(parser); } -bool parser_finish(const char *output) +bool parser_finish(parser_t *parser, const char *output) { size_t i; ir_builder *ir; @@ -5854,11 +6312,11 @@ bool parser_finish(const char *output) ast_expression *subtype; field->hasvalue = true; subtype = field->expression.next; - ifld = ir_builder_create_field(ir, field->name, subtype->expression.vtype); - if (subtype->expression.vtype == TYPE_FIELD) - ifld->fieldtype = subtype->expression.next->expression.vtype; - else if (subtype->expression.vtype == TYPE_FUNCTION) - ifld->outtype = subtype->expression.next->expression.vtype; + ifld = ir_builder_create_field(ir, field->name, subtype->vtype); + if (subtype->vtype == TYPE_FIELD) + ifld->fieldtype = subtype->next->vtype; + else if (subtype->vtype == TYPE_FUNCTION) + ifld->outtype = subtype->next->vtype; (void)!ir_value_set_field(field->ir_v, ifld); } } @@ -5946,7 +6404,7 @@ bool parser_finish(const char *output) } for (i = 0; i < vec_size(parser->fields); ++i) { ast_value *asvalue; - asvalue = (ast_value*)(parser->fields[i]->expression.next); + asvalue = (ast_value*)(parser->fields[i]->next); if (!ast_istype((ast_expression*)asvalue, ast_value)) continue; @@ -5972,6 +6430,8 @@ bool parser_finish(const char *output) return false; } } + + generate_checksum(parser); if (OPTS_OPTION_BOOL(OPTION_DUMP)) ir_builder_dump(ir, con_out); for (i = 0; i < vec_size(parser->functions); ++i) { @@ -5981,6 +6441,7 @@ bool parser_finish(const char *output) return false; } } + parser_remove_ast(parser); if (compile_Werrors) { con_out("*** there were warnings treated as errors\n"); @@ -5992,15 +6453,12 @@ bool parser_finish(const char *output) if (OPTS_OPTION_BOOL(OPTION_DUMPFIN)) ir_builder_dump(ir, con_out); - generate_checksum(parser); - - if (!ir_builder_generate(ir, output)) { + if (!ir_builder_generate(parser->code, ir, output)) { con_out("*** failed to generate output file\n"); ir_builder_delete(ir); return false; } } - ir_builder_delete(ir); return retval; }