/* ============ PR_ParseFunctionCall ============ */ def_t *PR_ParseFunctionCall (def_t *func) { def_t *e; int arg; type_t *t; t = func->type; if (t->type != ev_function) PR_ParseError ("not a function"); // copy the arguments to the global parameter variables arg = 0; if (!PR_Check(")")) { do { if (t->num_parms != -1 && arg >= t->num_parms) PR_ParseError ("too many parameters"); e = PR_Expression (TOP_PRIORITY); if (arg == 0 && func->name) { // save information for model and sound caching if (!strncmp(func->name,"precache_sound", 14)) PrecacheSound (e, func->name[14]); else if (!strncmp(func->name,"precache_model", 14)) PrecacheModel (e, func->name[14]); else if (!strncmp(func->name,"precache_file", 13)) PrecacheFile (e, func->name[13]); } if (t->num_parms != -1 && ( e->type != t->parm_types[arg] ) ) PR_ParseError ("type mismatch on parm %i", arg); // a vector copy will copy everything def_parms[arg].type = t->parm_types[arg]; PR_Statement (&pr_opcodes[OP_STORE_V], e, &def_parms[arg]); arg++; } while (PR_Check (",")); if (t->num_parms != -1 && arg != t->num_parms) PR_ParseError ("too few parameters"); PR_Expect (")"); } if (arg >8) PR_ParseError ("More than eight parameters"); PR_Statement (&pr_opcodes[OP_CALL0+arg], func, 0); def_ret.type = t->aux_type; return &def_ret; }
/* ============ PR_Term ============ */ def_t *PR_Term (void) { def_t *e, *e2; etype_t t; if (PR_Check ("!")) { e = PR_Expression (NOT_PRIORITY); t = e->type->type; if (t == ev_float) e2 = PR_Statement (&pr_opcodes[OP_NOT_F], e, 0); else if (t == ev_string) e2 = PR_Statement (&pr_opcodes[OP_NOT_S], e, 0); else if (t == ev_entity) e2 = PR_Statement (&pr_opcodes[OP_NOT_ENT], e, 0); else if (t == ev_vector) e2 = PR_Statement (&pr_opcodes[OP_NOT_V], e, 0); else if (t == ev_function) e2 = PR_Statement (&pr_opcodes[OP_NOT_FNC], e, 0); else { e2 = NULL; // shut up compiler warning; PR_ParseError ("type mismatch for !"); } return e2; } if (PR_Check ("(")) { e = PR_Expression (TOP_PRIORITY); PR_Expect (")"); return e; } return PR_ParseValue (); }
/* ============ PR_ParseFunctionCall ============ */ def_t *PR_ParseFunctionCall (def_t *func) { def_t *e; int arg; type_t *t; t = func->type; if (t->type != ev_function) PR_ParseError ("not a function"); // copy the arguments to the global parameter variables arg = 0; if (!PR_Check(")")) { do { if (arg >= t->num_parms || arg >= MAX_PARMS /* works properly with varargs */) PR_ParseError ("too many parameters"); e = PR_Expression (TOP_PRIORITY); if (arg < (t->num_parms & VA_MASK) && !CompareType(e->type, t->parm_types[arg])) PR_ParseError ("type mismatch on parm %i", arg); // a vector copy will copy everything def_parms[arg].type = t->parm_types[arg]; PR_Statement (&pr_opcodes[OP_STORE_V], e, &def_parms[arg]); arg++; } while (PR_Check (",")); if (arg < (t->num_parms & VA_MASK)) PR_ParseError ("too few parameters"); PR_Expect (")"); } if (arg > MAX_PARMS) PR_ParseError ("more than %d parameters", (int)MAX_PARMS); PR_Statement (&pr_opcodes[OP_CALL0+arg], func, 0); def_ret.type = t->aux_type; return &def_ret; }
/* ============ PR_ParseStatement ============ */ void PR_ParseStatement (void) { def_t *e; dstatement_t *patch1, *patch2; if (PR_Check ("{")) { do { PR_ParseStatement (); } while (!PR_Check ("}")); return; } if (PR_Check("return")) { if (PR_Check (";")) { PR_Statement (&pr_opcodes[OP_RETURN], 0, 0); return; } e = PR_Expression (TOP_PRIORITY); PR_Expect (";"); PR_Statement (&pr_opcodes[OP_RETURN], e, 0); return; } if (PR_Check("while")) { PR_Expect ("("); patch2 = &statements[numstatements]; e = PR_Expression (TOP_PRIORITY); PR_Expect (")"); patch1 = &statements[numstatements]; PR_Statement (&pr_opcodes[OP_IFNOT], e, 0); PR_ParseStatement (); junkdef.ofs = patch2 - &statements[numstatements]; PR_Statement (&pr_opcodes[OP_GOTO], &junkdef, 0); patch1->b = &statements[numstatements] - patch1; return; } if (PR_Check("do")) { patch1 = &statements[numstatements]; PR_ParseStatement (); PR_Expect ("while"); PR_Expect ("("); e = PR_Expression (TOP_PRIORITY); PR_Expect (")"); PR_Expect (";"); junkdef.ofs = patch1 - &statements[numstatements]; PR_Statement (&pr_opcodes[OP_IF], e, &junkdef); return; } if (PR_Check("local")) { PR_ParseDefs (); locals_end = numpr_globals; return; } if (PR_Check("if")) { PR_Expect ("("); e = PR_Expression (TOP_PRIORITY); PR_Expect (")"); patch1 = &statements[numstatements]; PR_Statement (&pr_opcodes[OP_IFNOT], e, 0); PR_ParseStatement (); if (PR_Check ("else")) { patch2 = &statements[numstatements]; PR_Statement (&pr_opcodes[OP_GOTO], 0, 0); patch1->b = &statements[numstatements] - patch1; PR_ParseStatement (); patch2->a = &statements[numstatements] - patch2; } else patch1->b = &statements[numstatements] - patch1; return; } PR_Expression (TOP_PRIORITY); PR_Expect (";"); }
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_ParseStatement ============ */ void PR_ParseStatement (void) { def_t *e = NULL; dstatement_t *patch1 = NULL; dstatement_t *patch2 = NULL; if (PR_Check(";")) return; if (PR_Check ("{")) { while (!PR_Check ("}")) PR_ParseStatement (); return; } if (PR_Check("return")) { if (PR_Check (";")) { PR_Statement (&pr_opcodes[OP_RETURN], 0, 0); return; } e = PR_Expression (TOP_PRIORITY); PR_Expect (";"); PR_Statement (&pr_opcodes[OP_RETURN], e, 0); return; } if (PR_Check("while")) { PR_Expect ("("); patch2 = &statements[numstatements]; e = PR_Expression (TOP_PRIORITY); PR_Expect (")"); patch1 = &statements[numstatements]; PR_Statement (&pr_opcodes[OP_IFNOT], e, 0); PR_ParseStatement (); junkdef.ofs = patch2 - &statements[numstatements]; PR_Statement (&pr_opcodes[OP_GOTO], &junkdef, 0); patch1->b = (unsigned short)(&statements[numstatements] - patch1); return; } if (PR_Check("do")) { patch1 = &statements[numstatements]; PR_ParseStatement (); PR_Expect ("while"); PR_Expect ("("); e = PR_Expression (TOP_PRIORITY); PR_Expect (")"); PR_Expect (";"); junkdef.ofs = patch1 - &statements[numstatements]; PR_Statement (&pr_opcodes[OP_IF], e, &junkdef); return; } if ( PR_Check("local") || !strcmp(pr_token, "const") || !strcmp(pr_token, "float") || !strcmp(pr_token, "vector") || !strcmp(pr_token, "entity") || !strcmp(pr_token, "string") || !strcmp(pr_token, "void")) { PR_ParseDefs (); locals_end = numpr_globals; return; } if (PR_Check("if")) { PR_Expect ("("); e = PR_Expression (TOP_PRIORITY); PR_Expect (")"); patch1 = &statements[numstatements]; PR_Statement (&pr_opcodes[OP_IFNOT], e, 0); PR_ParseStatement (); if (PR_Check ("else")) { patch2 = &statements[numstatements]; PR_Statement (&pr_opcodes[OP_GOTO], 0, 0); patch1->b = (unsigned short)(&statements[numstatements] - patch1); PR_ParseStatement (); patch2->a = (unsigned short)(&statements[numstatements] - patch2); } else patch1->b = (unsigned short)(&statements[numstatements] - patch1); return; } if (PR_Check("else")) PR_ParseError ("illegal else without matching if"); PR_Expression (TOP_PRIORITY); PR_Expect (";"); }
/* ============== 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; }
/* ============ PR_Term ============ */ def_t *PR_Term (void) { if (pr_token_type != tt_punct) return PR_ParseValue (); def_t *e, *e2; etype_t t; if (PR_Check ("!")) { e = PR_Expression (NOT_PRIORITY); t = e->type->type; if (t == ev_float) e2 = PR_Statement (&pr_opcodes[OP_NOT_F], e, 0); else if (t == ev_string) e2 = PR_Statement (&pr_opcodes[OP_NOT_S], e, 0); else if (t == ev_entity) e2 = PR_Statement (&pr_opcodes[OP_NOT_ENT], e, 0); else if (t == ev_vector) e2 = PR_Statement (&pr_opcodes[OP_NOT_V], e, 0); else if (t == ev_function) e2 = PR_Statement (&pr_opcodes[OP_NOT_FNC], e, 0); else { PR_ParseError ("type mismatch for !"); return NULL; // shut up compiler } return e2; } if (PR_Check ("(")) { e = PR_Expression (TOP_PRIORITY); PR_Expect (")"); return e; } if (PR_Check("-")) { e = PR_Expression (1 /* FIXME, correct? */); t = e->type->type; if (t == ev_float) { eval_t v; v._float = 0; def_t *imm = PR_GetImmediate (&type_const_float, v); e2 = PR_Statement (&pr_opcodes[OP_SUB_F], imm, e); } else if (t == ev_vector) { eval_t v; v.vector[0] = v.vector[1] = v.vector[2] = 0; def_t *imm = PR_GetImmediate (&type_const_vector, v); e2 = PR_Statement (&pr_opcodes[OP_SUB_V], imm, e); } else { PR_ParseError ("type mismatch for -"); return NULL; // shut up compiler } return e2; } if (PR_Check("+")) { e = PR_Expression (1 /* FIXME, correct? */); t = e->type->type; if (t != ev_float && t != ev_vector) { PR_ParseError ("type mismatch for +"); return NULL; // shut up compiler } return e; } PR_ParseError ("syntax error : '%s'", pr_token); return NULL; // shut up compiler }