2 * Mesa 3-D graphics library
5 * Copyright (C) 2005-2006 Brian Paul All Rights Reserved.
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 * \file slang_preprocess.c
32 #include "grammar_mesa.h"
33 #include "slang_preprocess.h"
35 static const char *slang_pp_directives_syn
=
36 #include "library/slang_pp_directives_syn.h"
39 static const char *slang_pp_expression_syn
=
40 #include "library/slang_pp_expression_syn.h"
43 static const char *slang_pp_version_syn
=
44 #include "library/slang_pp_version_syn.h"
48 grammar_error_to_log (slang_info_log
*log
)
53 grammar_get_last_error ((byte
*) (buf
), sizeof (buf
), &pos
);
54 slang_info_log_error (log
, buf
);
58 _slang_preprocess_version (const char *text
, GLuint
*version
, GLuint
*eaten
, slang_info_log
*log
)
64 id
= grammar_load_from_text ((const byte
*) (slang_pp_version_syn
));
66 grammar_error_to_log (log
);
70 if (!grammar_fast_check (id
, (const byte
*) (text
), &prod
, &size
, 8)) {
71 grammar_error_to_log (log
);
76 /* there can be multiple #version directives - grab the last one */
78 *version
= (GLuint
) (I
[0]) + (GLuint
) (I
[1]) * 100;
79 *eaten
= (GLuint
) (I
[2]) + ((GLuint
) (I
[3]) << 8) + ((GLuint
) (I
[4]) << 16) + ((GLuint
) (I
[5]) << 24);
82 grammar_alloc_free (prod
);
87 * The preprocessor does the following work.
88 * 1. Remove comments. Each comment block is replaced with a single space and if the
89 * block contains new-lines, they are preserved. This ensures that line numbers
90 * stay the same and if a comment block delimits two tokens, the are delitmited
91 * by the space after comment removal.
92 * 2. Remove preprocessor directives from the source string, checking their syntax and
93 * executing them if appropriate. Again, new-lines are preserved.
95 * 4. Tokenize the source string by ensuring there is at least one space between every
96 * two adjacent tokens.
102 pp_annotate (slang_string
*output
, const char *fmt
, ...)
109 _mesa_vsprintf (buffer
, fmt
, va
);
111 slang_string_pushs (output
, buffer
, _mesa_strlen (buffer
));
119 * The expression is executed on a fixed-sized stack. The PUSH macro makes a runtime
120 * check if the stack is not overflown by too complex expressions. In that situation the
121 * GLSL preprocessor should report internal compiler error.
122 * The BINARYDIV makes a runtime check if the divider is not 0. If it is, it reports
126 #define EXECUTION_STACK_SIZE 1024
131 slang_info_log_error (elog, "internal compiler error: preprocessor execution stack overflow.");\
139 assert (sp < EXECUTION_STACK_SIZE);\
151 #define BINARYDIV(op)\
157 slang_info_log_error (elog, "division by zero in preprocessor expression.");\
172 #define OP_LOGICALOR 2
173 #define OP_LOGICALAND 3
178 #define OP_NOTEQUAL 8
179 #define OP_LESSEQUAL 9
180 #define OP_GREATEREQUAL 10
182 #define OP_GREATER 12
183 #define OP_LEFTSHIFT 13
184 #define OP_RIGHTSHIFT 14
186 #define OP_SUBTRACT 16
187 #define OP_MULTIPLY 17
189 #define OP_MODULUS 19
193 #define OP_COMPLEMENT 23
196 execute_expression (slang_string
*output
, const byte
*code
, GLuint
*pi
, GLint
*result
,
197 slang_info_log
*elog
)
200 GLint stack
[EXECUTION_STACK_SIZE
];
201 GLuint sp
= EXECUTION_STACK_SIZE
;
203 while (code
[i
] != OP_END
) {
207 PUSH(_mesa_atoi ((const char *) (&code
[i
])));
208 i
+= _mesa_strlen ((const char *) (&code
[i
])) + 1;
234 case OP_GREATEREQUAL
:
281 /* Write-back the index skipping the OP_END. */
284 /* There should be exactly one value left on the stack. This is our result. */
286 pp_annotate (output
, "%d ", *result
);
287 assert (sp
== EXECUTION_STACK_SIZE
);
292 * Function execute_expressions() executes up to 2 expressions. The second expression is there
293 * for the #line directive which takes 1 or 2 expressions that indicate line and file numbers.
294 * If it fails, it returns 0. If it succeeds, it returns the number of executed expressions.
298 #define EXP_EXPRESSION 1
301 execute_expressions (slang_string
*output
, grammar eid
, const byte
*expr
, GLint results
[2],
302 slang_info_log
*elog
)
306 GLuint size
, count
= 0;
308 success
= grammar_fast_check (eid
, expr
, &code
, &size
, 64);
312 while (code
[i
++] == EXP_EXPRESSION
) {
315 if (!execute_expression (output
, code
, &i
, &results
[count
], elog
)) {
321 grammar_alloc_free (code
);
324 slang_info_log_error (elog
, "syntax error in preprocessor expression.");\
330 * The pp_symbol structure is used to hold macro definitions and macro formal parameters. The
331 * pp_symbols strcture is a collection of pp_symbol. It is used both for storing macro formal
332 * parameters and all global macro definitions. Making this unification wastes some memory,
333 * becuse macro formal parameters don't need further lists of symbols. We lose 8 bytes per
334 * formal parameter here, but making this we can use the same code to substitute macro parameters
335 * as well as macros in the source string.
340 struct pp_symbol_
*symbols
;
345 pp_symbols_init (pp_symbols
*self
)
347 self
->symbols
= NULL
;
352 pp_symbols_free (pp_symbols
*);
354 typedef struct pp_symbol_
357 slang_string replacement
;
358 pp_symbols parameters
;
362 pp_symbol_init (pp_symbol
*self
)
364 slang_string_init (&self
->name
);
365 slang_string_init (&self
->replacement
);
366 pp_symbols_init (&self
->parameters
);
370 pp_symbol_free (pp_symbol
*self
)
372 slang_string_free (&self
->name
);
373 slang_string_free (&self
->replacement
);
374 pp_symbols_free (&self
->parameters
);
378 pp_symbol_reset (pp_symbol
*self
)
380 /* Leave symbol name intact. */
381 slang_string_reset (&self
->replacement
);
382 pp_symbols_free (&self
->parameters
);
383 pp_symbols_init (&self
->parameters
);
387 pp_symbols_free (pp_symbols
*self
)
391 for (i
= 0; i
< self
->count
; i
++)
392 pp_symbol_free (&self
->symbols
[i
]);
393 _mesa_free (self
->symbols
);
397 pp_symbols_push (pp_symbols
*self
)
399 self
->symbols
= (pp_symbol
*) (_mesa_realloc (self
->symbols
, self
->count
* sizeof (pp_symbol
),
400 (self
->count
+ 1) * sizeof (pp_symbol
)));
401 if (self
->symbols
== NULL
)
403 pp_symbol_init (&self
->symbols
[self
->count
]);
404 return &self
->symbols
[self
->count
++];
408 pp_symbols_erase (pp_symbols
*self
, pp_symbol
*symbol
)
410 assert (symbol
>= self
->symbols
&& symbol
< self
->symbols
+ self
->count
);
413 pp_symbol_free (symbol
);
414 if (symbol
< self
->symbols
+ self
->count
)
415 _mesa_memcpy (symbol
, symbol
+ 1, sizeof (pp_symbol
) * (self
->symbols
+ self
->count
- symbol
));
416 self
->symbols
= (pp_symbol
*) (_mesa_realloc (self
->symbols
, (self
->count
+ 1) * sizeof (pp_symbol
),
417 self
->count
* sizeof (pp_symbol
)));
418 return self
->symbols
!= NULL
;
422 pp_symbols_find (pp_symbols
*self
, const char *name
)
426 for (i
= 0; i
< self
->count
; i
++)
427 if (_mesa_strcmp (name
, slang_string_cstr (&self
->symbols
[i
].name
)) == 0)
428 return &self
->symbols
[i
];
433 * The condition context of a single #if/#else/#endif level. Those can be nested, so there
434 * is a stack of condition contexts.
435 * There is a special global context on the bottom of the stack. It is there to simplify
441 GLboolean current
; /* The condition value of this level. */
442 GLboolean effective
; /* The effective product of current condition, outer level conditions
443 * and position within #if-#else-#endif sections. */
444 GLboolean else_allowed
; /* TRUE if in #if-#else section, FALSE if in #else-#endif section
445 * and for global context. */
446 GLboolean endif_required
; /* FALSE for global context only. */
449 /* Should be enuff. */
450 #define CONDITION_STACK_SIZE 64
454 pp_cond_ctx stack
[CONDITION_STACK_SIZE
];
459 pp_cond_stack_push (pp_cond_stack
*self
, slang_info_log
*elog
)
461 if (self
->top
== self
->stack
) {
462 slang_info_log_error (elog
, "internal compiler error: preprocessor condition stack overflow.");
470 pp_cond_stack_reevaluate (pp_cond_stack
*self
)
472 /* There must be at least 2 conditions on the stack - one global and one being evaluated. */
473 assert (self
->top
<= &self
->stack
[CONDITION_STACK_SIZE
- 2]);
475 self
->top
->effective
= self
->top
->current
&& self
->top
[1].effective
;
479 * Extension enables through #extension directive.
480 * NOTE: Currently, only enable/disable state is stored.
485 GLboolean MESA_shader_debug
; /* GL_MESA_shader_debug enable */
489 * Disable all extensions. Called at startup and on #extension all: disable.
492 pp_ext_disable_all (pp_ext
*self
)
494 self
->MESA_shader_debug
= GL_FALSE
;
498 pp_ext_init (pp_ext
*self
)
500 pp_ext_disable_all (self
);
501 /* Other initialization code goes here. */
505 pp_ext_set (pp_ext
*self
, const char *name
, GLboolean enable
)
507 if (_mesa_strcmp (name
, "MESA_shader_debug") == 0)
508 self
->MESA_shader_debug
= enable
;
509 /* Next extension name tests go here. */
516 * The state of preprocessor: current line, file and version number, list of all defined macros
517 * and the #if/#endif context.
527 slang_info_log
*elog
;
532 pp_state_init (pp_state
*self
, slang_info_log
*elog
)
537 pp_symbols_init (&self
->symbols
);
538 pp_ext_init (&self
->ext
);
541 /* Initialize condition stack and create the global context. */
542 self
->cond
.top
= &self
->cond
.stack
[CONDITION_STACK_SIZE
- 1];
543 self
->cond
.top
->current
= GL_TRUE
;
544 self
->cond
.top
->effective
= GL_TRUE
;
545 self
->cond
.top
->else_allowed
= GL_FALSE
;
546 self
->cond
.top
->endif_required
= GL_FALSE
;
550 pp_state_free (pp_state
*self
)
552 pp_symbols_free (&self
->symbols
);
555 #define IS_FIRST_ID_CHAR(x) (((x) >= 'a' && (x) <= 'z') || ((x) >= 'A' && (x) <= 'Z') || (x) == '_')
556 #define IS_NEXT_ID_CHAR(x) (IS_FIRST_ID_CHAR(x) || ((x) >= '0' && (x) <= '9'))
557 #define IS_WHITE(x) ((x) == ' ' || (x) == '\n')
558 #define IS_NULL(x) ((x) == '\0')
560 #define SKIP_WHITE(x) do { while (IS_WHITE(*(x))) (x)++; } while (GL_FALSE)
564 slang_string
*output
;
570 expand_defined (expand_state
*e
, slang_string
*buffer
)
572 GLboolean in_paren
= GL_FALSE
;
575 /* Parse the optional opening parenthesis. */
576 SKIP_WHITE(e
->input
);
577 if (*e
->input
== '(') {
580 SKIP_WHITE(e
->input
);
584 if (!IS_FIRST_ID_CHAR(*e
->input
)) {
585 slang_info_log_error (e
->state
->elog
,
586 "preprocess error: identifier expected after operator 'defined'.");
589 slang_string_reset (buffer
);
590 slang_string_pushc (buffer
, *e
->input
++);
591 while (IS_NEXT_ID_CHAR(*e
->input
))
592 slang_string_pushc (buffer
, *e
->input
++);
593 id
= slang_string_cstr (buffer
);
595 /* Check if the operand is defined. Output 1 if it is defined, output 0 if not. */
596 if (pp_symbols_find (&e
->state
->symbols
, id
) == NULL
)
597 slang_string_pushs (e
->output
, " 0 ", 3);
599 slang_string_pushs (e
->output
, " 1 ", 3);
601 /* Parse the closing parentehesis if the opening one was there. */
603 SKIP_WHITE(e
->input
);
604 if (*e
->input
!= ')') {
605 slang_info_log_error (e
->state
->elog
, "preprocess error: ')' expected.");
609 SKIP_WHITE(e
->input
);
615 expand (expand_state
*, pp_symbols
*);
618 expand_symbol (expand_state
*e
, pp_symbol
*symbol
)
622 /* If the macro has some parameters, we need to parse them. */
623 if (symbol
->parameters
.count
!= 0) {
626 /* Parse the opening parenthesis. */
627 SKIP_WHITE(e
->input
);
628 if (*e
->input
!= '(') {
629 slang_info_log_error (e
->state
->elog
, "preprocess error: '(' expected.");
633 SKIP_WHITE(e
->input
);
635 /* Parse macro actual parameters. This can be anything, separated by a colon.
636 * TODO: What about nested/grouped parameters by parenthesis? */
637 for (i
= 0; i
< symbol
->parameters
.count
; i
++) {
638 if (*e
->input
== ')') {
639 slang_info_log_error (e
->state
->elog
, "preprocess error: unexpected ')'.");
643 /* Eat all characters up to the comma or closing parentheses. */
644 pp_symbol_reset (&symbol
->parameters
.symbols
[i
]);
645 while (!IS_NULL(*e
->input
) && *e
->input
!= ',' && *e
->input
!= ')')
646 slang_string_pushc (&symbol
->parameters
.symbols
[i
].replacement
, *e
->input
++);
648 /* If it was not the last paremeter, skip the comma. Otherwise, skip the
649 * closing parentheses. */
650 if (i
+ 1 == symbol
->parameters
.count
) {
651 /* This is the last paremeter - skip the closing parentheses. */
652 if (*e
->input
!= ')') {
653 slang_info_log_error (e
->state
->elog
, "preprocess error: ')' expected.");
657 SKIP_WHITE(e
->input
);
660 /* Skip the separating comma. */
661 if (*e
->input
!= ',') {
662 slang_info_log_error (e
->state
->elog
, "preprocess error: ',' expected.");
666 SKIP_WHITE(e
->input
);
671 /* Expand the macro. Use its parameters as a priority symbol list to expand
672 * macro parameters correctly. */
673 es
.output
= e
->output
;
674 es
.input
= slang_string_cstr (&symbol
->replacement
);
676 slang_string_pushc (e
->output
, ' ');
677 if (!expand (&es
, &symbol
->parameters
))
679 slang_string_pushc (e
->output
, ' ');
684 * Function expand() expands source text from <input> to <output>. The expansion is made using
685 * the list passed in <symbols> parameter. It allows us to expand macro formal parameters with
686 * actual parameters. The global list of symbols from pp state is used when doing a recursive
691 expand (expand_state
*e
, pp_symbols
*symbols
)
693 while (!IS_NULL(*e
->input
)) {
694 if (IS_FIRST_ID_CHAR(*e
->input
)) {
698 /* Parse the identifier. */
699 slang_string_init (&buffer
);
700 slang_string_pushc (&buffer
, *e
->input
++);
701 while (IS_NEXT_ID_CHAR(*e
->input
))
702 slang_string_pushc (&buffer
, *e
->input
++);
703 id
= slang_string_cstr (&buffer
);
705 /* Now check if the identifier is special in some way. The "defined" identifier is
706 * actually an operator that we must handle here and expand it either to " 0 " or " 1 ".
707 * The other identifiers start with "__" and we expand it to appropriate values
708 * taken from the preprocessor state. */
709 if (_mesa_strcmp (id
, "defined") == 0) {
710 if (!expand_defined (e
, &buffer
))
713 else if (_mesa_strcmp (id
, "__LINE__") == 0) {
714 slang_string_pushc (e
->output
, ' ');
715 slang_string_pushi (e
->output
, e
->state
->line
);
716 slang_string_pushc (e
->output
, ' ');
718 else if (_mesa_strcmp (id
, "__FILE__") == 0) {
719 slang_string_pushc (e
->output
, ' ');
720 slang_string_pushi (e
->output
, e
->state
->file
);
721 slang_string_pushc (e
->output
, ' ');
723 else if (_mesa_strcmp (id
, "__VERSION__") == 0) {
724 slang_string_pushc (e
->output
, ' ');
725 slang_string_pushi (e
->output
, e
->state
->version
);
726 slang_string_pushc (e
->output
, ' ');
731 /* The list of symbols from <symbols> take precedence over the list from <state>.
732 * Note that in some cases this is the same list so avoid double look-up. */
733 symbol
= pp_symbols_find (symbols
, id
);
734 if (symbol
== NULL
&& symbols
!= &e
->state
->symbols
)
735 symbol
= pp_symbols_find (&e
->state
->symbols
, id
);
737 /* If the symbol was found, recursively expand its definition. */
738 if (symbol
!= NULL
) {
739 if (!expand_symbol (e
, symbol
)) {
740 slang_string_free (&buffer
);
745 slang_string_push (e
->output
, &buffer
);
748 slang_string_free (&buffer
);
750 else if (IS_WHITE(*e
->input
)) {
751 slang_string_pushc (e
->output
, *e
->input
++);
754 while (!IS_WHITE(*e
->input
) && !IS_NULL(*e
->input
) && !IS_FIRST_ID_CHAR(*e
->input
))
755 slang_string_pushc (e
->output
, *e
->input
++);
762 parse_if (slang_string
*output
, const byte
*prod
, GLuint
*pi
, GLint
*result
, pp_state
*state
,
768 text
= (const char *) (&prod
[*pi
]);
769 len
= _mesa_strlen (text
);
771 if (state
->cond
.top
->effective
) {
777 /* Expand the expression. */
778 slang_string_init (&expr
);
782 if (!expand (&es
, &state
->symbols
))
785 /* Execute the expression. */
786 count
= execute_expressions (output
, eid
, (const byte
*) (slang_string_cstr (&expr
)),
787 results
, state
->elog
);
788 slang_string_free (&expr
);
791 *result
= results
[0];
794 /* The directive is dead. */
802 #define ESCAPE_TOKEN 0
805 #define TOKEN_DEFINE 1
806 #define TOKEN_UNDEF 2
810 #define TOKEN_ENDIF 6
811 #define TOKEN_ERROR 7
812 #define TOKEN_PRAGMA 8
813 #define TOKEN_EXTENSION 9
814 #define TOKEN_LINE 10
817 #define PARAM_PARAMETER 1
819 #define BEHAVIOR_REQUIRE 1
820 #define BEHAVIOR_ENABLE 2
821 #define BEHAVIOR_WARN 3
822 #define BEHAVIOR_DISABLE 4
825 preprocess_source (slang_string
*output
, const char *source
, grammar pid
, grammar eid
,
826 slang_info_log
*elog
)
832 if (!grammar_fast_check (pid
, (const byte
*) (source
), &prod
, &size
, 65536)) {
833 grammar_error_to_log (elog
);
837 pp_state_init (&state
, elog
);
841 if (prod
[i
] != ESCAPE_TOKEN
) {
842 if (state
.cond
.top
->effective
) {
846 /* Eat only one line of source code to expand it.
847 * FIXME: This approach has one drawback. If a macro with parameters spans across
848 * multiple lines, the preprocessor will raise an error. */
849 slang_string_init (&input
);
850 while (prod
[i
] != '\0' && prod
[i
] != '\n')
851 slang_string_pushc (&input
, prod
[i
++]);
853 slang_string_pushc (&input
, prod
[i
++]);
855 /* Increment line number. */
859 es
.input
= slang_string_cstr (&input
);
861 if (!expand (&es
, &state
.symbols
))
864 slang_string_free (&input
);
867 /* Condition stack is disabled - keep track on line numbers and output only newlines. */
868 if (prod
[i
] == '\n') {
870 /*pp_annotate (output, "%c", prod[i]);*/
873 /*pp_annotate (output, "%c", prod[i]);*/
886 /* End of source string.
887 * Check if all #ifs have been terminated by matching #endifs.
888 * On condition stack there should be only the global condition context. */
889 if (state
.cond
.top
->endif_required
) {
890 slang_info_log_error (elog
, "end of source without matching #endif.");
897 pp_symbol
*symbol
= NULL
;
899 /* Parse macro name. */
900 id
= (const char *) (&prod
[i
]);
901 idlen
= _mesa_strlen (id
);
902 if (state
.cond
.top
->effective
) {
903 pp_annotate (output
, "// #define %s(", id
);
905 /* If the symbol is already defined, override it. */
906 symbol
= pp_symbols_find (&state
.symbols
, id
);
907 if (symbol
== NULL
) {
908 symbol
= pp_symbols_push (&state
.symbols
);
911 slang_string_pushs (&symbol
->name
, id
, idlen
);
914 pp_symbol_reset (symbol
);
919 /* Parse optional macro parameters. */
920 while (prod
[i
++] != PARAM_END
) {
921 if (state
.cond
.top
->effective
) {
924 id
= (const char *) (&prod
[i
]);
925 idlen
= _mesa_strlen (id
);
926 pp_annotate (output
, "%s, ", id
);
927 param
= pp_symbols_push (&symbol
->parameters
);
930 slang_string_pushs (¶m
->name
, id
, idlen
);
935 /* Parse macro replacement. */
936 id
= (const char *) (&prod
[i
]);
937 idlen
= _mesa_strlen (id
);
938 if (state
.cond
.top
->effective
) {
939 pp_annotate (output
, ") %s", id
);
940 slang_string_pushs (&symbol
->replacement
, id
, idlen
);
947 id
= (const char *) (&prod
[i
]);
948 i
+= _mesa_strlen (id
) + 1;
949 if (state
.cond
.top
->effective
) {
952 pp_annotate (output
, "// #undef %s", id
);
953 /* Try to find symbol with given name and remove it. */
954 symbol
= pp_symbols_find (&state
.symbols
, id
);
956 if (!pp_symbols_erase (&state
.symbols
, symbol
))
965 /* Parse #if expression end execute it. */
966 pp_annotate (output
, "// #if ");
967 if (!parse_if (output
, prod
, &i
, &result
, &state
, eid
))
970 /* Push new condition on the stack. */
971 if (!pp_cond_stack_push (&state
.cond
, state
.elog
))
973 state
.cond
.top
->current
= result
? GL_TRUE
: GL_FALSE
;
974 state
.cond
.top
->else_allowed
= GL_TRUE
;
975 state
.cond
.top
->endif_required
= GL_TRUE
;
976 pp_cond_stack_reevaluate (&state
.cond
);
981 /* Check if #else is alloved here. */
982 if (!state
.cond
.top
->else_allowed
) {
983 slang_info_log_error (elog
, "#else without matching #if.");
987 /* Negate current condition and reevaluate it. */
988 state
.cond
.top
->current
= !state
.cond
.top
->current
;
989 state
.cond
.top
->else_allowed
= GL_FALSE
;
990 pp_cond_stack_reevaluate (&state
.cond
);
991 if (state
.cond
.top
->effective
)
992 pp_annotate (output
, "// #else");
996 /* Check if #elif is alloved here. */
997 if (!state
.cond
.top
->else_allowed
) {
998 slang_info_log_error (elog
, "#elif without matching #if.");
1002 /* Negate current condition and reevaluate it. */
1003 state
.cond
.top
->current
= !state
.cond
.top
->current
;
1004 pp_cond_stack_reevaluate (&state
.cond
);
1006 if (state
.cond
.top
->effective
)
1007 pp_annotate (output
, "// #elif ");
1012 /* Parse #elif expression end execute it. */
1013 if (!parse_if (output
, prod
, &i
, &result
, &state
, eid
))
1016 /* Update current condition and reevaluate it. */
1017 state
.cond
.top
->current
= result
? GL_TRUE
: GL_FALSE
;
1018 pp_cond_stack_reevaluate (&state
.cond
);
1023 /* Check if #endif is alloved here. */
1024 if (!state
.cond
.top
->endif_required
) {
1025 slang_info_log_error (elog
, "#endif without matching #if.");
1029 /* Pop the condition off the stack. */
1031 if (state
.cond
.top
->effective
)
1032 pp_annotate (output
, "// #endif");
1035 case TOKEN_EXTENSION
:
1036 /* Parse the extension name. */
1037 id
= (const char *) (&prod
[i
]);
1038 i
+= _mesa_strlen (id
) + 1;
1039 if (state
.cond
.top
->effective
)
1040 pp_annotate (output
, "// #extension %s: ", id
);
1042 /* Parse and apply extension behavior. */
1043 if (state
.cond
.top
->effective
) {
1044 switch (prod
[i
++]) {
1046 case BEHAVIOR_REQUIRE
:
1047 pp_annotate (output
, "require");
1048 if (!pp_ext_set (&state
.ext
, id
, GL_TRUE
)) {
1049 if (_mesa_strcmp (id
, "all") == 0) {
1050 slang_info_log_error (elog
, "require: bad behavior for #extension all.");
1054 slang_info_log_error (elog
, "%s: required extension is not supported.", id
);
1060 case BEHAVIOR_ENABLE
:
1061 pp_annotate (output
, "enable");
1062 if (!pp_ext_set (&state
.ext
, id
, GL_TRUE
)) {
1063 if (_mesa_strcmp (id
, "all") == 0) {
1064 slang_info_log_error (elog
, "enable: bad behavior for #extension all.");
1068 slang_info_log_warning (elog
, "%s: enabled extension is not supported.", id
);
1074 pp_annotate (output
, "warn");
1075 if (!pp_ext_set (&state
.ext
, id
, GL_TRUE
)) {
1076 if (_mesa_strcmp (id
, "all") != 0) {
1077 slang_info_log_warning (elog
, "%s: enabled extension is not supported.", id
);
1082 case BEHAVIOR_DISABLE
:
1083 pp_annotate (output
, "disable");
1084 if (!pp_ext_set (&state
.ext
, id
, GL_FALSE
)) {
1085 if (_mesa_strcmp (id
, "all") == 0) {
1086 pp_ext_disable_all (&state
.ext
);
1089 slang_info_log_warning (elog
, "%s: disabled extension is not supported.", id
);
1101 id
= (const char *) (&prod
[i
]);
1102 i
+= _mesa_strlen (id
) + 1;
1104 if (state
.cond
.top
->effective
) {
1105 slang_string buffer
;
1110 slang_string_init (&buffer
);
1112 es
.output
= &buffer
;
1115 if (!expand (&es
, &state
.symbols
))
1118 pp_annotate (output
, "// #line ");
1119 count
= execute_expressions (output
, eid
,
1120 (const byte
*) (slang_string_cstr (&buffer
)),
1121 results
, state
.elog
);
1122 slang_string_free (&buffer
);
1126 state
.line
= results
[0] - 1;
1128 state
.file
= results
[1];
1135 /* Check for missing #endifs. */
1136 if (state
.cond
.top
->endif_required
) {
1137 slang_info_log_error (elog
, "#endif expected but end of source found.");
1141 pp_state_free (&state
);
1145 pp_state_free (&state
);
1150 _slang_preprocess_directives (slang_string
*output
, const char *input
, slang_info_log
*elog
)
1155 pid
= grammar_load_from_text ((const byte
*) (slang_pp_directives_syn
));
1157 grammar_error_to_log (elog
);
1160 eid
= grammar_load_from_text ((const byte
*) (slang_pp_expression_syn
));
1162 grammar_error_to_log (elog
);
1163 grammar_destroy (pid
);
1166 success
= preprocess_source (output
, input
, pid
, eid
, elog
);
1167 grammar_destroy (eid
);
1168 grammar_destroy (pid
);