1 /*
2 Copyright (C) 2003-2006 Andrey Nazarov
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19 */
20
21 //
22 // lex.c
23 //
24
25 #include <setjmp.h>
26 #include "q_shared.h"
27 #include "com_public.h"
28 #include "q_list.h"
29 #include "q_lex.h"
30
31 lexContext_t lex;
32
33 lexImm_t lex_immediate;
34 lexImmType_t lex_immediateType;
35
36 jmp_buf lex_jmpbuf;
37
38 static char *lex_punctuation[] = { "&&", "||", "<=", ">=","==", "!=", "+=", "-=",
39 "*=", "/=", "|=", "&=", "^=", "++", "--", "(*",
40 ";", ",", "!", "*", "/", "(", ")", "-",
41 "+", "=", "[", "]", "{", "}", ".", "<",
42 ">", "#", "&", "$", "|", "~", "^", "%", NULL };
43
44
Lex_Error(const char * fmt,...)45 void Lex_Error( const char *fmt, ... ) {
46 va_list argptr;
47 char buffer[MAXPRINTMSG];
48
49 va_start( argptr, fmt );
50 Q_vsnprintf( buffer, sizeof( buffer ), fmt, argptr );
51 va_end( argptr );
52
53 Com_Printf( "*************\n" );
54 Com_Printf( "ERROR: line %i: %s\n", lex.currentLine, buffer );
55 Com_Printf( "*************\n" );
56
57 longjmp( lex_jmpbuf, -1 );
58 }
59
60 /*
61 ===============
62 Lex_NewLine
63 ===============
64 */
Lex_NewLine(void)65 void Lex_NewLine( void ) {
66 if( lex.rejectNewLines ) {
67 Lex_Error( "No newlines expected" );
68 }
69 lex.currentLine++;
70 }
71
72 /*
73 ===============
74 Lex_Whitespace
75 ===============
76 */
Lex_Whitespace(void)77 static void Lex_Whitespace( void ) {
78 while( 1 ) {
79 while( *lex.data <= ' ' ) {
80 if( !lex.data[0] ) {
81 return;
82 }
83 if( *lex.data == '\n' ) {
84 Lex_NewLine();
85 }
86 lex.data++;
87 }
88
89 if( lex.data[0] == '/' && lex.data[1] == '/' ) {
90 lex.data += 2;
91 while( *lex.data ) {
92 if( *lex.data == '\n' ) {
93 lex.data++;
94 Lex_NewLine();
95 break;
96 }
97 lex.data++;
98 }
99 if( !lex.data[0] ) {
100 return;
101 }
102 continue;
103 }
104
105 if( lex.data[0] == '/' && lex.data[1] == '*' ) {
106 lex.data += 2;
107 while( *lex.data ) {
108 if( *lex.data == '\n' ) {
109 Lex_NewLine();
110 } else if( lex.data[0] == '*' && lex.data[1] == '/' ) {
111 lex.data += 2;
112 break;
113 }
114 lex.data++;
115 }
116 if( !lex.data[0] ) {
117 return;
118 }
119 continue;
120 }
121
122 break;
123 }
124
125 }
126
127
128 /*
129 ===============
130 Lex_String
131 ===============
132 */
Lex_String(void)133 static void Lex_String( void ) {
134 int c;
135 int stringLength;
136 int integer;
137
138 lex.token[0] = 0;
139 lex.tokenLength = 0;
140 lex.tokenType = TT_IMMEDIATE;
141 lex_immediateType = IT_STRING;
142 lex_immediate.string[0] = 0;
143 stringLength = 0;
144
145 while( 1 ) {
146 lex.data++;
147
148 while( 1 ) {
149 c = *lex.data++;
150
151 if( c == '\"' ) {
152 break;
153 }
154
155 switch( c ) {
156 case '\0':
157 Lex_Error( "EOF inside quoted string" );
158 break;
159 case '\n':
160 Lex_Error( "Newline inside quoted string" );
161 break;
162 case '\\':
163 c = *lex.data++;
164
165 switch( c ) {
166 case '\0':
167 Lex_Error( "EOF inside quoted string" );
168 break;
169 case '\n':
170 Lex_Error( "Newline inside quoted string" );
171 break;
172 case 'n':
173 c = '\n';
174 break;
175 case 'r':
176 c = '\r';
177 break;
178 case 't':
179 c = '\t';
180 break;
181 case 'b':
182 c = '\b';
183 break;
184 case '\"':
185 c = '\"';
186 break;
187 case '\\':
188 c = '\\';
189 break;
190 //case '\n':
191 // break;
192 case 'x':
193 integer = 0;
194 while( 1 ) {
195 c = *lex.data;
196
197 if( c >= '0' && c <= '9' ) {
198 c = ( c - '0' );
199 } else if( c >= 'a' && c <= 'f' ) {
200 c = ( c - 'a' ) + 10;
201 } else if( c >= 'A' && c <= 'F' ) {
202 c = ( c - 'A' ) + 10;
203 } else {
204 break;
205 }
206
207 integer = ( integer << 4 ) + c;
208
209 lex.data++;
210 }
211 if( integer > 0xff ) {
212 Lex_Error( "\\x%x does not fit in a character", integer );
213 }
214 c = integer;
215 break;
216 default:
217 Lex_Error( "Unrecognized escape char" );
218 break;
219 }
220 break;
221 default:
222 break;
223 }
224
225 if( stringLength == MAX_STRING_CHARS - 1 ) {
226 Lex_Error( "String exceeded %i chars", MAX_STRING_CHARS );
227 }
228 lex_immediate.string[stringLength++] = c;
229
230 }
231
232 lex_immediate.string[stringLength] = 0;
233 Lex_Whitespace();
234
235 c = *lex.data;
236 if( c != '\"' ) {
237 break;
238 }
239 }
240 }
241
242 /*
243 ===============
244 Lex_Punctuation
245 ===============
246 */
Lex_Punctuation(void)247 static void Lex_Punctuation( void ) {
248 char **p;
249 int len = 0;
250
251 for( p = lex_punctuation; *p; p++ ) {
252 len = strlen( *p );
253 if( !strncmp( lex.data, *p, len ) ) {
254 break;
255 }
256 }
257
258 if( !p[0] ) {
259 Lex_Error( "Unknown punctuation" );
260 }
261
262 lex.data += len;
263 strcpy( lex.token, *p );
264 lex.tokenLength = len;
265 lex.tokenType = TT_PUNCTUATION;
266 }
267
268 /*
269 ===============
270 Lex_Name
271 ===============
272 */
Lex_Name(void)273 static void Lex_Name( void ) {
274 int c;
275
276 lex.token[0] = 0;
277 lex.tokenLength = 0;
278 lex.tokenType = TT_NAME;
279
280 c = *lex.data++;
281 while( 1 ) {
282 if( lex.tokenLength == MAX_TOKEN_CHARS - 1 ) {
283 Lex_Error( "Name exceeded %i chars", MAX_TOKEN_CHARS );
284 }
285 lex.token[lex.tokenLength++] = c;
286
287 c = *lex.data;
288 if( ( c < 'A' || c > 'Z' ) && ( c < 'a' || c > 'z' ) && ( c < '0' || c > '9' ) && c != '_' ) {
289 break;
290 }
291
292 lex.data++;
293 }
294
295 lex.token[lex.tokenLength] = 0;
296
297 }
298
299
300 /*
301 ===============
302 Lex_VectorToken
303 ===============
304 */
305 #define MAX_VECTOR_TOKEN 32
306
Lex_VectorToken(void)307 char *Lex_VectorToken( void ) {
308 static char token[MAX_VECTOR_TOKEN];
309 int tokenLength;
310 int c;
311
312 token[0] = 0;
313 tokenLength = 0;
314
315 Lex_Whitespace();
316
317 c = *lex.data++;
318 if( c == '\'' ) {
319 return NULL;
320 }
321
322 while( 1 ) {
323
324 if( ( c < '0' || c > '9' ) && c != '.' && c != '-' ) {
325 Lex_Error( "Illegal char inside vector" );
326 }
327 if( tokenLength == MAX_VECTOR_TOKEN - 1 ) {
328 Lex_Error( "Vector component exceeded %i chars", MAX_VECTOR_TOKEN );
329 }
330 token[tokenLength++] = c;
331
332 c = *lex.data;
333 if( c <= ' ' || c == '\'' ) {
334 break;
335 }
336
337 lex.data++;
338 }
339
340 token[tokenLength] = 0;
341
342 return token;
343 }
344
345
346 /*
347 ===============
348 Lex_Vector
349 ===============
350 */
Lex_Vector(void)351 static void Lex_Vector( void ) {
352 char *token;
353 vec4_t vector;
354 int numComponents;
355
356 lex.token[0] = 0;
357 lex.tokenLength = 0;
358 lex.tokenType = TT_IMMEDIATE;
359
360 lex.data++;
361 lex.rejectNewLines = qtrue;
362
363 numComponents = 0;
364 while( 1 ) {
365 if( !( token = Lex_VectorToken() ) ) {
366 break;
367 }
368
369 if( numComponents == 4 ) {
370 Lex_Error( "Too many vector components" );
371 }
372
373 vector[numComponents++] = atof( token );
374
375 }
376
377 lex.rejectNewLines = qfalse;
378
379 switch( numComponents ) {
380 case 0:
381 Lex_Error( "Empty vectors not allowed" );
382 break;
383 case 1:
384 lex_immediate.vector[0] = vector[0];
385 lex_immediate.vector[1] = 0;
386 lex_immediate.vector[2] = 0;
387 lex_immediate.vector[3] = 0;
388 lex_immediateType = IT_VECTOR1;
389 break;
390 case 2:
391 lex_immediate.vector[0] = vector[0];
392 lex_immediate.vector[1] = vector[1];
393 lex_immediate.vector[2] = 0;
394 lex_immediate.vector[3] = 0;
395 lex_immediateType = IT_VECTOR2;
396 break;
397 case 3:
398 lex_immediate.vector[0] = vector[0];
399 lex_immediate.vector[1] = vector[1];
400 lex_immediate.vector[2] = vector[2];
401 lex_immediate.vector[3] = 0;
402 lex_immediateType = IT_VECTOR3;
403 break;
404 case 4:
405 lex_immediate.vector[0] = vector[0];
406 lex_immediate.vector[1] = vector[1];
407 lex_immediate.vector[2] = vector[2];
408 lex_immediate.vector[3] = vector[3];
409 lex_immediateType = IT_VECTOR4;
410 break;
411 }
412
413 }
414
415 /*
416 ===============
417 Lex_Number
418 ===============
419 */
Lex_Number(void)420 static void Lex_Number( void ) {
421 int c;
422 int integer;
423 double value, frac;
424
425 lex.token[0] = 0;
426 lex.tokenLength = 0;
427 lex.tokenType = TT_IMMEDIATE;
428
429 integer = 0;
430 value = 0;
431
432 c = *lex.data++;
433 if( c == '0' ) {
434 c = *lex.data++;
435
436 switch( c ) {
437 case '\0':
438 Lex_Error( "EOF inside number" );
439 break;
440 case '.':
441 frac = 0.1;
442 while( 1 ) {
443 c = *lex.data;
444
445 if( c < '0' || c > '9' ) {
446 break;
447 }
448
449 value += frac * ( c - '0' );
450 frac *= 0.1;
451
452 lex.data++;
453 }
454 lex_immediateType = IT_FLOAT;
455 lex_immediate.value = value;
456 return;
457 case 'x':
458 while( 1 ) {
459 c = *lex.data;
460
461 if( c >= '0' && c <= '9' ) {
462 c = ( c - '0' );
463 } else if( c >= 'a' && c <= 'f' ) {
464 c = ( c - 'a' ) + 10;
465 } else if( c >= 'A' && c <= 'F' ) {
466 c = ( c - 'A' ) + 10;
467 } else {
468 break;
469 }
470
471 integer = ( integer << 4 ) + c;
472
473 lex.data++;
474 }
475 lex_immediateType = IT_INT;
476 lex_immediate.integer = integer;
477 return;
478 case '1':
479 case '2':
480 case '3':
481 case '4':
482 case '5':
483 case '6':
484 case '7':
485 while( 1 ) {
486 integer = ( integer * 8 ) + ( c - '0' );
487
488 c = *lex.data;
489
490 if( c < '0' || c > '9' ) {
491 break;
492 }
493
494 if( c == 8 || c == 9 ) {
495 Lex_Error( "Bad octal digit" );
496 }
497
498 lex.data++;
499 }
500 lex_immediateType = IT_INT;
501 lex_immediate.integer = integer;
502 return;
503
504
505 case '0':
506 case '8':
507 case '9':
508 Lex_Error( "Bad octal digit" );
509 break;
510 default:
511 lex.data--;
512 break;
513 }
514
515 lex_immediateType = IT_INT;
516 lex_immediate.integer = 0;
517 return;
518 }
519
520
521 while( 1 ) {
522 integer = ( integer * 10 ) + ( c - '0' );
523
524 c = *lex.data;
525 if( c == '.' ) {
526 lex.data++;
527
528 frac = 0.1;
529 value = integer;
530 while( 1 ) {
531 c = *lex.data;
532
533 if( c < '0' || c > '9' ) {
534 break;
535 }
536
537 value += frac * ( c - '0' );
538
539 frac *= 0.1;
540 lex.data++;
541 }
542
543 lex_immediateType = IT_FLOAT;
544 lex_immediate.value = value;
545
546 return;
547 }
548
549 if( c < '0' || c > '9' ) {
550 break;
551 }
552
553 lex.data++;
554
555 }
556
557 lex_immediateType = IT_INT;
558 lex_immediate.integer = integer;
559
560 }
561
562
563
564 /*
565 ===============
566 Lex_Whitespace
567 ===============
568 */
Lex_Eof(void)569 static void Lex_Eof( void ) {
570 lex.token[0] = 0;
571 lex.tokenLength = 0;
572 lex.tokenType = TT_EOF;
573 }
574
575 /*
576 ===============
577 Lex_Check
578 ===============
579 */
Lex_Check(const char * check)580 qboolean Lex_Check( const char *check ) {
581 if( !strcmp( lex.token, check ) ) {
582 Lex();
583 return qtrue;
584 }
585
586 return qfalse;
587 }
588
589 /*
590 ===============
591 Lex_Expect
592 ===============
593 */
Lex_Expect(const char * expect)594 void Lex_Expect( const char *expect ) {
595 if( strcmp( lex.token, expect ) ) {
596 Lex_Error( "Expected '%s', found '%s'", expect, lex.token );
597 }
598
599 Lex();
600
601 }
602
603 /*
604 ===============
605 Lex_ExpectToken
606 ===============
607 */
Lex_ExpectToken(const char * expect)608 void Lex_ExpectToken( const char *expect ) {
609 if( strcmp( lex.token, expect ) ) {
610 Lex_Error( "Expected '%s', found '%s'", expect, lex.token );
611 }
612 }
613
614 /*
615 ===============
616 Lex_ExpectImmediate
617 ===============
618 */
Lex_ExpectImmediate(lexImmType_t expect)619 void Lex_ExpectImmediate( lexImmType_t expect ) {
620 if( lex.tokenType != TT_IMMEDIATE ) {
621 Lex_Error( "Expected immediate, found '%s'", lex.token );
622 }
623 if( ( lex_immediateType & expect ) == 0 ) {
624 Lex_Error( "Expected different immediate type" );
625 }
626 Lex();
627 }
628
629 /*
630 ===============
631 Lex
632 ===============
633 */
Lex(void)634 void Lex( void ) {
635 int c;
636
637 Lex_Whitespace();
638
639 c = *lex.data;
640 if( c >= 'A' && c <= 'z' ) {
641 Lex_Name();
642 return;
643 }
644 if( c >= '0' && c <= '9' ) {
645 Lex_Number();
646 return;
647 }
648
649 switch( c ) {
650 case '\0':
651 Lex_Eof();
652 break;
653 case '_':
654 Lex_Name();
655 break;
656 case '\'':
657 Lex_Vector();
658 break;
659 case '\"':
660 Lex_String();
661 break;
662 default:
663 Lex_Punctuation();
664 break;
665 }
666
667 }
668
Lex_BeginParse(const char * data)669 void Lex_BeginParse( const char *data ) {
670 memset( &lex, 0, sizeof( lex ) );
671 lex.data = data;
672 lex.currentLine = 1;
673
674 memset( &lex_immediate, 0, sizeof( lex_immediate ) );
675 lex_immediateType = IT_INT;
676
677 Lex();
678 }
679
680
681
682
683