X-Git-Url: https://git.xonotic.org/?a=blobdiff_plain;f=parser.c;h=9ed80431364fc6b04692362effdad2bfd265dfcf;hb=fc57fa406438ce41ddaff4a6d8b80f65e99b03c2;hp=bfa7105151428ab0167296976150e6b9f8cf351c;hpb=fa5ad1212eb2cac046ff66dffb472cec9b024b9f;p=xonotic%2Fgmqcc.git diff --git a/parser.c b/parser.c index bfa7105..9ed8043 100644 --- a/parser.c +++ b/parser.c @@ -29,8 +29,6 @@ #define PARSER_HT_SIZE 512 #define TYPEDEF_HT_SIZE 512 -static ast_expression * const intrinsic_debug_typestring = (ast_expression*)0x1; - static void parser_enterblock(parser_t *parser); static bool parser_leaveblock(parser_t *parser); static void parser_addlocal(parser_t *parser, const char *name, ast_expression *e); @@ -111,7 +109,7 @@ static ast_expression* parser_find_label(parser_t *parser, const char *name) return NULL; } -static ast_expression* parser_find_global(parser_t *parser, const char *name) +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) @@ -173,9 +171,6 @@ 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 */ @@ -353,11 +348,6 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) #define NotSameType(T) \ (exprs[0]->vtype != exprs[1]->vtype || \ exprs[0]->vtype != T) - - /* preform any constant folding on operator usage first */ - /*if ((out = fold_op(parser->fold, op, exprs)))*/ - /*goto complete;*/ - switch (op->id) { default: @@ -504,7 +494,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) 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", type_name[exprs[0]->vtype], @@ -587,6 +577,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) } } break; + case opid1('/'): if (exprs[1]->vtype != TYPE_FLOAT) { ast_type_to_string(exprs[0], ty1, sizeof(ty1)); @@ -595,12 +586,9 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) return false; } if (!(out = fold_op(parser->fold, op, exprs))) { - if (exprs[0]->vtype == TYPE_FLOAT) + 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) - out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_VF, exprs[0], out); - else /* TODO stot */ - { + 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 types %s and %s", ty1, ty2); @@ -617,7 +605,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) return false; } else if (!(out = fold_op(parser->fold, op, exprs))) { /* generate a call to __builtin_mod */ - ast_expression *mod = intrin_func(parser, "mod"); + ast_expression *mod = intrin_func(parser->intrin, "mod"); ast_call *call = NULL; if (!mod) return false; /* can return null for missing floor */ @@ -635,55 +623,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) 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]->vtype], - type_name[exprs[1]->vtype]); - return false; - } - 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('^'): - /* - * 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 ( !(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)) @@ -700,46 +640,26 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) * since scalar ^ vector is not allowed. */ if (exprs[0]->vtype == TYPE_FLOAT) { - ast_binary *expr = ast_binary_new( - ctx, - INSTR_SUB_F, - (ast_expression*)parser->fold->imm_float[2], - (ast_expression*)ast_binary_new( - ctx, - INSTR_BITAND, - exprs[0], - exprs[1] - ) - ); - expr->refs = AST_REF_NONE; - - out = (ast_expression*) - ast_binary_new( - ctx, - INSTR_BITAND, - (ast_expression*)ast_binary_new( - ctx, - INSTR_BITOR, - exprs[0], - exprs[1] - ), - (ast_expression*)expr - ); + out = (ast_expression*)ast_binary_new(ctx, + (op->id == opid1('^') ? VINSTR_BITXOR : op->id == opid1('|') ? INSTR_BITOR : INSTR_BITAND), + exprs[0], exprs[1]); } else { /* - * The first is a vector: vector is allowed to xor with vector and + * The first is a vector: vector is allowed to bitop 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 + * Bitop 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; + out = (ast_expression*)ast_binary_new(ctx, + (op->id == opid1('^') ? VINSTR_BITXOR_V : op->id == opid1('|') ? VINSTR_BITOR_V : VINSTR_BITAND_V), + exprs[0], exprs[1]); } else { - compile_error(ast_ctx(exprs[0]), "Not Yet Implemented: bit-xor for vector against float"); - return false; + out = (ast_expression*)ast_binary_new(ctx, + (op->id == opid1('^') ? VINSTR_BITXOR_VF : op->id == opid1('|') ? VINSTR_BITOR_VF : VINSTR_BITAND_VF), + exprs[0], exprs[1]); } } } @@ -753,18 +673,19 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) compile_error(ast_ctx(exprs[0]), "Not Yet Implemented: bit-shifts"); return false; } + break; case opid2('|','|'): generated_op += 1; /* INSTR_OR */ case opid2('&','&'): generated_op += INSTR_AND; - 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)); - compile_error(ctx, "invalid types for logical operation with -fperl-logic: %s and %s", ty1, ty2); - return false; - } 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)); + compile_error(ctx, "invalid types for logical operation with -fperl-logic: %s and %s", ty1, ty2); + return false; + } for (i = 0; i < 2; ++i) { if (OPTS_FLAG(CORRECT_LOGIC) && exprs[i]->vtype == TYPE_VECTOR) { out = (ast_expression*)ast_unary_new(ctx, INSTR_NOT_V, exprs[i]); @@ -816,8 +737,10 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) compile_error(ctx, "invalid types used in exponentiation: %s and %s", ty1, ty2); return false; - } else if (!(out = fold_op(parser->fold, op, exprs))) { - ast_call *gencall = ast_call_new(parser_ctx(parser), intrin_func(parser, "pow")); + } + + if (!(out = fold_op(parser->fold, op, exprs))) { + ast_call *gencall = ast_call_new(parser_ctx(parser), intrin_func(parser->intrin, "pow")); vec_push(gencall->params, exprs[0]); vec_push(gencall->params, exprs[1]); out = (ast_expression*)gencall; @@ -832,7 +755,9 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) ty1, ty2); return false; - } else if (!(out = fold_op(parser->fold, op, exprs))) { + } + + 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_REF_NONE; @@ -1103,7 +1028,8 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) break; case opid2('&','='): case opid2('|','='): - if (NotSameType(TYPE_FLOAT)) { + case opid2('^','='): + if (NotSameType(TYPE_FLOAT) && NotSameType(TYPE_VECTOR)) { 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: %s and %s", @@ -1117,16 +1043,21 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) assignop = type_storep_instr[exprs[0]->vtype]; else 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]); + if (exprs[0]->vtype == TYPE_FLOAT) + out = (ast_expression*)ast_binstore_new(ctx, assignop, + (op->id == opid2('^','=') ? VINSTR_BITXOR : op->id == opid2('&','=') ? INSTR_BITAND : INSTR_BITOR), + exprs[0], exprs[1]); + else + out = (ast_expression*)ast_binstore_new(ctx, assignop, + (op->id == opid2('^','=') ? VINSTR_BITXOR_V : op->id == opid2('&','=') ? VINSTR_BITAND_V : VINSTR_BITOR_V), + exprs[0], exprs[1]); break; case opid3('&','~','='): /* This is like: a &= ~(b); * But QC has no bitwise-not, so we implement it as * a -= a & (b); */ - if (NotSameType(TYPE_FLOAT)) { + if (NotSameType(TYPE_FLOAT) && NotSameType(TYPE_VECTOR)) { 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: %s and %s", @@ -1137,29 +1068,39 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) assignop = type_storep_instr[exprs[0]->vtype]; else assignop = type_store_instr[exprs[0]->vtype]; - out = (ast_expression*)ast_binary_new(ctx, INSTR_BITAND, exprs[0], exprs[1]); + if (exprs[0]->vtype == TYPE_FLOAT) + out = (ast_expression*)ast_binary_new(ctx, INSTR_BITAND, exprs[0], exprs[1]); + else + out = (ast_expression*)ast_binary_new(ctx, VINSTR_BITAND_V, exprs[0], exprs[1]); if (!out) return false; if (ast_istype(exprs[0], ast_value) && asvalue[0]->cvq == CV_CONST) { compile_error(ctx, "assignment to constant `%s`", asvalue[0]->name); } - asbinstore = ast_binstore_new(ctx, assignop, INSTR_SUB_F, exprs[0], out); + if (exprs[0]->vtype == TYPE_FLOAT) + asbinstore = ast_binstore_new(ctx, assignop, INSTR_SUB_F, exprs[0], out); + else + asbinstore = ast_binstore_new(ctx, assignop, INSTR_SUB_V, exprs[0], out); asbinstore->keep_dest = true; out = (ast_expression*)asbinstore; break; case opid2('~', 'P'): - if (exprs[0]->vtype != TYPE_FLOAT) { + if (exprs[0]->vtype != TYPE_FLOAT && exprs[0]->vtype != TYPE_VECTOR) { ast_type_to_string(exprs[0], ty1, sizeof(ty1)); compile_error(ast_ctx(exprs[0]), "invalid type for bit not: %s", ty1); return false; } - if (!(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]); + if (!(out = fold_op(parser->fold, op, exprs))) { + if (exprs[0]->vtype == TYPE_FLOAT) { + out = (ast_expression*)ast_binary_new(ctx, INSTR_SUB_F, (ast_expression*)parser->fold->imm_float[2], exprs[0]); + } else { + out = (ast_expression*)ast_binary_new(ctx, INSTR_SUB_V, (ast_expression*)parser->fold->imm_vector[1], exprs[0]); + } + } break; } #undef NotSameType -/*complete:*/ if (!out) { compile_error(ctx, "failed to apply operator %s", op->op); return false; @@ -1201,9 +1142,11 @@ static bool parser_close_call(parser_t *parser, shunt *sy) return false; } - fun = sy->out[fid].out; - - if (fun == intrinsic_debug_typestring) { + /* + * TODO handle this at the intrinsic level with an ast_intrinsic + * node and codegen. + */ + if ((fun = sy->out[fid].out) == intrin_debug_typestring(parser->intrin)) { char ty[1024]; if (fid+2 != vec_size(sy->out) || vec_last(sy->out).block) @@ -1218,8 +1161,8 @@ static bool parser_close_call(parser_t *parser, shunt *sy) vec_shrinkby(sy->out, 1); return true; } - call = ast_call_new(sy->ops[vec_size(sy->ops)].ctx, fun); + if (!call) return false; @@ -1454,8 +1397,7 @@ static ast_expression* parse_vararg(parser_t *parser) } /* not to be exposed */ -extern bool ftepp_predef_exists(const char *name); - +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) && @@ -1535,9 +1477,7 @@ static bool parse_sya_operand(parser_t *parser, shunt *sy, bool with_labels) /* a_vector.{x,y,z} */ if (!vec_size(sy->ops) || !vec_last(sy->ops).etype || - operators[vec_last(sy->ops).etype-1].id != opid1('.') || - (prev >= intrinsic_debug_typestring && - prev <= intrinsic_debug_typestring)) + operators[vec_last(sy->ops).etype-1].id != opid1('.')) { /* When adding more intrinsics, fix the above condition */ prev = NULL; @@ -1561,16 +1501,13 @@ static bool parse_sya_operand(parser_t *parser, shunt *sy, bool with_labels) if (!var && !strcmp(parser_tokval(parser), "__FUNC__")) var = (ast_expression*)fold_constgen_string(parser->fold, parser->function->name, false); if (!var) { - /* intrinsics */ - if (!strcmp(parser_tokval(parser), "__builtin_debug_typestring")) { - var = (ast_expression*)intrinsic_debug_typestring; - } - /* now we try for the real intrinsic hashtable. If the string + /* + * 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 (!strncmp(parser_tokval(parser), "__builtin_", 10)) { + var = intrin_func(parser->intrin, parser_tokval(parser)); } if (!var) { @@ -3878,7 +3815,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*)fold_constgen_float(parser->fold, 0.1)); + gbl_time, (ast_expression*)fold_constgen_float(parser->fold, 0.1f)); if (!self_frame || !self_nextthink || !self_think || !time_plus_1) { if (self_frame) ast_delete(self_frame); @@ -5441,7 +5378,7 @@ skipvar: parseerror(parser, "error parsing break definition"); break; } - (void)!!parsewarning(parser, WARN_BREAKDEF, "break definition ignored (suggest removing it)"); + (void)!parsewarning(parser, WARN_BREAKDEF, "break definition ignored (suggest removing it)"); } else { parseerror(parser, "missing semicolon or initializer, got: `%s`", parser_tokval(parser)); break; @@ -5877,7 +5814,8 @@ parser_t *parser_create() parser->reserved_version = NULL; } - parser->fold = fold_init(parser); + parser->fold = fold_init (parser); + parser->intrin = intrin_init(parser); return parser; } @@ -5996,8 +5934,8 @@ static void parser_remove_ast(parser_t *parser) ast_value_delete(parser->reserved_version); util_htdel(parser->aliases); - intrin_intrinsics_destroy(parser); fold_cleanup(parser->fold); + intrin_cleanup(parser->intrin); } void parser_cleanup(parser_t *parser)