Skip to content
Newer
Older
100644 696 lines (582 sloc) 12.4 KB
c0d1b91 @tbradshaw Source release of qcc and the qutils, updated long ago to be GPL.
tbradshaw authored
1 /* Copyright (C) 1996-1997 Id Software, Inc.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2 of the License, or
6 (at your option) any later version.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16
17 See file, 'COPYING', for details.
18 */
19
20 #include "qcc.h"
21
22 int pr_source_line;
23
24 char *pr_file_p;
25 char *pr_line_start; // start of current source line
26
27 int pr_bracelevel;
28
29 char pr_token[2048];
30 token_type_t pr_token_type;
31 type_t *pr_immediate_type;
32 eval_t pr_immediate;
33
34 char pr_immediate_string[2048];
35
36 int pr_error_count;
37
38 char *pr_punctuation[] =
39 // longer symbols must be before a shorter partial match
40 {"&&", "||", "<=", ">=","==", "!=", ";", ",", "!", "*", "/", "(", ")", "-", "+", "=", "[", "]", "{", "}", "...", ".", "<", ">" , "#" , "&" , "|" , NULL};
41
42 // simple types. function types are dynamically allocated
43 type_t type_void = {ev_void, &def_void};
44 type_t type_string = {ev_string, &def_string};
45 type_t type_float = {ev_float, &def_float};
46 type_t type_vector = {ev_vector, &def_vector};
47 type_t type_entity = {ev_entity, &def_entity};
48 type_t type_field = {ev_field, &def_field};
49 type_t type_function = {ev_function, &def_function,NULL,&type_void};
50 // type_function is a void() function used for state defs
51 type_t type_pointer = {ev_pointer, &def_pointer};
52
53 type_t type_floatfield = {ev_field, &def_field, NULL, &type_float};
54
55 int type_size[8] = {1,1,1,3,1,1,1,1};
56
57 def_t def_void = {&type_void, "temp"};
58 def_t def_string = {&type_string, "temp"};
59 def_t def_float = {&type_float, "temp"};
60 def_t def_vector = {&type_vector, "temp"};
61 def_t def_entity = {&type_entity, "temp"};
62 def_t def_field = {&type_field, "temp"};
63 def_t def_function = {&type_function, "temp"};
64 def_t def_pointer = {&type_pointer, "temp"};
65
66 def_t def_ret, def_parms[MAX_PARMS];
67
68 def_t *def_for_type[8] = {&def_void, &def_string, &def_float, &def_vector, &def_entity, &def_field, &def_function, &def_pointer};
69
70 void PR_LexWhitespace (void);
71
72
73 /*
74 ==============
75 PR_PrintNextLine
76 ==============
77 */
78 void PR_PrintNextLine (void)
79 {
80 char *t;
81
82 printf ("%3i:",pr_source_line);
83 for (t=pr_line_start ; *t && *t != '\n' ; t++)
84 printf ("%c",*t);
85 printf ("\n");
86 }
87
88 /*
89 ==============
90 PR_NewLine
91
92 Call at start of file and when *pr_file_p == '\n'
93 ==============
94 */
95 void PR_NewLine (void)
96 {
97 boolean m;
98
99 if (*pr_file_p == '\n')
100 {
101 pr_file_p++;
102 m = true;
103 }
104 else
105 m = false;
106
107 pr_source_line++;
108 pr_line_start = pr_file_p;
109
110 // if (pr_dumpasm)
111 // PR_PrintNextLine ();
112 if (m)
113 pr_file_p--;
114 }
115
116 /*
117 ==============
118 PR_LexString
119
120 Parses a quoted string
121 ==============
122 */
123 void PR_LexString (void)
124 {
125 int c;
126 int len;
127
128 len = 0;
129 pr_file_p++;
130 do
131 {
132 c = *pr_file_p++;
133 if (!c)
134 PR_ParseError ("EOF inside quote");
135 if (c=='\n')
136 PR_ParseError ("newline inside quote");
137 if (c=='\\')
138 { // escape char
139 c = *pr_file_p++;
140 if (!c)
141 PR_ParseError ("EOF inside quote");
142 if (c == 'n')
143 c = '\n';
144 else if (c == '"')
145 c = '"';
146 else
147 PR_ParseError ("Unknown escape char");
148 }
149 else if (c=='\"')
150 {
151 pr_token[len] = 0;
152 pr_token_type = tt_immediate;
153 pr_immediate_type = &type_string;
154 strcpy (pr_immediate_string, pr_token);
155 return;
156 }
157 pr_token[len] = c;
158 len++;
159 } while (1);
160 }
161
162 /*
163 ==============
164 PR_LexNumber
165 ==============
166 */
167 float PR_LexNumber (void)
168 {
169 int c;
170 int len;
171
172 len = 0;
173 c = *pr_file_p;
174 do
175 {
176 pr_token[len] = c;
177 len++;
178 pr_file_p++;
179 c = *pr_file_p;
180 } while ((c >= '0' && c<= '9') || c == '.');
181 pr_token[len] = 0;
182 return atof (pr_token);
183 }
184
185 /*
186 ==============
187 PR_LexVector
188
189 Parses a single quoted vector
190 ==============
191 */
192 void PR_LexVector (void)
193 {
194 int i;
195
196 pr_file_p++;
197 pr_token_type = tt_immediate;
198 pr_immediate_type = &type_vector;
199 for (i=0 ; i<3 ; i++)
200 {
201 pr_immediate.vector[i] = PR_LexNumber ();
202 PR_LexWhitespace ();
203 }
204 if (*pr_file_p != '\'')
205 PR_ParseError ("Bad vector");
206 pr_file_p++;
207 }
208
209 /*
210 ==============
211 PR_LexName
212
213 Parses an identifier
214 ==============
215 */
216 void PR_LexName (void)
217 {
218 int c;
219 int len;
220
221 len = 0;
222 c = *pr_file_p;
223 do
224 {
225 pr_token[len] = c;
226 len++;
227 pr_file_p++;
228 c = *pr_file_p;
229 } while ( (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_'
230 || (c >= '0' && c <= '9'));
231 pr_token[len] = 0;
232 pr_token_type = tt_name;
233 }
234
235 /*
236 ==============
237 PR_LexPunctuation
238 ==============
239 */
240 void PR_LexPunctuation (void)
241 {
242 int i;
243 int len;
244 char *p;
245
246 pr_token_type = tt_punct;
247
248 for (i=0 ; (p = pr_punctuation[i]) != NULL ; i++)
249 {
250 len = strlen(p);
251 if (!strncmp(p, pr_file_p, len) )
252 {
253 strcpy (pr_token, p);
254 if (p[0] == '{')
255 pr_bracelevel++;
256 else if (p[0] == '}')
257 pr_bracelevel--;
258 pr_file_p += len;
259 return;
260 }
261 }
262
263 PR_ParseError ("Unknown punctuation");
264 }
265
266
267 /*
268 ==============
269 PR_LexWhitespace
270 ==============
271 */
272 void PR_LexWhitespace (void)
273 {
274 int c;
275
276 while (1)
277 {
278 // skip whitespace
279 while ( (c = *pr_file_p) <= ' ')
280 {
281 if (c=='\n')
282 PR_NewLine ();
283 if (c == 0)
284 return; // end of file
285 pr_file_p++;
286 }
287
288 // skip // comments
289 if (c=='/' && pr_file_p[1] == '/')
290 {
291 while (*pr_file_p && *pr_file_p != '\n')
292 pr_file_p++;
293 PR_NewLine();
294 pr_file_p++;
295 continue;
296 }
297
298 // skip /* */ comments
299 if (c=='/' && pr_file_p[1] == '*')
300 {
301 do
302 {
303 pr_file_p++;
304 if (pr_file_p[0]=='\n')
305 PR_NewLine();
306 if (pr_file_p[1] == 0)
307 return;
308 } while (pr_file_p[-1] != '*' || pr_file_p[0] != '/');
309 pr_file_p++;
310 continue;
311 }
312
313 break; // a real character has been found
314 }
315 }
316
317 //============================================================================
318
319 #define MAX_FRAMES 256
320
321 char pr_framemacros[MAX_FRAMES][16];
322 int pr_nummacros;
323
324 void PR_ClearGrabMacros (void)
325 {
326 pr_nummacros = 0;
327 }
328
329 void PR_FindMacro (void)
330 {
331 int i;
332
333 for (i=0 ; i<pr_nummacros ; i++)
334 if (!strcmp (pr_token, pr_framemacros[i]))
335 {
336 sprintf (pr_token,"%d", i);
337 pr_token_type = tt_immediate;
338 pr_immediate_type = &type_float;
339 pr_immediate._float = i;
340 return;
341 }
342 PR_ParseError ("Unknown frame macro $%s", pr_token);
343 }
344
345 // just parses text, returning false if an eol is reached
346 boolean PR_SimpleGetToken (void)
347 {
348 int c;
349 int i;
350
351 // skip whitespace
352 while ( (c = *pr_file_p) <= ' ')
353 {
354 if (c=='\n' || c == 0)
355 return false;
356 pr_file_p++;
357 }
358
359 i = 0;
360 while ( (c = *pr_file_p) > ' ' && c != ',' && c != ';')
361 {
362 pr_token[i] = c;
363 i++;
364 pr_file_p++;
365 }
366 pr_token[i] = 0;
367 return true;
368 }
369
370 void PR_ParseFrame (void)
371 {
372 while (PR_SimpleGetToken ())
373 {
374 strcpy (pr_framemacros[pr_nummacros], pr_token);
375 pr_nummacros++;
376 }
377 }
378
379 /*
380 ==============
381 PR_LexGrab
382
383 Deals with counting sequence numbers and replacing frame macros
384 ==============
385 */
386 void PR_LexGrab (void)
387 {
388 pr_file_p++; // skip the $
389 if (!PR_SimpleGetToken ())
390 PR_ParseError ("hanging $");
391
392 // check for $frame
393 if (!strcmp (pr_token, "frame"))
394 {
395 PR_ParseFrame ();
396 PR_Lex ();
397 }
398 // ignore other known $commands
399 else if (!strcmp (pr_token, "cd")
400 || !strcmp (pr_token, "origin")
401 || !strcmp (pr_token, "base")
402 || !strcmp (pr_token, "flags")
403 || !strcmp (pr_token, "scale")
404 || !strcmp (pr_token, "skin") )
405 { // skip to end of line
406 while (PR_SimpleGetToken ())
407 ;
408 PR_Lex ();
409 }
410 // look for a frame name macro
411 else
412 PR_FindMacro ();
413 }
414
415 //============================================================================
416
417 /*
418 ==============
419 PR_Lex
420
421 Sets pr_token, pr_token_type, and possibly pr_immediate and pr_immediate_type
422 ==============
423 */
424 void PR_Lex (void)
425 {
426 int c;
427
428 pr_token[0] = 0;
429
430 if (!pr_file_p)
431 {
432 pr_token_type = tt_eof;
433 return;
434 }
435
436 PR_LexWhitespace ();
437
438 c = *pr_file_p;
439
440 if (!c)
441 {
442 pr_token_type = tt_eof;
443 return;
444 }
445
446 // handle quoted strings as a unit
447 if (c == '\"')
448 {
449 PR_LexString ();
450 return;
451 }
452
453 // handle quoted vectors as a unit
454 if (c == '\'')
455 {
456 PR_LexVector ();
457 return;
458 }
459
460 // if the first character is a valid identifier, parse until a non-id
461 // character is reached
462 if ( (c >= '0' && c <= '9') || ( c=='-' && pr_file_p[1]>='0' && pr_file_p[1] <='9') )
463 {
464 pr_token_type = tt_immediate;
465 pr_immediate_type = &type_float;
466 pr_immediate._float = PR_LexNumber ();
467 return;
468 }
469
470 if ( (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' )
471 {
472 PR_LexName ();
473 return;
474 }
475
476 if (c == '$')
477 {
478 PR_LexGrab ();
479 return;
480 }
481
482 // parse symbol strings until a non-symbol is found
483 PR_LexPunctuation ();
484 }
485
486 //=============================================================================
487
488 /*
489 ============
490 PR_ParseError
491
492 Aborts the current file load
493 ============
494 */
495 void PR_ParseError (char *error, ...)
496 {
497 va_list argptr;
498 char string[1024];
499
500 va_start (argptr,error);
501 vsprintf (string,error,argptr);
502 va_end (argptr);
503
504 printf ("%s:%i:%s\n", strings + s_file, pr_source_line, string);
505
506 longjmp (pr_parse_abort, 1);
507 }
508
509
510 /*
511 =============
512 PR_Expect
513
514 Issues an error if the current token isn't equal to string
515 Gets the next token
516 =============
517 */
518 void PR_Expect (char *string)
519 {
520 if (strcmp (string, pr_token))
521 PR_ParseError ("expected %s, found %s",string, pr_token);
522 PR_Lex ();
523 }
524
525
526 /*
527 =============
528 PR_Check
529
530 Returns true and gets the next token if the current token equals string
531 Returns false and does nothing otherwise
532 =============
533 */
534 boolean PR_Check (char *string)
535 {
536 if (strcmp (string, pr_token))
537 return false;
538
539 PR_Lex ();
540 return true;
541 }
542
543 /*
544 ============
545 PR_ParseName
546
547 Checks to see if the current token is a valid name
548 ============
549 */
550 char *PR_ParseName (void)
551 {
552 static char ident[MAX_NAME];
553
554 if (pr_token_type != tt_name)
555 PR_ParseError ("not a name");
556 if (strlen(pr_token) >= MAX_NAME-1)
557 PR_ParseError ("name too long");
558 strcpy (ident, pr_token);
559 PR_Lex ();
560
561 return ident;
562 }
563
564 /*
565 ============
566 PR_FindType
567
568 Returns a preexisting complex type that matches the parm, or allocates
569 a new one and copies it out.
570 ============
571 */
572 type_t *PR_FindType (type_t *type)
573 {
574 def_t *def;
575 type_t *check;
576 int i;
577
578 for (check = pr.types ; check ; check = check->next)
579 {
580 if (check->type != type->type
581 || check->aux_type != type->aux_type
582 || check->num_parms != type->num_parms)
583 continue;
584
585 for (i=0 ; i< type->num_parms ; i++)
586 if (check->parm_types[i] != type->parm_types[i])
587 break;
588
589 if (i == type->num_parms)
590 return check;
591 }
592
593 // allocate a new one
594 check = malloc (sizeof (*check));
595 *check = *type;
596 check->next = pr.types;
597 pr.types = check;
598
599 // allocate a generic def for the type, so fields can reference it
600 def = malloc (sizeof(def_t));
601 def->name = "COMPLEX TYPE";
602 def->type = check;
603 check->def = def;
604 return check;
605 }
606
607
608 /*
609 ============
610 PR_SkipToSemicolon
611
612 For error recovery, also pops out of nested braces
613 ============
614 */
615 void PR_SkipToSemicolon (void)
616 {
617 do
618 {
619 if (!pr_bracelevel && PR_Check (";"))
620 return;
621 PR_Lex ();
622 } while (pr_token[0]); // eof will return a null token
623 }
624
625
626 /*
627 ============
628 PR_ParseType
629
630 Parses a variable type, including field and functions types
631 ============
632 */
633 char pr_parm_names[MAX_PARMS][MAX_NAME];
634
635 type_t *PR_ParseType (void)
636 {
637 type_t new;
638 type_t *type;
639 char *name;
640
641 if (PR_Check ("."))
642 {
643 memset (&new, 0, sizeof(new));
644 new.type = ev_field;
645 new.aux_type = PR_ParseType ();
646 return PR_FindType (&new);
647 }
648
649 if (!strcmp (pr_token, "float") )
650 type = &type_float;
651 else if (!strcmp (pr_token, "vector") )
652 type = &type_vector;
653 else if (!strcmp (pr_token, "float") )
654 type = &type_float;
655 else if (!strcmp (pr_token, "entity") )
656 type = &type_entity;
657 else if (!strcmp (pr_token, "string") )
658 type = &type_string;
659 else if (!strcmp (pr_token, "void") )
660 type = &type_void;
661 else
662 {
663 PR_ParseError ("\"%s\" is not a type", pr_token);
664 type = &type_float; // shut up compiler warning
665 }
666 PR_Lex ();
667
668 if (!PR_Check ("("))
669 return type;
670
671 // function type
672 memset (&new, 0, sizeof(new));
673 new.type = ev_function;
674 new.aux_type = type; // return type
675 new.num_parms = 0;
676 if (!PR_Check (")"))
677 {
678 if (PR_Check ("..."))
679 new.num_parms = -1; // variable args
680 else
681 do
682 {
683 type = PR_ParseType ();
684 name = PR_ParseName ();
685 strcpy (pr_parm_names[new.num_parms], name);
686 new.parm_types[new.num_parms] = type;
687 new.num_parms++;
688 } while (PR_Check (","));
689
690 PR_Expect (")");
691 }
692
693 return PR_FindType (&new);
694 }
695
Something went wrong with that request. Please try again.