X-Git-Url: https://git.xonotic.org/?p=xonotic%2Fgmqcc.git;a=blobdiff_plain;f=parser.c;h=e8760bb08344a5e07f2333f3e6eba5fe83f9c360;hp=b53dba5ec5b9df6055eebd0789ac07a5d1a4f0b6;hb=960cb7034af7240036a969a59f21e28e63a86df2;hpb=0c5850941790653e5fbb8cb4f8050446137806f9 diff --git a/parser.c b/parser.c index b53dba5..e8760bb 100644 --- a/parser.c +++ b/parser.c @@ -23,91 +23,11 @@ */ #include #include +#include "parser.h" -#include "gmqcc.h" -#include "lexer.h" -#include "ast.h" - -/* beginning of locals */ #define PARSER_HT_LOCALS 2 - -#define PARSER_HT_SIZE 128 -#define TYPEDEF_HT_SIZE 16 - -typedef struct parser_s { - lex_file *lex; - int tok; - - bool ast_cleaned; - - ast_expression **globals; - ast_expression **fields; - ast_function **functions; - ast_value **imm_float; - ast_value **imm_string; - ast_value **imm_vector; - size_t translated; - - ht ht_imm_string; - - /* must be deleted first, they reference immediates and values */ - ast_value **accessors; - - 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; - - size_t crc_globals; - size_t crc_fields; - - ast_function *function; - ht aliases; - - /* All the labels the function defined... - * Should they be in ast_function instead? - */ - ast_label **labels; - ast_goto **gotos; - const char **breaks; - const char **continues; - - /* A list of hashtables for each scope */ - ht *variables; - ht htfields; - ht htglobals; - ht *typedefs; - - /* same as above but for the spelling corrector */ - correct_trie_t **correct_variables; - size_t ***correct_variables_score; /* vector of vector of size_t* */ - - /* not to be used directly, we use the hash table */ - ast_expression **_locals; - size_t *_blocklocals; - ast_value **_typedefs; - size_t *_blocktypedefs; - lex_ctx *_block_ctx; - - /* we store the '=' operator info */ - const oper_info *assign_op; - - /* magic values */ - ast_value *const_vec[3]; - - /* pragma flags */ - bool noref; - - /* collected information */ - size_t max_param_count; - - /* code generator */ - code_t *code; -} parser_t; +#define PARSER_HT_SIZE 512 +#define TYPEDEF_HT_SIZE 512 static ast_expression * const intrinsic_debug_typestring = (ast_expression*)0x1; @@ -146,42 +66,6 @@ static bool GMQCC_WARN parsewarning(parser_t *parser, int warntype, const char * return r; } -/********************************************************************** - * some maths used for constant folding - */ - -vector vec3_add(vector a, vector b) -{ - vector out; - out.x = a.x + b.x; - out.y = a.y + b.y; - out.z = a.z + b.z; - return out; -} - -vector vec3_sub(vector a, vector b) -{ - vector out; - out.x = a.x - b.x; - out.y = a.y - b.y; - out.z = a.z - b.z; - return out; -} - -qcfloat vec3_mulvv(vector a, vector b) -{ - return (a.x * b.x + a.y * b.y + a.z * b.z); -} - -vector vec3_mulvf(vector a, float b) -{ - vector out; - out.x = a.x * b; - out.y = a.y * b; - out.z = a.z * b; - return out; -} - /********************************************************************** * parsing */ @@ -201,53 +85,8 @@ static bool parser_next(parser_t *parser) #define parser_tokval(p) ((p)->lex->tok.value) #define parser_token(p) (&((p)->lex->tok)) -#define parser_ctx(p) ((p)->lex->tok.ctx) -static ast_value* parser_const_float(parser_t *parser, double d) -{ - size_t i; - ast_value *out; - lex_ctx ctx; - for (i = 0; i < vec_size(parser->imm_float); ++i) { - const double compare = parser->imm_float[i]->constval.vfloat; - if (memcmp((const void*)&compare, (const void *)&d, sizeof(double)) == 0) - return parser->imm_float[i]; - } - if (parser->lex) - ctx = parser_ctx(parser); - else { - memset(&ctx, 0, sizeof(ctx)); - } - 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; -} - -static ast_value* parser_const_float_0(parser_t *parser) -{ - if (!parser->imm_float_zero) - parser->imm_float_zero = parser_const_float(parser, 0); - 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) - parser->imm_float_one = parser_const_float(parser, 1); - return parser->imm_float_one; -} - -static char *parser_strdup(const char *str) +char *parser_strdup(const char *str) { if (str && !*str) { /* actually dup empty strings */ @@ -258,74 +97,6 @@ static char *parser_strdup(const char *str) return util_strdup(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); - 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]; - 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; -} - -static ast_value* parser_const_vector(parser_t *parser, vector v) -{ - size_t i; - ast_value *out; - for (i = 0; i < vec_size(parser->imm_vector); ++i) { - if (!memcmp(&parser->imm_vector[i]->constval.vvec, &v, sizeof(v))) - return parser->imm_vector[i]; - } - 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; -} - -static ast_value* parser_const_vector_f(parser_t *parser, float x, float y, float z) -{ - vector v; - v.x = x; - v.y = y; - v.z = z; - return parser_const_vector(parser, v); -} - -static ast_value* parser_const_vector_0(parser_t *parser) -{ - if (!parser->imm_vector_zero) - parser->imm_vector_zero = parser_const_vector_f(parser, 0, 0, 0); - return parser->imm_vector_zero; -} - static ast_expression* parser_find_field(parser_t *parser, const char *name) { return ( ast_expression*)util_htget(parser->htfields, name); @@ -412,7 +183,7 @@ typedef struct size_t off; ast_expression *out; ast_block *block; /* for commas and function calls */ - lex_ctx ctx; + lex_ctx_t ctx; } sy_elem; enum { @@ -430,7 +201,7 @@ typedef struct unsigned int *paren; } shunt; -static sy_elem syexp(lex_ctx ctx, ast_expression *v) { +static sy_elem syexp(lex_ctx_t ctx, ast_expression *v) { sy_elem e; e.etype = 0; e.off = 0; @@ -441,7 +212,7 @@ static sy_elem syexp(lex_ctx ctx, ast_expression *v) { return e; } -static sy_elem syblock(lex_ctx ctx, ast_block *v) { +static sy_elem syblock(lex_ctx_t ctx, ast_block *v) { sy_elem e; e.etype = 0; e.off = 0; @@ -452,7 +223,7 @@ static sy_elem syblock(lex_ctx ctx, ast_block *v) { return e; } -static sy_elem syop(lex_ctx ctx, const oper_info *op) { +static sy_elem syop(lex_ctx_t ctx, const oper_info *op) { sy_elem e; e.etype = 1 + (op - operators); e.off = 0; @@ -463,7 +234,7 @@ static sy_elem syop(lex_ctx ctx, const oper_info *op) { return e; } -static sy_elem syparen(lex_ctx ctx, size_t off) { +static sy_elem syparen(lex_ctx_t ctx, size_t off) { sy_elem e; e.etype = 0; e.off = off; @@ -486,7 +257,7 @@ static bool rotate_entfield_array_index_nodes(ast_expression **out) ast_expression *sub; ast_expression *entity; - lex_ctx ctx = ast_ctx(*out); + lex_ctx_t ctx = ast_ctx(*out); if (!ast_istype(*out, ast_array_index)) return false; @@ -516,43 +287,17 @@ static bool rotate_entfield_array_index_nodes(ast_expression **out) return true; } -static bool immediate_is_true(lex_ctx ctx, ast_value *v) -{ - switch (v->expression.vtype) { - case TYPE_FLOAT: - return !!v->constval.vfloat; - case TYPE_INTEGER: - return !!v->constval.vint; - case TYPE_VECTOR: - if (OPTS_FLAG(CORRECT_LOGIC)) - return v->constval.vvec.x && - v->constval.vvec.y && - v->constval.vvec.z; - else - return !!(v->constval.vvec.x); - case TYPE_STRING: - if (!v->constval.vstring) - return false; - if (v->constval.vstring && OPTS_FLAG(TRUE_EMPTY_STRINGS)) - return true; - return !!v->constval.vstring[0]; - default: - compile_error(ctx, "internal error: immediate_is_true on invalid type"); - return !!v->constval.vfunc; - } -} - static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) { const oper_info *op; - lex_ctx ctx; + lex_ctx_t ctx; ast_expression *out = NULL; ast_expression *exprs[3]; ast_block *blocks[3]; ast_value *asvalue[3]; ast_binstore *asbinstore; size_t i, assignop, addop, subop; - qcint generated_op = 0; + qcint_t generated_op = 0; char ty1[1024]; char ty2[1024]; @@ -608,14 +353,11 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) #define NotSameType(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)->vtype != TYPE_FUNCTION) -#define CanConstFold(A, B) \ - (CanConstFold1(A) && CanConstFold1(B)) -#define ConstV(i) (asvalue[(i)]->constval.vvec) -#define ConstF(i) (asvalue[(i)]->constval.vfloat) -#define ConstS(i) (asvalue[(i)]->constval.vstring) + + /* preform any constant folding on operator usage first */ + /*if ((out = fold_op(parser->fold, op, exprs)))*/ + /*goto complete;*/ + switch (op->id) { default: @@ -710,132 +452,107 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) out = exprs[0]; break; case opid2('-','P'): - switch (exprs[0]->vtype) { - case TYPE_FLOAT: - if (CanConstFold1(exprs[0])) - out = (ast_expression*)parser_const_float(parser, -ConstF(0)); - else + if (!(out = fold_op(parser->fold, op, exprs))) { + switch (exprs[0]->vtype) { + case TYPE_FLOAT: out = (ast_expression*)ast_binary_new(ctx, INSTR_SUB_F, - (ast_expression*)parser_const_float_0(parser), - exprs[0]); - break; - case TYPE_VECTOR: - if (CanConstFold1(exprs[0])) - out = (ast_expression*)parser_const_vector_f(parser, - -ConstV(0).x, -ConstV(0).y, -ConstV(0).z); - else + (ast_expression*)parser->fold->imm_float[0], + exprs[0]); + break; + case TYPE_VECTOR: out = (ast_expression*)ast_binary_new(ctx, INSTR_SUB_V, - (ast_expression*)parser_const_vector_0(parser), - exprs[0]); - break; - default: - compile_error(ctx, "invalid types used in expression: cannot negate type %s", - type_name[exprs[0]->vtype]); - return false; + (ast_expression*)parser->fold->imm_vector[0], + exprs[0]); + break; + default: + compile_error(ctx, "invalid types used in expression: cannot negate type %s", + type_name[exprs[0]->vtype]); + return false; + } } break; case opid2('!','P'): - switch (exprs[0]->vtype) { - case TYPE_FLOAT: - if (CanConstFold1(exprs[0])) - out = (ast_expression*)parser_const_float(parser, !ConstF(0)); - else + if (!(out = fold_op(parser->fold, op, exprs))) { + switch (exprs[0]->vtype) { + case TYPE_FLOAT: out = (ast_expression*)ast_unary_new(ctx, INSTR_NOT_F, exprs[0]); - break; - case TYPE_VECTOR: - if (CanConstFold1(exprs[0])) - out = (ast_expression*)parser_const_float(parser, - (!ConstV(0).x && !ConstV(0).y && !ConstV(0).z)); - else + break; + case TYPE_VECTOR: out = (ast_expression*)ast_unary_new(ctx, INSTR_NOT_V, exprs[0]); - break; - case TYPE_STRING: - if (CanConstFold1(exprs[0])) { - if (OPTS_FLAG(TRUE_EMPTY_STRINGS)) - out = (ast_expression*)parser_const_float(parser, !ConstS(0)); - else - out = (ast_expression*)parser_const_float(parser, !ConstS(0) || !*ConstS(0)); - } else { + break; + case TYPE_STRING: if (OPTS_FLAG(TRUE_EMPTY_STRINGS)) out = (ast_expression*)ast_unary_new(ctx, INSTR_NOT_F, exprs[0]); else out = (ast_expression*)ast_unary_new(ctx, INSTR_NOT_S, exprs[0]); - } - break; - /* we don't constant-fold NOT for these types */ - case TYPE_ENTITY: - out = (ast_expression*)ast_unary_new(ctx, INSTR_NOT_ENT, exprs[0]); - break; - case TYPE_FUNCTION: - out = (ast_expression*)ast_unary_new(ctx, INSTR_NOT_FNC, exprs[0]); - break; - default: - compile_error(ctx, "invalid types used in expression: cannot logically negate type %s", - type_name[exprs[0]->vtype]); - return false; + break; + /* we don't constant-fold NOT for these types */ + case TYPE_ENTITY: + out = (ast_expression*)ast_unary_new(ctx, INSTR_NOT_ENT, exprs[0]); + break; + case TYPE_FUNCTION: + out = (ast_expression*)ast_unary_new(ctx, INSTR_NOT_FNC, exprs[0]); + break; + default: + compile_error(ctx, "invalid types used in expression: cannot logically negate type %s", + type_name[exprs[0]->vtype]); + return false; + } } break; case opid1('+'): if (exprs[0]->vtype != exprs[1]->vtype || - (exprs[0]->vtype != TYPE_VECTOR && exprs[0]->vtype != TYPE_FLOAT) ) + (exprs[0]->vtype != TYPE_VECTOR && exprs[0]->vtype != TYPE_FLOAT) ) { - compile_error(ctx, "invalid types used in expression: cannot add type %s and %s", + compile_error(ctx, "invalid types used in expression: cannot add type %s and %s (%s %s)", type_name[exprs[0]->vtype], - type_name[exprs[1]->vtype]); + type_name[exprs[1]->vtype], + asvalue[0]->name, + asvalue[1]->name); return false; } - switch (exprs[0]->vtype) { - case TYPE_FLOAT: - if (CanConstFold(exprs[0], exprs[1])) - { - out = (ast_expression*)parser_const_float(parser, ConstF(0) + ConstF(1)); - } - else + if (!(out = fold_op(parser->fold, op, exprs))) { + switch (exprs[0]->vtype) { + case TYPE_FLOAT: out = (ast_expression*)ast_binary_new(ctx, INSTR_ADD_F, exprs[0], exprs[1]); - break; - case TYPE_VECTOR: - if (CanConstFold(exprs[0], exprs[1])) - out = (ast_expression*)parser_const_vector(parser, vec3_add(ConstV(0), ConstV(1))); - else + break; + case TYPE_VECTOR: out = (ast_expression*)ast_binary_new(ctx, INSTR_ADD_V, exprs[0], exprs[1]); - break; - default: - compile_error(ctx, "invalid types used in expression: cannot add type %s and %s", - type_name[exprs[0]->vtype], - type_name[exprs[1]->vtype]); - return false; - }; + break; + default: + compile_error(ctx, "invalid types used in expression: cannot add type %s and %s", + type_name[exprs[0]->vtype], + type_name[exprs[1]->vtype]); + return false; + } + } break; case opid1('-'): - if (exprs[0]->vtype != exprs[1]->vtype || - (exprs[0]->vtype != TYPE_VECTOR && exprs[0]->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]->vtype], type_name[exprs[0]->vtype]); return false; } - switch (exprs[0]->vtype) { - case TYPE_FLOAT: - if (CanConstFold(exprs[0], exprs[1])) - out = (ast_expression*)parser_const_float(parser, ConstF(0) - ConstF(1)); - else + if (!(out = fold_op(parser->fold, op, exprs))) { + switch (exprs[0]->vtype) { + case TYPE_FLOAT: out = (ast_expression*)ast_binary_new(ctx, INSTR_SUB_F, exprs[0], exprs[1]); - break; - case TYPE_VECTOR: - if (CanConstFold(exprs[0], exprs[1])) - out = (ast_expression*)parser_const_vector(parser, vec3_sub(ConstV(0), ConstV(1))); - else + break; + case TYPE_VECTOR: out = (ast_expression*)ast_binary_new(ctx, INSTR_SUB_V, exprs[0], exprs[1]); - break; - default: - compile_error(ctx, "invalid types used in expression: cannot subtract type %s from %s", - type_name[exprs[1]->vtype], - type_name[exprs[0]->vtype]); - return false; - }; + break; + default: + compile_error(ctx, "invalid types used in expression: cannot subtract type %s from %s", + type_name[exprs[1]->vtype], + type_name[exprs[0]->vtype]); + return false; + } + } break; case opid1('*'): if (exprs[0]->vtype != exprs[1]->vtype && @@ -850,142 +567,46 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) type_name[exprs[0]->vtype]); return false; } - switch (exprs[0]->vtype) { - case TYPE_FLOAT: - 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))); - else + if (!(out = fold_op(parser->fold, op, exprs))) { + switch (exprs[0]->vtype) { + case TYPE_FLOAT: + if (exprs[1]->vtype == TYPE_VECTOR) out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_FV, exprs[0], exprs[1]); - } - else - { - 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_MUL_F, exprs[0], exprs[1]); - } - break; - case TYPE_VECTOR: - 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))); - else + break; + case TYPE_VECTOR: + if (exprs[1]->vtype == TYPE_FLOAT) out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_VF, exprs[0], exprs[1]); - } - else - { - if (CanConstFold(exprs[0], exprs[1])) - out = (ast_expression*)parser_const_float(parser, vec3_mulvv(ConstV(0), ConstV(1))); - else if (OPTS_OPTIMIZATION(OPTIM_VECTOR_COMPONENTS) && CanConstFold1(exprs[0])) { - vector vec = ConstV(0); - 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->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); - } - 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->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); - } - 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->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); - } - else - out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_V, exprs[0], exprs[1]); - } - else if (OPTS_OPTIMIZATION(OPTIM_VECTOR_COMPONENTS) && CanConstFold1(exprs[1])) { - vector vec = ConstV(1); - 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->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)); - } - 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->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)); - } - 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->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)); - } - else - out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_V, exprs[0], exprs[1]); - } else out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_V, exprs[0], exprs[1]); - } - break; - default: - compile_error(ctx, "invalid types used in expression: cannot multiply types %s and %s", - type_name[exprs[1]->vtype], - type_name[exprs[0]->vtype]); - return false; - }; + break; + default: + compile_error(ctx, "invalid types used in expression: cannot multiply types %s and %s", + type_name[exprs[1]->vtype], + type_name[exprs[0]->vtype]); + return false; + } + } break; + case opid1('/'): 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) { - if (CanConstFold(exprs[0], exprs[1])) - out = (ast_expression*)parser_const_float(parser, ConstF(0) / ConstF(1)); - else + if (!(out = fold_op(parser->fold, op, exprs))) { + if (exprs[0]->vtype == TYPE_FLOAT) out = (ast_expression*)ast_binary_new(ctx, INSTR_DIV_F, exprs[0], exprs[1]); - } - 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 { - if (CanConstFold1(exprs[1])) { - out = (ast_expression*)parser_const_float(parser, 1.0 / ConstF(1)); - } else { - out = (ast_expression*)ast_binary_new(ctx, INSTR_DIV_F, - (ast_expression*)parser_const_float_1(parser), - exprs[1]); - } - if (!out) { - compile_error(ctx, "internal error: failed to generate division"); - return false; - } - out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_VF, exprs[0], out); + 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 types %s and %s", ty1, ty2); + return false; } } - else - { - 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; - } break; case opid1('%'): @@ -994,11 +615,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) 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 { + } else if (!(out = fold_op(parser->fold, op, exprs))) { /* generate a call to __builtin_mod */ ast_expression *mod = intrin_func(parser, "mod"); ast_call *call = NULL; @@ -1024,91 +641,124 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) type_name[exprs[1]->vtype]); return false; } - if (CanConstFold(exprs[0], exprs[1])) - out = (ast_expression*)parser_const_float(parser, - (op->id == opid1('|') ? (float)( ((qcint)ConstF(0)) | ((qcint)ConstF(1)) ) : - (float)( ((qcint)ConstF(0)) & ((qcint)ConstF(1)) ) )); - else + if (!(out = fold_op(parser->fold, op, exprs))) out = (ast_expression*)ast_binary_new(ctx, (op->id == opid1('|') ? INSTR_BITOR : INSTR_BITAND), exprs[0], exprs[1]); break; case opid1('^'): /* - * ^ can be implemented as: - * (LHS | RHS) & ~(LHS & RHS) - * to implement ~ we need to use -1-X, as you can see the - * whole process ends up becoming: - * (LHS | RHS) & (-1 - (LHS & RHS)) + * Okay lets designate what the hell is an acceptable use + * of the ^ operator. In many vector processing units, XOR + * is allowed to be used on vectors, but only if the first + * operand is a vector, the second operand can be a float + * or vector. It's never legal for the first operand to be + * a float, and then the following operand to be a vector. + * 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 + * is also not scalar, this process is repeated for all + * 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 + * are their own inverse. */ - if (NotSameType(TYPE_FLOAT)) { + if ( !(exprs[0]->vtype == TYPE_FLOAT && exprs[1]->vtype == TYPE_FLOAT) && + !(exprs[0]->vtype == TYPE_VECTOR && exprs[1]->vtype == TYPE_FLOAT) && + !(exprs[0]->vtype == TYPE_VECTOR && exprs[1]->vtype == TYPE_VECTOR)) + { compile_error(ctx, "invalid types used in expression: cannot perform bit operations 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 { - out = (ast_expression*) - ast_binary_new( + if (!(out = fold_op(parser->fold, op, exprs))) { + /* + * IF the first expression is float, the following will be too + * since scalar ^ vector is not allowed. + */ + if (exprs[0]->vtype == TYPE_FLOAT) { + ast_binary *expr = ast_binary_new( ctx, - INSTR_BITAND, + INSTR_SUB_F, + (ast_expression*)parser->fold->imm_float[2], (ast_expression*)ast_binary_new( ctx, - INSTR_BITOR, + INSTR_BITAND, exprs[0], exprs[1] - ), - (ast_expression*)ast_binary_new( + ) + ); + expr->refs = AST_REF_NONE; + + out = (ast_expression*) + ast_binary_new( ctx, - INSTR_SUB_F, - (ast_expression*)parser_const_float_neg1(parser), + INSTR_BITAND, (ast_expression*)ast_binary_new( ctx, - INSTR_BITAND, + INSTR_BITOR, exprs[0], exprs[1] - ) - ) - ); + ), + (ast_expression*)expr + ); + } else { + /* + * The first is a vector: vector is allowed to xor with vector and + * with scalar, branch here for the second operand. + */ + if (exprs[1]->vtype == TYPE_VECTOR) { + /* + * Xor all the values of the vector components against the + * vectors components in question. + */ + compile_error(ast_ctx(exprs[0]), "Not Yet Implemented: bit-xor for vector against vector"); + return false; + } else { + compile_error(ast_ctx(exprs[0]), "Not Yet Implemented: bit-xor for vector against float"); + return false; + } + } } break; case opid2('<','<'): case opid2('>','>'): - if (CanConstFold(exprs[0], exprs[1]) && ! NotSameType(TYPE_FLOAT)) { - if (op->id == opid2('<','<')) - 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)((unsigned int)(ConstF(0)) >> (unsigned int)(ConstF(1)))); - break; - } case opid3('<','<','='): case opid3('>','>','='): - compile_error(ast_ctx(exprs[0]), "Not Yet Implemented: bit-shifts"); - return false; + if(!(out = fold_op(parser->fold, op, exprs))) { + compile_error(ast_ctx(exprs[0]), "Not Yet Implemented: bit-shifts"); + return false; + } case opid2('|','|'): generated_op += 1; /* INSTR_OR */ case opid2('&','&'): generated_op += INSTR_AND; - if (CanConstFold(exprs[0], exprs[1])) - { - if (OPTS_FLAG(PERL_LOGIC)) { - if (immediate_is_true(ctx, asvalue[0])) - out = exprs[1]; - } - else - out = (ast_expression*)parser_const_float(parser, - ( (generated_op == INSTR_OR) - ? (immediate_is_true(ctx, asvalue[0]) || immediate_is_true(ctx, asvalue[1])) - : (immediate_is_true(ctx, asvalue[0]) && immediate_is_true(ctx, asvalue[1])) ) - ? 1 : 0); - } - else - { + if (!(out = fold_op(parser->fold, op, exprs))) { if (OPTS_FLAG(PERL_LOGIC) && !ast_compare_type(exprs[0], exprs[1])) { ast_type_to_string(exprs[0], ty1, sizeof(ty1)); ast_type_to_string(exprs[1], ty2, sizeof(ty2)); @@ -1155,9 +805,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) compile_error(ctx, "operands of ternary expression must have the same type, got %s and %s", ty1, ty2); return false; } - if (CanConstFold1(exprs[0])) - out = (immediate_is_true(ctx, asvalue[0]) ? exprs[1] : exprs[2]); - else + if (!(out = fold_op(parser->fold, op, exprs))) out = (ast_expression*)ast_ternary_new(ctx, exprs[0], exprs[1], exprs[2]); break; @@ -1167,13 +815,10 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) 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 { + + if (!(out = fold_op(parser->fold, op, exprs))) { 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]); @@ -1189,33 +834,26 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) 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 { + if (!(out = fold_op(parser->fold, op, exprs))) { ast_binary *eq = ast_binary_new(ctx, INSTR_EQ_F, exprs[0], exprs[1]); - eq->refs = (ast_binary_ref)false; /* references nothing */ + eq->refs = AST_REF_NONE; /* 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), + (ast_expression*)parser->fold->imm_float[2], /* } else { */ /* if (eq) { */ (ast_expression*)ast_ternary_new(ctx, (ast_expression*)eq, /* out = 0 */ - (ast_expression*)parser_const_float_0(parser), + (ast_expression*)parser->fold->imm_float[0], /* } else { */ /* out = 1 */ - (ast_expression*)parser_const_float_1(parser) + (ast_expression*)parser->fold->imm_float[1] /* } */ ) /* } */ @@ -1238,7 +876,8 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) type_name[exprs[1]->vtype]); return false; } - out = (ast_expression*)ast_binary_new(ctx, generated_op, exprs[0], exprs[1]); + if (!(out = fold_op(parser->fold, op, exprs))) + out = (ast_expression*)ast_binary_new(ctx, generated_op, exprs[0], exprs[1]); break; case opid2('!', '='): if (exprs[0]->vtype != exprs[1]->vtype) { @@ -1247,7 +886,8 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) type_name[exprs[1]->vtype]); return false; } - out = (ast_expression*)ast_binary_new(ctx, type_ne_instr[exprs[0]->vtype], exprs[0], exprs[1]); + if (!(out = fold_op(parser->fold, op, exprs))) + out = (ast_expression*)ast_binary_new(ctx, type_ne_instr[exprs[0]->vtype], exprs[0], exprs[1]); break; case opid2('=', '='): if (exprs[0]->vtype != exprs[1]->vtype) { @@ -1256,7 +896,8 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) type_name[exprs[1]->vtype]); return false; } - out = (ast_expression*)ast_binary_new(ctx, type_eq_instr[exprs[0]->vtype], exprs[0], exprs[1]); + if (!(out = fold_op(parser->fold, op, exprs))) + out = (ast_expression*)ast_binary_new(ctx, type_eq_instr[exprs[0]->vtype], exprs[0], exprs[1]); break; case opid1('='): @@ -1340,11 +981,11 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) if (ast_istype(exprs[0], ast_entfield)) { out = (ast_expression*)ast_binstore_new(ctx, INSTR_STOREP_F, addop, exprs[0], - (ast_expression*)parser_const_float_1(parser)); + (ast_expression*)parser->fold->imm_float[1]); } else { out = (ast_expression*)ast_binstore_new(ctx, INSTR_STORE_F, addop, exprs[0], - (ast_expression*)parser_const_float_1(parser)); + (ast_expression*)parser->fold->imm_float[1]); } break; case opid3('S','+','+'): @@ -1368,17 +1009,17 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) if (ast_istype(exprs[0], ast_entfield)) { out = (ast_expression*)ast_binstore_new(ctx, INSTR_STOREP_F, addop, exprs[0], - (ast_expression*)parser_const_float_1(parser)); + (ast_expression*)parser->fold->imm_float[1]); } else { out = (ast_expression*)ast_binstore_new(ctx, INSTR_STORE_F, addop, exprs[0], - (ast_expression*)parser_const_float_1(parser)); + (ast_expression*)parser->fold->imm_float[1]); } if (!out) return false; out = (ast_expression*)ast_binary_new(ctx, subop, out, - (ast_expression*)parser_const_float_1(parser)); + (ast_expression*)parser->fold->imm_float[1]); break; case opid2('+','='): case opid2('-','='): @@ -1446,14 +1087,9 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) out = (ast_expression*)ast_binstore_new(ctx, assignop, INSTR_MUL_VF, exprs[0], exprs[1]); } else { - /* there's no DIV_VF */ - if (CanConstFold1(exprs[1])) { - out = (ast_expression*)parser_const_float(parser, 1.0 / ConstF(1)); - } else { - out = (ast_expression*)ast_binary_new(ctx, INSTR_DIV_F, - (ast_expression*)parser_const_float_1(parser), + out = (ast_expression*)ast_binary_new(ctx, INSTR_DIV_F, + (ast_expression*)parser->fold->imm_float[1], exprs[1]); - } if (!out) { compile_error(ctx, "internal error: failed to generate division"); return false; @@ -1522,16 +1158,12 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) 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]); + if (!(out = fold_op(parser->fold, op, exprs))) + out = (ast_expression*)ast_binary_new(ctx, INSTR_SUB_F, (ast_expression*)parser->fold->imm_float[2], exprs[0]); break; } #undef NotSameType - +/*complete:*/ if (!out) { compile_error(ctx, "failed to apply operator %s", op->op); return false; @@ -1586,7 +1218,7 @@ static bool parser_close_call(parser_t *parser, shunt *sy) ast_type_to_string(vec_last(sy->out).out, ty, sizeof(ty)); ast_unref(vec_last(sy->out).out); sy->out[fid] = syexp(ast_ctx(vec_last(sy->out).out), - (ast_expression*)parser_const_string(parser, ty, false)); + (ast_expression*)fold_constgen_string(parser->fold, ty, false)); vec_shrinkby(sy->out, 1); return true; } @@ -1616,7 +1248,7 @@ static bool parser_close_call(parser_t *parser, shunt *sy) if ((fun->flags & AST_FLAG_VARIADIC) && !(/*funval->cvq == CV_CONST && */ funval->hasvalue && funval->constval.vfunc->builtin)) { - call->va_count = (ast_expression*)parser_const_float(parser, (double)paramcount); + call->va_count = (ast_expression*)fold_constgen_float(parser->fold, (qcfloat_t)paramcount); } } @@ -1729,6 +1361,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; @@ -1742,7 +1376,7 @@ static ast_expression* parse_vararg_do(parser_t *parser) ast_expression *idx, *out; ast_value *typevar; ast_value *funtype = parser->function->vtype; - lex_ctx ctx = parser_ctx(parser); + lex_ctx_t ctx = parser_ctx(parser); if (!parser->function->varargs) { parseerror(parser, "function has no variable argument list"); @@ -1845,7 +1479,7 @@ static bool parse_sya_operand(parser_t *parser, shunt *sy, bool with_labels) parseerror(parser, "expected a constant string in translatable-string extension"); return false; } - val = parser_const_string(parser, parser_tokval(parser), true); + val = (ast_value*)fold_constgen_string(parser->fold, parser_tokval(parser), true); if (!val) return false; vec_push(sy->out, syexp(parser_ctx(parser), (ast_expression*)val)); @@ -1870,35 +1504,31 @@ static bool parse_sya_operand(parser_t *parser, shunt *sy, bool with_labels) return true; } else if (parser->tok == TOKEN_FLOATCONST) { - ast_value *val; - val = parser_const_float(parser, (parser_token(parser)->constval.f)); + ast_expression *val = fold_constgen_float(parser->fold, (parser_token(parser)->constval.f)); if (!val) return false; - vec_push(sy->out, syexp(parser_ctx(parser), (ast_expression*)val)); + vec_push(sy->out, syexp(parser_ctx(parser), val)); return true; } else if (parser->tok == TOKEN_INTCONST || parser->tok == TOKEN_CHARCONST) { - ast_value *val; - val = parser_const_float(parser, (double)(parser_token(parser)->constval.i)); + ast_expression *val = fold_constgen_float(parser->fold, (qcfloat_t)(parser_token(parser)->constval.i)); if (!val) return false; - vec_push(sy->out, syexp(parser_ctx(parser), (ast_expression*)val)); + vec_push(sy->out, syexp(parser_ctx(parser), val)); return true; } else if (parser->tok == TOKEN_STRINGCONST) { - ast_value *val; - val = parser_const_string(parser, parser_tokval(parser), false); + ast_expression *val = fold_constgen_string(parser->fold, parser_tokval(parser), false); if (!val) return false; - vec_push(sy->out, syexp(parser_ctx(parser), (ast_expression*)val)); + vec_push(sy->out, syexp(parser_ctx(parser), val)); return true; } else if (parser->tok == TOKEN_VECTORCONST) { - ast_value *val; - val = parser_const_vector(parser, parser_token(parser)->constval.v); + ast_expression *val = fold_constgen_vector(parser->fold, parser_token(parser)->constval.v); if (!val) return false; - vec_push(sy->out, syexp(parser_ctx(parser), (ast_expression*)val)); + vec_push(sy->out, syexp(parser_ctx(parser), val)); return true; } else if (parser->tok == TOKEN_IDENT) @@ -1933,7 +1563,7 @@ static bool parse_sya_operand(parser_t *parser, shunt *sy, bool with_labels) } } if (!var && !strcmp(parser_tokval(parser), "__FUNC__")) - var = (ast_expression*)parser_const_string(parser, parser->function->name, false); + var = (ast_expression*)fold_constgen_string(parser->fold, parser->function->name, false); if (!var) { /* intrinsics */ if (!strcmp(parser_tokval(parser), "__builtin_debug_typestring")) { @@ -1976,7 +1606,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; } @@ -2233,7 +1863,7 @@ static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma { 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); + vec_last(sy.out).out = (ast_expression*)fold_constgen_string(parser->fold, newstr, false); mem_d(newstr); concatenated = true; } @@ -2434,7 +2064,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; @@ -2456,7 +2087,7 @@ static bool parse_if(parser_t *parser, ast_block *block, ast_expression **out) ast_expression *cond, *ontrue = NULL, *onfalse = NULL; bool ifnot = false; - lex_ctx ctx = parser_ctx(parser); + lex_ctx_t ctx = parser_ctx(parser); (void)block; /* not touching */ @@ -2595,7 +2226,7 @@ static bool parse_while_go(parser_t *parser, ast_block *block, ast_expression ** bool ifnot = false; - lex_ctx ctx = parser_ctx(parser); + lex_ctx_t ctx = parser_ctx(parser); (void)block; /* not touching */ @@ -2674,7 +2305,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 { @@ -2691,7 +2327,7 @@ static bool parse_dowhile_go(parser_t *parser, ast_block *block, ast_expression bool ifnot = false; - lex_ctx ctx = parser_ctx(parser); + lex_ctx_t ctx = parser_ctx(parser); (void)block; /* not touching */ @@ -2816,7 +2452,7 @@ static bool parse_for_go(parser_t *parser, ast_block *block, ast_expression **ou bool ifnot = false; - lex_ctx ctx = parser_ctx(parser); + lex_ctx_t ctx = parser_ctx(parser); parser_enterblock(parser); @@ -2882,7 +2518,7 @@ static bool parse_for_go(parser_t *parser, ast_block *block, ast_expression **ou /* parse the incrementor */ if (parser->tok != ')') { - lex_ctx condctx = parser_ctx(parser); + lex_ctx_t condctx = parser_ctx(parser); increment = parse_expression_leave(parser, false, false, false); if (!increment) goto onerr; @@ -2934,7 +2570,7 @@ static bool parse_return(parser_t *parser, ast_block *block, ast_expression **ou ast_value *retval = parser->function->return_value; ast_value *expected = parser->function->vtype; - lex_ctx ctx = parser_ctx(parser); + lex_ctx_t ctx = parser_ctx(parser); (void)block; /* not touching */ @@ -3033,7 +2669,7 @@ static bool parse_break_continue(parser_t *parser, ast_block *block, ast_express { size_t i; unsigned int levels = 0; - lex_ctx ctx = parser_ctx(parser); + lex_ctx_t ctx = parser_ctx(parser); const char **loops = (is_continue ? parser->continues : parser->breaks); (void)block; /* not touching */ @@ -3320,7 +2956,7 @@ static bool parse_switch_go(parser_t *parser, ast_block *block, ast_expression * bool noref, is_static; uint32_t qflags = 0; - lex_ctx ctx = parser_ctx(parser); + lex_ctx_t ctx = parser_ctx(parser); (void)block; /* not touching */ (void)opval; @@ -3542,7 +3178,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; } @@ -3831,7 +3468,7 @@ static bool parse_statement(parser_t *parser, ast_block *block, ast_expression * } else { - lex_ctx ctx = parser_ctx(parser); + lex_ctx_t ctx = parser_ctx(parser); ast_expression *exp = parse_expression(parser, false, false); if (!exp) return false; @@ -3848,7 +3485,7 @@ static bool parse_enum(parser_t *parser) { bool flag = false; bool reverse = false; - qcfloat num = 0; + qcfloat_t num = 0; ast_value **values = NULL; ast_value *var = NULL; ast_value *asvalue; @@ -4230,7 +3867,7 @@ static bool parse_function_body(parser_t *parser, ast_value *var) } if (has_frame_think) { - lex_ctx ctx; + lex_ctx_t ctx; ast_expression *self_frame; ast_expression *self_nextthink; ast_expression *self_think; @@ -4245,7 +3882,7 @@ static bool parse_function_body(parser_t *parser, ast_value *var) self_think = (ast_expression*)ast_entfield_new(ctx, gbl_self, fld_think); time_plus_1 = (ast_expression*)ast_binary_new(ctx, INSTR_ADD_F, - gbl_time, (ast_expression*)parser_const_float(parser, 0.1)); + gbl_time, (ast_expression*)fold_constgen_float(parser->fold, 0.1)); if (!self_frame || !self_nextthink || !self_think || !time_plus_1) { if (self_frame) ast_delete(self_frame); @@ -4359,9 +3996,8 @@ static bool parse_function_body(parser_t *parser, ast_value *var) ast_block_delete(block); goto enderrfn; } - func->varargs = varargs; - - func->fixedparams = parser_const_float(parser, vec_size(var->expression.params)); + func->varargs = varargs; + func->fixedparams = (ast_value*)fold_constgen_float(parser->fold, vec_size(var->expression.params)); } parser->function = func; @@ -4410,7 +4046,7 @@ static ast_expression *array_accessor_split( ast_ifthen *ifthen; ast_binary *cmp; - lex_ctx ctx = ast_ctx(array); + lex_ctx_t ctx = ast_ctx(array); if (!left || !right) { if (left) ast_delete(left); @@ -4420,7 +4056,7 @@ static ast_expression *array_accessor_split( cmp = ast_binary_new(ctx, INSTR_LT, (ast_expression*)index, - (ast_expression*)parser_const_float(parser, middle)); + (ast_expression*)fold_constgen_float(parser->fold, middle)); if (!cmp) { ast_delete(left); ast_delete(right); @@ -4440,7 +4076,7 @@ static ast_expression *array_accessor_split( static ast_expression *array_setter_node(parser_t *parser, ast_value *array, ast_value *index, ast_value *value, size_t from, size_t afterend) { - lex_ctx ctx = ast_ctx(array); + lex_ctx_t ctx = ast_ctx(array); if (from+1 == afterend) { /* set this value */ @@ -4453,7 +4089,7 @@ static ast_expression *array_setter_node(parser_t *parser, ast_value *array, ast if (value->expression.vtype == TYPE_FIELD && value->expression.next->vtype == TYPE_VECTOR) assignop = INSTR_STORE_V; - subscript = ast_array_index_new(ctx, (ast_expression*)array, (ast_expression*)parser_const_float(parser, from)); + subscript = ast_array_index_new(ctx, (ast_expression*)array, (ast_expression*)fold_constgen_float(parser->fold, from)); if (!subscript) return NULL; @@ -4505,7 +4141,7 @@ static ast_expression *array_field_setter_node( size_t from, size_t afterend) { - lex_ctx ctx = ast_ctx(array); + lex_ctx_t ctx = ast_ctx(array); if (from+1 == afterend) { /* set this value */ @@ -4519,7 +4155,7 @@ static ast_expression *array_field_setter_node( if (value->expression.vtype == TYPE_FIELD && value->expression.next->vtype == TYPE_VECTOR) assignop = INSTR_STOREP_V; - subscript = ast_array_index_new(ctx, (ast_expression*)array, (ast_expression*)parser_const_float(parser, from)); + subscript = ast_array_index_new(ctx, (ast_expression*)array, (ast_expression*)fold_constgen_float(parser->fold, from)); if (!subscript) return NULL; @@ -4576,13 +4212,13 @@ static ast_expression *array_field_setter_node( static ast_expression *array_getter_node(parser_t *parser, ast_value *array, ast_value *index, size_t from, size_t afterend) { - lex_ctx ctx = ast_ctx(array); + lex_ctx_t ctx = ast_ctx(array); if (from+1 == afterend) { ast_return *ret; ast_array_index *subscript; - subscript = ast_array_index_new(ctx, (ast_expression*)array, (ast_expression*)parser_const_float(parser, from)); + subscript = ast_array_index_new(ctx, (ast_expression*)array, (ast_expression*)fold_constgen_float(parser->fold, from)); if (!subscript) return NULL; @@ -4812,7 +4448,7 @@ static bool parser_create_array_getter(parser_t *parser, ast_value *array, const static ast_value *parse_typename(parser_t *parser, ast_value **storebase, ast_value *cached_typedef); static ast_value *parse_parameter_list(parser_t *parser, ast_value *var) { - lex_ctx ctx; + lex_ctx_t ctx; size_t i; ast_value **params; ast_value *param; @@ -4939,7 +4575,7 @@ static ast_value *parse_arraysize(parser_t *parser, ast_value *var) { ast_expression *cexp; ast_value *cval, *tmp; - lex_ctx ctx; + lex_ctx_t ctx; ctx = parser_ctx(parser); @@ -5018,7 +4654,7 @@ static ast_value *parse_arraysize(parser_t *parser, ast_value *var) static ast_value *parse_typename(parser_t *parser, ast_value **storebase, ast_value *cached_typedef) { ast_value *var, *tmp; - lex_ctx ctx; + lex_ctx_t ctx; const char *name = NULL; bool isfield = false; @@ -5804,8 +5440,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)) { @@ -6121,7 +5765,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; @@ -6175,14 +5819,13 @@ 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() { parser_t *parser; - lex_ctx empty_ctx; + lex_ctx_t empty_ctx; size_t i; parser = (parser_t*)mem_a(sizeof(parser_t)); @@ -6191,11 +5834,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; @@ -6215,14 +5853,13 @@ parser_t *parser_create() 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); - 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)) @@ -6244,6 +5881,7 @@ parser_t *parser_create() parser->reserved_version = NULL; } + parser->fold = fold_init(parser); return parser; } @@ -6313,15 +5951,6 @@ static void parser_remove_ast(parser_t *parser) for (i = 0; i < vec_size(parser->functions); ++i) { ast_delete(parser->functions[i]); } - for (i = 0; i < vec_size(parser->imm_vector); ++i) { - ast_delete(parser->imm_vector[i]); - } - for (i = 0; i < vec_size(parser->imm_string); ++i) { - ast_delete(parser->imm_string[i]); - } - for (i = 0; i < vec_size(parser->imm_float); ++i) { - ast_delete(parser->imm_float[i]); - } for (i = 0; i < vec_size(parser->fields); ++i) { ast_delete(parser->fields[i]); } @@ -6330,10 +5959,6 @@ static void parser_remove_ast(parser_t *parser) } vec_free(parser->accessors); 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); @@ -6350,7 +5975,6 @@ static void parser_remove_ast(parser_t *parser) vec_free(parser->correct_variables); vec_free(parser->correct_variables_score); - for (i = 0; i < vec_size(parser->_typedefs); ++i) ast_delete(parser->_typedefs[i]); vec_free(parser->_typedefs); @@ -6372,15 +5996,17 @@ static void parser_remove_ast(parser_t *parser) ast_value_delete(parser->const_vec[1]); ast_value_delete(parser->const_vec[2]); + if (parser->reserved_version) + ast_value_delete(parser->reserved_version); + util_htdel(parser->aliases); intrin_intrinsics_destroy(parser); + fold_cleanup(parser->fold); } void parser_cleanup(parser_t *parser) { parser_remove_ast(parser); - code_cleanup(parser->code); - mem_d(parser); } @@ -6467,27 +6093,9 @@ bool parser_finish(parser_t *parser, const char *output) } } /* Now we can generate immediates */ - for (i = 0; i < vec_size(parser->imm_float); ++i) { - if (!ast_global_codegen(parser->imm_float[i], ir, false)) { - con_out("failed to generate global %s\n", parser->imm_float[i]->name); - ir_builder_delete(ir); - return false; - } - } - for (i = 0; i < vec_size(parser->imm_string); ++i) { - if (!ast_global_codegen(parser->imm_string[i], ir, false)) { - con_out("failed to generate global %s\n", parser->imm_string[i]->name); - ir_builder_delete(ir); - return false; - } - } - for (i = 0; i < vec_size(parser->imm_vector); ++i) { - if (!ast_global_codegen(parser->imm_vector[i], ir, false)) { - con_out("failed to generate global %s\n", parser->imm_vector[i]->name); - ir_builder_delete(ir); - return false; - } - } + if (!fold_generate(parser->fold, ir)) + return false; + for (i = 0; i < vec_size(parser->globals); ++i) { ast_value *asvalue; if (!ast_istype(parser->globals[i], ast_value)) @@ -6538,7 +6146,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) { @@ -6560,7 +6169,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;