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