123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696 |
- /* Copyright (C) 1996-1997 Id Software, Inc.
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- See file, 'COPYING', for details.
- */
- #include "qcc.h"
- int pr_source_line;
- char *pr_file_p;
- char *pr_line_start; // start of current source line
- int pr_bracelevel;
- char pr_token[2048];
- token_type_t pr_token_type;
- type_t *pr_immediate_type;
- eval_t pr_immediate;
- char pr_immediate_string[2048];
- int pr_error_count;
- char *pr_punctuation[] =
- // longer symbols must be before a shorter partial match
- {"&&", "||", "<=", ">=","==", "!=", ";", ",", "!", "*", "/", "(", ")", "-", "+", "=", "[", "]", "{", "}", "...", ".", "<", ">" , "#" , "&" , "|" , NULL};
- // simple types. function types are dynamically allocated
- type_t type_void = {ev_void, &def_void};
- type_t type_string = {ev_string, &def_string};
- type_t type_float = {ev_float, &def_float};
- type_t type_vector = {ev_vector, &def_vector};
- type_t type_entity = {ev_entity, &def_entity};
- type_t type_field = {ev_field, &def_field};
- type_t type_function = {ev_function, &def_function,NULL,&type_void};
- // type_function is a void() function used for state defs
- type_t type_pointer = {ev_pointer, &def_pointer};
- type_t type_floatfield = {ev_field, &def_field, NULL, &type_float};
- int type_size[8] = {1,1,1,3,1,1,1,1};
- def_t def_void = {&type_void, "temp"};
- def_t def_string = {&type_string, "temp"};
- def_t def_float = {&type_float, "temp"};
- def_t def_vector = {&type_vector, "temp"};
- def_t def_entity = {&type_entity, "temp"};
- def_t def_field = {&type_field, "temp"};
- def_t def_function = {&type_function, "temp"};
- def_t def_pointer = {&type_pointer, "temp"};
- def_t def_ret, def_parms[MAX_PARMS];
- def_t *def_for_type[8] = {&def_void, &def_string, &def_float, &def_vector, &def_entity, &def_field, &def_function, &def_pointer};
- void PR_LexWhitespace (void);
- /*
- ==============
- PR_PrintNextLine
- ==============
- */
- void PR_PrintNextLine (void)
- {
- char *t;
- printf ("%3i:",pr_source_line);
- for (t=pr_line_start ; *t && *t != '\n' ; t++)
- printf ("%c",*t);
- printf ("\n");
- }
- /*
- ==============
- PR_NewLine
- Call at start of file and when *pr_file_p == '\n'
- ==============
- */
- void PR_NewLine (void)
- {
- boolean m;
-
- if (*pr_file_p == '\n')
- {
- pr_file_p++;
- m = true;
- }
- else
- m = false;
- pr_source_line++;
- pr_line_start = pr_file_p;
- // if (pr_dumpasm)
- // PR_PrintNextLine ();
- if (m)
- pr_file_p--;
- }
- /*
- ==============
- 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);
- }
- /*
- ==============
- PR_LexNumber
- ==============
- */
- float PR_LexNumber (void)
- {
- int c;
- int len;
-
- len = 0;
- c = *pr_file_p;
- do
- {
- pr_token[len] = c;
- len++;
- pr_file_p++;
- c = *pr_file_p;
- } while ((c >= '0' && c<= '9') || c == '.');
- pr_token[len] = 0;
- return atof (pr_token);
- }
- /*
- ==============
- 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_LexName
- Parses an identifier
- ==============
- */
- void PR_LexName (void)
- {
- int c;
- int len;
-
- len = 0;
- c = *pr_file_p;
- do
- {
- pr_token[len] = c;
- len++;
- pr_file_p++;
- c = *pr_file_p;
- } while ( (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_'
- || (c >= '0' && c <= '9'));
- pr_token[len] = 0;
- pr_token_type = tt_name;
- }
- /*
- ==============
- 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_LexWhitespace
- ==============
- */
- void PR_LexWhitespace (void)
- {
- int c;
-
- while (1)
- {
- // skip whitespace
- while ( (c = *pr_file_p) <= ' ')
- {
- if (c=='\n')
- PR_NewLine ();
- if (c == 0)
- return; // end of file
- pr_file_p++;
- }
-
- // skip // comments
- if (c=='/' && pr_file_p[1] == '/')
- {
- while (*pr_file_p && *pr_file_p != '\n')
- pr_file_p++;
- PR_NewLine();
- pr_file_p++;
- continue;
- }
-
- // skip /* */ comments
- if (c=='/' && pr_file_p[1] == '*')
- {
- do
- {
- pr_file_p++;
- if (pr_file_p[0]=='\n')
- PR_NewLine();
- if (pr_file_p[1] == 0)
- return;
- } while (pr_file_p[-1] != '*' || pr_file_p[0] != '/');
- pr_file_p++;
- continue;
- }
-
- break; // a real character has been found
- }
- }
- //============================================================================
- #define MAX_FRAMES 256
- char pr_framemacros[MAX_FRAMES][16];
- int pr_nummacros;
- void PR_ClearGrabMacros (void)
- {
- pr_nummacros = 0;
- }
- 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);
- }
- // just parses text, returning false if an eol is reached
- boolean PR_SimpleGetToken (void)
- {
- int c;
- int i;
-
- // skip whitespace
- while ( (c = *pr_file_p) <= ' ')
- {
- if (c=='\n' || c == 0)
- return false;
- pr_file_p++;
- }
-
- i = 0;
- while ( (c = *pr_file_p) > ' ' && c != ',' && c != ';')
- {
- pr_token[i] = c;
- i++;
- pr_file_p++;
- }
- pr_token[i] = 0;
- return true;
- }
- void PR_ParseFrame (void)
- {
- while (PR_SimpleGetToken ())
- {
- strcpy (pr_framemacros[pr_nummacros], pr_token);
- pr_nummacros++;
- }
- }
- /*
- ==============
- 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 ();
- }
- //============================================================================
- /*
- ==============
- PR_Lex
- Sets pr_token, pr_token_type, and possibly pr_immediate and pr_immediate_type
- ==============
- */
- void PR_Lex (void)
- {
- int c;
- pr_token[0] = 0;
-
- if (!pr_file_p)
- {
- pr_token_type = tt_eof;
- return;
- }
- PR_LexWhitespace ();
- c = *pr_file_p;
-
- if (!c)
- {
- pr_token_type = tt_eof;
- return;
- }
- // handle quoted strings as a unit
- if (c == '\"')
- {
- PR_LexString ();
- return;
- }
- // handle quoted vectors as a unit
- if (c == '\'')
- {
- PR_LexVector ();
- return;
- }
- // if the first character is a valid identifier, parse until a non-id
- // character is reached
- if ( (c >= '0' && c <= '9') || ( c=='-' && pr_file_p[1]>='0' && pr_file_p[1] <='9') )
- {
- pr_token_type = tt_immediate;
- pr_immediate_type = &type_float;
- pr_immediate._float = PR_LexNumber ();
- return;
- }
-
- if ( (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' )
- {
- PR_LexName ();
- return;
- }
-
- if (c == '$')
- {
- PR_LexGrab ();
- return;
- }
-
- // parse symbol strings until a non-symbol is found
- PR_LexPunctuation ();
- }
- //=============================================================================
- /*
- ============
- PR_ParseError
- Aborts the current file load
- ============
- */
- void PR_ParseError (char *error, ...)
- {
- va_list argptr;
- char string[1024];
- va_start (argptr,error);
- vsprintf (string,error,argptr);
- va_end (argptr);
- printf ("%s:%i:%s\n", strings + s_file, pr_source_line, string);
-
- longjmp (pr_parse_abort, 1);
- }
- /*
- =============
- PR_Expect
- Issues an error if the current token isn't equal to string
- Gets the next token
- =============
- */
- void PR_Expect (char *string)
- {
- if (strcmp (string, pr_token))
- PR_ParseError ("expected %s, found %s",string, pr_token);
- PR_Lex ();
- }
- /*
- =============
- PR_Check
- Returns true and gets the next token if the current token equals string
- Returns false and does nothing otherwise
- =============
- */
- boolean PR_Check (char *string)
- {
- if (strcmp (string, pr_token))
- return false;
-
- PR_Lex ();
- return true;
- }
- /*
- ============
- 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_FindType
- Returns a preexisting complex type that matches the parm, or allocates
- a new one and copies it out.
- ============
- */
- type_t *PR_FindType (type_t *type)
- {
- def_t *def;
- type_t *check;
- int i;
-
- for (check = pr.types ; check ; check = check->next)
- {
- if (check->type != type->type
- || check->aux_type != type->aux_type
- || check->num_parms != type->num_parms)
- continue;
-
- for (i=0 ; i< type->num_parms ; i++)
- if (check->parm_types[i] != type->parm_types[i])
- break;
-
- if (i == type->num_parms)
- return check;
- }
-
- // allocate a new one
- check = malloc (sizeof (*check));
- *check = *type;
- check->next = pr.types;
- pr.types = check;
-
- // allocate a generic def for the type, so fields can reference it
- def = malloc (sizeof(def_t));
- def->name = "COMPLEX TYPE";
- def->type = check;
- check->def = def;
- return check;
- }
- /*
- ============
- PR_SkipToSemicolon
- For error recovery, also pops out of nested braces
- ============
- */
- void PR_SkipToSemicolon (void)
- {
- do
- {
- if (!pr_bracelevel && PR_Check (";"))
- return;
- PR_Lex ();
- } while (pr_token[0]); // eof will return a null token
- }
- /*
- ============
- PR_ParseType
- Parses a variable type, including field and functions types
- ============
- */
- char pr_parm_names[MAX_PARMS][MAX_NAME];
- type_t *PR_ParseType (void)
- {
- type_t new;
- type_t *type;
- char *name;
-
- if (PR_Check ("."))
- {
- memset (&new, 0, sizeof(new));
- new.type = ev_field;
- new.aux_type = PR_ParseType ();
- return PR_FindType (&new);
- }
-
- 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
- }
- PR_Lex ();
-
- if (!PR_Check ("("))
- return type;
-
- // function type
- memset (&new, 0, sizeof(new));
- new.type = ev_function;
- new.aux_type = type; // return type
- new.num_parms = 0;
- if (!PR_Check (")"))
- {
- if (PR_Check ("..."))
- new.num_parms = -1; // variable args
- else
- do
- {
- type = PR_ParseType ();
- name = PR_ParseName ();
- strcpy (pr_parm_names[new.num_parms], name);
- new.parm_types[new.num_parms] = type;
- new.num_parms++;
- } while (PR_Check (","));
-
- PR_Expect (")");
- }
-
- return PR_FindType (&new);
- }
|