X-Git-Url: https://git.xonotic.org/?p=xonotic%2Fgmqcc.git;a=blobdiff_plain;f=parser.c;h=b3e98823604b553363ff9db41caa7151d1551e51;hp=5340f1a79a095ddce36e75195130f9128a23e17f;hb=160e7cf7eebd7fa173fb739aca00143097a3518b;hpb=f19adcd1b3e7f15ce83d1d43c5acee312c9f56ca diff --git a/parser.c b/parser.c index 5340f1a..b3e9882 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 @@ -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,13 +1893,16 @@ 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; size_t i; @@ -3351,251 +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 % and __builtin_mod)"); - 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; @@ -3957,6 +3727,7 @@ 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; @@ -3971,19 +3742,28 @@ static bool parse_enum(parser_t *parser) /* enumeration attributes (can add more later) */ if (parser->tok == ':') { - if (!parser_next(parser) || parser->tok != TOKEN_IDENT || strcmp(parser_tokval(parser), "flag")) { - parseerror(parser, "expected `flag` after enumeration attribute ':'"); + if (!parser_next(parser) || parser->tok != TOKEN_IDENT){ + parseerror(parser, "expected `flag` or `reverse` for enumeration attribute"); return false; } - if (!parser_next(parser) || parser->tok != '{') { - parseerror(parser, "expected `{` after enum attribute `flag`"); + /* 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; } - /* flagged enumeration start from 1 */ - num = 1; - flag = true; + if (!parser_next(parser) || parser->tok != '{') { + parseerror(parser, "expected `{` after enum attribute "); + return false; + } } while (true) { @@ -4012,7 +3792,6 @@ static bool parse_enum(parser_t *parser) /* 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)) { @@ -4051,6 +3830,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; @@ -5018,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]); @@ -5383,7 +5171,7 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield /* * 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; @@ -5480,7 +5268,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; @@ -5621,13 +5409,13 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield /* * 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), @@ -5653,7 +5441,7 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield /* * add to corrector so corrections can work * even for aliases too. - */ + */ correct_add ( vec_last(parser->correct_variables), &vec_last(parser->correct_variables_score), @@ -6136,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)); @@ -6158,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)); @@ -6168,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); @@ -6194,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; @@ -6229,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) { @@ -6279,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); @@ -6320,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;