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