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; }
static int ParseArray (const char *name, type_t *type) { int count; etype_t t; t = type->type; if (t == ev_field) { t = type->aux_type->type; } if (t != ev_float && t != ev_vector && t != ev_string && t != ev_entity && t != ev_function) { PR_ParseError("bad array type"); } if (PR_GetDef(type, name, pr_scope, false) != NULL) { PR_ParseError("array redefinition"); } if (pr_token_type != tt_immediate || pr_immediate_type != &type_float || pr_immediate._float != (int)pr_immediate._float) { PR_ParseError("subscript is not integral"); } count = (int)pr_immediate._float; if (count < 1 || count > MAX_ARRAY_ELEMENTS) { PR_ParseError("bad subscript: %d", count); } LX_Fetch(); LX_Require("]"); return count; }
/* ============ PR_ParseImmediateStatements Parse a function body ============ */ function_t *PR_ParseImmediateStatements (type_t *type) { int i; function_t *f; def_t *defs[MAX_PARMS]; f = malloc (sizeof(function_t)); // // check for builtin function definition #1, #2, etc // if (PR_Check ("#")) { if (pr_token_type != tt_immediate || pr_immediate_type != &type_float || pr_immediate._float != (int)pr_immediate._float) PR_ParseError ("Bad builtin immediate"); f->builtin = (int)pr_immediate._float; PR_Lex (); return f; } f->builtin = 0; // // define the parms // for (i=0 ; i<type->num_parms ; i++) { defs[i] = PR_GetDef (type->parm_types[i], pr_parm_names[i], pr_scope, true); f->parm_ofs[i] = defs[i]->ofs; if (i > 0 && f->parm_ofs[i] < f->parm_ofs[i-1]) Error ("bad parm order"); } f->code = numstatements; // // check for a state opcode // if (PR_Check ("[")) PR_ParseState (); // // parse regular statements // PR_Expect ("{"); while (!PR_Check("}")) PR_ParseStatement (); // emit an end of statements opcode PR_Statement (pr_opcodes, 0,0); return f; }
/* ============ 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_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(";"); }
def_t *PR_GetDef (type_t *type, const char *name, def_t *scope, qboolean allocate) { def_t *def; def_t *elementDef; char element[MAX_NAME]; char key[100], *tmp; int idx = 0; struct hash_element *cell = NULL; if (scope != NULL) { sprintf(key, "%s:%s", name, scope->name); idx = COM_Hash(key); } else { idx = COM_Hash(name); } for (cell = HashTable[idx]; cell != NULL; cell = cell->next) { def = cell->def; if (!STRCMP(def->name, name)) { // Found a match if (def->scope && def->scope != scope) { // In a different function continue; } if (type && def->type != type) { // Type mismatch PR_ParseError("type mismatch on redeclaration of %s", name); } return def; } } if (scope != NULL) { idx = COM_Hash(name); for (cell = HashTable[idx]; cell != NULL; cell = cell->next) { def = cell->def; if (!STRCMP(def->name, name)) { // Found a match if (def->scope && def->scope != scope) { // In a different function continue; } if (type && def->type != type) { // Type mismatch PR_ParseError("type mismatch on redeclaration of %s", name); } return def; } } } if (allocate == false) { return NULL; } // Allocate a new def def = (def_t *) malloc(sizeof(def_t)); memset(def, 0, sizeof(*def)); def->next = NULL; pr.def_tail->next = def; pr.def_tail = def; // Add to hash table cell = (struct hash_element *) malloc(sizeof(struct hash_element)); cell->next = HashTable[idx]; cell->def = def; HashTable[idx] = cell; tmp = (char *) malloc(strlen(name) + 1); strcpy(tmp, name); def->name = tmp; def->type = type; def->scope = scope; def->ofs = numpr_globals; pr_global_defs[numpr_globals] = def; if (type->type == ev_vector) { // Create vector element defs sprintf(element, "%s_x", name); elementDef = PR_GetDef(&type_float, element, scope, true); elementDef->parentVector = def; sprintf(element, "%s_y", name); elementDef = PR_GetDef(&type_float, element, scope, true); elementDef->parentVector = def; sprintf(element, "%s_z", name); elementDef = PR_GetDef(&type_float, element, scope, true); elementDef->parentVector = def; } else { numpr_globals += type_size[type->type]; } if (type->type == ev_field) { *(int *)&pr_globals[def->ofs] = pr.size_fields; if (type->aux_type->type == ev_vector) { // Create vector element defs sprintf(element, "%s_x", name); PR_GetDef(&type_floatfield, element, scope, true); sprintf(element, "%s_y", name); PR_GetDef(&type_floatfield, element, scope, true); sprintf(element, "%s_z", name); PR_GetDef(&type_floatfield, element, scope, true); } else { pr.size_fields += type_size[type->aux_type->type]; } } return def; }
static function_t *ParseImmediateStatements (type_t *type) { int i; function_t *f; def_t *defs[MAX_PARMS]; def_t *scopeDef; def_t *searchDef; f = (function_t *) malloc(sizeof(function_t)); // Check for builtin function definition if (TK_CHECK(TK_COLON)) { if (pr_token_type != tt_immediate || pr_immediate_type != &type_float || pr_immediate._float != (int)pr_immediate._float) { PR_ParseError("bad builtin immediate"); } f->builtin = (int)pr_immediate._float; LX_Fetch(); return f; } f->builtin = 0; // Define the parms for (i = 0; i < type->num_parms; i++) { defs[i] = PR_GetDef(type->parm_types[i], pr_parm_names[i], pr_scope, true); f->parm_ofs[i] = defs[i]->ofs; if (i > 0 && f->parm_ofs[i] < f->parm_ofs[i-1]) { PR_ParseError("bad parm order"); } } f->code = numstatements; // Check for a state opcode if (TK_CHECK(TK_LBRACKET)) { ParseState(); } // Check for regular statements st_ReturnType = type->aux_type; st_ReturnParsed = false; if (TK_CHECK(TK_LBRACE)) { scopeDef = pr_scope; searchDef = pr.def_tail; while (pr_tokenclass != TK_RBRACE) { ST_ParseStatement(); } while ((searchDef = searchDef->next) != NULL) { if (searchDef->scope == scopeDef && searchDef->referenceCount == 0 && searchDef->parentVector == NULL) { PR_ParseWarning("unreferenced local variable '%s'", searchDef->name); } } if (type->aux_type->type != ev_void && st_ReturnParsed == false) { PR_ParseError("missing return"); } LX_Fetch(); } else if (type->aux_type->type != ev_void && st_ReturnParsed == false) { PR_ParseError("missing return"); } // Emit an end of statements opcode CO_GenCode(pr_opcodes, 0, 0); return f; }
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_GetDef If type is NULL, it will match any type If allocate is true, a new def will be allocated if it can't be found ============ */ def_t *PR_GetDef (type_t *type, char *name, def_t *scope, qboolean allocate) { def_t *def, **old; char element[MAX_NAME]; // see if the name is already in use old = &pr.search; for (def = *old ; def ; old=&def->search_next,def = *old) if (!strcmp(def->name,name) ) { if ( def->scope && def->scope != scope) continue; // in a different function if (type && def->type != type) PR_ParseError ("Type mismatch on redeclaration of %s",name); // move to head of list to find fast next time *old = def->search_next; def->search_next = pr.search; pr.search = def; return def; } if (!allocate) return NULL; // allocate a new def def = malloc (sizeof(def_t)); memset (def, 0, sizeof(*def)); def->next = NULL; pr.def_tail->next = def; pr.def_tail = def; def->search_next = pr.search; pr.search = def; def->name = malloc (strlen(name)+1); strcpy (def->name, name); def->type = type; def->scope = scope; def->ofs = numpr_globals; pr_global_defs[numpr_globals] = def; // // make automatic defs for the vectors elements // .origin can be accessed as .origin_x, .origin_y, and .origin_z // if (type->type == ev_vector) { sprintf (element, "%s_x",name); PR_GetDef (&type_float, element, scope, true); sprintf (element, "%s_y",name); PR_GetDef (&type_float, element, scope, true); sprintf (element, "%s_z",name); PR_GetDef (&type_float, element, scope, true); } else numpr_globals += type_size[type->type]; if (type->type == ev_field) { *(int *)&pr_globals[def->ofs] = pr.size_fields; if (type->aux_type->type == ev_vector) { sprintf (element, "%s_x",name); PR_GetDef (&type_floatfield, element, scope, true); sprintf (element, "%s_y",name); PR_GetDef (&type_floatfield, element, scope, true); sprintf (element, "%s_z",name); PR_GetDef (&type_floatfield, element, scope, true); } else pr.size_fields += type_size[type->aux_type->type]; } // if (pr_dumpasm) // PR_PrintOfs (def->ofs); return def; }
void WriteData (int crc) { def_t *def; ddef_t *dd; dprograms_t progs; char tname[1024]; int h; unsigned int i; int size; for (def = pr.def_head.next ; def ; def = def->next) { if ((def->type->type == ev_field) && def->constant) { dd = &fields[numfielddefs]; numfielddefs++; dd->type = def->type->aux_type->type == ev_int ? ev_float : def->type->aux_type->type; if (def->save == 0) { strcpy(tname, def->name); strcat(tname, "__"); dd->s_name = CopyString(tname, 0); } else dd->s_name = CopyString (def->name, 0); dd->ofs = G_INT(def->ofs); } else if (pr_optimize_constant_names && def->constant && (def->type->type != ev_function)) { num_constant_names += strlen(def->name) + 1; num_constant_names += sizeof(ddef_t); continue; } else if (pr_optimize_unreferenced && pr_global_refs[def->ofs] <= 0) { if (!(def->type->type != ev_function)) { num_unreferenced += 1; continue; } } else if (pr_optimize_unreferenced && def->type->type == ev_vector) { if (pr_global_refs[def->ofs] + pr_global_refs[def->ofs + 1] + pr_global_refs[def->ofs +1] == 3) { num_unreferenced += 3; def = def->next; // def_x def = def->next; // def_y def = def->next; // def_z continue; } } dd = &globals[numglobaldefs]; dd->type = def->type->type == ev_int ? ev_float : def->type->type; if (def->save && ( dd->type != ev_field || def->constant != 1)) dd->type |= DEF_SAVEGLOBAL; if (def->name) { if (pr_optimize_locals && (def->scope || !(STRCMP(def->name, "IMMEDIATE")))) { num_locals_saved += strlen(def->name); dd->s_name = 0; } else dd->s_name = CopyString (def->name, 0); } dd->ofs = def->ofs; numglobaldefs++; } strofs = (strofs+3)&~3; if (strofs > INT_MAX) PR_ParseWarning(122, "strofs exceeds INT_MAX by %i", strofs - INT_MAX); if (numstatements > INT_MAX) PR_ParseWarning(123, "numstatements exceeds INT_MAX by %i", numstatements - INT_MAX); if (numfunctions > SHRT_MAX) PR_ParseWarning(124, "numfunctions exceeds SHRT_MAX by %i", numfunctions - SHRT_MAX); if (numglobaldefs > SHRT_MAX) PR_ParseWarning(125, "numglobaldefs exceeds SHRT_MAX by %i", numglobaldefs - SHRT_MAX); if (numfielddefs > SHRT_MAX) PR_ParseWarning(126, "numfielddefs exceeds SHRT_MAX by %i", numfielddefs - SHRT_MAX); if (numpr_globals > SHRT_MAX) PR_ParseWarning(127, "numpr_globals exceeds SHRT_MAX by %i", numpr_globals - SHRT_MAX); if (crc != NQ_PROGHEADER_CRC && crc != QW_PROGHEADER_CRC) PR_ParseWarning(208, "System defs do match internal crcs."); if (summary) { summary_print("----------- Summary -----------\n"); i = I_FloatTime() - StartTime; summary_print (" %02i:%02i elapsed time\n", (i / 60) % 59, i % 59); summary_print ("%6i strofs (MAX: %6i)\n", strofs, MAX_STRINGS ); summary_print ("%6i numstatements (MAX: %6i)\n", numstatements, MAX_STATEMENTS); summary_print ("%6i numfunctions (MAX: %6i)\n", numfunctions, SHRT_MAX); summary_print ("%6i numglobaldefs (MAX: %6i)\n", numglobaldefs, SHRT_MAX); summary_print ("%6i numfielddefs (MAX: %6i)\n", numfielddefs, SHRT_MAX); summary_print ("%6i numpr_globals (MAX: %6i)\n", numpr_globals, SHRT_MAX); } h = SafeOpenWrite (destfile); SafeWrite (h, &progs, sizeof(progs)); progs.ofs_strings = lseek (h, 0, SEEK_CUR); progs.numstrings = strofs; SafeWrite (h, strings, strofs); progs.ofs_statements = lseek (h, 0, SEEK_CUR); progs.numstatements = numstatements; for (i=0 ; i<numstatements ; i++) { statements[i].op = LittleShort(statements[i].op); statements[i].a = LittleShort(statements[i].a); statements[i].b = LittleShort(statements[i].b); statements[i].c = LittleShort(statements[i].c); } SafeWrite (h, statements, numstatements*sizeof(dstatement_t)); progs.ofs_functions = lseek (h, 0, SEEK_CUR); progs.numfunctions = numfunctions; for (i=0 ; i<numfunctions ; i++) { functions[i].first_statement = LittleLong (functions[i].first_statement); functions[i].parm_start = LittleLong (functions[i].parm_start); functions[i].s_name = LittleLong (functions[i].s_name < 0 || functions[i].s_name > strofs ? 0 : functions[i].s_name); functions[i].s_file = LittleLong (functions[i].s_file < 0 || functions[i].s_file > strofs ? 0 : functions[i].s_file); functions[i].numparms = LittleLong (functions[i].numparms > MAX_PARMS ? MAX_PARMS : functions[i].numparms); functions[i].locals = LittleLong (functions[i].locals); } SafeWrite (h, functions, numfunctions*sizeof(dfunction_t)); progs.ofs_globaldefs = lseek (h, 0, SEEK_CUR); progs.numglobaldefs = numglobaldefs; for (i=0 ; i<numglobaldefs ; i++) { globals[i].type = LittleShort (globals[i].type); globals[i].ofs = LittleShort (globals[i].ofs); globals[i].s_name = LittleLong (globals[i].s_name); } SafeWrite (h, globals, numglobaldefs*sizeof(ddef_t)); progs.ofs_fielddefs = lseek (h, 0, SEEK_CUR); progs.numfielddefs = numfielddefs; for (i=0 ; i<numfielddefs ; i++) { fields[i].type = LittleShort (fields[i].type); fields[i].ofs = LittleShort (fields[i].ofs); fields[i].s_name = LittleLong (fields[i].s_name < 0 || fields[i].s_name > strofs ? 0: fields[i].s_name); } SafeWrite (h, fields, numfielddefs*sizeof(ddef_t)); progs.ofs_globals = lseek (h, 0, SEEK_CUR); progs.numglobals = numpr_globals; for (i=0 ; i<numpr_globals ; i++) ((int *)pr_globals)[i] = LittleLong (((int *)pr_globals)[i]); SafeWrite (h, pr_globals, numpr_globals*4); i = (int)lseek(h, 0, SEEK_CUR); if (summary) summary_print ("%6i TOTAL SIZE\n", i); size = (i+16)&(~15); progs.entityfields = pr.size_fields; progs.version = PROG_VERSION; progs.crc = crc; if (summary) { summary_print("%6i Progheader CRC ", crc); if (crc == NQ_PROGHEADER_CRC) summary_print("( Quake )\n"); else if (crc == QW_PROGHEADER_CRC) summary_print("(Quake World)\n"); else summary_print("( UNKNOWN )\n"); } // byte swap the header and write it out for (i=0 ; i<sizeof(progs)/4 ; i++) ((int *)&progs)[i] = LittleLong ( ((int *)&progs)[i] ); lseek (h, 0, SEEK_SET); SafeWrite (h, &progs, sizeof(progs)); // look for progs if ((def = PR_GetDef(&type_entity, "progs", NULL, false, 0, 0))) { lseek(h, progs.ofs_globals + 4 * def->ofs, SEEK_SET); i = - (size + 112); SafeWrite (h, &i, 4); } for (def = pr.def_head.next ; def ; def = def->next) { if (def->type->arraysize) { lseek(h, progs.ofs_globals + 4 * def->ofs, SEEK_SET); i = (-(size + 112)) + progs.ofs_globals + 4 * (def->arraystart); //printf("filled in %s with %i\n", def->name, def->arraystart); SafeWrite (h, &i, 4); } } if (summary) { summary_print ("%6i precache_sounds(MAX: %6i)\n", numsounds, MAX_SOUNDS); summary_print ("%6i precache_models(MAX: %6i)\n", nummodels, MAX_MODELS); } close (h); if (summary) { if (pr_optimize_eliminate_temps || pr_optimize_shorten_ifs || pr_optimize_nonvec_parms || pr_optimize_constant_names || pr_optimize_defs || pr_optimize_hash_strings || pr_optimize_locals || pr_optimize_function_names || pr_optimize_filenames || pr_optimize_unreferenced || pr_optimize_logicops || pr_optimize_recycle || pr_optimize_constant_arithmetic) { summary_print("----------- Optimization Summary -----------\n"); if (pr_optimize_eliminate_temps) summary_print("%d stores shortened\n", num_stores_shortened); if (pr_optimize_shorten_ifs) summary_print("%d ifs shortened\n", num_ifs_shortened); if (pr_optimize_nonvec_parms) summary_print("%d non-vector parms\n", num_nonvec_parms); if (pr_optimize_constant_names) summary_print("%d bytes of constant defs/names eliminated\n", num_constant_names); if (pr_optimize_defs) summary_print("%d duplicate defs eliminated\n", num_defs); if (pr_optimize_hash_strings) summary_print("%d bytes of duplicate strings eliminated\n", num_strings); if (pr_optimize_locals) summary_print("%d bytes of immediate and local names eliminated\n", num_locals_saved); if (pr_optimize_function_names) summary_print("%d bytes of function names eliminated\n", num_funcs_saved); if (pr_optimize_filenames) summary_print("%d bytes of filenames eliminated\n", num_files_saved); if (pr_optimize_unreferenced) summary_print("%d unreferenced global defs eliminated\n", num_unreferenced); if (pr_optimize_logicops) summary_print("%d logic jumps added\n", num_logic_jumps); if (pr_optimize_recycle) summary_print("%d temporary globals recycled\n", num_recycled); if (pr_optimize_constant_arithmetic) summary_print("%d constant arithmetic statements eliminated\n", num_constant_ops_saved); } } }
/* ============ PR_GetDef A new def will be allocated if it can't be found ============ */ def_t *PR_GetDef (type_t *type, char *name, def_t *scope, def_t *visscope, bool isParm) { def_t *def; char element[MAX_NAME]; int hash; hash = Com_HashKey (name); // see if the name is already in use def = PR_FindDef2 (name, scope, hash); if (def) { if (def->scope != scope) { if (!opt_idcomp) goto allocNew; // a local def overrides global (ok) else PR_Warning (WARN_HIGH, "'%s' already declared on global scope", name); } if (def->type != type) PR_ParseError ("type mismatch on redeclaration of %s", name); if (def->isParm && !isParm) if (!opt_idcomp) PR_ParseError ("redefinition of formal parameter '%s'", name); else PR_Warning (WARN_HIGH, "redefinition of formal parameter '%s'", name); // fixup visibility scope if (def->visscope) def->visscope = visscope; return def; } // allocate a new def allocNew: def = PR_NewDef (hash); def->name = (char *) malloc (strlen(name)+1); strcpy (def->name, name); def->type = type; def->isParm = isParm; def->scope = scope; def->visscope = visscope; if (numpr_globals + type_size[type->type] > MAX_REGS) Error ("numpr_globals > MAX_REGS"); def->ofs = numpr_globals; pr_global_defs[numpr_globals] = def; // // make automatic defs for the vectors elements // .origin can be accessed as .origin_x, .origin_y, and .origin_z // if (type->type == ev_vector) { sprintf (element, "%s_x",name); PR_GetDef (&type_float, element, scope, visscope, isParm); sprintf (element, "%s_y",name); PR_GetDef (&type_float, element, scope, visscope, isParm); sprintf (element, "%s_z",name); PR_GetDef (&type_float, element, scope, visscope, isParm); } else numpr_globals += type_size[type->type]; if (type->type == ev_field) { assert (scope == NULL && visscope == NULL); *(int *)&pr_globals[def->ofs] = pr.size_fields; if (type->aux_type->type == ev_vector) { sprintf (element, "%s_x",name); PR_GetDef (&type_floatfield, element, NULL, NULL, isParm); sprintf (element, "%s_y",name); PR_GetDef (&type_floatfield, element, NULL, NULL, isParm); sprintf (element, "%s_z",name); PR_GetDef (&type_floatfield, element, NULL, NULL, isParm); } else pr.size_fields += type_size[type->aux_type->type]; } if (opt_dumpasm) PR_PrintOfs (def->ofs); return def; }
/* ================ 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 }