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