X-Git-Url: https://git.xonotic.org/?a=blobdiff_plain;f=parser.c;h=681207c192c01d55b74f565856ae537d78b6fdaa;hb=3b923a01836b889579658412f6ce81a918c5da68;hp=73ced3afe7cd82829e50a3a6856341ab5cd565a6;hpb=15141897aebe66883c23ac6a7cb28a3935ecdce8;p=xonotic%2Fgmqcc.git diff --git a/parser.c b/parser.c index 73ced3a..681207c 100644 --- a/parser.c +++ b/parser.c @@ -62,6 +62,7 @@ typedef struct { size_t crc_fields; ast_function *function; + ht aliases; /* All the labels the function defined... * Should they be in ast_function instead? @@ -318,6 +319,9 @@ static ast_expression* parser_find_label(parser_t *parser, const char *name) static 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) + return var; return (ast_expression*)util_htget(parser->htglobals, name); } @@ -671,8 +675,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) return false; } } - if (!ast_block_set_type(blocks[0], exprs[1])) - return false; + ast_block_set_type(blocks[0], exprs[1]); vec_push(sy->out, syblock(ctx, blocks[0])); return true; @@ -1068,6 +1071,49 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) out = (ast_expression*)ast_ternary_new(ctx, exprs[0], exprs[1], exprs[2]); break; + case opid3('<','=','>'): /* -1, 0, or 1 */ + if (NotSameType(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 comparision: %s and %s", + 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 { + ast_binary *eq = ast_binary_new(ctx, INSTR_EQ_F, exprs[0], exprs[1]); + + eq->refs = (ast_binary_ref)false; /* references nothing */ + + /* 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), + /* } else { */ + /* if (eq) { */ + (ast_expression*)ast_ternary_new(ctx, (ast_expression*)eq, + /* out = 0 */ + (ast_expression*)parser_const_float_0(parser), + /* } else { */ + /* out = 1 */ + (ast_expression*)parser_const_float_1(parser) + /* } */ + ) + /* } */ + ); + + } + break; + case opid1('>'): generated_op += 1; /* INSTR_GT */ case opid1('<'): @@ -1372,7 +1418,6 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) else out = (ast_expression*)ast_binary_new(ctx, INSTR_SUB_F, (ast_expression*)parser_const_float_neg1(parser), exprs[0]); break; - } #undef NotSameType @@ -1785,8 +1830,8 @@ 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; } - else - { + + if (!var) { char *correct = NULL; size_t i; @@ -1900,11 +1945,6 @@ static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma if (o == operator_count) { compile_error(parser_ctx(parser), "unknown operator: %s", parser_tokval(parser)); goto onerr; -#if 0 -Are there any expressions which actually end with an operator? - /* no operator found... must be the end of the statement */ - break; -#endif } /* found an operator */ op = &operators[o]; @@ -2896,8 +2936,44 @@ static bool parse_qualifiers(parser_t *parser, bool with_local, int *cvq, bool * return false; } } + else if (!strcmp(parser_tokval(parser), "alias") && !(flags & AST_FLAG_ALIAS)) { + flags |= AST_FLAG_ALIAS; + *message = NULL; + if (!parser_next(parser)) { + parseerror(parser, "parse error in attribute"); + goto argerr; + } + + if (parser->tok == '(') { + if (!parser_next(parser) || parser->tok != TOKEN_STRINGCONST) { + parseerror(parser, "`alias` attribute missing parameter"); + goto argerr; + } + + *message = util_strdup(parser_tokval(parser)); + + if (!parser_next(parser)) { + parseerror(parser, "parse error in attribute"); + goto argerr; + } + if (parser->tok != ')') { + parseerror(parser, "`alias` attribute expected `)` after parameter"); + goto argerr; + } + + if (!parser_next(parser)) { + parseerror(parser, "parse error in attribute"); + goto argerr; + } + } + + if (parser->tok != TOKEN_ATTRIBUTE_CLOSE) { + parseerror(parser, "`alias` attribute expected `]]`"); + goto argerr; + } + } else if (!strcmp(parser_tokval(parser), "deprecated") && !(flags & AST_FLAG_DEPRECATED)) { flags |= AST_FLAG_DEPRECATED; *message = NULL; @@ -3784,6 +3860,11 @@ static bool parse_function_body(parser_t *parser, ast_value *var) has_frame_think = false; old = parser->function; + if (var->expression.flags & AST_FLAG_ALIAS) { + parseerror(parser, "function aliases cannot have bodies"); + return false; + } + if (vec_size(parser->gotos) || vec_size(parser->labels)) { parseerror(parser, "gotos/labels leaking"); return false; @@ -3856,11 +3937,12 @@ static bool parse_function_body(parser_t *parser, ast_value *var) ast_expression *functype = fld_think->expression.next; thinkfunc = ast_value_new(parser_ctx(parser), parser_tokval(parser), functype->expression.vtype); - if (!thinkfunc || !ast_type_adopt(thinkfunc, functype)) { + if (!thinkfunc) { /* || !ast_type_adopt(thinkfunc, functype)*/ ast_unref(framenum); parseerror(parser, "failed to create implicit prototype for `%s`", parser_tokval(parser)); return false; } + ast_type_adopt(thinkfunc, functype); if (!parser_next(parser)) { ast_unref(framenum); @@ -4975,7 +5057,13 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield var->cvq = qualifier; var->expression.flags |= qflags; - if (var->expression.flags & AST_FLAG_DEPRECATED) + + /* + * 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; /* Part 1: @@ -5180,10 +5268,85 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield } } else { - parser_addglobal(parser, var->name, (ast_expression*)var); - if (isvector) { - for (i = 0; i < 3; ++i) { - parser_addglobal(parser, me[i]->name, (ast_expression*)me[i]); + if (!(var->expression.flags & AST_FLAG_ALIAS)) { + parser_addglobal(parser, var->name, (ast_expression*)var); + if (isvector) { + for (i = 0; i < 3; ++i) { + parser_addglobal(parser, me[i]->name, (ast_expression*)me[i]); + } + } + } else { + ast_expression *find = parser_find_global(parser, var->desc); + + if (!find) { + compile_error(parser_ctx(parser), "undeclared variable `%s` for alias `%s`", var->desc, var->name); + return false; + } + + if (var->expression.vtype != find->expression.vtype) { + char ty1[1024]; + char ty2[1024]; + + ast_type_to_string(find, ty1, sizeof(ty1)); + ast_type_to_string((ast_expression*)var, ty2, sizeof(ty2)); + + compile_error(parser_ctx(parser), "incompatible types `%s` and `%s` for alias `%s`", + ty1, ty2, var->name + ); + return false; + } + + /* + * 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), + var->name + ); + + /* generate aliases for vector components */ + if (isvector) { + char *buffer[3]; + + util_asprintf(&buffer[0], "%s_x", var->desc); + util_asprintf(&buffer[1], "%s_y", var->desc); + util_asprintf(&buffer[2], "%s_z", var->desc); + + util_htset(parser->aliases, me[0]->name, parser_find_global(parser, buffer[0])); + util_htset(parser->aliases, me[1]->name, parser_find_global(parser, buffer[1])); + util_htset(parser->aliases, me[2]->name, parser_find_global(parser, buffer[2])); + + mem_d(buffer[0]); + mem_d(buffer[1]); + mem_d(buffer[2]); + + /* + * add to corrector so corrections can work + * even for aliases too. + */ + correct_add ( + vec_last(parser->correct_variables), + &vec_last(parser->correct_variables_score), + me[0]->name + ); + correct_add ( + vec_last(parser->correct_variables), + &vec_last(parser->correct_variables_score), + me[1]->name + ); + correct_add ( + vec_last(parser->correct_variables), + &vec_last(parser->correct_variables_score), + me[2]->name + ); } } } @@ -5681,6 +5844,8 @@ bool parser_init() vec_push(parser->typedefs, util_htnew(TYPEDEF_HT_SIZE)); vec_push(parser->_blocktypedefs, 0); + parser->aliases = util_htnew(PARSER_HT_SIZE); + /* corrector */ vec_push(parser->correct_variables, correct_trie_new()); vec_push(parser->correct_variables_score, NULL); @@ -5831,6 +5996,8 @@ void parser_cleanup() ast_value_delete(parser->const_vec[1]); ast_value_delete(parser->const_vec[2]); + util_htdel(parser->aliases); + mem_d(parser); }