3 * Copyright © 2010 Intel Corporation
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:
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
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.
32 #include "main/core.h" /* for struct gl_extensions */
33 #include "main/mtypes.h" /* for gl_api enum */
36 yyerror (YYLTYPE *locp
, glcpp_parser_t
*parser
, const char *error);
39 _define_object_macro
(glcpp_parser_t
*parser
,
42 token_list_t
*replacements
);
45 _define_function_macro
(glcpp_parser_t
*parser
,
48 string_list_t
*parameters
,
49 token_list_t
*replacements
);
51 static string_list_t
*
52 _string_list_create
(void *ctx
);
55 _string_list_append_item
(string_list_t
*list
, const char *str
);
58 _string_list_contains
(string_list_t
*list
, const char *member
, int *index
);
61 _string_list_length
(string_list_t
*list
);
64 _string_list_equal
(string_list_t
*a
, string_list_t
*b
);
66 static argument_list_t
*
67 _argument_list_create
(void *ctx
);
70 _argument_list_append
(argument_list_t
*list
, token_list_t
*argument
);
73 _argument_list_length
(argument_list_t
*list
);
76 _argument_list_member_at
(argument_list_t
*list
, int index
);
78 /* Note: This function ralloc_steal()s the str pointer. */
80 _token_create_str
(void *ctx
, int type
, char *str
);
83 _token_create_ival
(void *ctx
, int type
, int ival
);
86 _token_list_create
(void *ctx
);
88 /* Note: This function calls ralloc_steal on token. */
90 _token_list_append
(token_list_t
*list
, token_t
*token
);
93 _token_list_append_list
(token_list_t
*list
, token_list_t
*tail
);
96 _token_list_equal_ignoring_space
(token_list_t
*a
, token_list_t
*b
);
99 _parser_active_list_push
(glcpp_parser_t
*parser
,
100 const char *identifier
,
101 token_node_t
*marker
);
104 _parser_active_list_pop
(glcpp_parser_t
*parser
);
107 _parser_active_list_contains
(glcpp_parser_t
*parser
, const char *identifier
);
110 _glcpp_parser_expand_if
(glcpp_parser_t
*parser
, int type
, token_list_t
*list
);
113 _glcpp_parser_expand_token_list
(glcpp_parser_t
*parser
,
117 _glcpp_parser_print_expanded_token_list
(glcpp_parser_t
*parser
,
121 _glcpp_parser_skip_stack_push_if
(glcpp_parser_t
*parser
, YYLTYPE *loc
,
125 _glcpp_parser_skip_stack_change_if
(glcpp_parser_t
*parser
, YYLTYPE *loc
,
126 const char *type
, int condition
);
129 _glcpp_parser_skip_stack_pop
(glcpp_parser_t
*parser
, YYLTYPE *loc
);
131 #define yylex glcpp_parser_lex
134 glcpp_parser_lex
(YYSTYPE *yylval, YYLTYPE *yylloc, glcpp_parser_t
*parser
);
137 glcpp_parser_lex_from
(glcpp_parser_t
*parser
, token_list_t
*list
);
140 add_builtin_define
(glcpp_parser_t
*parser
, const char *name
, int value
);
156 %parse
-param
{glcpp_parser_t
*parser
}
157 %lex
-param
{glcpp_parser_t
*parser
}
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
162 %type
<ival
> expression INTEGER operator SPACE integer_constant
163 %type
<str
> IDENTIFIER INTEGER_STRING OTHER
164 %type
<string_list
> identifier_list
165 %type
<token
> preprocessing_token conditional_token
166 %type
<token_list
> pp_tokens replacement_list text_line conditional_tokens
172 %left EQUAL NOT_EQUAL
173 %left
'<' '>' LESS_OR_EQUAL GREATER_OR_EQUAL
174 %left LEFT_SHIFT RIGHT_SHIFT
188 ralloc_strcat
(&parser
->output
, "\n");
191 _glcpp_parser_print_expanded_token_list
(parser
, $1);
192 ralloc_strcat
(&parser
->output
, "\n");
200 IF_EXPANDED expression NEWLINE
{
201 _glcpp_parser_skip_stack_push_if
(parser
, & @
1, $2);
203 | ELIF_EXPANDED expression NEWLINE
{
204 _glcpp_parser_skip_stack_change_if
(parser
, & @
1, "elif", $2);
209 HASH_DEFINE_OBJ IDENTIFIER replacement_list NEWLINE
{
210 _define_object_macro
(parser
, & @
2, $2, $3);
212 | HASH_DEFINE_FUNC IDENTIFIER
'(' ')' replacement_list NEWLINE
{
213 _define_function_macro
(parser
, & @
2, $2, NULL
, $5);
215 | HASH_DEFINE_FUNC IDENTIFIER
'(' identifier_list
')' replacement_list NEWLINE
{
216 _define_function_macro
(parser
, & @
2, $2, $4, $6);
218 | HASH_UNDEF IDENTIFIER NEWLINE
{
219 macro_t
*macro
= hash_table_find
(parser
->defines
, $2);
221 hash_table_remove
(parser
->defines
, $2);
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
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
)
237 _glcpp_parser_expand_if
(parser
, IF_EXPANDED
, $2);
241 _glcpp_parser_skip_stack_push_if
(parser
, & @
1, 0);
242 parser
->skip_stack
->type
= SKIP_TO_ENDIF
;
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
)
251 glcpp_error
(& @
1, parser
, "#if with no expression");
253 _glcpp_parser_skip_stack_push_if
(parser
, & @
1, 0);
255 | HASH_IFDEF IDENTIFIER junk NEWLINE
{
256 macro_t
*macro
= hash_table_find
(parser
->defines
, $2);
258 _glcpp_parser_skip_stack_push_if
(parser
, & @
1, macro
!= NULL
);
260 | HASH_IFNDEF IDENTIFIER junk NEWLINE
{
261 macro_t
*macro
= hash_table_find
(parser
->defines
, $2);
263 _glcpp_parser_skip_stack_push_if
(parser
, & @
1, macro
== NULL
);
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
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
)
276 _glcpp_parser_expand_if
(parser
, ELIF_EXPANDED
, $2);
280 _glcpp_parser_skip_stack_change_if
(parser
, & @
1,
284 | HASH_ELIF NEWLINE
{
285 /* #elif without an expression is an error unless we
287 if
(parser
->skip_stack
&&
288 parser
->skip_stack
->type
== SKIP_TO_ELSE
)
290 glcpp_error
(& @
1, parser
, "#elif with no expression");
294 _glcpp_parser_skip_stack_change_if
(parser
, & @
1,
296 glcpp_warning
(& @
1, parser
, "ignoring illegal #elif without expression");
299 | HASH_ELSE NEWLINE
{
300 _glcpp_parser_skip_stack_change_if
(parser
, & @
1, "else", 1);
302 | HASH_ENDIF NEWLINE
{
303 _glcpp_parser_skip_stack_pop
(parser
, & @
1);
305 | HASH_VERSION integer_constant NEWLINE
{
306 macro_t
*macro
= hash_table_find
(parser
->defines
, "__VERSION__");
308 hash_table_remove
(parser
->defines
, "__VERSION__");
311 add_builtin_define
(parser
, "__VERSION__", $2);
314 add_builtin_define
(parser
, "GL_ES", 1);
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.
321 if
($2 >= 130 ||
$2 == 100)
322 add_builtin_define
(parser
, "GL_FRAGMENT_PRECISION_HIGH", 1);
324 ralloc_asprintf_append
(&parser
->output
, "#version %" PRIiMAX
, $2);
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);
336 $$
= strtoll
($1, NULL
, 10);
345 | expression OR expression
{
348 | expression AND expression
{
351 | expression
'|' expression
{
354 | expression
'^' expression
{
357 | expression
'&' expression
{
360 | expression NOT_EQUAL expression
{
363 | expression EQUAL expression
{
366 | expression GREATER_OR_EQUAL expression
{
369 | expression LESS_OR_EQUAL expression
{
372 | expression
'>' expression
{
375 | expression
'<' expression
{
378 | expression RIGHT_SHIFT expression
{
381 | expression LEFT_SHIFT expression
{
384 | expression
'-' expression
{
387 | expression
'+' expression
{
390 | expression
'%' expression
{
392 yyerror (& @
1, parser
,
393 "zero modulus in preprocessor directive");
398 | expression
'/' expression
{
400 yyerror (& @
1, parser
,
401 "division by 0 in preprocessor directive");
406 | expression
'*' expression
{
409 |
'!' expression %prec UNARY
{
412 |
'~' expression %prec UNARY
{
415 |
'-' expression %prec UNARY
{
418 |
'+' expression %prec UNARY
{
421 |
'(' expression
')' {
428 $$
= _string_list_create
(parser
);
429 _string_list_append_item
($$
, $1);
430 ralloc_steal
($$
, $1);
432 | identifier_list
',' IDENTIFIER
{
434 _string_list_append_item
($$
, $3);
435 ralloc_steal
($$
, $3);
440 NEWLINE
{ $$
= NULL
; }
446 yyerror (& @
1, parser
, "Invalid tokens after #");
451 /* empty */ { $$
= NULL
; }
458 glcpp_warning
(&@
1, parser
, "extra tokens at end of directive");
463 /* Handle "defined" operator */
465 int v
= hash_table_find
(parser
->defines
, $2) ?
1 : 0;
466 $$
= _token_create_ival
(parser
, INTEGER
, v
);
468 | DEFINED
'(' IDENTIFIER
')' {
469 int v
= hash_table_find
(parser
->defines
, $3) ?
1 : 0;
470 $$
= _token_create_ival
(parser
, INTEGER
, v
);
472 | preprocessing_token
476 /* Exactly the same as pp_tokens, but using conditional_token */
478 $$
= _token_list_create
(parser
);
479 _token_list_append
($$
, $1);
481 | conditional_tokens conditional_token
{
483 _token_list_append
($$
, $2);
488 preprocessing_token
{
489 parser
->space_tokens
= 1;
490 $$
= _token_list_create
(parser
);
491 _token_list_append
($$
, $1);
493 | pp_tokens preprocessing_token
{
495 _token_list_append
($$
, $2);
501 $$
= _token_create_str
(parser
, IDENTIFIER
, $1);
502 $$
->location
= yylloc;
505 $$
= _token_create_str
(parser
, INTEGER_STRING
, $1);
506 $$
->location
= yylloc;
509 $$
= _token_create_ival
(parser
, $1, $1);
510 $$
->location
= yylloc;
513 $$
= _token_create_str
(parser
, OTHER
, $1);
514 $$
->location
= yylloc;
517 $$
= _token_create_ival
(parser
, SPACE
, SPACE
);
518 $$
->location
= yylloc;
538 | LEFT_SHIFT
{ $$
= LEFT_SHIFT
; }
539 | RIGHT_SHIFT
{ $$
= RIGHT_SHIFT
; }
542 | LESS_OR_EQUAL
{ $$
= LESS_OR_EQUAL
; }
543 | GREATER_OR_EQUAL
{ $$
= GREATER_OR_EQUAL
; }
544 | EQUAL
{ $$
= EQUAL
; }
545 | NOT_EQUAL
{ $$
= NOT_EQUAL
; }
553 | PASTE
{ $$
= PASTE
; }
559 _string_list_create
(void *ctx
)
563 list
= ralloc
(ctx
, string_list_t
);
571 _string_list_append_item
(string_list_t
*list
, const char *str
)
575 node
= ralloc
(list
, string_node_t
);
576 node
->str
= ralloc_strdup
(node
, str
);
580 if
(list
->head
== NULL
) {
583 list
->tail
->next
= node
;
590 _string_list_contains
(string_list_t
*list
, const char *member
, int *index
)
598 for
(i
= 0, node
= list
->head
; node
; i
++, node
= node
->next
) {
599 if
(strcmp
(node
->str
, member
) == 0) {
610 _string_list_length
(string_list_t
*list
)
618 for
(node
= list
->head
; node
; node
= node
->next
)
625 _string_list_equal
(string_list_t
*a
, string_list_t
*b
)
627 string_node_t
*node_a
, *node_b
;
629 if
(a
== NULL
&& b
== NULL
)
632 if
(a
== NULL || b
== NULL
)
635 for
(node_a
= a
->head
, node_b
= b
->head
;
637 node_a
= node_a
->next
, node_b
= node_b
->next
)
639 if
(strcmp
(node_a
->str
, node_b
->str
))
643 /* Catch the case of lists being different lengths, (which
644 * would cause the loop above to terminate after the shorter
646 return node_a
== node_b
;
650 _argument_list_create
(void *ctx
)
652 argument_list_t
*list
;
654 list
= ralloc
(ctx
, argument_list_t
);
662 _argument_list_append
(argument_list_t
*list
, token_list_t
*argument
)
664 argument_node_t
*node
;
666 node
= ralloc
(list
, argument_node_t
);
667 node
->argument
= argument
;
671 if
(list
->head
== NULL
) {
674 list
->tail
->next
= node
;
681 _argument_list_length
(argument_list_t
*list
)
684 argument_node_t
*node
;
689 for
(node
= list
->head
; node
; node
= node
->next
)
696 _argument_list_member_at
(argument_list_t
*list
, int index
)
698 argument_node_t
*node
;
705 for
(i
= 0; i
< index
; i
++) {
712 return node
->argument
;
717 /* Note: This function ralloc_steal()s the str pointer. */
719 _token_create_str
(void *ctx
, int type
, char *str
)
723 token
= ralloc
(ctx
, token_t
);
725 token
->value.str
= str
;
727 ralloc_steal
(token
, str
);
733 _token_create_ival
(void *ctx
, int type
, int ival
)
737 token
= ralloc
(ctx
, token_t
);
739 token
->value.ival
= ival
;
745 _token_list_create
(void *ctx
)
749 list
= ralloc
(ctx
, token_list_t
);
752 list
->non_space_tail
= NULL
;
758 _token_list_append
(token_list_t
*list
, token_t
*token
)
762 node
= ralloc
(list
, token_node_t
);
766 ralloc_steal
(list
, token
);
768 if
(list
->head
== NULL
) {
771 list
->tail
->next
= node
;
775 if
(token
->type
!= SPACE
)
776 list
->non_space_tail
= node
;
780 _token_list_append_list
(token_list_t
*list
, token_list_t
*tail
)
782 if
(tail
== NULL || tail
->head
== NULL
)
785 if
(list
->head
== NULL
) {
786 list
->head
= tail
->head
;
788 list
->tail
->next
= tail
->head
;
791 list
->tail
= tail
->tail
;
792 list
->non_space_tail
= tail
->non_space_tail
;
795 static token_list_t
*
796 _token_list_copy
(void *ctx
, token_list_t
*other
)
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
);
815 _token_list_trim_trailing_space
(token_list_t
*list
)
817 token_node_t
*tail
, *next
;
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
;
833 _token_list_is_empty_ignoring_space
(token_list_t
*l
)
841 while
(n
!= NULL
&& n
->token
->type
== SPACE
)
848 _token_list_equal_ignoring_space
(token_list_t
*a
, token_list_t
*b
)
850 token_node_t
*node_a
, *node_b
;
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
;
863 if
(node_a
== NULL
&& node_b
== NULL
)
866 if
(node_a
== NULL || node_b
== NULL
)
869 if
(node_a
->token
->type
== SPACE
) {
870 node_a
= node_a
->next
;
874 if
(node_b
->token
->type
== SPACE
) {
875 node_b
= node_b
->next
;
879 if
(node_a
->token
->type
!= node_b
->token
->type
)
882 switch
(node_a
->token
->type
) {
884 if
(node_a
->token
->value.ival
!=
885 node_b
->token
->value.ival
)
893 if
(strcmp
(node_a
->token
->value.str
,
894 node_b
->token
->value.str
))
901 node_a
= node_a
->next
;
902 node_b
= node_b
->next
;
909 _token_print
(char **out
, token_t
*token
)
911 if
(token
->type
< 256) {
912 ralloc_asprintf_append
(out
, "%c", token
->type
);
916 switch
(token
->type
) {
918 ralloc_asprintf_append
(out
, "%" PRIiMAX
, token
->value.ival
);
923 ralloc_strcat
(out
, token
->value.str
);
926 ralloc_strcat
(out
, " ");
929 ralloc_strcat
(out
, "<<");
932 ralloc_strcat
(out
, ">>");
935 ralloc_strcat
(out
, "<=");
937 case GREATER_OR_EQUAL
:
938 ralloc_strcat
(out
, ">=");
941 ralloc_strcat
(out
, "==");
944 ralloc_strcat
(out
, "!=");
947 ralloc_strcat
(out
, "&&");
950 ralloc_strcat
(out
, "||");
953 ralloc_strcat
(out
, "##");
956 ralloc_strcat
(out
, ",");
959 /* Nothing to print. */
962 assert
(!"Error: Don't know how to print token.");
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.
971 * Caution: Only very cursory error-checking is performed to see if
972 * the final result is a valid single token. */
974 _token_paste
(glcpp_parser_t
*parser
, token_t
*token
, token_t
*other
)
976 token_t
*combined
= NULL
;
978 /* Pasting a placeholder onto anything makes no change. */
979 if
(other
->type
== PLACEHOLDER
)
982 /* When 'token' is a placeholder, just return 'other'. */
983 if
(token
->type
== PLACEHOLDER
)
986 /* A very few single-character punctuators can be combined
987 * with another to form a multi-character punctuator. */
988 switch
(token
->type
) {
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
);
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
);
1002 if
(other
->type
== '=')
1003 combined
= _token_create_ival
(token
, EQUAL
, EQUAL
);
1006 if
(other
->type
== '=')
1007 combined
= _token_create_ival
(token
, NOT_EQUAL
, NOT_EQUAL
);
1010 if
(other
->type
== '&')
1011 combined
= _token_create_ival
(token
, AND
, AND
);
1014 if
(other
->type
== '|')
1015 combined
= _token_create_ival
(token
, OR
, OR
);
1019 if
(combined
!= NULL
) {
1020 /* Inherit the location from the first token */
1021 combined
->location
= token
->location
;
1025 /* Two string-valued tokens can usually just be mashed
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
1033 if
((token
->type
== IDENTIFIER || token
->type
== OTHER || token
->type
== INTEGER_STRING
) &&
1034 (other
->type
== IDENTIFIER || other
->type
== OTHER || other
->type
== INTEGER_STRING
))
1038 str
= ralloc_asprintf
(token
, "%s%s", token
->value.str
,
1040 combined
= _token_create_str
(token
, token
->type
, str
);
1041 combined
->location
= token
->location
;
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");
1056 _token_list_print
(glcpp_parser_t
*parser
, token_list_t
*list
)
1063 for
(node
= list
->head
; node
; node
= node
->next
)
1064 _token_print
(&parser
->output
, node
->token
);
1068 yyerror (YYLTYPE *locp
, glcpp_parser_t
*parser
, const char *error)
1070 glcpp_error
(locp
, parser
, "%s", error);
1073 static void add_builtin_define
(glcpp_parser_t
*parser
,
1074 const char *name
, int value
)
1079 tok
= _token_create_ival
(parser
, INTEGER
, value
);
1081 list
= _token_list_create
(parser
);
1082 _token_list_append
(list
, tok
);
1083 _define_object_macro
(parser
, NULL
, name
, list
);
1087 glcpp_parser_create
(const struct gl_extensions
*extensions
, int api
)
1089 glcpp_parser_t
*parser
;
1090 int language_version
;
1092 parser
= ralloc
(NULL
, glcpp_parser_t
);
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;
1104 parser
->skip_stack
= NULL
;
1106 parser
->lex_from_list
= NULL
;
1107 parser
->lex_from_node
= NULL
;
1109 parser
->output
= ralloc_strdup
(parser
, "");
1110 parser
->info_log
= ralloc_strdup
(parser
, "");
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);
1117 if
(api
== API_OPENGLES2
)
1118 add_builtin_define
(parser
, "GL_ES", 1);
1120 if
(extensions
!= NULL
) {
1121 if
(extensions
->EXT_texture_array
) {
1122 add_builtin_define
(parser
, "GL_EXT_texture_array", 1);
1125 if
(extensions
->ARB_fragment_coord_conventions
)
1126 add_builtin_define
(parser
, "GL_ARB_fragment_coord_conventions",
1129 if
(extensions
->ARB_explicit_attrib_location
)
1130 add_builtin_define
(parser
, "GL_ARB_explicit_attrib_location", 1);
1132 if
(extensions
->ARB_shader_texture_lod
)
1133 add_builtin_define
(parser
, "GL_ARB_shader_texture_lod", 1);
1135 if
(extensions
->AMD_conservative_depth
)
1136 add_builtin_define
(parser
, "GL_AMD_conservative_depth", 1);
1139 language_version
= 110;
1140 add_builtin_define
(parser
, "__VERSION__", language_version
);
1146 glcpp_parser_parse
(glcpp_parser_t
*parser
)
1148 return
yyparse (parser
);
1152 glcpp_parser_destroy
(glcpp_parser_t
*parser
)
1154 glcpp_lex_destroy
(parser
->scanner
);
1155 hash_table_dtor
(parser
->defines
);
1156 ralloc_free
(parser
);
1159 typedef
enum function_status
1161 FUNCTION_STATUS_SUCCESS
,
1162 FUNCTION_NOT_A_FUNCTION
,
1163 FUNCTION_UNBALANCED_PARENTHESES
1164 } function_status_t
;
1166 /* Find a set of function-like macro arguments by looking for a
1167 * balanced set of parentheses.
1169 * When called, 'node' should be the opening-parenthesis token, (or
1170 * perhaps preceeding SPACE tokens). Upon successful return *last will
1171 * be the last consumed node, (corresponding to the closing right
1176 * FUNCTION_STATUS_SUCCESS:
1178 * Successfully parsed a set of function arguments.
1180 * FUNCTION_NOT_A_FUNCTION:
1182 * Macro name not followed by a '('. This is not an error, but
1183 * simply that the macro name should be treated as a non-macro.
1185 * FUNCTION_UNBALANCED_PARENTHESES
1187 * Macro name is not followed by a balanced set of parentheses.
1189 static function_status_t
1190 _arguments_parse
(argument_list_t
*arguments
,
1192 token_node_t
**last
)
1194 token_list_t
*argument
;
1199 /* Ignore whitespace before first parenthesis. */
1200 while
(node
&& node
->token
->type
== SPACE
)
1203 if
(node
== NULL || node
->token
->type
!= '(')
1204 return FUNCTION_NOT_A_FUNCTION
;
1208 argument
= _token_list_create
(arguments
);
1209 _argument_list_append
(arguments
, argument
);
1211 for
(paren_count
= 1; node
; node
= node
->next
) {
1212 if
(node
->token
->type
== '(')
1216 else if
(node
->token
->type
== ')')
1219 if
(paren_count
== 0)
1223 if
(node
->token
->type
== ',' &&
1226 _token_list_trim_trailing_space
(argument
);
1227 argument
= _token_list_create
(arguments
);
1228 _argument_list_append
(arguments
, argument
);
1231 if
(argument
->head
== NULL
) {
1232 /* Don't treat initial whitespace as
1233 * part of the arguement. */
1234 if
(node
->token
->type
== SPACE
)
1237 _token_list_append
(argument
, node
->token
);
1242 return FUNCTION_UNBALANCED_PARENTHESES
;
1246 return FUNCTION_STATUS_SUCCESS
;
1249 static token_list_t
*
1250 _token_list_create_with_one_space
(void *ctx
)
1255 list
= _token_list_create
(ctx
);
1256 space
= _token_create_ival
(list
, SPACE
, SPACE
);
1257 _token_list_append
(list
, space
);
1263 _glcpp_parser_expand_if
(glcpp_parser_t
*parser
, int type
, token_list_t
*list
)
1265 token_list_t
*expanded
;
1268 expanded
= _token_list_create
(parser
);
1269 token
= _token_create_ival
(parser
, type
, type
);
1270 _token_list_append
(expanded
, token
);
1271 _glcpp_parser_expand_token_list
(parser
, list
);
1272 _token_list_append_list
(expanded
, list
);
1273 glcpp_parser_lex_from
(parser
, expanded
);
1276 /* This is a helper function that's essentially part of the
1277 * implementation of _glcpp_parser_expand_node. It shouldn't be called
1278 * except for by that function.
1280 * Returns NULL if node is a simple token with no expansion, (that is,
1281 * although 'node' corresponds to an identifier defined as a
1282 * function-like macro, it is not followed with a parenthesized
1285 * Compute the complete expansion of node (which is a function-like
1286 * macro) and subsequent nodes which are arguments.
1288 * Returns the token list that results from the expansion and sets
1289 * *last to the last node in the list that was consumed by the
1290 * expansion. Specifically, *last will be set as follows: as the
1291 * token of the closing right parenthesis.
1293 static token_list_t
*
1294 _glcpp_parser_expand_function
(glcpp_parser_t
*parser
,
1296 token_node_t
**last
)
1300 const char *identifier
;
1301 argument_list_t
*arguments
;
1302 function_status_t status
;
1303 token_list_t
*substituted
;
1304 int parameter_index
;
1306 identifier
= node
->token
->value.str
;
1308 macro
= hash_table_find
(parser
->defines
, identifier
);
1310 assert
(macro
->is_function
);
1312 arguments
= _argument_list_create
(parser
);
1313 status
= _arguments_parse
(arguments
, node
, last
);
1316 case FUNCTION_STATUS_SUCCESS
:
1318 case FUNCTION_NOT_A_FUNCTION
:
1320 case FUNCTION_UNBALANCED_PARENTHESES
:
1321 glcpp_error
(&node
->token
->location
, parser
, "Macro %s call has unbalanced parentheses\n", identifier
);
1325 /* Replace a macro defined as empty with a SPACE token. */
1326 if
(macro
->replacements
== NULL
) {
1327 ralloc_free
(arguments
);
1328 return _token_list_create_with_one_space
(parser
);
1331 if
(! ((_argument_list_length
(arguments
) ==
1332 _string_list_length
(macro
->parameters
)) ||
1333 (_string_list_length
(macro
->parameters
) == 0 &&
1334 _argument_list_length
(arguments
) == 1 &&
1335 arguments
->head
->argument
->head
== NULL
)))
1337 glcpp_error
(&node
->token
->location
, parser
,
1338 "Error: macro %s invoked with %d arguments (expected %d)\n",
1340 _argument_list_length
(arguments
),
1341 _string_list_length
(macro
->parameters
));
1345 /* Perform argument substitution on the replacement list. */
1346 substituted
= _token_list_create
(arguments
);
1348 for
(node
= macro
->replacements
->head
; node
; node
= node
->next
)
1350 if
(node
->token
->type
== IDENTIFIER
&&
1351 _string_list_contains
(macro
->parameters
,
1352 node
->token
->value.str
,
1355 token_list_t
*argument
;
1356 argument
= _argument_list_member_at
(arguments
,
1358 /* Before substituting, we expand the argument
1359 * tokens, or append a placeholder token for
1360 * an empty argument. */
1361 if
(argument
->head
) {
1362 token_list_t
*expanded_argument
;
1363 expanded_argument
= _token_list_copy
(parser
,
1365 _glcpp_parser_expand_token_list
(parser
,
1367 _token_list_append_list
(substituted
,
1372 new_token
= _token_create_ival
(substituted
,
1375 _token_list_append
(substituted
, new_token
);
1378 _token_list_append
(substituted
, node
->token
);
1382 /* After argument substitution, and before further expansion
1383 * below, implement token pasting. */
1385 _token_list_trim_trailing_space
(substituted
);
1387 node
= substituted
->head
;
1390 token_node_t
*next_non_space
;
1392 /* Look ahead for a PASTE token, skipping space. */
1393 next_non_space
= node
->next
;
1394 while
(next_non_space
&& next_non_space
->token
->type
== SPACE
)
1395 next_non_space
= next_non_space
->next
;
1397 if
(next_non_space
== NULL
)
1400 if
(next_non_space
->token
->type
!= PASTE
) {
1401 node
= next_non_space
;
1405 /* Now find the next non-space token after the PASTE. */
1406 next_non_space
= next_non_space
->next
;
1407 while
(next_non_space
&& next_non_space
->token
->type
== SPACE
)
1408 next_non_space
= next_non_space
->next
;
1410 if
(next_non_space
== NULL
) {
1411 yyerror (&node
->token
->location
, parser
, "'##' cannot appear at either end of a macro expansion\n");
1415 node
->token
= _token_paste
(parser
, node
->token
, next_non_space
->token
);
1416 node
->next
= next_non_space
->next
;
1417 if
(next_non_space
== substituted
->tail
)
1418 substituted
->tail
= node
;
1423 substituted
->non_space_tail
= substituted
->tail
;
1428 /* Compute the complete expansion of node, (and subsequent nodes after
1429 * 'node' in the case that 'node' is a function-like macro and
1430 * subsequent nodes are arguments).
1432 * Returns NULL if node is a simple token with no expansion.
1434 * Otherwise, returns the token list that results from the expansion
1435 * and sets *last to the last node in the list that was consumed by
1436 * the expansion. Specifically, *last will be set as follows:
1438 * As 'node' in the case of object-like macro expansion.
1440 * As the token of the closing right parenthesis in the case of
1441 * function-like macro expansion.
1443 static token_list_t
*
1444 _glcpp_parser_expand_node
(glcpp_parser_t
*parser
,
1446 token_node_t
**last
)
1448 token_t
*token
= node
->token
;
1449 const char *identifier
;
1452 /* We only expand identifiers */
1453 if
(token
->type
!= IDENTIFIER
) {
1454 /* We change any COMMA into a COMMA_FINAL to prevent
1455 * it being mistaken for an argument separator
1457 if
(token
->type
== ',') {
1458 token
->type
= COMMA_FINAL
;
1459 token
->value.ival
= COMMA_FINAL
;
1465 /* Look up this identifier in the hash table. */
1466 identifier
= token
->value.str
;
1467 macro
= hash_table_find
(parser
->defines
, identifier
);
1469 /* Not a macro, so no expansion needed. */
1473 /* Finally, don't expand this macro if we're already actively
1474 * expanding it, (to avoid infinite recursion). */
1475 if
(_parser_active_list_contains
(parser
, identifier
)) {
1476 /* We change the token type here from IDENTIFIER to
1477 * OTHER to prevent any future expansion of this
1478 * unexpanded token. */
1480 token_list_t
*expansion
;
1483 str
= ralloc_strdup
(parser
, token
->value.str
);
1484 final
= _token_create_str
(parser
, OTHER
, str
);
1485 expansion
= _token_list_create
(parser
);
1486 _token_list_append
(expansion
, final
);
1491 if
(! macro
->is_function
)
1495 /* Replace a macro defined as empty with a SPACE token. */
1496 if
(macro
->replacements
== NULL
)
1497 return _token_list_create_with_one_space
(parser
);
1499 return _token_list_copy
(parser
, macro
->replacements
);
1502 return _glcpp_parser_expand_function
(parser
, node
, last
);
1505 /* Push a new identifier onto the parser's active list.
1507 * Here, 'marker' is the token node that appears in the list after the
1508 * expansion of 'identifier'. That is, when the list iterator begins
1509 * examining 'marker', then it is time to pop this node from the
1513 _parser_active_list_push
(glcpp_parser_t
*parser
,
1514 const char *identifier
,
1515 token_node_t
*marker
)
1517 active_list_t
*node
;
1519 node
= ralloc
(parser
->active
, active_list_t
);
1520 node
->identifier
= ralloc_strdup
(node
, identifier
);
1521 node
->marker
= marker
;
1522 node
->next
= parser
->active
;
1524 parser
->active
= node
;
1528 _parser_active_list_pop
(glcpp_parser_t
*parser
)
1530 active_list_t
*node
= parser
->active
;
1533 parser
->active
= NULL
;
1537 node
= parser
->active
->next
;
1538 ralloc_free
(parser
->active
);
1540 parser
->active
= node
;
1544 _parser_active_list_contains
(glcpp_parser_t
*parser
, const char *identifier
)
1546 active_list_t
*node
;
1548 if
(parser
->active
== NULL
)
1551 for
(node
= parser
->active
; node
; node
= node
->next
)
1552 if
(strcmp
(node
->identifier
, identifier
) == 0)
1558 /* Walk over the token list replacing nodes with their expansion.
1559 * Whenever nodes are expanded the walking will walk over the new
1560 * nodes, continuing to expand as necessary. The results are placed in
1564 _glcpp_parser_expand_token_list
(glcpp_parser_t
*parser
,
1567 token_node_t
*node_prev
;
1568 token_node_t
*node
, *last
= NULL
;
1569 token_list_t
*expansion
;
1570 active_list_t
*active_initial
= parser
->active
;
1575 _token_list_trim_trailing_space
(list
);
1582 while
(parser
->active
&& parser
->active
->marker
== node
)
1583 _parser_active_list_pop
(parser
);
1585 expansion
= _glcpp_parser_expand_node
(parser
, node
, &last
);
1589 for
(n
= node
; n
!= last
->next
; n
= n
->next
)
1590 while
(parser
->active
&&
1591 parser
->active
->marker
== n
)
1593 _parser_active_list_pop
(parser
);
1596 _parser_active_list_push
(parser
,
1597 node
->token
->value.str
,
1600 /* Splice expansion into list, supporting a
1601 * simple deletion if the expansion is
1603 if
(expansion
->head
) {
1605 node_prev
->next
= expansion
->head
;
1607 list
->head
= expansion
->head
;
1608 expansion
->tail
->next
= last
->next
;
1609 if
(last
== list
->tail
)
1610 list
->tail
= expansion
->tail
;
1613 node_prev
->next
= last
->next
;
1615 list
->head
= last
->next
;
1616 if
(last
== list
->tail
)
1622 node
= node_prev ? node_prev
->next
: list
->head
;
1625 /* Remove any lingering effects of this invocation on the
1626 * active list. That is, pop until the list looks like it did
1627 * at the beginning of this function. */
1628 while
(parser
->active
&& parser
->active
!= active_initial
)
1629 _parser_active_list_pop
(parser
);
1631 list
->non_space_tail
= list
->tail
;
1635 _glcpp_parser_print_expanded_token_list
(glcpp_parser_t
*parser
,
1641 _glcpp_parser_expand_token_list
(parser
, list
);
1643 _token_list_trim_trailing_space
(list
);
1645 _token_list_print
(parser
, list
);
1649 _check_for_reserved_macro_name
(glcpp_parser_t
*parser
, YYLTYPE *loc
,
1650 const char *identifier
)
1652 /* According to the GLSL specification, macro names starting with "__"
1653 * or "GL_" are reserved for future use. So, don't allow them.
1655 if
(strncmp
(identifier
, "__", 2) == 0) {
1656 glcpp_error
(loc
, parser
, "Macro names starting with \"__\" are reserved.\n");
1658 if
(strncmp
(identifier
, "GL_", 3) == 0) {
1659 glcpp_error
(loc
, parser
, "Macro names starting with \"GL_\" are reserved.\n");
1664 _macro_equal
(macro_t
*a
, macro_t
*b
)
1666 if
(a
->is_function
!= b
->is_function
)
1669 if
(a
->is_function
) {
1670 if
(! _string_list_equal
(a
->parameters
, b
->parameters
))
1674 return _token_list_equal_ignoring_space
(a
->replacements
,
1679 _define_object_macro
(glcpp_parser_t
*parser
,
1681 const char *identifier
,
1682 token_list_t
*replacements
)
1684 macro_t
*macro
, *previous
;
1687 _check_for_reserved_macro_name
(parser
, loc
, identifier
);
1689 macro
= ralloc
(parser
, macro_t
);
1691 macro
->is_function
= 0;
1692 macro
->parameters
= NULL
;
1693 macro
->identifier
= ralloc_strdup
(macro
, identifier
);
1694 macro
->replacements
= replacements
;
1695 ralloc_steal
(macro
, replacements
);
1697 previous
= hash_table_find
(parser
->defines
, identifier
);
1699 if
(_macro_equal
(macro
, previous
)) {
1700 ralloc_free
(macro
);
1703 glcpp_error
(loc
, parser
, "Redefinition of macro %s\n",
1707 hash_table_insert
(parser
->defines
, macro
, identifier
);
1711 _define_function_macro
(glcpp_parser_t
*parser
,
1713 const char *identifier
,
1714 string_list_t
*parameters
,
1715 token_list_t
*replacements
)
1717 macro_t
*macro
, *previous
;
1719 _check_for_reserved_macro_name
(parser
, loc
, identifier
);
1721 macro
= ralloc
(parser
, macro_t
);
1722 ralloc_steal
(macro
, parameters
);
1723 ralloc_steal
(macro
, replacements
);
1725 macro
->is_function
= 1;
1726 macro
->parameters
= parameters
;
1727 macro
->identifier
= ralloc_strdup
(macro
, identifier
);
1728 macro
->replacements
= replacements
;
1729 previous
= hash_table_find
(parser
->defines
, identifier
);
1731 if
(_macro_equal
(macro
, previous
)) {
1732 ralloc_free
(macro
);
1735 glcpp_error
(loc
, parser
, "Redefinition of macro %s\n",
1739 hash_table_insert
(parser
->defines
, macro
, identifier
);
1743 glcpp_parser_lex
(YYSTYPE *yylval, YYLTYPE *yylloc, glcpp_parser_t
*parser
)
1748 if
(parser
->lex_from_list
== NULL
) {
1749 ret
= glcpp_lex
(yylval, yylloc, parser
->scanner
);
1751 /* XXX: This ugly block of code exists for the sole
1752 * purpose of converting a NEWLINE token into a SPACE
1753 * token, but only in the case where we have seen a
1754 * function-like macro name, but have not yet seen its
1755 * closing parenthesis.
1757 * There's perhaps a more compact way to do this with
1758 * mid-rule actions in the grammar.
1760 * I'm definitely not pleased with the complexity of
1763 if
(parser
->newline_as_space
)
1766 parser
->paren_count
++;
1767 } else if
(ret
== ')') {
1768 parser
->paren_count
--;
1769 if
(parser
->paren_count
== 0)
1770 parser
->newline_as_space
= 0;
1771 } else if
(ret
== NEWLINE
) {
1773 } else if
(ret
!= SPACE
) {
1774 if
(parser
->paren_count
== 0)
1775 parser
->newline_as_space
= 0;
1778 else if
(parser
->in_control_line
)
1781 parser
->in_control_line
= 0;
1783 else if
(ret
== HASH_DEFINE_OBJ || ret
== HASH_DEFINE_FUNC ||
1784 ret
== HASH_UNDEF || ret
== HASH_IF ||
1785 ret
== HASH_IFDEF || ret
== HASH_IFNDEF ||
1786 ret
== HASH_ELIF || ret
== HASH_ELSE ||
1787 ret
== HASH_ENDIF || ret
== HASH
)
1789 parser
->in_control_line
= 1;
1791 else if
(ret
== IDENTIFIER
)
1794 macro
= hash_table_find
(parser
->defines
,
1796 if
(macro
&& macro
->is_function
) {
1797 parser
->newline_as_space
= 1;
1798 parser
->paren_count
= 0;
1805 node
= parser
->lex_from_node
;
1808 ralloc_free
(parser
->lex_from_list
);
1809 parser
->lex_from_list
= NULL
;
1813 *yylval = node
->token
->value
;
1814 ret
= node
->token
->type
;
1816 parser
->lex_from_node
= node
->next
;
1822 glcpp_parser_lex_from
(glcpp_parser_t
*parser
, token_list_t
*list
)
1826 assert
(parser
->lex_from_list
== NULL
);
1828 /* Copy list, eliminating any space tokens. */
1829 parser
->lex_from_list
= _token_list_create
(parser
);
1831 for
(node
= list
->head
; node
; node
= node
->next
) {
1832 if
(node
->token
->type
== SPACE
)
1834 _token_list_append
(parser
->lex_from_list
, node
->token
);
1839 parser
->lex_from_node
= parser
->lex_from_list
->head
;
1841 /* It's possible the list consisted of nothing but whitespace. */
1842 if
(parser
->lex_from_node
== NULL
) {
1843 ralloc_free
(parser
->lex_from_list
);
1844 parser
->lex_from_list
= NULL
;
1849 _glcpp_parser_skip_stack_push_if
(glcpp_parser_t
*parser
, YYLTYPE *loc
,
1852 skip_type_t current
= SKIP_NO_SKIP
;
1855 if
(parser
->skip_stack
)
1856 current
= parser
->skip_stack
->type
;
1858 node
= ralloc
(parser
, skip_node_t
);
1861 if
(current
== SKIP_NO_SKIP
) {
1863 node
->type
= SKIP_NO_SKIP
;
1865 node
->type
= SKIP_TO_ELSE
;
1867 node
->type
= SKIP_TO_ENDIF
;
1870 node
->next
= parser
->skip_stack
;
1871 parser
->skip_stack
= node
;
1875 _glcpp_parser_skip_stack_change_if
(glcpp_parser_t
*parser
, YYLTYPE *loc
,
1876 const char *type
, int condition
)
1878 if
(parser
->skip_stack
== NULL
) {
1879 glcpp_error
(loc
, parser
, "%s without #if\n", type
);
1883 if
(parser
->skip_stack
->type
== SKIP_TO_ELSE
) {
1885 parser
->skip_stack
->type
= SKIP_NO_SKIP
;
1887 parser
->skip_stack
->type
= SKIP_TO_ENDIF
;
1892 _glcpp_parser_skip_stack_pop
(glcpp_parser_t
*parser
, YYLTYPE *loc
)
1896 if
(parser
->skip_stack
== NULL
) {
1897 glcpp_error
(loc
, parser
, "#endif without #if\n");
1901 node
= parser
->skip_stack
;
1902 parser
->skip_stack
= node
->next
;