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