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; }
void PR_Expect (char *string, token_type_t type) { if (STRCMP(string, pr_token)) PR_ParseError (550, "Expected %s, found %s",string, pr_token); if (type) if (pr_token_type != type) PR_ParseError (550, "Expected %s, found %s",string, pr_token); PR_Lex (); }
/* ============ 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_ParseName Checks to see if the current token is a valid name ============ */ char *PR_ParseName (void) { static char ident[MAX_NAME]; if (pr_token_type != tt_name) PR_ParseError ("not a name"); if (strlen(pr_token) >= MAX_NAME-1) PR_ParseError ("name too long"); strcpy (ident, pr_token); PR_Lex (); return ident; }
/* ============== PR_LexPunctuation ============== */ void PR_LexPunctuation (void) { int i; int len; char *p; pr_token_type = tt_punct; for (i=0 ; (p = pr_punctuation[i]) != NULL ; i++) { len = strlen(p); if (!strncmp(p, pr_file_p, len) ) { strcpy (pr_token, p); if (p[0] == '{') pr_bracelevel++; else if (p[0] == '}') pr_bracelevel--; pr_file_p += len; return; } } PR_ParseError ("Unknown punctuation"); }
/* ============== PR_LexGrab Deals with counting sequence numbers and replacing frame macros ============== */ void PR_LexGrab (void) { pr_file_p++; // skip the $ if (!PR_SimpleGetToken ()) PR_ParseError ("hanging $"); // check for $frame if (!strcmp (pr_token, "frame")) { PR_ParseFrame (); PR_Lex (); } // ignore other known $commands else if (!strcmp (pr_token, "cd") || !strcmp (pr_token, "origin") || !strcmp (pr_token, "base") || !strcmp (pr_token, "flags") || !strcmp (pr_token, "scale") || !strcmp (pr_token, "skin") ) { // skip to end of line while (PR_SimpleGetToken ()) ; PR_Lex (); } // look for a frame name macro else PR_FindMacro (); }
static void ParseCase (void) { def_t *e; def_t *e2; do { e = EX_Expression(TOP_PRIORITY); if (TK_CHECK(TK_RANGE)) { e2 = EX_Expression(TOP_PRIORITY); if (e->type->type != ev_float || e2->type->type != ev_float) { PR_ParseError("type mismatch for case range"); } } else { e2 = NULL; } AddCase(e->type->type, e, e2, false); } while (TK_CHECK(TK_COMMA)); LX_Require(":"); }
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); }
void PR_Expect(char *string) { if (DefCmp(string, pr_token)) PR_ParseError("expected %s, found %s", string, pr_token); PR_Lex(); }
const char *PR_ParseName (void) { static char ident[MAX_NAME]; if (pr_token_type != tt_name) { PR_ParseError ("not a name"); } if (strlen(pr_token) >= MAX_NAME-1) { PR_ParseError ("name too long"); } strcpy(ident, pr_token); LX_Fetch(); return ident; }
void LX_Require (const char *string) { if (strcmp(string, pr_token)) { PR_ParseError("expected %s, found %s", string, pr_token); } LX_Fetch(); }
/* ============ 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; }
static void AddContinue (void) { if (ContinueIndex == MAX_CONTINUE) { PR_ParseError("continue overflow"); } ContinueInfo[ContinueIndex].level = ContextLevel; ContinueInfo[ContinueIndex].patch = &statements[numstatements]; CO_GenCode(&pr_opcodes[OP_GOTO], NULL, NULL); ContinueIndex++; }
static void AddBreak (void) { if (BreakIndex == MAX_BREAK) { PR_ParseError("break overflow"); } BreakInfo[BreakIndex].level = ContextLevel; BreakInfo[BreakIndex].patch = &statements[numstatements]; CO_GenCode(&pr_opcodes[OP_GOTO], NULL, NULL); BreakIndex++; }
/* ============ 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_ParseInitialization "<type> <name> = " was parsed, parse the rest ================ */ void PR_ParseInitialization (type_t *type, char *name, def_t *def) { if (def->initialized) PR_ParseError ("%s redeclared", name); if (pr_token_type != tt_immediate && pr_token_type != tt_name) PR_ParseError ("syntax error : '%s'", pr_token); if (pr_token_type == tt_name) { PR_ParseError ("initializer is not a constant"); } if (!CompareType(pr_immediate_type, type)) PR_ParseError ("wrong immediate type for %s", name); def->initialized = 1; if (type == &type_const_string || type == &type_string) pr_immediate.string = CopyString (pr_immediate_string); memcpy (pr_globals + def->ofs, &pr_immediate, 4*type_size[pr_immediate_type->type]); PR_Lex (); }
/* ================ PR_ParseFunctionBody ================ */ void PR_ParseFunctionBody (type_t *type, char *name, def_t *def) { function_t *f; dfunction_t *df; int locals_start; if (pr_scope) PR_ParseError ("'%s': local function definitions are illegal", name); if (def->initialized) PR_ParseError ("function '%s' already has a body", name); 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 (opt_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; // id's qcc would set numparms to -1 for varargs functions // but non-builtin varargs functions don't make sense anyway so don't bother checking df->numparms = f->def->type->num_parms & VA_MASK; df->locals = locals_end - locals_start; df->parm_start = locals_start; for (int i=0 ; i<df->numparms ; i++) df->parm_size[i] = type_size[f->def->type->parm_types[i]->type]; }
/* ============== PR_FinishCompilation called after all files are compiled to check for errors Returns false if errors were detected. ============== */ boolean PR_FinishCompilation (void) { def_t *d; boolean errors; int i; s_file = "LINK" - strings; pr_source_line = 0; errors = false; // check to make sure all functions prototyped have code for (d=pr.def_head.next ; d ; d=d->next) { if (d->constant) { if (!d->defined) { PR_ParseError (551, "%s was not defined (see prototype %s(%i))",d->name, d->s_file, d->line); errors = true; pr_source_line++; // just to be cute } } } // FrikaC: make sure all labels were defined for(i = num_defines; i > 0; i--) { if (pr_defines[i].label) { if (!pr_defines[i].defined) { PR_ParseError (552, "Label %s was not defined",pr_defines[i].name); errors = true; pr_source_line++; // just to be cute } } } return !errors; }
/* ============== PR_LexString Parses a quoted string ============== */ void PR_LexString (void) { int c; int len; len = 0; pr_file_p++; do { c = *pr_file_p++; if (!c) PR_ParseError ("EOF inside quote"); if (c=='\n') PR_ParseError ("newline inside quote"); if (c=='\\') { // escape char c = *pr_file_p++; if (!c) PR_ParseError ("EOF inside quote"); if (c == 'n') c = '\n'; else if (c == '"') c = '"'; else PR_ParseError ("Unknown escape char"); } else if (c=='\"') { pr_token[len] = 0; pr_token_type = tt_immediate; pr_immediate_type = &type_string; strcpy (pr_immediate_string, pr_token); return; } pr_token[len] = c; len++; } while (1); }
static void AddCase(etype_t type, def_t *value1, def_t *value2, qboolean isDefault) { if (CaseIndex == MAX_CASE) { PR_ParseError("case overflow"); } CaseInfo[CaseIndex].level = ContextLevel; CaseInfo[CaseIndex].value1 = value1; CaseInfo[CaseIndex].value2 = value2; CaseInfo[CaseIndex].isDefault = isDefault; CaseInfo[CaseIndex].statement = numstatements; CaseInfo[CaseIndex].type = type; CaseIndex++; }
/* ============ 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); }
static void ParseReturn (void) { def_t *e; //if (TK_CHECK(TK_SEMICOLON)) if (pr_tokenclass == TK_SEMICOLON) { if (st_ReturnType->type != ev_void) { PR_ParseError("missing return value"); } CO_GenCode(&pr_opcodes[OP_RETURN], 0, 0); LX_Fetch(); return; } e = EX_Expression(TOP_PRIORITY); if (e->type != st_ReturnType) { PR_ParseError("return type mismatch"); } LX_Require(";"); CO_GenCode(&pr_opcodes[OP_RETURN], e, 0); st_ReturnParsed = true; }
void PR_FindMacro (void) { int i; for (i=0 ; i<pr_nummacros ; i++) if (!strcmp (pr_token, pr_framemacros[i])) { sprintf (pr_token,"%d", i); pr_token_type = tt_immediate; pr_immediate_type = &type_float; pr_immediate._float = i; return; } PR_ParseError ("Unknown frame macro $%s", pr_token); }
static void ParseThinktime (void) { def_t *expr1; def_t *expr2; expr1 = EX_Expression(TOP_PRIORITY); LX_Require(":"); expr2 = EX_Expression(TOP_PRIORITY); if (expr1->type->type != ev_entity || expr2->type->type != ev_float) { PR_ParseError("type mismatch for thinktime"); } LX_Require(";"); CO_GenCode(&pr_opcodes[OP_THINKTIME], expr1, expr2); }
/* ============== PR_LexVector Parses a single quoted vector ============== */ void PR_LexVector (void) { int i; pr_file_p++; pr_token_type = tt_immediate; pr_immediate_type = &type_vector; for (i=0 ; i<3 ; i++) { pr_immediate.vector[i] = PR_LexNumber (); PR_LexWhitespace (); } if (*pr_file_p != '\'') PR_ParseError ("Bad vector"); pr_file_p++; }
/* ============ 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; }
static void FindFrameMacro (void) { int i; for (i = 0; i < FrameMacroCount; i++) { if (!strcmp(pr_token, FrameMacroNames[i])) { sprintf(pr_token, "%d", i); pr_token_type = tt_immediate; pr_immediate_type = &type_float; pr_immediate._float = (float)FrameMacroValues[i]; return; } } PR_ParseError("unknown frame macro $%s", pr_token); }
/* ============== 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); }