2 * Mesa 3-D graphics library
4 * Copyright (C) 2005-2008 Brian Paul All Rights Reserved.
5 * Copyright (C) 2009 VMware, Inc. 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
31 #include "main/imports.h"
32 #include "shader/grammar/grammar_mesa.h"
33 #include "slang_preprocess.h"
35 LONGSTRING
static const char *slang_pp_directives_syn
=
36 #include "library/slang_pp_directives_syn.h"
39 LONGSTRING
static const char *slang_pp_expression_syn
=
40 #include "library/slang_pp_expression_syn.h"
43 LONGSTRING
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
);
55 _mesa_snprintf(buf
, sizeof(buf
), "Preprocessor error");
57 slang_info_log_error (log
, buf
);
61 _slang_preprocess_version (const char *text
, GLuint
*version
, GLuint
*eaten
, slang_info_log
*log
)
67 id
= grammar_load_from_text ((const byte
*) (slang_pp_version_syn
));
69 grammar_error_to_log (log
);
73 if (!grammar_fast_check (id
, (const byte
*) (text
), &prod
, &size
, 8)) {
74 grammar_error_to_log (log
);
79 /* there can be multiple #version directives - grab the last one */
81 *version
= (GLuint
) (I
[0]) + (GLuint
) (I
[1]) * 100;
82 *eaten
= (GLuint
) (I
[2]) + ((GLuint
) (I
[3]) << 8) + ((GLuint
) (I
[4]) << 16) + ((GLuint
) (I
[5]) << 24);
85 grammar_alloc_free (prod
);
90 * The preprocessor does the following work.
91 * 1. Remove comments. Each comment block is replaced with a single space and if the
92 * block contains new-lines, they are preserved. This ensures that line numbers
93 * stay the same and if a comment block delimits two tokens, the are delitmited
94 * by the space after comment removal.
95 * 2. Remove preprocessor directives from the source string, checking their syntax and
96 * executing them if appropriate. Again, new-lines are preserved.
98 * 4. Tokenize the source string by ensuring there is at least one space between every
99 * two adjacent tokens.
102 #define PP_ANNOTATE 0
105 pp_annotate (slang_string
*output
, const char *fmt
, ...)
112 _mesa_vsprintf (buffer
, fmt
, va
);
114 slang_string_pushs (output
, buffer
, _mesa_strlen (buffer
));
122 * The expression is executed on a fixed-sized stack. The PUSH macro makes a runtime
123 * check if the stack is not overflown by too complex expressions. In that situation the
124 * GLSL preprocessor should report internal compiler error.
125 * The BINARYDIV makes a runtime check if the divider is not 0. If it is, it reports
129 #define EXECUTION_STACK_SIZE 1024
134 slang_info_log_error (elog, "internal compiler error: preprocessor execution stack overflow.");\
142 assert (sp < EXECUTION_STACK_SIZE);\
154 #define BINARYDIV(op)\
160 slang_info_log_error (elog, "division by zero in preprocessor expression.");\
175 #define OP_LOGICALOR 2
176 #define OP_LOGICALAND 3
181 #define OP_NOTEQUAL 8
182 #define OP_LESSEQUAL 9
183 #define OP_GREATEREQUAL 10
185 #define OP_GREATER 12
186 #define OP_LEFTSHIFT 13
187 #define OP_RIGHTSHIFT 14
189 #define OP_SUBTRACT 16
190 #define OP_MULTIPLY 17
192 #define OP_MODULUS 19
196 #define OP_COMPLEMENT 23
199 execute_expression (slang_string
*output
, const byte
*code
, GLuint
*pi
, GLint
*result
,
200 slang_info_log
*elog
)
203 GLint stack
[EXECUTION_STACK_SIZE
];
204 GLuint sp
= EXECUTION_STACK_SIZE
;
206 while (code
[i
] != OP_END
) {
210 PUSH(_mesa_atoi ((const char *) (&code
[i
])));
211 i
+= _mesa_strlen ((const char *) (&code
[i
])) + 1;
237 case OP_GREATEREQUAL
:
284 /* Write-back the index skipping the OP_END. */
287 /* There should be exactly one value left on the stack. This is our result. */
289 pp_annotate (output
, "%d ", *result
);
290 assert (sp
== EXECUTION_STACK_SIZE
);
295 * Function execute_expressions() executes up to 2 expressions. The second expression is there
296 * for the #line directive which takes 1 or 2 expressions that indicate line and file numbers.
297 * If it fails, it returns 0. If it succeeds, it returns the number of executed expressions.
301 #define EXP_EXPRESSION 1
304 execute_expressions (slang_string
*output
, grammar eid
, const byte
*expr
, GLint results
[2],
305 slang_info_log
*elog
)
309 GLuint size
, count
= 0;
311 success
= grammar_fast_check (eid
, expr
, &code
, &size
, 64);
315 while (code
[i
++] == EXP_EXPRESSION
) {
318 if (!execute_expression (output
, code
, &i
, &results
[count
], elog
)) {
324 grammar_alloc_free (code
);
327 slang_info_log_error (elog
, "syntax error in preprocessor expression.");\
333 * The pp_symbol structure is used to hold macro definitions and macro formal parameters. The
334 * pp_symbols strcture is a collection of pp_symbol. It is used both for storing macro formal
335 * parameters and all global macro definitions. Making this unification wastes some memory,
336 * becuse macro formal parameters don't need further lists of symbols. We lose 8 bytes per
337 * formal parameter here, but making this we can use the same code to substitute macro parameters
338 * as well as macros in the source string.
343 struct pp_symbol_
*symbols
;
348 pp_symbols_init (pp_symbols
*self
)
350 self
->symbols
= NULL
;
355 pp_symbols_free (pp_symbols
*);
357 typedef struct pp_symbol_
360 slang_string replacement
;
361 pp_symbols parameters
;
365 pp_symbol_init (pp_symbol
*self
)
367 slang_string_init (&self
->name
);
368 slang_string_init (&self
->replacement
);
369 pp_symbols_init (&self
->parameters
);
373 pp_symbol_free (pp_symbol
*self
)
375 slang_string_free (&self
->name
);
376 slang_string_free (&self
->replacement
);
377 pp_symbols_free (&self
->parameters
);
381 pp_symbol_reset (pp_symbol
*self
)
383 /* Leave symbol name intact. */
384 slang_string_reset (&self
->replacement
);
385 pp_symbols_free (&self
->parameters
);
386 pp_symbols_init (&self
->parameters
);
390 pp_symbols_free (pp_symbols
*self
)
394 for (i
= 0; i
< self
->count
; i
++)
395 pp_symbol_free (&self
->symbols
[i
]);
396 _mesa_free (self
->symbols
);
400 pp_symbols_push (pp_symbols
*self
)
402 self
->symbols
= (pp_symbol
*) (_mesa_realloc (self
->symbols
, self
->count
* sizeof (pp_symbol
),
403 (self
->count
+ 1) * sizeof (pp_symbol
)));
404 if (self
->symbols
== NULL
)
406 pp_symbol_init (&self
->symbols
[self
->count
]);
407 return &self
->symbols
[self
->count
++];
411 pp_symbols_erase (pp_symbols
*self
, pp_symbol
*symbol
)
413 assert (symbol
>= self
->symbols
&& symbol
< self
->symbols
+ self
->count
);
416 pp_symbol_free (symbol
);
417 if (symbol
< self
->symbols
+ self
->count
)
418 _mesa_memcpy (symbol
, symbol
+ 1, sizeof (pp_symbol
) * (self
->symbols
+ self
->count
- symbol
));
419 self
->symbols
= (pp_symbol
*) (_mesa_realloc (self
->symbols
, (self
->count
+ 1) * sizeof (pp_symbol
),
420 self
->count
* sizeof (pp_symbol
)));
421 return self
->symbols
!= NULL
;
425 pp_symbols_find (pp_symbols
*self
, const char *name
)
429 for (i
= 0; i
< self
->count
; i
++)
430 if (_mesa_strcmp (name
, slang_string_cstr (&self
->symbols
[i
].name
)) == 0)
431 return &self
->symbols
[i
];
436 * The condition context of a single #if/#else/#endif level. Those can be nested, so there
437 * is a stack of condition contexts.
438 * There is a special global context on the bottom of the stack. It is there to simplify
444 GLboolean current
; /* The condition value of this level. */
445 GLboolean effective
; /* The effective product of current condition, outer level conditions
446 * and position within #if-#else-#endif sections. */
447 GLboolean else_allowed
; /* TRUE if in #if-#else section, FALSE if in #else-#endif section
448 * and for global context. */
449 GLboolean endif_required
; /* FALSE for global context only. */
452 /* Should be enuff. */
453 #define CONDITION_STACK_SIZE 64
457 pp_cond_ctx stack
[CONDITION_STACK_SIZE
];
462 pp_cond_stack_push (pp_cond_stack
*self
, slang_info_log
*elog
)
464 if (self
->top
== self
->stack
) {
465 slang_info_log_error (elog
, "internal compiler error: preprocessor condition stack overflow.");
473 pp_cond_stack_reevaluate (pp_cond_stack
*self
)
475 /* There must be at least 2 conditions on the stack - one global and one being evaluated. */
476 assert (self
->top
<= &self
->stack
[CONDITION_STACK_SIZE
- 2]);
478 self
->top
->effective
= self
->top
->current
&& self
->top
[1].effective
;
483 * Extension enables through #extension directive.
484 * NOTE: Currently, only enable/disable state is stored.
488 GLboolean ARB_draw_buffers
;
489 GLboolean ARB_texture_rectangle
;
494 * Disable all extensions. Called at startup and on #extension all: disable.
497 pp_ext_disable_all(pp_ext
*self
)
499 _mesa_memset(self
, 0, sizeof(self
));
504 * Called during preprocessor initialization to set the initial enable/disable
505 * state of extensions.
508 pp_ext_init(pp_ext
*self
, const struct gl_extensions
*extensions
)
510 pp_ext_disable_all (self
);
511 if (extensions
->ARB_draw_buffers
)
512 self
->ARB_draw_buffers
= GL_TRUE
;
513 if (extensions
->NV_texture_rectangle
)
514 self
->ARB_texture_rectangle
= GL_TRUE
;
518 * Called in response to #extension directives to enable/disable
519 * the named extension.
522 pp_ext_set(pp_ext
*self
, const char *name
, GLboolean enable
)
524 if (_mesa_strcmp (name
, "GL_ARB_draw_buffers") == 0)
525 self
->ARB_draw_buffers
= enable
;
526 else if (_mesa_strcmp (name
, "GL_ARB_texture_rectangle") == 0)
527 self
->ARB_texture_rectangle
= enable
;
535 pp_pragmas_init(struct gl_sl_pragmas
*pragmas
)
537 pragmas
->Optimize
= GL_TRUE
;
538 pragmas
->Debug
= GL_FALSE
;
543 * Called in response to #pragma. For example, "#pragma debug(on)" would
544 * call this function as pp_pragma("debug", "on").
545 * \return GL_TRUE if pragma is valid, GL_FALSE if invalid
548 pp_pragma(struct gl_sl_pragmas
*pragmas
, const char *pragma
, const char *param
)
551 printf("#pragma %s %s\n", pragma
, param
);
553 if (_mesa_strcmp(pragma
, "optimize") == 0) {
555 return GL_FALSE
; /* missing required param */
556 if (_mesa_strcmp(param
, "on") == 0) {
557 pragmas
->Optimize
= GL_TRUE
;
559 else if (_mesa_strcmp(param
, "off") == 0) {
560 pragmas
->Optimize
= GL_FALSE
;
563 return GL_FALSE
; /* invalid param */
566 else if (_mesa_strcmp(pragma
, "debug") == 0) {
568 return GL_FALSE
; /* missing required param */
569 if (_mesa_strcmp(param
, "on") == 0) {
570 pragmas
->Debug
= GL_TRUE
;
572 else if (_mesa_strcmp(param
, "off") == 0) {
573 pragmas
->Debug
= GL_FALSE
;
576 return GL_FALSE
; /* invalid param */
579 /* all other pragmas are silently ignored */
585 * The state of preprocessor: current line, file and version number, list
586 * of all defined macros and the #if/#endif context.
595 slang_info_log
*elog
;
600 pp_state_init (pp_state
*self
, slang_info_log
*elog
,
601 const struct gl_extensions
*extensions
)
610 pp_symbols_init (&self
->symbols
);
611 pp_ext_init (&self
->ext
, extensions
);
614 /* Initialize condition stack and create the global context. */
615 self
->cond
.top
= &self
->cond
.stack
[CONDITION_STACK_SIZE
- 1];
616 self
->cond
.top
->current
= GL_TRUE
;
617 self
->cond
.top
->effective
= GL_TRUE
;
618 self
->cond
.top
->else_allowed
= GL_FALSE
;
619 self
->cond
.top
->endif_required
= GL_FALSE
;
623 pp_state_free (pp_state
*self
)
625 pp_symbols_free (&self
->symbols
);
628 #define IS_FIRST_ID_CHAR(x) (((x) >= 'a' && (x) <= 'z') || ((x) >= 'A' && (x) <= 'Z') || (x) == '_')
629 #define IS_NEXT_ID_CHAR(x) (IS_FIRST_ID_CHAR(x) || ((x) >= '0' && (x) <= '9'))
630 #define IS_WHITE(x) ((x) == ' ' || (x) == '\n')
631 #define IS_NULL(x) ((x) == '\0')
633 #define SKIP_WHITE(x) do { while (IS_WHITE(*(x))) (x)++; } while (GL_FALSE)
637 slang_string
*output
;
643 expand_defined (expand_state
*e
, slang_string
*buffer
)
645 GLboolean in_paren
= GL_FALSE
;
648 /* Parse the optional opening parenthesis. */
649 SKIP_WHITE(e
->input
);
650 if (*e
->input
== '(') {
653 SKIP_WHITE(e
->input
);
657 if (!IS_FIRST_ID_CHAR(*e
->input
)) {
658 slang_info_log_error (e
->state
->elog
,
659 "preprocess error: identifier expected after operator 'defined'.");
662 slang_string_reset (buffer
);
663 slang_string_pushc (buffer
, *e
->input
++);
664 while (IS_NEXT_ID_CHAR(*e
->input
))
665 slang_string_pushc (buffer
, *e
->input
++);
666 id
= slang_string_cstr (buffer
);
668 /* Check if the operand is defined. Output 1 if it is defined, output 0 if not. */
669 if (pp_symbols_find (&e
->state
->symbols
, id
) == NULL
)
670 slang_string_pushs (e
->output
, " 0 ", 3);
672 slang_string_pushs (e
->output
, " 1 ", 3);
674 /* Parse the closing parentehesis if the opening one was there. */
676 SKIP_WHITE(e
->input
);
677 if (*e
->input
!= ')') {
678 slang_info_log_error (e
->state
->elog
, "preprocess error: ')' expected.");
682 SKIP_WHITE(e
->input
);
688 expand (expand_state
*, pp_symbols
*);
691 expand_symbol (expand_state
*e
, pp_symbol
*symbol
)
695 /* If the macro has some parameters, we need to parse them. */
696 if (symbol
->parameters
.count
!= 0) {
699 /* Parse the opening parenthesis. */
700 SKIP_WHITE(e
->input
);
701 if (*e
->input
!= '(') {
702 slang_info_log_error (e
->state
->elog
, "preprocess error: '(' expected.");
706 SKIP_WHITE(e
->input
);
708 /* Parse macro actual parameters. This can be anything, separated by a colon.
710 for (i
= 0; i
< symbol
->parameters
.count
; i
++) {
711 GLuint nested_paren_count
= 0; /* track number of nested parentheses */
713 if (*e
->input
== ')') {
714 slang_info_log_error (e
->state
->elog
, "preprocess error: unexpected ')'.");
718 /* Eat all characters up to the comma or closing parentheses. */
719 pp_symbol_reset (&symbol
->parameters
.symbols
[i
]);
720 while (!IS_NULL(*e
->input
)) {
721 /* Exit loop only when all nested parens have been eaten. */
722 if (nested_paren_count
== 0 && (*e
->input
== ',' || *e
->input
== ')'))
725 /* Actually count nested parens here. */
726 if (*e
->input
== '(')
727 nested_paren_count
++;
728 else if (*e
->input
== ')')
729 nested_paren_count
--;
731 slang_string_pushc (&symbol
->parameters
.symbols
[i
].replacement
, *e
->input
++);
734 /* If it was not the last paremeter, skip the comma. Otherwise, skip the
735 * closing parentheses. */
736 if (i
+ 1 == symbol
->parameters
.count
) {
737 /* This is the last paremeter - skip the closing parentheses. */
738 if (*e
->input
!= ')') {
739 slang_info_log_error (e
->state
->elog
, "preprocess error: ')' expected.");
743 SKIP_WHITE(e
->input
);
746 /* Skip the separating comma. */
747 if (*e
->input
!= ',') {
748 slang_info_log_error (e
->state
->elog
, "preprocess error: ',' expected.");
752 SKIP_WHITE(e
->input
);
757 /* Expand the macro. Use its parameters as a priority symbol list to expand
758 * macro parameters correctly. */
759 es
.output
= e
->output
;
760 es
.input
= slang_string_cstr (&symbol
->replacement
);
762 slang_string_pushc (e
->output
, ' ');
763 if (!expand (&es
, &symbol
->parameters
))
765 slang_string_pushc (e
->output
, ' ');
770 * Function expand() expands source text from <input> to <output>. The expansion is made using
771 * the list passed in <symbols> parameter. It allows us to expand macro formal parameters with
772 * actual parameters. The global list of symbols from pp state is used when doing a recursive
777 expand (expand_state
*e
, pp_symbols
*symbols
)
779 while (!IS_NULL(*e
->input
)) {
780 if (IS_FIRST_ID_CHAR(*e
->input
)) {
784 /* Parse the identifier. */
785 slang_string_init (&buffer
);
786 slang_string_pushc (&buffer
, *e
->input
++);
787 while (IS_NEXT_ID_CHAR(*e
->input
))
788 slang_string_pushc (&buffer
, *e
->input
++);
789 id
= slang_string_cstr (&buffer
);
791 /* Now check if the identifier is special in some way. The "defined" identifier is
792 * actually an operator that we must handle here and expand it either to " 0 " or " 1 ".
793 * The other identifiers start with "__" and we expand it to appropriate values
794 * taken from the preprocessor state. */
795 if (_mesa_strcmp (id
, "defined") == 0) {
796 if (!expand_defined (e
, &buffer
))
799 else if (_mesa_strcmp (id
, "__LINE__") == 0) {
800 slang_string_pushc (e
->output
, ' ');
801 slang_string_pushi (e
->output
, e
->state
->line
);
802 slang_string_pushc (e
->output
, ' ');
804 else if (_mesa_strcmp (id
, "__FILE__") == 0) {
805 slang_string_pushc (e
->output
, ' ');
806 slang_string_pushi (e
->output
, e
->state
->file
);
807 slang_string_pushc (e
->output
, ' ');
809 else if (_mesa_strcmp (id
, "__VERSION__") == 0) {
810 slang_string_pushc (e
->output
, ' ');
811 slang_string_pushi (e
->output
, e
->state
->version
);
812 slang_string_pushc (e
->output
, ' ');
815 else if (_mesa_strcmp (id
, "GL_ES") == 0 ||
816 _mesa_strcmp (id
, "GL_FRAGMENT_PRECISION_HIGH") == 0) {
817 slang_string_pushc (e
->output
, ' ');
818 slang_string_pushi (e
->output
, '1');
819 slang_string_pushc (e
->output
, ' ');
825 /* The list of symbols from <symbols> take precedence over the list from <state>.
826 * Note that in some cases this is the same list so avoid double look-up. */
827 symbol
= pp_symbols_find (symbols
, id
);
828 if (symbol
== NULL
&& symbols
!= &e
->state
->symbols
)
829 symbol
= pp_symbols_find (&e
->state
->symbols
, id
);
831 /* If the symbol was found, recursively expand its definition. */
832 if (symbol
!= NULL
) {
833 if (!expand_symbol (e
, symbol
)) {
834 slang_string_free (&buffer
);
839 slang_string_push (e
->output
, &buffer
);
842 slang_string_free (&buffer
);
844 else if (IS_WHITE(*e
->input
)) {
845 slang_string_pushc (e
->output
, *e
->input
++);
848 while (!IS_WHITE(*e
->input
) && !IS_NULL(*e
->input
) && !IS_FIRST_ID_CHAR(*e
->input
))
849 slang_string_pushc (e
->output
, *e
->input
++);
856 parse_if (slang_string
*output
, const byte
*prod
, GLuint
*pi
, GLint
*result
, pp_state
*state
,
862 text
= (const char *) (&prod
[*pi
]);
863 len
= _mesa_strlen (text
);
865 if (state
->cond
.top
->effective
) {
871 /* Expand the expression. */
872 slang_string_init (&expr
);
876 if (!expand (&es
, &state
->symbols
))
879 /* Execute the expression. */
880 count
= execute_expressions (output
, eid
, (const byte
*) (slang_string_cstr (&expr
)),
881 results
, state
->elog
);
882 slang_string_free (&expr
);
885 *result
= results
[0];
888 /* The directive is dead. */
896 #define ESCAPE_TOKEN 0
899 #define TOKEN_DEFINE 1
900 #define TOKEN_UNDEF 2
904 #define TOKEN_ENDIF 6
905 #define TOKEN_ERROR 7
906 #define TOKEN_PRAGMA 8
907 #define TOKEN_EXTENSION 9
908 #define TOKEN_LINE 10
911 #define PARAM_PARAMETER 1
913 #define BEHAVIOR_REQUIRE 1
914 #define BEHAVIOR_ENABLE 2
915 #define BEHAVIOR_WARN 3
916 #define BEHAVIOR_DISABLE 4
918 #define PRAGMA_NO_PARAM 0
919 #define PRAGMA_PARAM 1
923 preprocess_source (slang_string
*output
, const char *source
,
924 grammar pid
, grammar eid
,
925 slang_info_log
*elog
,
926 <<<<<<< HEAD
:src
/mesa
/shader
/slang
/slang_preprocess
.c
927 const struct gl_extensions
*extensions
)
929 const struct gl_extensions
*extensions
,
930 struct gl_sl_pragmas
*pragmas
)
931 >>>>>>> origin
/master
:src
/mesa
/shader
/slang
/slang_preprocess
.c
933 static const char *predefined
[] = {
939 "GL_FRAGMENT_PRECISION_HIGH",
947 if (!grammar_fast_check (pid
, (const byte
*) (source
), &prod
, &size
, 65536)) {
948 grammar_error_to_log (elog
);
952 pp_state_init (&state
, elog
, extensions
);
953 <<<<<<< HEAD
:src
/mesa
/shader
/slang
/slang_preprocess
.c
955 pp_pragmas_init (pragmas
);
956 >>>>>>> origin
/master
:src
/mesa
/shader
/slang
/slang_preprocess
.c
958 /* add the predefined symbols to the symbol table */
959 for (i
= 0; predefined
[i
]; i
++) {
960 pp_symbol
*symbol
= NULL
;
961 symbol
= pp_symbols_push(&state
.symbols
);
963 slang_string_pushs(&symbol
->name
,
964 predefined
[i
], _mesa_strlen(predefined
[i
]));
969 if (prod
[i
] != ESCAPE_TOKEN
) {
970 if (state
.cond
.top
->effective
) {
974 /* Eat only one line of source code to expand it.
975 * FIXME: This approach has one drawback. If a macro with parameters spans across
976 * multiple lines, the preprocessor will raise an error. */
977 slang_string_init (&input
);
978 while (prod
[i
] != '\0' && prod
[i
] != '\n')
979 slang_string_pushc (&input
, prod
[i
++]);
981 slang_string_pushc (&input
, prod
[i
++]);
983 /* Increment line number. */
987 es
.input
= slang_string_cstr (&input
);
989 if (!expand (&es
, &state
.symbols
))
992 slang_string_free (&input
);
995 /* Condition stack is disabled - keep track on line numbers and output only newlines. */
996 if (prod
[i
] == '\n') {
998 /*pp_annotate (output, "%c", prod[i]);*/
1001 /*pp_annotate (output, "%c", prod[i]);*/
1016 /* End of source string.
1017 * Check if all #ifs have been terminated by matching #endifs.
1018 * On condition stack there should be only the global condition context. */
1019 if (state
.cond
.top
->endif_required
) {
1020 slang_info_log_error (elog
, "end of source without matching #endif.");
1027 pp_symbol
*symbol
= NULL
;
1029 /* Parse macro name. */
1030 id
= (const char *) (&prod
[i
]);
1031 idlen
= _mesa_strlen (id
);
1032 if (state
.cond
.top
->effective
) {
1033 pp_annotate (output
, "// #define %s(", id
);
1035 /* If the symbol is already defined, override it. */
1036 symbol
= pp_symbols_find (&state
.symbols
, id
);
1037 if (symbol
== NULL
) {
1038 symbol
= pp_symbols_push (&state
.symbols
);
1041 slang_string_pushs (&symbol
->name
, id
, idlen
);
1044 pp_symbol_reset (symbol
);
1049 /* Parse optional macro parameters. */
1050 while (prod
[i
++] != PARAM_END
) {
1051 if (state
.cond
.top
->effective
) {
1054 id
= (const char *) (&prod
[i
]);
1055 idlen
= _mesa_strlen (id
);
1056 pp_annotate (output
, "%s, ", id
);
1057 param
= pp_symbols_push (&symbol
->parameters
);
1060 slang_string_pushs (¶m
->name
, id
, idlen
);
1065 /* Parse macro replacement. */
1066 id
= (const char *) (&prod
[i
]);
1067 idlen
= _mesa_strlen (id
);
1068 if (state
.cond
.top
->effective
) {
1069 pp_annotate (output
, ") %s", id
);
1070 slang_string_pushs (&symbol
->replacement
, id
, idlen
);
1077 id
= (const char *) (&prod
[i
]);
1078 i
+= _mesa_strlen (id
) + 1;
1079 if (state
.cond
.top
->effective
) {
1082 pp_annotate (output
, "// #undef %s", id
);
1083 /* Try to find symbol with given name and remove it. */
1084 symbol
= pp_symbols_find (&state
.symbols
, id
);
1086 if (!pp_symbols_erase (&state
.symbols
, symbol
))
1095 /* Parse #if expression end execute it. */
1096 pp_annotate (output
, "// #if ");
1097 if (!parse_if (output
, prod
, &i
, &result
, &state
, eid
))
1100 /* Push new condition on the stack. */
1101 if (!pp_cond_stack_push (&state
.cond
, state
.elog
))
1103 state
.cond
.top
->current
= result
? GL_TRUE
: GL_FALSE
;
1104 state
.cond
.top
->else_allowed
= GL_TRUE
;
1105 state
.cond
.top
->endif_required
= GL_TRUE
;
1106 pp_cond_stack_reevaluate (&state
.cond
);
1111 /* Check if #else is alloved here. */
1112 if (!state
.cond
.top
->else_allowed
) {
1113 slang_info_log_error (elog
, "#else without matching #if.");
1117 /* Negate current condition and reevaluate it. */
1118 state
.cond
.top
->current
= !state
.cond
.top
->current
;
1119 state
.cond
.top
->else_allowed
= GL_FALSE
;
1120 pp_cond_stack_reevaluate (&state
.cond
);
1121 if (state
.cond
.top
->effective
)
1122 pp_annotate (output
, "// #else");
1126 /* Check if #elif is alloved here. */
1127 if (!state
.cond
.top
->else_allowed
) {
1128 slang_info_log_error (elog
, "#elif without matching #if.");
1132 /* Negate current condition and reevaluate it. */
1133 state
.cond
.top
->current
= !state
.cond
.top
->current
;
1134 pp_cond_stack_reevaluate (&state
.cond
);
1136 if (state
.cond
.top
->effective
)
1137 pp_annotate (output
, "// #elif ");
1142 /* Parse #elif expression end execute it. */
1143 if (!parse_if (output
, prod
, &i
, &result
, &state
, eid
))
1146 /* Update current condition and reevaluate it. */
1147 state
.cond
.top
->current
= result
? GL_TRUE
: GL_FALSE
;
1148 pp_cond_stack_reevaluate (&state
.cond
);
1153 /* Check if #endif is alloved here. */
1154 if (!state
.cond
.top
->endif_required
) {
1155 slang_info_log_error (elog
, "#endif without matching #if.");
1159 /* Pop the condition off the stack. */
1161 if (state
.cond
.top
->effective
)
1162 pp_annotate (output
, "// #endif");
1165 case TOKEN_EXTENSION
:
1166 /* Parse the extension name. */
1167 id
= (const char *) (&prod
[i
]);
1168 i
+= _mesa_strlen (id
) + 1;
1169 if (state
.cond
.top
->effective
)
1170 pp_annotate (output
, "// #extension %s: ", id
);
1172 /* Parse and apply extension behavior. */
1173 if (state
.cond
.top
->effective
) {
1174 switch (prod
[i
++]) {
1176 case BEHAVIOR_REQUIRE
:
1177 pp_annotate (output
, "require");
1178 if (!pp_ext_set (&state
.ext
, id
, GL_TRUE
)) {
1179 if (_mesa_strcmp (id
, "all") == 0) {
1180 slang_info_log_error (elog
, "require: bad behavior for #extension all.");
1184 slang_info_log_error (elog
, "%s: required extension is not supported.", id
);
1190 case BEHAVIOR_ENABLE
:
1191 pp_annotate (output
, "enable");
1192 if (!pp_ext_set (&state
.ext
, id
, GL_TRUE
)) {
1193 if (_mesa_strcmp (id
, "all") == 0) {
1194 slang_info_log_error (elog
, "enable: bad behavior for #extension all.");
1198 slang_info_log_warning (elog
, "%s: enabled extension is not supported.", id
);
1204 pp_annotate (output
, "warn");
1205 if (!pp_ext_set (&state
.ext
, id
, GL_TRUE
)) {
1206 if (_mesa_strcmp (id
, "all") != 0) {
1207 slang_info_log_warning (elog
, "%s: enabled extension is not supported.", id
);
1212 case BEHAVIOR_DISABLE
:
1213 pp_annotate (output
, "disable");
1214 if (!pp_ext_set (&state
.ext
, id
, GL_FALSE
)) {
1215 if (_mesa_strcmp (id
, "all") == 0) {
1216 pp_ext_disable_all (&state
.ext
);
1219 slang_info_log_warning (elog
, "%s: disabled extension is not supported.", id
);
1233 const char *pragma
, *param
;
1235 pragma
= (const char *) (&prod
[i
]);
1236 i
+= _mesa_strlen(pragma
) + 1;
1237 have_param
= (prod
[i
++] == PRAGMA_PARAM
);
1239 param
= (const char *) (&prod
[i
]);
1240 i
+= _mesa_strlen(param
) + 1;
1245 pp_pragma(pragmas
, pragma
, param
);
1250 id
= (const char *) (&prod
[i
]);
1251 i
+= _mesa_strlen (id
) + 1;
1253 if (state
.cond
.top
->effective
) {
1254 slang_string buffer
;
1259 slang_string_init (&buffer
);
1261 es
.output
= &buffer
;
1264 if (!expand (&es
, &state
.symbols
))
1267 pp_annotate (output
, "// #line ");
1268 count
= execute_expressions (output
, eid
,
1269 (const byte
*) (slang_string_cstr (&buffer
)),
1270 results
, state
.elog
);
1271 slang_string_free (&buffer
);
1275 state
.line
= results
[0] - 1;
1277 state
.file
= results
[1];
1284 /* Check for missing #endifs. */
1285 if (state
.cond
.top
->endif_required
) {
1286 slang_info_log_error (elog
, "#endif expected but end of source found.");
1290 grammar_alloc_free(prod
);
1291 pp_state_free (&state
);
1295 grammar_alloc_free(prod
);
1296 pp_state_free (&state
);
1302 * Run preprocessor on source code.
1303 * \param extensions indicates which GL extensions are enabled
1304 * \param output the post-process results
1305 * \param input the input text
1306 * \param elog log to record warnings, errors
1307 * \return GL_TRUE for success, GL_FALSE for error
1310 _slang_preprocess_directives(slang_string
*output
,
1312 slang_info_log
*elog
,
1313 <<<<<<< HEAD
:src
/mesa
/shader
/slang
/slang_preprocess
.c
1314 const struct gl_extensions
*extensions
)
1316 const struct gl_extensions
*extensions
,
1317 struct gl_sl_pragmas
*pragmas
)
1318 >>>>>>> origin
/master
:src
/mesa
/shader
/slang
/slang_preprocess
.c
1323 pid
= grammar_load_from_text ((const byte
*) (slang_pp_directives_syn
));
1325 grammar_error_to_log (elog
);
1328 eid
= grammar_load_from_text ((const byte
*) (slang_pp_expression_syn
));
1330 grammar_error_to_log (elog
);
1331 grammar_destroy (pid
);
1334 <<<<<<< HEAD
:src
/mesa
/shader
/slang
/slang_preprocess
.c
1335 success
= preprocess_source (output
, input
, pid
, eid
, elog
, extensions
);
1337 success
= preprocess_source (output
, input
, pid
, eid
, elog
, extensions
, pragmas
);
1338 >>>>>>> origin
/master
:src
/mesa
/shader
/slang
/slang_preprocess
.c
1339 grammar_destroy (eid
);
1340 grammar_destroy (pid
);