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