X-Git-Url: https://git.xonotic.org/?p=xonotic%2Fgmqcc.git;a=blobdiff_plain;f=parser.c;h=5d4ea7d0650de50c505d809dd36cab0c7a52cf5c;hp=5340f1a79a095ddce36e75195130f9128a23e17f;hb=21c6079b7a4b17f7110094a94f7fc3c850c295ae;hpb=f19adcd1b3e7f15ce83d1d43c5acee312c9f56ca diff --git a/parser.c b/parser.c index 5340f1a..5d4ea7d 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; @@ -121,10 +121,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; @@ -384,6 +380,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 +978,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 +1113,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 +1880,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,251 +3353,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 +3714,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 +3729,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 +3779,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 +3817,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 +4791,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]); @@ -6136,16 +5911,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 +5932,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)); @@ -6194,10 +5968,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 +6004,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) { @@ -6320,10 +6095,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;