diff options
author | Carl Worth <[email protected]> | 2014-07-02 12:52:33 -0700 |
---|---|---|
committer | Ian Romanick <[email protected]> | 2014-08-07 16:08:29 -0700 |
commit | 218e878b5491210dd0bc27a9171f88fa23278f4e (patch) | |
tree | ba848c26d0ae7f1c7dfa9f615205fa9b04322e28 /src/glsl/glcpp/tests/142-defined-within-macro.c | |
parent | a48ff781c1cac00ad432edf88fafa44e667fa90f (diff) |
glsl/glcpp: Fix for macros that expand to include "defined" operators
Prior to this commit, the following snippet would trigger an error in glcpp:
#define FOO defined BAR
#if FOO
#endif
The problem was that support for the "defined" operator was implemented within
the grammar, (where the parser was parsing the tokens of the condition
itself). But what is required is to interpret the "defined" operator that
results after macro expansion is performed.
I could not find any fix for this case by modifying the grammar alone. The
difficulty is that outside of the grammar we already have a recursive function
that performs macro expansion (_glcpp_parser_expand_token_list) and that
function itself must be augmented to be made aware of the semantics of the
"defined" operator.
The reason we can't simply handle "defined" outside of the recursive expansion
function is that not only must we scan for any "defined" operators in the
original condition (before any macro expansion occurs); but at each level of
the recursive expansion, we must again scan the list of tokens resulting from
expansion and handle "defined" before entering the next level of recursion to
further expand macros.
And of course, all of this is context dependent. The evaluation of "defined"
operators must only happen when we are handling preprocessor conditionals,
(#if and #elif) and not when performing any other expansion, (such as in the
main body).
To implement this, we add a new "mode" parameter to all of the expansion
functions to specify whether resulting DEFINED tokens should be evaluated or
ignored.
One side benefit of this change is that an ugly wart in the grammar is
removed. We previously had "conditional_token" and "conditional_tokens"
productions that were basically copies of "pp_token" and "pp_tokens" but with
added productions for the various forms of DEFINED operators. With the new
code here, those ugly copy-and-paste productions are eliminated from the
grammar.
A new "make check" test is added to stress-test the code here.
This commit fixes the following Khronos GLES3 CTS tests:
conditional_inclusion.basic_2_vertex
conditional_inclusion.basic_2_fragment
Reviewed-by: Ian Romanick <[email protected]>
Diffstat (limited to 'src/glsl/glcpp/tests/142-defined-within-macro.c')
-rw-r--r-- | src/glsl/glcpp/tests/142-defined-within-macro.c | 94 |
1 files changed, 94 insertions, 0 deletions
diff --git a/src/glsl/glcpp/tests/142-defined-within-macro.c b/src/glsl/glcpp/tests/142-defined-within-macro.c new file mode 100644 index 00000000000..b60c04232a6 --- /dev/null +++ b/src/glsl/glcpp/tests/142-defined-within-macro.c @@ -0,0 +1,94 @@ +/* Macro using defined with a hard-coded identifier (no parentheses) */ +#define is_foo_defined defined /*...*/ foo +#undef foo +#if is_foo_defined +failure +#else +success +#endif +#define foo +#if is_foo_defined +success +#else +failure +#endif + +/* Macro using defined with a hard-coded identifier within parentheses */ +#define is_foo_defined_parens defined /*...*/ ( /*...*/ foo /*...*/ ) // +#define foo +#if is_foo_defined_parens +success +#else +failure +#endif +#undef foo +#if is_foo_defined_parens +failure +#else +success +#endif + +/* Macro using defined with an argument identifier (no parentheses) */ +#define is_defined(arg) defined /*...*/ arg +#define foo bar +#undef bar +#if is_defined(foo) +failure +#else +success +#endif +#define bar bar +#if is_defined(foo) +success +#else +failure +#endif + +/* Macro using defined with an argument identifier within parentheses */ +#define is_defined_parens(arg) defined /*...*/ ( /*...*/ arg /*...*/ ) // +#define foo bar +#define bar bar +#if is_defined_parens(foo) +success +#else +failure +#endif +#undef bar +#if is_defined_parens(foo) +failure +#else +success +#endif + +/* Multiple levels of macro resulting in defined */ +#define X defined A && Y +#define Y defined B && Z +#define Z defined C +#define A +#define B +#define C +#if X +success +#else +failure +#endif +#undef A +#if X +failure +#else +success +#endif +#define A +#undef B +#if X +failure +#else +success +#endif +#define B +#undef C +#if X +failure +#else +success +#endif |