X-Git-Url: https://git.xonotic.org/?p=xonotic%2Fgmqcc.git;a=blobdiff_plain;f=parser.c;h=c1d3fb1d786641ecd3611c3e2f66337b897d968c;hp=a5c039a4c2691a688af8b540256d64a7a651ba34;hb=6009e2b3ea2768b2439010c9a77545bd9137b963;hpb=d8d78f61a76bffb96ff70c410312f1434fd98e5a diff --git a/parser.c b/parser.c index a5c039a..c1d3fb1 100644 --- a/parser.c +++ b/parser.c @@ -35,7 +35,7 @@ #define PARSER_HT_SIZE 128 #define TYPEDEF_HT_SIZE 16 -typedef struct { +typedef struct parser_s { lex_file *lex; int tok; @@ -47,6 +47,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; @@ -121,10 +123,6 @@ static ast_value* parser_create_array_setter_proto(parser_t *parser, ast_value * static ast_value* parser_create_array_getter_proto(parser_t *parser, ast_value *array, const ast_expression *elemtype, const char *funcname); static ast_value *parse_typename(parser_t *parser, ast_value **storebase, ast_value *cached_typedef); -static ast_expression *parser_builtin_pow(parser_t *); -static ast_expression *parser_builtin_exp(parser_t *); -static ast_expression *parser_builtin_mod(parser_t *); - static void parseerror(parser_t *parser, const char *fmt, ...) { va_list ap; @@ -257,12 +255,22 @@ 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 = util_htgeth(parser->ht_imm_string, str, hash)) ) { + if (dotranslate && out->name[0] == '#') { + char name[32]; + snprintf(name, sizeof(name), "dotranslate_%lu", (unsigned long)(parser->translated++)); + ast_value_set_name(out, name); + } + 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++)); @@ -273,6 +281,7 @@ static ast_value* parser_const_string(parser_t *parser, const char *str, bool do out->hasvalue = true; out->constval.vstring = parser_strdup(str); vec_push(parser->imm_string, out); + util_htseth(parser->ht_imm_string, str, hash, out); return out; } @@ -384,6 +393,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 */ @@ -979,7 +991,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) (float)(((qcint)ConstF(0)) % ((qcint)ConstF(1)))); } else { /* generate a call to __builtin_mod */ - ast_expression *mod = parser_builtin_mod(parser); + ast_expression *mod = intrin_func(parser, "mod"); ast_call *call = NULL; if (!mod) return false; /* can return null for missing floor */ @@ -1114,7 +1126,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) 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), parser_builtin_pow(parser)); + 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; @@ -1881,12 +1893,15 @@ static bool parse_sya_operand(parser_t *parser, shunt *sy, bool with_labels) if (!strcmp(parser_tokval(parser), "__builtin_debug_typestring")) { var = (ast_expression*)intrinsic_debug_typestring; } - if (!strcmp(parser_tokval(parser), "__builtin_pow")) - var = parser_builtin_pow(parser); - if (!strcmp(parser_tokval(parser), "__builtin_exp")) - var = parser_builtin_exp(parser); - if (!strcmp(parser_tokval(parser), "__builtin_mod")) - var = parser_builtin_mod(parser); + /* 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 */); + } else { + var = intrin_func(parser, parser_tokval(parser)); + } if (!var) { char *correct = NULL; @@ -3351,254 +3366,6 @@ static bool parse_switch_go(parser_t *parser, ast_block *block, ast_expression * return true; } -ast_expression *parser_builtin_pow(parser_t *parser) { - /* - * float __builtin_pow(float x, float y) { - * float value = 1.0f; - * while (y > 0) { - * while (!(y&1)) { - * y *= 0.25f; - * x *= x; - * } - * y--; - * value *= x; - * } - * return value; - * } - */ - static ast_function *pow_func = NULL; - static ast_value *pow_func_val = NULL; - if (!pow_func) { - ast_value *pow_arguments[2]; - ast_value *pow_value = ast_value_new (parser_ctx(parser), "value", TYPE_FLOAT); - ast_block *pow_body = ast_block_new (parser_ctx(parser)); - ast_block *pow_loop_body = ast_block_new (parser_ctx(parser)); - ast_block *pow_loop_nest_body = ast_block_new (parser_ctx(parser)); - ast_loop *pow_loop = NULL; - ast_loop *pow_loop_nest = NULL; - - pow_arguments[0] = ast_value_new (parser_ctx(parser), "x", TYPE_FLOAT); - pow_arguments[1] = ast_value_new (parser_ctx(parser), "x", TYPE_FLOAT); - pow_func_val = ast_value_new (parser_ctx(parser), "__builtin_pow", TYPE_FUNCTION); - pow_func_val->expression.next = (ast_expression*)ast_value_new(parser_ctx(parser), "", TYPE_FLOAT); - - vec_push(pow_func_val->expression.params, pow_arguments[0]); - vec_push(pow_func_val->expression.params, pow_arguments[1]); - - pow_func = ast_function_new(parser_ctx(parser), "__builtin_pow", pow_func_val); - - /* float value; */ - vec_push(pow_body->locals, pow_value); - /* value = 1.0f; */ - vec_push(pow_body->exprs, - (ast_expression*)ast_store_new( - parser_ctx(parser), - INSTR_STORE_F, - (ast_expression*)pow_value, - (ast_expression*)parser_const_float_1(parser) - ) - ); - - /* y >>= 2 */ - vec_push(pow_loop_nest_body->exprs, - (ast_expression*)ast_binstore_new( - parser_ctx(parser), - INSTR_STORE_F, - INSTR_MUL_F, - (ast_expression*)pow_arguments[1], - (ast_expression*)parser_const_float(parser, 0.25f) - ) - ); - vec_push(pow_loop_nest_body->exprs, - (ast_expression*)ast_binstore_new( - parser_ctx(parser), - INSTR_STORE_F, - INSTR_MUL_F, - (ast_expression*)pow_arguments[0], - (ast_expression*)pow_arguments[0] - ) - ); - - /* while (!(y&1)) */ - pow_loop_nest = ast_loop_new ( - parser_ctx(parser), - NULL, - (ast_expression*)ast_binary_new( - parser_ctx(parser), - INSTR_AND, - (ast_expression*)pow_arguments[1], - (ast_expression*)parser_const_float_1(parser) - ), - true, - NULL, - false, - NULL, - (ast_expression*)pow_loop_nest_body - ); - - vec_push(pow_loop_body->exprs, (ast_expression*)pow_loop_nest); - vec_push(pow_loop_body->exprs, - (ast_expression*)ast_binstore_new( - parser_ctx(parser), - INSTR_STORE_F, - INSTR_SUB_F, - (ast_expression*)pow_arguments[1], - (ast_expression*)parser_const_float_1(parser) - ) - ); - vec_push(pow_loop_body->exprs, - (ast_expression*)ast_binstore_new( - parser_ctx(parser), - INSTR_STORE_F, - INSTR_MUL_F, - (ast_expression*)pow_value, - (ast_expression*)pow_arguments[0] - ) - ); - - /* while (y > 0) { */ - pow_loop = ast_loop_new( - parser_ctx(parser), - NULL, - (ast_expression*)ast_binary_new( - parser_ctx(parser), - INSTR_GT, - (ast_expression*)pow_arguments[1], - (ast_expression*)parser_const_float_0(parser) - ), - false, - NULL, - false, - NULL, - (ast_expression*)pow_loop_body - ); - /* } */ - vec_push(pow_body->exprs, (ast_expression*)pow_loop); - /* return value; */ - vec_push(pow_body->exprs, - (ast_expression*)ast_return_new( - parser_ctx(parser), - (ast_expression*)pow_value - ) - ); - - vec_push(pow_func->blocks, pow_body); - vec_push(parser->globals, (ast_expression*)pow_func_val); - vec_push(parser->functions, pow_func); - } - - return (ast_expression*)pow_func_val; -} - -#ifndef M_E -#define M_E 2.71828182845905 -#endif -static ast_expression *parser_builtin_exp(parser_t *parser) { - /* - * float __builtin_exp(float x) { - * return __builtin_exp(E, x); - * } - */ - static ast_value *exp_func_val = NULL; - - if (!exp_func_val) { - ast_function *exp_func = NULL; - ast_value *arg = ast_value_new (parser_ctx(parser), "x", TYPE_FLOAT); - ast_block *exp_body = ast_block_new (parser_ctx(parser)); - ast_call *exp_call = ast_call_new (parser_ctx(parser), parser_builtin_pow(parser)); - exp_func_val = ast_value_new (parser_ctx(parser), "__builtin_exp", TYPE_FUNCTION); - exp_func_val->expression.next = (ast_expression*)ast_value_new(parser_ctx(parser), "", TYPE_FLOAT); - exp_func = ast_function_new(parser_ctx(parser), "__builtin_exp", exp_func_val); - - vec_push(exp_call->params, (ast_expression*)parser_const_float(parser, M_E)); - vec_push(exp_call->params, (ast_expression*)arg); - - vec_push(exp_body->exprs, - (ast_expression*)ast_return_new( - parser_ctx(parser), - (ast_expression*)exp_call - ) - ); - - vec_push(exp_func_val->expression.params, arg); - vec_push(exp_func->blocks, exp_body); - - vec_push(parser->functions, exp_func); - vec_push(parser->globals, (ast_expression*)exp_func_val); - } - - return (ast_expression*)exp_func_val; -} - -static ast_expression *parser_builtin_mod(parser_t *parser) { - /* - * float __builtin_mod(float x, float y) { - * return x - y * floor(x / y); - * } - */ - static ast_value *mod_func_val = NULL; - static ast_expression *mod_floor = NULL; - - if (!mod_floor) { - if (!(mod_floor = parser_find_global(parser, "floor"))) { - parseerror(parser, - "internal error: no suitable definition found for `floor`" - "(required for `%%` operator and `__builtin_mod` intrinsic)" - ); - return NULL; - } - } - - if (!mod_func_val) { - ast_value *mod_args[2]; - ast_function *mod_func = NULL; - ast_block *mod_body = ast_block_new (parser_ctx(parser)); - ast_call *mod_call = ast_call_new (parser_ctx(parser), mod_floor); - mod_func_val = ast_value_new (parser_ctx(parser), "__builtin_mod", TYPE_FUNCTION); - mod_func_val->expression.next = (ast_expression*)ast_value_new(parser_ctx(parser), "", TYPE_FLOAT); - mod_func = ast_function_new(parser_ctx(parser), "__builtin_mod", mod_func_val); - mod_args[0] = ast_value_new (parser_ctx(parser), "x", TYPE_FLOAT); - mod_args[1] = ast_value_new (parser_ctx(parser), "x", TYPE_FLOAT); - - /* floor(x/y) */ - vec_push(mod_call->params, - (ast_expression*)ast_binary_new( - parser_ctx(parser), - INSTR_DIV_F, - (ast_expression*)mod_args[0], - (ast_expression*)mod_args[1] - ) - ); - - vec_push(mod_body->exprs, - (ast_expression*)ast_return_new( - parser_ctx(parser), - (ast_expression*)ast_binary_new( - parser_ctx(parser), - INSTR_SUB_F, - (ast_expression*)mod_args[0], - (ast_expression*)ast_binary_new( - parser_ctx(parser), - INSTR_MUL_F, - (ast_expression*)mod_args[1], - (ast_expression*)mod_call - ) - ) - ) - ); - - vec_push(mod_func_val->expression.params, mod_args[0]); - vec_push(mod_func_val->expression.params, mod_args[1]); - - vec_push(mod_func->blocks, mod_body); - - vec_push(parser->functions, mod_func); - vec_push(parser->globals, (ast_expression*)mod_func_val); - } - - return (ast_expression*)mod_func_val; -} - /* parse computed goto sides */ static ast_expression *parse_goto_computed(parser_t *parser, ast_expression **side) { ast_expression *on_true; @@ -5037,6 +4804,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]); @@ -6155,16 +5924,15 @@ static void generate_checksum(parser_t *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)); @@ -6177,7 +5945,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)); @@ -6187,6 +5955,8 @@ bool parser_init() 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); @@ -6213,10 +5983,11 @@ bool parser_init() } else { parser->reserved_version = NULL; } - return true; + + return parser; } -bool parser_compile() +bool parser_compile(parser_t *parser) { /* initial lexer/parser state */ parser->lex->flags.noops = true; @@ -6248,27 +6019,27 @@ 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() +void parser_cleanup(parser_t *parser) { size_t i; for (i = 0; i < vec_size(parser->accessors); ++i) { @@ -6298,6 +6069,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); @@ -6339,10 +6111,12 @@ void parser_cleanup() util_htdel(parser->aliases); + intrin_intrinsics_destroy(parser); + mem_d(parser); } -bool parser_finish(const char *output) +bool parser_finish(parser_t *parser, const char *output) { size_t i; ir_builder *ir;