X-Git-Url: https://git.xonotic.org/?a=blobdiff_plain;f=parser.c;h=798f2dd9e606d9b73a56628b787b02e0ac6d6d3f;hb=0e3bc87c757c31e4b77010d8f64642aa8656dbf1;hp=62953ce46a49d56f7b7db0fece227bf3dd09cf47;hpb=1a3a0014c51d8110f6d6d9f4c2804221edeb56d5;p=xonotic%2Fgmqcc.git diff --git a/parser.c b/parser.c index 62953ce..798f2dd 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,6 +490,7 @@ 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: @@ -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; } @@ -1065,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) { @@ -1126,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; @@ -1171,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; @@ -1690,10 +1740,14 @@ static bool parser_variable(parser_t *parser, ast_block *localblock) varentry_t varent; ast_expression *olddecl; + bool hadproto; + int basetype = parser_token(parser)->constval.t; while (true) { + hadproto = false; + if (!parser_next(parser)) { /* skip basetype or comma */ parseerror(parser, "expected variable declaration"); return false; @@ -1792,8 +1846,9 @@ static bool parser_variable(parser_t *parser, ast_block *localblock) } ast_function_delete(func); ast_value_delete(fval); - var = proto; - func = var->constval.vfunc; + fval = proto; + func = proto->constval.vfunc; + hadproto = true; } else { @@ -1807,54 +1862,68 @@ static bool parser_variable(parser_t *parser, ast_block *localblock) var = fval; } - varent.name = util_strdup(var->name); - varent.var = (ast_expression*)var; - if (var->expression.vtype == TYPE_VECTOR) - { - size_t len = strlen(varent.name); - varentry_t vx, vy, vz; - vx.var = (ast_expression*)ast_member_new(var->expression.node.context, (ast_expression*)var, 0); - vy.var = (ast_expression*)ast_member_new(var->expression.node.context, (ast_expression*)var, 1); - vz.var = (ast_expression*)ast_member_new(var->expression.node.context, (ast_expression*)var, 2); - vx.name = (char*)mem_a(len+3); - vy.name = (char*)mem_a(len+3); - vz.name = (char*)mem_a(len+3); - memcpy(vx.name, varent.name, len); - memcpy(vy.name, varent.name, len); - memcpy(vz.name, varent.name, len); - vx.name[len] = vy.name[len] = vz.name[len] = '_'; - vx.name[len+1] = 'x'; - vy.name[len+1] = 'y'; - vz.name[len+1] = 'z'; - vx.name[len+2] = vy.name[len+2] = vz.name[len+2] = 0; - - if (!localblock) { - (void)!parser_t_globals_add(parser, varent); - (void)!parser_t_globals_add(parser, vx); - (void)!parser_t_globals_add(parser, vy); - (void)!parser_t_globals_add(parser, vz); - } else { - (void)!parser_t_locals_add(parser, varent); - (void)!parser_t_locals_add(parser, vx); - (void)!parser_t_locals_add(parser, vy); - (void)!parser_t_locals_add(parser, vz); + if (!hadproto) { + varent.name = util_strdup(var->name); + varent.var = (ast_expression*)var; + if (var->expression.vtype == TYPE_VECTOR) + { + size_t len = strlen(varent.name); + varentry_t vx, vy, vz; + vx.var = (ast_expression*)ast_member_new(var->expression.node.context, (ast_expression*)var, 0); + vy.var = (ast_expression*)ast_member_new(var->expression.node.context, (ast_expression*)var, 1); + vz.var = (ast_expression*)ast_member_new(var->expression.node.context, (ast_expression*)var, 2); + vx.name = (char*)mem_a(len+3); + vy.name = (char*)mem_a(len+3); + vz.name = (char*)mem_a(len+3); + memcpy(vx.name, varent.name, len); + memcpy(vy.name, varent.name, len); + memcpy(vz.name, varent.name, len); + vx.name[len] = vy.name[len] = vz.name[len] = '_'; + vx.name[len+1] = 'x'; + vy.name[len+1] = 'y'; + vz.name[len+1] = 'z'; + vx.name[len+2] = vy.name[len+2] = vz.name[len+2] = 0; + + if (!localblock) { + (void)!parser_t_globals_add(parser, varent); + (void)!parser_t_globals_add(parser, vx); + (void)!parser_t_globals_add(parser, vy); + (void)!parser_t_globals_add(parser, vz); + } else { + (void)!parser_t_locals_add(parser, varent); + (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(localblock, vx.var) || + !ast_block_collect(localblock, vy.var) || + !ast_block_collect(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 - { - if ( (!localblock && !parser_t_globals_add(parser, varent)) || - ( localblock && !parser_t_locals_add(parser, varent)) ) + else { - ast_value_delete(var); - return false; + if ( (!localblock && !parser_t_globals_add(parser, varent)) || + ( localblock && !parser_t_locals_add(parser, varent)) ) + { + 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)) { ast_value_delete(var); @@ -1980,6 +2049,7 @@ static bool parser_do(parser_t *parser) else if (parser->tok == '.') { ast_value *var; + ast_value *typevar; ast_value *fld; ast_expression *oldex; bool isfunc = false; @@ -2003,11 +2073,12 @@ static bool parser_do(parser_t *parser) } /* parse the field type fully */ - var = parser_parse_type(parser, basetype, &isfunc); + typevar = var = parser_parse_type(parser, basetype, &isfunc); if (!var) return false; while (true) { + var = ast_value_copy(typevar); /* now the field name */ if (parser->tok != TOKEN_IDENT) { parseerror(parser, "expected field name"); @@ -2117,6 +2188,7 @@ nextfield: return false; } } + ast_delete(typevar); /* skip the semicolon */ if (!parser_next(parser)) @@ -2124,6 +2196,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); @@ -2165,13 +2244,14 @@ bool parser_compile(const char *filename) else if (!parser->errors) parseerror(parser, "parse error\n"); lex_close(parser->lex); - mem_d(parser); + parser->lex = NULL; return false; } } } lex_close(parser->lex); + parser->lex = NULL; return !parser->errors; } @@ -2191,11 +2271,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); }