X-Git-Url: https://de.git.xonotic.org/?a=blobdiff_plain;f=parser.c;h=46c7ff42543131c36899185644f5a59d7196e809;hb=d8890fda9e8234870cd330d968e90ad7d3ee4bcb;hp=94486d62fb38cc648f258f398bae7ad7bb6eb016;hpb=ce082551d8538fea703968d23d68b805ee530132;p=xonotic%2Fgmqcc.git diff --git a/parser.c b/parser.c index 94486d6..46c7ff4 100644 --- a/parser.c +++ b/parser.c @@ -14,6 +14,7 @@ typedef struct { int tok; MEM_VECTOR_MAKE(varentry_t, globals); + MEM_VECTOR_MAKE(varentry_t, fields); MEM_VECTOR_MAKE(ast_function*, functions); MEM_VECTOR_MAKE(ast_value*, imm_float); MEM_VECTOR_MAKE(ast_value*, imm_string); @@ -24,9 +25,16 @@ typedef struct { size_t blocklocal; size_t errors; + + /* TYPE_FIELD -> parser_find_fields is used instead of find_var + * TODO: TYPE_VECTOR -> x, y and z are accepted in the gmqcc standard + * anything else: type error + */ + qcint memberof; } parser_t; MEM_VEC_FUNCTIONS(parser_t, varentry_t, globals) +MEM_VEC_FUNCTIONS(parser_t, varentry_t, fields) MEM_VEC_FUNCTIONS(parser_t, ast_value*, imm_float) MEM_VEC_FUNCTIONS(parser_t, ast_value*, imm_string) MEM_VEC_FUNCTIONS(parser_t, ast_value*, imm_vector) @@ -126,6 +134,16 @@ ast_value* parser_const_vector(parser_t *parser, vector v) return out; } +ast_expression* parser_find_field(parser_t *parser, const char *name) +{ + size_t i; + for (i = 0; i < parser->fields_count; ++i) { + if (!strcmp(parser->fields[i].name, name)) + return parser->fields[i].var; + } + return NULL; +} + ast_expression* parser_find_global(parser_t *parser, const char *name) { size_t i; @@ -295,6 +313,12 @@ static sy_elem syparen(lex_ctx ctx, int p, size_t off) { return e; } +#ifdef DEBUGSHUNT +# define DEBUGSHUNTDO(x) x +#else +# define DEBUGSHUNTDO(x) +#endif + static bool parser_sy_pop(parser_t *parser, shunt *sy) { const oper_info *op; @@ -302,7 +326,8 @@ static bool parser_sy_pop(parser_t *parser, shunt *sy) ast_expression *out = NULL; ast_expression *exprs[3]; ast_block *blocks[3]; - size_t i; + size_t i, assignop; + qcint generated_op = 0; if (!sy->ops_count) { parseerror(parser, "internal error: missing operator"); @@ -317,6 +342,8 @@ static bool parser_sy_pop(parser_t *parser, shunt *sy) op = &operators[sy->ops[sy->ops_count-1].etype - 1]; ctx = sy->ops[sy->ops_count-1].ctx; + DEBUGSHUNTDO(printf("apply %s\n", op->op)); + if (sy->out_count < op->operands) { parseerror(parser, "internal error: not enough operands: %i", sy->out_count); return false; @@ -335,12 +362,33 @@ static bool parser_sy_pop(parser_t *parser, shunt *sy) return false; } +#define NotSameType(T) \ + (exprs[0]->expression.vtype != exprs[1]->expression.vtype || \ + exprs[0]->expression.vtype != T) switch (op->id) { default: parseerror(parser, "internal error: unhandled operand"); return false; + case opid1('.'): + if (exprs[0]->expression.vtype == TYPE_ENTITY) { + if (exprs[1]->expression.vtype != TYPE_FIELD) { + parseerror(parser, "type error: right hand of member-operand should be an entity-field"); + return false; + } + out = (ast_expression*)ast_entfield_new(ctx, exprs[0], exprs[1]); + } + else if (exprs[0]->expression.vtype == TYPE_VECTOR) { + parseerror(parser, "internal error: vector access is not supposed to be handled at this point"); + return false; + } + else { + parseerror(parser, "type error: member-of operator on something that is not an entity or vector"); + return false; + } + break; + case opid1(','): if (blocks[0]) { if (!ast_block_exprs_add(blocks[0], exprs[1])) @@ -366,6 +414,12 @@ static bool parser_sy_pop(parser_t *parser, shunt *sy) type_name[exprs[1]->expression.vtype]); return false; } + if (exprs[0]->expression.vtype != TYPE_VECTOR && exprs[0]->expression.vtype != TYPE_FLOAT) { + parseerror(parser, "type error: %s - %s not defined", + type_name[exprs[0]->expression.vtype], + type_name[exprs[1]->expression.vtype]); + return false; + } switch (exprs[0]->expression.vtype) { case TYPE_FLOAT: out = (ast_expression*)ast_binary_new(ctx, INSTR_ADD_F, exprs[0], exprs[1]); @@ -374,7 +428,7 @@ static bool parser_sy_pop(parser_t *parser, shunt *sy) out = (ast_expression*)ast_binary_new(ctx, INSTR_ADD_V, exprs[0], exprs[1]); break; default: - parseerror(parser, "Cannot add type %s and %s", + parseerror(parser, "type error: cannot add type %s to %s", type_name[exprs[0]->expression.vtype], type_name[exprs[1]->expression.vtype]); return false; @@ -382,11 +436,17 @@ static bool parser_sy_pop(parser_t *parser, shunt *sy) break; case opid1('-'): if (exprs[0]->expression.vtype != exprs[1]->expression.vtype) { - parseerror(parser, "Cannot subtract type %s from %s", + parseerror(parser, "type error: cannot subtract type %s from %s", type_name[exprs[1]->expression.vtype], type_name[exprs[0]->expression.vtype]); return false; } + if (exprs[0]->expression.vtype != TYPE_VECTOR && exprs[0]->expression.vtype != TYPE_FLOAT) { + parseerror(parser, "type error: %s - %s not defined", + type_name[exprs[0]->expression.vtype], + type_name[exprs[1]->expression.vtype]); + return false; + } switch (exprs[0]->expression.vtype) { case TYPE_FLOAT: out = (ast_expression*)ast_binary_new(ctx, INSTR_SUB_F, exprs[0], exprs[1]); @@ -395,7 +455,7 @@ static bool parser_sy_pop(parser_t *parser, shunt *sy) out = (ast_expression*)ast_binary_new(ctx, INSTR_SUB_V, exprs[0], exprs[1]); break; default: - parseerror(parser, "Cannot add type %s from %s", + parseerror(parser, "type error: cannot subtract type %s from %s", type_name[exprs[1]->expression.vtype], type_name[exprs[0]->expression.vtype]); return false; @@ -408,7 +468,7 @@ static bool parser_sy_pop(parser_t *parser, shunt *sy) exprs[1]->expression.vtype != TYPE_VECTOR && exprs[1]->expression.vtype != TYPE_FLOAT) { - parseerror(parser, "Cannot multiply type %s from %s", + parseerror(parser, "type error: cannot multiply type %s by %s", type_name[exprs[1]->expression.vtype], type_name[exprs[0]->expression.vtype]); return false; @@ -427,37 +487,86 @@ static bool parser_sy_pop(parser_t *parser, shunt *sy) out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_V, exprs[0], exprs[1]); break; default: - parseerror(parser, "Cannot add type %s from %s", + parseerror(parser, "type error: cannot multiplye type %s by %s", type_name[exprs[1]->expression.vtype], 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_FLOAT) - { - parseerror(parser, "Cannot divide types %s and %s", + if (NotSameType(TYPE_FLOAT)) { + parseerror(parser, "type error: cannot divide types %s and %s", type_name[exprs[0]->expression.vtype], type_name[exprs[1]->expression.vtype]); return false; } out = (ast_expression*)ast_binary_new(ctx, INSTR_DIV_F, exprs[0], exprs[1]); break; + case opid1('|'): + case opid1('&'): + if (NotSameType(TYPE_FLOAT)) { + parseerror(parser, "type error: cannot perform bit operations on types %s and %s", + type_name[exprs[0]->expression.vtype], + type_name[exprs[1]->expression.vtype]); + return false; + } + out = (ast_expression*)ast_binary_new(ctx, + (op->id == opid1('|') ? INSTR_BITOR : INSTR_BITAND), + exprs[0], exprs[1]); + break; + + case opid1('>'): + generated_op += 1; /* INSTR_GT */ + case opid1('<'): + generated_op += 1; /* INSTR_LT */ + case opid2('>', '='): + generated_op += 1; /* INSTR_GE */ + case opid2('<', '='): + generated_op += INSTR_LE; + if (NotSameType(TYPE_FLOAT)) { + parseerror(parser, "type error: cannot compare types %s and %s", + type_name[exprs[0]->expression.vtype], + type_name[exprs[1]->expression.vtype]); + return false; + } + out = (ast_expression*)ast_binary_new(ctx, generated_op, exprs[0], exprs[1]); + break; + case opid2('!', '='): + if (exprs[0]->expression.vtype != exprs[1]->expression.vtype) { + parseerror(parser, "type error: cannot compare types %s and %s", + type_name[exprs[0]->expression.vtype], + type_name[exprs[1]->expression.vtype]); + return false; + } + out = (ast_expression*)ast_binary_new(ctx, type_ne_op[exprs[0]->expression.vtype], exprs[0], exprs[1]); + break; + case opid2('=', '='): + if (exprs[0]->expression.vtype != exprs[1]->expression.vtype) { + parseerror(parser, "type error: cannot compare types %s and %s", + type_name[exprs[0]->expression.vtype], + type_name[exprs[1]->expression.vtype]); + return false; + } + out = (ast_expression*)ast_binary_new(ctx, type_eq_op[exprs[0]->expression.vtype], exprs[0], exprs[1]); + break; case opid1('='): - out = (ast_expression*)ast_store_new(ctx, - type_store_instr[exprs[0]->expression.vtype], - exprs[0], exprs[1]); + if (ast_istype(exprs[0], ast_entfield)) + assignop = type_storep_instr[exprs[0]->expression.vtype]; + else + assignop = type_store_instr[exprs[0]->expression.vtype]; + out = (ast_expression*)ast_store_new(ctx, assignop, exprs[0], exprs[1]); break; } +#undef NotSameType if (!out) { parseerror(parser, "failed to apply operand %s", op->op); return false; } + DEBUGSHUNTDO(printf("applied %s\n", op->op)); sy->out[sy->out_count++] = syexp(ctx, out); return true; } @@ -571,6 +680,7 @@ static ast_expression* parser_expression(parser_t *parser) ast_expression *expr = NULL; shunt sy; bool wantop = false; + bool gotmemberof = false; /* count the parens because an if starts with one, so the * end of a condition is an unmatched closing paren @@ -582,13 +692,37 @@ static ast_expression* parser_expression(parser_t *parser) while (true) { + if (gotmemberof) + gotmemberof = false; + else + parser->memberof = 0; if (!wantop) { bool nextwant = true; if (parser->tok == TOKEN_IDENT) { /* variable */ - ast_expression *var = parser_find_var(parser, parser_tokval(parser)); + 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 { + 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)); goto onerr; @@ -597,6 +731,7 @@ static ast_expression* parser_expression(parser_t *parser) parseerror(parser, "out of memory"); goto onerr; } + DEBUGSHUNTDO(printf("push %s\n", parser_tokval(parser))); } else if (parser->tok == TOKEN_FLOATCONST) { ast_value *val = parser_const_float(parser, (parser_token(parser)->constval.f)); @@ -606,6 +741,7 @@ static ast_expression* parser_expression(parser_t *parser) parseerror(parser, "out of memory"); goto onerr; } + DEBUGSHUNTDO(printf("push %g\n", parser_token(parser)->constval.f)); } else if (parser->tok == TOKEN_INTCONST) { ast_value *val = parser_const_float(parser, (double)(parser_token(parser)->constval.i)); @@ -615,6 +751,7 @@ static ast_expression* parser_expression(parser_t *parser) 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 = parser_const_string(parser, parser_tokval(parser)); @@ -624,6 +761,7 @@ static ast_expression* parser_expression(parser_t *parser) parseerror(parser, "out of memory"); goto onerr; } + DEBUGSHUNTDO(printf("push string\n")); } else if (parser->tok == TOKEN_VECTORCONST) { ast_value *val = parser_const_vector(parser, parser_token(parser)->constval.v); @@ -633,6 +771,10 @@ static ast_expression* parser_expression(parser_t *parser) 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; @@ -641,8 +783,10 @@ static ast_expression* parser_expression(parser_t *parser) parseerror(parser, "out of memory"); goto onerr; } + DEBUGSHUNTDO(printf("push (\n")); } else if (parser->tok == ')') { + DEBUGSHUNTDO(printf("do[nop] )\n")); --parens; if (parens < 0) break; @@ -658,7 +802,9 @@ static ast_expression* parser_expression(parser_t *parser) 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))) { @@ -667,6 +813,7 @@ static ast_expression* parser_expression(parser_t *parser) } } else if (parser->tok == ')') { + DEBUGSHUNTDO(printf("do[op] )\n")); --parens; if (parens < 0) break; @@ -674,6 +821,7 @@ static ast_expression* parser_expression(parser_t *parser) /* closing an opening paren */ if (!parser_close_paren(parser, &sy, false)) goto onerr; + nextwant = true; } else if (parser->tok != TOKEN_OPERATOR) { parseerror(parser, "expected operator or end of statement"); @@ -699,6 +847,23 @@ static ast_expression* parser_expression(parser_t *parser) } /* 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 (sy.ops_count && !sy.ops[sy.ops_count-1].paren) olast = &operators[sy.ops[sy.ops_count-1].etype-1]; @@ -711,13 +876,16 @@ static ast_expression* parser_expression(parser_t *parser) 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; } + DEBUGSHUNTDO(printf("push operator %s\n", op->op)); if (!shunt_ops_add(&sy, syop(parser_ctx(parser), op))) goto onerr; } - wantop = false; - parser->lex->flags.noops = true; + wantop = nextwant; + parser->lex->flags.noops = !wantop; } if (!parser_next(parser)) { goto onerr; @@ -744,6 +912,7 @@ static ast_expression* parser_expression(parser_t *parser) expr = sy.out[0].out; MEM_VECTOR_CLEAR(&sy, out); MEM_VECTOR_CLEAR(&sy, ops); + DEBUGSHUNTDO(printf("shut done\n")); return expr; onerr: @@ -938,10 +1107,10 @@ static ast_block* parser_parse_block(parser_t *parser) } cleanup: - parser->blocklocal = oldblocklocal; - /* unroll the local vector */ while (parser->locals_count > parser->blocklocal) parser_pop_local(parser); + parser->blocklocal = oldblocklocal; + /* unroll the local vector */ return block; } @@ -1186,8 +1355,103 @@ static bool parser_do(parser_t *parser) } else if (parser->tok == '.') { + ast_value *var; + ast_value *fld; + bool isfunc = false; + int basetype; + lex_ctx ctx = parser_ctx(parser); + varentry_t varent; + /* entity-member declaration */ - return false; + if (!parser_next(parser) || parser->tok != TOKEN_TYPENAME) { + parseerror(parser, "expected member variable definition"); + return false; + } + + /* remember the base/return type */ + basetype = parser_token(parser)->constval.t; + + /* parse into the declaration */ + if (!parser_next(parser)) { + parseerror(parser, "expected field def"); + return false; + } + + /* parse the field type fully */ + var = parser_parse_type(parser, basetype, &isfunc); + if (!var) + return false; + + /* now the field name */ + if (parser->tok != TOKEN_IDENT) { + parseerror(parser, "expected field name"); + ast_delete(var); + return false; + } + + /* check for an existing field + * in original qc we also have to check for an existing + * global named like the field + */ + if (opts_standard == COMPILER_QCC) { + if (parser_find_global(parser, parser_tokval(parser))) { + parseerror(parser, "cannot declare a field and a global of the same name with -std=qcc"); + ast_delete(var); + 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; + } + + /* turn it into a field */ + fld = ast_value_new(ctx, parser_tokval(parser), TYPE_FIELD); + fld->expression.next = (ast_expression*)var; + + varent.var = (ast_expression*)fld; + if (var->expression.vtype == TYPE_VECTOR) + { + /* create _x, _y and _z fields as well */ + parseerror(parser, "TODO: vector field members (_x,_y,_z)"); + ast_delete(fld); + return false; + } + + varent.name = util_strdup(fld->name); + (void)!parser_t_fields_add(parser, varent); + + /* end with a semicolon */ + if (!parser_next(parser) || parser->tok != ';') { + parseerror(parser, "semicolon expected"); + return false; + } + + /* skip the semicolon */ + if (!parser_next(parser)) + return parser->tok == TOKEN_EOF; + + return true; } else { @@ -1302,6 +1566,32 @@ bool parser_finish(const char *output) return false; } } + for (i = 0; i < parser->fields_count; ++i) { + ast_value *field; + bool isconst; + if (!ast_istype(parser->fields[i].var, ast_value)) + continue; + field = (ast_value*)parser->fields[i].var; + isconst = field->isconst; + field->isconst = false; + if (!ast_global_codegen((ast_value*)field, ir)) { + printf("failed to generate field %s\n", field->name); + ir_builder_delete(ir); + return false; + } + if (isconst) { + ir_value *ifld; + ast_expression *subtype; + field->isconst = true; + subtype = field->expression.next; + ifld = ir_builder_create_field(ir, field->name, subtype->expression.vtype); + if (subtype->expression.vtype == TYPE_FIELD) + ifld->fieldtype = subtype->expression.next->expression.vtype; + else if (subtype->expression.vtype == TYPE_FUNCTION) + ifld->outtype = subtype->expression.next->expression.vtype; + (void)!ir_value_set_field(field->ir_v, ifld); + } + } for (i = 0; i < parser->globals_count; ++i) { if (!ast_istype(parser->globals[i].var, ast_value)) continue;