static void ParseUnion (void) { const char *name; type_t *type; int startFieldOffset; int highestFieldOffset; LX_Require("{"); startFieldOffset = pr.size_fields; highestFieldOffset = startFieldOffset; do { if (LX_CheckFetch("struct")) { pr.size_fields = startFieldOffset; LX_Require("{"); do { type = ParseUnionType(); do { name = PR_ParseName(); PR_GetDef(type, name, pr_scope, true); } while (TK_CHECK(TK_COMMA)); LX_Require(";"); } while (pr_tokenclass != TK_RBRACE); LX_Require("}"); LX_Require(";"); if (pr.size_fields > highestFieldOffset) { highestFieldOffset = pr.size_fields; } } else { type = ParseUnionType(); do { name = PR_ParseName(); pr.size_fields = startFieldOffset; PR_GetDef(type, name, pr_scope, true); if (pr.size_fields > highestFieldOffset) { highestFieldOffset = pr.size_fields; } } while (TK_CHECK(TK_COMMA)); LX_Require(";"); } } while (pr_tokenclass != TK_RBRACE); LX_Require("}"); LX_Require(";"); pr.size_fields = highestFieldOffset; }
type_t *PR_ParseFunctionType (type_t *returnType) { type_t newtype; memset (&newtype, 0, sizeof(newtype)); newtype.type = ev_function; newtype.aux_type = returnType; newtype.num_parms = 0; if (PR_Check (")")) { // empty args return PR_GetType (&newtype); } do { if (PR_Check ("...")) { // variable args PR_Expect (")"); newtype.num_parms |= VA_BIT; return PR_GetType (&newtype); } if (newtype.num_parms >= MAX_PARMS) PR_ParseError ("too many parameters (max. %d allowed)", (int)MAX_PARMS); type_t *type = PR_ParseType (); char *name = PR_ParseName (); strlcpy (pr_parm_names[newtype.num_parms], name, sizeof(pr_parm_names[newtype.num_parms])); newtype.parm_types[newtype.num_parms] = type; newtype.num_parms++; } while (PR_Check (",")); PR_Expect (")"); return PR_GetType(&newtype); }
/* ============ PR_ParseValue Returns the global ofs for the current token ============ */ def_t *PR_ParseValue (void) { def_t *d; char *name; // if the token is an immediate, allocate a constant for it if (pr_token_type == tt_immediate) return PR_ParseImmediate (); name = PR_ParseName (); // look through the defs d = PR_GetDef (NULL, name, pr_scope, false); if (!d) PR_ParseError ("Unknown value \"%s\"", name); return d; }
/* ============ PR_ParseValue Returns the global ofs for the current token ============ */ def_t *PR_ParseValue (void) { def_t *d; char *name; // if the token is an immediate, allocate a constant for it if (pr_token_type == tt_immediate) return PR_ParseImmediate (); name = PR_ParseName (); // look through the defs d = PR_FindDef (name, pr_scope); if (!d) PR_ParseError ("'%s' : undeclared identifier", name); return d; }
/* ============== PR_ParseState States are special functions made for convenience. They automatically set frame, nextthink (implicitly), and think (allowing forward definitions). // void() name = [framenum, nextthink] {code} // expands to: // function void name () // { // self.frame=framenum; // self.nextthink = time + 0.1; // self.think = nextthink // <code> // }; ============== */ void PR_ParseState (void) { char *name; def_t *s1, *def; if (pr_token_type != tt_immediate || pr_immediate_type != &type_float) PR_ParseError ("state frame must be a number"); s1 = PR_ParseImmediate (); PR_Expect (","); name = PR_ParseName (); def = PR_GetDef (&type_function, name,0, true); PR_Expect ("]"); PR_Statement (&pr_opcodes[OP_STATE], s1, def); }
void CO_ParseDefs (void) { int i; const char *name; def_t *def; type_t *type; int elementCount; gofs_t offset; type = PR_ParseType(); if (type == &type_union) { if (pr_scope) { PR_ParseError("unions must be global"); } ParseUnion(); return; } if (pr_scope && (type->type == ev_field || type->type == ev_function)) { PR_ParseError("fields and functions must be global"); } do { name = PR_ParseName(); if (TK_CHECK(TK_LPAREN)) { ParseCStyleFunctionDef(name, type); return; } elementCount = 0; if (TK_CHECK(TK_LBRACKET)) { def = GetArrayDef(name, type, &elementCount); } else { def = PR_GetDef(type, name, pr_scope, true); } // Check for initialization if (TK_CHECK(TK_ASSIGN)) { if (def->initialized) { PR_ParseError("'%s' : redefinition", name); } if (type->type == ev_field) { PR_ParseError("fields cannot be initialized"); } if (elementCount != 0) { LX_Require("{"); i = 0; offset = def->ofs; do { if (pr_token_type != tt_immediate) { PR_ParseError("immediate type required for %s", name); } if (pr_immediate_type->type != type->type) { PR_ParseError("wrong immediate type for %s", name); } memcpy(pr_globals+offset, &pr_immediate, 4*type_size[pr_immediate_type->type]); offset += type_size[pr_immediate_type->type]; i++; LX_Fetch(); } while (TK_CHECK(TK_COMMA)); LX_Require("}"); if (i != elementCount) { PR_ParseError("element count mismatch in array" " initialization"); } def->initialized = 1; continue; } else if (type->type == ev_function) { ParseFunctionDef(def, type); continue; } else if (pr_immediate_type != type) { PR_ParseError("wrong immediate type for %s", name); } def->initialized = 1; memcpy(pr_globals+def->ofs, &pr_immediate, 4*type_size[pr_immediate_type->type]); LX_Fetch(); } else if (elementCount != 0 && type->type != ev_field) { memset(pr_globals+def->ofs, 0, elementCount*4*type_size[type->type]); def->initialized = 1; } } while (TK_CHECK(TK_COMMA)); LX_Require(";"); }
static void ParseState (void) { const char *name; def_t *def; def_t *s1, *s2; int frame1, frame2; int direction; qboolean weapon; if (pr_token_type == tt_name) { FrameIndex++; // Stuff a float for CO_ParseImmediate() pr_token_type = tt_immediate; pr_immediate_type = &type_float; pr_immediate._float = (float)FrameIndex; s1 = CO_ParseImmediate(); pr_token_type = tt_name; name = PR_ParseName(); def = PR_GetDef(&type_function, name, 0, true); LX_Require("]"); CO_GenCode(&pr_opcodes[OP_STATE], s1, def); return; } else if (pr_tokenclass == TK_INC || pr_tokenclass == TK_DEC) { direction = pr_tokenclass; weapon = false; LX_Fetch(); if (TK_CHECK(TK_LPAREN)) { if (LX_Check("w")) { LX_Fetch(); } else { LX_Require("W"); } LX_Require(")"); weapon = true; } if (pr_token_type != tt_immediate || pr_immediate_type != &type_float) { PR_ParseError("state frame must be a number"); } frame1 = (int)pr_immediate._float; s1 = CO_ParseImmediate(); LX_Fetch(); LX_Require(".."); if (pr_token_type != tt_immediate || pr_immediate_type != &type_float) { PR_ParseError("state frame must be a number"); } frame2 = (int)pr_immediate._float; s2 = CO_ParseImmediate(); LX_Fetch(); if (direction == TK_INC) { if (frame1 > frame2) { PR_ParseError("bad frame order in state cycle"); } } else if (frame1 < frame2) { PR_ParseError("bad frame order in state cycle"); } LX_Require("]"); if (weapon == true) { CO_GenCode(&pr_opcodes[OP_CWSTATE], s1, s2); } else { CO_GenCode(&pr_opcodes[OP_CSTATE], s1, s2); } return; } if (pr_token_type != tt_immediate || pr_immediate_type != &type_float) { PR_ParseError("state frame must be a number"); } FrameIndex = (int)pr_immediate._float; s1 = CO_ParseImmediate(); LX_Fetch(); if (pr_tokenclass == TK_COMMA) { LX_Fetch(); } name = PR_ParseName(); def = PR_GetDef(&type_function, name, 0, true); LX_Require("]"); CO_GenCode(&pr_opcodes[OP_STATE], s1, def); }
static void ParseCStyleFunctionDef (const char *funcName, type_t *type) { int i; const char *name = NULL; // FIXME: init to NULL, avoid compiler warning type_t newType; type_t *funcType; def_t *def; function_t *f; dfunction_t *df; int locals_start; char funcIdent[MAX_NAME]; int initClass; strcpy(funcIdent, funcName); memset(&newType, 0, sizeof(newType)); newType.type = ev_function; newType.aux_type = type; // Return type newType.num_parms = 0; if (!TK_CHECK(TK_RPAREN)) { if (TK_CHECK(TK_ELLIPSIS)) { // Variable args newType.num_parms = -1; } else if (!LX_CheckFetch("void")) { do { type = PR_ParseType(); name = PR_ParseName(); strcpy(pr_parm_names[newType.num_parms], name); newType.parm_types[newType.num_parms] = type; newType.num_parms++; } while (TK_CHECK(TK_COMMA)); } LX_Require(")"); } funcType = PR_FindType(&newType); def = PR_GetDef(funcType, funcIdent, pr_scope, true); if (def->initialized) { PR_ParseError("%s redeclared", funcName); } if (TK_TEST(TK_LBRACE) || TK_TEST(TK_LBRACKET) || TK_TEST(TK_COLON)) { initClass = pr_tokenclass; if (def->initialized) { PR_ParseError("%s redeclared", name); } locals_start = locals_end = numpr_globals; pr_scope = def; f = ParseImmediateStatements(funcType); pr_scope = NULL; def->initialized = 1; G_FUNCTION(def->ofs) = numfunctions; f->def = def; df = &functions[numfunctions]; numfunctions++; if (f->builtin) { df->first_statement = -f->builtin; def->referenceCount++; } else { df->first_statement = f->code; } df->s_name = CopyString(f->def->name); df->s_file = s_file; df->numparms = f->def->type->num_parms; df->locals = locals_end - locals_start; df->parm_start = locals_start; for (i = 0; i < df->numparms; i++) { df->parm_size[i] = type_size[f->def->type->parm_types[i]->type]; } if (initClass == TK_COLON) { LX_Require(";"); } } else { LX_Require(";"); } }
/* ================ PR_ParseDefs Called at the outer layer and when a local statement is hit ================ */ void PR_ParseDefs (void) { char *name; type_t *type; def_t *def; function_t *f; dfunction_t *df; int i; int locals_start; type = PR_ParseType (); if (pr_scope && (type->type == ev_field || type->type == ev_function) ) PR_ParseError ("Fields and functions must be global"); do { name = PR_ParseName (); def = PR_GetDef (type, name, pr_scope, true); // check for an initialization if ( PR_Check ("=") ) { if (def->initialized) PR_ParseError ("%s redeclared", name); if (type->type == ev_function) { locals_start = locals_end = numpr_globals; pr_scope = def; f = PR_ParseImmediateStatements (type); pr_scope = NULL; def->initialized = 1; G_FUNCTION(def->ofs) = numfunctions; f->def = def; // if (pr_dumpasm) // PR_PrintFunction (def); // fill in the dfunction df = &functions[numfunctions]; numfunctions++; if (f->builtin) df->first_statement = -f->builtin; else df->first_statement = f->code; df->s_name = CopyString (f->def->name); df->s_file = s_file; df->numparms = f->def->type->num_parms; df->locals = locals_end - locals_start; df->parm_start = locals_start; for (i=0 ; i<df->numparms ; i++) df->parm_size[i] = type_size[f->def->type->parm_types[i]->type]; continue; } else if (pr_immediate_type != type) PR_ParseError ("wrong immediate type for %s", name); def->initialized = 1; memcpy (pr_globals + def->ofs, &pr_immediate, 4*type_size[pr_immediate_type->type]); PR_Lex (); } } while (PR_Check (",")); 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_ParseDefs Called at the outer layer and when a local statement is hit ================ */ void PR_ParseDefs (void) { type_t *type = PR_ParseType (); if (pr_scope && type->type == ev_field) PR_ParseError ("'%s': local field definitions are illegal", pr_token); int c_defs = 0; bool qc_style_function_def = false; // functions are always global def_t *defscope = (type->type == ev_function) ? NULL : pr_scope; do { char *name = PR_ParseName (); if (type->type != ev_function && PR_Check("(")) { // C-style function declaration char functionName[MAX_NAME]; if (strlen(name) >= (size_t)MAX_NAME) PR_ParseError ("name of function \"%s\" is too long (max. %d chars)", name, (int)(MAX_NAME - 1)); strcpy (functionName, name); type_t *functionType = PR_ParseFunctionType (type); def_t *def = PR_GetDef (functionType, functionName, NULL, pr_scope); if ((!c_defs && !strcmp(pr_token, "{")) || PR_Check("=")) { // C-style function definition (including builtin function definition #1, #2, etc.) PR_ParseFunctionBody (functionType, functionName, def); while (PR_Check(";")) ; // skip redundant semicolons return; } continue; } def_t *def = PR_GetDef (type, name, defscope, pr_scope); if (type->type == ev_void) { // end_sys_globals and end_sys_fields are special flags for structure dumping if (strcmp(name, "end_sys_globals") && strcmp(name, "end_sys_fields")) PR_ParseError ("'%s' : illegal use of type 'void'", name); } // check for an initialization if (PR_Check("=")) { if (type->type == ev_function) { // QuakeC-style function definition qc_style_function_def = true; PR_ParseFunctionBody (type, name, def); } else // variable initialization PR_ParseInitialization (type, name, def); } } while (c_defs++, PR_Check (",")); if (qc_style_function_def && c_defs == 1) ; // allow void() func = {} without semicolon else PR_Expect (";"); while (PR_Check(";")) ; // skip redundant semicolons }
type_t *PR_ParseType (void) { const char *name; type_t newtype; type_t *type; if (TK_CHECK(TK_PERIOD)) { if (LX_CheckFetch("union")) { return &type_union; } memset(&newtype, 0, sizeof(newtype)); newtype.type = ev_field; newtype.aux_type = PR_ParseType(); return PR_FindType(&newtype); } if (!strcmp (pr_token, "float") ) type = &type_float; else if (!strcmp (pr_token, "vector") ) type = &type_vector; // else if (!strcmp (pr_token, "float") ) // type = &type_float; else if (!strcmp (pr_token, "entity") ) type = &type_entity; else if (!strcmp (pr_token, "string") ) type = &type_string; else if (!strcmp (pr_token, "void") ) type = &type_void; else { PR_ParseError ("\"%s\" is not a type", pr_token); type = &type_float; // shut up compiler warning } LX_Fetch(); if (!TK_CHECK(TK_LPAREN)) { return type; } // Function type memset(&newtype, 0, sizeof(newtype)); newtype.type = ev_function; newtype.aux_type = type; // Return type newtype.num_parms = 0; if (!TK_CHECK(TK_RPAREN)) { if (TK_CHECK(TK_ELLIPSIS)) { newtype.num_parms = -1; // variable args } else { do { type = PR_ParseType(); name = PR_ParseName(); strcpy (pr_parm_names[newtype.num_parms], name); newtype.parm_types[newtype.num_parms] = type; newtype.num_parms++; } while (TK_CHECK(TK_COMMA)); } LX_Require(")"); } return PR_FindType(&newtype); }