Implement all operators specified for GLSL #if expressions (with tests).
[mesa.git] / glcpp-parse.y
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 <assert.h>
28
29 #include "glcpp.h"
30
31 void
32 yyerror (void *scanner, const char *error);
33
34 void
35 _define_object_macro (glcpp_parser_t *parser,
36 const char *macro,
37 token_list_t *replacements);
38
39 void
40 _define_function_macro (glcpp_parser_t *parser,
41 const char *macro,
42 string_list_t *parameters,
43 token_list_t *replacements);
44
45 void
46 _expand_object_macro (glcpp_parser_t *parser, const char *identifier);
47
48 void
49 _expand_function_macro (glcpp_parser_t *parser,
50 const char *identifier,
51 argument_list_t *arguments);
52
53 string_list_t *
54 _string_list_create (void *ctx);
55
56 void
57 _string_list_append_item (string_list_t *list, const char *str);
58
59 void
60 _string_list_append_list (string_list_t *list, string_list_t *tail);
61
62 int
63 _string_list_contains (string_list_t *list, const char *member, int *index);
64
65 int
66 _string_list_length (string_list_t *list);
67
68 argument_list_t *
69 _argument_list_create (void *ctx);
70
71 void
72 _argument_list_append (argument_list_t *list, token_list_t *argument);
73
74 int
75 _argument_list_length (argument_list_t *list);
76
77 token_list_t *
78 _argument_list_member_at (argument_list_t *list, int index);
79
80 token_list_t *
81 _token_list_create (void *ctx);
82
83 void
84 _token_list_append (token_list_t *list, int type, const char *value);
85
86 void
87 _token_list_append_list (token_list_t *list, token_list_t *tail);
88
89 static void
90 glcpp_parser_pop_expansion (glcpp_parser_t *parser);
91
92 static void
93 _glcpp_parser_skip_stack_push_if (glcpp_parser_t *parser, int condition);
94
95 static void
96 _glcpp_parser_skip_stack_change_if (glcpp_parser_t *parser, const char *type,
97 int condition);
98
99 static void
100 _glcpp_parser_skip_stack_pop (glcpp_parser_t *parser);
101
102 #define yylex glcpp_parser_lex
103
104 static int
105 glcpp_parser_lex (glcpp_parser_t *parser);
106
107 %}
108
109 %union {
110 int ival;
111 char *str;
112 argument_list_t *argument_list;
113 string_list_t *string_list;
114 token_t token;
115 token_list_t *token_list;
116 }
117
118 %parse-param {glcpp_parser_t *parser}
119 %lex-param {glcpp_parser_t *parser}
120
121 %token DEFINE DEFINED ELIF ELSE ENDIF FUNC_MACRO IDENTIFIER IDENTIFIER_FINALIZED IF IFDEF IFNDEF INTEGER OBJ_MACRO NEWLINE SPACE TOKEN UNDEF
122 %type <ival> expression INTEGER punctuator
123 %type <str> content FUNC_MACRO IDENTIFIER IDENTIFIER_FINALIZED OBJ_MACRO
124 %type <argument_list> argument_list
125 %type <string_list> macro parameter_list
126 %type <token> TOKEN argument_word argument_word_or_comma
127 %type <token_list> argument argument_or_comma replacement_list pp_tokens
128 %left OR
129 %left AND
130 %left '|'
131 %left '^'
132 %left '&'
133 %left EQUAL NOT_EQUAL
134 %left '<' '>' LESS_OR_EQUAL GREATER_OR_EQUAL
135 %left LEFT_SHIFT RIGHT_SHIFT
136 %left '+' '-'
137 %left '*' '/' '%'
138 %right UNARY
139
140 /* Hard to remove shift/reduce conflicts documented as follows:
141 *
142 * 1. '(' after FUNC_MACRO name which is correctly resolved to shift
143 * to form macro invocation rather than reducing directly to
144 * content.
145 *
146 * 2. Similarly, '(' after FUNC_MACRO which is correctly resolved to
147 * shift to form macro invocation rather than reducing directly to
148 * argument.
149 *
150 * 3. Similarly again now that we added argument_or_comma as well.
151 */
152 %expect 3
153
154 %%
155
156 /* We do all printing at the input level. */
157 input:
158 /* empty */ {
159 parser->just_printed_separator = 1;
160 }
161 | input content {
162 int is_token;
163 int skipping = 0;
164
165 if (parser->skip_stack && parser->skip_stack->type != SKIP_NO_SKIP)
166 skipping = 1;
167
168 if ($2 && strlen ($2) && ! skipping) {
169 int c = $2[0];
170 int is_not_separator = ((c >= 'a' && c <= 'z') ||
171 (c >= 'A' && c <= 'Z') ||
172 (c >= 'A' && c <= 'Z') ||
173 (c >= '0' && c <= '9') ||
174 (c == '_'));
175
176 if (! parser->just_printed_separator && is_not_separator)
177 {
178 printf (" ");
179 }
180 printf ("%s", $2);
181
182 if (is_not_separator)
183 parser->just_printed_separator = 0;
184 else
185 parser->just_printed_separator = 1;
186 }
187
188 if ($2)
189 talloc_free ($2);
190
191 if (parser->need_newline) {
192 printf ("\n");
193 parser->just_printed_separator = 1;
194 parser->need_newline = 0;
195 }
196 }
197 ;
198
199 content:
200 IDENTIFIER {
201 $$ = $1;
202 }
203 | IDENTIFIER_FINALIZED {
204 $$ = $1;
205 }
206 | TOKEN {
207 $$ = $1.value;
208 }
209 | FUNC_MACRO {
210 $$ = $1;
211 }
212 | directive {
213 $$ = talloc_strdup (parser, "\n");
214 }
215 | punctuator {
216 $$ = talloc_asprintf (parser, "%c", $1);
217 }
218 | macro {
219 $$ = NULL;
220 }
221 ;
222
223 punctuator:
224 '(' { $$ = '('; }
225 | ')' { $$ = ')'; }
226 | ',' { $$ = ','; }
227 ;
228
229 macro:
230 FUNC_MACRO '(' argument_list ')' {
231 _expand_function_macro (parser, $1, $3);
232 }
233 | OBJ_MACRO {
234 _expand_object_macro (parser, $1);
235 talloc_free ($1);
236 }
237 ;
238
239 argument_list:
240 /* empty */ {
241 $$ = _argument_list_create (parser);
242 }
243 | argument {
244 $$ = _argument_list_create (parser);
245 _argument_list_append ($$, $1);
246 }
247 | argument_list ',' argument {
248 _argument_list_append ($1, $3);
249 $$ = $1;
250 }
251 ;
252
253 argument:
254 argument_word {
255 $$ = _token_list_create (parser);
256 _token_list_append ($$, $1.type, $1.value);
257 }
258 | argument argument_word {
259 _token_list_append ($1, $2.type, $2.value);
260 talloc_free ($2.value);
261 $$ = $1;
262 }
263 | argument '(' argument_or_comma ')' {
264 _token_list_append ($1, '(', "(");
265 _token_list_append_list ($1, $3);
266 _token_list_append ($1, ')', ")");
267 $$ = $1;
268 }
269 ;
270
271 argument_word:
272 IDENTIFIER { $$.type = IDENTIFIER; $$.value = $1; }
273 | IDENTIFIER_FINALIZED { $$.type = IDENTIFIER_FINALIZED; $$.value = $1; }
274 | TOKEN { $$ = $1; }
275 | FUNC_MACRO { $$.type = FUNC_MACRO; $$.value = $1; }
276 | macro { $$.type = TOKEN; $$.value = xtalloc_strdup (parser, ""); }
277 ;
278
279 /* XXX: The body of argument_or_comma is the same as the body
280 * of argument, but with "argument" and "argument_word"
281 * changed to "argument_or_comma" and
282 * "argument_word_or_comma". It would be nice to have less
283 * redundancy here, but I'm not sure how.
284 *
285 * It would also be nice to have a less ugly grammar to have
286 * to implement, but such is the C preprocessor.
287 */
288 argument_or_comma:
289 argument_word_or_comma {
290 $$ = _token_list_create (parser);
291 _token_list_append ($$, $1.type, $1.value);
292 }
293 | argument_or_comma argument_word_or_comma {
294 _token_list_append ($1, $2.type, $2.value);
295 $$ = $1;
296 }
297 | argument_or_comma '(' argument_or_comma ')' {
298 _token_list_append ($1, '(', "(");
299 _token_list_append_list ($1, $3);
300 _token_list_append ($1, ')', ")");
301 $$ = $1;
302 }
303 ;
304
305 argument_word_or_comma:
306 IDENTIFIER { $$.type = IDENTIFIER; $$.value = $1; }
307 | IDENTIFIER_FINALIZED { $$.type = IDENTIFIER_FINALIZED; $$.value = $1; }
308 | TOKEN { $$ = $1; }
309 | FUNC_MACRO { $$.type = FUNC_MACRO; $$.value = $1; }
310 | macro { $$.type = TOKEN; $$.value = xtalloc_strdup (parser, ""); }
311 | ',' { $$.type = ','; $$.value = xtalloc_strdup (parser, ","); }
312 ;
313
314 directive:
315 DEFINE IDENTIFIER NEWLINE {
316 token_list_t *list = _token_list_create (parser);
317 _define_object_macro (parser, $2, list);
318 }
319 | DEFINE IDENTIFIER SPACE replacement_list NEWLINE {
320 _define_object_macro (parser, $2, $4);
321 }
322 | DEFINE IDENTIFIER '(' parameter_list ')' replacement_list NEWLINE {
323 _define_function_macro (parser, $2, $4, $6);
324 }
325 | IF expression NEWLINE {
326 _glcpp_parser_skip_stack_push_if (parser, $2);
327 }
328 | IFDEF IDENTIFIER NEWLINE {
329 string_list_t *macro = hash_table_find (parser->defines, $2);
330 talloc_free ($2);
331 _glcpp_parser_skip_stack_push_if (parser, macro != NULL);
332 }
333 | IFNDEF IDENTIFIER NEWLINE {
334 string_list_t *macro = hash_table_find (parser->defines, $2);
335 talloc_free ($2);
336 _glcpp_parser_skip_stack_push_if (parser, macro == NULL);
337 }
338 | ELIF expression NEWLINE {
339 _glcpp_parser_skip_stack_change_if (parser, "#elif", $2);
340 }
341 | ELSE {
342 _glcpp_parser_skip_stack_change_if (parser, "else", 1);
343 }
344 | ENDIF {
345 _glcpp_parser_skip_stack_pop (parser);
346 }
347 | UNDEF IDENTIFIER {
348 string_list_t *macro = hash_table_find (parser->defines, $2);
349 if (macro) {
350 /* XXX: Need hash table to support a real way
351 * to remove an element rather than prefixing
352 * a new node with data of NULL like this. */
353 hash_table_insert (parser->defines, NULL, $2);
354 talloc_free (macro);
355 }
356 talloc_free ($2);
357 }
358 ;
359
360 expression:
361 INTEGER {
362 $$ = $1;
363 }
364 | expression OR expression {
365 $$ = $1 || $3;
366 }
367 | expression AND expression {
368 $$ = $1 && $3;
369 }
370 | expression '|' expression {
371 $$ = $1 | $3;
372 }
373 | expression '^' expression {
374 $$ = $1 ^ $3;
375 }
376 | expression '&' expression {
377 $$ = $1 & $3;
378 }
379 | expression NOT_EQUAL expression {
380 $$ = $1 != $3;
381 }
382 | expression EQUAL expression {
383 $$ = $1 == $3;
384 }
385 | expression GREATER_OR_EQUAL expression {
386 $$ = $1 >= $3;
387 }
388 | expression LESS_OR_EQUAL expression {
389 $$ = $1 <= $3;
390 }
391 | expression '>' expression {
392 $$ = $1 > $3;
393 }
394 | expression '<' expression {
395 $$ = $1 < $3;
396 }
397 | expression RIGHT_SHIFT expression {
398 $$ = $1 >> $3;
399 }
400 | expression LEFT_SHIFT expression {
401 $$ = $1 << $3;
402 }
403 | expression '-' expression {
404 $$ = $1 - $3;
405 }
406 | expression '+' expression {
407 $$ = $1 + $3;
408 }
409 | expression '%' expression {
410 $$ = $1 % $3;
411 }
412 | expression '/' expression {
413 $$ = $1 / $3;
414 }
415 | expression '*' expression {
416 $$ = $1 * $3;
417 }
418 | '!' expression %prec UNARY {
419 $$ = ! $2;
420 }
421 | '~' expression %prec UNARY {
422 $$ = ~ $2;
423 }
424 | '-' expression %prec UNARY {
425 $$ = - $2;
426 }
427 | '+' expression %prec UNARY {
428 $$ = + $2;
429 }
430 | DEFINED IDENTIFIER %prec UNARY {
431 string_list_t *macro = hash_table_find (parser->defines, $2);
432 talloc_free ($2);
433 if (macro)
434 $$ = 1;
435 else
436 $$ = 0;
437 }
438 | '(' expression ')' {
439 $$ = $2;
440 }
441 ;
442
443 parameter_list:
444 /* empty */ {
445 $$ = _string_list_create (parser);
446 }
447 | IDENTIFIER {
448 $$ = _string_list_create (parser);
449 _string_list_append_item ($$, $1);
450 talloc_free ($1);
451 }
452 | parameter_list ',' IDENTIFIER {
453 _string_list_append_item ($1, $3);
454 talloc_free ($3);
455 $$ = $1;
456 }
457 ;
458
459 replacement_list:
460 /* empty */ {
461 $$ = _token_list_create (parser);
462 }
463 | pp_tokens {
464 $$ = $1;
465 }
466 ;
467
468
469 pp_tokens:
470 TOKEN {
471 $$ = _token_list_create (parser);
472 _token_list_append ($$, $1.type, $1.value);
473 }
474 | pp_tokens TOKEN {
475 _token_list_append ($1, $2.type, $2.value);
476 $$ = $1;
477 }
478 ;
479
480 %%
481
482 string_list_t *
483 _string_list_create (void *ctx)
484 {
485 string_list_t *list;
486
487 list = xtalloc (ctx, string_list_t);
488 list->head = NULL;
489 list->tail = NULL;
490
491 return list;
492 }
493
494 void
495 _string_list_append_list (string_list_t *list, string_list_t *tail)
496 {
497 if (list->head == NULL) {
498 list->head = tail->head;
499 } else {
500 list->tail->next = tail->head;
501 }
502
503 list->tail = tail->tail;
504 }
505
506 void
507 _string_list_append_item (string_list_t *list, const char *str)
508 {
509 string_node_t *node;
510
511 node = xtalloc (list, string_node_t);
512 node->str = xtalloc_strdup (node, str);
513
514 node->next = NULL;
515
516 if (list->head == NULL) {
517 list->head = node;
518 } else {
519 list->tail->next = node;
520 }
521
522 list->tail = node;
523 }
524
525 int
526 _string_list_contains (string_list_t *list, const char *member, int *index)
527 {
528 string_node_t *node;
529 int i;
530
531 if (list == NULL)
532 return 0;
533
534 for (i = 0, node = list->head; node; i++, node = node->next) {
535 if (strcmp (node->str, member) == 0) {
536 if (index)
537 *index = i;
538 return 1;
539 }
540 }
541
542 return 0;
543 }
544
545 int
546 _string_list_length (string_list_t *list)
547 {
548 int length = 0;
549 string_node_t *node;
550
551 if (list == NULL)
552 return 0;
553
554 for (node = list->head; node; node = node->next)
555 length++;
556
557 return length;
558 }
559
560 argument_list_t *
561 _argument_list_create (void *ctx)
562 {
563 argument_list_t *list;
564
565 list = xtalloc (ctx, argument_list_t);
566 list->head = NULL;
567 list->tail = NULL;
568
569 return list;
570 }
571
572 void
573 _argument_list_append (argument_list_t *list, token_list_t *argument)
574 {
575 argument_node_t *node;
576
577 if (argument == NULL || argument->head == NULL)
578 return;
579
580 node = xtalloc (list, argument_node_t);
581 node->argument = argument;
582
583 node->next = NULL;
584
585 if (list->head == NULL) {
586 list->head = node;
587 } else {
588 list->tail->next = node;
589 }
590
591 list->tail = node;
592 }
593
594 int
595 _argument_list_length (argument_list_t *list)
596 {
597 int length = 0;
598 argument_node_t *node;
599
600 if (list == NULL)
601 return 0;
602
603 for (node = list->head; node; node = node->next)
604 length++;
605
606 return length;
607 }
608
609 token_list_t *
610 _argument_list_member_at (argument_list_t *list, int index)
611 {
612 argument_node_t *node;
613 int i;
614
615 if (list == NULL)
616 return NULL;
617
618 node = list->head;
619 for (i = 0; i < index; i++) {
620 node = node->next;
621 if (node == NULL)
622 break;
623 }
624
625 if (node)
626 return node->argument;
627
628 return NULL;
629 }
630
631 token_list_t *
632 _token_list_create (void *ctx)
633 {
634 token_list_t *list;
635
636 list = xtalloc (ctx, token_list_t);
637 list->head = NULL;
638 list->tail = NULL;
639
640 return list;
641 }
642
643 void
644 _token_list_append (token_list_t *list, int type, const char *value)
645 {
646 token_node_t *node;
647
648 node = xtalloc (list, token_node_t);
649 node->type = type;
650 node->value = xtalloc_strdup (list, value);
651
652 node->next = NULL;
653
654 if (list->head == NULL) {
655 list->head = node;
656 } else {
657 list->tail->next = node;
658 }
659
660 list->tail = node;
661 }
662
663 void
664 _token_list_append_list (token_list_t *list, token_list_t *tail)
665 {
666 if (list->head == NULL) {
667 list->head = tail->head;
668 } else {
669 list->tail->next = tail->head;
670 }
671
672 list->tail = tail->tail;
673 }
674
675 void
676 yyerror (void *scanner, const char *error)
677 {
678 fprintf (stderr, "Parse error: %s\n", error);
679 }
680
681 glcpp_parser_t *
682 glcpp_parser_create (void)
683 {
684 glcpp_parser_t *parser;
685
686 parser = xtalloc (NULL, glcpp_parser_t);
687
688 glcpp_lex_init_extra (parser, &parser->scanner);
689 parser->defines = hash_table_ctor (32, hash_table_string_hash,
690 hash_table_string_compare);
691 parser->expansions = NULL;
692
693 parser->just_printed_separator = 1;
694 parser->need_newline = 0;
695
696 parser->skip_stack = NULL;
697
698 return parser;
699 }
700
701 int
702 glcpp_parser_parse (glcpp_parser_t *parser)
703 {
704 return yyparse (parser);
705 }
706
707 void
708 glcpp_parser_destroy (glcpp_parser_t *parser)
709 {
710 if (parser->need_newline)
711 printf ("\n");
712 if (parser->skip_stack)
713 fprintf (stderr, "Error: Unterminated #if\n");
714 glcpp_lex_destroy (parser->scanner);
715 hash_table_dtor (parser->defines);
716 talloc_free (parser);
717 }
718
719 static int
720 glcpp_parser_is_expanding (glcpp_parser_t *parser, const char *member)
721 {
722 expansion_node_t *node;
723
724 for (node = parser->expansions; node; node = node->next) {
725 if (node->macro &&
726 strcmp (node->macro->identifier, member) == 0)
727 {
728 return 1;
729 }
730 }
731
732 return 0;
733 }
734
735 token_class_t
736 glcpp_parser_classify_token (glcpp_parser_t *parser,
737 const char *identifier,
738 int *parameter_index)
739 {
740 macro_t *macro;
741
742 /* Is this token a defined macro? */
743 macro = hash_table_find (parser->defines, identifier);
744
745 if (macro == NULL)
746 return TOKEN_CLASS_IDENTIFIER;
747
748 /* Don't consider this a macro if we are already actively
749 * expanding this macro. */
750 if (glcpp_parser_is_expanding (parser, identifier))
751 return TOKEN_CLASS_IDENTIFIER_FINALIZED;
752
753 /* Definitely a macro. Just need to check if it's function-like. */
754 if (macro->is_function)
755 return TOKEN_CLASS_FUNC_MACRO;
756 else
757 return TOKEN_CLASS_OBJ_MACRO;
758 }
759
760 void
761 _define_object_macro (glcpp_parser_t *parser,
762 const char *identifier,
763 token_list_t *replacements)
764 {
765 macro_t *macro;
766
767 macro = xtalloc (parser, macro_t);
768
769 macro->is_function = 0;
770 macro->parameters = NULL;
771 macro->identifier = talloc_strdup (macro, identifier);
772 macro->replacements = talloc_steal (macro, replacements);
773
774 hash_table_insert (parser->defines, macro, identifier);
775 }
776
777 void
778 _define_function_macro (glcpp_parser_t *parser,
779 const char *identifier,
780 string_list_t *parameters,
781 token_list_t *replacements)
782 {
783 macro_t *macro;
784
785 macro = xtalloc (parser, macro_t);
786
787 macro->is_function = 1;
788 macro->parameters = talloc_steal (macro, parameters);
789 macro->identifier = talloc_strdup (macro, identifier);
790 macro->replacements = talloc_steal (macro, replacements);
791
792 hash_table_insert (parser->defines, macro, identifier);
793 }
794
795 static void
796 _glcpp_parser_push_expansion (glcpp_parser_t *parser,
797 macro_t *macro,
798 token_node_t *replacements)
799 {
800 expansion_node_t *node;
801
802 node = xtalloc (parser, expansion_node_t);
803
804 node->macro = macro;
805 node->replacements = replacements;
806
807 node->next = parser->expansions;
808 parser->expansions = node;
809 }
810
811 static void
812 glcpp_parser_pop_expansion (glcpp_parser_t *parser)
813 {
814 expansion_node_t *node;
815
816 node = parser->expansions;
817
818 if (node == NULL) {
819 fprintf (stderr, "Internal error: _expansion_list_pop called on an empty list.\n");
820 exit (1);
821 }
822
823 parser->expansions = node->next;
824
825 talloc_free (node);
826 }
827
828 void
829 _expand_object_macro (glcpp_parser_t *parser, const char *identifier)
830 {
831 macro_t *macro;
832
833 macro = hash_table_find (parser->defines, identifier);
834 assert (! macro->is_function);
835 assert (! glcpp_parser_is_expanding (parser, identifier));
836
837 _glcpp_parser_push_expansion (parser, macro, macro->replacements->head);
838 }
839
840 void
841 _expand_function_macro (glcpp_parser_t *parser,
842 const char *identifier,
843 argument_list_t *arguments)
844 {
845 macro_t *macro;
846 token_list_t *expanded;
847 token_node_t *i, *j;
848 int parameter_index;
849
850 macro = hash_table_find (parser->defines, identifier);
851 assert (macro->is_function);
852 assert (! glcpp_parser_is_expanding (parser, identifier));
853
854 if (_argument_list_length (arguments) !=
855 _string_list_length (macro->parameters))
856 {
857 fprintf (stderr,
858 "Error: macro %s invoked with %d arguments (expected %d)\n",
859 identifier,
860 _argument_list_length (arguments),
861 _string_list_length (macro->parameters));
862 return;
863 }
864
865 expanded = _token_list_create (macro);
866
867 for (i = macro->replacements->head; i; i = i->next) {
868 if (_string_list_contains (macro->parameters, i->value,
869 &parameter_index))
870 {
871 token_list_t *argument;
872 argument = _argument_list_member_at (arguments,
873 parameter_index);
874 for (j = argument->head; j; j = j->next)
875 {
876 _token_list_append (expanded, j->type,
877 j->value);
878 }
879 } else {
880 _token_list_append (expanded, i->type, i->value);
881 }
882 }
883
884 _glcpp_parser_push_expansion (parser, macro, expanded->head);
885 }
886
887 static int
888 glcpp_parser_lex (glcpp_parser_t *parser)
889 {
890 expansion_node_t *expansion;
891 token_node_t *replacements;
892 int parameter_index;
893 const char *token;
894 token_class_t class;
895
896 /* Who says C can't do efficient tail recursion? */
897 RECURSE:
898
899 expansion = parser->expansions;
900
901 if (expansion == NULL)
902 return glcpp_lex (parser->scanner);
903
904 replacements = expansion->replacements;
905
906 /* Pop expansion when replacements is exhausted. */
907 if (replacements == NULL) {
908 glcpp_parser_pop_expansion (parser);
909 goto RECURSE;
910 }
911
912 expansion->replacements = replacements->next;
913
914 token = replacements->value;
915
916 /* Implement token pasting. */
917 if (replacements->next && strcmp (replacements->next->value, "##") == 0) {
918 token_node_t *next_node;
919
920 next_node = replacements->next->next;
921
922 if (next_node == NULL) {
923 fprintf (stderr, "Error: '##' cannot appear at the end of a macro expansion.\n");
924 exit (1);
925 }
926
927 token = xtalloc_asprintf (parser, "%s%s",
928 token, next_node->value);
929 expansion->replacements = next_node->next;
930 }
931
932
933 if (strcmp (token, "(") == 0)
934 return '(';
935 else if (strcmp (token, ")") == 0)
936 return ')';
937
938 yylval.str = xtalloc_strdup (parser, token);
939
940 /* Carefully refuse to expand any finalized identifier. */
941 if (replacements->type == IDENTIFIER_FINALIZED)
942 return IDENTIFIER_FINALIZED;
943
944 switch (glcpp_parser_classify_token (parser, yylval.str,
945 &parameter_index))
946 {
947 case TOKEN_CLASS_IDENTIFIER:
948 return IDENTIFIER;
949 break;
950 case TOKEN_CLASS_IDENTIFIER_FINALIZED:
951 return IDENTIFIER_FINALIZED;
952 break;
953 case TOKEN_CLASS_FUNC_MACRO:
954 return FUNC_MACRO;
955 break;
956 default:
957 case TOKEN_CLASS_OBJ_MACRO:
958 return OBJ_MACRO;
959 break;
960 }
961 }
962
963 static void
964 _glcpp_parser_skip_stack_push_if (glcpp_parser_t *parser, int condition)
965 {
966 skip_type_t current = SKIP_NO_SKIP;
967 skip_node_t *node;
968
969 if (parser->skip_stack)
970 current = parser->skip_stack->type;
971
972 node = xtalloc (parser, skip_node_t);
973
974 if (current == SKIP_NO_SKIP) {
975 if (condition)
976 node->type = SKIP_NO_SKIP;
977 else
978 node->type = SKIP_TO_ELSE;
979 } else {
980 node->type = SKIP_TO_ENDIF;
981 }
982
983 node->next = parser->skip_stack;
984 parser->skip_stack = node;
985 }
986
987 static void
988 _glcpp_parser_skip_stack_change_if (glcpp_parser_t *parser, const char *type,
989 int condition)
990 {
991 if (parser->skip_stack == NULL) {
992 fprintf (stderr, "Error: %s without #if\n", type);
993 exit (1);
994 }
995
996 if (parser->skip_stack->type == SKIP_TO_ELSE) {
997 if (condition)
998 parser->skip_stack->type = SKIP_NO_SKIP;
999 } else {
1000 parser->skip_stack->type = SKIP_TO_ENDIF;
1001 }
1002 }
1003
1004 static void
1005 _glcpp_parser_skip_stack_pop (glcpp_parser_t *parser)
1006 {
1007 skip_node_t *node;
1008
1009 if (parser->skip_stack == NULL) {
1010 fprintf (stderr, "Error: #endif without #if\n");
1011 exit (1);
1012 }
1013
1014 node = parser->skip_stack;
1015 parser->skip_stack = node->next;
1016 talloc_free (node);
1017 }