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