blob: 830a6232d80294295f9a6a5a495a545ef74d2e51 [file] [log] [blame]
Carl Worth3a37b872010-05-10 11:44:09 -07001%{
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>
Carl Worthfcbbb462010-05-13 09:36:23 -070027#include <assert.h>
Carl Worth3a37b872010-05-10 11:44:09 -070028
Carl Wortha1e32bc2010-05-10 13:17:25 -070029#include "glcpp.h"
30
Carl Worth3a37b872010-05-10 11:44:09 -070031void
Carl Wortha1e32bc2010-05-10 13:17:25 -070032yyerror (void *scanner, const char *error);
Carl Worth3a37b872010-05-10 11:44:09 -070033
Carl Worth33cc4002010-05-12 12:17:10 -070034void
Carl Worthfcbbb462010-05-13 09:36:23 -070035_define_object_macro (glcpp_parser_t *parser,
36 const char *macro,
Carl Worth47252442010-05-19 13:54:37 -070037 token_list_t *replacements);
Carl Worthfcbbb462010-05-13 09:36:23 -070038
39void
40_define_function_macro (glcpp_parser_t *parser,
41 const char *macro,
Carl Worthc5e98552010-05-14 10:12:21 -070042 string_list_t *parameters,
Carl Worth47252442010-05-19 13:54:37 -070043 token_list_t *replacements);
Carl Worthfcbbb462010-05-13 09:36:23 -070044
Carl Wortha807fb72010-05-18 22:10:04 -070045void
Carl Worth2be8be02010-05-14 10:31:43 -070046_expand_object_macro (glcpp_parser_t *parser, const char *identifier);
47
Carl Wortha807fb72010-05-18 22:10:04 -070048void
Carl Worth2be8be02010-05-14 10:31:43 -070049_expand_function_macro (glcpp_parser_t *parser,
50 const char *identifier,
Carl Worth8f6a8282010-05-14 10:44:19 -070051 argument_list_t *arguments);
Carl Worthfcbbb462010-05-13 09:36:23 -070052
Carl Worth610053b2010-05-14 10:05:11 -070053string_list_t *
54_string_list_create (void *ctx);
Carl Worth33cc4002010-05-12 12:17:10 -070055
56void
Carl Worth610053b2010-05-14 10:05:11 -070057_string_list_append_item (string_list_t *list, const char *str);
Carl Worthfcbbb462010-05-13 09:36:23 -070058
59void
Carl Worth610053b2010-05-14 10:05:11 -070060_string_list_append_list (string_list_t *list, string_list_t *tail);
Carl Worthc6d5af32010-05-11 12:30:09 -070061
Carl Worthae6517f2010-05-25 15:24:59 -070062void
63_string_list_push (string_list_t *list, const char *str);
64
65void
66_string_list_pop (string_list_t *list);
67
Carl Worthdcc2ecd2010-05-13 12:56:42 -070068int
Carl Worth610053b2010-05-14 10:05:11 -070069_string_list_contains (string_list_t *list, const char *member, int *index);
Carl Worthdcc2ecd2010-05-13 12:56:42 -070070
Carl Worthdcc2ecd2010-05-13 12:56:42 -070071int
Carl Worth610053b2010-05-14 10:05:11 -070072_string_list_length (string_list_t *list);
Carl Worthdcc2ecd2010-05-13 12:56:42 -070073
Carl Worth8f6a8282010-05-14 10:44:19 -070074argument_list_t *
75_argument_list_create (void *ctx);
76
77void
Carl Worth47252442010-05-19 13:54:37 -070078_argument_list_append (argument_list_t *list, token_list_t *argument);
Carl Worth8f6a8282010-05-14 10:44:19 -070079
80int
81_argument_list_length (argument_list_t *list);
82
Carl Worth47252442010-05-19 13:54:37 -070083token_list_t *
Carl Worth8f6a8282010-05-14 10:44:19 -070084_argument_list_member_at (argument_list_t *list, int index);
85
Carl Worth808401f2010-05-25 14:52:43 -070086/* Note: This function talloc_steal()s the str pointer. */
87token_t *
88_token_create_str (void *ctx, int type, char *str);
89
90token_t *
91_token_create_ival (void *ctx, int type, int ival);
92
Carl Worth47252442010-05-19 13:54:37 -070093token_list_t *
94_token_list_create (void *ctx);
95
Carl Worth808401f2010-05-25 14:52:43 -070096/* Note: This function add a talloc_reference() to token.
97 *
98 * You may want to talloc_unlink any current reference if you no
99 * longer need it. */
Carl Worth47252442010-05-19 13:54:37 -0700100void
Carl Worth808401f2010-05-25 14:52:43 -0700101_token_list_append (token_list_t *list, token_t *token);
Carl Worth47252442010-05-19 13:54:37 -0700102
103void
104_token_list_append_list (token_list_t *list, token_list_t *tail);
105
Carl Worth808401f2010-05-25 14:52:43 -0700106void
Carl Worthae6517f2010-05-25 15:24:59 -0700107_glcpp_parser_print_expanded_token_list (glcpp_parser_t *parser,
108 token_list_t *list);
Carl Worth808401f2010-05-25 14:52:43 -0700109
Carl Worthaaa9acb2010-05-19 13:28:24 -0700110static void
Carl Worthaaa9acb2010-05-19 13:28:24 -0700111glcpp_parser_pop_expansion (glcpp_parser_t *parser);
112
Carl Worthb20d33c2010-05-20 22:27:07 -0700113static void
114_glcpp_parser_skip_stack_push_if (glcpp_parser_t *parser, int condition);
115
116static void
117_glcpp_parser_skip_stack_change_if (glcpp_parser_t *parser, const char *type,
118 int condition);
Carl Worth80dc60b2010-05-25 14:42:00 -0700119
Carl Worthb20d33c2010-05-20 22:27:07 -0700120static void
121_glcpp_parser_skip_stack_pop (glcpp_parser_t *parser);
122
Carl Worth0293b2e2010-05-19 10:05:40 -0700123#define yylex glcpp_parser_lex
124
Carl Worth8f38aff2010-05-19 10:01:29 -0700125static int
Carl Worth0293b2e2010-05-19 10:05:40 -0700126glcpp_parser_lex (glcpp_parser_t *parser);
Carl Worth8f38aff2010-05-19 10:01:29 -0700127
Carl Worth3a37b872010-05-10 11:44:09 -0700128%}
129
Carl Worth33cc4002010-05-12 12:17:10 -0700130%union {
Carl Worth005b3202010-05-20 14:19:57 -0700131 int ival;
Carl Worth33cc4002010-05-12 12:17:10 -0700132 char *str;
Carl Worth808401f2010-05-25 14:52:43 -0700133 token_t *token;
Carl Worth47252442010-05-19 13:54:37 -0700134 token_list_t *token_list;
Carl Worth33cc4002010-05-12 12:17:10 -0700135}
136
Carl Worth0b27b5f2010-05-10 16:16:06 -0700137%parse-param {glcpp_parser_t *parser}
Carl Worth0293b2e2010-05-19 10:05:40 -0700138%lex-param {glcpp_parser_t *parser}
Carl Worth38aa8352010-05-10 11:52:29 -0700139
Carl Worth3ff81672010-05-25 13:09:03 -0700140%token HASH_DEFINE_FUNC HASH_DEFINE_OBJ HASH IDENTIFIER NEWLINE OTHER HASH_UNDEF
141%token LEFT_SHIFT RIGHT_SHIFT LESS_OR_EQUAL GREATER_OR_EQUAL EQUAL NOT_EQUAL AND OR PASTE
Carl Worth808401f2010-05-25 14:52:43 -0700142%type <ival> punctuator
143%type <str> IDENTIFIER OTHER
144%type <token> preprocessing_token
145%type <token_list> pp_tokens replacement_list text_line
Carl Worth3a37b872010-05-10 11:44:09 -0700146
Carl Worth3ff81672010-05-25 13:09:03 -0700147 /* Stale stuff just to allow code to compile. */
148%token IDENTIFIER_FINALIZED FUNC_MACRO OBJ_MACRO
Carl Worth796e1f02010-05-17 12:45:16 -0700149
Carl Worth3a37b872010-05-10 11:44:09 -0700150%%
151
Carl Worth33cc4002010-05-12 12:17:10 -0700152input:
Carl Worth3ff81672010-05-25 13:09:03 -0700153 /* empty */
Carl Worthae6517f2010-05-25 15:24:59 -0700154| input line {
155 printf ("\n");
156 }
Carl Worth3a37b872010-05-10 11:44:09 -0700157;
158
Carl Worth3ff81672010-05-25 13:09:03 -0700159line:
160 control_line
Carl Worth808401f2010-05-25 14:52:43 -0700161| text_line {
Carl Worthae6517f2010-05-25 15:24:59 -0700162 _glcpp_parser_print_expanded_token_list (parser, $1);
Carl Worth808401f2010-05-25 14:52:43 -0700163 talloc_free ($1);
164 }
Carl Worth3ff81672010-05-25 13:09:03 -0700165| HASH non_directive
Carl Worthcd27e642010-05-12 13:11:50 -0700166;
167
Carl Worth3ff81672010-05-25 13:09:03 -0700168control_line:
Carl Worthae6517f2010-05-25 15:24:59 -0700169 HASH_DEFINE_OBJ IDENTIFIER replacement_list NEWLINE {
170 _define_object_macro (parser, $2, $3);
171 }
Carl Worth3ff81672010-05-25 13:09:03 -0700172| HASH_DEFINE_FUNC IDENTIFIER '(' ')' replacement_list NEWLINE
173| HASH_DEFINE_FUNC IDENTIFIER '(' identifier_list ')' replacement_list NEWLINE
Carl Worthe6fb7822010-05-25 15:28:58 -0700174| HASH_UNDEF IDENTIFIER NEWLINE {
175 string_list_t *macro = hash_table_find (parser->defines, $2);
176 if (macro) {
177 /* XXX: Need hash table to support a real way
178 * to remove an element rather than prefixing
179 * a new node with data of NULL like this. */
180 hash_table_insert (parser->defines, NULL, $2);
181 talloc_free (macro);
182 }
183 talloc_free ($2);
184 }
Carl Worth3ff81672010-05-25 13:09:03 -0700185| HASH NEWLINE
Carl Worthfcbbb462010-05-13 09:36:23 -0700186;
187
Carl Worth3ff81672010-05-25 13:09:03 -0700188identifier_list:
189 IDENTIFIER
190| identifier_list ',' IDENTIFIER
Carl Worthfcbbb462010-05-13 09:36:23 -0700191;
192
Carl Worth3ff81672010-05-25 13:09:03 -0700193text_line:
Carl Worth808401f2010-05-25 14:52:43 -0700194 NEWLINE { $$ = NULL; }
Carl Worth3ff81672010-05-25 13:09:03 -0700195| pp_tokens NEWLINE
Carl Worthfcbbb462010-05-13 09:36:23 -0700196;
197
Carl Worth3ff81672010-05-25 13:09:03 -0700198non_directive:
199 pp_tokens NEWLINE
Carl Worthfcbbb462010-05-13 09:36:23 -0700200;
201
Carl Worthaaa9acb2010-05-19 13:28:24 -0700202replacement_list:
Carl Worth808401f2010-05-25 14:52:43 -0700203 /* empty */ { $$ = NULL; }
Carl Worth3ff81672010-05-25 13:09:03 -0700204| pp_tokens
Carl Worthaaa9acb2010-05-19 13:28:24 -0700205;
206
Carl Worthaaa9acb2010-05-19 13:28:24 -0700207pp_tokens:
Carl Worth808401f2010-05-25 14:52:43 -0700208 preprocessing_token {
209 $$ = _token_list_create (parser);
210 _token_list_append ($$, $1);
211 talloc_unlink (parser, $1);
212 }
213| pp_tokens preprocessing_token {
214 $$ = $1;
215 _token_list_append ($$, $2);
216 talloc_unlink (parser, $2);
217 }
Carl Worthaaa9acb2010-05-19 13:28:24 -0700218;
219
Carl Worth3ff81672010-05-25 13:09:03 -0700220preprocessing_token:
Carl Worth808401f2010-05-25 14:52:43 -0700221 IDENTIFIER {
222 $$ = _token_create_str (parser, IDENTIFIER, $1);
223 }
224| punctuator {
225 $$ = _token_create_ival (parser, $1, $1);
226 }
227| OTHER {
228 $$ = _token_create_str (parser, OTHER, $1);
229 }
Carl Worth3ff81672010-05-25 13:09:03 -0700230;
231
232punctuator:
Carl Worth808401f2010-05-25 14:52:43 -0700233 '[' { $$ = '['; }
234| ']' { $$ = ']'; }
235| '(' { $$ = '('; }
236| ')' { $$ = ')'; }
237| '{' { $$ = '{'; }
238| '}' { $$ = '}'; }
239| '.' { $$ = '.'; }
240| '&' { $$ = '&'; }
241| '*' { $$ = '*'; }
242| '+' { $$ = '+'; }
243| '-' { $$ = '-'; }
244| '~' { $$ = '~'; }
245| '!' { $$ = '!'; }
246| '/' { $$ = '/'; }
247| '%' { $$ = '%'; }
248| LEFT_SHIFT { $$ = LEFT_SHIFT; }
249| RIGHT_SHIFT { $$ = RIGHT_SHIFT; }
250| '<' { $$ = '<'; }
251| '>' { $$ = '>'; }
252| LESS_OR_EQUAL { $$ = LESS_OR_EQUAL; }
253| GREATER_OR_EQUAL { $$ = GREATER_OR_EQUAL; }
254| EQUAL { $$ = EQUAL; }
255| NOT_EQUAL { $$ = NOT_EQUAL; }
256| '^' { $$ = '^'; }
257| '|' { $$ = '|'; }
258| AND { $$ = AND; }
259| OR { $$ = OR; }
260| ';' { $$ = ';'; }
261| ',' { $$ = ','; }
262| PASTE { $$ = PASTE; }
Carl Worth3ff81672010-05-25 13:09:03 -0700263;
264
Carl Worth33cc4002010-05-12 12:17:10 -0700265%%
266
Carl Worth610053b2010-05-14 10:05:11 -0700267string_list_t *
268_string_list_create (void *ctx)
Carl Worth33cc4002010-05-12 12:17:10 -0700269{
Carl Worth610053b2010-05-14 10:05:11 -0700270 string_list_t *list;
Carl Worth33cc4002010-05-12 12:17:10 -0700271
Carl Worth610053b2010-05-14 10:05:11 -0700272 list = xtalloc (ctx, string_list_t);
Carl Worth33cc4002010-05-12 12:17:10 -0700273 list->head = NULL;
274 list->tail = NULL;
275
276 return list;
Carl Worth0b27b5f2010-05-10 16:16:06 -0700277}
Carl Worth0b27b5f2010-05-10 16:16:06 -0700278
Carl Worth33cc4002010-05-12 12:17:10 -0700279void
Carl Worth610053b2010-05-14 10:05:11 -0700280_string_list_append_list (string_list_t *list, string_list_t *tail)
Carl Worthfcbbb462010-05-13 09:36:23 -0700281{
282 if (list->head == NULL) {
283 list->head = tail->head;
284 } else {
285 list->tail->next = tail->head;
286 }
287
288 list->tail = tail->tail;
289}
290
291void
Carl Worth610053b2010-05-14 10:05:11 -0700292_string_list_append_item (string_list_t *list, const char *str)
Carl Worth33cc4002010-05-12 12:17:10 -0700293{
Carl Worth610053b2010-05-14 10:05:11 -0700294 string_node_t *node;
Carl Worth3a37b872010-05-10 11:44:09 -0700295
Carl Worth610053b2010-05-14 10:05:11 -0700296 node = xtalloc (list, string_node_t);
Carl Worth5070a202010-05-12 12:45:33 -0700297 node->str = xtalloc_strdup (node, str);
Carl Worth80dc60b2010-05-25 14:42:00 -0700298
Carl Worth33cc4002010-05-12 12:17:10 -0700299 node->next = NULL;
300
301 if (list->head == NULL) {
302 list->head = node;
303 } else {
304 list->tail->next = node;
305 }
306
307 list->tail = node;
308}
Carl Worthdcc2ecd2010-05-13 12:56:42 -0700309
Carl Worthae6517f2010-05-25 15:24:59 -0700310void
311_string_list_push (string_list_t *list, const char *str)
312{
313 string_node_t *node;
314
315 node = xtalloc (list, string_node_t);
316 node->str = xtalloc_strdup (node, str);
317 node->next = list->head;
318
319 if (list->tail == NULL) {
320 list->tail = node;
321 }
322 list->head = node;
323}
324
325void
326_string_list_pop (string_list_t *list)
327{
328 string_node_t *node;
329
330 node = list->head;
331
332 if (node == NULL) {
333 fprintf (stderr, "Internal error: _string_list_pop called on an empty list.\n");
334 exit (1);
335 }
336
337 list->head = node->next;
338 if (list->tail == node) {
339 assert (node->next == NULL);
340 list->tail = NULL;
341 }
342
343 talloc_free (node);
344}
345
Carl Worthdcc2ecd2010-05-13 12:56:42 -0700346int
Carl Worth610053b2010-05-14 10:05:11 -0700347_string_list_contains (string_list_t *list, const char *member, int *index)
Carl Worthdcc2ecd2010-05-13 12:56:42 -0700348{
Carl Worth610053b2010-05-14 10:05:11 -0700349 string_node_t *node;
Carl Worthdcc2ecd2010-05-13 12:56:42 -0700350 int i;
351
352 if (list == NULL)
353 return 0;
354
355 for (i = 0, node = list->head; node; i++, node = node->next) {
356 if (strcmp (node->str, member) == 0) {
Carl Worth420d05a2010-05-17 10:15:23 -0700357 if (index)
358 *index = i;
Carl Worthdcc2ecd2010-05-13 12:56:42 -0700359 return 1;
360 }
361 }
362
363 return 0;
364}
365
366int
Carl Worth610053b2010-05-14 10:05:11 -0700367_string_list_length (string_list_t *list)
Carl Worthdcc2ecd2010-05-13 12:56:42 -0700368{
369 int length = 0;
Carl Worth610053b2010-05-14 10:05:11 -0700370 string_node_t *node;
Carl Worthdcc2ecd2010-05-13 12:56:42 -0700371
372 if (list == NULL)
373 return 0;
374
375 for (node = list->head; node; node = node->next)
376 length++;
377
378 return length;
379}
380
Carl Worth8f6a8282010-05-14 10:44:19 -0700381argument_list_t *
382_argument_list_create (void *ctx)
Carl Worthdcc2ecd2010-05-13 12:56:42 -0700383{
Carl Worth8f6a8282010-05-14 10:44:19 -0700384 argument_list_t *list;
385
386 list = xtalloc (ctx, argument_list_t);
387 list->head = NULL;
388 list->tail = NULL;
389
390 return list;
391}
392
393void
Carl Worth47252442010-05-19 13:54:37 -0700394_argument_list_append (argument_list_t *list, token_list_t *argument)
Carl Worth8f6a8282010-05-14 10:44:19 -0700395{
396 argument_node_t *node;
397
398 if (argument == NULL || argument->head == NULL)
399 return;
400
401 node = xtalloc (list, argument_node_t);
402 node->argument = argument;
403
404 node->next = NULL;
405
406 if (list->head == NULL) {
407 list->head = node;
408 } else {
409 list->tail->next = node;
410 }
411
412 list->tail = node;
413}
414
415int
416_argument_list_length (argument_list_t *list)
417{
418 int length = 0;
419 argument_node_t *node;
420
421 if (list == NULL)
422 return 0;
423
424 for (node = list->head; node; node = node->next)
425 length++;
426
427 return length;
428}
429
Carl Worth47252442010-05-19 13:54:37 -0700430token_list_t *
Carl Worth8f6a8282010-05-14 10:44:19 -0700431_argument_list_member_at (argument_list_t *list, int index)
432{
433 argument_node_t *node;
Carl Worthdcc2ecd2010-05-13 12:56:42 -0700434 int i;
435
436 if (list == NULL)
437 return NULL;
438
439 node = list->head;
440 for (i = 0; i < index; i++) {
441 node = node->next;
442 if (node == NULL)
443 break;
444 }
445
446 if (node)
Carl Worth8f6a8282010-05-14 10:44:19 -0700447 return node->argument;
Carl Worthdcc2ecd2010-05-13 12:56:42 -0700448
449 return NULL;
450}
Carl Worth47252442010-05-19 13:54:37 -0700451
Carl Worth808401f2010-05-25 14:52:43 -0700452/* Note: This function talloc_steal()s the str pointer. */
453token_t *
454_token_create_str (void *ctx, int type, char *str)
455{
456 token_t *token;
457
458 token = xtalloc (ctx, token_t);
459 token->type = type;
460 token->value.str = talloc_steal (token, str);
461
462 return token;
463}
464
465token_t *
466_token_create_ival (void *ctx, int type, int ival)
467{
468 token_t *token;
469
470 token = xtalloc (ctx, token_t);
471 token->type = type;
472 token->value.ival = ival;
473
474 return token;
475}
476
477void
478_token_print (token_t *token)
479{
480 if (token->type < 256) {
481 printf ("%c", token->type);
482 return;
483 }
484
485 switch (token->type) {
486 case IDENTIFIER:
487 case OTHER:
488 printf ("%s", token->value.str);
489 break;
490 case LEFT_SHIFT:
491 printf ("<<");
492 break;
493 case RIGHT_SHIFT:
494 printf (">>");
495 break;
496 case LESS_OR_EQUAL:
497 printf ("<=");
498 break;
499 case GREATER_OR_EQUAL:
500 printf (">=");
501 break;
502 case EQUAL:
503 printf ("==");
504 break;
505 case NOT_EQUAL:
506 printf ("!=");
507 break;
508 case AND:
509 printf ("&&");
510 break;
511 case OR:
512 printf ("||");
513 break;
514 case PASTE:
515 printf ("##");
516 break;
517 default:
518 fprintf (stderr, "Error: Don't know how to print token type %d\n", token->type);
519 break;
520 }
521}
522
Carl Worth47252442010-05-19 13:54:37 -0700523token_list_t *
524_token_list_create (void *ctx)
525{
526 token_list_t *list;
527
528 list = xtalloc (ctx, token_list_t);
529 list->head = NULL;
530 list->tail = NULL;
531
532 return list;
533}
534
535void
Carl Worth808401f2010-05-25 14:52:43 -0700536_token_list_append (token_list_t *list, token_t *token)
Carl Worth47252442010-05-19 13:54:37 -0700537{
538 token_node_t *node;
539
540 node = xtalloc (list, token_node_t);
Carl Worth808401f2010-05-25 14:52:43 -0700541 node->token = xtalloc_reference (list, token);
Carl Worth47252442010-05-19 13:54:37 -0700542
543 node->next = NULL;
544
545 if (list->head == NULL) {
546 list->head = node;
547 } else {
548 list->tail->next = node;
549 }
550
551 list->tail = node;
552}
553
554void
555_token_list_append_list (token_list_t *list, token_list_t *tail)
556{
557 if (list->head == NULL) {
558 list->head = tail->head;
559 } else {
560 list->tail->next = tail->head;
561 }
562
563 list->tail = tail->tail;
564}
Carl Worth80dc60b2010-05-25 14:42:00 -0700565
Carl Worth3a37b872010-05-10 11:44:09 -0700566void
Carl Wortha1e32bc2010-05-10 13:17:25 -0700567yyerror (void *scanner, const char *error)
Carl Worth3a37b872010-05-10 11:44:09 -0700568{
569 fprintf (stderr, "Parse error: %s\n", error);
570}
Carl Worth0b27b5f2010-05-10 16:16:06 -0700571
Carl Worth33cc4002010-05-12 12:17:10 -0700572glcpp_parser_t *
573glcpp_parser_create (void)
Carl Worth0b27b5f2010-05-10 16:16:06 -0700574{
Carl Worth33cc4002010-05-12 12:17:10 -0700575 glcpp_parser_t *parser;
576
Carl Worth5070a202010-05-12 12:45:33 -0700577 parser = xtalloc (NULL, glcpp_parser_t);
Carl Worth33cc4002010-05-12 12:17:10 -0700578
Carl Worth8f38aff2010-05-19 10:01:29 -0700579 glcpp_lex_init_extra (parser, &parser->scanner);
Carl Worth0b27b5f2010-05-10 16:16:06 -0700580 parser->defines = hash_table_ctor (32, hash_table_string_hash,
581 hash_table_string_compare);
Carl Worthae6517f2010-05-25 15:24:59 -0700582 parser->active = _string_list_create (parser);
Carl Wortha807fb72010-05-18 22:10:04 -0700583 parser->expansions = NULL;
584
Carl Worth5a6b9a22010-05-20 14:29:43 -0700585 parser->just_printed_separator = 1;
Carl Worth876e5102010-05-20 14:38:06 -0700586 parser->need_newline = 0;
Carl Worth5a6b9a22010-05-20 14:29:43 -0700587
Carl Worthb20d33c2010-05-20 22:27:07 -0700588 parser->skip_stack = NULL;
589
Carl Worth33cc4002010-05-12 12:17:10 -0700590 return parser;
Carl Worth0b27b5f2010-05-10 16:16:06 -0700591}
592
593int
594glcpp_parser_parse (glcpp_parser_t *parser)
595{
596 return yyparse (parser);
597}
598
599void
Carl Worth33cc4002010-05-12 12:17:10 -0700600glcpp_parser_destroy (glcpp_parser_t *parser)
Carl Worth0b27b5f2010-05-10 16:16:06 -0700601{
Carl Worth876e5102010-05-20 14:38:06 -0700602 if (parser->need_newline)
603 printf ("\n");
Carl Worthb20d33c2010-05-20 22:27:07 -0700604 if (parser->skip_stack)
605 fprintf (stderr, "Error: Unterminated #if\n");
Carl Worth8f38aff2010-05-19 10:01:29 -0700606 glcpp_lex_destroy (parser->scanner);
Carl Worth0b27b5f2010-05-10 16:16:06 -0700607 hash_table_dtor (parser->defines);
Carl Worth33cc4002010-05-12 12:17:10 -0700608 talloc_free (parser);
Carl Worth0b27b5f2010-05-10 16:16:06 -0700609}
Carl Worthc6d5af32010-05-11 12:30:09 -0700610
Carl Worthbe0e2e92010-05-19 07:29:22 -0700611static int
612glcpp_parser_is_expanding (glcpp_parser_t *parser, const char *member)
613{
614 expansion_node_t *node;
615
616 for (node = parser->expansions; node; node = node->next) {
617 if (node->macro &&
618 strcmp (node->macro->identifier, member) == 0)
619 {
620 return 1;
621 }
622 }
623
624 return 0;
625}
626
Carl Wortha807fb72010-05-18 22:10:04 -0700627token_class_t
628glcpp_parser_classify_token (glcpp_parser_t *parser,
629 const char *identifier,
630 int *parameter_index)
Carl Worth9f62a7e2010-05-13 07:38:29 -0700631{
Carl Worthfcbbb462010-05-13 09:36:23 -0700632 macro_t *macro;
633
Carl Worthc10a51b2010-05-20 15:15:26 -0700634 /* Is this token a defined macro? */
Carl Worthfcbbb462010-05-13 09:36:23 -0700635 macro = hash_table_find (parser->defines, identifier);
636
637 if (macro == NULL)
Carl Wortha807fb72010-05-18 22:10:04 -0700638 return TOKEN_CLASS_IDENTIFIER;
Carl Worthfcbbb462010-05-13 09:36:23 -0700639
Carl Worthbe0e2e92010-05-19 07:29:22 -0700640 /* Don't consider this a macro if we are already actively
641 * expanding this macro. */
642 if (glcpp_parser_is_expanding (parser, identifier))
Carl Worthb5693832010-05-20 08:01:44 -0700643 return TOKEN_CLASS_IDENTIFIER_FINALIZED;
Carl Worthbe0e2e92010-05-19 07:29:22 -0700644
645 /* Definitely a macro. Just need to check if it's function-like. */
Carl Worthfcbbb462010-05-13 09:36:23 -0700646 if (macro->is_function)
Carl Wortha807fb72010-05-18 22:10:04 -0700647 return TOKEN_CLASS_FUNC_MACRO;
Carl Worthfcbbb462010-05-13 09:36:23 -0700648 else
Carl Wortha807fb72010-05-18 22:10:04 -0700649 return TOKEN_CLASS_OBJ_MACRO;
Carl Worth9f62a7e2010-05-13 07:38:29 -0700650}
651
Carl Worth33cc4002010-05-12 12:17:10 -0700652void
Carl Worthae6517f2010-05-25 15:24:59 -0700653_glcpp_parser_print_expanded_token (glcpp_parser_t *parser,
654 token_t *token)
655{
656 const char *identifier;
657 macro_t *macro;
658
659 /* We only expand identifiers */
660 if (token->type != IDENTIFIER) {
661 _token_print (token);
662 return;
663 }
664
665 /* Look up this identifier in the hash table. */
666 identifier = token->value.str;
667 macro = hash_table_find (parser->defines, identifier);
668
669 /* Not a macro, so just print directly. */
670 if (macro == NULL) {
671 printf ("%s", identifier);
672 return;
673 }
674
675 /* We're not (yet) supporting function-like macros. */
676 if (macro->is_function) {
677 printf ("%s", identifier);
678 return;
679 }
680
681 /* Finally, don't expand this macro if we're already actively
682 * expanding it, (to avoid infinite recursion). */
683 if (_string_list_contains (parser->active, identifier, NULL)) {
684 printf ("%s", identifier);
685 return;
686 }
687
688 _string_list_push (parser->active, identifier);
689 _glcpp_parser_print_expanded_token_list (parser,
690 macro->replacements);
691 _string_list_pop (parser->active);
692}
693
694void
695_glcpp_parser_print_expanded_token_list (glcpp_parser_t *parser,
696 token_list_t *list)
697{
698 token_node_t *node;
699
700 if (list == NULL)
701 return;
702
703 for (node = list->head; node; node = node->next) {
704 _glcpp_parser_print_expanded_token (parser, node->token);
705 if (node->next)
706 printf (" ");
707 }
708}
709
710void
Carl Worthfcbbb462010-05-13 09:36:23 -0700711_define_object_macro (glcpp_parser_t *parser,
712 const char *identifier,
Carl Worth47252442010-05-19 13:54:37 -0700713 token_list_t *replacements)
Carl Worthfcbbb462010-05-13 09:36:23 -0700714{
715 macro_t *macro;
716
717 macro = xtalloc (parser, macro_t);
718
719 macro->is_function = 0;
Carl Worthc5e98552010-05-14 10:12:21 -0700720 macro->parameters = NULL;
Carl Wortha807fb72010-05-18 22:10:04 -0700721 macro->identifier = talloc_strdup (macro, identifier);
Carl Worthaaa9acb2010-05-19 13:28:24 -0700722 macro->replacements = talloc_steal (macro, replacements);
Carl Worthfcbbb462010-05-13 09:36:23 -0700723
724 hash_table_insert (parser->defines, macro, identifier);
725}
726
727void
728_define_function_macro (glcpp_parser_t *parser,
729 const char *identifier,
Carl Worthc5e98552010-05-14 10:12:21 -0700730 string_list_t *parameters,
Carl Worth47252442010-05-19 13:54:37 -0700731 token_list_t *replacements)
Carl Worthfcbbb462010-05-13 09:36:23 -0700732{
733 macro_t *macro;
734
735 macro = xtalloc (parser, macro_t);
736
737 macro->is_function = 1;
Carl Worthc5e98552010-05-14 10:12:21 -0700738 macro->parameters = talloc_steal (macro, parameters);
Carl Wortha807fb72010-05-18 22:10:04 -0700739 macro->identifier = talloc_strdup (macro, identifier);
Carl Worthaaa9acb2010-05-19 13:28:24 -0700740 macro->replacements = talloc_steal (macro, replacements);
Carl Worthfcbbb462010-05-13 09:36:23 -0700741
742 hash_table_insert (parser->defines, macro, identifier);
743}
744
Carl Wortha807fb72010-05-18 22:10:04 -0700745static void
Carl Worthc10a51b2010-05-20 15:15:26 -0700746_glcpp_parser_push_expansion (glcpp_parser_t *parser,
747 macro_t *macro,
748 token_node_t *replacements)
Carl Worthdcc2ecd2010-05-13 12:56:42 -0700749{
Carl Wortha807fb72010-05-18 22:10:04 -0700750 expansion_node_t *node;
751
752 node = xtalloc (parser, expansion_node_t);
753
754 node->macro = macro;
Carl Worthaaa9acb2010-05-19 13:28:24 -0700755 node->replacements = replacements;
Carl Wortha807fb72010-05-18 22:10:04 -0700756
757 node->next = parser->expansions;
758 parser->expansions = node;
Carl Wortha807fb72010-05-18 22:10:04 -0700759}
760
Carl Worthaaa9acb2010-05-19 13:28:24 -0700761static void
Carl Wortha807fb72010-05-18 22:10:04 -0700762glcpp_parser_pop_expansion (glcpp_parser_t *parser)
Carl Worthdcc2ecd2010-05-13 12:56:42 -0700763{
Carl Wortha807fb72010-05-18 22:10:04 -0700764 expansion_node_t *node;
Carl Worth420d05a2010-05-17 10:15:23 -0700765
Carl Wortha807fb72010-05-18 22:10:04 -0700766 node = parser->expansions;
Carl Worth420d05a2010-05-17 10:15:23 -0700767
Carl Wortha807fb72010-05-18 22:10:04 -0700768 if (node == NULL) {
769 fprintf (stderr, "Internal error: _expansion_list_pop called on an empty list.\n");
770 exit (1);
Carl Worthdcc2ecd2010-05-13 12:56:42 -0700771 }
772
Carl Wortha807fb72010-05-18 22:10:04 -0700773 parser->expansions = node->next;
Carl Worthdcc2ecd2010-05-13 12:56:42 -0700774
Carl Wortha807fb72010-05-18 22:10:04 -0700775 talloc_free (node);
Carl Worthdcc2ecd2010-05-13 12:56:42 -0700776}
777
Carl Wortha807fb72010-05-18 22:10:04 -0700778void
Carl Worth2be8be02010-05-14 10:31:43 -0700779_expand_object_macro (glcpp_parser_t *parser, const char *identifier)
Carl Worth33cc4002010-05-12 12:17:10 -0700780{
Carl Worthfcbbb462010-05-13 09:36:23 -0700781 macro_t *macro;
Carl Worth33cc4002010-05-12 12:17:10 -0700782
Carl Worthfcbbb462010-05-13 09:36:23 -0700783 macro = hash_table_find (parser->defines, identifier);
784 assert (! macro->is_function);
Carl Worthbe0e2e92010-05-19 07:29:22 -0700785 assert (! glcpp_parser_is_expanding (parser, identifier));
Carl Worthfcbbb462010-05-13 09:36:23 -0700786
Carl Worthc10a51b2010-05-20 15:15:26 -0700787 _glcpp_parser_push_expansion (parser, macro, macro->replacements->head);
Carl Worthfcbbb462010-05-13 09:36:23 -0700788}
789
Carl Wortha807fb72010-05-18 22:10:04 -0700790void
Carl Worth2be8be02010-05-14 10:31:43 -0700791_expand_function_macro (glcpp_parser_t *parser,
792 const char *identifier,
Carl Worth8f6a8282010-05-14 10:44:19 -0700793 argument_list_t *arguments)
Carl Worthfcbbb462010-05-13 09:36:23 -0700794{
Carl Worthfcbbb462010-05-13 09:36:23 -0700795 macro_t *macro;
Carl Worthc10a51b2010-05-20 15:15:26 -0700796 token_list_t *expanded;
797 token_node_t *i, *j;
798 int parameter_index;
Carl Worthfcbbb462010-05-13 09:36:23 -0700799
800 macro = hash_table_find (parser->defines, identifier);
801 assert (macro->is_function);
Carl Worthbe0e2e92010-05-19 07:29:22 -0700802 assert (! glcpp_parser_is_expanding (parser, identifier));
Carl Worthfcbbb462010-05-13 09:36:23 -0700803
Carl Worth8f6a8282010-05-14 10:44:19 -0700804 if (_argument_list_length (arguments) !=
Carl Worth2be8be02010-05-14 10:31:43 -0700805 _string_list_length (macro->parameters))
806 {
Carl Worthdcc2ecd2010-05-13 12:56:42 -0700807 fprintf (stderr,
808 "Error: macro %s invoked with %d arguments (expected %d)\n",
809 identifier,
Carl Worth8f6a8282010-05-14 10:44:19 -0700810 _argument_list_length (arguments),
Carl Worthc5e98552010-05-14 10:12:21 -0700811 _string_list_length (macro->parameters));
Carl Wortha807fb72010-05-18 22:10:04 -0700812 return;
Carl Worthdcc2ecd2010-05-13 12:56:42 -0700813 }
Carl Worthfcbbb462010-05-13 09:36:23 -0700814
Carl Worthc10a51b2010-05-20 15:15:26 -0700815 expanded = _token_list_create (macro);
816
817 for (i = macro->replacements->head; i; i = i->next) {
Carl Worth808401f2010-05-25 14:52:43 -0700818 if (_string_list_contains (macro->parameters,
819 i->token->value.str,
Carl Worthc10a51b2010-05-20 15:15:26 -0700820 &parameter_index))
821 {
822 token_list_t *argument;
823 argument = _argument_list_member_at (arguments,
824 parameter_index);
825 for (j = argument->head; j; j = j->next)
826 {
Carl Worth808401f2010-05-25 14:52:43 -0700827 _token_list_append (expanded, j->token);
Carl Worthc10a51b2010-05-20 15:15:26 -0700828 }
829 } else {
Carl Worth808401f2010-05-25 14:52:43 -0700830 _token_list_append (expanded, i->token);
Carl Worthc10a51b2010-05-20 15:15:26 -0700831 }
832 }
833
834 _glcpp_parser_push_expansion (parser, macro, expanded->head);
Carl Worth33cc4002010-05-12 12:17:10 -0700835}
Carl Worth8f38aff2010-05-19 10:01:29 -0700836
837static int
Carl Worth0293b2e2010-05-19 10:05:40 -0700838glcpp_parser_lex (glcpp_parser_t *parser)
Carl Worth8f38aff2010-05-19 10:01:29 -0700839{
Carl Worthaaa9acb2010-05-19 13:28:24 -0700840 expansion_node_t *expansion;
Carl Worth47252442010-05-19 13:54:37 -0700841 token_node_t *replacements;
Carl Worthaaa9acb2010-05-19 13:28:24 -0700842 int parameter_index;
Carl Worthd8327e52010-05-20 15:18:54 -0700843 const char *token;
844 token_class_t class;
Carl Worthaaa9acb2010-05-19 13:28:24 -0700845
846 /* Who says C can't do efficient tail recursion? */
847 RECURSE:
848
849 expansion = parser->expansions;
850
851 if (expansion == NULL)
852 return glcpp_lex (parser->scanner);
853
854 replacements = expansion->replacements;
855
856 /* Pop expansion when replacements is exhausted. */
857 if (replacements == NULL) {
858 glcpp_parser_pop_expansion (parser);
859 goto RECURSE;
860 }
861
862 expansion->replacements = replacements->next;
863
Carl Worth808401f2010-05-25 14:52:43 -0700864 token = replacements->token->value.str;
Carl Worthd8327e52010-05-20 15:18:54 -0700865
866 /* Implement token pasting. */
Carl Worth808401f2010-05-25 14:52:43 -0700867 if (replacements->next && strcmp (replacements->next->token->value.str, "##") == 0) {
Carl Worthd8327e52010-05-20 15:18:54 -0700868 token_node_t *next_node;
869
870 next_node = replacements->next->next;
871
872 if (next_node == NULL) {
873 fprintf (stderr, "Error: '##' cannot appear at the end of a macro expansion.\n");
874 exit (1);
875 }
876
877 token = xtalloc_asprintf (parser, "%s%s",
Carl Worth808401f2010-05-25 14:52:43 -0700878 token, next_node->token->value.str);
Carl Worthd8327e52010-05-20 15:18:54 -0700879 expansion->replacements = next_node->next;
880 }
881
882
883 if (strcmp (token, "(") == 0)
Carl Worthaaa9acb2010-05-19 13:28:24 -0700884 return '(';
Carl Worthd8327e52010-05-20 15:18:54 -0700885 else if (strcmp (token, ")") == 0)
Carl Worthaaa9acb2010-05-19 13:28:24 -0700886 return ')';
Carl Worthaaa9acb2010-05-19 13:28:24 -0700887
Carl Worthd8327e52010-05-20 15:18:54 -0700888 yylval.str = xtalloc_strdup (parser, token);
Carl Worthaaa9acb2010-05-19 13:28:24 -0700889
Carl Worthb5693832010-05-20 08:01:44 -0700890 /* Carefully refuse to expand any finalized identifier. */
Carl Worth808401f2010-05-25 14:52:43 -0700891 if (replacements->token->type == IDENTIFIER_FINALIZED)
Carl Worthb5693832010-05-20 08:01:44 -0700892 return IDENTIFIER_FINALIZED;
893
Carl Worthaaa9acb2010-05-19 13:28:24 -0700894 switch (glcpp_parser_classify_token (parser, yylval.str,
895 &parameter_index))
896 {
Carl Worthaaa9acb2010-05-19 13:28:24 -0700897 case TOKEN_CLASS_IDENTIFIER:
898 return IDENTIFIER;
899 break;
Carl Worthb5693832010-05-20 08:01:44 -0700900 case TOKEN_CLASS_IDENTIFIER_FINALIZED:
901 return IDENTIFIER_FINALIZED;
902 break;
Carl Worthaaa9acb2010-05-19 13:28:24 -0700903 case TOKEN_CLASS_FUNC_MACRO:
904 return FUNC_MACRO;
905 break;
906 default:
907 case TOKEN_CLASS_OBJ_MACRO:
908 return OBJ_MACRO;
909 break;
910 }
Carl Worth8f38aff2010-05-19 10:01:29 -0700911}
Carl Worthb20d33c2010-05-20 22:27:07 -0700912
913static void
914_glcpp_parser_skip_stack_push_if (glcpp_parser_t *parser, int condition)
915{
916 skip_type_t current = SKIP_NO_SKIP;
917 skip_node_t *node;
918
919 if (parser->skip_stack)
920 current = parser->skip_stack->type;
921
922 node = xtalloc (parser, skip_node_t);
923
924 if (current == SKIP_NO_SKIP) {
925 if (condition)
926 node->type = SKIP_NO_SKIP;
927 else
928 node->type = SKIP_TO_ELSE;
929 } else {
930 node->type = SKIP_TO_ENDIF;
931 }
932
933 node->next = parser->skip_stack;
934 parser->skip_stack = node;
935}
936
937static void
938_glcpp_parser_skip_stack_change_if (glcpp_parser_t *parser, const char *type,
939 int condition)
940{
941 if (parser->skip_stack == NULL) {
942 fprintf (stderr, "Error: %s without #if\n", type);
943 exit (1);
944 }
945
946 if (parser->skip_stack->type == SKIP_TO_ELSE) {
947 if (condition)
948 parser->skip_stack->type = SKIP_NO_SKIP;
949 } else {
950 parser->skip_stack->type = SKIP_TO_ENDIF;
951 }
952}
Carl Worth80dc60b2010-05-25 14:42:00 -0700953
Carl Worthb20d33c2010-05-20 22:27:07 -0700954static void
955_glcpp_parser_skip_stack_pop (glcpp_parser_t *parser)
956{
957 skip_node_t *node;
958
959 if (parser->skip_stack == NULL) {
960 fprintf (stderr, "Error: #endif without #if\n");
961 exit (1);
962 }
963
964 node = parser->skip_stack;
965 parser->skip_stack = node->next;
966 talloc_free (node);
967}