]> de.git.xonotic.org Git - voretournament/voretournament.git/blob - misc/source/fteqcc-src/qcc_pr_lex.c
Latest fteqcc and netradiant sources
[voretournament/voretournament.git] / misc / source / fteqcc-src / qcc_pr_lex.c
1 #ifndef MINIMAL
2
3 #include "qcc.h"
4 #ifdef QCC
5 #define print printf
6 #endif
7 #include "time.h"
8
9 // I put the following here to resolve "undefined reference to `__imp__vsnprintf'" with MinGW64 ~ Moodles
10 #ifdef __MINGW64__
11 #ifndef QCCONLY
12         #if (_MSC_VER >= 1400)
13                 //with MSVC 8, use MS extensions
14                 #define snprintf linuxlike_snprintf_vc8
15                 int VARGS linuxlike_snprintf_vc8(char *buffer, int size, const char *format, ...) LIKEPRINTF(3);
16                 #define vsnprintf(a, b, c, d) vsnprintf_s(a, b, _TRUNCATE, c, d)
17         #else
18                 //msvc crap
19                 #define snprintf linuxlike_snprintf
20                 int VARGS linuxlike_snprintf(char *buffer, int size, const char *format, ...) LIKEPRINTF(3);
21                 #define vsnprintf linuxlike_vsnprintf
22                 int VARGS linuxlike_vsnprintf(char *buffer, int size, const char *format, va_list argptr);
23         #endif
24 #endif
25 #endif
26
27 #define MEMBERFIELDNAME "__m%s"
28
29 #define STRCMP(s1,s2) (((*s1)!=(*s2)) || strcmp(s1+1,s2+1))     //saves about 2-6 out of 120 - expansion of idea from fastqcc
30
31 void QCC_PR_ConditionCompilation(void);
32 pbool QCC_PR_UndefineName(char *name);
33 char *QCC_PR_CheakCompConstString(char *def);
34 CompilerConstant_t *QCC_PR_CheckCompConstDefined(char *def);
35 pbool QCC_Include(char *filename);
36
37 char *compilingfile;
38
39 int                     pr_source_line;
40
41 char            *pr_file_p;
42 char            *pr_line_start;         // start of current source line
43
44 int                     pr_bracelevel;
45
46 char            pr_token[8192];
47 token_type_t    pr_token_type;
48 QCC_type_t              *pr_immediate_type;
49 QCC_eval_t              pr_immediate;
50
51 char    pr_immediate_string[8192];
52
53 int             pr_error_count;
54 int             pr_warning_count;
55
56
57 CompilerConstant_t *CompilerConstant;
58 int numCompilerConstants;
59 extern pbool expandedemptymacro;
60
61
62
63 char    *pr_punctuation[] =
64 // longer symbols must be before a shorter partial match
65 {"&&", "||", "<=", ">=","==", "!=", "/=", "*=", "+=", "-=", "(+)", "(-)", "|=", "&~=", "++", "--", "->", "::", ";", ",", "!", "*", "/", "(", ")", "-", "+", "=", "[", "]", "{", "}", "...", "..", ".", "<<", "<", ">>", ">" , "?", "#" , "@", "&" , "|", "^", ":", NULL};
66
67 char *pr_punctuationremap[] =   //a nice bit of evilness.
68 //(+) -> |=
69 //-> -> .
70 //(-) -> &~=
71 {"&&", "||", "<=", ">=","==", "!=", "/=", "*=", "+=", "-=", "|=",  "&~=", "|=", "&~=", "++", "--", ".", "::", ";", ",", "!", "*", "/", "(", ")", "-", "+", "=", "[", "]", "{", "}", "...", "..", ".", "<<", "<", ">>", ">" , "?", "#" , "@", "&" , "|", "^", ":", NULL};
72
73 // simple types.  function types are dynamically allocated
74 QCC_type_t      *type_void;// = {ev_void/*, &def_void*/};
75 QCC_type_t      *type_string;// = {ev_string/*, &def_string*/};
76 QCC_type_t      *type_float;// = {ev_float/*, &def_float*/};
77 QCC_type_t      *type_vector;// = {ev_vector/*, &def_vector*/};
78 QCC_type_t      *type_entity;// = {ev_entity/*, &def_entity*/};
79 QCC_type_t      *type_field;// = {ev_field/*, &def_field*/};
80 QCC_type_t      *type_function;// = {ev_function/*, &def_function*/,NULL,&type_void};
81 // type_function is a void() function used for state defs
82 QCC_type_t      *type_pointer;// = {ev_pointer/*, &def_pointer*/};
83 QCC_type_t      *type_integer;// = {ev_integer/*, &def_integer*/};
84 QCC_type_t      *type_variant;// = {ev_integer/*, &def_integer*/};
85
86 QCC_type_t      *type_floatfield;// = {ev_field/*, &def_field*/, NULL, &type_float};
87
88 /*QCC_def_t     def_void = {type_void, "temp"};
89 QCC_def_t       def_string = {type_string, "temp"};
90 QCC_def_t       def_float = {type_float, "temp"};
91 QCC_def_t       def_vector = {type_vector, "temp"};
92 QCC_def_t       def_entity = {type_entity, "temp"};
93 QCC_def_t       def_field = {type_field, "temp"};
94 QCC_def_t       def_function = {type_function, "temp"};
95 QCC_def_t       def_pointer = {type_pointer, "temp"};
96 QCC_def_t       def_integer = {type_integer, "temp"};
97 */
98 QCC_def_t       def_ret, def_parms[MAX_PARMS];
99
100 //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};
101
102 void QCC_PR_LexWhitespace (void);
103
104
105
106
107 //for compiler constants and file includes.
108
109 typedef struct qcc_includechunk_s {
110         struct qcc_includechunk_s *prev;
111         char *filename;
112         char *currentdatapoint;
113         int currentlinenumber;
114         CompilerConstant_t *cnst;
115 } qcc_includechunk_t;
116 qcc_includechunk_t *currentchunk;
117 void QCC_PR_IncludeChunkEx (char *data, pbool duplicate, char *filename, CompilerConstant_t *cnst)
118 {
119         qcc_includechunk_t *chunk = qccHunkAlloc(sizeof(qcc_includechunk_t));
120         chunk->prev = currentchunk;
121         currentchunk = chunk;
122
123         chunk->currentdatapoint = pr_file_p;
124         chunk->currentlinenumber = pr_source_line;
125         chunk->cnst = cnst;
126         if( cnst )
127         {
128                 cnst->inside++;
129         }
130
131         if (duplicate)
132         {
133                 pr_file_p = qccHunkAlloc(strlen(data)+1);
134                 strcpy(pr_file_p, data);
135         }
136         else
137                 pr_file_p = data;
138 }
139 void QCC_PR_IncludeChunk (char *data, pbool duplicate, char *filename)
140 {
141         QCC_PR_IncludeChunkEx(data, duplicate, filename, NULL);
142 }
143
144 pbool QCC_PR_UnInclude(void)
145 {
146         if (!currentchunk)
147                 return false;
148
149         if( currentchunk->cnst )
150                 currentchunk->cnst->inside--;
151
152         pr_file_p = currentchunk->currentdatapoint;
153         pr_source_line = currentchunk->currentlinenumber;
154
155         currentchunk = currentchunk->prev;
156
157         return true;
158 }
159
160
161 /*
162 ==============
163 PR_PrintNextLine
164 ==============
165 */
166 void QCC_PR_PrintNextLine (void)
167 {
168         char    *t;
169
170         printf ("%3i:",pr_source_line);
171         for (t=pr_line_start ; *t && *t != '\n' ; t++)
172                 printf ("%c",*t);
173         printf ("\n");
174 }
175
176 extern char qccmsourcedir[];
177 //also meant to include it.
178 void QCC_FindBestInclude(char *newfile, char *currentfile, char *rootpath)
179 {
180         char fullname[1024];
181         int doubledots;
182
183         char *end = fullname;
184
185         if (!*newfile)
186                 return;
187
188         doubledots = 0;
189         /*count how far up we need to go*/
190         while(!strncmp(newfile, "../", 3) || !strncmp(newfile, "..\\", 3))
191         {
192                 newfile+=3;
193                 doubledots++;
194         }
195
196         currentfile += strlen(rootpath);        //could this be bad?
197
198         strcpy(fullname, rootpath);
199         end = fullname+strlen(end);
200         if (*fullname && end[-1] != '/')
201         {
202                 strcpy(end, "/");
203                 end = end+strlen(end);
204         }
205         strcpy(end, currentfile);
206         end = end+strlen(end);
207
208         while (end > fullname)
209         {
210                 end--;
211                 /*stop at the slash, unless we're meant to go further*/
212                 if (*end == '/' || *end == '\\')
213                 {
214                         if (!doubledots)
215                         {
216                                 end++;
217                                 break;
218                         }
219                         doubledots--;
220                 }
221         }
222
223         strcpy(end, newfile);
224
225         QCC_Include(fullname);
226 }
227
228 pbool defaultnoref;
229 pbool defaultstatic;
230 int ForcedCRC;
231 int QCC_PR_LexInteger (void);
232 void    QCC_AddFile (char *filename);
233 void QCC_PR_LexString (void);
234 pbool QCC_PR_SimpleGetToken (void);
235
236 int ParsePrecompilerIf(void)
237 {
238         CompilerConstant_t *c;
239         int eval = 0;
240         //char *start = pr_file_p; //warning: unused variable Ã¢startâ
241         if (!QCC_PR_SimpleGetToken())
242         {
243                 if (*pr_file_p == '(')
244                 {
245                         eval = ParsePrecompilerIf();
246                         while (*pr_file_p == ' ' || *pr_file_p == '\t')
247                                 pr_file_p++;
248                         if (*pr_file_p != ')')
249                                 QCC_PR_ParseError(ERR_EXPECTED, "unclosed bracket condition\n");
250                 }
251                 else
252                         QCC_PR_ParseError(ERR_EXPECTED, "expected bracket or constant\n");
253         }
254         else if (!strcmp(pr_token, "defined"))
255         {
256                 while (*pr_file_p == ' ' || *pr_file_p == '\t')
257                         pr_file_p++;
258                 if (*pr_file_p != '(')
259                         QCC_PR_ParseError(ERR_EXPECTED, "no opening bracket after defined\n");
260                 else
261                 {
262                         pr_file_p++;
263
264                         QCC_PR_SimpleGetToken();
265                         eval = !!QCC_PR_CheckCompConstDefined(pr_token);
266
267                         while (*pr_file_p == ' ' || *pr_file_p == '\t')
268                                 pr_file_p++;
269                         if (*pr_file_p != ')')
270                                 QCC_PR_ParseError(ERR_EXPECTED, "unclosed defined condition\n");
271                         pr_file_p++;
272                 }
273         }
274         else
275         {
276                 c = QCC_PR_CheckCompConstDefined(pr_token);
277                 if (!c)
278                         eval = atoi(pr_token);
279                 else
280                         eval = atoi(c->value);
281         }
282
283         QCC_PR_SimpleGetToken();
284         if (!strcmp(pr_token, "||"))
285                 eval = ParsePrecompilerIf()||eval;
286         else if (!strcmp(pr_token, "&&"))
287                 eval = ParsePrecompilerIf()&&eval;
288         else if (!strcmp(pr_token, "<="))
289                 eval = eval <= ParsePrecompilerIf();
290         else if (!strcmp(pr_token, ">="))
291                 eval = eval >= ParsePrecompilerIf();
292         else if (!strcmp(pr_token, "<"))
293                 eval = eval < ParsePrecompilerIf();
294         else if (!strcmp(pr_token, ">"))
295                 eval = eval > ParsePrecompilerIf();
296         else if (!strcmp(pr_token, "!="))
297                 eval = eval != ParsePrecompilerIf();
298
299         return eval;
300 }
301 /*
302 ==============
303 QCC_PR_Precompiler
304 ==============
305
306 Runs precompiler stage
307 */
308 pbool QCC_PR_Precompiler(void)
309 {
310         char msg[1024];
311         int ifmode;
312         int a;
313         static int ifs = 0;
314         int level;      //#if level
315         pbool eval = false;
316
317         if (*pr_file_p == '#')
318         {
319                 char *directive;
320                 for (directive = pr_file_p+1; *directive; directive++)  //so #    define works
321                 {
322                         if (*directive == '\r' || *directive == '\n')
323                                 QCC_PR_ParseError(ERR_UNKNOWNPUCTUATION, "Hanging # with no directive\n");
324                         if (*directive > ' ')
325                                 break;
326                 }
327                 if (!strncmp(directive, "define", 6))
328                 {
329                         pr_file_p = directive;
330                         QCC_PR_ConditionCompilation();
331                         while(*pr_file_p != '\n' && *pr_file_p != '\0') //read on until the end of the line
332                         {
333                                 pr_file_p++;
334                         }
335                 }
336                 else if (!strncmp(directive, "undef", 5))
337                 {
338                         pr_file_p = directive+5;
339                         while(*pr_file_p <= ' ')
340                                 pr_file_p++;
341
342                         QCC_PR_SimpleGetToken ();
343                         QCC_PR_UndefineName(pr_token);
344
345         //              QCC_PR_ConditionCompilation();
346                         while(*pr_file_p != '\n' && *pr_file_p != '\0') //read on until the end of the line
347                         {
348                                 pr_file_p++;
349                         }
350                 }
351                 else if (!strncmp(directive, "if", 2))
352                 {
353                         int originalline = pr_source_line;
354                         pr_file_p = directive+2;
355                         if (!strncmp(pr_file_p, "def ", 4))
356                         {
357                                 ifmode = 0;
358                                 pr_file_p+=4;
359                         }
360                         else if (!strncmp(pr_file_p, "ndef ", 5))
361                         {
362                                 ifmode = 1;
363                                 pr_file_p+=5;
364                         }
365                         else
366                         {
367                                 ifmode = 2;
368                                 pr_file_p+=0;
369                                 //QCC_PR_ParseError("bad \"#if\" type");
370                         }
371
372                         if (ifmode == 2)
373                         {
374                                 eval = ParsePrecompilerIf();
375
376                                 if(*pr_file_p != '\n' && *pr_file_p != '\0')    //read on until the end of the line
377                                 {
378                                         QCC_PR_ParseError (ERR_NOENDIF, "junk on the end of #if line");
379                                 }
380                         }
381                         else
382                         {
383                                 QCC_PR_SimpleGetToken ();
384
385         //                      if (!STRCMP(pr_token, "COOP_MODE"))
386         //                              eval = false;
387                                 if (QCC_PR_CheckCompConstDefined(pr_token))
388                                         eval = true;
389
390                                 if (ifmode == 1)
391                                         eval = eval?false:true;
392                         }
393
394                         while(*pr_file_p != '\n' && *pr_file_p != '\0') //read on until the end of the line
395                         {
396                                 pr_file_p++;
397                         }
398                         level = 1;
399
400                         if (eval)
401                                 ifs+=1;
402                         else
403                         {
404                                 while (1)
405                                 {
406                                         while(*pr_file_p && (*pr_file_p==' ' || *pr_file_p == '\t'))
407                                                 pr_file_p++;
408
409                                         if (!*pr_file_p)
410                                         {
411                                                 pr_source_line = originalline;
412                                                 QCC_PR_ParseError (ERR_NOENDIF, "#if with no endif");
413                                         }
414
415                                         if (*pr_file_p == '#')
416                                         {
417                                                 pr_file_p++;
418                                                 while(*pr_file_p==' ' || *pr_file_p == '\t')
419                                                         pr_file_p++;
420                                                 if (!strncmp(pr_file_p, "endif", 5))
421                                                         level--;
422                                                 if (!strncmp(pr_file_p, "if", 2))
423                                                         level++;
424                                                 if (!strncmp(pr_file_p, "else", 4) && level == 1)
425                                                 {
426                                                         ifs+=1;
427                                                         while(*pr_file_p != '\n' && *pr_file_p != '\0') //read on until the end of the line
428                                                         {
429                                                                 pr_file_p++;
430                                                         }
431                                                         break;
432                                                 }
433                                         }
434
435                                         while(*pr_file_p != '\n' && *pr_file_p != '\0') //read on until the end of the line
436                                         {
437                                                 pr_file_p++;
438                                         }
439                                         if (level <= 0)
440                                                 break;
441                                         pr_file_p++;    //next line
442                                         pr_source_line++;
443                                 }
444                         }
445                 }
446                 else if (!strncmp(directive, "else", 4))
447                 {
448                         int originalline = pr_source_line;
449
450                         ifs -= 1;
451                         level = 1;
452
453                         while(*pr_file_p != '\n' && *pr_file_p != '\0') //read on until the end of the line
454                         {
455                                 pr_file_p++;
456                         }
457                         while (1)
458                         {
459                                 while(*pr_file_p && (*pr_file_p==' ' || *pr_file_p == '\t'))
460                                         pr_file_p++;
461
462                                 if (!*pr_file_p)
463                                 {
464                                         pr_source_line = originalline;
465                                         QCC_PR_ParseError(ERR_NOENDIF, "#if with no endif");
466                                 }
467
468                                 if (*pr_file_p == '#')
469                                 {
470                                         pr_file_p++;
471                                         while(*pr_file_p==' ' || *pr_file_p == '\t')
472                                                 pr_file_p++;
473
474                                         if (!strncmp(pr_file_p, "endif", 5))
475                                                 level--;
476                                         if (!strncmp(pr_file_p, "if", 2))
477                                                         level++;
478                                         if (!strncmp(pr_file_p, "else", 4) && level == 1)
479                                         {
480                                                 ifs+=1;
481                                                 break;
482                                         }
483                                 }
484
485                                 while(*pr_file_p != '\n' && *pr_file_p != '\0') //read on until the end of the line
486                                 {
487                                         pr_file_p++;
488                                 }
489                                 if (level <= 0)
490                                         break;
491                                 pr_file_p++;    //go off the end
492                                 pr_source_line++;
493                         }
494                 }
495                 else if (!strncmp(directive, "endif", 5))
496                 {
497                         while(*pr_file_p != '\n' && *pr_file_p != '\0') //read on until the end of the line
498                         {
499                                 pr_file_p++;
500                         }
501                         if (ifs <= 0)
502                                 QCC_PR_ParseError(ERR_NOPRECOMPILERIF, "unmatched #endif");
503                         else
504                                 ifs-=1;
505                 }
506                 else if (!strncmp(directive, "eof", 3))
507                 {
508                         pr_file_p = NULL;
509                         return true;
510                 }
511                 else if (!strncmp(directive, "error", 5))
512                 {
513                         pr_file_p = directive+5;
514                         for (a = 0; a < sizeof(msg)-1 && pr_file_p[a] != '\n' && pr_file_p[a] != '\0'; a++)
515                                 msg[a] = pr_file_p[a];
516
517                         msg[a-1] = '\0';
518
519                         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...
520                         {
521                                 pr_file_p++;
522                         }
523
524                         QCC_PR_ParseError(ERR_HASHERROR, "#Error: %s", msg);
525                 }
526                 else if (!strncmp(directive, "warning", 7))
527                 {
528                         pr_file_p = directive+7;
529                         for (a = 0; a < 1023 && pr_file_p[a] != '\n' && pr_file_p[a] != '\0'; a++)
530                                 msg[a] = pr_file_p[a];
531
532                         msg[a-1] = '\0';
533
534                         while(*pr_file_p != '\n' && *pr_file_p != '\0') //read on until the end of the line
535                         {
536                                 pr_file_p++;
537                         }
538
539                         QCC_PR_ParseWarning(WARN_PRECOMPILERMESSAGE, "#warning: %s", msg);
540                 }
541                 else if (!strncmp(directive, "message", 7))
542                 {
543                         pr_file_p = directive+7;
544                         for (a = 0; a < 1023 && pr_file_p[a] != '\n' && pr_file_p[a] != '\0'; a++)
545                                 msg[a] = pr_file_p[a];
546
547                         msg[a-1] = '\0';
548
549                         while(*pr_file_p != '\n' && *pr_file_p != '\0') //read on until the end of the line
550                         {
551                                 pr_file_p++;
552                         }
553
554                         printf("#message: %s\n", msg);
555                 }
556                 else if (!strncmp(directive, "copyright", 9))
557                 {
558                         pr_file_p = directive+9;
559                         for (a = 0; a < sizeof(msg)-1 && pr_file_p[a] != '\n' && pr_file_p[a] != '\0'; a++)
560                                 msg[a] = pr_file_p[a];
561
562                         msg[a-1] = '\0';
563
564                         while(*pr_file_p != '\n' && *pr_file_p != '\0') //read on until the end of the line
565                         {
566                                 pr_file_p++;
567                         }
568
569                         if (strlen(msg) >= sizeof(QCC_copyright))
570                                 QCC_PR_ParseWarning(WARN_STRINGTOOLONG, "Copyright message is too long\n");
571                         strncpy(QCC_copyright, msg, sizeof(QCC_copyright)-1);
572                 }
573                 else if (!strncmp(directive, "pack", 4))
574                 {
575                         ifmode = 0;
576                         pr_file_p=directive+4;
577                         if (!strncmp(pr_file_p, "id", 2))
578                                 pr_file_p+=3;
579                         else
580                         {
581                                 ifmode = QCC_PR_LexInteger();
582                                 if (ifmode == 0)
583                                         ifmode = 1;
584                                 pr_file_p++;
585                         }
586                         for (a = 0; a < sizeof(msg)-1 && pr_file_p[a] != '\n' && pr_file_p[a] != '\0'; a++)
587                                 msg[a] = pr_file_p[a];
588
589                         msg[a-1] = '\0';
590
591                         while(*pr_file_p != '\n' && *pr_file_p != '\0') //read on until the end of the line
592                         {
593                                 pr_file_p++;
594                         }
595
596                         if (ifmode == 0)
597                                 QCC_packid = atoi(msg);
598                         else if (ifmode <= 5)
599                                 strcpy(QCC_Packname[ifmode-1], msg);
600                         else
601                                 QCC_PR_ParseError(ERR_TOOMANYPACKFILES, "No more than 5 packs are allowed");
602                 }
603                 else if (!strncmp(directive, "forcecrc", 8))
604                 {
605                         pr_file_p=directive+8;
606
607                         ForcedCRC = QCC_PR_LexInteger();
608
609                         pr_file_p++;
610
611                         for (a = 0; a < sizeof(msg)-1 && pr_file_p[a] != '\n' && pr_file_p[a] != '\0'; a++)
612                                 msg[a] = pr_file_p[a];
613
614                         msg[a-1] = '\0';
615
616                         while(*pr_file_p != '\n' && *pr_file_p != '\0') //read on until the end of the line
617                         {
618                                 pr_file_p++;
619                         }
620                 }
621                 else if (!strncmp(directive, "includelist", 11))
622                 {
623                         pr_file_p=directive+11;
624
625                         while(*pr_file_p <= ' ')
626                                 pr_file_p++;
627
628                         while(1)
629                         {
630                                 QCC_PR_LexWhitespace();
631                                 if (!QCC_PR_SimpleGetToken())
632                                 {
633                                         if (!*pr_file_p)
634                                                 QCC_Error(ERR_EOF, "eof in includelist");
635                                         else
636                                         {
637                                                 pr_file_p++;
638                                                 pr_source_line++;
639                                         }
640                                         continue;
641                                 }
642                                 if (!strcmp(pr_token, "#endlist"))
643                                         break;
644
645                                 QCC_FindBestInclude(pr_token, compilingfile, qccmsourcedir);
646
647                                 if (*pr_file_p == '\r')
648                                         pr_file_p++;
649
650                                 for (a = 0; a < sizeof(msg)-1 && pr_file_p[a] != '\n' && pr_file_p[a] != '\0'; a++)
651                                         msg[a] = pr_file_p[a];
652
653                                 msg[a-1] = '\0';
654
655                                 while(*pr_file_p != '\n' && *pr_file_p != '\0') //read on until the end of the line
656                                 {
657                                         pr_file_p++;
658                                 }
659                         }
660
661                         while(*pr_file_p != '\n' && *pr_file_p != '\0') //read on until the end of the line
662                         {
663                                 pr_file_p++;
664                         }
665                 }
666                 else if (!strncmp(directive, "include", 7))
667                 {
668                         char sm;
669
670                         pr_file_p=directive+7;
671
672                         while(*pr_file_p <= ' ')
673                                 pr_file_p++;
674
675                         msg[0] = '\0';
676                         if (*pr_file_p == '\"')
677                                 sm = '\"';
678                         else if (*pr_file_p == '<')
679                                 sm = '>';
680                         else
681                         {
682                                 QCC_PR_ParseError(0, "Not a string literal (on a #include)");
683                                 sm = 0;
684                         }
685                         pr_file_p++;
686                         a=0;
687                         while(*pr_file_p != sm)
688                         {
689                                 if (*pr_file_p == '\n')
690                                 {
691                                         QCC_PR_ParseError(0, "#include continued over line boundry\n");
692                                         break;
693                                 }
694                                 msg[a++] = *pr_file_p;
695                                 pr_file_p++;
696                         }
697                         msg[a] = 0;
698
699                         QCC_FindBestInclude(msg, compilingfile, qccmsourcedir);
700
701                         pr_file_p++;
702
703                         while(*pr_file_p != '\n' && *pr_file_p != '\0' && *pr_file_p <= ' ')
704                                 pr_file_p++;
705
706
707                         while(*pr_file_p != '\n' && *pr_file_p != '\0') //read on until the end of the line
708                         {
709                                 pr_file_p++;
710                         }
711                 }
712                 else if (!strncmp(directive, "datafile", 8))
713                 {
714                         pr_file_p=directive+8;
715
716                         while(*pr_file_p <= ' ')
717                                 pr_file_p++;
718
719                         QCC_PR_LexString();
720                         printf("Including datafile: %s\n", pr_token);
721                         QCC_AddFile(pr_token);
722
723                         pr_file_p++;
724
725                         for (a = 0; a < sizeof(msg)-1 && pr_file_p[a] != '\n' && pr_file_p[a] != '\0'; a++)
726                                 msg[a] = pr_file_p[a];
727
728                         msg[a-1] = '\0';
729
730                         while(*pr_file_p != '\n' && *pr_file_p != '\0') //read on until the end of the line
731                         {
732                                 pr_file_p++;
733                         }
734                 }
735                 else if (!strncmp(directive, "output", 6))
736                 {
737                         extern char             destfile[1024];
738                         pr_file_p=directive+6;
739
740                         while(*pr_file_p <= ' ')
741                                 pr_file_p++;
742
743                         QCC_PR_LexString();
744                         strcpy(destfile, pr_token);
745                         printf("Outputfile: %s\n", destfile);
746
747                         pr_file_p++;
748
749                         for (a = 0; a < sizeof(msg)-1 && pr_file_p[a] != '\n' && pr_file_p[a] != '\0'; a++)
750                                 msg[a] = pr_file_p[a];
751
752                         msg[a-1] = '\0';
753
754                         while(*pr_file_p != '\n' && *pr_file_p != '\0') //read on until the end of the line
755                         {
756                                 pr_file_p++;
757                         }
758                 }
759                 else if (!strncmp(directive, "pragma", 6))
760                 {
761                         pr_file_p=directive+6;
762                         while(*pr_file_p <= ' ')
763                                 pr_file_p++;
764
765                         qcc_token[0] = '\0';
766                         for(a = 0; *pr_file_p != '\n' && *pr_file_p != '\0'; pr_file_p++)       //read on until the end of the line
767                         {
768                                 if ((*pr_file_p == ' ' || *pr_file_p == '\t'|| *pr_file_p == '(') && !*qcc_token)
769                                 {
770                                         msg[a] = '\0';
771                                         strcpy(qcc_token, msg);
772                                         a=0;
773                                         continue;
774                                 }
775                                 msg[a++] = *pr_file_p;
776                         }
777
778                         msg[a] = '\0';
779                         {
780                                 char *end;
781                                 for (end = msg + a-1; end>=msg && *end <= ' '; end--)
782                                         *end = '\0';
783                         }
784
785                         if (!*qcc_token)
786                         {
787                                 strcpy(qcc_token, msg);
788                                 msg[0] = '\0';
789                         }
790
791                         {
792                                 char *end;
793                                 for (end = msg + a-1; end>=msg && *end <= ' '; end--)
794                                         *end = '\0';
795                         }
796
797                         if (!QC_strcasecmp(qcc_token, "DONT_COMPILE_THIS_FILE"))
798                         {
799                                 while (*pr_file_p)
800                                 {
801                                         while(*pr_file_p != '\n' && *pr_file_p != '\0') //read on until the end of the line
802                                                 pr_file_p++;
803
804                                         if (*pr_file_p == '\n')
805                                         {
806                                                 pr_file_p++;
807                                                 QCC_PR_NewLine(false);
808                                         }
809                                 }
810                         }
811                         else if (!QC_strcasecmp(qcc_token, "COPYRIGHT"))
812                         {
813                                 if (strlen(msg) >= sizeof(QCC_copyright))
814                                         QCC_PR_ParseWarning(WARN_STRINGTOOLONG, "Copyright message is too long\n");
815                                 strncpy(QCC_copyright, msg, sizeof(QCC_copyright)-1);
816                         }
817                         else if (!strncmp(qcc_token, "compress", 8))
818                         {
819                                 extern pbool compressoutput;
820                                 compressoutput = atoi(msg);
821                         }
822                         else if (!strncmp(qcc_token, "forcecrc", 8))
823                         {
824                                 ForcedCRC = atoi(msg);
825                         }
826                         else if (!strncmp(qcc_token, "noref", 8))
827                         {
828                                 defaultnoref = atoi(msg);
829                         }
830                         else if (!strncmp(qcc_token, "defaultstatic", 13))
831                         {
832                                 defaultstatic = atoi(msg);
833                         }
834                         else if (!strncmp(qcc_token, "sourcefile", 10))
835                         {
836         #define MAXSOURCEFILESLIST 8
837         extern char sourcefileslist[MAXSOURCEFILESLIST][1024];
838         //extern int currentsourcefile; // warning: unused variable Ã¢currentsourcefileâ
839         extern int numsourcefiles;
840
841                                 int i;
842
843                                 QCC_COM_Parse(msg);
844
845                                 for (i = 0; i < numsourcefiles; i++)
846                                 {
847                                         if (!strcmp(sourcefileslist[i], qcc_token))
848                                                 break;
849                                 }
850                                 if (i == numsourcefiles)
851                                         strcpy(sourcefileslist[numsourcefiles++], qcc_token);
852                         }
853                         else if (!QC_strcasecmp(qcc_token, "TARGET"))
854                         {
855                                 if (qcc_targetformat == QCF_HEXEN2 && numstatements)
856                                         QCC_PR_ParseWarning(WARN_BADTARGET, "Cannot switch from hexen2 target \'%s\'. Ignored.", msg);
857                                 else if (!QC_strcasecmp(msg, "H2") || !QC_strcasecmp(msg, "HEXEN2"))
858                                 {
859                                         if (numstatements)
860                                                 QCC_PR_ParseWarning(WARN_BADTARGET, "Cannot switch from hexen2 target \'%s\'. Ignored.", msg);
861                                         else
862                                                 qcc_targetformat = QCF_HEXEN2;
863                                 }
864                                 else if (!QC_strcasecmp(msg, "KK7"))
865                                         qcc_targetformat = QCF_KK7;
866                                 else if (!QC_strcasecmp(msg, "DP") || !QC_strcasecmp(msg, "DARKPLACES"))
867                                         qcc_targetformat = QCF_DARKPLACES;
868                                 else if (!QC_strcasecmp(msg, "FTEDEBUG"))
869                                         qcc_targetformat = QCF_FTEDEBUG;
870                                 else if (!QC_strcasecmp(msg, "FTE"))
871                                         qcc_targetformat = QCF_FTE;
872                                 else if (!QC_strcasecmp(msg, "STANDARD") || !QC_strcasecmp(msg, "ID"))
873                                         qcc_targetformat = QCF_STANDARD;
874                                 else if (!QC_strcasecmp(msg, "DEBUG"))
875                                         qcc_targetformat = QCF_FTEDEBUG;
876                                 else if (!QC_strcasecmp(msg, "QTEST"))
877                                         qcc_targetformat = QCF_QTEST;
878                                 else
879                                         QCC_PR_ParseWarning(WARN_BADTARGET, "Unknown target \'%s\'. Ignored.", msg);
880                         }
881                         else if (!QC_strcasecmp(qcc_token, "PROGS_SRC"))
882                         {       //doesn't make sence, but silenced if you are switching between using a certain precompiler app used with CuTF.
883                         }
884                         else if (!QC_strcasecmp(qcc_token, "PROGS_DAT"))
885                         {       //doesn't make sence, but silenced if you are switching between using a certain precompiler app used with CuTF.
886                                 extern char             destfile[1024];
887 #ifndef QCCONLY
888                                 extern char qccmfilename[1024];
889                                 int p;
890                                 char *s, *s2;
891 #endif
892                                 QCC_COM_Parse(msg);
893
894 #ifndef QCCONLY
895         p=0;
896         s2 = qcc_token;
897         if (!strncmp(s2, "./", 2))
898                 s2+=2;
899         else
900         {
901                 while(!strncmp(s2, "../", 3))
902                 {
903                         s2+=3;
904                         p++;
905                 }
906         }
907         strcpy(qccmfilename, qccmsourcedir);
908         for (s=qccmfilename+strlen(qccmfilename);p && s>=qccmfilename; s--)
909         {
910                 if (*s == '/' || *s == '\\')
911                 {
912                         *(s+1) = '\0';
913                         p--;
914                 }
915         }
916         sprintf(destfile, "%s", s2);
917
918         while (p>0)
919         {
920                 memmove(destfile+3, destfile, strlen(destfile)+1);
921                 destfile[0] = '.';
922                 destfile[1] = '.';
923                 destfile[2] = '/';
924                 p--;
925         }
926 #else
927
928                                 strcpy(destfile, qcc_token);
929 #endif
930                                 printf("Outputfile: %s\n", destfile);
931                         }
932                         else if (!QC_strcasecmp(qcc_token, "keyword") || !QC_strcasecmp(qcc_token, "flag"))
933                         {
934                                 char *s;
935                                 int st;
936                                 s = QCC_COM_Parse(msg);
937                                 if (!QC_strcasecmp(qcc_token, "enable") || !QC_strcasecmp(qcc_token, "on"))
938                                         st = 1;
939                                 else if (!QC_strcasecmp(qcc_token, "disable") || !QC_strcasecmp(qcc_token, "off"))
940                                         st = 0;
941                                 else
942                                 {
943                                         QCC_PR_ParseWarning(WARN_BADPRAGMA, "compiler flag state not recognised");
944                                         st = -1;
945                                 }
946                                 if (st < 0)
947                                         QCC_PR_ParseWarning(WARN_BADPRAGMA, "warning id not recognised");
948                                 else
949                                 {
950                                         int f;
951                                         s = QCC_COM_Parse(s);
952
953                                         for (f = 0; compiler_flag[f].enabled; f++)
954                                         {
955                                                 if (!QC_strcasecmp(compiler_flag[f].abbrev, qcc_token))
956                                                 {
957                                                         if (compiler_flag[f].flags & FLAG_MIDCOMPILE)
958                                                                 *compiler_flag[f].enabled = st;
959                                                         else
960                                                                 QCC_PR_ParseWarning(WARN_BADPRAGMA, "Cannot enable/disable keyword/flag via a pragma");
961                                                         break;
962                                                 }
963                                         }
964                                         if (!compiler_flag[f].enabled)
965                                                 QCC_PR_ParseWarning(WARN_BADPRAGMA, "keyword/flag not recognised");
966
967                                 }
968                         }
969                         else if (!QC_strcasecmp(qcc_token, "warning"))
970                         {
971                                 int st;
972                                 char *s;
973                                 s = QCC_COM_Parse(msg);
974                                 if (!stricmp(qcc_token, "enable") || !stricmp(qcc_token, "on"))
975                                         st = 0;
976                                 else if (!stricmp(qcc_token, "disable") || !stricmp(qcc_token, "off"))
977                                         st = 1;
978                                 else if (!stricmp(qcc_token, "toggle"))
979                                         st = 2;
980                                 else
981                                 {
982                                         QCC_PR_ParseWarning(WARN_BADPRAGMA, "warning state not recognised");
983                                         st = -1;
984                                 }
985                                 if (st>=0)
986                                 {
987                                         int wn;
988                                         s = QCC_COM_Parse(s);
989                                         wn = QCC_WarningForName(qcc_token);
990                                         if (wn < 0)
991                                                 QCC_PR_ParseWarning(WARN_BADPRAGMA, "warning id not recognised");
992                                         else
993                                         {
994                                                 if (st == 2)    //toggle
995                                                         qccwarningdisabled[wn] = true - qccwarningdisabled[wn];
996                                                 else
997                                                         qccwarningdisabled[wn] = st;
998                                         }
999                                 }
1000                         }
1001                         else
1002                                 QCC_PR_ParseWarning(WARN_BADPRAGMA, "Unknown pragma \'%s\'", qcc_token);
1003                 }
1004                 return true;
1005         }
1006
1007         return false;
1008 }
1009
1010 /*
1011 ==============
1012 PR_NewLine
1013
1014 Call at start of file and when *pr_file_p == '\n'
1015 ==============
1016 */
1017 void QCC_PR_NewLine (pbool incomment)
1018 {
1019         pr_source_line++;
1020         pr_line_start = pr_file_p;
1021         while(*pr_file_p==' ' || *pr_file_p == '\t')
1022                 pr_file_p++;
1023         if (incomment)  //no constants if in a comment.
1024         {
1025         }
1026         else if (QCC_PR_Precompiler())
1027         {
1028         }
1029
1030 //      if (pr_dumpasm)
1031 //              PR_PrintNextLine ();
1032 }
1033
1034 /*
1035 ==============
1036 PR_LexString
1037
1038 Parses a quoted string
1039 ==============
1040 */
1041 #if 0
1042 void QCC_PR_LexString (void)
1043 {
1044         int             c;
1045         int             len;
1046         char tmpbuf[2048];
1047
1048         char *text;
1049         char *oldf;
1050         int oldline;
1051
1052         bool fromfile = true;
1053
1054         len = 0;
1055
1056         text = pr_file_p;
1057         do
1058         {
1059                 QCC_COM_Parse(text);
1060 //              print("Next token is \"%s\"\n", com_token);
1061                 if (*text == '\"')
1062                 {
1063                         text++;
1064                         if (fromfile) pr_file_p++;
1065                 }
1066         do
1067         {
1068                 c = *text++;
1069                 if (fromfile) pr_file_p++;
1070                 if (!c)
1071                         QCC_PR_ParseError ("EOF inside quote");
1072                 if (c=='\n')
1073                         QCC_PR_ParseError ("newline inside quote");
1074                 if (c=='\\')
1075                 {       // escape char
1076                         c = *text++;
1077                         if (fromfile) pr_file_p++;
1078                         if (!c)
1079                                 QCC_PR_ParseError ("EOF inside quote");
1080                         if (c == 'n')
1081                                 c = '\n';
1082                         else if (c == '"')
1083                                 c = '"';
1084                         else if (c == '\\')
1085                                 c = '\\';
1086                         else
1087                                 QCC_PR_ParseError ("Unknown escape char");
1088                 }
1089                 else if (c=='\"')
1090                 {
1091                         if (fromfile) pr_file_p++;
1092                         break;
1093                 }
1094                 tmpbuf[len] = c;
1095                 len++;
1096         } while (1);
1097                 tmpbuf[len] = 0;
1098 //              if (fromfile) pr_file_p++;
1099
1100                 pr_immediate_type=NULL;
1101                 oldline=pr_source_line;
1102                 oldf=pr_file_p;
1103                 QCC_PR_Lex();
1104                 if (pr_immediate_type == &type_string)
1105                 {
1106 //                      print("Appending \"%s\" to \"%s\"\n", pr_immediate_string, tmpbuf);
1107                         strcat(tmpbuf, pr_immediate_string);
1108                         len+=strlen(pr_immediate_string);
1109                 }
1110                 else
1111                 {
1112                         pr_source_line = oldline;
1113                         pr_file_p = oldf-1;
1114                         QCC_PR_LexWhitespace();
1115                         if (*pr_file_p != '\"') //annother string
1116                                 break;
1117                 }
1118
1119                 QCC_PR_LexWhitespace();
1120                 text = pr_file_p;
1121
1122         } while (1);
1123
1124         strcpy(pr_token, tmpbuf);
1125         pr_token_type = tt_immediate;
1126         pr_immediate_type = &type_string;
1127         strcpy (pr_immediate_string, pr_token);
1128
1129 //      print("Found \"%s\"\n", pr_immediate_string);
1130 }
1131 #else
1132 void QCC_PR_LexString (void)
1133 {
1134         int             c;
1135         int             len;
1136         char    *end, *cnst;
1137
1138         int texttype=0;
1139
1140         len = 0;
1141         pr_file_p++;
1142         do
1143         {
1144                 c = *pr_file_p++;
1145                 if (!c)
1146                         QCC_PR_ParseError (ERR_EOF, "EOF inside quote");
1147                 if (c=='\n')
1148                         QCC_PR_ParseError (ERR_INVALIDSTRINGIMMEDIATE, "newline inside quote");
1149                 if (c=='\\')
1150                 {       // escape char
1151                         c = *pr_file_p++;
1152                         if (!c)
1153                                 QCC_PR_ParseError (ERR_EOF, "EOF inside quote");
1154                         if (c == 'n')
1155                                 c = '\n';
1156                         else if (c == 'r')
1157                                 c = '\r';
1158                         else if (c == '"')
1159                                 c = '"';
1160                         else if (c == 't')
1161                                 c = '\t';
1162                         else if (c == 'a')
1163                                 c = '\a';
1164                         else if (c == 'v')
1165                                 c = '\v';
1166                         else if (c == 'f')
1167                                 c = '\f';
1168                         else if (c == 's' || c == 'b')
1169                         {
1170                                 texttype ^= 128;
1171                                 continue;
1172                         }
1173                         else if (c == '[')
1174                                 c = 16;
1175                         else if (c == ']')
1176                                 c = 17;
1177                         else if (c == '{')
1178                         {
1179                                 int d;
1180                                 c = 0;
1181                                 while ((d = *pr_file_p++) != '}')
1182                                 {
1183                                         c = c * 10 + d - '0';
1184                                         if (d < '0' || d > '9' || c > 255)
1185                                                 QCC_PR_ParseError(ERR_BADCHARACTERCODE, "Bad character code");
1186                                 }
1187                         }
1188                         else if (c == '<')
1189                                 c = 29;
1190                         else if (c == '-')
1191                                 c = 30;
1192                         else if (c == '>')
1193                                 c = 31;
1194                         else if (c == 'x' || c == 'X')
1195                         {
1196                                 int d;
1197                                 c = 0;
1198
1199                                 d = (unsigned char)*pr_file_p++;
1200                                 if (d >= '0' && d <= '9')
1201                                         c += d - '0';
1202                                 else if (d >= 'A' && d <= 'F')
1203                                         c += d - 'A' + 10;
1204                                 else if (d >= 'a' && d <= 'f')
1205                                         c += d - 'a' + 10;
1206                                 else
1207                                         QCC_PR_ParseError(ERR_BADCHARACTERCODE, "Bad character code");
1208
1209                                 c *= 16;
1210
1211                                 d = (unsigned char)*pr_file_p++;
1212                                 if (d >= '0' && d <= '9')
1213                                         c += d - '0';
1214                                 else if (d >= 'A' && d <= 'F')
1215                                         c += d - 'A' + 10;
1216                                 else if (d >= 'a' && d <= 'f')
1217                                         c += d - 'a' + 10;
1218                                 else
1219                                         QCC_PR_ParseError(ERR_BADCHARACTERCODE, "Bad character code");
1220                         }
1221                         else if (c == '\\')
1222                                 c = '\\';
1223                         else if (c == '\'')
1224                                 c = '\'';
1225                         else if (c >= '0' && c <= '9')
1226                                 c = 18 + c - '0';
1227                         else if (c == '\r')
1228                         {       //sigh
1229                                 c = *pr_file_p++;
1230                                 if (c != '\n')
1231                                         QCC_PR_ParseWarning(WARN_HANGINGSLASHR, "Hanging \\\\\r");
1232                                 pr_source_line++;
1233                         }
1234                         else if (c == '\n')
1235                         {       //sigh
1236                                 pr_source_line++;
1237                         }
1238                         else
1239                                 QCC_PR_ParseError (ERR_INVALIDSTRINGIMMEDIATE, "Unknown escape char %c", c);
1240                 }
1241                 else if (c=='\"')
1242                 {
1243                         if (len >= sizeof(pr_immediate_string)-1)
1244                                 QCC_Error(ERR_INVALIDSTRINGIMMEDIATE, "String length exceeds %i", sizeof(pr_immediate_string)-1);
1245
1246                         while(*pr_file_p && *pr_file_p <= ' ')
1247                         {
1248                                 if (*pr_file_p == '\n')
1249                                 {
1250                                         pr_file_p++;
1251                                         QCC_PR_NewLine(false);
1252                                 }
1253                                 else
1254                                         pr_file_p++;
1255                         }
1256                         if (*pr_file_p == '\"') //have annother go
1257                         {
1258                                 pr_file_p++;
1259                                 continue;
1260                         }
1261                         pr_token[len] = 0;
1262                         pr_token_type = tt_immediate;
1263                         pr_immediate_type = type_string;
1264                         strcpy (pr_immediate_string, pr_token);
1265                         return;
1266                 }
1267                 else if (c == '#')
1268                 {
1269                         for (end = pr_file_p; ; end++)
1270                         {
1271                                 if (*end <= ' ')
1272                                         break;
1273
1274                                 if (*end == ')'
1275                                         ||      *end == '('
1276                                         ||      *end == '+'
1277                                         ||      *end == '-'
1278                                         ||      *end == '*'
1279                                         ||      *end == '/'
1280                                         ||      *end == '\\'
1281                                         ||      *end == '|'
1282                                         ||      *end == '&'
1283                                         ||      *end == '='
1284                                         ||      *end == '^'
1285                                         ||      *end == '~'
1286                                         ||      *end == '['
1287                                         ||      *end == ']'
1288                                         ||      *end == '\"'
1289                                         ||      *end == '{'
1290                                         ||      *end == '}'
1291                                         ||      *end == ';'
1292                                         ||      *end == ':'
1293                                         ||      *end == ','
1294                                         ||      *end == '.'
1295                                         ||      *end == '#')
1296                                                 break;
1297                         }
1298
1299                         c = *end;
1300                         *end = '\0';
1301                         cnst = QCC_PR_CheakCompConstString(pr_file_p);
1302                         if (cnst==pr_file_p)
1303                                 cnst=NULL;
1304                         *end = c;
1305                         c = '#';        //undo
1306                         if (cnst)
1307                         {
1308                                 QCC_PR_ParseWarning(WARN_MACROINSTRING, "Macro expansion in string");
1309
1310                                 if (len+strlen(cnst) >= sizeof(pr_token)-1)
1311                                         QCC_Error(ERR_INVALIDSTRINGIMMEDIATE, "String length exceeds %i", sizeof(pr_token)-1);
1312
1313                                 strcpy(pr_token+len, cnst);
1314                                 len+=strlen(cnst);
1315                                 pr_file_p = end;
1316                                 continue;
1317                         }
1318                 }
1319                 else if (c == 0x7C && flag_acc) //reacc support... reacc is strange.
1320                         c = '\n';
1321                 else
1322                         c |= texttype;
1323
1324                 pr_token[len] = c;
1325                 len++;
1326                 if (len >= sizeof(pr_token)-1)
1327                         QCC_Error(ERR_INVALIDSTRINGIMMEDIATE, "String length exceeds %i", sizeof(pr_token)-1);
1328         } while (1);
1329 }
1330 #endif
1331
1332 /*
1333 ==============
1334 PR_LexNumber
1335 ==============
1336 */
1337 int QCC_PR_LexInteger (void)
1338 {
1339         int             c;
1340         int             len;
1341
1342         len = 0;
1343         c = *pr_file_p;
1344         if (pr_file_p[0] == '0' && pr_file_p[1] == 'x')
1345         {
1346                 pr_token[0] = '0';
1347                 pr_token[1] = 'x';
1348                 len = 2;
1349                 c = *(pr_file_p+=2);
1350         }
1351         do
1352         {
1353                 pr_token[len] = c;
1354                 len++;
1355                 pr_file_p++;
1356                 c = *pr_file_p;
1357         } while ((c >= '0' && c<= '9') || c == '.' || (c>='a' && c <= 'f'));
1358         pr_token[len] = 0;
1359         return atoi (pr_token);
1360 }
1361
1362 void QCC_PR_LexNumber (void)
1363 {
1364         int tokenlen = 0;
1365         int num=0;
1366         int base=0;
1367         int c;
1368         int sign=1;
1369         if (*pr_file_p == '-')
1370         {
1371                 sign=-1;
1372                 pr_file_p++;
1373
1374                 pr_token[tokenlen++] = '-';
1375         }
1376         if (pr_file_p[0] == '0' && pr_file_p[1] == 'x')
1377         {
1378                 pr_file_p+=2;
1379                 base = 16;
1380
1381                 pr_token[tokenlen++] = '0';
1382                 pr_token[tokenlen++] = 'x';
1383         }
1384
1385         pr_immediate_type = NULL;
1386         //assume base 10 if not stated
1387         if (!base)
1388                 base = 10;
1389
1390         while((c = *pr_file_p))
1391         {
1392                 if (c >= '0' && c <= '9')
1393                 {
1394                         pr_token[tokenlen++] = c;
1395                         num*=base;
1396                         num += c-'0';
1397                 }
1398                 else if (c >= 'a' && c <= 'f' && base > 10)
1399                 {
1400                         pr_token[tokenlen++] = c;
1401                         num*=base;
1402                         num += c -'a'+10;
1403                 }
1404                 else if (c >= 'A' && c <= 'F' && base > 10)
1405                 {
1406                         pr_token[tokenlen++] = c;
1407                         num*=base;
1408                         num += c -'A'+10;
1409                 }
1410                 else if (c == '.')
1411                 {
1412                         pr_token[tokenlen++] = c;
1413                         pr_file_p++;
1414                         pr_immediate_type = type_float;
1415                         while(1)
1416                         {
1417                                 c = *pr_file_p;
1418                                 if (c >= '0' && c <= '9')
1419                                 {
1420                                         pr_token[tokenlen++] = c;
1421                                 }
1422                                 else if (c == 'f')
1423                                 {
1424                                         pr_file_p++;
1425                                         break;
1426                                 }
1427                                 else
1428                                 {
1429                                         break;
1430                                 }
1431                                 pr_file_p++;
1432                         }
1433                         pr_token[tokenlen++] = 0;
1434                         pr_immediate._float = (float)atof(pr_token);
1435                         return;
1436                 }
1437                 else if (c == 'i')
1438                 {
1439                         pr_token[tokenlen++] = c;
1440                         pr_token[tokenlen++] = 0;
1441                         pr_file_p++;
1442                         pr_immediate_type = type_integer;
1443                         pr_immediate._int = num*sign;
1444                         return;
1445                 }
1446                 else
1447                         break;
1448                 pr_file_p++;
1449         }
1450         pr_token[tokenlen++] = 0;
1451
1452         if (!pr_immediate_type)
1453         {
1454                 if (flag_assume_integer)
1455                         pr_immediate_type = type_integer;
1456                 else
1457                         pr_immediate_type = type_float;
1458         }
1459
1460         if (pr_immediate_type == type_integer)
1461         {
1462                 pr_immediate_type = type_integer;
1463                 pr_immediate._int = num*sign;
1464         }
1465         else
1466         {
1467                 pr_immediate_type = type_float;
1468                 // at this point, we know there's no . in it, so the NaN bug shouldn't happen
1469                 // and we cannot use atof on tokens like 0xabc, so use num*sign, it SHOULD be safe
1470                 //pr_immediate._float = atof(pr_token);
1471                 pr_immediate._float = (float)(num*sign);
1472         }
1473 }
1474
1475
1476 float QCC_PR_LexFloat (void)
1477 {
1478         int             c;
1479         int             len;
1480
1481         len = 0;
1482         c = *pr_file_p;
1483         do
1484         {
1485                 pr_token[len] = c;
1486                 len++;
1487                 pr_file_p++;
1488                 c = *pr_file_p;
1489         } while ((c >= '0' && c<= '9') || (c == '.'&&pr_file_p[1]!='.'));       //only allow a . if the next isn't too...
1490         pr_token[len] = 0;
1491         return (float)atof (pr_token);
1492 }
1493
1494 /*
1495 ==============
1496 PR_LexVector
1497
1498 Parses a single quoted vector
1499 ==============
1500 */
1501 void QCC_PR_LexVector (void)
1502 {
1503         int             i;
1504
1505         pr_file_p++;
1506
1507         if (*pr_file_p == '\\')
1508         {//extended character constant
1509                 pr_token_type = tt_immediate;
1510                 pr_immediate_type = type_float;
1511                 pr_file_p++;
1512                 switch(*pr_file_p)
1513                 {
1514                 case 'n':
1515                         pr_immediate._float = '\n';
1516                         break;
1517                 case 'r':
1518                         pr_immediate._float = '\r';
1519                         break;
1520                 case 't':
1521                         pr_immediate._float = '\t';
1522                         break;
1523                 case '\'':
1524                         pr_immediate._float = '\'';
1525                         break;
1526                 case '\"':
1527                         pr_immediate._float = '\"';
1528                         break;
1529                 case '\\':
1530                         pr_immediate._float = '\\';
1531                         break;
1532                 default:
1533                         QCC_PR_ParseError (ERR_INVALIDVECTORIMMEDIATE, "Bad character constant");
1534                 }
1535                 if (*pr_file_p != '\'')
1536                         QCC_PR_ParseError (ERR_INVALIDVECTORIMMEDIATE, "Bad character constant");
1537                 pr_file_p++;
1538                 return;
1539         }
1540         if (pr_file_p[1] == '\'')
1541         {//character constant
1542                 pr_token_type = tt_immediate;
1543                 pr_immediate_type = type_float;
1544                 pr_immediate._float = pr_file_p[0];
1545                 pr_file_p+=2;
1546                 return;
1547         }
1548         pr_token_type = tt_immediate;
1549         pr_immediate_type = type_vector;
1550         QCC_PR_LexWhitespace ();
1551         for (i=0 ; i<3 ; i++)
1552         {
1553                 pr_immediate.vector[i] = QCC_PR_LexFloat ();
1554                 QCC_PR_LexWhitespace ();
1555
1556                 if (*pr_file_p == '\'' && i == 1)
1557                 {
1558                         if (i < 2)
1559                                 QCC_PR_ParseWarning (WARN_FTE_SPECIFIC, "Bad vector");
1560
1561                         for (i++ ; i<3 ; i++)
1562                                 pr_immediate.vector[i] = 0;
1563                         break;
1564                 }
1565         }
1566         if (*pr_file_p != '\'')
1567                 QCC_PR_ParseError (ERR_INVALIDVECTORIMMEDIATE, "Bad vector");
1568         pr_file_p++;
1569 }
1570
1571 /*
1572 ==============
1573 PR_LexName
1574
1575 Parses an identifier
1576 ==============
1577 */
1578 void QCC_PR_LexName (void)
1579 {
1580         int             c;
1581         int             len;
1582
1583         len = 0;
1584         c = *pr_file_p;
1585         do
1586         {
1587                 pr_token[len] = c;
1588                 len++;
1589                 pr_file_p++;
1590                 c = *pr_file_p;
1591         } while ( (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_'
1592         || (c >= '0' && c <= '9'));
1593
1594         pr_token[len] = 0;
1595         pr_token_type = tt_name;
1596 }
1597
1598 /*
1599 ==============
1600 PR_LexPunctuation
1601 ==============
1602 */
1603 void QCC_PR_LexPunctuation (void)
1604 {
1605         int             i;
1606         int             len;
1607         char    *p;
1608
1609         pr_token_type = tt_punct;
1610
1611         for (i=0 ; (p = pr_punctuation[i]) != NULL ; i++)
1612         {
1613                 len = strlen(p);
1614                 if (!strncmp(p, pr_file_p, len) )
1615                 {
1616                         strcpy (pr_token, pr_punctuationremap[i]);
1617                         if (p[0] == '{')
1618                                 pr_bracelevel++;
1619                         else if (p[0] == '}')
1620                                 pr_bracelevel--;
1621                         pr_file_p += len;
1622                         return;
1623                 }
1624         }
1625
1626         QCC_PR_ParseError (ERR_UNKNOWNPUCTUATION, "Unknown punctuation");
1627 }
1628
1629
1630 /*
1631 ==============
1632 PR_LexWhitespace
1633 ==============
1634 */
1635 void QCC_PR_LexWhitespace (void)
1636 {
1637         int             c;
1638
1639         while (1)
1640         {
1641         // skip whitespace
1642                 while ( (c = *pr_file_p) <= ' ')
1643                 {
1644                         if (c=='\n')
1645                         {
1646                                 pr_file_p++;
1647                                 QCC_PR_NewLine (false);
1648                                 if (!pr_file_p)
1649                                         return;
1650                         }
1651                         else
1652                         {
1653                                 if (c == 0)
1654                                         return;         // end of file
1655                                 pr_file_p++;
1656                         }
1657                 }
1658
1659         // skip // comments
1660                 if (c=='/' && pr_file_p[1] == '/')
1661                 {
1662                         while (*pr_file_p && *pr_file_p != '\n')
1663                                 pr_file_p++;
1664
1665                         if (*pr_file_p == '\n')
1666                                 pr_file_p++;    //don't break on eof.
1667                         QCC_PR_NewLine(false);
1668                         continue;
1669                 }
1670
1671         // skip /* */ comments
1672                 if (c=='/' && pr_file_p[1] == '*')
1673                 {
1674                         pr_file_p+=2;
1675                         do
1676                         {
1677                                 if (pr_file_p[0]=='\n')
1678                                 {
1679                                         QCC_PR_NewLine(true);
1680                                 }
1681                                 if (pr_file_p[1] == 0)
1682                                 {
1683                                         pr_file_p++;
1684                                         return;
1685                                 }
1686                                 pr_file_p++;
1687                         } while (pr_file_p[0] != '*' || pr_file_p[1] != '/');
1688                         pr_file_p+=2;
1689                         continue;
1690                 }
1691
1692                 break;          // a real character has been found
1693         }
1694 }
1695
1696 //============================================================================
1697
1698 #define MAX_FRAMES      8192
1699 char    pr_framemodelname[64];
1700 char    pr_framemacros[MAX_FRAMES][64];
1701 int             pr_framemacrovalue[MAX_FRAMES];
1702 int             pr_nummacros, pr_oldmacros;
1703 int             pr_macrovalue;
1704 int             pr_savedmacro;
1705
1706 void QCC_PR_ClearGrabMacros (void)
1707 {
1708         pr_oldmacros = pr_nummacros;
1709 //      pr_nummacros = 0;
1710         pr_macrovalue = 0;
1711         pr_savedmacro = -1;
1712 }
1713
1714 int QCC_PR_FindMacro (char *name)
1715 {
1716         int             i;
1717
1718         for (i=pr_nummacros-1 ; i>=0 ; i--)
1719         {
1720                 if (!STRCMP (name, pr_framemacros[i]))
1721                 {
1722                         return pr_framemacrovalue[i];
1723                 }
1724         }
1725         for (i=pr_nummacros-1 ; i>=0 ; i--)
1726         {
1727                 if (!stricmp (name, pr_framemacros[i]))
1728                 {
1729                         QCC_PR_ParseWarning(WARN_CASEINSENSATIVEFRAMEMACRO, "Case insensative frame macro");
1730                         return pr_framemacrovalue[i];
1731                 }
1732         }
1733         return -1;
1734 }
1735
1736 void QCC_PR_ExpandMacro(void)
1737 {
1738         int             i = QCC_PR_FindMacro(pr_token);
1739
1740         if (i < 0)
1741                 QCC_PR_ParseError (ERR_BADFRAMEMACRO, "Unknown frame macro $%s", pr_token);
1742
1743         sprintf (pr_token,"%d", i);
1744         pr_token_type = tt_immediate;
1745         pr_immediate_type = type_float;
1746         pr_immediate._float = (float)i;
1747 }
1748
1749 // just parses text, returning false if an eol is reached
1750 pbool QCC_PR_SimpleGetToken (void)
1751 {
1752         int             c;
1753         int             i;
1754
1755         pr_token[0] = 0;
1756
1757 // skip whitespace
1758         while ( (c = *pr_file_p) <= ' ')
1759         {
1760                 if (c=='\n' || c == 0)
1761                         return false;
1762                 pr_file_p++;
1763         }
1764         if (pr_file_p[0] == '/')
1765         {
1766                 if (pr_file_p[1] == '/')
1767                 {       //comment alert
1768                         while(*pr_file_p && *pr_file_p != '\n')
1769                                 pr_file_p++;
1770                         return false;
1771                 }
1772                 if (pr_file_p[1] == '*')
1773                         return false;
1774         }
1775
1776         i = 0;
1777         while ( (c = *pr_file_p) > ' ' && c != ',' && c != ';' && c != ')' && c != '(' && c != ']')
1778         {
1779                 pr_token[i] = c;
1780                 i++;
1781                 pr_file_p++;
1782         }
1783         pr_token[i] = 0;
1784         return i!=0;
1785 }
1786
1787 pbool QCC_PR_LexMacroName(void)
1788 {
1789         int             c;
1790         int             i;
1791
1792         pr_token[0] = 0;
1793
1794 // skip whitespace
1795         while ( (c = *pr_file_p) <= ' ')
1796         {
1797                 if (c=='\n' || c == 0)
1798                         return false;
1799                 pr_file_p++;
1800         }
1801         if (pr_file_p[0] == '/')
1802         {
1803                 if (pr_file_p[1] == '/')
1804                 {       //comment alert
1805                         while(*pr_file_p && *pr_file_p != '\n')
1806                                 pr_file_p++;
1807                         return false;
1808                 }
1809                 if (pr_file_p[1] == '*')
1810                         return false;
1811         }
1812
1813         i = 0;
1814         while ( (c = *pr_file_p) > ' ' && c != '\n' && c != ',' && c != ';' && c != ')' && c != '(' && c != ']' && !(pr_file_p[0] == '.' && pr_file_p[1] == '.'))
1815         {
1816                 pr_token[i] = c;
1817                 i++;
1818                 pr_file_p++;
1819         }
1820         pr_token[i] = 0;
1821         return i!=0;
1822 }
1823
1824 void QCC_PR_MacroFrame(char *name, int value)
1825 {
1826         int i;
1827         for (i=pr_nummacros-1 ; i>=0 ; i--)
1828         {
1829                 if (!STRCMP (name, pr_framemacros[i]))
1830                 {
1831                         pr_framemacrovalue[i] = value;
1832                         if (i>=pr_oldmacros)
1833                                 QCC_PR_ParseWarning(WARN_DUPLICATEMACRO, "Duplicate macro defined (%s)", pr_token);
1834                         //else it's from an old file, and shouldn't be mentioned.
1835                         return;
1836                 }
1837         }
1838
1839         if (strlen(name)+1 > sizeof(pr_framemacros[0]))
1840                 QCC_PR_ParseWarning(ERR_TOOMANYFRAMEMACROS, "Name for frame macro %s is too long", name);
1841         else
1842         {
1843                 strcpy (pr_framemacros[pr_nummacros], name);
1844                 pr_framemacrovalue[pr_nummacros] = value;
1845                 pr_nummacros++;
1846                 if (pr_nummacros >= MAX_FRAMES)
1847                         QCC_PR_ParseError(ERR_TOOMANYFRAMEMACROS, "Too many frame macros defined");
1848         }
1849 }
1850
1851 void QCC_PR_ParseFrame (void)
1852 {
1853         while (QCC_PR_LexMacroName ())
1854         {
1855                 QCC_PR_MacroFrame(pr_token, pr_macrovalue++);
1856         }
1857 }
1858
1859 /*
1860 ==============
1861 PR_LexGrab
1862
1863 Deals with counting sequence numbers and replacing frame macros
1864 ==============
1865 */
1866 void QCC_PR_LexGrab (void)
1867 {
1868         pr_file_p++;    // skip the $
1869 //      if (!QCC_PR_SimpleGetToken ())
1870 //              QCC_PR_ParseError ("hanging $");
1871         if (*pr_file_p <= ' ')
1872                 QCC_PR_ParseError (ERR_BADFRAMEMACRO, "hanging $");
1873         QCC_PR_LexMacroName();
1874         if (!*pr_token)
1875                 QCC_PR_ParseError (ERR_BADFRAMEMACRO, "hanging $");
1876
1877 // check for $frame
1878         if (!STRCMP (pr_token, "frame") || !STRCMP (pr_token, "framesave"))
1879         {
1880                 QCC_PR_ParseFrame ();
1881                 QCC_PR_Lex ();
1882         }
1883 // ignore other known $commands - just for model/spritegen
1884         else if (!STRCMP (pr_token, "cd")
1885         || !STRCMP (pr_token, "origin")
1886         || !STRCMP (pr_token, "base")
1887         || !STRCMP (pr_token, "flags")
1888         || !STRCMP (pr_token, "scale")
1889         || !STRCMP (pr_token, "skin") )
1890         {       // skip to end of line
1891                 while (QCC_PR_LexMacroName ())
1892                 ;
1893                 QCC_PR_Lex ();
1894         }
1895         else if (!STRCMP (pr_token, "flush"))
1896         {
1897                 QCC_PR_ClearGrabMacros();
1898                 while (QCC_PR_LexMacroName ())
1899                 ;
1900                 QCC_PR_Lex ();
1901         }
1902         else if (!STRCMP (pr_token, "framevalue"))
1903         {
1904                 QCC_PR_LexMacroName ();
1905                 pr_macrovalue = atoi(pr_token);
1906
1907                 QCC_PR_Lex ();
1908         }
1909         else if (!STRCMP (pr_token, "framerestore"))
1910         {
1911                 QCC_PR_LexMacroName ();
1912                 QCC_PR_ExpandMacro();
1913                 pr_macrovalue = (int)pr_immediate._float;
1914
1915                 QCC_PR_Lex ();
1916         }
1917         else if (!STRCMP (pr_token, "modelname"))
1918         {
1919                 int i;
1920                 QCC_PR_LexMacroName ();
1921
1922                 if (*pr_framemodelname)
1923                         QCC_PR_MacroFrame(pr_framemodelname, pr_macrovalue);
1924
1925                 strncpy(pr_framemodelname, pr_token, sizeof(pr_framemodelname)-1);
1926                 pr_framemodelname[sizeof(pr_framemodelname)-1] = '\0';
1927
1928                 i = QCC_PR_FindMacro(pr_framemodelname);
1929                 if (i)
1930                         pr_macrovalue = i;
1931                 else
1932                         i = 0;
1933
1934                 QCC_PR_Lex ();
1935         }
1936 // look for a frame name macro
1937         else
1938                 QCC_PR_ExpandMacro ();
1939 }
1940
1941 //===========================
1942 //compiler constants    - dmw
1943
1944 pbool QCC_PR_UndefineName(char *name)
1945 {
1946 //      int a;
1947         CompilerConstant_t *c;
1948         c = pHash_Get(&compconstantstable, name);
1949         if (!c)
1950         {
1951                 QCC_PR_ParseWarning(WARN_UNDEFNOTDEFINED, "Precompiler constant %s was not defined", name);
1952                 return false;
1953         }
1954
1955         Hash_Remove(&compconstantstable, name);
1956         return true;
1957 }
1958
1959 CompilerConstant_t *QCC_PR_DefineName(char *name)
1960 {
1961         int i;
1962         CompilerConstant_t *cnst;
1963
1964 //      if (numCompilerConstants >= MAX_CONSTANTS)
1965 //              QCC_PR_ParseError("Too many compiler constants - %i >= %i", numCompilerConstants, MAX_CONSTANTS);
1966
1967         if (strlen(name) >= MAXCONSTANTLENGTH || !*name)
1968                 QCC_PR_ParseError(ERR_NAMETOOLONG, "Compiler constant name length is too long or short");
1969
1970         cnst = pHash_Get(&compconstantstable, name);
1971         if (cnst)
1972         {
1973                 QCC_PR_ParseWarning(WARN_DUPLICATEDEFINITION, "Duplicate definition for Precompiler constant %s", name);
1974                 Hash_Remove(&compconstantstable, name);
1975         }
1976
1977         cnst = qccHunkAlloc(sizeof(CompilerConstant_t));
1978
1979         cnst->used = false;
1980         cnst->numparams = 0;
1981         strcpy(cnst->name, name);
1982         cnst->namelen = strlen(name);
1983         cnst->value = cnst->name + strlen(cnst->name);
1984         for (i = 0; i < MAXCONSTANTPARAMS; i++)
1985                 cnst->params[i][0] = '\0';
1986
1987         pHash_Add(&compconstantstable, cnst->name, cnst, qccHunkAlloc(sizeof(bucket_t)));
1988
1989         return cnst;
1990 }
1991
1992 void QCC_PR_Undefine(void)
1993 {
1994         QCC_PR_SimpleGetToken ();
1995
1996         QCC_PR_UndefineName(pr_token);
1997 //              QCC_PR_ParseError("%s was not defined.", pr_token);
1998 }
1999
2000 void QCC_PR_ConditionCompilation(void)
2001 {
2002         char *oldval;
2003         char *d;
2004         char *dbuf;
2005         int dbuflen;
2006         char *s;
2007         int quote=false;
2008         CompilerConstant_t *cnst;
2009
2010         QCC_PR_SimpleGetToken ();
2011
2012         if (!QCC_PR_SimpleGetToken ())
2013                 QCC_PR_ParseError(ERR_NONAME, "No name defined for compiler constant");
2014
2015         cnst = pHash_Get(&compconstantstable, pr_token);
2016         if (cnst)
2017         {
2018                 oldval = cnst->value;
2019                 Hash_Remove(&compconstantstable, pr_token);
2020         }
2021         else
2022                 oldval = NULL;
2023
2024         cnst = QCC_PR_DefineName(pr_token);
2025
2026         if (*pr_file_p == '(')
2027         {
2028                 s = pr_file_p+1;
2029                 while(*pr_file_p++)
2030                 {
2031                         if (*pr_file_p == ',')
2032                         {
2033                                 if (cnst->numparams >= MAXCONSTANTPARAMS)
2034                                         QCC_PR_ParseError(ERR_MACROTOOMANYPARMS, "May not have more than %i parameters to a macro", MAXCONSTANTPARAMS);
2035                                 strncpy(cnst->params[cnst->numparams], s, pr_file_p-s);
2036                                 cnst->params[cnst->numparams][pr_file_p-s] = '\0';
2037                                 cnst->numparams++;
2038                                 pr_file_p++;
2039                                 s = pr_file_p;
2040                         }
2041                         if (*pr_file_p == ')')
2042                         {
2043                                 if (cnst->numparams >= MAXCONSTANTPARAMS)
2044                                         QCC_PR_ParseError(ERR_MACROTOOMANYPARMS, "May not have more than %i parameters to a macro", MAXCONSTANTPARAMS);
2045                                 strncpy(cnst->params[cnst->numparams], s, pr_file_p-s);
2046                                 cnst->params[cnst->numparams][pr_file_p-s] = '\0';
2047                                 cnst->numparams++;
2048                                 pr_file_p++;
2049                                 break;
2050                         }
2051                 }
2052         }
2053         else cnst->numparams = -1;
2054
2055         s = pr_file_p;
2056         d = dbuf = NULL;
2057         dbuflen = 0;
2058         while(*s == ' ' || *s == '\t')
2059                 s++;
2060         while(1)
2061         {
2062                 if ((d - dbuf) + 2 >= dbuflen)
2063                 {
2064                         int len = d - dbuf;
2065                         dbuflen = (len+128) * 2;
2066                         dbuf = qccHunkAlloc(dbuflen);
2067                         memcpy(dbuf, d - len, len);
2068                         d = dbuf + len;
2069                 }
2070
2071                 if( *s == '\\' )
2072                 {
2073                         // read over a newline if necessary
2074                         if( s[1] == '\n' || s[1] == '\r' )
2075                         {
2076                                 s++;
2077                                 QCC_PR_NewLine(false);
2078                                 *d++ = *s++;
2079                                 if( s[-1] == '\r' && s[0] == '\n' )
2080                                 {
2081                                         *d++ = *s++;
2082                                 }
2083                         }
2084                 }
2085                 else if(*s == '\r' || *s == '\n' || *s == '\0')
2086                 {
2087                         break;
2088                 }
2089
2090                 if (!quote && s[0]=='/'&&(s[1]=='/'||s[1]=='*'))
2091                         break;
2092                 if (*s == '\"')
2093                         quote=!quote;
2094
2095                 *d = *s;
2096                 d++;
2097                 s++;
2098         }
2099         *d = '\0';
2100
2101         cnst->value = dbuf;
2102
2103         if (oldval)
2104         {       //we always warn if it was already defined
2105                 //we use different warning codes so that -Wno-mundane can be used to ignore identical redefinitions.
2106                 if (strcmp(oldval, cnst->value))
2107                         QCC_PR_ParseWarning(WARN_DUPLICATEPRECOMPILER, "Alternate precompiler definition of %s", pr_token);
2108                 else
2109                         QCC_PR_ParseWarning(WARN_IDENTICALPRECOMPILER, "Identical precompiler definition of %s", pr_token);
2110         }
2111
2112         pr_file_p = s;
2113 }
2114
2115 int QCC_PR_CheakCompConst(void)
2116 {
2117         char            *oldpr_file_p = pr_file_p;
2118         int whitestart;
2119
2120         CompilerConstant_t *c;
2121
2122         char *end;
2123         for (end = pr_file_p; ; end++)
2124         {
2125                 if (*end <= ' ')
2126                         break;
2127
2128                 if (*end == ')'
2129                         ||      *end == '('
2130                         ||      *end == '+'
2131                         ||      *end == '-'
2132                         ||      *end == '*'
2133                         ||      *end == '/'
2134                         ||      *end == '|'
2135                         ||      *end == '&'
2136                         ||      *end == '='
2137                         ||      *end == '^'
2138                         ||      *end == '~'
2139                         ||      *end == '['
2140                         ||      *end == ']'
2141                         ||      *end == '\"'
2142                         ||      *end == '{'
2143                         ||      *end == '}'
2144                         ||      *end == ';'
2145                         ||      *end == ':'
2146                         ||      *end == ','
2147                         ||      *end == '.'
2148                         ||      *end == '#')
2149                                 break;
2150         }
2151         strncpy(pr_token, pr_file_p, end-pr_file_p);
2152         pr_token[end-pr_file_p]='\0';
2153
2154 //      printf("%s\n", pr_token);
2155         c = pHash_Get(&compconstantstable, pr_token);
2156
2157         if (c && !c->inside)
2158         {
2159                 pr_file_p = oldpr_file_p+strlen(c->name);
2160                 while(*pr_file_p == ' ' || *pr_file_p == '\t')
2161                         pr_file_p++;
2162                 if (c->numparams>=0)
2163                 {
2164                         if (*pr_file_p == '(')
2165                         {
2166                                 int p;
2167                                 char *start;
2168                                 char buffer[1024];
2169                                 char *paramoffset[MAXCONSTANTPARAMS+1];
2170                                 int param=0;
2171                                 int plevel=0;
2172
2173                                 pr_file_p++;
2174                                 while(*pr_file_p == ' ' || *pr_file_p == '\t')
2175                                         pr_file_p++;
2176                                 start = pr_file_p;
2177                                 while(1)
2178                                 {
2179                                         // handle strings correctly by ignoring them
2180                                         if (*pr_file_p == '\"')
2181                                         {
2182                                                 do {
2183                                                         pr_file_p++;
2184                                                 } while( (pr_file_p[-1] == '\\' || pr_file_p[0] != '\"') && *pr_file_p && *pr_file_p != '\n' );
2185                                         }
2186                                         if (*pr_file_p == '(')
2187                                                 plevel++;
2188                                         else if (!plevel && (*pr_file_p == ',' || *pr_file_p == ')'))
2189                                         {
2190                                                 paramoffset[param++] = start;
2191                                                 start = pr_file_p+1;
2192                                                 if (*pr_file_p == ')')
2193                                                 {
2194                                                         *pr_file_p = '\0';
2195                                                         pr_file_p++;
2196                                                         break;
2197                                                 }
2198                                                 *pr_file_p = '\0';
2199                                                 pr_file_p++;
2200                                                 while(*pr_file_p == ' ' || *pr_file_p == '\t')
2201                                                 {
2202                                                         pr_file_p++;
2203                                                         start++;
2204                                                 }
2205                                                 // move back by one char because we move forward by one at the end of the loop
2206                                                 pr_file_p--;
2207                                                 if (param == MAXCONSTANTPARAMS)
2208                                                         QCC_PR_ParseError(ERR_TOOMANYPARAMS, "Too many parameters in macro call");
2209                                         } else if (*pr_file_p == ')' )
2210                                                 plevel--;
2211                                         else if(*pr_file_p == '\n')
2212                                                 QCC_PR_NewLine(false);
2213
2214                                         // see that *pr_file_p = '\0' up there? Must ++ BEFORE checking for !*pr_file_p
2215                                         pr_file_p++;
2216                                         if (!*pr_file_p)
2217                                                 QCC_PR_ParseError(ERR_EOF, "EOF on macro call");
2218                                 }
2219                                 if (param < c->numparams)
2220                                         QCC_PR_ParseError(ERR_TOOFEWPARAMS, "Not enough macro parameters");
2221                                 paramoffset[param] = start;
2222
2223                                 *buffer = '\0';
2224
2225                                 oldpr_file_p = pr_file_p;
2226                                 pr_file_p = c->value;
2227                                 for(;;)
2228                                 {
2229                                         whitestart = p = strlen(buffer);
2230                                         while(*pr_file_p <= ' ')        //copy across whitespace
2231                                         {
2232                                                 if (!*pr_file_p)
2233                                                         break;
2234                                                 buffer[p++] = *pr_file_p++;
2235                                         }
2236                                         buffer[p] = 0;
2237
2238                                         if(*pr_file_p == '\"')
2239                                         {
2240                                                 do
2241                                                 {
2242                                                         buffer[p++] = *pr_file_p;
2243                                                         ++pr_file_p;
2244                                                 } while( (pr_file_p[-1] == '\\' || pr_file_p[0] != '\"') && *pr_file_p && *pr_file_p != '\n' );
2245                                                 buffer[p++] = *pr_file_p; // copy the end-quote too
2246                                                 buffer[p] = 0;
2247                                                 ++pr_file_p; // and skip it
2248                                                 continue;
2249                                         }
2250                                         else if (*pr_file_p == '#')     //if you ask for #a##b you will be shot. use #a #b instead, or chain macros.
2251                                         {
2252                                                 if (pr_file_p[1] == '#')
2253                                                 {       //concatinate (srip out whitespace)
2254                                                         buffer[whitestart] = '\0';
2255                                                         pr_file_p+=2;
2256                                                 }
2257                                                 else
2258                                                 {       //stringify
2259                                                         pr_file_p++;
2260                                                         pr_file_p = QCC_COM_Parse2(pr_file_p);
2261                                                         if (!pr_file_p)
2262                                                                 break;
2263
2264                                                         for (p = 0; p < param; p++)
2265                                                         {
2266                                                                 if (!STRCMP(qcc_token, c->params[p]))
2267                                                                 {
2268                                                                         strcat(buffer, "\"");
2269                                                                         strcat(buffer, paramoffset[p]);
2270                                                                         strcat(buffer, "\"");
2271                                                                         break;
2272                                                                 }
2273                                                         }
2274                                                         if (p == param)
2275                                                         {
2276                                                                 strcat(buffer, "#");
2277                                                                 strcat(buffer, qcc_token);
2278                                                                 //QCC_PR_ParseWarning(0, "Stringification ignored");
2279                                                         }
2280                                                         continue;       //already did this one
2281                                                 }
2282                                         }
2283
2284                                         pr_file_p = QCC_COM_Parse2(pr_file_p);
2285                                         if (!pr_file_p)
2286                                                 break;
2287
2288                                         for (p = 0; p < param; p++)
2289                                         {
2290                                                 if (!STRCMP(qcc_token, c->params[p]))
2291                                                 {
2292                                                         strcat(buffer, paramoffset[p]);
2293                                                         break;
2294                                                 }
2295                                         }
2296                                         if (p == param)
2297                                                 strcat(buffer, qcc_token);
2298                                 }
2299
2300                                 for (p = 0; p < param-1; p++)
2301                                         paramoffset[p][strlen(paramoffset[p])] = ',';
2302                                 paramoffset[p][strlen(paramoffset[p])] = ')';
2303
2304                                 pr_file_p = oldpr_file_p;
2305                                 if (!*buffer)
2306                                         expandedemptymacro = true;
2307                                 QCC_PR_IncludeChunkEx(buffer, true, NULL, c);
2308                         }
2309                         else
2310                                 QCC_PR_ParseError(ERR_TOOFEWPARAMS, "Macro without opening brace");
2311                 }
2312                 else
2313                 {
2314                         if (!*c->value)
2315                                 expandedemptymacro = true;
2316                         QCC_PR_IncludeChunkEx(c->value, false, NULL, c);
2317                 }
2318
2319                 QCC_PR_Lex();
2320                 return true;
2321         }
2322
2323         if (!strncmp(pr_file_p, "__TIME__", 8))
2324         {
2325                 static char retbuf[128];
2326
2327                 time_t long_time;
2328                 time( &long_time );
2329                 strftime( retbuf, sizeof(retbuf),
2330                          "\"%H:%M\"", localtime( &long_time ));
2331
2332                 pr_file_p = retbuf;
2333                 QCC_PR_Lex();   //translate the macro's value
2334                 pr_file_p = oldpr_file_p+8;
2335
2336                 return true;
2337         }
2338         if (!strncmp(pr_file_p, "__DATE__", 8))
2339         {
2340                 static char retbuf[128];
2341
2342                 time_t long_time;
2343                 time( &long_time );
2344                 strftime( retbuf, sizeof(retbuf),
2345                          "\"%a %d %b %Y\"", localtime( &long_time ));
2346
2347                 pr_file_p = retbuf;
2348                 QCC_PR_Lex();   //translate the macro's value
2349                 pr_file_p = oldpr_file_p+8;
2350
2351                 return true;
2352         }
2353         if (!strncmp(pr_file_p, "__FILE__", 8))
2354         {
2355                 static char retbuf[256];
2356                 sprintf(retbuf, "\"%s\"", strings + s_file);
2357                 pr_file_p = retbuf;
2358                 QCC_PR_Lex();   //translate the macro's value
2359                 pr_file_p = oldpr_file_p+8;
2360
2361                 return true;
2362         }
2363         if (!strncmp(pr_file_p, "__LINE__", 8))
2364         {
2365                 static char retbuf[256];
2366                 sprintf(retbuf, "\"%i\"", pr_source_line);
2367                 pr_file_p = retbuf;
2368                 QCC_PR_Lex();   //translate the macro's value
2369                 pr_file_p = oldpr_file_p+8;
2370                 return true;
2371         }
2372         if (!strncmp(pr_file_p, "__FUNC__", 8))
2373         {
2374                 static char retbuf[256];
2375                 sprintf(retbuf, "\"%s\"",pr_scope->name);
2376                 pr_file_p = retbuf;
2377                 QCC_PR_Lex();   //translate the macro's value
2378                 pr_file_p = oldpr_file_p+8;
2379                 return true;
2380         }
2381         if (!strncmp(pr_file_p, "__NULL__", 8))
2382         {
2383                 static char retbuf[256];
2384                 sprintf(retbuf, "0i");
2385                 pr_file_p = retbuf;
2386                 QCC_PR_Lex();   //translate the macro's value
2387                 pr_file_p = oldpr_file_p+8;
2388                 return true;
2389         }
2390         return false;
2391 }
2392
2393 char *QCC_PR_CheakCompConstString(char *def)
2394 {
2395         char *s;
2396
2397         CompilerConstant_t *c;
2398
2399         c = pHash_Get(&compconstantstable, def);
2400
2401         if (c)
2402         {
2403                 s = QCC_PR_CheakCompConstString(c->value);
2404                 return s;
2405         }
2406         return def;
2407 }
2408
2409 CompilerConstant_t *QCC_PR_CheckCompConstDefined(char *def)
2410 {
2411         CompilerConstant_t *c = pHash_Get(&compconstantstable, def);
2412         return c;
2413 }
2414
2415 //============================================================================
2416
2417 /*
2418 ==============
2419 PR_Lex
2420
2421 Sets pr_token, pr_token_type, and possibly pr_immediate and pr_immediate_type
2422 ==============
2423 */
2424 void QCC_PR_Lex (void)
2425 {
2426         int             c;
2427
2428         pr_token[0] = 0;
2429
2430         if (!pr_file_p)
2431         {
2432                 if (QCC_PR_UnInclude())
2433                 {
2434                         QCC_PR_Lex();
2435                         return;
2436                 }
2437                 pr_token_type = tt_eof;
2438                 return;
2439         }
2440
2441         QCC_PR_LexWhitespace ();
2442
2443         if (!pr_file_p)
2444         {
2445                 if (QCC_PR_UnInclude())
2446                 {
2447                         QCC_PR_Lex();
2448                         return;
2449                 }
2450                 pr_token_type = tt_eof;
2451                 return;
2452         }
2453
2454         c = *pr_file_p;
2455
2456         if (!c)
2457         {
2458                 if (QCC_PR_UnInclude())
2459                 {
2460                         QCC_PR_Lex();
2461                         return;
2462                 }
2463                 pr_token_type = tt_eof;
2464                 return;
2465         }
2466
2467 // handle quoted strings as a unit
2468         if (c == '\"')
2469         {
2470                 QCC_PR_LexString ();
2471                 return;
2472         }
2473
2474 // handle quoted vectors as a unit
2475         if (c == '\'')
2476         {
2477                 QCC_PR_LexVector ();
2478                 return;
2479         }
2480
2481 // if the first character is a valid identifier, parse until a non-id
2482 // character is reached
2483         if ( c == '~' || c == '%')      //let's see which one we make into an operator first... possibly both...
2484         {
2485                 QCC_PR_ParseWarning(0, "~ or %% prefixes to denote integers are deprecated. Please use a postfix of 'i'");
2486                 pr_file_p++;
2487                 pr_token_type = tt_immediate;
2488                 pr_immediate_type = type_integer;
2489                 pr_immediate._int = QCC_PR_LexInteger ();
2490                 return;
2491         }
2492         if ( c == '0' && pr_file_p[1] == 'x')
2493         {
2494                 pr_token_type = tt_immediate;
2495                 QCC_PR_LexNumber();
2496                 return;
2497         }
2498         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') )
2499         {
2500                 pr_token_type = tt_immediate;
2501                 QCC_PR_LexNumber ();
2502                 return;
2503         }
2504
2505         if (c == '#' && !(pr_file_p[1]=='-' || (pr_file_p[1]>='0' && pr_file_p[1] <='9')))      //hash and not number
2506         {
2507                 pr_file_p++;
2508                 if (!QCC_PR_CheakCompConst())
2509                 {
2510                         if (!QCC_PR_SimpleGetToken())
2511                                 strcpy(pr_token, "unknown");
2512                         QCC_PR_ParseError(ERR_CONSTANTNOTDEFINED, "Explicit precompiler usage when not defined %s", pr_token);
2513                 }
2514                 else
2515                         if (pr_token_type == tt_eof)
2516                                 QCC_PR_Lex();
2517
2518                 return;
2519         }
2520
2521         if ( (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' )
2522         {
2523                 if (flag_hashonly || !QCC_PR_CheakCompConst())  //look for a macro.
2524                         QCC_PR_LexName ();
2525                 else
2526                         if (pr_token_type == tt_eof)
2527                         {
2528                                 if (QCC_PR_UnInclude())
2529                                 {
2530                                         QCC_PR_Lex();
2531                                         return;
2532                                 }
2533                                 pr_token_type = tt_eof;
2534                         }
2535                 return;
2536         }
2537
2538         if (c == '$')
2539         {
2540                 QCC_PR_LexGrab ();
2541                 return;
2542         }
2543
2544 // parse symbol strings until a non-symbol is found
2545         QCC_PR_LexPunctuation ();
2546 }
2547
2548 //=============================================================================
2549
2550
2551 void QCC_PR_ParsePrintDef (int type, QCC_def_t *def)
2552 {
2553         if (qccwarningdisabled[type])
2554                 return;
2555         if (def->s_file)
2556         {
2557                 if (flag_msvcstyle)
2558                         printf ("%s(%i) :    %s  is defined here\n", strings + def->s_file, def->s_line, def->name);
2559                 else
2560                         printf ("%s:%i:    %s  is defined here\n", strings + def->s_file, def->s_line, def->name);
2561         }
2562 }
2563 void *errorscope;
2564 void QCC_PR_PrintScope (void)
2565 {
2566         if (pr_scope)
2567         {
2568                 if (errorscope != pr_scope)
2569                         printf ("in function %s (line %i),\n", pr_scope->name, pr_scope->s_line);
2570                 errorscope = pr_scope;
2571         }
2572         else
2573         {
2574                 if (errorscope)
2575                         printf ("at global scope,\n");
2576                 errorscope = NULL;
2577         }
2578 }
2579 void QCC_PR_ResetErrorScope(void)
2580 {
2581         errorscope = NULL;
2582 }
2583 /*
2584 ============
2585 PR_ParseError
2586
2587 Aborts the current file load
2588 ============
2589 */
2590 #ifndef QCC
2591 void editbadfile(char *file, int line);
2592 #endif
2593 void VARGS QCC_PR_ParseError (int errortype, char *error, ...)
2594 {
2595         va_list         argptr;
2596         char            string[1024];
2597
2598         va_start (argptr,error);
2599         QC_vsnprintf (string,sizeof(string)-1, error,argptr);
2600         va_end (argptr);
2601
2602 #ifndef QCC
2603         editbadfile(strings+s_file, pr_source_line);
2604 #endif
2605
2606         QCC_PR_PrintScope();
2607         if (flag_msvcstyle)
2608                 printf ("%s(%i) : error: %s\n", strings + s_file, pr_source_line, string);
2609         else
2610                 printf ("%s:%i: error: %s\n", strings + s_file, pr_source_line, string);
2611
2612         longjmp (pr_parse_abort, 1);
2613 }
2614 void VARGS QCC_PR_ParseErrorPrintDef (int errortype, QCC_def_t *def, char *error, ...)
2615 {
2616         va_list         argptr;
2617         char            string[1024];
2618
2619         va_start (argptr,error);
2620         QC_vsnprintf (string,sizeof(string)-1, error,argptr);
2621         va_end (argptr);
2622
2623 #ifndef QCC
2624         editbadfile(strings+s_file, pr_source_line);
2625 #endif
2626         QCC_PR_PrintScope();
2627         if (flag_msvcstyle)
2628                 printf ("%s(%i) : error: %s\n", strings + s_file, pr_source_line, string);
2629         else
2630                 printf ("%s:%i: error: %s\n", strings + s_file, pr_source_line, string);
2631
2632         QCC_PR_ParsePrintDef(WARN_ERROR, def);
2633
2634         longjmp (pr_parse_abort, 1);
2635 }
2636 void VARGS QCC_PR_ParseWarning (int type, char *error, ...)
2637 {
2638         va_list         argptr;
2639         char            string[1024];
2640
2641         if (type < ERR_PARSEERRORS && qccwarningdisabled[type])
2642                 return;
2643
2644         va_start (argptr,error);
2645         QC_vsnprintf (string,sizeof(string)-1, error,argptr);
2646         va_end (argptr);
2647
2648         QCC_PR_PrintScope();
2649         if (type >= ERR_PARSEERRORS)
2650         {
2651                 if (flag_msvcstyle)
2652                         printf ("%s(%i) : error: %s\n", strings + s_file, pr_source_line, string);
2653                 else
2654                         printf ("%s:%i: error: %s\n", strings + s_file, pr_source_line, string);
2655                 pr_error_count++;
2656         }
2657         else
2658         {
2659                 if (flag_msvcstyle)
2660                         printf ("%s(%i) : warning: %s\n", strings + s_file, pr_source_line, string);
2661                 else
2662                         printf ("%s:%i: warning: %s\n", strings + s_file, pr_source_line, string);
2663                 pr_warning_count++;
2664         }
2665 }
2666
2667 void VARGS QCC_PR_Note (int type, char *file, int line, char *error, ...)
2668 {
2669                 va_list         argptr;
2670         char            string[1024];
2671
2672         if (qccwarningdisabled[type])
2673                 return;
2674
2675         va_start (argptr,error);
2676         QC_vsnprintf (string,sizeof(string)-1, error,argptr);
2677         va_end (argptr);
2678
2679         QCC_PR_PrintScope();
2680         if (file)
2681         {
2682                 if (flag_msvcstyle)
2683                         printf ("%s(%i) : note: %s\n", file, line, string);
2684                 else
2685                         printf ("%s:%i: note: %s\n", file, line, string);
2686         }
2687         else
2688                 printf ("note: %s\n", string);
2689 }
2690
2691 void VARGS QCC_PR_Warning (int type, char *file, int line, char *error, ...)
2692 {
2693         va_list         argptr;
2694         char            string[1024];
2695
2696         if (qccwarningdisabled[type])
2697                 return;
2698
2699         va_start (argptr,error);
2700         QC_vsnprintf (string,sizeof(string)-1, error,argptr);
2701         va_end (argptr);
2702
2703         QCC_PR_PrintScope();
2704         if (file)
2705         {
2706                 if (flag_msvcstyle)
2707                         printf ("%s(%i) : warning: %s\n", file, line, string);
2708                 else
2709                         printf ("%s:%i: warning: %s\n", file, line, string);
2710         }
2711         else
2712                 printf ("warning: %s\n", string);
2713         pr_warning_count++;
2714 }
2715
2716
2717 /*
2718 =============
2719 PR_Expect
2720
2721 Issues an error if the current token isn't equal to string
2722 Gets the next token
2723 =============
2724 */
2725 #ifndef COMMONINLINES
2726 void QCC_PR_Expect (char *string)
2727 {
2728         if (STRCMP (string, pr_token))
2729                 QCC_PR_ParseError (ERR_EXPECTED, "expected %s, found %s",string, pr_token);
2730         QCC_PR_Lex ();
2731 }
2732 #endif
2733
2734
2735 /*
2736 =============
2737 PR_Check
2738
2739 Returns true and gets the next token if the current token equals string
2740 Returns false and does nothing otherwise
2741 =============
2742 */
2743 #ifndef COMMONINLINES
2744 pbool QCC_PR_CheckToken (char *string)
2745 {
2746         if (pr_token_type != tt_punct)
2747                 return false;
2748
2749         if (STRCMP (string, pr_token))
2750                 return false;
2751
2752         QCC_PR_Lex ();
2753         return true;
2754 }
2755
2756 pbool QCC_PR_CheckImmediate (char *string)
2757 {
2758         if (pr_token_type != tt_immediate)
2759                 return false;
2760
2761         if (STRCMP (string, pr_token))
2762                 return false;
2763
2764         QCC_PR_Lex ();
2765         return true;
2766 }
2767
2768 pbool QCC_PR_CheckName(char *string)
2769 {
2770         if (pr_token_type != tt_name)
2771                 return false;
2772         if (flag_caseinsensative)
2773         {
2774                 if (stricmp (string, pr_token))
2775                         return false;
2776         }
2777         else
2778         {
2779                 if (STRCMP(string, pr_token))
2780                         return false;
2781         }
2782         QCC_PR_Lex ();
2783         return true;
2784 }
2785
2786 pbool QCC_PR_CheckKeyword(int keywordenabled, char *string)
2787 {
2788         if (!keywordenabled)
2789                 return false;
2790         if (flag_caseinsensative)
2791         {
2792                 if (stricmp (string, pr_token))
2793                         return false;
2794         }
2795         else
2796         {
2797                 if (STRCMP(string, pr_token))
2798                         return false;
2799         }
2800         QCC_PR_Lex ();
2801         return true;
2802 }
2803 #endif
2804
2805
2806 /*
2807 ============
2808 PR_ParseName
2809
2810 Checks to see if the current token is a valid name
2811 ============
2812 */
2813 char *QCC_PR_ParseName (void)
2814 {
2815         static char     ident[MAX_NAME];
2816         char *ret;
2817
2818         if (pr_token_type != tt_name)
2819                 QCC_PR_ParseError (ERR_NOTANAME, "\"%s\" - not a name", pr_token);
2820         if (strlen(pr_token) >= MAX_NAME-1)
2821                 QCC_PR_ParseError (ERR_NAMETOOLONG, "name too long");
2822         strcpy (ident, pr_token);
2823         QCC_PR_Lex ();
2824
2825         ret = qccHunkAlloc(strlen(ident)+1);
2826         strcpy(ret, ident);
2827         return ret;
2828 //      return ident;
2829 }
2830
2831 /*
2832 ============
2833 PR_FindType
2834
2835 Returns a preexisting complex type that matches the parm, or allocates
2836 a new one and copies it out.
2837 ============
2838 */
2839
2840 //0 if same
2841 QCC_type_t *QCC_PR_NewType (char *name, int basictype);
2842 int typecmp(QCC_type_t *a, QCC_type_t *b)
2843 {
2844         if (a == b)
2845                 return 0;
2846         if (!a || !b)
2847                 return 1;       //different (^ and not both null)
2848
2849         if (a->type != b->type)
2850                 return 1;
2851         if (a->num_parms != b->num_parms)
2852                 return 1;
2853
2854         if (a->size != b->size)
2855                 return 1;
2856 //      if (STRCMP(a->name, b->name))   //This isn't 100% clean.
2857 //              return 1;
2858
2859         if (typecmp(a->aux_type, b->aux_type))
2860                 return 1;
2861
2862         if (a->param || b->param)
2863         {
2864                 a = a->param;
2865                 b = b->param;
2866
2867                 while(a || b)
2868                 {
2869                         if (typecmp(a, b))
2870                                 return 1;
2871
2872                         a=a->next;
2873                         b=b->next;
2874                 }
2875         }
2876
2877         return 0;
2878 }
2879
2880 QCC_type_t *QCC_PR_DuplicateType(QCC_type_t *in)
2881 {
2882         QCC_type_t *out, *op, *ip;
2883         if (!in)
2884                 return NULL;
2885
2886         out = QCC_PR_NewType(in->name, in->type);
2887         out->aux_type = QCC_PR_DuplicateType(in->aux_type);
2888         out->param = QCC_PR_DuplicateType(in->param);
2889         ip = in->param;
2890         op = NULL;
2891         while(ip)
2892         {
2893                 if (!op)
2894                         out->param = op = QCC_PR_DuplicateType(ip);
2895                 else
2896                         op = (op->next = QCC_PR_DuplicateType(ip));
2897                 ip = ip->next;
2898         }
2899         out->size = in->size;
2900         out->num_parms = in->num_parms;
2901         out->ofs = in->ofs;
2902         out->name = in->name;
2903         out->parentclass = in->parentclass;
2904
2905         return out;
2906 }
2907
2908 char *TypeName(QCC_type_t *type)
2909 {
2910         static char buffer[2][512];
2911         static int op;
2912         char *ret;
2913
2914
2915         op++;
2916         ret = buffer[op&1];
2917         if (type->type == ev_field)
2918         {
2919                 type = type->aux_type;
2920                 *ret++ = '.';
2921         }
2922         *ret = 0;
2923
2924         if (type->type == ev_function)
2925         {
2926                 strcat(ret, type->aux_type->name);
2927                 strcat(ret, " (");
2928                 type = type->param;
2929                 while(type)
2930                 {
2931                         strcat(ret, type->name);
2932                         type = type->next;
2933
2934                         if (type)
2935                                 strcat(ret, ", ");
2936                 }
2937                 strcat(ret, ")");
2938         }
2939         else if (type->type == ev_entity && type->parentclass)
2940         {
2941                 ret = buffer[op&1];
2942                 *ret = 0;
2943                 strcat(ret, "class ");
2944                 strcat(ret, type->name);
2945 /*              strcat(ret, " {");
2946                 type = type->param;
2947                 while(type)
2948                 {
2949                         strcat(ret, type->name);
2950                         type = type->next;
2951
2952                         if (type)
2953                                 strcat(ret, ", ");
2954                 }
2955                 strcat(ret, "}");
2956 */
2957         }
2958         else
2959                 strcpy(ret, type->name);
2960
2961         return buffer[op&1];
2962 }
2963 //#define typecmp(a, b) (a && ((a)->type==(b)->type) && !STRCMP((a)->name, (b)->name))
2964
2965 QCC_type_t *QCC_PR_FindType (QCC_type_t *type)
2966 {
2967         int t;
2968         for (t = 0; t < numtypeinfos; t++)
2969         {
2970 //              check = &qcc_typeinfo[t];
2971                 if (typecmp(&qcc_typeinfo[t], type))
2972                         continue;
2973
2974
2975 //              c2 = check->next;
2976 //              n2 = type->next;
2977 //              for (i=0 ; n2&&c2 ; i++)
2978 //              {
2979 //                      if (!typecmp((c2), (n2)))
2980 //                              break;
2981 //                      c2=c2->next;
2982 //                      n2=n2->next;
2983 //              }
2984
2985 //              if (n2==NULL&&c2==NULL)
2986                 {
2987                         return &qcc_typeinfo[t];
2988                 }
2989         }
2990 QCC_Error(ERR_INTERNAL, "Error with type");
2991
2992         return type;
2993 }
2994 /*
2995 QCC_type_t *QCC_PR_NextSubType(QCC_type_t *type, QCC_type_t *prev)
2996 {
2997         int p;
2998         if (!prev)
2999                 return type->next;
3000
3001         for (p = prev->num_parms; p; p--)
3002                 prev = QCC_PR_NextSubType(prev, NULL);
3003         if (prev->num_parms)
3004
3005         switch(prev->type)
3006         {
3007         case ev_function:
3008
3009         }
3010
3011         return prev->next;
3012 }
3013 */
3014
3015 QCC_type_t *QCC_TypeForName(char *name)
3016 {
3017         int i;
3018
3019         for (i = 0; i < numtypeinfos; i++)
3020         {
3021                 if (!STRCMP(qcc_typeinfo[i].name, name))
3022                 {
3023                         return &qcc_typeinfo[i];
3024                 }
3025         }
3026
3027         return NULL;
3028 }
3029
3030 /*
3031 ============
3032 PR_SkipToSemicolon
3033
3034 For error recovery, also pops out of nested braces
3035 ============
3036 */
3037 void QCC_PR_SkipToSemicolon (void)
3038 {
3039         do
3040         {
3041                 if (!pr_bracelevel && QCC_PR_CheckToken (";"))
3042                         return;
3043                 QCC_PR_Lex ();
3044         } while (pr_token_type != tt_eof);
3045 }
3046
3047
3048 /*
3049 ============
3050 PR_ParseType
3051
3052 Parses a variable type, including field and functions types
3053 ============
3054 */
3055 #ifdef MAX_EXTRA_PARMS
3056 char    pr_parm_names[MAX_PARMS+MAX_EXTRA_PARMS][MAX_NAME];
3057 #else
3058 char    pr_parm_names[MAX_PARMS][MAX_NAME];
3059 #endif
3060
3061 pbool recursivefunctiontype;
3062
3063 QCC_type_t *QCC_PR_NewType (char *name, int basictype);
3064 //expects a ( to have already been parsed.
3065 QCC_type_t *QCC_PR_ParseFunctionType (int newtype, QCC_type_t *returntype)
3066 {
3067         QCC_type_t      *ftype, *ptype, *nptype;
3068         char    *name;
3069         int definenames = !recursivefunctiontype;
3070
3071         recursivefunctiontype++;
3072
3073         ftype = QCC_PR_NewType(type_function->name, ev_function);
3074
3075         ftype->aux_type = returntype;   // return type
3076         ftype->num_parms = 0;
3077         ptype = NULL;
3078
3079
3080         if (!QCC_PR_CheckToken (")"))
3081         {
3082                 if (QCC_PR_CheckToken ("..."))
3083                         ftype->num_parms = -1;  // variable args
3084                 else
3085                         do
3086                         {
3087                                 if (ftype->num_parms>=MAX_PARMS+MAX_EXTRA_PARMS)
3088                                         QCC_PR_ParseError(ERR_TOOMANYTOTALPARAMETERS, "Too many parameters. Sorry. (limit is %i)\n", MAX_PARMS+MAX_EXTRA_PARMS);
3089
3090                                 if (QCC_PR_CheckToken ("..."))
3091                                 {
3092                                         ftype->num_parms = (ftype->num_parms * -1) - 1;
3093                                         break;
3094                                 }
3095
3096                                 nptype = QCC_PR_ParseType(true);
3097
3098                                 if (nptype->type == ev_void)
3099                                         break;
3100                                 if (!ptype)
3101                                 {
3102                                         ptype = nptype;
3103                                         ftype->param = ptype;
3104                                 }
3105                                 else
3106                                 {
3107                                         ptype->next = nptype;
3108                                         ptype = ptype->next;
3109                                 }
3110 //                              type->name = "FUNC PARAMETER";
3111
3112
3113                                 if (STRCMP(pr_token, ",") && STRCMP(pr_token, ")"))
3114                                 {
3115                                         name = QCC_PR_ParseName ();
3116                                         if (definenames)
3117                                                 strcpy (pr_parm_names[ftype->num_parms], name);
3118                                 }
3119                                 else if (definenames)
3120                                         strcpy (pr_parm_names[ftype->num_parms], "");
3121                                 ftype->num_parms++;
3122                         } while (QCC_PR_CheckToken (","));
3123
3124                 QCC_PR_Expect (")");
3125         }
3126         recursivefunctiontype--;
3127         if (newtype)
3128                 return ftype;
3129         return QCC_PR_FindType (ftype);
3130 }
3131 QCC_type_t *QCC_PR_ParseFunctionTypeReacc (int newtype, QCC_type_t *returntype)
3132 {
3133         QCC_type_t      *ftype, *ptype, *nptype;
3134         char    *name;
3135         char    argname[64];
3136         int definenames = !recursivefunctiontype;
3137
3138         recursivefunctiontype++;
3139
3140         ftype = QCC_PR_NewType(type_function->name, ev_function);
3141
3142         ftype->aux_type = returntype;   // return type
3143         ftype->num_parms = 0;
3144         ptype = NULL;
3145
3146
3147         if (!QCC_PR_CheckToken (")"))
3148         {
3149                 if (QCC_PR_CheckToken ("..."))
3150                         ftype->num_parms = -1;  // variable args
3151                 else
3152                         do
3153                         {
3154                                 if (ftype->num_parms>=MAX_PARMS+MAX_EXTRA_PARMS)
3155                                         QCC_PR_ParseError(ERR_TOOMANYTOTALPARAMETERS, "Too many parameters. Sorry. (limit is %i)\n", MAX_PARMS+MAX_EXTRA_PARMS);
3156
3157                                 if (QCC_PR_CheckToken ("..."))
3158                                 {
3159                                         ftype->num_parms = (ftype->num_parms * -1) - 1;
3160                                         break;
3161                                 }
3162
3163                                 if (QCC_PR_CheckName("arg"))
3164                                 {
3165                                         sprintf(argname, "arg%i", ftype->num_parms);
3166                                         name = argname;
3167                                         nptype = QCC_PR_NewType("Variant", ev_variant);
3168                                 }
3169                                 else if (QCC_PR_CheckName("vect"))      //this can only be of vector sizes, so...
3170                                 {
3171                                         sprintf(argname, "arg%i", ftype->num_parms);
3172                                         name = argname;
3173                                         nptype = QCC_PR_NewType("Vector", ev_vector);
3174                                 }
3175                                 else
3176                                 {
3177                                         name = QCC_PR_ParseName();
3178                                         QCC_PR_Expect(":");
3179                                         nptype = QCC_PR_ParseType(true);
3180                                 }
3181
3182                                 if (nptype->type == ev_void)
3183                                         break;
3184                                 if (!ptype)
3185                                 {
3186                                         ptype = nptype;
3187                                         ftype->param = ptype;
3188                                 }
3189                                 else
3190                                 {
3191                                         ptype->next = nptype;
3192                                         ptype = ptype->next;
3193                                 }
3194 //                              type->name = "FUNC PARAMETER";
3195
3196                                 if (definenames)
3197                                         strcpy (pr_parm_names[ftype->num_parms], name);
3198                                 ftype->num_parms++;
3199                         } while (QCC_PR_CheckToken (";"));
3200
3201                 QCC_PR_Expect (")");
3202         }
3203         recursivefunctiontype--;
3204         if (newtype)
3205                 return ftype;
3206         return QCC_PR_FindType (ftype);
3207 }
3208 QCC_type_t *QCC_PR_PointerType (QCC_type_t *pointsto)
3209 {
3210         QCC_type_t      *ptype;
3211         char name[128];
3212         sprintf(name, "*%s", pointsto->name);
3213         ptype = QCC_PR_NewType(name, ev_pointer);
3214         ptype->aux_type = pointsto;
3215         return QCC_PR_FindType (ptype);
3216 }
3217 QCC_type_t *QCC_PR_FieldType (QCC_type_t *pointsto)
3218 {
3219         QCC_type_t      *ptype;
3220         char name[128];
3221         sprintf(name, "FIELD TYPE(%s)", pointsto->name);
3222         ptype = QCC_PR_NewType(name, ev_field);
3223         ptype->aux_type = pointsto;
3224         ptype->size = ptype->aux_type->size;
3225         return QCC_PR_FindType (ptype);
3226 }
3227
3228 pbool type_inlinefunction;
3229 QCC_type_t *QCC_PR_ParseType (int newtype)
3230 {
3231         QCC_type_t      *newparm;
3232         QCC_type_t      *newt;
3233         QCC_type_t      *type;
3234         char    *name;
3235         int i;
3236
3237         type_inlinefunction = false;    //doesn't really matter so long as its not from an inline function type
3238
3239 //      int ofs;
3240
3241         if (QCC_PR_CheckToken (".."))   //so we don't end up with the user specifying '. .vector blah' (hexen2 added the .. token for array ranges)
3242         {
3243                 newt = QCC_PR_NewType("FIELD TYPE", ev_field);
3244                 newt->aux_type = QCC_PR_ParseType (false);
3245
3246                 newt->size = newt->aux_type->size;
3247
3248                 newt = QCC_PR_FindType (newt);
3249
3250                 type = QCC_PR_NewType("FIELD TYPE", ev_field);
3251                 type->aux_type = newt;
3252
3253                 type->size = type->aux_type->size;
3254
3255                 if (newtype)
3256                         return type;
3257                 return QCC_PR_FindType (type);
3258         }
3259         if (QCC_PR_CheckToken ("."))
3260         {
3261                 newt = QCC_PR_NewType("FIELD TYPE", ev_field);
3262                 newt->aux_type = QCC_PR_ParseType (false);
3263
3264                 newt->size = newt->aux_type->size;
3265
3266                 if (newtype)
3267                         return newt;
3268                 return QCC_PR_FindType (newt);
3269         }
3270
3271         name = QCC_PR_CheakCompConstString(pr_token);
3272
3273         if (QCC_PR_CheckKeyword (keyword_class, "class"))
3274         {
3275 //              int parms;
3276                 QCC_type_t *fieldtype;
3277                 char membername[2048];
3278                 char *classname = QCC_PR_ParseName();
3279                 int forwarddeclaration;
3280
3281                 newt = 0;
3282
3283                 /* Don't advance the line number yet */
3284                 forwarddeclaration = pr_token[0] == ';';
3285
3286                 /* Look to see if this type is already defined */
3287                 for(i=0;i<numtypeinfos;i++)
3288                 {
3289                         if (STRCMP(qcc_typeinfo[i].name, classname) == 0)
3290                         {
3291                                 newt = &qcc_typeinfo[i];
3292                                 break;
3293                         }
3294                 }
3295
3296                 if (newt && forwarddeclaration)
3297                         QCC_PR_ParseError(ERR_REDECLARATION, "Forward declaration of already defined class %s", classname);
3298
3299                 if (newt && newt->num_parms != 0)
3300                         QCC_PR_ParseError(ERR_REDECLARATION, "Redeclaration of class %s", classname);
3301
3302                 if (!newt)
3303                         newt = QCC_PR_NewType(classname, ev_entity);
3304
3305                 newt->size=type_entity->size;
3306
3307                 type = NULL;
3308
3309                 if (forwarddeclaration)
3310                 {
3311                         QCC_PR_CheckToken(";");
3312                         return NULL;
3313                 }
3314
3315
3316
3317                 if (QCC_PR_CheckToken(":"))
3318                 {
3319                         char *parentname = QCC_PR_ParseName();
3320                         newt->parentclass = QCC_TypeForName(parentname);
3321                         if (!newt->parentclass)
3322                                 QCC_PR_ParseError(ERR_NOTANAME, "Parent class %s was not defined", parentname);
3323                 }
3324                 else
3325                         newt->parentclass = type_entity;
3326
3327
3328                 QCC_PR_Expect("{");
3329                 if (QCC_PR_CheckToken(","))
3330                         QCC_PR_ParseError(ERR_NOTANAME, "member missing name");
3331                 while (!QCC_PR_CheckToken("}"))
3332                 {
3333 //                      if (QCC_PR_CheckToken(","))
3334 //                              type->next = QCC_PR_NewType(type->name, type->type);
3335 //                      else
3336                                 newparm = QCC_PR_ParseType(true);
3337
3338                         if (newparm->type == ev_struct || newparm->type == ev_union)    //we wouldn't be able to handle it.
3339                                 QCC_PR_ParseError(ERR_INTERNAL, "Struct or union in class %s", classname);
3340
3341                         if (!QCC_PR_CheckToken(";"))
3342                         {
3343                                 newparm->name = QCC_CopyString(pr_token)+strings;
3344                                 QCC_PR_Lex();
3345                                 if (QCC_PR_CheckToken("["))
3346                                 {
3347                                         type->next->size*=atoi(pr_token);
3348                                         QCC_PR_Lex();
3349                                         QCC_PR_Expect("]");
3350                                 }
3351                                 QCC_PR_CheckToken(";");
3352                         }
3353                         else
3354                                 newparm->name = QCC_CopyString("")+strings;
3355
3356                         sprintf(membername, "%s::"MEMBERFIELDNAME, classname, newparm->name);
3357                         fieldtype = QCC_PR_NewType(newparm->name, ev_field);
3358                         fieldtype->aux_type = newparm;
3359                         fieldtype->size = newparm->size;
3360                         QCC_PR_GetDef(fieldtype, membername, pr_scope, 2, 1, false);
3361
3362
3363                         newparm->ofs = 0;//newt->size;
3364                         newt->num_parms++;
3365
3366                         if (type)
3367                                 type->next = newparm;
3368                         else
3369                                 newt->param = newparm;
3370
3371                         type = newparm;
3372                 }
3373
3374
3375                 QCC_PR_Expect(";");
3376                 return NULL;
3377         }
3378         if (QCC_PR_CheckKeyword (keyword_struct, "struct"))
3379         {
3380                 newt = QCC_PR_NewType("struct", ev_struct);
3381                 newt->size=0;
3382                 QCC_PR_Expect("{");
3383
3384                 type = NULL;
3385                 if (QCC_PR_CheckToken(","))
3386                         QCC_PR_ParseError(ERR_NOTANAME, "element missing name");
3387
3388                 newparm = NULL;
3389                 while (!QCC_PR_CheckToken("}"))
3390                 {
3391                         if (QCC_PR_CheckToken(","))
3392                         {
3393                                 if (!newparm)
3394                                         QCC_PR_ParseError(ERR_NOTANAME, "element missing type");
3395                                 newparm = QCC_PR_NewType(newparm->name, newparm->type);
3396                         }
3397                         else
3398                                 newparm = QCC_PR_ParseType(true);
3399
3400                         if (!QCC_PR_CheckToken(";"))
3401                         {
3402                                 newparm->name = QCC_CopyString(pr_token)+strings;
3403                                 QCC_PR_Lex();
3404                                 if (QCC_PR_CheckToken("["))
3405                                 {
3406                                         newparm->size*=atoi(pr_token);
3407                                         QCC_PR_Lex();
3408                                         QCC_PR_Expect("]");
3409                                 }
3410                                 QCC_PR_CheckToken(";");
3411                         }
3412                         else
3413                                 newparm->name = QCC_CopyString("")+strings;
3414                         newparm->ofs = newt->size;
3415                         newt->size += newparm->size;
3416                         newt->num_parms++;
3417
3418                         if (type)
3419                                 type->next = newparm;
3420                         else
3421                                 newt->param = newparm;
3422                         type = newparm;
3423                 }
3424                 return newt;
3425         }
3426         if (QCC_PR_CheckKeyword (keyword_union, "union"))
3427         {
3428                 newt = QCC_PR_NewType("union", ev_union);
3429                 newt->size=0;
3430                 QCC_PR_Expect("{");
3431
3432                 type = NULL;
3433                 if (QCC_PR_CheckToken(","))
3434                         QCC_PR_ParseError(ERR_NOTANAME, "element missing name");
3435                 newparm = NULL;
3436                 while (!QCC_PR_CheckToken("}"))
3437                 {
3438                         if (QCC_PR_CheckToken(","))
3439                         {
3440                                 if (!newparm)
3441                                         QCC_PR_ParseError(ERR_NOTANAME, "element missing type");
3442                                 newparm = QCC_PR_NewType(newparm->name, newparm->type);
3443                         }
3444                         else
3445                                 newparm = QCC_PR_ParseType(true);
3446                         if (QCC_PR_CheckToken(";"))
3447                                 newparm->name = QCC_CopyString("")+strings;
3448                         else
3449                         {
3450                                 newparm->name = QCC_CopyString(pr_token)+strings;
3451                                 QCC_PR_Lex();
3452                                 QCC_PR_Expect(";");
3453                         }
3454                         newparm->ofs = 0;
3455                         if (newparm->size > newt->size)
3456                                 newt->size = newparm->size;
3457                         newt->num_parms++;
3458
3459                         if (type)
3460                                 type->next = newparm;
3461                         else
3462                                 newt->param = newparm;
3463                         type = newparm;
3464                 }
3465                 return newt;
3466         }
3467         type = NULL;
3468         for (i = 0; i < numtypeinfos; i++)
3469         {
3470                 if (!STRCMP(qcc_typeinfo[i].name, name))
3471                 {
3472                         type = &qcc_typeinfo[i];
3473                         break;
3474                 }
3475         }
3476
3477         if (i == numtypeinfos)
3478         {
3479                 if (!*name)
3480                         return NULL;
3481                 if (!stricmp("Void", name))
3482                         type = type_void;
3483                 else if (!stricmp("Real", name))
3484                         type = type_float;
3485                 else if (!stricmp("Vector", name))
3486                         type = type_vector;
3487                 else if (!stricmp("Object", name))
3488                         type = type_entity;
3489                 else if (!stricmp("String", name))
3490                         type = type_string;
3491                 else if (!stricmp("PFunc", name))
3492                         type = type_function;
3493                 else
3494                 {
3495                         QCC_PR_ParseError (ERR_NOTATYPE, "\"%s\" is not a type", name);
3496                         type = type_float;      // shut up compiler warning
3497                 }
3498         }
3499         QCC_PR_Lex ();
3500
3501         if (QCC_PR_CheckToken ("("))    //this is followed by parameters. Must be a function.
3502         {
3503                 type_inlinefunction = true;
3504                 return QCC_PR_ParseFunctionType(newtype, type);
3505         }
3506         else
3507         {
3508                 if (newtype)
3509                 {
3510                         type = QCC_PR_DuplicateType(type);
3511                 }
3512
3513                 return type;
3514         }
3515 }
3516
3517 #endif
3518
3519
3520