X-Git-Url: https://git.xonotic.org/?a=blobdiff_plain;f=parser.c;h=1d9ae74577f9b9063f6d22c6d81da788b406f5c3;hb=b6ab0207b1b18a9a8eebffcfab5c61d7302b027d;hp=509176733ba6d0107eb14eb602fe4d468c09a07a;hpb=42e2102839d900bcc2a7e38ccf951e3b8bc487a9;p=xonotic%2Fgmqcc.git diff --git a/parser.c b/parser.c index 5091767..1d9ae74 100644 --- a/parser.c +++ b/parser.c @@ -20,6 +20,9 @@ typedef struct { MEM_VECTOR_MAKE(ast_value*, imm_string); MEM_VECTOR_MAKE(ast_value*, imm_vector); + ast_value *imm_float_zero; + ast_value *imm_vector_zero; + ast_function *function; MEM_VECTOR_MAKE(varentry_t, locals); size_t blocklocal; @@ -45,8 +48,8 @@ static void parser_pop_local(parser_t *parser); static bool parser_variable(parser_t *parser, ast_block *localblock); static ast_block* parser_parse_block(parser_t *parser); static ast_expression* parser_parse_statement_or_block(parser_t *parser); -static ast_expression* parser_expression_leave(parser_t *parser); -static ast_expression* parser_expression(parser_t *parser); +static ast_expression* parser_expression_leave(parser_t *parser, bool stopatcomma); +static ast_expression* parser_expression(parser_t *parser, bool stopatcomma); void parseerror(parser_t *parser, const char *fmt, ...) { @@ -57,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 */ @@ -70,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; } @@ -79,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; } /********************************************************************** @@ -161,6 +162,24 @@ ast_value* parser_const_float(parser_t *parser, double d) return out; } +ast_value* parser_const_float_0(parser_t *parser) +{ + if (!parser->imm_float_zero) + parser->imm_float_zero = parser_const_float(parser, 0); + 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; @@ -171,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; @@ -197,6 +216,22 @@ ast_value* parser_const_vector(parser_t *parser, vector v) return out; } +ast_value* parser_const_vector_f(parser_t *parser, float x, float y, float z) +{ + vector v; + v.x = x; + v.y = y; + v.z = z; + return parser_const_vector(parser, v); +} + +ast_value* parser_const_vector_0(parser_t *parser) +{ + if (!parser->imm_vector_zero) + parser->imm_vector_zero = parser_const_vector_f(parser, 0, 0, 0); + return parser->imm_vector_zero; +} + ast_expression* parser_find_field(parser_t *parser, const char *name) { size_t i; @@ -226,6 +261,8 @@ ast_expression* parser_find_local(parser_t *parser, const char *name, size_t upt if (!strcmp(parser->locals[i].name, name)) return parser->locals[i].var; } + if (!parser->function) + return NULL; fun = parser->function->vtype; for (i = 0; i < fun->expression.params_count; ++i) { if (!strcmp(fun->expression.params[i]->name, name)) @@ -264,6 +301,8 @@ static ast_value *parser_parse_type(parser_t *parser, int basetype, bool *isfunc *isfunc = true; while (true) { ast_value *param; + ast_value *fld; + bool isfield = false; bool dummy; if (!parser_next(parser)) @@ -272,6 +311,14 @@ static ast_value *parser_parse_type(parser_t *parser, int basetype, bool *isfunc if (parser->tok == ')') break; + if (parser->tok == '.') { + isfield = true; + if (!parser_next(parser)) { + parseerror(parser, "expected field parameter type"); + goto on_error; + } + } + temptype = parser_token(parser)->constval.t; if (!parser_next(parser)) goto on_error; @@ -290,6 +337,12 @@ static ast_value *parser_parse_type(parser_t *parser, int basetype, bool *isfunc goto on_error; } + if (isfield) { + fld = ast_value_new(ctx, param->name, TYPE_FIELD); + fld->expression.next = (ast_expression*)param; + param = fld; + } + if (!paramlist_t_p_add(¶ms, param)) { parseerror(parser, "Out of memory while parsing typename"); goto on_error; @@ -409,7 +462,8 @@ static bool parser_sy_pop(parser_t *parser, shunt *sy) DEBUGSHUNTDO(printf("apply %s\n", op->op)); if (sy->out_count < op->operands) { - parseerror(parser, "internal error: not enough operands: %i", sy->out_count); + parseerror(parser, "internal error: not enough operands: %i (operator %s (%i))", sy->out_count, + op->op, (int)op->id); return false; } @@ -430,15 +484,17 @@ static bool parser_sy_pop(parser_t *parser, shunt *sy) #define NotSameType(T) \ (exprs[0]->expression.vtype != exprs[1]->expression.vtype || \ exprs[0]->expression.vtype != T) -#define CanConstFold(A, B) \ - (ast_istype((A), ast_value) && ast_istype((B), ast_value) && \ - ((ast_value*)(A))->isconst && ((ast_value*)(B))->isconst) +#define CanConstFold1(A) \ + (ast_istype((A), ast_value) && ((ast_value*)(A))->isconst) +#define CanConstFold(A, B) \ + (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 operand"); + parseerror(parser, "internal error: unhandled operator: %s (%i)", op->op, (int)op->id); return false; case opid1('.'): @@ -477,6 +533,67 @@ static bool parser_sy_pop(parser_t *parser, shunt *sy) sy->out[sy->out_count++] = syblock(ctx, blocks[0]); return true; + 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_binary_new(ctx, INSTR_SUB_F, + (ast_expression*)parser_const_float_0(parser), + exprs[0]); + break; + case TYPE_VECTOR: + if (CanConstFold1(exprs[0])) + out = (ast_expression*)parser_const_vector_f(parser, + -ConstV(0).x, -ConstV(0).y, -ConstV(0).z); + else + out = (ast_expression*)ast_binary_new(ctx, INSTR_SUB_V, + (ast_expression*)parser_const_vector_0(parser), + exprs[0]); + break; + default: + parseerror(parser, "invalid types used in expression: cannot negate type %s", + type_name[exprs[0]->expression.vtype]); + return false; + } + 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) ) @@ -802,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; } @@ -845,7 +962,18 @@ static bool parser_close_paren(parser_t *parser, shunt *sy, bool functions_only) return true; } -static ast_expression* parser_expression_leave(parser_t *parser) +static void parser_reclassify_token(parser_t *parser) +{ + size_t i; + for (i = 0; i < operator_count; ++i) { + if (!strcmp(parser_tokval(parser), operators[i].op)) { + parser->tok = TOKEN_OPERATOR; + return; + } + } +} + +static ast_expression* parser_expression_leave(parser_t *parser, bool stopatcomma) { ast_expression *expr = NULL; shunt sy; @@ -860,129 +988,133 @@ static ast_expression* parser_expression_leave(parser_t *parser) MEM_VECTOR_INIT(&sy, out); MEM_VECTOR_INIT(&sy, ops); + parser->lex->flags.noops = false; + + parser_reclassify_token(parser); + while (true) { if (gotmemberof) gotmemberof = false; else parser->memberof = 0; - if (!wantop) + + if (parser->tok == TOKEN_IDENT) { - bool nextwant = true; - if (parser->tok == TOKEN_IDENT) + ast_expression *var; + if (wantop) { + parseerror(parser, "expected operator or end of statement"); + goto onerr; + } + wantop = true; + /* variable */ + if (opts_standard == COMPILER_GMQCC) { - /* variable */ - ast_expression *var; - if (opts_standard == COMPILER_GMQCC) - { - if (parser->memberof == TYPE_ENTITY) - var = parser_find_field(parser, parser_tokval(parser)); - else if (parser->memberof == TYPE_VECTOR) - { - parseerror(parser, "TODO: implement effective vector member access"); - goto onerr; - } - else if (parser->memberof) { - parseerror(parser, "namespace for member not found"); - goto onerr; - } - else - var = parser_find_var(parser, parser_tokval(parser)); - } else { + 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)); } - if (!var) { - parseerror(parser, "unexpected ident: %s", parser_tokval(parser)); + else if (parser->memberof == TYPE_VECTOR) + { + parseerror(parser, "TODO: implement effective vector member access"); goto onerr; } - if (!shunt_out_add(&sy, syexp(parser_ctx(parser), var))) { - parseerror(parser, "out of memory"); + else if (parser->memberof) { + parseerror(parser, "namespace for member not found"); goto onerr; } - DEBUGSHUNTDO(printf("push %s\n", parser_tokval(parser))); + else + var = parser_find_var(parser, parser_tokval(parser)); + } else { + var = parser_find_var(parser, parser_tokval(parser)); + if (!var) + var = parser_find_field(parser, parser_tokval(parser)); } - else if (parser->tok == TOKEN_FLOATCONST) { - ast_value *val = parser_const_float(parser, (parser_token(parser)->constval.f)); - if (!val) - return false; - if (!shunt_out_add(&sy, syexp(parser_ctx(parser), (ast_expression*)val))) { - parseerror(parser, "out of memory"); - goto onerr; - } - DEBUGSHUNTDO(printf("push %g\n", parser_token(parser)->constval.f)); + if (!var) { + parseerror(parser, "unexpected ident: %s", parser_tokval(parser)); + goto onerr; } - else if (parser->tok == TOKEN_INTCONST) { - ast_value *val = parser_const_float(parser, (double)(parser_token(parser)->constval.i)); - if (!val) - return false; - if (!shunt_out_add(&sy, syexp(parser_ctx(parser), (ast_expression*)val))) { - parseerror(parser, "out of memory"); - goto onerr; - } - DEBUGSHUNTDO(printf("push %i\n", parser_token(parser)->constval.i)); + if (!shunt_out_add(&sy, syexp(parser_ctx(parser), var))) { + parseerror(parser, "out of memory"); + goto onerr; } - else if (parser->tok == TOKEN_STRINGCONST) { - ast_value *val = parser_const_string(parser, parser_tokval(parser)); - if (!val) - return false; - if (!shunt_out_add(&sy, syexp(parser_ctx(parser), (ast_expression*)val))) { - parseerror(parser, "out of memory"); - goto onerr; - } - DEBUGSHUNTDO(printf("push string\n")); + DEBUGSHUNTDO(printf("push %s\n", parser_tokval(parser))); + } + else if (parser->tok == TOKEN_FLOATCONST) { + ast_value *val; + if (wantop) { + parseerror(parser, "expected operator or end of statement, got constant"); + goto onerr; } - else if (parser->tok == TOKEN_VECTORCONST) { - ast_value *val = parser_const_vector(parser, parser_token(parser)->constval.v); - if (!val) - return false; - if (!shunt_out_add(&sy, syexp(parser_ctx(parser), (ast_expression*)val))) { - parseerror(parser, "out of memory"); - goto onerr; - } - DEBUGSHUNTDO(printf("push '%g %g %g'\n", - parser_token(parser)->constval.v.x, - parser_token(parser)->constval.v.y, - parser_token(parser)->constval.v.z)); - } - else if (parser->tok == '(') { - ++parens; - nextwant = false; /* not expecting an operator next */ - if (!shunt_ops_add(&sy, syparen(parser_ctx(parser), 1, 0))) { - parseerror(parser, "out of memory"); - goto onerr; - } - DEBUGSHUNTDO(printf("push (\n")); + wantop = true; + val = parser_const_float(parser, (parser_token(parser)->constval.f)); + if (!val) + return false; + if (!shunt_out_add(&sy, syexp(parser_ctx(parser), (ast_expression*)val))) { + parseerror(parser, "out of memory"); + goto onerr; } - else if (parser->tok == ')') { - DEBUGSHUNTDO(printf("do[nop] )\n")); - --parens; - if (parens < 0) - break; - /* allowed for function calls */ - if (!parser_close_paren(parser, &sy, true)) - goto onerr; + DEBUGSHUNTDO(printf("push %g\n", parser_token(parser)->constval.f)); + } + else if (parser->tok == TOKEN_INTCONST) { + ast_value *val; + if (wantop) { + parseerror(parser, "expected operator or end of statement, got constant"); + goto onerr; } - else { - /* TODO: prefix operators */ - parseerror(parser, "expected statement"); + wantop = true; + val = parser_const_float(parser, (double)(parser_token(parser)->constval.i)); + if (!val) + return false; + if (!shunt_out_add(&sy, syexp(parser_ctx(parser), (ast_expression*)val))) { + parseerror(parser, "out of memory"); goto onerr; } - wantop = nextwant; - parser->lex->flags.noops = !wantop; - } else { - bool nextwant = false; - if (parser->tok == '(') { - 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; - } + DEBUGSHUNTDO(printf("push %i\n", parser_token(parser)->constval.i)); + } + else if (parser->tok == TOKEN_STRINGCONST) { + ast_value *val; + if (wantop) { + parseerror(parser, "expected operator or end of statement, got constant"); + goto onerr; + } + wantop = true; + val = parser_const_string(parser, parser_tokval(parser)); + if (!val) + return false; + if (!shunt_out_add(&sy, syexp(parser_ctx(parser), (ast_expression*)val))) { + parseerror(parser, "out of memory"); + goto onerr; + } + DEBUGSHUNTDO(printf("push string\n")); + } + else if (parser->tok == TOKEN_VECTORCONST) { + ast_value *val; + if (wantop) { + parseerror(parser, "expected operator or end of statement, got constant"); + goto onerr; + } + wantop = true; + val = parser_const_vector(parser, parser_token(parser)->constval.v); + if (!val) + return false; + if (!shunt_out_add(&sy, syexp(parser_ctx(parser), (ast_expression*)val))) { + parseerror(parser, "out of memory"); + goto onerr; } - else if (parser->tok == ')') { + DEBUGSHUNTDO(printf("push '%g %g %g'\n", + parser_token(parser)->constval.v.x, + parser_token(parser)->constval.v.y, + parser_token(parser)->constval.v.z)); + } + else if (parser->tok == '(') { + parseerror(parser, "internal error: '(' should be classified as operator"); + goto onerr; + } + else if (parser->tok == ')') { + if (wantop) { DEBUGSHUNTDO(printf("do[op] )\n")); --parens; if (parens < 0) @@ -991,71 +1123,107 @@ static ast_expression* parser_expression_leave(parser_t *parser) /* closing an opening paren */ if (!parser_close_paren(parser, &sy, false)) goto onerr; - nextwant = true; + } else { + DEBUGSHUNTDO(printf("do[nop] )\n")); + --parens; + if (parens < 0) + break; + /* allowed for function calls */ + if (!parser_close_paren(parser, &sy, true)) + goto onerr; } - else if (parser->tok != TOKEN_OPERATOR) { + wantop = true; + } + else if (parser->tok != TOKEN_OPERATOR) { + if (wantop) { parseerror(parser, "expected operator or end of statement"); goto onerr; } - else { - /* classify the operator */ - /* TODO: suffix operators */ - const oper_info *op; - const oper_info *olast = NULL; - size_t o; - for (o = 0; o < operator_count; ++o) { - if (!(operators[o].flags & OP_PREFIX) && - !(operators[o].flags & OP_SUFFIX) && /* remove this */ - !strcmp(parser_tokval(parser), operators[o].op)) - { - break; - } - } - if (o == operator_count) { - /* no operator found... must be the end of the statement */ + break; + } + else + { + /* classify the operator */ + /* TODO: suffix operators */ + const oper_info *op; + const oper_info *olast = NULL; + size_t o; + for (o = 0; o < operator_count; ++o) { + if ((!(operators[o].flags & OP_PREFIX) == wantop) && + !(operators[o].flags & OP_SUFFIX) && /* remove this */ + !strcmp(parser_tokval(parser), operators[o].op)) + { break; } - /* found an operator */ - op = &operators[o]; - if (op->id == opid1('.')) { - /* for gmqcc standard: open up the namespace of the previous type */ - ast_expression *prevex = sy.out[sy.out_count-1].out; - if (!prevex) { - parseerror(parser, "unexpected member operator"); - goto onerr; - } - if (prevex->expression.vtype == TYPE_ENTITY) - parser->memberof = TYPE_ENTITY; - else if (prevex->expression.vtype == TYPE_VECTOR) - parser->memberof = TYPE_VECTOR; - else { - parseerror(parser, "type error: type has no members"); - goto onerr; - } - gotmemberof = true; + } + if (o == operator_count) { + /* no operator found... must be the end of the statement */ + break; + } + /* found an operator */ + op = &operators[o]; + + /* when declaring variables, a comma starts a new variable */ + if (op->id == opid1(',') && !parens && stopatcomma) + break; + + if (op->id == opid1('.')) { + /* for gmqcc standard: open up the namespace of the previous type */ + ast_expression *prevex = sy.out[sy.out_count-1].out; + if (!prevex) { + parseerror(parser, "unexpected member operator"); + goto onerr; + } + if (prevex->expression.vtype == TYPE_ENTITY) + parser->memberof = TYPE_ENTITY; + else if (prevex->expression.vtype == TYPE_VECTOR) + parser->memberof = TYPE_VECTOR; + else { + parseerror(parser, "type error: type has no members"); + goto onerr; } + gotmemberof = true; + } + if (sy.ops_count && !sy.ops[sy.ops_count-1].paren) + olast = &operators[sy.ops[sy.ops_count-1].etype-1]; + + while (olast && ( + (op->prec < olast->prec) || + (op->assoc == ASSOC_LEFT && op->prec <= olast->prec) ) ) + { + if (!parser_sy_pop(parser, &sy)) + goto onerr; if (sy.ops_count && !sy.ops[sy.ops_count-1].paren) olast = &operators[sy.ops[sy.ops_count-1].etype-1]; + else + olast = NULL; + } - while (olast && ( - (op->prec < olast->prec) || - (op->assoc == ASSOC_LEFT && op->prec <= olast->prec) ) ) - { - if (!parser_sy_pop(parser, &sy)) + 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; - if (sy.ops_count && !sy.ops[sy.ops_count-1].paren) - olast = &operators[sy.ops[sy.ops_count-1].etype-1]; - else - olast = NULL; + } + } 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; } - wantop = nextwant; - parser->lex->flags.noops = !wantop; } if (!parser_next(parser)) { goto onerr; @@ -1078,7 +1246,7 @@ static ast_expression* parser_expression_leave(parser_t *parser) expr = sy.out[0].out; MEM_VECTOR_CLEAR(&sy, out); MEM_VECTOR_CLEAR(&sy, ops); - DEBUGSHUNTDO(printf("shut done\n")); + DEBUGSHUNTDO(printf("shunt done\n")); return expr; onerr: @@ -1088,9 +1256,9 @@ onerr: return NULL; } -static ast_expression* parser_expression(parser_t *parser) +static ast_expression* parser_expression(parser_t *parser, bool stopatcomma) { - ast_expression *e = parser_expression_leave(parser); + ast_expression *e = parser_expression_leave(parser, stopatcomma); if (!e) return NULL; if (!parser_next(parser)) { @@ -1118,7 +1286,7 @@ static bool parser_parse_if(parser_t *parser, ast_block *block, ast_expression * return false; } /* parse the condition */ - cond = parser_expression_leave(parser); + cond = parser_expression_leave(parser, false); if (!cond) return false; /* closing paren */ @@ -1178,7 +1346,7 @@ static bool parser_parse_while(parser_t *parser, ast_block *block, ast_expressio return false; } /* parse the condition */ - cond = parser_expression_leave(parser); + cond = parser_expression_leave(parser, false); if (!cond) return false; /* closing paren */ @@ -1242,7 +1410,7 @@ static bool parser_parse_dowhile(parser_t *parser, ast_block *block, ast_express return false; } /* parse the condition */ - cond = parser_expression_leave(parser); + cond = parser_expression_leave(parser, false); if (!cond) return false; /* closing paren */ @@ -1313,7 +1481,7 @@ static bool parser_parse_for(parser_t *parser, ast_block *block, ast_expression } else if (parser->tok != ';') { - initexpr = parser_expression_leave(parser); + initexpr = parser_expression_leave(parser, false); if (!initexpr) goto onerr; } @@ -1330,7 +1498,7 @@ static bool parser_parse_for(parser_t *parser, ast_block *block, ast_expression /* parse the condition */ if (parser->tok != ';') { - cond = parser_expression_leave(parser); + cond = parser_expression_leave(parser, false); if (!cond) goto onerr; } @@ -1347,7 +1515,7 @@ static bool parser_parse_for(parser_t *parser, ast_block *block, ast_expression /* parse the incrementor */ if (parser->tok != ')') { - increment = parser_expression_leave(parser); + increment = parser_expression_leave(parser, false); if (!increment) goto onerr; } @@ -1431,7 +1599,7 @@ static bool parser_parse_statement(parser_t *parser, ast_block *block, ast_expre } if (parser->tok != ';') { - exp = parser_expression(parser); + exp = parser_expression(parser, false); if (!exp) return false; @@ -1488,7 +1656,7 @@ static bool parser_parse_statement(parser_t *parser, ast_block *block, ast_expre } else { - ast_expression *exp = parser_expression(parser); + ast_expression *exp = parser_expression(parser, false); if (!exp) return false; *out = exp; @@ -1698,12 +1866,12 @@ static bool parser_variable(parser_t *parser, ast_block *localblock) 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 = mem_a(len+3); - vy.name = mem_a(len+3); - vz.name = mem_a(len+3); - strcpy(vx.name, varent.name); - strcpy(vy.name, varent.name); - strcpy(vz.name, varent.name); + 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'; @@ -1720,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(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 @@ -1730,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)) { @@ -1785,6 +1965,9 @@ static bool parser_variable(parser_t *parser, ast_block *localblock) } func->builtin = -parser_token(parser)->constval.i; + + if (!parser_next(parser)) + return false; } else if (parser->tok == '{') { /* function body */ ast_block *block; @@ -1813,11 +1996,21 @@ static bool parser_variable(parser_t *parser, ast_block *localblock) parseerror(parser, "missing semicolon after function body (mandatory with -std=qcc)"); return true; } else { - parseerror(parser, "TODO, const assignment"); - } + ast_expression *cexp; + ast_value *cval; - if (!parser_next(parser)) - return false; + cexp = parser_expression_leave(parser, true); + cval = (ast_value*)cexp; + if (!ast_istype(cval, ast_value) || !cval->isconst) + parseerror(parser, "cannot initialize a global constant variable with a non-constant expression"); + else + { + var->isconst = true; + memcpy(&var->constval, &cval->constval, sizeof(var->constval)); + memset(&cval->constval, 0, sizeof(cval->constval)); + ast_unref(cval); + } + } if (parser->tok == ',') { /* another */ @@ -1825,7 +2018,7 @@ static bool parser_variable(parser_t *parser, ast_block *localblock) } if (parser->tok != ';') { - parseerror(parser, "expected semicolon"); + parseerror(parser, "missing semicolon"); return false; } @@ -1850,6 +2043,7 @@ static bool parser_do(parser_t *parser) { ast_value *var; ast_value *fld; + ast_expression *oldex; bool isfunc = false; int basetype; lex_ctx ctx = parser_ctx(parser); @@ -1894,28 +2088,16 @@ static bool parser_do(parser_t *parser) return false; } } - if (parser_find_field(parser, parser_tokval(parser))) { - parseerror(parser, "field %s already exists", parser_tokval(parser)); - ast_delete(var); - return false; - } - /* if it was a function, turn it into a function */ if (isfunc) { ast_value *fval; - /* turn var into a value of TYPE_FUNCTION, with the old var - * as return type - */ fval = ast_value_new(ctx, var->name, TYPE_FUNCTION); if (!fval) { ast_value_delete(var); - ast_value_delete(fval); return false; } - fval->expression.next = (ast_expression*)var; MEM_VECTOR_MOVE(&var->expression, params, &fval->expression, params); - var = fval; } @@ -1923,6 +2105,38 @@ static bool parser_do(parser_t *parser) fld = ast_value_new(ctx, parser_tokval(parser), TYPE_FIELD); fld->expression.next = (ast_expression*)var; + if ( (oldex = parser_find_field(parser, parser_tokval(parser)))) { + if (ast_istype(oldex, ast_member)) { + parseerror(parser, "cannot declare a field with the same name as a vector component, component %s has been declared here: %s:%i", + parser_tokval(parser), ast_ctx(oldex).file, (int)ast_ctx(oldex).line); + ast_delete(fld); + return false; + } + if (!ast_istype(oldex, ast_value)) { + /* not possible / sanity check */ + parseerror(parser, "internal error: %s is not an ast_value", parser_tokval(parser)); + ast_delete(fld); + return false; + } + + if (!ast_compare_type(oldex, (ast_expression*)fld)) { + parseerror(parser, "field %s has previously been declared with a different type here: %s:%i", + parser_tokval(parser), ast_ctx(oldex).file, (int)ast_ctx(oldex).line); + ast_delete(fld); + return false; + } else { + if (parsewarning(parser, WARN_FIELD_REDECLARED, "field %s has already been declared here: %s:%i", + parser_tokval(parser), ast_ctx(oldex).file, (int)ast_ctx(oldex).line)) + { + ast_delete(fld); + return false; + } + } + + ast_delete(fld); + goto nextfield; + } + varent.var = (ast_expression*)fld; varent.name = util_strdup(fld->name); (void)!parser_t_fields_add(parser, varent); @@ -1937,12 +2151,12 @@ static bool parser_do(parser_t *parser) vx.var = (ast_expression*)ast_member_new(ast_ctx(fld), (ast_expression*)fld, 0); vy.var = (ast_expression*)ast_member_new(ast_ctx(fld), (ast_expression*)fld, 1); vz.var = (ast_expression*)ast_member_new(ast_ctx(fld), (ast_expression*)fld, 2); - vx.name = mem_a(len+3); - vy.name = mem_a(len+3); - vz.name = mem_a(len+3); - strcpy(vx.name, varent.name); - strcpy(vy.name, varent.name); - strcpy(vz.name, varent.name); + 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'; @@ -1953,6 +2167,7 @@ static bool parser_do(parser_t *parser) (void)!parser_t_fields_add(parser, vz); } +nextfield: if (!parser_next(parser)) { parseerror(parser, "expected semicolon or another field name"); return false; @@ -1971,6 +2186,13 @@ static bool parser_do(parser_t *parser) 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); @@ -2038,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); }