--- /dev/null
+#ifndef MINIMAL
+
+#include "qcc.h"
+#ifdef QCC
+#define print printf
+#endif
+#include "time.h"
+
+#define MEMBERFIELDNAME "__m%s"
+
+#define STRCMP(s1,s2) (((*s1)!=(*s2)) || strcmp(s1+1,s2+1)) //saves about 2-6 out of 120 - expansion of idea from fastqcc
+
+void QCC_PR_ConditionCompilation(void);
+pbool QCC_PR_UndefineName(char *name);
+char *QCC_PR_CheakCompConstString(char *def);
+CompilerConstant_t *QCC_PR_CheckCompConstDefined(char *def);
+pbool QCC_Include(char *filename);
+
+char *compilingfile;
+
+int pr_source_line;
+
+char *pr_file_p;
+char *pr_line_start; // start of current source line
+
+int pr_bracelevel;
+
+char pr_token[8192];
+token_type_t pr_token_type;
+QCC_type_t *pr_immediate_type;
+QCC_eval_t pr_immediate;
+
+char pr_immediate_string[8192];
+
+int pr_error_count;
+int pr_warning_count;
+
+
+CompilerConstant_t *CompilerConstant;
+int numCompilerConstants;
+extern pbool expandedemptymacro;
+
+
+
+char *pr_punctuation[] =
+// longer symbols must be before a shorter partial match
+{"&&", "||", "<=", ">=","==", "!=", "/=", "*=", "+=", "-=", "(+)", "(-)", "|=", "&~=", "++", "--", "->", "::", ";", ",", "!", "*", "/", "(", ")", "-", "+", "=", "[", "]", "{", "}", "...", "..", ".", "<<", "<", ">>", ">" , "?", "#" , "@", "&" , "|", "^", ":", NULL};
+
+char *pr_punctuationremap[] = //a nice bit of evilness.
+//(+) -> |=
+//-> -> .
+//(-) -> &~=
+{"&&", "||", "<=", ">=","==", "!=", "/=", "*=", "+=", "-=", "|=", "&~=", "|=", "&~=", "++", "--", ".", "::", ";", ",", "!", "*", "/", "(", ")", "-", "+", "=", "[", "]", "{", "}", "...", "..", ".", "<<", "<", ">>", ">" , "?", "#" , "@", "&" , "|", "^", ":", NULL};
+
+// simple types. function types are dynamically allocated
+QCC_type_t *type_void;// = {ev_void/*, &def_void*/};
+QCC_type_t *type_string;// = {ev_string/*, &def_string*/};
+QCC_type_t *type_float;// = {ev_float/*, &def_float*/};
+QCC_type_t *type_vector;// = {ev_vector/*, &def_vector*/};
+QCC_type_t *type_entity;// = {ev_entity/*, &def_entity*/};
+QCC_type_t *type_field;// = {ev_field/*, &def_field*/};
+QCC_type_t *type_function;// = {ev_function/*, &def_function*/,NULL,&type_void};
+// type_function is a void() function used for state defs
+QCC_type_t *type_pointer;// = {ev_pointer/*, &def_pointer*/};
+QCC_type_t *type_integer;// = {ev_integer/*, &def_integer*/};
+QCC_type_t *type_variant;// = {ev_integer/*, &def_integer*/};
+
+QCC_type_t *type_floatfield;// = {ev_field/*, &def_field*/, NULL, &type_float};
+
+/*QCC_def_t def_void = {type_void, "temp"};
+QCC_def_t def_string = {type_string, "temp"};
+QCC_def_t def_float = {type_float, "temp"};
+QCC_def_t def_vector = {type_vector, "temp"};
+QCC_def_t def_entity = {type_entity, "temp"};
+QCC_def_t def_field = {type_field, "temp"};
+QCC_def_t def_function = {type_function, "temp"};
+QCC_def_t def_pointer = {type_pointer, "temp"};
+QCC_def_t def_integer = {type_integer, "temp"};
+*/
+QCC_def_t def_ret, def_parms[MAX_PARMS];
+
+//QCC_def_t *def_for_type[9] = {&def_void, &def_string, &def_float, &def_vector, &def_entity, &def_field, &def_function, &def_pointer, &def_integer};
+
+void QCC_PR_LexWhitespace (void);
+
+
+
+
+//for compiler constants and file includes.
+
+typedef struct qcc_includechunk_s {
+ struct qcc_includechunk_s *prev;
+ char *filename;
+ char *currentdatapoint;
+ int currentlinenumber;
+ CompilerConstant_t *cnst;
+} qcc_includechunk_t;
+qcc_includechunk_t *currentchunk;
+void QCC_PR_IncludeChunkEx (char *data, pbool duplicate, char *filename, CompilerConstant_t *cnst)
+{
+ qcc_includechunk_t *chunk = qccHunkAlloc(sizeof(qcc_includechunk_t));
+ chunk->prev = currentchunk;
+ currentchunk = chunk;
+
+ chunk->currentdatapoint = pr_file_p;
+ chunk->currentlinenumber = pr_source_line;
+ chunk->cnst = cnst;
+ if( cnst )
+ {
+ cnst->inside++;
+ }
+
+ if (duplicate)
+ {
+ pr_file_p = qccHunkAlloc(strlen(data)+1);
+ strcpy(pr_file_p, data);
+ }
+ else
+ pr_file_p = data;
+}
+void QCC_PR_IncludeChunk (char *data, pbool duplicate, char *filename)
+{
+ QCC_PR_IncludeChunkEx(data, duplicate, filename, NULL);
+}
+
+pbool QCC_PR_UnInclude(void)
+{
+ if (!currentchunk)
+ return false;
+
+ if( currentchunk->cnst )
+ currentchunk->cnst->inside--;
+
+ pr_file_p = currentchunk->currentdatapoint;
+ pr_source_line = currentchunk->currentlinenumber;
+
+ currentchunk = currentchunk->prev;
+
+ return true;
+}
+
+
+/*
+==============
+PR_PrintNextLine
+==============
+*/
+void QCC_PR_PrintNextLine (void)
+{
+ char *t;
+
+ printf ("%3i:",pr_source_line);
+ for (t=pr_line_start ; *t && *t != '\n' ; t++)
+ printf ("%c",*t);
+ printf ("\n");
+}
+
+extern char qccmsourcedir[];
+//also meant to include it.
+void QCC_FindBestInclude(char *newfile, char *currentfile, char *rootpath)
+{
+ char fullname[10248];
+ char *stripfrom;
+ int doubledots;
+
+ char *end = fullname;
+
+ if (!*newfile)
+ return;
+
+ doubledots = 0;
+ while(!strncmp(newfile, "../", 3) || !strncmp(newfile, "..\\", 3))
+ {
+ newfile+=3;
+ doubledots++;
+ }
+
+ currentfile += strlen(rootpath); //could this be bad?
+
+ for(stripfrom = currentfile+strlen(currentfile)-1; stripfrom>currentfile; stripfrom--)
+ {
+ if (*stripfrom == '/' || *stripfrom == '\\')
+ {
+ if (doubledots>0)
+ doubledots--;
+ else
+ {
+ stripfrom++;
+ break;
+ }
+ }
+ }
+ strcpy(end, rootpath); end = end+strlen(end);
+ if (*fullname && end[-1] != '/')
+ {
+ strcpy(end, "/");
+ end = end+strlen(end);
+ }
+ strncpy(end, currentfile, stripfrom - currentfile); end += stripfrom - currentfile; *end = '\0';
+ strcpy(end, newfile);
+
+ QCC_Include(fullname);
+}
+
+pbool defaultstatic;
+int ForcedCRC;
+int QCC_PR_LexInteger (void);
+void QCC_AddFile (char *filename);
+void QCC_PR_LexString (void);
+pbool QCC_PR_SimpleGetToken (void);
+
+int ParsePrecompilerIf(void)
+{
+ CompilerConstant_t *c;
+ int eval;
+ char *start = pr_file_p;
+ if (!QCC_PR_SimpleGetToken())
+ {
+ if (*pr_file_p == '(')
+ {
+ eval = ParsePrecompilerIf();
+ while (*pr_file_p == ' ' || *pr_file_p == '\t')
+ pr_file_p++;
+ if (*pr_file_p != ')')
+ QCC_PR_ParseError(ERR_EXPECTED, "unclosed bracket condition\n");
+ }
+ else
+ QCC_PR_ParseError(ERR_EXPECTED, "expected bracket or constant\n");
+ }
+ else if (!strcmp(pr_token, "defined"))
+ {
+ while (*pr_file_p == ' ' || *pr_file_p == '\t')
+ pr_file_p++;
+ if (*pr_file_p != '(')
+ QCC_PR_ParseError(ERR_EXPECTED, "no opening bracket after defined\n");
+ else
+ {
+ pr_file_p++;
+
+ QCC_PR_SimpleGetToken();
+ eval = !!QCC_PR_CheckCompConstDefined(pr_token);
+
+ while (*pr_file_p == ' ' || *pr_file_p == '\t')
+ pr_file_p++;
+ if (*pr_file_p != ')')
+ QCC_PR_ParseError(ERR_EXPECTED, "unclosed defined condition\n");
+ pr_file_p++;
+ }
+ }
+ else
+ {
+ c = QCC_PR_CheckCompConstDefined(pr_token);
+ if (!c)
+ eval = atoi(pr_token);
+ else
+ eval = atoi(c->value);
+ }
+
+ QCC_PR_SimpleGetToken();
+ if (!strcmp(pr_token, "||"))
+ eval = ParsePrecompilerIf()||eval;
+ else if (!strcmp(pr_token, "&&"))
+ eval = ParsePrecompilerIf()&&eval;
+ else if (!strcmp(pr_token, "<="))
+ eval = eval <= ParsePrecompilerIf();
+ else if (!strcmp(pr_token, ">="))
+ eval = eval >= ParsePrecompilerIf();
+ else if (!strcmp(pr_token, "<"))
+ eval = eval < ParsePrecompilerIf();
+ else if (!strcmp(pr_token, ">"))
+ eval = eval > ParsePrecompilerIf();
+ else if (!strcmp(pr_token, "!="))
+ eval = eval != ParsePrecompilerIf();
+
+ return eval;
+}
+/*
+==============
+QCC_PR_Precompiler
+==============
+
+Runs precompiler stage
+*/
+pbool QCC_PR_Precompiler(void)
+{
+ char msg[1024];
+ int ifmode;
+ int a;
+ static int ifs = 0;
+ int level; //#if level
+ pbool eval = false;
+
+ if (*pr_file_p == '#')
+ {
+ char *directive;
+ for (directive = pr_file_p+1; *directive; directive++) //so # define works
+ {
+ if (*directive == '\r' || *directive == '\n')
+ QCC_PR_ParseError(ERR_UNKNOWNPUCTUATION, "Hanging # with no directive\n");
+ if (*directive > ' ')
+ break;
+ }
+ if (!strncmp(directive, "define", 6))
+ {
+ pr_file_p = directive;
+ QCC_PR_ConditionCompilation();
+ while(*pr_file_p != '\n' && *pr_file_p != '\0') //read on until the end of the line
+ {
+ pr_file_p++;
+ }
+ }
+ else if (!strncmp(directive, "undef", 5))
+ {
+ pr_file_p = directive+5;
+ while(*pr_file_p <= ' ')
+ pr_file_p++;
+
+ QCC_PR_SimpleGetToken ();
+ QCC_PR_UndefineName(pr_token);
+
+ // QCC_PR_ConditionCompilation();
+ while(*pr_file_p != '\n' && *pr_file_p != '\0') //read on until the end of the line
+ {
+ pr_file_p++;
+ }
+ }
+ else if (!strncmp(directive, "if", 2))
+ {
+ int originalline = pr_source_line;
+ pr_file_p = directive+2;
+ if (!strncmp(pr_file_p, "def ", 4))
+ {
+ ifmode = 0;
+ pr_file_p+=4;
+ }
+ else if (!strncmp(pr_file_p, "ndef ", 5))
+ {
+ ifmode = 1;
+ pr_file_p+=5;
+ }
+ else
+ {
+ ifmode = 2;
+ pr_file_p+=0;
+ //QCC_PR_ParseError("bad \"#if\" type");
+ }
+
+ if (ifmode == 2)
+ {
+ eval = ParsePrecompilerIf();
+
+ if(*pr_file_p != '\n' && *pr_file_p != '\0') //read on until the end of the line
+ {
+ QCC_PR_ParseError (ERR_NOENDIF, "junk on the end of #if line");
+ }
+ }
+ else
+ {
+ QCC_PR_SimpleGetToken ();
+
+ // if (!STRCMP(pr_token, "COOP_MODE"))
+ // eval = false;
+ if (QCC_PR_CheckCompConstDefined(pr_token))
+ eval = true;
+
+ if (ifmode == 1)
+ eval = eval?false:true;
+ }
+
+ while(*pr_file_p != '\n' && *pr_file_p != '\0') //read on until the end of the line
+ {
+ pr_file_p++;
+ }
+ level = 1;
+
+ if (eval)
+ ifs+=1;
+ else
+ {
+ while (1)
+ {
+ while(*pr_file_p && (*pr_file_p==' ' || *pr_file_p == '\t'))
+ pr_file_p++;
+
+ if (!*pr_file_p)
+ {
+ pr_source_line = originalline;
+ QCC_PR_ParseError (ERR_NOENDIF, "#if with no endif");
+ }
+
+ if (*pr_file_p == '#')
+ {
+ pr_file_p++;
+ while(*pr_file_p==' ' || *pr_file_p == '\t')
+ pr_file_p++;
+ if (!strncmp(pr_file_p, "endif", 5))
+ level--;
+ if (!strncmp(pr_file_p, "if", 2))
+ level++;
+ if (!strncmp(pr_file_p, "else", 4) && level == 1)
+ {
+ ifs+=1;
+ while(*pr_file_p != '\n' && *pr_file_p != '\0') //read on until the end of the line
+ {
+ pr_file_p++;
+ }
+ break;
+ }
+ }
+
+ while(*pr_file_p != '\n' && *pr_file_p != '\0') //read on until the end of the line
+ {
+ pr_file_p++;
+ }
+ if (level <= 0)
+ break;
+ pr_file_p++; //next line
+ pr_source_line++;
+ }
+ }
+ }
+ else if (!strncmp(directive, "else", 4))
+ {
+ int originalline = pr_source_line;
+
+ ifs -= 1;
+ level = 1;
+
+ while(*pr_file_p != '\n' && *pr_file_p != '\0') //read on until the end of the line
+ {
+ pr_file_p++;
+ }
+ while (1)
+ {
+ while(*pr_file_p && (*pr_file_p==' ' || *pr_file_p == '\t'))
+ pr_file_p++;
+
+ if (!*pr_file_p)
+ {
+ pr_source_line = originalline;
+ QCC_PR_ParseError(ERR_NOENDIF, "#if with no endif");
+ }
+
+ if (*pr_file_p == '#')
+ {
+ pr_file_p++;
+ while(*pr_file_p==' ' || *pr_file_p == '\t')
+ pr_file_p++;
+
+ if (!strncmp(pr_file_p, "endif", 5))
+ level--;
+ if (!strncmp(pr_file_p, "if", 2))
+ level++;
+ if (!strncmp(pr_file_p, "else", 4) && level == 1)
+ {
+ ifs+=1;
+ break;
+ }
+ }
+
+ while(*pr_file_p != '\n' && *pr_file_p != '\0') //read on until the end of the line
+ {
+ pr_file_p++;
+ }
+ if (level <= 0)
+ break;
+ pr_file_p++; //go off the end
+ pr_source_line++;
+ }
+ }
+ else if (!strncmp(directive, "endif", 5))
+ {
+ while(*pr_file_p != '\n' && *pr_file_p != '\0') //read on until the end of the line
+ {
+ pr_file_p++;
+ }
+ if (ifs <= 0)
+ QCC_PR_ParseError(ERR_NOPRECOMPILERIF, "unmatched #endif");
+ else
+ ifs-=1;
+ }
+ else if (!strncmp(directive, "eof", 3))
+ {
+ pr_file_p = NULL;
+ return true;
+ }
+ else if (!strncmp(directive, "error", 5))
+ {
+ pr_file_p = directive+5;
+ for (a = 0; a < 1023 && pr_file_p[a] != '\n' && pr_file_p[a] != '\0'; a++)
+ msg[a] = pr_file_p[a];
+
+ msg[a-1] = '\0';
+
+ while(*pr_file_p != '\n' && *pr_file_p != '\0') //read on until the end of the line, yes, I KNOW we are going to register an error, and not properly leave this function tree, but...
+ {
+ pr_file_p++;
+ }
+
+ QCC_PR_ParseError(ERR_HASHERROR, "#Error: %s", msg);
+ }
+ else if (!strncmp(directive, "warning", 7))
+ {
+ pr_file_p = directive+7;
+ for (a = 0; a < 1023 && pr_file_p[a] != '\n' && pr_file_p[a] != '\0'; a++)
+ msg[a] = pr_file_p[a];
+
+ msg[a-1] = '\0';
+
+ while(*pr_file_p != '\n' && *pr_file_p != '\0') //read on until the end of the line
+ {
+ pr_file_p++;
+ }
+
+ QCC_PR_ParseWarning(WARN_PRECOMPILERMESSAGE, "#warning: %s", msg);
+ }
+ else if (!strncmp(directive, "message", 7))
+ {
+ pr_file_p = directive+7;
+ for (a = 0; a < 1023 && pr_file_p[a] != '\n' && pr_file_p[a] != '\0'; a++)
+ msg[a] = pr_file_p[a];
+
+ msg[a-1] = '\0';
+
+ while(*pr_file_p != '\n' && *pr_file_p != '\0') //read on until the end of the line
+ {
+ pr_file_p++;
+ }
+
+ printf("#message: %s\n", msg);
+ }
+ else if (!strncmp(directive, "copyright", 9))
+ {
+ pr_file_p = directive+9;
+ for (a = 0; a < 1023 && pr_file_p[a] != '\n' && pr_file_p[a] != '\0'; a++)
+ msg[a] = pr_file_p[a];
+
+ msg[a-1] = '\0';
+
+ while(*pr_file_p != '\n' && *pr_file_p != '\0') //read on until the end of the line
+ {
+ pr_file_p++;
+ }
+
+ if (strlen(msg) >= sizeof(QCC_copyright))
+ QCC_PR_ParseWarning(WARN_STRINGTOOLONG, "Copyright message is too long\n");
+ strncpy(QCC_copyright, msg, sizeof(QCC_copyright)-1);
+ }
+ else if (!strncmp(directive, "pack", 4))
+ {
+ ifmode = 0;
+ pr_file_p=directive+4;
+ if (!strncmp(pr_file_p, "id", 2))
+ pr_file_p+=3;
+ else
+ {
+ ifmode = QCC_PR_LexInteger();
+ if (ifmode == 0)
+ ifmode = 1;
+ pr_file_p++;
+ }
+ for (a = 0; a < 1023 && pr_file_p[a] != '\n' && pr_file_p[a] != '\0'; a++)
+ msg[a] = pr_file_p[a];
+
+ msg[a-1] = '\0';
+
+ while(*pr_file_p != '\n' && *pr_file_p != '\0') //read on until the end of the line
+ {
+ pr_file_p++;
+ }
+
+ if (ifmode == 0)
+ QCC_packid = atoi(msg);
+ else if (ifmode <= 5)
+ strcpy(QCC_Packname[ifmode-1], msg);
+ else
+ QCC_PR_ParseError(ERR_TOOMANYPACKFILES, "No more than 5 packs are allowed");
+ }
+ else if (!strncmp(directive, "forcecrc", 8))
+ {
+ pr_file_p=directive+8;
+
+ ForcedCRC = QCC_PR_LexInteger();
+
+ pr_file_p++;
+
+ for (a = 0; a < 1023 && pr_file_p[a] != '\n' && pr_file_p[a] != '\0'; a++)
+ msg[a] = pr_file_p[a];
+
+ msg[a-1] = '\0';
+
+ while(*pr_file_p != '\n' && *pr_file_p != '\0') //read on until the end of the line
+ {
+ pr_file_p++;
+ }
+ }
+ else if (!strncmp(directive, "includelist", 11))
+ {
+ pr_file_p=directive+11;
+
+ while(*pr_file_p <= ' ')
+ pr_file_p++;
+
+ while(1)
+ {
+ QCC_PR_LexWhitespace();
+ if (!QCC_PR_SimpleGetToken())
+ {
+ if (!*pr_file_p)
+ QCC_Error(ERR_EOF, "eof in includelist");
+ else
+ {
+ pr_file_p++;
+ pr_source_line++;
+ }
+ continue;
+ }
+ if (!strcmp(pr_token, "#endlist"))
+ break;
+
+ QCC_FindBestInclude(pr_token, compilingfile, qccmsourcedir);
+
+ if (*pr_file_p == '\r')
+ pr_file_p++;
+
+ for (a = 0; a < 1023 && pr_file_p[a] != '\n' && pr_file_p[a] != '\0'; a++)
+ msg[a] = pr_file_p[a];
+
+ msg[a-1] = '\0';
+
+ while(*pr_file_p != '\n' && *pr_file_p != '\0') //read on until the end of the line
+ {
+ pr_file_p++;
+ }
+ }
+
+ while(*pr_file_p != '\n' && *pr_file_p != '\0') //read on until the end of the line
+ {
+ pr_file_p++;
+ }
+ }
+ else if (!strncmp(directive, "include", 7))
+ {
+ char sm;
+
+ pr_file_p=directive+7;
+
+ while(*pr_file_p <= ' ')
+ pr_file_p++;
+
+ msg[0] = '\0';
+ if (*pr_file_p == '\"')
+ sm = '\"';
+ else if (*pr_file_p == '<')
+ sm = '>';
+ else
+ {
+ QCC_PR_ParseError(0, "Not a string literal (on a #include)");
+ sm = 0;
+ }
+ pr_file_p++;
+ a=0;
+ while(*pr_file_p != sm)
+ {
+ if (*pr_file_p == '\n')
+ {
+ QCC_PR_ParseError(0, "#include continued over line boundy\n");
+ break;
+ }
+ msg[a++] = *pr_file_p;
+ pr_file_p++;
+ }
+ msg[a] = 0;
+
+ QCC_FindBestInclude(msg, compilingfile, qccmsourcedir);
+
+ pr_file_p++;
+
+ while(*pr_file_p != '\n' && *pr_file_p != '\0' && *pr_file_p <= ' ')
+ pr_file_p++;
+
+
+ while(*pr_file_p != '\n' && *pr_file_p != '\0') //read on until the end of the line
+ {
+ pr_file_p++;
+ }
+ }
+ else if (!strncmp(directive, "datafile", 8))
+ {
+ pr_file_p=directive+8;
+
+ while(*pr_file_p <= ' ')
+ pr_file_p++;
+
+ QCC_PR_LexString();
+ printf("Including datafile: %s\n", pr_token);
+ QCC_AddFile(pr_token);
+
+ pr_file_p++;
+
+ for (a = 0; a < 1023 && pr_file_p[a] != '\n' && pr_file_p[a] != '\0'; a++)
+ msg[a] = pr_file_p[a];
+
+ msg[a-1] = '\0';
+
+ while(*pr_file_p != '\n' && *pr_file_p != '\0') //read on until the end of the line
+ {
+ pr_file_p++;
+ }
+ }
+ else if (!strncmp(directive, "output", 6))
+ {
+ extern char destfile[1024];
+ pr_file_p=directive+6;
+
+ while(*pr_file_p <= ' ')
+ pr_file_p++;
+
+ QCC_PR_LexString();
+ strcpy(destfile, pr_token);
+ printf("Outputfile: %s\n", destfile);
+
+ pr_file_p++;
+
+ for (a = 0; a < 1023 && pr_file_p[a] != '\n' && pr_file_p[a] != '\0'; a++)
+ msg[a] = pr_file_p[a];
+
+ msg[a-1] = '\0';
+
+ while(*pr_file_p != '\n' && *pr_file_p != '\0') //read on until the end of the line
+ {
+ pr_file_p++;
+ }
+ }
+ else if (!strncmp(directive, "pragma", 6))
+ {
+ pr_file_p=directive+6;
+ while(*pr_file_p <= ' ')
+ pr_file_p++;
+
+ qcc_token[0] = '\0';
+ for(a = 0; *pr_file_p != '\n' && *pr_file_p != '\0'; pr_file_p++) //read on until the end of the line
+ {
+ if ((*pr_file_p == ' ' || *pr_file_p == '\t'|| *pr_file_p == '(') && !*qcc_token)
+ {
+ msg[a] = '\0';
+ strcpy(qcc_token, msg);
+ a=0;
+ continue;
+ }
+ msg[a++] = *pr_file_p;
+ }
+
+ msg[a] = '\0';
+ {
+ char *end;
+ for (end = msg + a-1; end>=msg && *end <= ' '; end--)
+ *end = '\0';
+ }
+
+ if (!*qcc_token)
+ {
+ strcpy(qcc_token, msg);
+ msg[0] = '\0';
+ }
+
+ {
+ char *end;
+ for (end = msg + a-1; end>=msg && *end <= ' '; end--)
+ *end = '\0';
+ }
+
+ if (!QC_strcasecmp(qcc_token, "DONT_COMPILE_THIS_FILE"))
+ {
+ while (*pr_file_p)
+ {
+ while(*pr_file_p != '\n' && *pr_file_p != '\0') //read on until the end of the line
+ pr_file_p++;
+
+ if (*pr_file_p == '\n')
+ {
+ pr_file_p++;
+ QCC_PR_NewLine(false);
+ }
+ }
+ }
+ else if (!QC_strcasecmp(qcc_token, "COPYRIGHT"))
+ {
+ if (strlen(msg) >= sizeof(QCC_copyright))
+ QCC_PR_ParseWarning(WARN_STRINGTOOLONG, "Copyright message is too long\n");
+ strncpy(QCC_copyright, msg, sizeof(QCC_copyright)-1);
+ }
+ else if (!strncmp(qcc_token, "compress", 8))
+ {
+ extern pbool compressoutput;
+ compressoutput = atoi(msg);
+ }
+ else if (!strncmp(qcc_token, "forcecrc", 8))
+ {
+ ForcedCRC = atoi(msg);
+ }
+ else if (!strncmp(qcc_token, "defaultstatic", 13))
+ {
+ defaultstatic = atoi(msg);
+ }
+ else if (!strncmp(qcc_token, "sourcefile", 10))
+ {
+ #define MAXSOURCEFILESLIST 8
+ extern char sourcefileslist[MAXSOURCEFILESLIST][1024];
+ extern int currentsourcefile;
+ extern int numsourcefiles;
+
+ int i;
+
+ QCC_COM_Parse(msg);
+
+ for (i = 0; i < numsourcefiles; i++)
+ {
+ if (!strcmp(sourcefileslist[i], qcc_token))
+ break;
+ }
+ if (i == numsourcefiles)
+ strcpy(sourcefileslist[numsourcefiles++], qcc_token);
+ }
+ else if (!QC_strcasecmp(qcc_token, "TARGET"))
+ {
+ if (qcc_targetformat == QCF_HEXEN2 && numstatements)
+ QCC_PR_ParseWarning(WARN_BADTARGET, "Cannot switch from hexen2 target \'%s\'. Ignored.", msg);
+ else if (!QC_strcasecmp(msg, "H2") || !QC_strcasecmp(msg, "HEXEN2"))
+ {
+ if (numstatements)
+ QCC_PR_ParseWarning(WARN_BADTARGET, "Cannot switch from hexen2 target \'%s\'. Ignored.", msg);
+ else
+ qcc_targetformat = QCF_HEXEN2;
+ }
+ else if (!QC_strcasecmp(msg, "KK7"))
+ qcc_targetformat = QCF_KK7;
+ else if (!QC_strcasecmp(msg, "DP") || !QC_strcasecmp(msg, "DARKPLACES"))
+ qcc_targetformat = QCF_DARKPLACES;
+ else if (!QC_strcasecmp(msg, "FTEDEBUG"))
+ qcc_targetformat = QCF_FTEDEBUG;
+ else if (!QC_strcasecmp(msg, "FTE"))
+ qcc_targetformat = QCF_FTE;
+ else if (!QC_strcasecmp(msg, "STANDARD") || !QC_strcasecmp(msg, "ID"))
+ qcc_targetformat = QCF_STANDARD;
+ else if (!QC_strcasecmp(msg, "DEBUG"))
+ qcc_targetformat = QCF_FTEDEBUG;
+ else
+ QCC_PR_ParseWarning(WARN_BADTARGET, "Unknown target \'%s\'. Ignored.", msg);
+ }
+ else if (!QC_strcasecmp(qcc_token, "PROGS_SRC"))
+ { //doesn't make sence, but silenced if you are switching between using a certain precompiler app used with CuTF.
+ }
+ else if (!QC_strcasecmp(qcc_token, "PROGS_DAT"))
+ { //doesn't make sence, but silenced if you are switching between using a certain precompiler app used with CuTF.
+ extern char destfile[1024];
+#ifndef QCCONLY
+ extern char qccmfilename[1024];
+ int p;
+ char *s, *s2;
+#endif
+ QCC_COM_Parse(msg);
+
+#ifndef QCCONLY
+ p=0;
+ s2 = qcc_token;
+ if (!strncmp(s2, "./", 2))
+ s2+=2;
+ else
+ {
+ while(!strncmp(s2, "../", 3))
+ {
+ s2+=3;
+ p++;
+ }
+ }
+ strcpy(qccmfilename, qccmsourcedir);
+ for (s=qccmfilename+strlen(qccmfilename);p && s>=qccmfilename; s--)
+ {
+ if (*s == '/' || *s == '\\')
+ {
+ *(s+1) = '\0';
+ p--;
+ }
+ }
+ sprintf(destfile, "%s", s2);
+
+ while (p>0)
+ {
+ memmove(destfile+3, destfile, strlen(destfile)+1);
+ destfile[0] = '.';
+ destfile[1] = '.';
+ destfile[2] = '/';
+ p--;
+ }
+#else
+
+ strcpy(destfile, qcc_token);
+#endif
+ printf("Outputfile: %s\n", destfile);
+ }
+ else if (!QC_strcasecmp(qcc_token, "keyword") || !QC_strcasecmp(qcc_token, "flag"))
+ {
+ char *s;
+ int st;
+ s = QCC_COM_Parse(msg);
+ if (!QC_strcasecmp(qcc_token, "enable") || !QC_strcasecmp(qcc_token, "on"))
+ st = 1;
+ else if (!QC_strcasecmp(qcc_token, "disable") || !QC_strcasecmp(qcc_token, "off"))
+ st = 0;
+ else
+ {
+ QCC_PR_ParseWarning(WARN_BADPRAGMA, "compiler flag state not recognised");
+ st = -1;
+ }
+ if (st < 0)
+ QCC_PR_ParseWarning(WARN_BADPRAGMA, "warning id not recognised");
+ else
+ {
+ int f;
+ s = QCC_COM_Parse(s);
+
+ for (f = 0; compiler_flag[f].enabled; f++)
+ {
+ if (!QC_strcasecmp(compiler_flag[f].abbrev, qcc_token))
+ {
+ if (compiler_flag[f].flags & FLAG_MIDCOMPILE)
+ *compiler_flag[f].enabled = st;
+ else
+ QCC_PR_ParseWarning(WARN_BADPRAGMA, "Cannot enable/disable keyword/flag via a pragma");
+ break;
+ }
+ }
+ if (!compiler_flag[f].enabled)
+ QCC_PR_ParseWarning(WARN_BADPRAGMA, "keyword/flag not recognised");
+
+ }
+ }
+ else if (!QC_strcasecmp(qcc_token, "warning"))
+ {
+ int st;
+ char *s;
+ s = QCC_COM_Parse(msg);
+ if (!stricmp(qcc_token, "enable") || !stricmp(qcc_token, "on"))
+ st = 0;
+ else if (!stricmp(qcc_token, "disable") || !stricmp(qcc_token, "off"))
+ st = 1;
+ else if (!stricmp(qcc_token, "toggle"))
+ st = 2;
+ else
+ {
+ QCC_PR_ParseWarning(WARN_BADPRAGMA, "warning state not recognised");
+ st = -1;
+ }
+ if (st>=0)
+ {
+ int wn;
+ s = QCC_COM_Parse(s);
+ wn = QCC_WarningForName(qcc_token);
+ if (wn < 0)
+ QCC_PR_ParseWarning(WARN_BADPRAGMA, "warning id not recognised");
+ else
+ {
+ if (st == 2) //toggle
+ qccwarningdisabled[wn] = true - qccwarningdisabled[wn];
+ else
+ qccwarningdisabled[wn] = st;
+ }
+ }
+ }
+ else
+ QCC_PR_ParseWarning(WARN_BADPRAGMA, "Unknown pragma \'%s\'", qcc_token);
+ }
+ return true;
+ }
+
+ return false;
+}
+
+/*
+==============
+PR_NewLine
+
+Call at start of file and when *pr_file_p == '\n'
+==============
+*/
+void QCC_PR_NewLine (pbool incomment)
+{
+ pr_source_line++;
+ pr_line_start = pr_file_p;
+ while(*pr_file_p==' ' || *pr_file_p == '\t')
+ pr_file_p++;
+ if (incomment) //no constants if in a comment.
+ {
+ }
+ else if (QCC_PR_Precompiler())
+ {
+ }
+
+// if (pr_dumpasm)
+// PR_PrintNextLine ();
+}
+
+/*
+==============
+PR_LexString
+
+Parses a quoted string
+==============
+*/
+#if 0
+void QCC_PR_LexString (void)
+{
+ int c;
+ int len;
+ char tmpbuf[2048];
+
+ char *text;
+ char *oldf;
+ int oldline;
+
+ bool fromfile = true;
+
+ len = 0;
+
+ text = pr_file_p;
+ do
+ {
+ QCC_COM_Parse(text);
+// print("Next token is \"%s\"\n", com_token);
+ if (*text == '\"')
+ {
+ text++;
+ if (fromfile) pr_file_p++;
+ }
+ do
+ {
+ c = *text++;
+ if (fromfile) pr_file_p++;
+ if (!c)
+ QCC_PR_ParseError ("EOF inside quote");
+ if (c=='\n')
+ QCC_PR_ParseError ("newline inside quote");
+ if (c=='\\')
+ { // escape char
+ c = *text++;
+ if (fromfile) pr_file_p++;
+ if (!c)
+ QCC_PR_ParseError ("EOF inside quote");
+ if (c == 'n')
+ c = '\n';
+ else if (c == '"')
+ c = '"';
+ else if (c == '\\')
+ c = '\\';
+ else
+ QCC_PR_ParseError ("Unknown escape char");
+ }
+ else if (c=='\"')
+ {
+ if (fromfile) pr_file_p++;
+ break;
+ }
+ tmpbuf[len] = c;
+ len++;
+ } while (1);
+ tmpbuf[len] = 0;
+// if (fromfile) pr_file_p++;
+
+ pr_immediate_type=NULL;
+ oldline=pr_source_line;
+ oldf=pr_file_p;
+ QCC_PR_Lex();
+ if (pr_immediate_type == &type_string)
+ {
+// print("Appending \"%s\" to \"%s\"\n", pr_immediate_string, tmpbuf);
+ strcat(tmpbuf, pr_immediate_string);
+ len+=strlen(pr_immediate_string);
+ }
+ else
+ {
+ pr_source_line = oldline;
+ pr_file_p = oldf-1;
+ QCC_PR_LexWhitespace();
+ if (*pr_file_p != '\"') //annother string
+ break;
+ }
+
+ QCC_PR_LexWhitespace();
+ text = pr_file_p;
+
+ } while (1);
+
+ strcpy(pr_token, tmpbuf);
+ pr_token_type = tt_immediate;
+ pr_immediate_type = &type_string;
+ strcpy (pr_immediate_string, pr_token);
+
+// print("Found \"%s\"\n", pr_immediate_string);
+}
+#else
+void QCC_PR_LexString (void)
+{
+ int c;
+ int len;
+ char *end, *cnst;
+
+ int texttype=0;
+
+ len = 0;
+ pr_file_p++;
+ do
+ {
+ c = *pr_file_p++;
+ if (!c)
+ QCC_PR_ParseError (ERR_EOF, "EOF inside quote");
+ if (c=='\n')
+ QCC_PR_ParseError (ERR_INVALIDSTRINGIMMEDIATE, "newline inside quote");
+ if (c=='\\')
+ { // escape char
+ c = *pr_file_p++;
+ if (!c)
+ QCC_PR_ParseError (ERR_EOF, "EOF inside quote");
+ if (c == 'n')
+ c = '\n';
+ else if (c == 'r')
+ c = '\r';
+ else if (c == '"')
+ c = '"';
+ else if (c == 't')
+ c = '\t';
+ else if (c == 'a')
+ c = '\a';
+ else if (c == 'v')
+ c = '\v';
+ else if (c == 'f')
+ c = '\f';
+ else if (c == 's' || c == 'b')
+ {
+ texttype ^= 128;
+ continue;
+ }
+ else if (c == '[')
+ c = 16;
+ else if (c == ']')
+ c = 17;
+ else if (c == '{')
+ {
+ int d;
+ c = 0;
+ while ((d = *pr_file_p++) != '}')
+ {
+ c = c * 10 + d - '0';
+ if (d < '0' || d > '9' || c > 255)
+ QCC_PR_ParseError(ERR_BADCHARACTERCODE, "Bad character code");
+ }
+ }
+ else if (c == '<')
+ c = 29;
+ else if (c == '-')
+ c = 30;
+ else if (c == '>')
+ c = 31;
+ else if (c == 'x' || c == 'X')
+ {
+ int d;
+ c = 0;
+
+ d = (unsigned char)*pr_file_p++;
+ if (d >= '0' && d <= '9')
+ c += d - '0';
+ else if (d >= 'A' && d <= 'F')
+ c += d - 'A' + 10;
+ else if (d >= 'a' && d <= 'f')
+ c += d - 'a' + 10;
+ else
+ QCC_PR_ParseError(ERR_BADCHARACTERCODE, "Bad character code");
+
+ c *= 16;
+
+ d = (unsigned char)*pr_file_p++;
+ if (d >= '0' && d <= '9')
+ c += d - '0';
+ else if (d >= 'A' && d <= 'F')
+ c += d - 'A' + 10;
+ else if (d >= 'a' && d <= 'f')
+ c += d - 'a' + 10;
+ else
+ QCC_PR_ParseError(ERR_BADCHARACTERCODE, "Bad character code");
+ }
+ else if (c == '\\')
+ c = '\\';
+ else if (c == '\'')
+ c = '\'';
+ else if (c >= '0' && c <= '9')
+ c = 18 + c - '0';
+ else if (c == '\r')
+ { //sigh
+ c = *pr_file_p++;
+ if (c != '\n')
+ QCC_PR_ParseWarning(WARN_HANGINGSLASHR, "Hanging \\\\\r");
+ pr_source_line++;
+ }
+ else if (c == '\n')
+ { //sigh
+ pr_source_line++;
+ }
+ else
+ QCC_PR_ParseError (ERR_INVALIDSTRINGIMMEDIATE, "Unknown escape char %c", c);
+ }
+ else if (c=='\"')
+ {
+ if (len >= sizeof(pr_immediate_string)-1)
+ QCC_Error(ERR_INVALIDSTRINGIMMEDIATE, "String length exceeds %i", sizeof(pr_immediate_string)-1);
+
+ while(*pr_file_p && *pr_file_p <= ' ')
+ {
+ if (*pr_file_p == '\n')
+ {
+ pr_file_p++;
+ QCC_PR_NewLine(false);
+ }
+ else
+ pr_file_p++;
+ }
+ if (*pr_file_p == '\"') //have annother go
+ {
+ pr_file_p++;
+ continue;
+ }
+ pr_token[len] = 0;
+ pr_token_type = tt_immediate;
+ pr_immediate_type = type_string;
+ strcpy (pr_immediate_string, pr_token);
+ return;
+ }
+ else if (c == '#')
+ {
+ for (end = pr_file_p; ; end++)
+ {
+ if (*end <= ' ')
+ break;
+
+ if (*end == ')'
+ || *end == '('
+ || *end == '+'
+ || *end == '-'
+ || *end == '*'
+ || *end == '/'
+ || *end == '\\'
+ || *end == '|'
+ || *end == '&'
+ || *end == '='
+ || *end == '^'
+ || *end == '~'
+ || *end == '['
+ || *end == ']'
+ || *end == '\"'
+ || *end == '{'
+ || *end == '}'
+ || *end == ';'
+ || *end == ':'
+ || *end == ','
+ || *end == '.'
+ || *end == '#')
+ break;
+ }
+
+ c = *end;
+ *end = '\0';
+ cnst = QCC_PR_CheakCompConstString(pr_file_p);
+ if (cnst==pr_file_p)
+ cnst=NULL;
+ *end = c;
+ c = '#'; //undo
+ if (cnst)
+ {
+ QCC_PR_ParseWarning(WARN_MACROINSTRING, "Macro expansion in string");
+
+ if (len+strlen(cnst) >= sizeof(pr_token)-1)
+ QCC_Error(ERR_INVALIDSTRINGIMMEDIATE, "String length exceeds %i", sizeof(pr_token)-1);
+
+ strcpy(pr_token+len, cnst);
+ len+=strlen(cnst);
+ pr_file_p = end;
+ continue;
+ }
+ }
+ else if (c == 0x7C && flag_acc) //reacc support... reacc is strange.
+ c = '\n';
+ else
+ c |= texttype;
+
+ pr_token[len] = c;
+ len++;
+ if (len >= sizeof(pr_token)-1)
+ QCC_Error(ERR_INVALIDSTRINGIMMEDIATE, "String length exceeds %i", sizeof(pr_token)-1);
+ } while (1);
+}
+#endif
+
+/*
+==============
+PR_LexNumber
+==============
+*/
+int QCC_PR_LexInteger (void)
+{
+ int c;
+ int len;
+
+ len = 0;
+ c = *pr_file_p;
+ if (pr_file_p[0] == '0' && pr_file_p[1] == 'x')
+ {
+ pr_token[0] = '0';
+ pr_token[1] = 'x';
+ len = 2;
+ c = *(pr_file_p+=2);
+ }
+ do
+ {
+ pr_token[len] = c;
+ len++;
+ pr_file_p++;
+ c = *pr_file_p;
+ } while ((c >= '0' && c<= '9') || c == '.' || (c>='a' && c <= 'f'));
+ pr_token[len] = 0;
+ return atoi (pr_token);
+}
+
+void QCC_PR_LexNumber (void)
+{
+ int tokenlen = 0;
+ int num=0;
+ int base=0;
+ int c;
+ int sign=1;
+ if (*pr_file_p == '-')
+ {
+ sign=-1;
+ pr_file_p++;
+
+ pr_token[tokenlen++] = '-';
+ }
+ if (pr_file_p[0] == '0' && pr_file_p[1] == 'x')
+ {
+ pr_file_p+=2;
+ base = 16;
+
+ pr_token[tokenlen++] = '0';
+ pr_token[tokenlen++] = 'x';
+ }
+
+ pr_immediate_type = NULL;
+ //assume base 10 if not stated
+ if (!base)
+ base = 10;
+
+ while((c = *pr_file_p))
+ {
+ if (c >= '0' && c <= '9')
+ {
+ pr_token[tokenlen++] = c;
+ num*=base;
+ num += c-'0';
+ }
+ else if (c >= 'a' && c <= 'f' && base > 10)
+ {
+ pr_token[tokenlen++] = c;
+ num*=base;
+ num += c -'a'+10;
+ }
+ else if (c >= 'A' && c <= 'F' && base > 10)
+ {
+ pr_token[tokenlen++] = c;
+ num*=base;
+ num += c -'A'+10;
+ }
+ else if (c == '.')
+ {
+ pr_token[tokenlen++] = c;
+ pr_file_p++;
+ pr_immediate_type = type_float;
+ while(1)
+ {
+ c = *pr_file_p;
+ if (c >= '0' && c <= '9')
+ {
+ pr_token[tokenlen++] = c;
+ }
+ else if (c == 'f')
+ {
+ pr_file_p++;
+ break;
+ }
+ else
+ {
+ break;
+ }
+ pr_file_p++;
+ }
+ pr_token[tokenlen++] = 0;
+ pr_immediate._float = (float)atof(pr_token);
+ return;
+ }
+ else if (c == 'i')
+ {
+ pr_token[tokenlen++] = c;
+ pr_token[tokenlen++] = 0;
+ pr_file_p++;
+ pr_immediate_type = type_integer;
+ pr_immediate._int = num*sign;
+ return;
+ }
+ else
+ break;
+ pr_file_p++;
+ }
+ pr_token[tokenlen++] = 0;
+
+ if (!pr_immediate_type)
+ {
+ if (flag_assume_integer)
+ pr_immediate_type = type_integer;
+ else
+ pr_immediate_type = type_float;
+ }
+
+ if (pr_immediate_type == type_integer)
+ {
+ pr_immediate_type = type_integer;
+ pr_immediate._int = num*sign;
+ }
+ else
+ {
+ pr_immediate_type = type_float;
+ // at this point, we know there's no . in it, so the NaN bug shouldn't happen
+ // and we cannot use atof on tokens like 0xabc, so use num*sign, it SHOULD be safe
+ //pr_immediate._float = atof(pr_token);
+ pr_immediate._float = (float)(num*sign);
+ }
+}
+
+
+float QCC_PR_LexFloat (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_file_p[1]!='.')); //only allow a . if the next isn't too...
+ pr_token[len] = 0;
+ return (float)atof (pr_token);
+}
+
+/*
+==============
+PR_LexVector
+
+Parses a single quoted vector
+==============
+*/
+void QCC_PR_LexVector (void)
+{
+ int i;
+
+ pr_file_p++;
+
+ if (*pr_file_p == '\\')
+ {//extended character constant
+ pr_token_type = tt_immediate;
+ pr_immediate_type = type_float;
+ pr_file_p++;
+ switch(*pr_file_p)
+ {
+ case 'n':
+ pr_immediate._float = '\n';
+ break;
+ case 'r':
+ pr_immediate._float = '\r';
+ break;
+ case 't':
+ pr_immediate._float = '\t';
+ break;
+ case '\'':
+ pr_immediate._float = '\'';
+ break;
+ case '\"':
+ pr_immediate._float = '\"';
+ break;
+ case '\\':
+ pr_immediate._float = '\\';
+ break;
+ default:
+ QCC_PR_ParseError (ERR_INVALIDVECTORIMMEDIATE, "Bad character constant");
+ }
+ if (*pr_file_p != '\'')
+ QCC_PR_ParseError (ERR_INVALIDVECTORIMMEDIATE, "Bad character constant");
+ pr_file_p++;
+ return;
+ }
+ if (pr_file_p[1] == '\'')
+ {//character constant
+ pr_token_type = tt_immediate;
+ pr_immediate_type = type_float;
+ pr_immediate._float = pr_file_p[0];
+ pr_file_p+=2;
+ return;
+ }
+ pr_token_type = tt_immediate;
+ pr_immediate_type = type_vector;
+ QCC_PR_LexWhitespace ();
+ for (i=0 ; i<3 ; i++)
+ {
+ pr_immediate.vector[i] = QCC_PR_LexFloat ();
+ QCC_PR_LexWhitespace ();
+
+ if (*pr_file_p == '\'' && i == 1)
+ {
+ if (i < 2)
+ QCC_PR_ParseWarning (WARN_FTE_SPECIFIC, "Bad vector");
+
+ for (i++ ; i<3 ; i++)
+ pr_immediate.vector[i] = 0;
+ break;
+ }
+ }
+ if (*pr_file_p != '\'')
+ QCC_PR_ParseError (ERR_INVALIDVECTORIMMEDIATE, "Bad vector");
+ pr_file_p++;
+}
+
+/*
+==============
+PR_LexName
+
+Parses an identifier
+==============
+*/
+void QCC_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 QCC_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, pr_punctuationremap[i]);
+ if (p[0] == '{')
+ pr_bracelevel++;
+ else if (p[0] == '}')
+ pr_bracelevel--;
+ pr_file_p += len;
+ return;
+ }
+ }
+
+ QCC_PR_ParseError (ERR_UNKNOWNPUCTUATION, "Unknown punctuation");
+}
+
+
+/*
+==============
+PR_LexWhitespace
+==============
+*/
+void QCC_PR_LexWhitespace (void)
+{
+ int c;
+
+ while (1)
+ {
+ // skip whitespace
+ while ( (c = *pr_file_p) <= ' ')
+ {
+ if (c=='\n')
+ {
+ pr_file_p++;
+ QCC_PR_NewLine (false);
+ if (!pr_file_p)
+ return;
+ }
+ else
+ {
+ 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++;
+
+ if (*pr_file_p == '\n')
+ pr_file_p++; //don't break on eof.
+ QCC_PR_NewLine(false);
+ continue;
+ }
+
+ // skip /* */ comments
+ if (c=='/' && pr_file_p[1] == '*')
+ {
+ pr_file_p+=2;
+ do
+ {
+ if (pr_file_p[0]=='\n')
+ {
+ QCC_PR_NewLine(true);
+ }
+ if (pr_file_p[1] == 0)
+ {
+ pr_file_p++;
+ return;
+ }
+ pr_file_p++;
+ } while (pr_file_p[0] != '*' || pr_file_p[1] != '/');
+ pr_file_p+=2;
+ continue;
+ }
+
+ break; // a real character has been found
+ }
+}
+
+//============================================================================
+
+#define MAX_FRAMES 8192
+char pr_framemodelname[64];
+char pr_framemacros[MAX_FRAMES][64];
+int pr_framemacrovalue[MAX_FRAMES];
+int pr_nummacros, pr_oldmacros;
+int pr_macrovalue;
+int pr_savedmacro;
+
+void QCC_PR_ClearGrabMacros (void)
+{
+ pr_oldmacros = pr_nummacros;
+// pr_nummacros = 0;
+ pr_macrovalue = 0;
+ pr_savedmacro = -1;
+}
+
+int QCC_PR_FindMacro (char *name)
+{
+ int i;
+
+ for (i=pr_nummacros-1 ; i>=0 ; i--)
+ {
+ if (!STRCMP (name, pr_framemacros[i]))
+ {
+ return pr_framemacrovalue[i];
+ }
+ }
+ for (i=pr_nummacros-1 ; i>=0 ; i--)
+ {
+ if (!stricmp (name, pr_framemacros[i]))
+ {
+ QCC_PR_ParseWarning(WARN_CASEINSENSATIVEFRAMEMACRO, "Case insensative frame macro");
+ return pr_framemacrovalue[i];
+ }
+ }
+ return -1;
+}
+
+void QCC_PR_ExpandMacro(void)
+{
+ int i = QCC_PR_FindMacro(pr_token);
+
+ if (i < 0)
+ QCC_PR_ParseError (ERR_BADFRAMEMACRO, "Unknown frame macro $%s", pr_token);
+
+ sprintf (pr_token,"%d", i);
+ pr_token_type = tt_immediate;
+ pr_immediate_type = type_float;
+ pr_immediate._float = (float)i;
+}
+
+// just parses text, returning false if an eol is reached
+pbool QCC_PR_SimpleGetToken (void)
+{
+ int c;
+ int i;
+
+ pr_token[0] = 0;
+
+// skip whitespace
+ while ( (c = *pr_file_p) <= ' ')
+ {
+ if (c=='\n' || c == 0)
+ return false;
+ pr_file_p++;
+ }
+ if (pr_file_p[0] == '/')
+ {
+ if (pr_file_p[1] == '/')
+ { //comment alert
+ while(*pr_file_p && *pr_file_p != '\n')
+ pr_file_p++;
+ return false;
+ }
+ if (pr_file_p[1] == '*')
+ return false;
+ }
+
+ i = 0;
+ while ( (c = *pr_file_p) > ' ' && c != ',' && c != ';' && c != ')' && c != '(' && c != ']')
+ {
+ pr_token[i] = c;
+ i++;
+ pr_file_p++;
+ }
+ pr_token[i] = 0;
+ return i!=0;
+}
+
+pbool QCC_PR_LexMacroName(void)
+{
+ int c;
+ int i;
+
+ pr_token[0] = 0;
+
+// skip whitespace
+ while ( (c = *pr_file_p) <= ' ')
+ {
+ if (c=='\n' || c == 0)
+ return false;
+ pr_file_p++;
+ }
+ if (pr_file_p[0] == '/')
+ {
+ if (pr_file_p[1] == '/')
+ { //comment alert
+ while(*pr_file_p && *pr_file_p != '\n')
+ pr_file_p++;
+ return false;
+ }
+ if (pr_file_p[1] == '*')
+ return false;
+ }
+
+ i = 0;
+ while ( (c = *pr_file_p) > ' ' && c != '\n' && c != ',' && c != ';' && c != ')' && c != '(' && c != ']' && !(pr_file_p[0] == '.' && pr_file_p[1] == '.'))
+ {
+ pr_token[i] = c;
+ i++;
+ pr_file_p++;
+ }
+ pr_token[i] = 0;
+ return i!=0;
+}
+
+void QCC_PR_MacroFrame(char *name, int value)
+{
+ int i;
+ for (i=pr_nummacros-1 ; i>=0 ; i--)
+ {
+ if (!STRCMP (name, pr_framemacros[i]))
+ {
+ pr_framemacrovalue[i] = value;
+ if (i>=pr_oldmacros)
+ QCC_PR_ParseWarning(WARN_DUPLICATEMACRO, "Duplicate macro defined (%s)", pr_token);
+ //else it's from an old file, and shouldn't be mentioned.
+ return;
+ }
+ }
+
+ if (strlen(name)+1 > sizeof(pr_framemacros[0]))
+ QCC_PR_ParseWarning(ERR_TOOMANYFRAMEMACROS, "Name for frame macro %s is too long", name);
+ else
+ {
+ strcpy (pr_framemacros[pr_nummacros], name);
+ pr_framemacrovalue[pr_nummacros] = value;
+ pr_nummacros++;
+ if (pr_nummacros >= MAX_FRAMES)
+ QCC_PR_ParseError(ERR_TOOMANYFRAMEMACROS, "Too many frame macros defined");
+ }
+}
+
+void QCC_PR_ParseFrame (void)
+{
+ while (QCC_PR_LexMacroName ())
+ {
+ QCC_PR_MacroFrame(pr_token, pr_macrovalue++);
+ }
+}
+
+/*
+==============
+PR_LexGrab
+
+Deals with counting sequence numbers and replacing frame macros
+==============
+*/
+void QCC_PR_LexGrab (void)
+{
+ pr_file_p++; // skip the $
+// if (!QCC_PR_SimpleGetToken ())
+// QCC_PR_ParseError ("hanging $");
+ if (*pr_file_p <= ' ')
+ QCC_PR_ParseError (ERR_BADFRAMEMACRO, "hanging $");
+ QCC_PR_LexMacroName();
+ if (!*pr_token)
+ QCC_PR_ParseError (ERR_BADFRAMEMACRO, "hanging $");
+
+// check for $frame
+ if (!STRCMP (pr_token, "frame") || !STRCMP (pr_token, "framesave"))
+ {
+ QCC_PR_ParseFrame ();
+ QCC_PR_Lex ();
+ }
+// ignore other known $commands - just for model/spritegen
+ 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 (QCC_PR_LexMacroName ())
+ ;
+ QCC_PR_Lex ();
+ }
+ else if (!STRCMP (pr_token, "flush"))
+ {
+ QCC_PR_ClearGrabMacros();
+ while (QCC_PR_LexMacroName ())
+ ;
+ QCC_PR_Lex ();
+ }
+ else if (!STRCMP (pr_token, "framevalue"))
+ {
+ QCC_PR_LexMacroName ();
+ pr_macrovalue = atoi(pr_token);
+
+ QCC_PR_Lex ();
+ }
+ else if (!STRCMP (pr_token, "framerestore"))
+ {
+ QCC_PR_LexMacroName ();
+ QCC_PR_ExpandMacro();
+ pr_macrovalue = (int)pr_immediate._float;
+
+ QCC_PR_Lex ();
+ }
+ else if (!STRCMP (pr_token, "modelname"))
+ {
+ int i;
+ QCC_PR_LexMacroName ();
+
+ if (*pr_framemodelname)
+ QCC_PR_MacroFrame(pr_framemodelname, pr_macrovalue);
+
+ strncpy(pr_framemodelname, pr_token, sizeof(pr_framemodelname)-1);
+ pr_framemodelname[sizeof(pr_framemodelname)-1] = '\0';
+
+ i = QCC_PR_FindMacro(pr_framemodelname);
+ if (i)
+ pr_macrovalue = i;
+ else
+ i = 0;
+
+ QCC_PR_Lex ();
+ }
+// look for a frame name macro
+ else
+ QCC_PR_ExpandMacro ();
+}
+
+//===========================
+//compiler constants - dmw
+
+pbool QCC_PR_UndefineName(char *name)
+{
+// int a;
+ CompilerConstant_t *c;
+ c = pHash_Get(&compconstantstable, name);
+ if (!c)
+ {
+ QCC_PR_ParseWarning(WARN_UNDEFNOTDEFINED, "Precompiler constant %s was not defined", name);
+ return false;
+ }
+
+ Hash_Remove(&compconstantstable, name);
+ return true;
+ /*
+ a = c-CompilerConstant;
+// for (a = 0; a < numCompilerConstants; a++)
+ {
+// if (!STRCMP(name, CompilerConstant[a].name))
+ {
+ memmove(&CompilerConstant[a], &CompilerConstant[a+1], sizeof(CompilerConstant_t) * (numCompilerConstants-a));
+ numCompilerConstants--;
+
+
+
+
+ if (!STRCMP(name, "OP_NODUP"))
+ qccop_noduplicatestrings = false;
+
+ if (!STRCMP(name, "OP_COMP_ALL")) //group
+ {
+ QCC_PR_UndefineName("OP_COMP_STATEMENTS");
+ QCC_PR_UndefineName("OP_COMP_DEFS");
+ QCC_PR_UndefineName("OP_COMP_FIELDS");
+ QCC_PR_UndefineName("OP_COMP_FUNCTIONS");
+ QCC_PR_UndefineName("OP_COMP_STRINGS");
+ QCC_PR_UndefineName("OP_COMP_GLOBALS");
+ QCC_PR_UndefineName("OP_COMP_LINES");
+ QCC_PR_UndefineName("OP_COMP_TYPES");
+ }
+
+ return true;
+ }
+ }
+// return false;
+*/
+}
+
+CompilerConstant_t *QCC_PR_DefineName(char *name)
+{
+ int i;
+ CompilerConstant_t *cnst;
+
+// if (numCompilerConstants >= MAX_CONSTANTS)
+// QCC_PR_ParseError("Too many compiler constants - %i >= %i", numCompilerConstants, MAX_CONSTANTS);
+
+ if (strlen(name) >= MAXCONSTANTLENGTH || !*name)
+ QCC_PR_ParseError(ERR_CONSTANTTOOLONG, "Compiler constant name length is too long or short");
+
+ cnst = pHash_Get(&compconstantstable, name);
+ if (cnst )
+ {
+ QCC_PR_ParseWarning(WARN_DUPLICATEDEFINITION, "Duplicate definition for Precompiler constant %s", name);
+ Hash_Remove(&compconstantstable, name);
+ }
+
+ cnst = qccHunkAlloc(sizeof(CompilerConstant_t));
+
+ cnst->used = false;
+ cnst->numparams = 0;
+ strcpy(cnst->name, name);
+ cnst->namelen = strlen(name);
+ *cnst->value = '\0';
+ for (i = 0; i < MAXCONSTANTPARAMS; i++)
+ cnst->params[i][0] = '\0';
+
+ pHash_Add(&compconstantstable, cnst->name, cnst, qccHunkAlloc(sizeof(bucket_t)));
+
+ if (!STRCMP(name, "OP_NODUP"))
+ opt_noduplicatestrings = true;
+
+
+ if (!STRCMP(name, "OP_TIME")) //group - optimize for a fast compiler
+ {
+ QCC_PR_UndefineName("OP_SIZE");
+ QCC_PR_UndefineName("OP_SPEED");
+
+ QCC_PR_UndefineName("OP_NODUP");
+ QCC_PR_UndefineName("OP_COMP_ALL");
+ }
+
+ if (!STRCMP(name, "OP_SPEED")) //group - optimize run speed
+ {
+ QCC_PR_UndefineName("OP_SIZE");
+ QCC_PR_UndefineName("OP_TIME");
+
+// QCC_PR_UndefineName("OP_NODUP");
+ QCC_PR_UndefineName("OP_COMP_ALL");
+ }
+
+ if (!STRCMP(name, "OP_SIZE")) //group - produce small output.
+ {
+ QCC_PR_UndefineName("OP_SPEED");
+ QCC_PR_UndefineName("OP_TIME");
+
+ QCC_PR_DefineName("OP_NODUP");
+ QCC_PR_DefineName("OP_COMP_ALL");
+ }
+
+ if (!STRCMP(name, "OP_COMP_ALL")) //group - compress the output
+ {
+ QCC_PR_DefineName("OP_COMP_STATEMENTS");
+ QCC_PR_DefineName("OP_COMP_DEFS");
+ QCC_PR_DefineName("OP_COMP_FIELDS");
+ QCC_PR_DefineName("OP_COMP_FUNCTIONS");
+ QCC_PR_DefineName("OP_COMP_STRINGS");
+ QCC_PR_DefineName("OP_COMP_GLOBALS");
+ QCC_PR_DefineName("OP_COMP_LINES");
+ QCC_PR_DefineName("OP_COMP_TYPES");
+ }
+
+
+
+ return cnst;
+}
+
+void QCC_PR_Undefine(void)
+{
+ QCC_PR_SimpleGetToken ();
+
+ QCC_PR_UndefineName(pr_token);
+// QCC_PR_ParseError("%s was not defined.", pr_token);
+}
+
+void QCC_PR_ConditionCompilation(void)
+{
+ char *oldval;
+ char *d;
+ char *s;
+ int quote=false;
+ CompilerConstant_t *cnst;
+
+ QCC_PR_SimpleGetToken ();
+
+ if (!QCC_PR_SimpleGetToken ())
+ QCC_PR_ParseError(ERR_NONAME, "No name defined for compiler constant");
+
+ cnst = pHash_Get(&compconstantstable, pr_token);
+ if (cnst)
+ {
+ oldval = cnst->value;
+ Hash_Remove(&compconstantstable, pr_token);
+ }
+ else
+ oldval = NULL;
+
+ cnst = QCC_PR_DefineName(pr_token);
+
+ if (*pr_file_p == '(')
+ {
+ s = pr_file_p+1;
+ while(*pr_file_p++)
+ {
+ if (*pr_file_p == ',')
+ {
+ if (cnst->numparams >= MAXCONSTANTPARAMS)
+ QCC_PR_ParseError(ERR_MACROTOOMANYPARMS, "May not have more than %i parameters to a macro", MAXCONSTANTPARAMS);
+ strncpy(cnst->params[cnst->numparams], s, pr_file_p-s);
+ cnst->params[cnst->numparams][pr_file_p-s] = '\0';
+ cnst->numparams++;
+ pr_file_p++;
+ s = pr_file_p;
+ }
+ if (*pr_file_p == ')')
+ {
+ if (cnst->numparams >= MAXCONSTANTPARAMS)
+ QCC_PR_ParseError(ERR_MACROTOOMANYPARMS, "May not have more than %i parameters to a macro", MAXCONSTANTPARAMS);
+ strncpy(cnst->params[cnst->numparams], s, pr_file_p-s);
+ cnst->params[cnst->numparams][pr_file_p-s] = '\0';
+ cnst->numparams++;
+ pr_file_p++;
+ break;
+ }
+ }
+ }
+ else cnst->numparams = -1;
+
+ s = pr_file_p;
+ d = cnst->value;
+ while(*s == ' ' || *s == '\t')
+ s++;
+ while(1)
+ {
+ if( *s == '\\' )
+ {
+ // read over a newline if necessary
+ if( s[1] == '\n' || s[1] == '\r' )
+ {
+ s++;
+ QCC_PR_NewLine(false);
+ *d++ = *s++;
+ if( s[-1] == '\r' && s[0] == '\n' )
+ {
+ *d++ = *s++;
+ }
+ }
+ }
+ else if(*s == '\r' || *s == '\n' || *s == '\0')
+ {
+ break;
+ }
+
+ if (!quote && s[0]=='/'&&(s[1]=='/'||s[1]=='*'))
+ break;
+ if (*s == '\"')
+ quote=!quote;
+
+ *d = *s;
+ d++;
+ s++;
+ }
+ *d = '\0';
+ d--;
+ while(*d<= ' ' && d >= cnst->value)
+ *d-- = '\0';
+ if (strlen(cnst->value) >= sizeof(cnst->value)) //this is too late.
+ QCC_PR_ParseError(ERR_CONSTANTTOOLONG, "Macro %s too long (%i not %i)", cnst->name, strlen(cnst->value), sizeof(cnst->value));
+
+ if (oldval)
+ { //we always warn if it was already defined
+ //we use different warning codes so that -Wno-mundane can be used to ignore identical redefinitions.
+ if (strcmp(oldval, cnst->value))
+ QCC_PR_ParseWarning(WARN_DUPLICATEPRECOMPILER, "Alternate precompiler definition of %s", pr_token);
+ else
+ QCC_PR_ParseWarning(WARN_IDENTICALPRECOMPILER, "Identical precompiler definition of %s", pr_token);
+ }
+
+ pr_file_p = s;
+}
+
+int QCC_PR_CheakCompConst(void)
+{
+ char *oldpr_file_p = pr_file_p;
+ int whitestart;
+
+ CompilerConstant_t *c;
+
+ char *end;
+ for (end = pr_file_p; ; end++)
+ {
+ if (*end <= ' ')
+ break;
+
+ if (*end == ')'
+ || *end == '('
+ || *end == '+'
+ || *end == '-'
+ || *end == '*'
+ || *end == '/'
+ || *end == '|'
+ || *end == '&'
+ || *end == '='
+ || *end == '^'
+ || *end == '~'
+ || *end == '['
+ || *end == ']'
+ || *end == '\"'
+ || *end == '{'
+ || *end == '}'
+ || *end == ';'
+ || *end == ':'
+ || *end == ','
+ || *end == '.'
+ || *end == '#')
+ break;
+ }
+ strncpy(pr_token, pr_file_p, end-pr_file_p);
+ pr_token[end-pr_file_p]='\0';
+
+// printf("%s\n", pr_token);
+ c = pHash_Get(&compconstantstable, pr_token);
+
+ if (c && !c->inside)
+ {
+ pr_file_p = oldpr_file_p+strlen(c->name);
+ while(*pr_file_p == ' ' || *pr_file_p == '\t')
+ pr_file_p++;
+ if (c->numparams>=0)
+ {
+ if (*pr_file_p == '(')
+ {
+ int p;
+ char *start;
+ char buffer[1024];
+ char *paramoffset[MAXCONSTANTPARAMS+1];
+ int param=0;
+ int plevel=0;
+
+ pr_file_p++;
+ while(*pr_file_p == ' ' || *pr_file_p == '\t')
+ pr_file_p++;
+ start = pr_file_p;
+ while(1)
+ {
+ // handle strings correctly by ignoring them
+ if (*pr_file_p == '\"')
+ {
+ do {
+ pr_file_p++;
+ } while( (pr_file_p[-1] == '\\' || pr_file_p[0] != '\"') && *pr_file_p && *pr_file_p != '\n' );
+ }
+ if (*pr_file_p == '(')
+ plevel++;
+ else if (!plevel && (*pr_file_p == ',' || *pr_file_p == ')'))
+ {
+ paramoffset[param++] = start;
+ start = pr_file_p+1;
+ if (*pr_file_p == ')')
+ {
+ *pr_file_p = '\0';
+ pr_file_p++;
+ break;
+ }
+ *pr_file_p = '\0';
+ pr_file_p++;
+ while(*pr_file_p == ' ' || *pr_file_p == '\t')
+ {
+ pr_file_p++;
+ start++;
+ }
+ // move back by one char because we move forward by one at the end of the loop
+ pr_file_p--;
+ if (param == MAXCONSTANTPARAMS)
+ QCC_PR_ParseError(ERR_TOOMANYPARAMS, "Too many parameters in macro call");
+ } else if (*pr_file_p == ')' )
+ plevel--;
+ else if(*pr_file_p == '\n')
+ QCC_PR_NewLine(false);
+
+ // see that *pr_file_p = '\0' up there? Must ++ BEFORE checking for !*pr_file_p
+ pr_file_p++;
+ if (!*pr_file_p)
+ QCC_PR_ParseError(ERR_EOF, "EOF on macro call");
+ }
+ if (param < c->numparams)
+ QCC_PR_ParseError(ERR_TOOFEWPARAMS, "Not enough macro parameters");
+ paramoffset[param] = start;
+
+ *buffer = '\0';
+
+ oldpr_file_p = pr_file_p;
+ pr_file_p = c->value;
+ for(;;)
+ {
+ whitestart = p = strlen(buffer);
+ while(*pr_file_p <= ' ') //copy across whitespace
+ {
+ if (!*pr_file_p)
+ break;
+ buffer[p++] = *pr_file_p++;
+ }
+ buffer[p] = 0;
+
+ if(*pr_file_p == '\"')
+ {
+ do
+ {
+ buffer[p++] = *pr_file_p;
+ ++pr_file_p;
+ } while( (pr_file_p[-1] == '\\' || pr_file_p[0] != '\"') && *pr_file_p && *pr_file_p != '\n' );
+ buffer[p++] = *pr_file_p; // copy the end-quote too
+ buffer[p] = 0;
+ ++pr_file_p; // and skip it
+ continue;
+ }
+ else if (*pr_file_p == '#') //if you ask for #a##b you will be shot. use #a #b instead, or chain macros.
+ {
+ if (pr_file_p[1] == '#')
+ { //concatinate (srip out whitespace)
+ buffer[whitestart] = '\0';
+ pr_file_p+=2;
+ }
+ else
+ { //stringify
+ pr_file_p++;
+ pr_file_p = QCC_COM_Parse2(pr_file_p);
+ if (!pr_file_p)
+ break;
+
+ for (p = 0; p < param; p++)
+ {
+ if (!STRCMP(qcc_token, c->params[p]))
+ {
+ strcat(buffer, "\"");
+ strcat(buffer, paramoffset[p]);
+ strcat(buffer, "\"");
+ break;
+ }
+ }
+ if (p == param)
+ {
+ strcat(buffer, "#");
+ strcat(buffer, qcc_token);
+ //QCC_PR_ParseWarning(0, "Stringification ignored");
+ }
+ continue; //already did this one
+ }
+ }
+
+ pr_file_p = QCC_COM_Parse2(pr_file_p);
+ if (!pr_file_p)
+ break;
+
+ for (p = 0; p < param; p++)
+ {
+ if (!STRCMP(qcc_token, c->params[p]))
+ {
+ strcat(buffer, paramoffset[p]);
+ break;
+ }
+ }
+ if (p == param)
+ strcat(buffer, qcc_token);
+ }
+
+ for (p = 0; p < param-1; p++)
+ paramoffset[p][strlen(paramoffset[p])] = ',';
+ paramoffset[p][strlen(paramoffset[p])] = ')';
+
+ pr_file_p = oldpr_file_p;
+ if (!*buffer)
+ expandedemptymacro = true;
+ QCC_PR_IncludeChunkEx(buffer, true, NULL, c);
+ }
+ else
+ QCC_PR_ParseError(ERR_TOOFEWPARAMS, "Macro without opening brace");
+ }
+ else
+ {
+ if (!*c->value)
+ expandedemptymacro = true;
+ QCC_PR_IncludeChunkEx(c->value, false, NULL, c);
+ }
+
+ QCC_PR_Lex();
+ return true;
+ }
+
+ if (!strncmp(pr_file_p, "__TIME__", 8))
+ {
+ static char retbuf[128];
+
+ time_t long_time;
+ time( &long_time );
+ strftime( retbuf, sizeof(retbuf),
+ "\"%H:%M\"", localtime( &long_time ));
+
+ pr_file_p = retbuf;
+ QCC_PR_Lex(); //translate the macro's value
+ pr_file_p = oldpr_file_p+8;
+
+ return true;
+ }
+ if (!strncmp(pr_file_p, "__DATE__", 8))
+ {
+ static char retbuf[128];
+
+ time_t long_time;
+ time( &long_time );
+ strftime( retbuf, sizeof(retbuf),
+ "\"%a %d %b %Y\"", localtime( &long_time ));
+
+ pr_file_p = retbuf;
+ QCC_PR_Lex(); //translate the macro's value
+ pr_file_p = oldpr_file_p+8;
+
+ return true;
+ }
+ if (!strncmp(pr_file_p, "__FILE__", 8))
+ {
+ static char retbuf[256];
+ sprintf(retbuf, "\"%s\"", strings + s_file);
+ pr_file_p = retbuf;
+ QCC_PR_Lex(); //translate the macro's value
+ pr_file_p = oldpr_file_p+8;
+
+ return true;
+ }
+ if (!strncmp(pr_file_p, "__LINE__", 8))
+ {
+ static char retbuf[256];
+ sprintf(retbuf, "\"%i\"", pr_source_line);
+ pr_file_p = retbuf;
+ QCC_PR_Lex(); //translate the macro's value
+ pr_file_p = oldpr_file_p+8;
+ return true;
+ }
+ if (!strncmp(pr_file_p, "__FUNC__", 8))
+ {
+ static char retbuf[256];
+ sprintf(retbuf, "\"%s\"",pr_scope->name);
+ pr_file_p = retbuf;
+ QCC_PR_Lex(); //translate the macro's value
+ pr_file_p = oldpr_file_p+8;
+ return true;
+ }
+ if (!strncmp(pr_file_p, "__NULL__", 8))
+ {
+ static char retbuf[256];
+ sprintf(retbuf, "0i");
+ pr_file_p = retbuf;
+ QCC_PR_Lex(); //translate the macro's value
+ pr_file_p = oldpr_file_p+8;
+ return true;
+ }
+ return false;
+}
+
+char *QCC_PR_CheakCompConstString(char *def)
+{
+ char *s;
+
+ CompilerConstant_t *c;
+
+ c = pHash_Get(&compconstantstable, def);
+
+ if (c)
+ {
+ s = QCC_PR_CheakCompConstString(c->value);
+ return s;
+ }
+ return def;
+}
+
+CompilerConstant_t *QCC_PR_CheckCompConstDefined(char *def)
+{
+ CompilerConstant_t *c = pHash_Get(&compconstantstable, def);
+ return c;
+ /*int a;
+ for (a = 0; a < numCompilerConstants; a++)
+ {
+ if (!strncmp(def, CompilerConstant[a].name, CompilerConstant[a].namelen+1))
+ return &CompilerConstant[a];
+ }
+ return NULL;
+ */
+}
+
+//============================================================================
+
+/*
+==============
+PR_Lex
+
+Sets pr_token, pr_token_type, and possibly pr_immediate and pr_immediate_type
+==============
+*/
+void QCC_PR_Lex (void)
+{
+ int c;
+
+ pr_token[0] = 0;
+
+ if (!pr_file_p)
+ {
+ if (QCC_PR_UnInclude())
+ {
+ QCC_PR_Lex();
+ return;
+ }
+ pr_token_type = tt_eof;
+ return;
+ }
+
+ QCC_PR_LexWhitespace ();
+
+ if (!pr_file_p)
+ {
+ if (QCC_PR_UnInclude())
+ {
+ QCC_PR_Lex();
+ return;
+ }
+ pr_token_type = tt_eof;
+ return;
+ }
+
+ c = *pr_file_p;
+
+ if (!c)
+ {
+ if (QCC_PR_UnInclude())
+ {
+ QCC_PR_Lex();
+ return;
+ }
+ pr_token_type = tt_eof;
+ return;
+ }
+
+// handle quoted strings as a unit
+ if (c == '\"')
+ {
+ QCC_PR_LexString ();
+ return;
+ }
+
+// handle quoted vectors as a unit
+ if (c == '\'')
+ {
+ QCC_PR_LexVector ();
+ return;
+ }
+
+// if the first character is a valid identifier, parse until a non-id
+// character is reached
+ if ( c == '~' || c == '%') //let's see which one we make into an operator first... possibly both...
+ {
+ QCC_PR_ParseWarning(0, "~ or %% prefixes to denote integers are deprecated. Please use a postfix of 'i'");
+ pr_file_p++;
+ pr_token_type = tt_immediate;
+ pr_immediate_type = type_integer;
+ pr_immediate._int = QCC_PR_LexInteger ();
+ return;
+ }
+ if ( c == '0' && pr_file_p[1] == 'x')
+ {
+ pr_token_type = tt_immediate;
+ QCC_PR_LexNumber();
+ return;
+ }
+ if ( (c == '.'&&pr_file_p[1] >='0' && pr_file_p[1] <= '9') || (c >= '0' && c <= '9') || ( c=='-' && pr_file_p[1]>='0' && pr_file_p[1] <='9') )
+ {
+ pr_token_type = tt_immediate;
+ QCC_PR_LexNumber ();
+ return;
+ }
+
+ if (c == '#' && !(pr_file_p[1]=='-' || (pr_file_p[1]>='0' && pr_file_p[1] <='9'))) //hash and not number
+ {
+ pr_file_p++;
+ if (!QCC_PR_CheakCompConst())
+ {
+ if (!QCC_PR_SimpleGetToken())
+ strcpy(pr_token, "unknown");
+ QCC_PR_ParseError(ERR_CONSTANTNOTDEFINED, "Explicit precompiler usage when not defined %s", pr_token);
+ }
+ else
+ if (pr_token_type == tt_eof)
+ QCC_PR_Lex();
+
+ return;
+ }
+
+ if ( (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' )
+ {
+ if (flag_hashonly || !QCC_PR_CheakCompConst()) //look for a macro.
+ QCC_PR_LexName ();
+ else
+ if (pr_token_type == tt_eof)
+ {
+ if (QCC_PR_UnInclude())
+ {
+ QCC_PR_Lex();
+ return;
+ }
+ pr_token_type = tt_eof;
+ }
+ return;
+ }
+
+ if (c == '$')
+ {
+ QCC_PR_LexGrab ();
+ return;
+ }
+
+// parse symbol strings until a non-symbol is found
+ QCC_PR_LexPunctuation ();
+}
+
+//=============================================================================
+
+
+void QCC_PR_ParsePrintDef (int type, QCC_def_t *def)
+{
+ if (qccwarningdisabled[type])
+ return;
+ if (def->s_file)
+ {
+ if (flag_msvcstyle)
+ printf ("%s(%i) : %s is defined here\n", strings + def->s_file, def->s_line, def->name);
+ else
+ printf ("%s:%i: %s is defined here\n", strings + def->s_file, def->s_line, def->name);
+ }
+}
+void *errorscope;
+void QCC_PR_PrintScope (void)
+{
+ if (pr_scope)
+ {
+ if (errorscope != pr_scope)
+ printf ("in function %s (line %i),\n", pr_scope->name, pr_scope->s_line);
+ errorscope = pr_scope;
+ }
+ else
+ {
+ if (errorscope)
+ printf ("at global scope,\n");
+ errorscope = NULL;
+ }
+}
+void QCC_PR_ResetErrorScope(void)
+{
+ errorscope = NULL;
+}
+/*
+============
+PR_ParseError
+
+Aborts the current file load
+============
+*/
+#ifndef QCC
+void editbadfile(char *file, int line);
+#endif
+void VARGS QCC_PR_ParseError (int errortype, char *error, ...)
+{
+ va_list argptr;
+ char string[1024];
+
+ va_start (argptr,error);
+ QC_vsnprintf (string,sizeof(string)-1, error,argptr);
+ va_end (argptr);
+
+#ifndef QCC
+ editbadfile(strings+s_file, pr_source_line);
+#endif
+
+ QCC_PR_PrintScope();
+ if (flag_msvcstyle)
+ printf ("%s(%i) : error: %s\n", strings + s_file, pr_source_line, string);
+ else
+ printf ("%s:%i: error: %s\n", strings + s_file, pr_source_line, string);
+
+ longjmp (pr_parse_abort, 1);
+}
+void VARGS QCC_PR_ParseErrorPrintDef (int errortype, QCC_def_t *def, char *error, ...)
+{
+ va_list argptr;
+ char string[1024];
+
+ va_start (argptr,error);
+ QC_vsnprintf (string,sizeof(string)-1, error,argptr);
+ va_end (argptr);
+
+#ifndef QCC
+ editbadfile(strings+s_file, pr_source_line);
+#endif
+ QCC_PR_PrintScope();
+ if (flag_msvcstyle)
+ printf ("%s(%i) : error: %s\n", strings + s_file, pr_source_line, string);
+ else
+ printf ("%s:%i: error: %s\n", strings + s_file, pr_source_line, string);
+
+ QCC_PR_ParsePrintDef(WARN_ERROR, def);
+
+ longjmp (pr_parse_abort, 1);
+}
+void VARGS QCC_PR_ParseWarning (int type, char *error, ...)
+{
+ va_list argptr;
+ char string[1024];
+
+ if (type < ERR_PARSEERRORS && qccwarningdisabled[type])
+ return;
+
+ va_start (argptr,error);
+ QC_vsnprintf (string,sizeof(string)-1, error,argptr);
+ va_end (argptr);
+
+ QCC_PR_PrintScope();
+ if (type >= ERR_PARSEERRORS)
+ {
+ if (flag_msvcstyle)
+ printf ("%s(%i) : error: %s\n", strings + s_file, pr_source_line, string);
+ else
+ printf ("%s:%i: error: %s\n", strings + s_file, pr_source_line, string);
+ pr_error_count++;
+ }
+ else
+ {
+ if (flag_msvcstyle)
+ printf ("%s(%i) : warning: %s\n", strings + s_file, pr_source_line, string);
+ else
+ printf ("%s:%i: warning: %s\n", strings + s_file, pr_source_line, string);
+ pr_warning_count++;
+ }
+}
+
+void VARGS QCC_PR_Warning (int type, char *file, int line, char *error, ...)
+{
+ va_list argptr;
+ char string[1024];
+
+ if (qccwarningdisabled[type])
+ return;
+
+ va_start (argptr,error);
+ QC_vsnprintf (string,sizeof(string)-1, error,argptr);
+ va_end (argptr);
+
+ QCC_PR_PrintScope();
+ if (file)
+ {
+ if (flag_msvcstyle)
+ printf ("%s(%i) : warning: %s\n", file, line, string);
+ else
+ printf ("%s:%i: warning: %s\n", file, line, string);
+ }
+ else
+ printf ("warning: %s\n", string);
+ pr_warning_count++;
+}
+
+
+/*
+=============
+PR_Expect
+
+Issues an error if the current token isn't equal to string
+Gets the next token
+=============
+*/
+#ifndef COMMONINLINES
+void QCC_PR_Expect (char *string)
+{
+ if (STRCMP (string, pr_token))
+ QCC_PR_ParseError (ERR_EXPECTED, "expected %s, found %s",string, pr_token);
+ QCC_PR_Lex ();
+}
+#endif
+
+
+/*
+=============
+PR_Check
+
+Returns true and gets the next token if the current token equals string
+Returns false and does nothing otherwise
+=============
+*/
+#ifndef COMMONINLINES
+pbool QCC_PR_CheckToken (char *string)
+{
+ if (pr_token_type != tt_punct)
+ return false;
+
+ if (STRCMP (string, pr_token))
+ return false;
+
+ QCC_PR_Lex ();
+ return true;
+}
+
+pbool QCC_PR_CheckImmediate (char *string)
+{
+ if (pr_token_type != tt_immediate)
+ return false;
+
+ if (STRCMP (string, pr_token))
+ return false;
+
+ QCC_PR_Lex ();
+ return true;
+}
+
+pbool QCC_PR_CheckName(char *string)
+{
+ if (pr_token_type != tt_name)
+ return false;
+ if (flag_caseinsensative)
+ {
+ if (stricmp (string, pr_token))
+ return false;
+ }
+ else
+ {
+ if (STRCMP(string, pr_token))
+ return false;
+ }
+ QCC_PR_Lex ();
+ return true;
+}
+
+pbool QCC_PR_CheckKeyword(int keywordenabled, char *string)
+{
+ if (!keywordenabled)
+ return false;
+ if (flag_caseinsensative)
+ {
+ if (stricmp (string, pr_token))
+ return false;
+ }
+ else
+ {
+ if (STRCMP(string, pr_token))
+ return false;
+ }
+ QCC_PR_Lex ();
+ return true;
+}
+#endif
+
+
+/*
+============
+PR_ParseName
+
+Checks to see if the current token is a valid name
+============
+*/
+char *QCC_PR_ParseName (void)
+{
+ static char ident[MAX_NAME];
+ char *ret;
+
+ if (pr_token_type != tt_name)
+ QCC_PR_ParseError (ERR_NOTANAME, "\"%s\" - not a name", pr_token);
+ if (strlen(pr_token) >= MAX_NAME-1)
+ QCC_PR_ParseError (ERR_NAMETOOLONG, "name too long");
+ strcpy (ident, pr_token);
+ QCC_PR_Lex ();
+
+ ret = qccHunkAlloc(strlen(ident)+1);
+ strcpy(ret, ident);
+ return ret;
+// return ident;
+}
+
+/*
+============
+PR_FindType
+
+Returns a preexisting complex type that matches the parm, or allocates
+a new one and copies it out.
+============
+*/
+
+//0 if same
+QCC_type_t *QCC_PR_NewType (char *name, int basictype);
+int typecmp(QCC_type_t *a, QCC_type_t *b)
+{
+ if (a == b)
+ return 0;
+ if (!a || !b)
+ return 1; //different (^ and not both null)
+
+ if (a->type != b->type)
+ return 1;
+ if (a->num_parms != b->num_parms)
+ return 1;
+
+ if (a->size != b->size)
+ return 1;
+// if (STRCMP(a->name, b->name)) //This isn't 100% clean.
+// return 1;
+
+ if (typecmp(a->aux_type, b->aux_type))
+ return 1;
+
+ if (a->param || b->param)
+ {
+ a = a->param;
+ b = b->param;
+
+ while(a || b)
+ {
+ if (typecmp(a, b))
+ return 1;
+
+ a=a->next;
+ b=b->next;
+ }
+ }
+
+ return 0;
+}
+
+QCC_type_t *QCC_PR_DuplicateType(QCC_type_t *in)
+{
+ QCC_type_t *out, *op, *ip;
+ if (!in)
+ return NULL;
+
+ out = QCC_PR_NewType(in->name, in->type);
+ out->aux_type = QCC_PR_DuplicateType(in->aux_type);
+ out->param = QCC_PR_DuplicateType(in->param);
+ ip = in->param;
+ op = NULL;
+ while(ip)
+ {
+ if (!op)
+ out->param = op = QCC_PR_DuplicateType(ip);
+ else
+ op = (op->next = QCC_PR_DuplicateType(ip));
+ ip = ip->next;
+ }
+ out->size = in->size;
+ out->num_parms = in->num_parms;
+ out->ofs = in->ofs;
+ out->name = in->name;
+ out->parentclass = in->parentclass;
+
+ return out;
+}
+
+char *TypeName(QCC_type_t *type)
+{
+ static char buffer[2][512];
+ static int op;
+ char *ret;
+
+
+ op++;
+ ret = buffer[op&1];
+ if (type->type == ev_field)
+ {
+ type = type->aux_type;
+ *ret++ = '.';
+ }
+ *ret = 0;
+
+ if (type->type == ev_function)
+ {
+ strcat(ret, type->aux_type->name);
+ strcat(ret, " (");
+ type = type->param;
+ while(type)
+ {
+ strcat(ret, type->name);
+ type = type->next;
+
+ if (type)
+ strcat(ret, ", ");
+ }
+ strcat(ret, ")");
+ }
+ else if (type->type == ev_entity && type->parentclass)
+ {
+ ret = buffer[op&1];
+ *ret = 0;
+ strcat(ret, "class ");
+ strcat(ret, type->name);
+/* strcat(ret, " {");
+ type = type->param;
+ while(type)
+ {
+ strcat(ret, type->name);
+ type = type->next;
+
+ if (type)
+ strcat(ret, ", ");
+ }
+ strcat(ret, "}");
+*/
+ }
+ else
+ strcpy(ret, type->name);
+
+ return buffer[op&1];
+}
+//#define typecmp(a, b) (a && ((a)->type==(b)->type) && !STRCMP((a)->name, (b)->name))
+
+QCC_type_t *QCC_PR_FindType (QCC_type_t *type)
+{
+ int t;
+ for (t = 0; t < numtypeinfos; t++)
+ {
+// check = &qcc_typeinfo[t];
+ if (typecmp(&qcc_typeinfo[t], type))
+ continue;
+
+
+// c2 = check->next;
+// n2 = type->next;
+// for (i=0 ; n2&&c2 ; i++)
+// {
+// if (!typecmp((c2), (n2)))
+// break;
+// c2=c2->next;
+// n2=n2->next;
+// }
+
+// if (n2==NULL&&c2==NULL)
+ {
+ return &qcc_typeinfo[t];
+ }
+ }
+QCC_Error(ERR_INTERNAL, "Error with type");
+
+ return type;
+}
+/*
+QCC_type_t *QCC_PR_NextSubType(QCC_type_t *type, QCC_type_t *prev)
+{
+ int p;
+ if (!prev)
+ return type->next;
+
+ for (p = prev->num_parms; p; p--)
+ prev = QCC_PR_NextSubType(prev, NULL);
+ if (prev->num_parms)
+
+ switch(prev->type)
+ {
+ case ev_function:
+
+ }
+
+ return prev->next;
+}
+*/
+
+QCC_type_t *QCC_TypeForName(char *name)
+{
+ int i;
+
+ for (i = 0; i < numtypeinfos; i++)
+ {
+ if (!STRCMP(qcc_typeinfo[i].name, name))
+ {
+ return &qcc_typeinfo[i];
+ }
+ }
+
+ return NULL;
+}
+
+/*
+============
+PR_SkipToSemicolon
+
+For error recovery, also pops out of nested braces
+============
+*/
+void QCC_PR_SkipToSemicolon (void)
+{
+ do
+ {
+ if (!pr_bracelevel && QCC_PR_CheckToken (";"))
+ return;
+ QCC_PR_Lex ();
+ } while (pr_token_type != tt_eof);
+}
+
+
+/*
+============
+PR_ParseType
+
+Parses a variable type, including field and functions types
+============
+*/
+#ifdef MAX_EXTRA_PARMS
+char pr_parm_names[MAX_PARMS+MAX_EXTRA_PARMS][MAX_NAME];
+#else
+char pr_parm_names[MAX_PARMS][MAX_NAME];
+#endif
+
+pbool recursivefunctiontype;
+
+QCC_type_t *QCC_PR_NewType (char *name, int basictype);
+//expects a ( to have already been parsed.
+QCC_type_t *QCC_PR_ParseFunctionType (int newtype, QCC_type_t *returntype)
+{
+ QCC_type_t *ftype, *ptype, *nptype;
+ char *name;
+ int definenames = !recursivefunctiontype;
+
+ recursivefunctiontype++;
+
+ ftype = QCC_PR_NewType(type_function->name, ev_function);
+
+ ftype->aux_type = returntype; // return type
+ ftype->num_parms = 0;
+ ptype = NULL;
+
+
+ if (!QCC_PR_CheckToken (")"))
+ {
+ if (QCC_PR_CheckToken ("..."))
+ ftype->num_parms = -1; // variable args
+ else
+ do
+ {
+ if (ftype->num_parms>=MAX_PARMS+MAX_EXTRA_PARMS)
+ QCC_PR_ParseError(ERR_TOOMANYTOTALPARAMETERS, "Too many parameters. Sorry. (limit is %i)\n", MAX_PARMS+MAX_EXTRA_PARMS);
+
+ if (QCC_PR_CheckToken ("..."))
+ {
+ ftype->num_parms = (ftype->num_parms * -1) - 1;
+ break;
+ }
+
+ nptype = QCC_PR_ParseType(true);
+
+ if (nptype->type == ev_void)
+ break;
+ if (!ptype)
+ {
+ ptype = nptype;
+ ftype->param = ptype;
+ }
+ else
+ {
+ ptype->next = nptype;
+ ptype = ptype->next;
+ }
+// type->name = "FUNC PARAMETER";
+
+
+ if (STRCMP(pr_token, ",") && STRCMP(pr_token, ")"))
+ {
+ name = QCC_PR_ParseName ();
+ if (definenames)
+ strcpy (pr_parm_names[ftype->num_parms], name);
+ }
+ else if (definenames)
+ strcpy (pr_parm_names[ftype->num_parms], "");
+ ftype->num_parms++;
+ } while (QCC_PR_CheckToken (","));
+
+ QCC_PR_Expect (")");
+ }
+ recursivefunctiontype--;
+ if (newtype)
+ return ftype;
+ return QCC_PR_FindType (ftype);
+}
+QCC_type_t *QCC_PR_ParseFunctionTypeReacc (int newtype, QCC_type_t *returntype)
+{
+ QCC_type_t *ftype, *ptype, *nptype;
+ char *name;
+ char argname[64];
+ int definenames = !recursivefunctiontype;
+
+ recursivefunctiontype++;
+
+ ftype = QCC_PR_NewType(type_function->name, ev_function);
+
+ ftype->aux_type = returntype; // return type
+ ftype->num_parms = 0;
+ ptype = NULL;
+
+
+ if (!QCC_PR_CheckToken (")"))
+ {
+ if (QCC_PR_CheckToken ("..."))
+ ftype->num_parms = -1; // variable args
+ else
+ do
+ {
+ if (ftype->num_parms>=MAX_PARMS+MAX_EXTRA_PARMS)
+ QCC_PR_ParseError(ERR_TOOMANYTOTALPARAMETERS, "Too many parameters. Sorry. (limit is %i)\n", MAX_PARMS+MAX_EXTRA_PARMS);
+
+ if (QCC_PR_CheckToken ("..."))
+ {
+ ftype->num_parms = (ftype->num_parms * -1) - 1;
+ break;
+ }
+
+ if (QCC_PR_CheckName("arg"))
+ {
+ sprintf(argname, "arg%i", ftype->num_parms);
+ name = argname;
+ nptype = QCC_PR_NewType("Variant", ev_variant);
+ }
+ else if (QCC_PR_CheckName("vect")) //this can only be of vector sizes, so...
+ {
+ sprintf(argname, "arg%i", ftype->num_parms);
+ name = argname;
+ nptype = QCC_PR_NewType("Vector", ev_vector);
+ }
+ else
+ {
+ name = QCC_PR_ParseName();
+ QCC_PR_Expect(":");
+ nptype = QCC_PR_ParseType(true);
+ }
+
+ if (nptype->type == ev_void)
+ break;
+ if (!ptype)
+ {
+ ptype = nptype;
+ ftype->param = ptype;
+ }
+ else
+ {
+ ptype->next = nptype;
+ ptype = ptype->next;
+ }
+// type->name = "FUNC PARAMETER";
+
+ if (definenames)
+ strcpy (pr_parm_names[ftype->num_parms], name);
+ ftype->num_parms++;
+ } while (QCC_PR_CheckToken (";"));
+
+ QCC_PR_Expect (")");
+ }
+ recursivefunctiontype--;
+ if (newtype)
+ return ftype;
+ return QCC_PR_FindType (ftype);
+}
+QCC_type_t *QCC_PR_PointerType (QCC_type_t *pointsto)
+{
+ QCC_type_t *ptype;
+ char name[128];
+ sprintf(name, "*%s", pointsto->name);
+ ptype = QCC_PR_NewType(name, ev_pointer);
+ ptype->aux_type = pointsto;
+ return QCC_PR_FindType (ptype);
+}
+QCC_type_t *QCC_PR_FieldType (QCC_type_t *pointsto)
+{
+ QCC_type_t *ptype;
+ char name[128];
+ sprintf(name, "FIELD TYPE(%s)", pointsto->name);
+ ptype = QCC_PR_NewType(name, ev_field);
+ ptype->aux_type = pointsto;
+ ptype->size = ptype->aux_type->size;
+ return QCC_PR_FindType (ptype);
+}
+
+pbool type_inlinefunction;
+QCC_type_t *QCC_PR_ParseType (int newtype)
+{
+ QCC_type_t *newparm;
+ QCC_type_t *newt;
+ QCC_type_t *type;
+ char *name;
+ int i;
+
+ type_inlinefunction = false; //doesn't really matter so long as its not from an inline function type
+
+// int ofs;
+
+ if (QCC_PR_CheckToken ("..")) //so we don't end up with the user specifying '. .vector blah' (hexen2 added the .. token for array ranges)
+ {
+ newt = QCC_PR_NewType("FIELD TYPE", ev_field);
+ newt->aux_type = QCC_PR_ParseType (false);
+
+ newt->size = newt->aux_type->size;
+
+ newt = QCC_PR_FindType (newt);
+
+ type = QCC_PR_NewType("FIELD TYPE", ev_field);
+ type->aux_type = newt;
+
+ type->size = type->aux_type->size;
+
+ if (newtype)
+ return type;
+ return QCC_PR_FindType (type);
+ }
+ if (QCC_PR_CheckToken ("."))
+ {
+ newt = QCC_PR_NewType("FIELD TYPE", ev_field);
+ newt->aux_type = QCC_PR_ParseType (false);
+
+ newt->size = newt->aux_type->size;
+
+ if (newtype)
+ return newt;
+ return QCC_PR_FindType (newt);
+ }
+
+ name = QCC_PR_CheakCompConstString(pr_token);
+
+ if (QCC_PR_CheckKeyword (keyword_class, "class"))
+ {
+// int parms;
+ QCC_type_t *fieldtype;
+ char membername[2048];
+ char *classname = QCC_PR_ParseName();
+ int forwarddeclaration;
+
+ newt = 0;
+
+ /* Don't advance the line number yet */
+ forwarddeclaration = pr_token[0] == ';';
+
+ /* Look to see if this type is already defined */
+ for(i=0;i<numtypeinfos;i++)
+ {
+ if (STRCMP(qcc_typeinfo[i].name, classname) == 0)
+ {
+ newt = &qcc_typeinfo[i];
+ break;
+ }
+ }
+
+ if (newt && forwarddeclaration)
+ QCC_PR_ParseError(ERR_REDECLARATION, "Forward declaration of already defined class %s", classname);
+
+ if (newt && newt->num_parms != 0)
+ QCC_PR_ParseError(ERR_REDECLARATION, "Redeclaration of class %s", classname);
+
+ if (!newt)
+ newt = QCC_PR_NewType(classname, ev_entity);
+
+ newt->size=type_entity->size;
+
+ type = NULL;
+
+ if (forwarddeclaration)
+ {
+ QCC_PR_CheckToken(";");
+ return NULL;
+ }
+
+
+
+ if (QCC_PR_CheckToken(":"))
+ {
+ char *parentname = QCC_PR_ParseName();
+ newt->parentclass = QCC_TypeForName(parentname);
+ if (!newt->parentclass)
+ QCC_PR_ParseError(ERR_NOTANAME, "Parent class %s was not defined", parentname);
+ }
+ else
+ newt->parentclass = type_entity;
+
+
+ QCC_PR_Expect("{");
+ if (QCC_PR_CheckToken(","))
+ QCC_PR_ParseError(ERR_NOTANAME, "member missing name");
+ while (!QCC_PR_CheckToken("}"))
+ {
+// if (QCC_PR_CheckToken(","))
+// type->next = QCC_PR_NewType(type->name, type->type);
+// else
+ newparm = QCC_PR_ParseType(true);
+
+ if (newparm->type == ev_struct || newparm->type == ev_union) //we wouldn't be able to handle it.
+ QCC_PR_ParseError(ERR_INTERNAL, "Struct or union in class %s", classname);
+
+ if (!QCC_PR_CheckToken(";"))
+ {
+ newparm->name = QCC_CopyString(pr_token)+strings;
+ QCC_PR_Lex();
+ if (QCC_PR_CheckToken("["))
+ {
+ type->next->size*=atoi(pr_token);
+ QCC_PR_Lex();
+ QCC_PR_Expect("]");
+ }
+ QCC_PR_CheckToken(";");
+ }
+ else
+ newparm->name = QCC_CopyString("")+strings;
+
+ sprintf(membername, "%s::"MEMBERFIELDNAME, classname, newparm->name);
+ fieldtype = QCC_PR_NewType(newparm->name, ev_field);
+ fieldtype->aux_type = newparm;
+ fieldtype->size = newparm->size;
+ QCC_PR_GetDef(fieldtype, membername, pr_scope, 2, 1, false);
+
+
+ newparm->ofs = 0;//newt->size;
+ newt->num_parms++;
+
+ if (type)
+ type->next = newparm;
+ else
+ newt->param = newparm;
+
+ type = newparm;
+ }
+
+
+ QCC_PR_Expect(";");
+ return NULL;
+ }
+ if (QCC_PR_CheckKeyword (keyword_struct, "struct"))
+ {
+ newt = QCC_PR_NewType("struct", ev_struct);
+ newt->size=0;
+ QCC_PR_Expect("{");
+
+ type = NULL;
+ if (QCC_PR_CheckToken(","))
+ QCC_PR_ParseError(ERR_NOTANAME, "element missing name");
+
+ newparm = NULL;
+ while (!QCC_PR_CheckToken("}"))
+ {
+ if (QCC_PR_CheckToken(","))
+ {
+ if (!newparm)
+ QCC_PR_ParseError(ERR_NOTANAME, "element missing type");
+ newparm = QCC_PR_NewType(newparm->name, newparm->type);
+ }
+ else
+ newparm = QCC_PR_ParseType(true);
+
+ if (!QCC_PR_CheckToken(";"))
+ {
+ newparm->name = QCC_CopyString(pr_token)+strings;
+ QCC_PR_Lex();
+ if (QCC_PR_CheckToken("["))
+ {
+ newparm->size*=atoi(pr_token);
+ QCC_PR_Lex();
+ QCC_PR_Expect("]");
+ }
+ QCC_PR_CheckToken(";");
+ }
+ else
+ newparm->name = QCC_CopyString("")+strings;
+ newparm->ofs = newt->size;
+ newt->size += newparm->size;
+ newt->num_parms++;
+
+ if (type)
+ type->next = newparm;
+ else
+ newt->param = newparm;
+ type = newparm;
+ }
+ return newt;
+ }
+ if (QCC_PR_CheckKeyword (keyword_union, "union"))
+ {
+ newt = QCC_PR_NewType("union", ev_union);
+ newt->size=0;
+ QCC_PR_Expect("{");
+
+ type = NULL;
+ if (QCC_PR_CheckToken(","))
+ QCC_PR_ParseError(ERR_NOTANAME, "element missing name");
+ newparm = NULL;
+ while (!QCC_PR_CheckToken("}"))
+ {
+ if (QCC_PR_CheckToken(","))
+ {
+ if (!newparm)
+ QCC_PR_ParseError(ERR_NOTANAME, "element missing type");
+ newparm = QCC_PR_NewType(newparm->name, newparm->type);
+ }
+ else
+ newparm = QCC_PR_ParseType(true);
+ if (QCC_PR_CheckToken(";"))
+ newparm->name = QCC_CopyString("")+strings;
+ else
+ {
+ newparm->name = QCC_CopyString(pr_token)+strings;
+ QCC_PR_Lex();
+ QCC_PR_Expect(";");
+ }
+ newparm->ofs = 0;
+ if (newparm->size > newt->size)
+ newt->size = newparm->size;
+ newt->num_parms++;
+
+ if (type)
+ type->next = newparm;
+ else
+ newt->param = newparm;
+ type = newparm;
+ }
+ return newt;
+ }
+ type = NULL;
+ for (i = 0; i < numtypeinfos; i++)
+ {
+ if (!STRCMP(qcc_typeinfo[i].name, name))
+ {
+ type = &qcc_typeinfo[i];
+ break;
+ }
+ }
+
+ if (i == numtypeinfos)
+ {
+ if (!*name)
+ return NULL;
+ if (!stricmp("Void", name))
+ type = type_void;
+ else if (!stricmp("Real", name))
+ type = type_float;
+ else if (!stricmp("Vector", name))
+ type = type_vector;
+ else if (!stricmp("Object", name))
+ type = type_entity;
+ else if (!stricmp("String", name))
+ type = type_string;
+ else if (!stricmp("PFunc", name))
+ type = type_function;
+ else
+ {
+ QCC_PR_ParseError (ERR_NOTATYPE, "\"%s\" is not a type", name);
+ type = type_float; // shut up compiler warning
+ }
+ }
+ QCC_PR_Lex ();
+
+ if (QCC_PR_CheckToken ("(")) //this is followed by parameters. Must be a function.
+ {
+ type_inlinefunction = true;
+ return QCC_PR_ParseFunctionType(newtype, type);
+ }
+ else
+ {
+ if (newtype)
+ {
+ type = QCC_PR_DuplicateType(type);
+ }
+
+ return type;
+ }
+}
+
+#endif
+
+
+