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_ParseType Parses a variable type, including field and functions types ============ */ type_t *PR_ParseType (void) { if (PR_Check (".")) { type_t newtype; memset (&newtype, 0, sizeof(newtype)); newtype.type = ev_field; newtype.aux_type = PR_ParseType (); return PR_GetType (&newtype); } type_t *type; bool constant = PR_Check ("const"); if (!strcmp (pr_token, "float") ) type = constant ? &type_const_float : &type_float; else if (!strcmp (pr_token, "vector") ) type = constant ? &type_const_vector : &type_vector; else if (!strcmp (pr_token, "entity") ) type = &type_entity; else if (!strcmp (pr_token, "string") ) type = constant ? &type_const_string : &type_string; else if (!strcmp (pr_token, "void") ) type = &type_void; else { PR_ParseError ("\"%s\" is not a type", pr_token); type = &type_void; // shut up compiler warning } PR_Lex (); if (PR_Check("(")) { // function type // go back to non-const types // FIXME: don't bother? Or force const types instead? if (type == &type_const_float) type = &type_float; else if (type == &type_const_vector) type = &type_vector; else if (type == &type_const_string) type = &type_string; return PR_ParseFunctionType(type); } return type; }
static type_t *ParseUnionType (void) { type_t *type; type_t newType; type = PR_ParseType(); if (type->type == ev_field) { PR_ParseError("union field types are implicit"); } memset(&newType, 0, sizeof(newType)); newType.type = ev_field; newType.aux_type = type; return PR_FindType(&newType); }
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 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_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); }