• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 %{
2 /*
3  * Copyright © 2010 Intel Corporation
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the next
13  * paragraph) shall be included in all copies or substantial portions of the
14  * Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22  * DEALINGS IN THE SOFTWARE.
23  */
24 
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <assert.h>
29 #include <inttypes.h>
30 
31 #include "glcpp.h"
32 #include "main/core.h" /* for struct gl_extensions */
33 #include "main/mtypes.h" /* for gl_api enum */
34 
35 #define glcpp_print(stream, str) stream = talloc_strdup_append(stream, str)
36 #define glcpp_printf(stream, fmt, args, ...) \
37 	stream = talloc_asprintf_append(stream, fmt, args)
38 
39 static void
40 yyerror (YYLTYPE *locp, glcpp_parser_t *parser, const char *error);
41 
42 static void
43 _define_object_macro (glcpp_parser_t *parser,
44 		      YYLTYPE *loc,
45 		      const char *macro,
46 		      token_list_t *replacements);
47 
48 static void
49 _define_function_macro (glcpp_parser_t *parser,
50 			YYLTYPE *loc,
51 			const char *macro,
52 			string_list_t *parameters,
53 			token_list_t *replacements);
54 
55 static string_list_t *
56 _string_list_create (void *ctx);
57 
58 static void
59 _string_list_append_item (string_list_t *list, const char *str);
60 
61 static int
62 _string_list_contains (string_list_t *list, const char *member, int *index);
63 
64 static int
65 _string_list_length (string_list_t *list);
66 
67 static int
68 _string_list_equal (string_list_t *a, string_list_t *b);
69 
70 static argument_list_t *
71 _argument_list_create (void *ctx);
72 
73 static void
74 _argument_list_append (argument_list_t *list, token_list_t *argument);
75 
76 static int
77 _argument_list_length (argument_list_t *list);
78 
79 static token_list_t *
80 _argument_list_member_at (argument_list_t *list, int index);
81 
82 /* Note: This function talloc_steal()s the str pointer. */
83 static token_t *
84 _token_create_str (void *ctx, int type, char *str);
85 
86 static token_t *
87 _token_create_ival (void *ctx, int type, int ival);
88 
89 static token_list_t *
90 _token_list_create (void *ctx);
91 
92 /* Note: This function adds a talloc_reference() to token.
93  *
94  * You may want to talloc_unlink any current reference if you no
95  * longer need it. */
96 static void
97 _token_list_append (token_list_t *list, token_t *token);
98 
99 static void
100 _token_list_append_list (token_list_t *list, token_list_t *tail);
101 
102 static int
103 _token_list_equal_ignoring_space (token_list_t *a, token_list_t *b);
104 
105 static active_list_t *
106 _active_list_push (active_list_t *list,
107 		   const char *identifier,
108 		   token_node_t *marker);
109 
110 static active_list_t *
111 _active_list_pop (active_list_t *list);
112 
113 int
114 _active_list_contains (active_list_t *list, const char *identifier);
115 
116 static void
117 _glcpp_parser_expand_if (glcpp_parser_t *parser, int type, token_list_t *list);
118 
119 static void
120 _glcpp_parser_expand_token_list (glcpp_parser_t *parser,
121 				 token_list_t *list);
122 
123 static void
124 _glcpp_parser_print_expanded_token_list (glcpp_parser_t *parser,
125 					 token_list_t *list);
126 
127 static void
128 _glcpp_parser_skip_stack_push_if (glcpp_parser_t *parser, YYLTYPE *loc,
129 				  int condition);
130 
131 static void
132 _glcpp_parser_skip_stack_change_if (glcpp_parser_t *parser, YYLTYPE *loc,
133 				    const char *type, int condition);
134 
135 static void
136 _glcpp_parser_skip_stack_pop (glcpp_parser_t *parser, YYLTYPE *loc);
137 
138 #define yylex glcpp_parser_lex
139 
140 static int
141 glcpp_parser_lex (YYSTYPE *yylval, YYLTYPE *yylloc, glcpp_parser_t *parser);
142 
143 static void
144 glcpp_parser_lex_from (glcpp_parser_t *parser, token_list_t *list);
145 
146 static void
147 add_builtin_define(glcpp_parser_t *parser, const char *name, int value);
148 
149 %}
150 
151 %pure-parser
152 %error-verbose
153 
154 %locations
155 %initial-action {
156 	@$.first_line = 1;
157 	@$.first_column = 1;
158 	@$.last_line = 1;
159 	@$.last_column = 1;
160 	@$.source = 0;
161 }
162 
163 %parse-param {glcpp_parser_t *parser}
164 %lex-param {glcpp_parser_t *parser}
165 
166 %expect 0
167 %token COMMA_FINAL DEFINED ELIF_EXPANDED HASH HASH_DEFINE_FUNC HASH_DEFINE_OBJ HASH_ELIF HASH_ELSE HASH_ENDIF HASH_IF HASH_IFDEF HASH_IFNDEF HASH_UNDEF HASH_VERSION IDENTIFIER IF_EXPANDED INTEGER INTEGER_STRING NEWLINE OTHER PLACEHOLDER SPACE
168 %token PASTE
169 %type <ival> expression INTEGER operator SPACE integer_constant
170 %type <str> IDENTIFIER INTEGER_STRING OTHER
171 %type <string_list> identifier_list
172 %type <token> preprocessing_token conditional_token
173 %type <token_list> pp_tokens replacement_list text_line conditional_tokens
174 %left OR
175 %left AND
176 %left '|'
177 %left '^'
178 %left '&'
179 %left EQUAL NOT_EQUAL
180 %left '<' '>' LESS_OR_EQUAL GREATER_OR_EQUAL
181 %left LEFT_SHIFT RIGHT_SHIFT
182 %left '+' '-'
183 %left '*' '/' '%'
184 %right UNARY
185 
186 %%
187 
188 input:
189 	/* empty */
190 |	input line
191 ;
192 
193 line:
194 	control_line {
195 		glcpp_print(parser->output, "\n");
196 	}
197 |	text_line {
198 		_glcpp_parser_print_expanded_token_list (parser, $1);
199 		glcpp_print(parser->output, "\n");
200 		talloc_free ($1);
201 	}
202 |	expanded_line
203 |	HASH non_directive
204 ;
205 
206 expanded_line:
207 	IF_EXPANDED expression NEWLINE {
208 		_glcpp_parser_skip_stack_push_if (parser, & @1, $2);
209 	}
210 |	ELIF_EXPANDED expression NEWLINE {
211 		_glcpp_parser_skip_stack_change_if (parser, & @1, "elif", $2);
212 	}
213 ;
214 
215 control_line:
216 	HASH_DEFINE_OBJ	IDENTIFIER replacement_list NEWLINE {
217 		_define_object_macro (parser, & @2, $2, $3);
218 	}
219 |	HASH_DEFINE_FUNC IDENTIFIER '(' ')' replacement_list NEWLINE {
220 		_define_function_macro (parser, & @2, $2, NULL, $5);
221 	}
222 |	HASH_DEFINE_FUNC IDENTIFIER '(' identifier_list ')' replacement_list NEWLINE {
223 		_define_function_macro (parser, & @2, $2, $4, $6);
224 	}
225 |	HASH_UNDEF IDENTIFIER NEWLINE {
226 		macro_t *macro = hash_table_find (parser->defines, $2);
227 		if (macro) {
228 			hash_table_remove (parser->defines, $2);
229 			talloc_free (macro);
230 		}
231 		talloc_free ($2);
232 	}
233 |	HASH_IF conditional_tokens NEWLINE {
234 		/* Be careful to only evaluate the 'if' expression if
235 		 * we are not skipping. When we are skipping, we
236 		 * simply push a new 0-valued 'if' onto the skip
237 		 * stack.
238 		 *
239 		 * This avoids generating diagnostics for invalid
240 		 * expressions that are being skipped. */
241 		if (parser->skip_stack == NULL ||
242 		    parser->skip_stack->type == SKIP_NO_SKIP)
243 		{
244 			_glcpp_parser_expand_if (parser, IF_EXPANDED, $2);
245 		}
246 		else
247 		{
248 			_glcpp_parser_skip_stack_push_if (parser, & @1, 0);
249 			parser->skip_stack->type = SKIP_TO_ENDIF;
250 		}
251 	}
252 |	HASH_IF NEWLINE {
253 		/* #if without an expression is only an error if we
254 		 *  are not skipping */
255 		if (parser->skip_stack == NULL ||
256 		    parser->skip_stack->type == SKIP_NO_SKIP)
257 		{
258 			glcpp_error(& @1, parser, "#if with no expression");
259 		}
260 		_glcpp_parser_skip_stack_push_if (parser, & @1, 0);
261 	}
262 |	HASH_IFDEF IDENTIFIER junk NEWLINE {
263 		macro_t *macro = hash_table_find (parser->defines, $2);
264 		talloc_free ($2);
265 		_glcpp_parser_skip_stack_push_if (parser, & @1, macro != NULL);
266 	}
267 |	HASH_IFNDEF IDENTIFIER junk NEWLINE {
268 		macro_t *macro = hash_table_find (parser->defines, $2);
269 		talloc_free ($2);
270 		_glcpp_parser_skip_stack_push_if (parser, & @1, macro == NULL);
271 	}
272 |	HASH_ELIF conditional_tokens NEWLINE {
273 		/* Be careful to only evaluate the 'elif' expression
274 		 * if we are not skipping. When we are skipping, we
275 		 * simply change to a 0-valued 'elif' on the skip
276 		 * stack.
277 		 *
278 		 * This avoids generating diagnostics for invalid
279 		 * expressions that are being skipped. */
280 		if (parser->skip_stack &&
281 		    parser->skip_stack->type == SKIP_TO_ELSE)
282 		{
283 			_glcpp_parser_expand_if (parser, ELIF_EXPANDED, $2);
284 		}
285 		else
286 		{
287 			_glcpp_parser_skip_stack_change_if (parser, & @1,
288 							    "elif", 0);
289 		}
290 	}
291 |	HASH_ELIF NEWLINE {
292 		/* #elif without an expression is an error unless we
293 		 * are skipping. */
294 		if (parser->skip_stack &&
295 		    parser->skip_stack->type == SKIP_TO_ELSE)
296 		{
297 			glcpp_error(& @1, parser, "#elif with no expression");
298 		}
299 		else
300 		{
301 			_glcpp_parser_skip_stack_change_if (parser, & @1,
302 							    "elif", 0);
303 			glcpp_warning(& @1, parser, "ignoring illegal #elif without expression");
304 		}
305 	}
306 |	HASH_ELSE NEWLINE {
307 		_glcpp_parser_skip_stack_change_if (parser, & @1, "else", 1);
308 	}
309 |	HASH_ENDIF NEWLINE {
310 		_glcpp_parser_skip_stack_pop (parser, & @1);
311 	}
312 |	HASH_VERSION integer_constant NEWLINE {
313 		macro_t *macro = hash_table_find (parser->defines, "__VERSION__");
314 		if (macro) {
315 			hash_table_remove (parser->defines, "__VERSION__");
316 			talloc_free (macro);
317 		}
318 		add_builtin_define (parser, "__VERSION__", $2);
319 
320 		if ($2 == 100)
321 			add_builtin_define (parser, "GL_ES", 1);
322 
323 		/* Currently, all ES2 implementations support highp in the
324 		 * fragment shader, so we always define this macro in ES2.
325 		 * If we ever get a driver that doesn't support highp, we'll
326 		 * need to add a flag to the gl_context and check that here.
327 		 */
328 		if ($2 >= 130 || $2 == 100)
329 			add_builtin_define (parser, "GL_FRAGMENT_PRECISION_HIGH", 1);
330 
331 		glcpp_printf(parser->output, "#version %" PRIiMAX, $2);
332 	}
333 |	HASH NEWLINE
334 ;
335 
336 integer_constant:
337 	INTEGER_STRING {
338 		if (strlen ($1) >= 3 && strncmp ($1, "0x", 2) == 0) {
339 			$$ = strtoll ($1 + 2, NULL, 16);
340 		} else if ($1[0] == '0') {
341 			$$ = strtoll ($1, NULL, 8);
342 		} else {
343 			$$ = strtoll ($1, NULL, 10);
344 		}
345 	}
346 |	INTEGER {
347 		$$ = $1;
348 	}
349 
350 expression:
351 	integer_constant
352 |	expression OR expression {
353 		$$ = $1 || $3;
354 	}
355 |	expression AND expression {
356 		$$ = $1 && $3;
357 	}
358 |	expression '|' expression {
359 		$$ = $1 | $3;
360 	}
361 |	expression '^' expression {
362 		$$ = $1 ^ $3;
363 	}
364 |	expression '&' expression {
365 		$$ = $1 & $3;
366 	}
367 |	expression NOT_EQUAL expression {
368 		$$ = $1 != $3;
369 	}
370 |	expression EQUAL expression {
371 		$$ = $1 == $3;
372 	}
373 |	expression GREATER_OR_EQUAL expression {
374 		$$ = $1 >= $3;
375 	}
376 |	expression LESS_OR_EQUAL expression {
377 		$$ = $1 <= $3;
378 	}
379 |	expression '>' expression {
380 		$$ = $1 > $3;
381 	}
382 |	expression '<' expression {
383 		$$ = $1 < $3;
384 	}
385 |	expression RIGHT_SHIFT expression {
386 		$$ = $1 >> $3;
387 	}
388 |	expression LEFT_SHIFT expression {
389 		$$ = $1 << $3;
390 	}
391 |	expression '-' expression {
392 		$$ = $1 - $3;
393 	}
394 |	expression '+' expression {
395 		$$ = $1 + $3;
396 	}
397 |	expression '%' expression {
398 		$$ = $1 % $3;
399 	}
400 |	expression '/' expression {
401 		$$ = $1 / $3;
402 	}
403 |	expression '*' expression {
404 		$$ = $1 * $3;
405 	}
406 |	'!' expression %prec UNARY {
407 		$$ = ! $2;
408 	}
409 |	'~' expression %prec UNARY {
410 		$$ = ~ $2;
411 	}
412 |	'-' expression %prec UNARY {
413 		$$ = - $2;
414 	}
415 |	'+' expression %prec UNARY {
416 		$$ = + $2;
417 	}
418 |	'(' expression ')' {
419 		$$ = $2;
420 	}
421 ;
422 
423 identifier_list:
424 	IDENTIFIER {
425 		$$ = _string_list_create (parser);
426 		_string_list_append_item ($$, $1);
427 		talloc_steal ($$, $1);
428 	}
429 |	identifier_list ',' IDENTIFIER {
430 		$$ = $1;
431 		_string_list_append_item ($$, $3);
432 		talloc_steal ($$, $3);
433 	}
434 ;
435 
436 text_line:
437 	NEWLINE { $$ = NULL; }
438 |	pp_tokens NEWLINE
439 ;
440 
441 non_directive:
442 	pp_tokens NEWLINE {
443 		yyerror (& @1, parser, "Invalid tokens after #");
444 	}
445 ;
446 
447 replacement_list:
448 	/* empty */ { $$ = NULL; }
449 |	pp_tokens
450 ;
451 
452 junk:
453 	/* empty */
454 |	pp_tokens {
455 		glcpp_warning(&@1, parser, "extra tokens at end of directive");
456 	}
457 ;
458 
459 conditional_token:
460 	/* Handle "defined" operator */
461 	DEFINED IDENTIFIER {
462 		int v = hash_table_find (parser->defines, $2) ? 1 : 0;
463 		$$ = _token_create_ival (parser, INTEGER, v);
464 	}
465 |	DEFINED '(' IDENTIFIER ')' {
466 		int v = hash_table_find (parser->defines, $3) ? 1 : 0;
467 		$$ = _token_create_ival (parser, INTEGER, v);
468 	}
469 |	preprocessing_token
470 ;
471 
472 conditional_tokens:
473 	/* Exactly the same as pp_tokens, but using conditional_token */
474 	conditional_token {
475 		$$ = _token_list_create (parser);
476 		_token_list_append ($$, $1);
477 		talloc_unlink (parser, $1);
478 	}
479 |	conditional_tokens conditional_token {
480 		$$ = $1;
481 		_token_list_append ($$, $2);
482 		talloc_unlink (parser, $2);
483 	}
484 ;
485 
486 pp_tokens:
487 	preprocessing_token {
488 		parser->space_tokens = 1;
489 		$$ = _token_list_create (parser);
490 		_token_list_append ($$, $1);
491 		talloc_unlink (parser, $1);
492 	}
493 |	pp_tokens preprocessing_token {
494 		$$ = $1;
495 		_token_list_append ($$, $2);
496 		talloc_unlink (parser, $2);
497 	}
498 ;
499 
500 preprocessing_token:
501 	IDENTIFIER {
502 		$$ = _token_create_str (parser, IDENTIFIER, $1);
503 		$$->location = yylloc;
504 	}
505 |	INTEGER_STRING {
506 		$$ = _token_create_str (parser, INTEGER_STRING, $1);
507 		$$->location = yylloc;
508 	}
509 |	operator {
510 		$$ = _token_create_ival (parser, $1, $1);
511 		$$->location = yylloc;
512 	}
513 |	OTHER {
514 		$$ = _token_create_str (parser, OTHER, $1);
515 		$$->location = yylloc;
516 	}
517 |	SPACE {
518 		$$ = _token_create_ival (parser, SPACE, SPACE);
519 		$$->location = yylloc;
520 	}
521 ;
522 
523 operator:
524 	'['			{ $$ = '['; }
525 |	']'			{ $$ = ']'; }
526 |	'('			{ $$ = '('; }
527 |	')'			{ $$ = ')'; }
528 |	'{'			{ $$ = '{'; }
529 |	'}'			{ $$ = '}'; }
530 |	'.'			{ $$ = '.'; }
531 |	'&'			{ $$ = '&'; }
532 |	'*'			{ $$ = '*'; }
533 |	'+'			{ $$ = '+'; }
534 |	'-'			{ $$ = '-'; }
535 |	'~'			{ $$ = '~'; }
536 |	'!'			{ $$ = '!'; }
537 |	'/'			{ $$ = '/'; }
538 |	'%'			{ $$ = '%'; }
539 |	LEFT_SHIFT		{ $$ = LEFT_SHIFT; }
540 |	RIGHT_SHIFT		{ $$ = RIGHT_SHIFT; }
541 |	'<'			{ $$ = '<'; }
542 |	'>'			{ $$ = '>'; }
543 |	LESS_OR_EQUAL		{ $$ = LESS_OR_EQUAL; }
544 |	GREATER_OR_EQUAL	{ $$ = GREATER_OR_EQUAL; }
545 |	EQUAL			{ $$ = EQUAL; }
546 |	NOT_EQUAL		{ $$ = NOT_EQUAL; }
547 |	'^'			{ $$ = '^'; }
548 |	'|'			{ $$ = '|'; }
549 |	AND			{ $$ = AND; }
550 |	OR			{ $$ = OR; }
551 |	';'			{ $$ = ';'; }
552 |	','			{ $$ = ','; }
553 |	'='			{ $$ = '='; }
554 |	PASTE			{ $$ = PASTE; }
555 ;
556 
557 %%
558 
559 string_list_t *
560 _string_list_create (void *ctx)
561 {
562 	string_list_t *list;
563 
564 	list = talloc (ctx, string_list_t);
565 	list->head = NULL;
566 	list->tail = NULL;
567 
568 	return list;
569 }
570 
571 void
_string_list_append_item(string_list_t * list,const char * str)572 _string_list_append_item (string_list_t *list, const char *str)
573 {
574 	string_node_t *node;
575 
576 	node = talloc (list, string_node_t);
577 	node->str = talloc_strdup (node, str);
578 
579 	node->next = NULL;
580 
581 	if (list->head == NULL) {
582 		list->head = node;
583 	} else {
584 		list->tail->next = node;
585 	}
586 
587 	list->tail = node;
588 }
589 
590 int
_string_list_contains(string_list_t * list,const char * member,int * index)591 _string_list_contains (string_list_t *list, const char *member, int *index)
592 {
593 	string_node_t *node;
594 	int i;
595 
596 	if (list == NULL)
597 		return 0;
598 
599 	for (i = 0, node = list->head; node; i++, node = node->next) {
600 		if (strcmp (node->str, member) == 0) {
601 			if (index)
602 				*index = i;
603 			return 1;
604 		}
605 	}
606 
607 	return 0;
608 }
609 
610 int
_string_list_length(string_list_t * list)611 _string_list_length (string_list_t *list)
612 {
613 	int length = 0;
614 	string_node_t *node;
615 
616 	if (list == NULL)
617 		return 0;
618 
619 	for (node = list->head; node; node = node->next)
620 		length++;
621 
622 	return length;
623 }
624 
625 int
_string_list_equal(string_list_t * a,string_list_t * b)626 _string_list_equal (string_list_t *a, string_list_t *b)
627 {
628 	string_node_t *node_a, *node_b;
629 
630 	if (a == NULL && b == NULL)
631 		return 1;
632 
633 	if (a == NULL || b == NULL)
634 		return 0;
635 
636 	for (node_a = a->head, node_b = b->head;
637 	     node_a && node_b;
638 	     node_a = node_a->next, node_b = node_b->next)
639 	{
640 		if (strcmp (node_a->str, node_b->str))
641 			return 0;
642 	}
643 
644 	/* Catch the case of lists being different lengths, (which
645 	 * would cause the loop above to terminate after the shorter
646 	 * list). */
647 	return node_a == node_b;
648 }
649 
650 argument_list_t *
_argument_list_create(void * ctx)651 _argument_list_create (void *ctx)
652 {
653 	argument_list_t *list;
654 
655 	list = talloc (ctx, argument_list_t);
656 	list->head = NULL;
657 	list->tail = NULL;
658 
659 	return list;
660 }
661 
662 void
_argument_list_append(argument_list_t * list,token_list_t * argument)663 _argument_list_append (argument_list_t *list, token_list_t *argument)
664 {
665 	argument_node_t *node;
666 
667 	node = talloc (list, argument_node_t);
668 	node->argument = argument;
669 
670 	node->next = NULL;
671 
672 	if (list->head == NULL) {
673 		list->head = node;
674 	} else {
675 		list->tail->next = node;
676 	}
677 
678 	list->tail = node;
679 }
680 
681 int
_argument_list_length(argument_list_t * list)682 _argument_list_length (argument_list_t *list)
683 {
684 	int length = 0;
685 	argument_node_t *node;
686 
687 	if (list == NULL)
688 		return 0;
689 
690 	for (node = list->head; node; node = node->next)
691 		length++;
692 
693 	return length;
694 }
695 
696 token_list_t *
_argument_list_member_at(argument_list_t * list,int index)697 _argument_list_member_at (argument_list_t *list, int index)
698 {
699 	argument_node_t *node;
700 	int i;
701 
702 	if (list == NULL)
703 		return NULL;
704 
705 	node = list->head;
706 	for (i = 0; i < index; i++) {
707 		node = node->next;
708 		if (node == NULL)
709 			break;
710 	}
711 
712 	if (node)
713 		return node->argument;
714 
715 	return NULL;
716 }
717 
718 /* Note: This function talloc_steal()s the str pointer. */
719 token_t *
_token_create_str(void * ctx,int type,char * str)720 _token_create_str (void *ctx, int type, char *str)
721 {
722 	token_t *token;
723 
724 	token = talloc (ctx, token_t);
725 	token->type = type;
726 	token->value.str = talloc_steal (token, str);
727 
728 	return token;
729 }
730 
731 token_t *
_token_create_ival(void * ctx,int type,int ival)732 _token_create_ival (void *ctx, int type, int ival)
733 {
734 	token_t *token;
735 
736 	token = talloc (ctx, token_t);
737 	token->type = type;
738 	token->value.ival = ival;
739 
740 	return token;
741 }
742 
743 token_list_t *
_token_list_create(void * ctx)744 _token_list_create (void *ctx)
745 {
746 	token_list_t *list;
747 
748 	list = talloc (ctx, token_list_t);
749 	list->head = NULL;
750 	list->tail = NULL;
751 	list->non_space_tail = NULL;
752 
753 	return list;
754 }
755 
756 void
_token_list_append(token_list_t * list,token_t * token)757 _token_list_append (token_list_t *list, token_t *token)
758 {
759 	token_node_t *node;
760 
761 	node = talloc (list, token_node_t);
762 	node->token = talloc_reference (list, token);
763 
764 	node->next = NULL;
765 
766 	if (list->head == NULL) {
767 		list->head = node;
768 	} else {
769 		list->tail->next = node;
770 	}
771 
772 	list->tail = node;
773 	if (token->type != SPACE)
774 		list->non_space_tail = node;
775 }
776 
777 void
_token_list_append_list(token_list_t * list,token_list_t * tail)778 _token_list_append_list (token_list_t *list, token_list_t *tail)
779 {
780 	if (tail == NULL || tail->head == NULL)
781 		return;
782 
783 	if (list->head == NULL) {
784 		list->head = tail->head;
785 	} else {
786 		list->tail->next = tail->head;
787 	}
788 
789 	list->tail = tail->tail;
790 	list->non_space_tail = tail->non_space_tail;
791 }
792 
793 static token_list_t *
_token_list_copy(void * ctx,token_list_t * other)794 _token_list_copy (void *ctx, token_list_t *other)
795 {
796 	token_list_t *copy;
797 	token_node_t *node;
798 
799 	if (other == NULL)
800 		return NULL;
801 
802 	copy = _token_list_create (ctx);
803 	for (node = other->head; node; node = node->next)
804 		_token_list_append (copy, node->token);
805 
806 	return copy;
807 }
808 
809 static void
_token_list_trim_trailing_space(token_list_t * list)810 _token_list_trim_trailing_space (token_list_t *list)
811 {
812 	token_node_t *tail, *next;
813 
814 	if (list->non_space_tail) {
815 		tail = list->non_space_tail->next;
816 		list->non_space_tail->next = NULL;
817 		list->tail = list->non_space_tail;
818 
819 		while (tail) {
820 			next = tail->next;
821 			talloc_free (tail);
822 			tail = next;
823 		}
824 	}
825 }
826 
827 int
_token_list_equal_ignoring_space(token_list_t * a,token_list_t * b)828 _token_list_equal_ignoring_space (token_list_t *a, token_list_t *b)
829 {
830 	token_node_t *node_a, *node_b;
831 
832 	node_a = a->head;
833 	node_b = b->head;
834 
835 	while (1)
836 	{
837 		if (node_a == NULL && node_b == NULL)
838 			break;
839 
840 		if (node_a == NULL || node_b == NULL)
841 			return 0;
842 
843 		if (node_a->token->type == SPACE) {
844 			node_a = node_a->next;
845 			continue;
846 		}
847 
848 		if (node_b->token->type == SPACE) {
849 			node_b = node_b->next;
850 			continue;
851 		}
852 
853 		if (node_a->token->type != node_b->token->type)
854 			return 0;
855 
856 		switch (node_a->token->type) {
857 		case INTEGER:
858 			if (node_a->token->value.ival !=
859 			    node_b->token->value.ival)
860 			{
861 				return 0;
862 			}
863 			break;
864 		case IDENTIFIER:
865 		case INTEGER_STRING:
866 		case OTHER:
867 			if (strcmp (node_a->token->value.str,
868 				    node_b->token->value.str))
869 			{
870 				return 0;
871 			}
872 			break;
873 		}
874 
875 		node_a = node_a->next;
876 		node_b = node_b->next;
877 	}
878 
879 	return 1;
880 }
881 
882 static void
_token_print(char ** out,token_t * token)883 _token_print (char **out, token_t *token)
884 {
885 	if (token->type < 256) {
886 		glcpp_printf (*out, "%c", token->type);
887 		return;
888 	}
889 
890 	switch (token->type) {
891 	case INTEGER:
892 		glcpp_printf (*out, "%" PRIiMAX, token->value.ival);
893 		break;
894 	case IDENTIFIER:
895 	case INTEGER_STRING:
896 	case OTHER:
897 		glcpp_print (*out, token->value.str);
898 		break;
899 	case SPACE:
900 		glcpp_print (*out, " ");
901 		break;
902 	case LEFT_SHIFT:
903 		glcpp_print (*out, "<<");
904 		break;
905 	case RIGHT_SHIFT:
906 		glcpp_print (*out, ">>");
907 		break;
908 	case LESS_OR_EQUAL:
909 		glcpp_print (*out, "<=");
910 		break;
911 	case GREATER_OR_EQUAL:
912 		glcpp_print (*out, ">=");
913 		break;
914 	case EQUAL:
915 		glcpp_print (*out, "==");
916 		break;
917 	case NOT_EQUAL:
918 		glcpp_print (*out, "!=");
919 		break;
920 	case AND:
921 		glcpp_print (*out, "&&");
922 		break;
923 	case OR:
924 		glcpp_print (*out, "||");
925 		break;
926 	case PASTE:
927 		glcpp_print (*out, "##");
928 		break;
929 	case COMMA_FINAL:
930 		glcpp_print (*out, ",");
931 		break;
932 	case PLACEHOLDER:
933 		/* Nothing to print. */
934 		break;
935 	default:
936 		assert(!"Error: Don't know how to print token.");
937 		break;
938 	}
939 }
940 
941 /* Return a new token (talloc()ed off of 'token') formed by pasting
942  * 'token' and 'other'. Note that this function may return 'token' or
943  * 'other' directly rather than allocating anything new.
944  *
945  * Caution: Only very cursory error-checking is performed to see if
946  * the final result is a valid single token. */
947 static token_t *
_token_paste(glcpp_parser_t * parser,token_t * token,token_t * other)948 _token_paste (glcpp_parser_t *parser, token_t *token, token_t *other)
949 {
950 	token_t *combined = NULL;
951 
952 	/* Pasting a placeholder onto anything makes no change. */
953 	if (other->type == PLACEHOLDER)
954 		return token;
955 
956 	/* When 'token' is a placeholder, just return 'other'. */
957 	if (token->type == PLACEHOLDER)
958 		return other;
959 
960 	/* A very few single-character punctuators can be combined
961 	 * with another to form a multi-character punctuator. */
962 	switch (token->type) {
963 	case '<':
964 		if (other->type == '<')
965 			combined = _token_create_ival (token, LEFT_SHIFT, LEFT_SHIFT);
966 		else if (other->type == '=')
967 			combined = _token_create_ival (token, LESS_OR_EQUAL, LESS_OR_EQUAL);
968 		break;
969 	case '>':
970 		if (other->type == '>')
971 			combined = _token_create_ival (token, RIGHT_SHIFT, RIGHT_SHIFT);
972 		else if (other->type == '=')
973 			combined = _token_create_ival (token, GREATER_OR_EQUAL, GREATER_OR_EQUAL);
974 		break;
975 	case '=':
976 		if (other->type == '=')
977 			combined = _token_create_ival (token, EQUAL, EQUAL);
978 		break;
979 	case '!':
980 		if (other->type == '=')
981 			combined = _token_create_ival (token, NOT_EQUAL, NOT_EQUAL);
982 		break;
983 	case '&':
984 		if (other->type == '&')
985 			combined = _token_create_ival (token, AND, AND);
986 		break;
987 	case '|':
988 		if (other->type == '|')
989 			combined = _token_create_ival (token, OR, OR);
990 		break;
991 	}
992 
993 	if (combined != NULL) {
994 		/* Inherit the location from the first token */
995 		combined->location = token->location;
996 		return combined;
997 	}
998 
999 	/* Two string-valued tokens can usually just be mashed
1000 	 * together.
1001 	 *
1002 	 * XXX: This isn't actually legitimate. Several things here
1003 	 * should result in a diagnostic since the result cannot be a
1004 	 * valid, single pre-processing token. For example, pasting
1005 	 * "123" and "abc" is not legal, but we don't catch that
1006 	 * here. */
1007 	if ((token->type == IDENTIFIER || token->type == OTHER || token->type == INTEGER_STRING) &&
1008 	    (other->type == IDENTIFIER || other->type == OTHER || other->type == INTEGER_STRING))
1009 	{
1010 		char *str;
1011 
1012 		str = talloc_asprintf (token, "%s%s", token->value.str,
1013 				       other->value.str);
1014 		combined = _token_create_str (token, token->type, str);
1015 		combined->location = token->location;
1016 		return combined;
1017 	}
1018 
1019 	glcpp_error (&token->location, parser, "");
1020 	glcpp_print (parser->info_log, "Pasting \"");
1021 	_token_print (&parser->info_log, token);
1022 	glcpp_print (parser->info_log, "\" and \"");
1023 	_token_print (&parser->info_log, other);
1024 	glcpp_print (parser->info_log, "\" does not give a valid preprocessing token.\n");
1025 
1026 	return token;
1027 }
1028 
1029 static void
_token_list_print(glcpp_parser_t * parser,token_list_t * list)1030 _token_list_print (glcpp_parser_t *parser, token_list_t *list)
1031 {
1032 	token_node_t *node;
1033 
1034 	if (list == NULL)
1035 		return;
1036 
1037 	for (node = list->head; node; node = node->next)
1038 		_token_print (&parser->output, node->token);
1039 }
1040 
1041 void
yyerror(YYLTYPE * locp,glcpp_parser_t * parser,const char * error)1042 yyerror (YYLTYPE *locp, glcpp_parser_t *parser, const char *error)
1043 {
1044 	glcpp_error(locp, parser, "%s", error);
1045 }
1046 
add_builtin_define(glcpp_parser_t * parser,const char * name,int value)1047 static void add_builtin_define(glcpp_parser_t *parser,
1048 			       const char *name, int value)
1049 {
1050    token_t *tok;
1051    token_list_t *list;
1052 
1053    tok = _token_create_ival (parser, INTEGER, value);
1054 
1055    list = _token_list_create(parser);
1056    _token_list_append(list, tok);
1057    _define_object_macro(parser, NULL, name, list);
1058 
1059    talloc_unlink(parser, tok);
1060 }
1061 
1062 glcpp_parser_t *
glcpp_parser_create(const struct gl_extensions * extensions,int api)1063 glcpp_parser_create (const struct gl_extensions *extensions, int api)
1064 {
1065 	glcpp_parser_t *parser;
1066 	int language_version;
1067 
1068 	parser = talloc (NULL, glcpp_parser_t);
1069 
1070 	glcpp_lex_init_extra (parser, &parser->scanner);
1071 	parser->defines = hash_table_ctor (32, hash_table_string_hash,
1072 					   hash_table_string_compare);
1073 	parser->active = NULL;
1074 	parser->lexing_if = 0;
1075 	parser->space_tokens = 1;
1076 	parser->newline_as_space = 0;
1077 	parser->in_control_line = 0;
1078 	parser->paren_count = 0;
1079 
1080 	parser->skip_stack = NULL;
1081 
1082 	parser->lex_from_list = NULL;
1083 	parser->lex_from_node = NULL;
1084 
1085 	parser->output = talloc_strdup(parser, "");
1086 	parser->info_log = talloc_strdup(parser, "");
1087 	parser->error = 0;
1088 
1089 	/* Add pre-defined macros. */
1090 	add_builtin_define(parser, "GL_ARB_draw_buffers", 1);
1091 	add_builtin_define(parser, "GL_ARB_texture_rectangle", 1);
1092 
1093 	if (api == API_OPENGLES2)
1094 		add_builtin_define(parser, "GL_ES", 1);
1095 
1096 	if (extensions != NULL) {
1097 	   if (extensions->EXT_texture_array) {
1098 	      add_builtin_define(parser, "GL_EXT_texture_array", 1);
1099 	   }
1100 
1101 	   if (extensions->ARB_fragment_coord_conventions)
1102 	      add_builtin_define(parser, "GL_ARB_fragment_coord_conventions",
1103 				 1);
1104 
1105 	   if (extensions->ARB_explicit_attrib_location)
1106 	      add_builtin_define(parser, "GL_ARB_explicit_attrib_location", 1);
1107 	}
1108 
1109 	language_version = 110;
1110 	add_builtin_define(parser, "__VERSION__", language_version);
1111 
1112 	return parser;
1113 }
1114 
1115 int
glcpp_parser_parse(glcpp_parser_t * parser)1116 glcpp_parser_parse (glcpp_parser_t *parser)
1117 {
1118 	return yyparse (parser);
1119 }
1120 
1121 void
glcpp_parser_destroy(glcpp_parser_t * parser)1122 glcpp_parser_destroy (glcpp_parser_t *parser)
1123 {
1124 	glcpp_lex_destroy (parser->scanner);
1125 	hash_table_dtor (parser->defines);
1126 	talloc_free (parser);
1127 }
1128 
1129 typedef enum function_status
1130 {
1131 	FUNCTION_STATUS_SUCCESS,
1132 	FUNCTION_NOT_A_FUNCTION,
1133 	FUNCTION_UNBALANCED_PARENTHESES
1134 } function_status_t;
1135 
1136 /* Find a set of function-like macro arguments by looking for a
1137  * balanced set of parentheses.
1138  *
1139  * When called, 'node' should be the opening-parenthesis token, (or
1140  * perhaps preceeding SPACE tokens). Upon successful return *last will
1141  * be the last consumed node, (corresponding to the closing right
1142  * parenthesis).
1143  *
1144  * Return values:
1145  *
1146  *   FUNCTION_STATUS_SUCCESS:
1147  *
1148  *	Successfully parsed a set of function arguments.
1149  *
1150  *   FUNCTION_NOT_A_FUNCTION:
1151  *
1152  *	Macro name not followed by a '('. This is not an error, but
1153  *	simply that the macro name should be treated as a non-macro.
1154  *
1155  *   FUNCTION_UNBALANCED_PARENTHESES
1156  *
1157  *	Macro name is not followed by a balanced set of parentheses.
1158  */
1159 static function_status_t
_arguments_parse(argument_list_t * arguments,token_node_t * node,token_node_t ** last)1160 _arguments_parse (argument_list_t *arguments,
1161 		  token_node_t *node,
1162 		  token_node_t **last)
1163 {
1164 	token_list_t *argument;
1165 	int paren_count;
1166 
1167 	node = node->next;
1168 
1169 	/* Ignore whitespace before first parenthesis. */
1170 	while (node && node->token->type == SPACE)
1171 		node = node->next;
1172 
1173 	if (node == NULL || node->token->type != '(')
1174 		return FUNCTION_NOT_A_FUNCTION;
1175 
1176 	node = node->next;
1177 
1178 	argument = _token_list_create (arguments);
1179 	_argument_list_append (arguments, argument);
1180 
1181 	for (paren_count = 1; node; node = node->next) {
1182 		if (node->token->type == '(')
1183 		{
1184 			paren_count++;
1185 		}
1186 		else if (node->token->type == ')')
1187 		{
1188 			paren_count--;
1189 			if (paren_count == 0)
1190 				break;
1191 		}
1192 
1193 		if (node->token->type == ',' &&
1194 			 paren_count == 1)
1195 		{
1196 			_token_list_trim_trailing_space (argument);
1197 			argument = _token_list_create (arguments);
1198 			_argument_list_append (arguments, argument);
1199 		}
1200 		else {
1201 			if (argument->head == NULL) {
1202 				/* Don't treat initial whitespace as
1203 				 * part of the arguement. */
1204 				if (node->token->type == SPACE)
1205 					continue;
1206 			}
1207 			_token_list_append (argument, node->token);
1208 		}
1209 	}
1210 
1211 	if (paren_count)
1212 		return FUNCTION_UNBALANCED_PARENTHESES;
1213 
1214 	*last = node;
1215 
1216 	return FUNCTION_STATUS_SUCCESS;
1217 }
1218 
1219 static token_list_t *
_token_list_create_with_one_space(void * ctx)1220 _token_list_create_with_one_space (void *ctx)
1221 {
1222 	token_list_t *list;
1223 	token_t *space;
1224 
1225 	list = _token_list_create (ctx);
1226 	space = _token_create_ival (list, SPACE, SPACE);
1227 	_token_list_append (list, space);
1228 
1229 	return list;
1230 }
1231 
1232 static void
_glcpp_parser_expand_if(glcpp_parser_t * parser,int type,token_list_t * list)1233 _glcpp_parser_expand_if (glcpp_parser_t *parser, int type, token_list_t *list)
1234 {
1235 	token_list_t *expanded;
1236 	token_t *token;
1237 
1238 	expanded = _token_list_create (parser);
1239 	token = _token_create_ival (parser, type, type);
1240 	_token_list_append (expanded, token);
1241 	_glcpp_parser_expand_token_list (parser, list);
1242 	_token_list_append_list (expanded, list);
1243 	glcpp_parser_lex_from (parser, expanded);
1244 }
1245 
1246 /* This is a helper function that's essentially part of the
1247  * implementation of _glcpp_parser_expand_node. It shouldn't be called
1248  * except for by that function.
1249  *
1250  * Returns NULL if node is a simple token with no expansion, (that is,
1251  * although 'node' corresponds to an identifier defined as a
1252  * function-like macro, it is not followed with a parenthesized
1253  * argument list).
1254  *
1255  * Compute the complete expansion of node (which is a function-like
1256  * macro) and subsequent nodes which are arguments.
1257  *
1258  * Returns the token list that results from the expansion and sets
1259  * *last to the last node in the list that was consumed by the
1260  * expansion. Specifically, *last will be set as follows: as the
1261  * token of the closing right parenthesis.
1262  */
1263 static token_list_t *
_glcpp_parser_expand_function(glcpp_parser_t * parser,token_node_t * node,token_node_t ** last)1264 _glcpp_parser_expand_function (glcpp_parser_t *parser,
1265 			       token_node_t *node,
1266 			       token_node_t **last)
1267 
1268 {
1269 	macro_t *macro;
1270 	const char *identifier;
1271 	argument_list_t *arguments;
1272 	function_status_t status;
1273 	token_list_t *substituted;
1274 	int parameter_index;
1275 
1276 	identifier = node->token->value.str;
1277 
1278 	macro = hash_table_find (parser->defines, identifier);
1279 
1280 	assert (macro->is_function);
1281 
1282 	arguments = _argument_list_create (parser);
1283 	status = _arguments_parse (arguments, node, last);
1284 
1285 	switch (status) {
1286 	case FUNCTION_STATUS_SUCCESS:
1287 		break;
1288 	case FUNCTION_NOT_A_FUNCTION:
1289 		return NULL;
1290 	case FUNCTION_UNBALANCED_PARENTHESES:
1291 		glcpp_error (&node->token->location, parser, "Macro %s call has unbalanced parentheses\n", identifier);
1292 		return NULL;
1293 	}
1294 
1295 	/* Replace a macro defined as empty with a SPACE token. */
1296 	if (macro->replacements == NULL) {
1297 		talloc_free (arguments);
1298 		return _token_list_create_with_one_space (parser);
1299 	}
1300 
1301 	if (! ((_argument_list_length (arguments) ==
1302 		_string_list_length (macro->parameters)) ||
1303 	       (_string_list_length (macro->parameters) == 0 &&
1304 		_argument_list_length (arguments) == 1 &&
1305 		arguments->head->argument->head == NULL)))
1306 	{
1307 		glcpp_error (&node->token->location, parser,
1308 			      "Error: macro %s invoked with %d arguments (expected %d)\n",
1309 			      identifier,
1310 			      _argument_list_length (arguments),
1311 			      _string_list_length (macro->parameters));
1312 		return NULL;
1313 	}
1314 
1315 	/* Perform argument substitution on the replacement list. */
1316 	substituted = _token_list_create (arguments);
1317 
1318 	for (node = macro->replacements->head; node; node = node->next)
1319 	{
1320 		if (node->token->type == IDENTIFIER &&
1321 		    _string_list_contains (macro->parameters,
1322 					   node->token->value.str,
1323 					   &parameter_index))
1324 		{
1325 			token_list_t *argument;
1326 			argument = _argument_list_member_at (arguments,
1327 							     parameter_index);
1328 			/* Before substituting, we expand the argument
1329 			 * tokens, or append a placeholder token for
1330 			 * an empty argument. */
1331 			if (argument->head) {
1332 				token_list_t *expanded_argument;
1333 				expanded_argument = _token_list_copy (parser,
1334 								      argument);
1335 				_glcpp_parser_expand_token_list (parser,
1336 								 expanded_argument);
1337 				_token_list_append_list (substituted,
1338 							 expanded_argument);
1339 			} else {
1340 				token_t *new_token;
1341 
1342 				new_token = _token_create_ival (substituted,
1343 								PLACEHOLDER,
1344 								PLACEHOLDER);
1345 				_token_list_append (substituted, new_token);
1346 			}
1347 		} else {
1348 			_token_list_append (substituted, node->token);
1349 		}
1350 	}
1351 
1352 	/* After argument substitution, and before further expansion
1353 	 * below, implement token pasting. */
1354 
1355 	_token_list_trim_trailing_space (substituted);
1356 
1357 	node = substituted->head;
1358 	while (node)
1359 	{
1360 		token_node_t *next_non_space;
1361 
1362 		/* Look ahead for a PASTE token, skipping space. */
1363 		next_non_space = node->next;
1364 		while (next_non_space && next_non_space->token->type == SPACE)
1365 			next_non_space = next_non_space->next;
1366 
1367 		if (next_non_space == NULL)
1368 			break;
1369 
1370 		if (next_non_space->token->type != PASTE) {
1371 			node = next_non_space;
1372 			continue;
1373 		}
1374 
1375 		/* Now find the next non-space token after the PASTE. */
1376 		next_non_space = next_non_space->next;
1377 		while (next_non_space && next_non_space->token->type == SPACE)
1378 			next_non_space = next_non_space->next;
1379 
1380 		if (next_non_space == NULL) {
1381 			yyerror (&node->token->location, parser, "'##' cannot appear at either end of a macro expansion\n");
1382 			return NULL;
1383 		}
1384 
1385 		node->token = _token_paste (parser, node->token, next_non_space->token);
1386 		node->next = next_non_space->next;
1387 		if (next_non_space == substituted->tail)
1388 			substituted->tail = node;
1389 
1390 		node = node->next;
1391 	}
1392 
1393 	substituted->non_space_tail = substituted->tail;
1394 
1395 	return substituted;
1396 }
1397 
1398 /* Compute the complete expansion of node, (and subsequent nodes after
1399  * 'node' in the case that 'node' is a function-like macro and
1400  * subsequent nodes are arguments).
1401  *
1402  * Returns NULL if node is a simple token with no expansion.
1403  *
1404  * Otherwise, returns the token list that results from the expansion
1405  * and sets *last to the last node in the list that was consumed by
1406  * the expansion. Specifically, *last will be set as follows:
1407  *
1408  *	As 'node' in the case of object-like macro expansion.
1409  *
1410  *	As the token of the closing right parenthesis in the case of
1411  *	function-like macro expansion.
1412  */
1413 static token_list_t *
_glcpp_parser_expand_node(glcpp_parser_t * parser,token_node_t * node,token_node_t ** last)1414 _glcpp_parser_expand_node (glcpp_parser_t *parser,
1415 			   token_node_t *node,
1416 			   token_node_t **last)
1417 {
1418 	token_t *token = node->token;
1419 	const char *identifier;
1420 	macro_t *macro;
1421 
1422 	/* We only expand identifiers */
1423 	if (token->type != IDENTIFIER) {
1424 		/* We change any COMMA into a COMMA_FINAL to prevent
1425 		 * it being mistaken for an argument separator
1426 		 * later. */
1427 		if (token->type == ',') {
1428 			token->type = COMMA_FINAL;
1429 			token->value.ival = COMMA_FINAL;
1430 		}
1431 
1432 		return NULL;
1433 	}
1434 
1435 	/* Look up this identifier in the hash table. */
1436 	identifier = token->value.str;
1437 	macro = hash_table_find (parser->defines, identifier);
1438 
1439 	/* Not a macro, so no expansion needed. */
1440 	if (macro == NULL)
1441 		return NULL;
1442 
1443 	/* Finally, don't expand this macro if we're already actively
1444 	 * expanding it, (to avoid infinite recursion). */
1445 	if (_active_list_contains (parser->active, identifier)) {
1446 		/* We change the token type here from IDENTIFIER to
1447 		 * OTHER to prevent any future expansion of this
1448 		 * unexpanded token. */
1449 		char *str;
1450 		token_list_t *expansion;
1451 		token_t *final;
1452 
1453 		str = talloc_strdup (parser, token->value.str);
1454 		final = _token_create_str (parser, OTHER, str);
1455 		expansion = _token_list_create (parser);
1456 		_token_list_append (expansion, final);
1457 		*last = node;
1458 		return expansion;
1459 	}
1460 
1461 	if (! macro->is_function)
1462 	{
1463 		*last = node;
1464 
1465 		/* Replace a macro defined as empty with a SPACE token. */
1466 		if (macro->replacements == NULL)
1467 			return _token_list_create_with_one_space (parser);
1468 
1469 		return _token_list_copy (parser, macro->replacements);
1470 	}
1471 
1472 	return _glcpp_parser_expand_function (parser, node, last);
1473 }
1474 
1475 /* Push a new identifier onto the active list, returning the new list.
1476  *
1477  * Here, 'marker' is the token node that appears in the list after the
1478  * expansion of 'identifier'. That is, when the list iterator begins
1479  * examinging 'marker', then it is time to pop this node from the
1480  * active stack.
1481  */
1482 active_list_t *
_active_list_push(active_list_t * list,const char * identifier,token_node_t * marker)1483 _active_list_push (active_list_t *list,
1484 		   const char *identifier,
1485 		   token_node_t *marker)
1486 {
1487 	active_list_t *node;
1488 
1489 	node = talloc (list, active_list_t);
1490 	node->identifier = talloc_strdup (node, identifier);
1491 	node->marker = marker;
1492 	node->next = list;
1493 
1494 	return node;
1495 }
1496 
1497 active_list_t *
_active_list_pop(active_list_t * list)1498 _active_list_pop (active_list_t *list)
1499 {
1500 	active_list_t *node = list;
1501 
1502 	if (node == NULL)
1503 		return NULL;
1504 
1505 	node = list->next;
1506 	talloc_free (list);
1507 
1508 	return node;
1509 }
1510 
1511 int
_active_list_contains(active_list_t * list,const char * identifier)1512 _active_list_contains (active_list_t *list, const char *identifier)
1513 {
1514 	active_list_t *node;
1515 
1516 	if (list == NULL)
1517 		return 0;
1518 
1519 	for (node = list; node; node = node->next)
1520 		if (strcmp (node->identifier, identifier) == 0)
1521 			return 1;
1522 
1523 	return 0;
1524 }
1525 
1526 /* Walk over the token list replacing nodes with their expansion.
1527  * Whenever nodes are expanded the walking will walk over the new
1528  * nodes, continuing to expand as necessary. The results are placed in
1529  * 'list' itself;
1530  */
1531 static void
_glcpp_parser_expand_token_list(glcpp_parser_t * parser,token_list_t * list)1532 _glcpp_parser_expand_token_list (glcpp_parser_t *parser,
1533 				 token_list_t *list)
1534 {
1535 	token_node_t *node_prev;
1536 	token_node_t *node, *last = NULL;
1537 	token_list_t *expansion;
1538 
1539 	if (list == NULL)
1540 		return;
1541 
1542 	_token_list_trim_trailing_space (list);
1543 
1544 	node_prev = NULL;
1545 	node = list->head;
1546 
1547 	while (node) {
1548 
1549 		while (parser->active && parser->active->marker == node)
1550 			parser->active = _active_list_pop (parser->active);
1551 
1552 		/* Find the expansion for node, which will replace all
1553 		 * nodes from node to last, inclusive. */
1554 		expansion = _glcpp_parser_expand_node (parser, node, &last);
1555 		if (expansion) {
1556 			token_node_t *n;
1557 
1558 			for (n = node; n != last->next; n = n->next)
1559 				while (parser->active &&
1560 				       parser->active->marker == n)
1561 				{
1562 					parser->active = _active_list_pop (parser->active);
1563 				}
1564 
1565 			parser->active = _active_list_push (parser->active,
1566 							    node->token->value.str,
1567 							    last->next);
1568 
1569 			/* Splice expansion into list, supporting a
1570 			 * simple deletion if the expansion is
1571 			 * empty. */
1572 			if (expansion->head) {
1573 				if (node_prev)
1574 					node_prev->next = expansion->head;
1575 				else
1576 					list->head = expansion->head;
1577 				expansion->tail->next = last->next;
1578 				if (last == list->tail)
1579 					list->tail = expansion->tail;
1580 			} else {
1581 				if (node_prev)
1582 					node_prev->next = last->next;
1583 				else
1584 					list->head = last->next;
1585 				if (last == list->tail)
1586 					list->tail = NULL;
1587 			}
1588 		} else {
1589 			node_prev = node;
1590 		}
1591 		node = node_prev ? node_prev->next : list->head;
1592 	}
1593 
1594 	while (parser->active)
1595 		parser->active = _active_list_pop (parser->active);
1596 
1597 	list->non_space_tail = list->tail;
1598 }
1599 
1600 void
_glcpp_parser_print_expanded_token_list(glcpp_parser_t * parser,token_list_t * list)1601 _glcpp_parser_print_expanded_token_list (glcpp_parser_t *parser,
1602 					 token_list_t *list)
1603 {
1604 	if (list == NULL)
1605 		return;
1606 
1607 	_glcpp_parser_expand_token_list (parser, list);
1608 
1609 	_token_list_trim_trailing_space (list);
1610 
1611 	_token_list_print (parser, list);
1612 }
1613 
1614 static void
_check_for_reserved_macro_name(glcpp_parser_t * parser,YYLTYPE * loc,const char * identifier)1615 _check_for_reserved_macro_name (glcpp_parser_t *parser, YYLTYPE *loc,
1616 				const char *identifier)
1617 {
1618 	/* According to the GLSL specification, macro names starting with "__"
1619 	 * or "GL_" are reserved for future use.  So, don't allow them.
1620 	 */
1621 	if (strncmp(identifier, "__", 2) == 0) {
1622 		glcpp_error (loc, parser, "Macro names starting with \"__\" are reserved.\n");
1623 	}
1624 	if (strncmp(identifier, "GL_", 3) == 0) {
1625 		glcpp_error (loc, parser, "Macro names starting with \"GL_\" are reserved.\n");
1626 	}
1627 }
1628 
1629 static int
_macro_equal(macro_t * a,macro_t * b)1630 _macro_equal (macro_t *a, macro_t *b)
1631 {
1632 	if (a->is_function != b->is_function)
1633 		return 0;
1634 
1635 	if (a->is_function) {
1636 		if (! _string_list_equal (a->parameters, b->parameters))
1637 			return 0;
1638 	}
1639 
1640 	return _token_list_equal_ignoring_space (a->replacements,
1641 						 b->replacements);
1642 }
1643 
1644 void
_define_object_macro(glcpp_parser_t * parser,YYLTYPE * loc,const char * identifier,token_list_t * replacements)1645 _define_object_macro (glcpp_parser_t *parser,
1646 		      YYLTYPE *loc,
1647 		      const char *identifier,
1648 		      token_list_t *replacements)
1649 {
1650 	macro_t *macro, *previous;
1651 
1652 	if (loc != NULL)
1653 		_check_for_reserved_macro_name(parser, loc, identifier);
1654 
1655 	macro = talloc (parser, macro_t);
1656 
1657 	macro->is_function = 0;
1658 	macro->parameters = NULL;
1659 	macro->identifier = talloc_strdup (macro, identifier);
1660 	macro->replacements = talloc_steal (macro, replacements);
1661 
1662 	previous = hash_table_find (parser->defines, identifier);
1663 	if (previous) {
1664 		if (_macro_equal (macro, previous)) {
1665 			talloc_free (macro);
1666 			return;
1667 		}
1668 		glcpp_error (loc, parser, "Redefinition of macro %s\n",
1669 			     identifier);
1670 	}
1671 
1672 	hash_table_insert (parser->defines, macro, identifier);
1673 }
1674 
1675 void
_define_function_macro(glcpp_parser_t * parser,YYLTYPE * loc,const char * identifier,string_list_t * parameters,token_list_t * replacements)1676 _define_function_macro (glcpp_parser_t *parser,
1677 			YYLTYPE *loc,
1678 			const char *identifier,
1679 			string_list_t *parameters,
1680 			token_list_t *replacements)
1681 {
1682 	macro_t *macro, *previous;
1683 
1684 	_check_for_reserved_macro_name(parser, loc, identifier);
1685 
1686 	macro = talloc (parser, macro_t);
1687 
1688 	macro->is_function = 1;
1689 	macro->parameters = talloc_steal (macro, parameters);
1690 	macro->identifier = talloc_strdup (macro, identifier);
1691 	macro->replacements = talloc_steal (macro, replacements);
1692 
1693 	previous = hash_table_find (parser->defines, identifier);
1694 	if (previous) {
1695 		if (_macro_equal (macro, previous)) {
1696 			talloc_free (macro);
1697 			return;
1698 		}
1699 		glcpp_error (loc, parser, "Redefinition of macro %s\n",
1700 			     identifier);
1701 	}
1702 
1703 	hash_table_insert (parser->defines, macro, identifier);
1704 }
1705 
1706 static int
glcpp_parser_lex(YYSTYPE * yylval,YYLTYPE * yylloc,glcpp_parser_t * parser)1707 glcpp_parser_lex (YYSTYPE *yylval, YYLTYPE *yylloc, glcpp_parser_t *parser)
1708 {
1709 	token_node_t *node;
1710 	int ret;
1711 
1712 	if (parser->lex_from_list == NULL) {
1713 		ret = glcpp_lex (yylval, yylloc, parser->scanner);
1714 
1715 		/* XXX: This ugly block of code exists for the sole
1716 		 * purpose of converting a NEWLINE token into a SPACE
1717 		 * token, but only in the case where we have seen a
1718 		 * function-like macro name, but have not yet seen its
1719 		 * closing parenthesis.
1720 		 *
1721 		 * There's perhaps a more compact way to do this with
1722 		 * mid-rule actions in the grammar.
1723 		 *
1724 		 * I'm definitely not pleased with the complexity of
1725 		 * this code here.
1726 		 */
1727 		if (parser->newline_as_space)
1728 		{
1729 			if (ret == '(') {
1730 				parser->paren_count++;
1731 			} else if (ret == ')') {
1732 				parser->paren_count--;
1733 				if (parser->paren_count == 0)
1734 					parser->newline_as_space = 0;
1735 			} else if (ret == NEWLINE) {
1736 				ret = SPACE;
1737 			} else if (ret != SPACE) {
1738 				if (parser->paren_count == 0)
1739 					parser->newline_as_space = 0;
1740 			}
1741 		}
1742 		else if (parser->in_control_line)
1743 		{
1744 			if (ret == NEWLINE)
1745 				parser->in_control_line = 0;
1746 		}
1747 		else if (ret == HASH_DEFINE_OBJ || ret == HASH_DEFINE_FUNC ||
1748 			   ret == HASH_UNDEF || ret == HASH_IF ||
1749 			   ret == HASH_IFDEF || ret == HASH_IFNDEF ||
1750 			   ret == HASH_ELIF || ret == HASH_ELSE ||
1751 			   ret == HASH_ENDIF || ret == HASH)
1752 		{
1753 			parser->in_control_line = 1;
1754 		}
1755 		else if (ret == IDENTIFIER)
1756 		{
1757 			macro_t *macro;
1758 			macro = hash_table_find (parser->defines,
1759 						 yylval->str);
1760 			if (macro && macro->is_function) {
1761 				parser->newline_as_space = 1;
1762 				parser->paren_count = 0;
1763 			}
1764 		}
1765 
1766 		return ret;
1767 	}
1768 
1769 	node = parser->lex_from_node;
1770 
1771 	if (node == NULL) {
1772 		talloc_free (parser->lex_from_list);
1773 		parser->lex_from_list = NULL;
1774 		return NEWLINE;
1775 	}
1776 
1777 	*yylval = node->token->value;
1778 	ret = node->token->type;
1779 
1780 	parser->lex_from_node = node->next;
1781 
1782 	return ret;
1783 }
1784 
1785 static void
glcpp_parser_lex_from(glcpp_parser_t * parser,token_list_t * list)1786 glcpp_parser_lex_from (glcpp_parser_t *parser, token_list_t *list)
1787 {
1788 	token_node_t *node;
1789 
1790 	assert (parser->lex_from_list == NULL);
1791 
1792 	/* Copy list, eliminating any space tokens. */
1793 	parser->lex_from_list = _token_list_create (parser);
1794 
1795 	for (node = list->head; node; node = node->next) {
1796 		if (node->token->type == SPACE)
1797 			continue;
1798 		_token_list_append (parser->lex_from_list, node->token);
1799 	}
1800 
1801 	talloc_free (list);
1802 
1803 	parser->lex_from_node = parser->lex_from_list->head;
1804 
1805 	/* It's possible the list consisted of nothing but whitespace. */
1806 	if (parser->lex_from_node == NULL) {
1807 		talloc_free (parser->lex_from_list);
1808 		parser->lex_from_list = NULL;
1809 	}
1810 }
1811 
1812 static void
_glcpp_parser_skip_stack_push_if(glcpp_parser_t * parser,YYLTYPE * loc,int condition)1813 _glcpp_parser_skip_stack_push_if (glcpp_parser_t *parser, YYLTYPE *loc,
1814 				  int condition)
1815 {
1816 	skip_type_t current = SKIP_NO_SKIP;
1817 	skip_node_t *node;
1818 
1819 	if (parser->skip_stack)
1820 		current = parser->skip_stack->type;
1821 
1822 	node = talloc (parser, skip_node_t);
1823 	node->loc = *loc;
1824 
1825 	if (current == SKIP_NO_SKIP) {
1826 		if (condition)
1827 			node->type = SKIP_NO_SKIP;
1828 		else
1829 			node->type = SKIP_TO_ELSE;
1830 	} else {
1831 		node->type = SKIP_TO_ENDIF;
1832 	}
1833 
1834 	node->next = parser->skip_stack;
1835 	parser->skip_stack = node;
1836 }
1837 
1838 static void
_glcpp_parser_skip_stack_change_if(glcpp_parser_t * parser,YYLTYPE * loc,const char * type,int condition)1839 _glcpp_parser_skip_stack_change_if (glcpp_parser_t *parser, YYLTYPE *loc,
1840 				    const char *type, int condition)
1841 {
1842 	if (parser->skip_stack == NULL) {
1843 		glcpp_error (loc, parser, "%s without #if\n", type);
1844 		return;
1845 	}
1846 
1847 	if (parser->skip_stack->type == SKIP_TO_ELSE) {
1848 		if (condition)
1849 			parser->skip_stack->type = SKIP_NO_SKIP;
1850 	} else {
1851 		parser->skip_stack->type = SKIP_TO_ENDIF;
1852 	}
1853 }
1854 
1855 static void
_glcpp_parser_skip_stack_pop(glcpp_parser_t * parser,YYLTYPE * loc)1856 _glcpp_parser_skip_stack_pop (glcpp_parser_t *parser, YYLTYPE *loc)
1857 {
1858 	skip_node_t *node;
1859 
1860 	if (parser->skip_stack == NULL) {
1861 		glcpp_error (loc, parser, "#endif without #if\n");
1862 		return;
1863 	}
1864 
1865 	node = parser->skip_stack;
1866 	parser->skip_stack = node->next;
1867 	talloc_free (node);
1868 }
1869