X-Git-Url: https://git.xonotic.org/?a=blobdiff_plain;f=parser.c;h=598202dcba7bf45699bfc34a53e13302d0bc445c;hb=68e4a937f25a7d083c08114693c4622376d97bdf;hp=fcad9b4a857764a86c530785029ca799394f52b0;hpb=d81ef812460c6823a8b0664f6f101752fb8025e2;p=xonotic%2Fgmqcc.git diff --git a/parser.c b/parser.c index fcad9b4..598202d 100644 --- a/parser.c +++ b/parser.c @@ -60,8 +60,6 @@ void parseerror(parser_t *parser, const char *fmt, ...) va_start(ap, fmt); vprintmsg(LVL_ERROR, parser->lex->tok->ctx.file, parser->lex->tok->ctx.line, "parse error", fmt, ap); va_end(ap); - - printf("\n"); } /* returns true if it counts as an error */ @@ -73,7 +71,7 @@ bool GMQCC_WARN parsewarning(parser_t *parser, int warntype, const char *fmt, .. if (!OPTS_WARN(warntype)) return false; - if (OPTS_WARN(WARN_ERROR)) { + if (opts_werror) { parser->errors++; lvl = LVL_ERROR; } @@ -82,7 +80,7 @@ bool GMQCC_WARN parsewarning(parser_t *parser, int warntype, const char *fmt, .. vprintmsg(lvl, parser->lex->tok->ctx.file, parser->lex->tok->ctx.line, "warning", fmt, ap); va_end(ap); - return OPTS_WARN(WARN_ERROR); + return opts_werror; } /********************************************************************** @@ -171,6 +169,17 @@ ast_value* parser_const_float_0(parser_t *parser) return parser->imm_float_zero; } +char *parser_strdup(const char *str) +{ + if (str && !*str) { + /* actually dup empty strings */ + char *out = mem_a(1); + *out = 0; + return out; + } + return util_strdup(str); +} + ast_value* parser_const_string(parser_t *parser, const char *str) { size_t i; @@ -181,7 +190,7 @@ ast_value* parser_const_string(parser_t *parser, const char *str) } out = ast_value_new(parser_ctx(parser), "#IMMEDIATE", TYPE_STRING); out->isconst = true; - out->constval.vstring = util_strdup(str); + out->constval.vstring = parser_strdup(str); if (!parser_t_imm_string_add(parser, out)) { ast_value_delete(out); return NULL; @@ -481,10 +490,11 @@ static bool parser_sy_pop(parser_t *parser, shunt *sy) (CanConstFold1(A) && CanConstFold1(B)) #define ConstV(i) (asvalue[(i)]->constval.vvec) #define ConstF(i) (asvalue[(i)]->constval.vfloat) +#define ConstS(i) (asvalue[(i)]->constval.vstring) switch (op->id) { default: - parseerror(parser, "internal error: unhandled operator"); + parseerror(parser, "internal error: unhandled operator: %s (%i)", op->op, (int)op->id); return false; case opid1('.'): @@ -549,6 +559,41 @@ static bool parser_sy_pop(parser_t *parser, shunt *sy) } break; + case opid2('!','P'): + switch (exprs[0]->expression.vtype) { + case TYPE_FLOAT: + if (CanConstFold1(exprs[0])) + out = (ast_expression*)parser_const_float(parser, !ConstF(0)); + else + out = (ast_expression*)ast_unary_new(ctx, INSTR_NOT_F, exprs[0]); + break; + case TYPE_VECTOR: + if (CanConstFold1(exprs[0])) + out = (ast_expression*)parser_const_float(parser, + (!ConstV(0).x && !ConstV(0).y && !ConstV(0).z)); + else + out = (ast_expression*)ast_unary_new(ctx, INSTR_NOT_V, exprs[0]); + break; + case TYPE_STRING: + if (CanConstFold1(exprs[0])) + out = (ast_expression*)parser_const_float(parser, !ConstS(0) || !*ConstS(0)); + else + out = (ast_expression*)ast_unary_new(ctx, INSTR_NOT_S, exprs[0]); + break; + /* we don't constant-fold NOT for these types */ + case TYPE_ENTITY: + out = (ast_expression*)ast_unary_new(ctx, INSTR_NOT_ENT, exprs[0]); + break; + case TYPE_FUNCTION: + out = (ast_expression*)ast_unary_new(ctx, INSTR_NOT_FNC, exprs[0]); + break; + default: + parseerror(parser, "invalid types used in expression: cannot logically negate type %s", + type_name[exprs[0]->expression.vtype]); + return false; + } + break; + case opid1('+'): if (exprs[0]->expression.vtype != exprs[1]->expression.vtype || (exprs[0]->expression.vtype != TYPE_VECTOR && exprs[0]->expression.vtype != TYPE_FLOAT) ) @@ -874,7 +919,7 @@ static bool parser_close_call(parser_t *parser, shunt *sy) sy->out[fid] = syexp(call->expression.node.context, (ast_expression*)call); if (fun->expression.vtype != TYPE_FUNCTION) { - parseerror(parser, "not a function"); + parseerror(parser, "not a function (%s)", type_name[fun->expression.vtype]); return false; } @@ -965,8 +1010,12 @@ static ast_expression* parser_expression_leave(parser_t *parser, bool stopatcomm /* variable */ if (opts_standard == COMPILER_GMQCC) { - if (parser->memberof == TYPE_ENTITY) - var = parser_find_field(parser, parser_tokval(parser)); + if (parser->memberof == TYPE_ENTITY) { + /* still get vars first since there could be a fieldpointer */ + var = parser_find_var(parser, parser_tokval(parser)); + if (!var) + var = parser_find_field(parser, parser_tokval(parser)); + } else if (parser->memberof == TYPE_VECTOR) { parseerror(parser, "TODO: implement effective vector member access"); @@ -1061,23 +1110,8 @@ static ast_expression* parser_expression_leave(parser_t *parser, bool stopatcomm parser_token(parser)->constval.v.z)); } else if (parser->tok == '(') { - if (wantop) { - DEBUGSHUNTDO(printf("push (\n")); - ++parens; - /* we expected an operator, this is the function-call operator */ - if (!shunt_ops_add(&sy, syparen(parser_ctx(parser), 'f', sy.out_count-1))) { - parseerror(parser, "out of memory"); - goto onerr; - } - } else { - ++parens; - if (!shunt_ops_add(&sy, syparen(parser_ctx(parser), 1, 0))) { - parseerror(parser, "out of memory"); - goto onerr; - } - DEBUGSHUNTDO(printf("push (\n")); - } - wantop = false; + parseerror(parser, "internal error: '(' should be classified as operator"); + goto onerr; } else if (parser->tok == ')') { if (wantop) { @@ -1122,7 +1156,6 @@ static ast_expression* parser_expression_leave(parser_t *parser, bool stopatcomm break; } } - wantop = false; if (o == operator_count) { /* no operator found... must be the end of the statement */ break; @@ -1167,9 +1200,30 @@ static ast_expression* parser_expression_leave(parser_t *parser, bool stopatcomm olast = NULL; } - DEBUGSHUNTDO(printf("push operator %s\n", op->op)); - if (!shunt_ops_add(&sy, syop(parser_ctx(parser), op))) - goto onerr; + if (op->id == opid1('(')) { + if (wantop) { + DEBUGSHUNTDO(printf("push (\n")); + ++parens; + /* we expected an operator, this is the function-call operator */ + if (!shunt_ops_add(&sy, syparen(parser_ctx(parser), 'f', sy.out_count-1))) { + parseerror(parser, "out of memory"); + goto onerr; + } + } else { + ++parens; + if (!shunt_ops_add(&sy, syparen(parser_ctx(parser), 1, 0))) { + parseerror(parser, "out of memory"); + goto onerr; + } + DEBUGSHUNTDO(printf("push (\n")); + } + wantop = false; + } else { + DEBUGSHUNTDO(printf("push operator %s\n", op->op)); + if (!shunt_ops_add(&sy, syop(parser_ctx(parser), op))) + goto onerr; + wantop = false; + } } if (!parser_next(parser)) { goto onerr; @@ -1834,6 +1888,18 @@ static bool parser_variable(parser_t *parser, ast_block *localblock) (void)!parser_t_locals_add(parser, vx); (void)!parser_t_locals_add(parser, vy); (void)!parser_t_locals_add(parser, vz); + if (!ast_block_locals_add(localblock, var) || + !ast_block_collect_add(localblock, vx.var) || + !ast_block_collect_add(localblock, vy.var) || + !ast_block_collect_add(localblock, vz.var)) + { + parser_pop_local(parser); + parser_pop_local(parser); + parser_pop_local(parser); + parser_pop_local(parser); + ast_value_delete(var); + return false; + } } } else @@ -1844,12 +1910,12 @@ static bool parser_variable(parser_t *parser, ast_block *localblock) ast_value_delete(var); return false; } - } - if (localblock && !ast_block_locals_add(localblock, var)) - { - parser_pop_local(parser); - ast_value_delete(var); - return false; + if (localblock && !ast_block_locals_add(localblock, var)) + { + parser_pop_local(parser); + ast_value_delete(var); + return false; + } } if (!parser_next(parser)) { @@ -2120,6 +2186,13 @@ nextfield: return true; } + else if (parser->tok == '$') + { + if (!parser_next(parser)) { + parseerror(parser, "parse error"); + return false; + } + } else { parseerror(parser, "unexpected token: %s", parser->lex->tok->value); @@ -2187,11 +2260,21 @@ void parser_cleanup() for (i = 0; i < parser->imm_float_count; ++i) { ast_delete(parser->imm_float[i]); } + for (i = 0; i < parser->fields_count; ++i) { + ast_delete(parser->fields[i].var); + mem_d(parser->fields[i].name); + } for (i = 0; i < parser->globals_count; ++i) { ast_delete(parser->globals[i].var); mem_d(parser->globals[i].name); } + MEM_VECTOR_CLEAR(parser, functions); + MEM_VECTOR_CLEAR(parser, imm_vector); + MEM_VECTOR_CLEAR(parser, imm_string); + MEM_VECTOR_CLEAR(parser, imm_float); MEM_VECTOR_CLEAR(parser, globals); + MEM_VECTOR_CLEAR(parser, fields); + MEM_VECTOR_CLEAR(parser, locals); mem_d(parser); }