def_t *PR_Expression (int priority) { opcode_t *op, *oldop; def_t *e, *e2; etype_t type_a, type_b, type_c; if (priority == 0) return PR_Term (); e = PR_Expression (priority-1); while (1) { if (priority == 1 && PR_Check ("(") ) return PR_ParseFunctionCall (e); for (op=pr_opcodes ; op->name ; op++) { if (op->priority != priority) continue; if (!PR_Check (op->name)) continue; if ( op->right_associative ) { // if last statement is an indirect, change it to an address of if ( (unsigned)(statements[numstatements-1].op - OP_LOAD_F) < 6 ) { statements[numstatements-1].op = OP_ADDRESS; def_pointer.type->aux_type = e->type; e->type = def_pointer.type; } e2 = PR_Expression (priority); } else e2 = PR_Expression (priority-1); // type check type_a = e->type->type; type_b = e2->type->type; if (op->name[0] == '.')// field access gets type from field { if (e2->type->aux_type) type_c = e2->type->aux_type->type; else type_c = -1; // not a field } else type_c = ev_void; oldop = op; while (type_a != op->type_a->type->type || type_b != op->type_b->type->type || (type_c != ev_void && type_c != op->type_c->type->type) ) { op++; if (!op->name || strcmp (op->name , oldop->name)) PR_ParseError ("type mismatch for %s", oldop->name); } if (type_a == ev_pointer && type_b != e->type->aux_type->type) PR_ParseError ("type mismatch for %s", op->name); if (op->right_associative) e = PR_Statement (op, e2, e); else e = PR_Statement (op, e, e2); if (type_c != ev_void) // field access gets type from field e->type = e2->type->aux_type; break; } if (!op->name) break; // next token isn't at this priority level } return e; }
/* ============== PR_Expression ============== */ def_t *PR_Expression (int priority) { opcode_t *op, *oldop; def_t *e, *e2; etype_t type_a, type_b, type_c; if (priority == 0) return PR_Term (); e = PR_Expression (priority-1); while (1) { if (priority == 1 && PR_Check ("(") ) return PR_ParseFunctionCall (e); for (op=pr_opcodes ; op->name ; op++) { if (op->priority != priority) continue; if (!PR_Check (op->name)) continue; if (op->name[0] == '.') { char *name = PR_ParseName (); if (e->type != &type_entity) PR_ParseError ("left of '.%s' must have entity type", name); e2 = PR_FindDef (name, pr_scope); if (!e2 || e2->type->type != ev_field) PR_ParseError ("'%s' is not a field", name); type_c = e2->type->aux_type->type; // we still allow ".void foo" so need to check if (type_c == ev_void) PR_ParseError ("tried to access a 'void' field"); assert (type_c != ev_pointer && type_c != ev_void); while (type_c != op->type_c) { op++; assert (op->name); } e = PR_Statement (op, e, e2); // field access gets type from field e->type = e2->type->aux_type; break; } if (op->right_associative) { if (e->type->constant) PR_ParseError ("assignment to constant"); // if last statement is an indirect, change it to an address of if ( (unsigned)(statements[numstatements-1].op - OP_LOAD_F) < 6 ) { statements[numstatements-1].op = (unsigned short)OP_ADDRESS; def_pointer.type->aux_type = e->type; e->type = def_pointer.type; } e2 = PR_Expression (priority); } else e2 = PR_Expression (priority-1); // type check type_a = e->type->type; type_b = e2->type->type; oldop = op; while (type_a != op->type_a || type_b != op->type_b ) { op++; if (!op->name || strcmp (op->name , oldop->name)) PR_ParseError ("type mismatch for %s", oldop->name); } if (type_a == ev_pointer && type_b != e->type->aux_type->type) PR_ParseError ("type mismatch for %s", op->name); #if 0 if (e->type->constant && e2->type->constant) { // try to calculate the expression at compile time eval_t result; if (PR_Calc(op - pr_opcodes, (eval_t *)(pr_globals + e->ofs), (eval_t *)(pr_globals + e2->ofs), &result)) { // printf ("line %i: folding %s %s %s into %s\n", pr_source_line, e->name, op->name, e2->name, // PR_ValueString(op->type_c, &val)); type_t *resulttype; switch (op->type_c) { case ev_float: resulttype = &type_const_float; break; //case ev_string: resulttype = &type_const_string; break; case ev_vector: resulttype = &type_const_vector; break; default: assert (false); } e = PR_GetImmediate (resulttype, result); break; } } #endif if (op->right_associative) e = PR_Statement (op, e2, e); else e = PR_Statement (op, e, e2); break; } if (!op->name) break; // next token isn't at this priority level } return e; }