Implement all operators specified for GLSL #if expressions (with tests).
authorCarl Worth <cworth@cworth.org>
Mon, 24 May 2010 17:37:38 +0000 (10:37 -0700)
committerCarl Worth <cworth@cworth.org>
Mon, 24 May 2010 17:37:38 +0000 (10:37 -0700)
The operator coverage here is quite complete. The one big thing
missing is that we are not yet doing macro expansion in #if
lines. This makes the whole support fairly useless, so we plan to fix
that shortcoming right away.

glcpp-lex.l
glcpp-parse.y
tests/049-if-expression-precedence.c [new file with mode: 0644]
tests/050-if-defined.c [new file with mode: 0644]
tests/051-if-relational.c [new file with mode: 0644]

index 825ce3d370925457e8cd822bac12587d609684ae..84166fb76fc2fcf2edffc6e206007f13bb9f492f 100644 (file)
@@ -66,6 +66,51 @@ TOKEN                [^[:space:](),]+
        return INTEGER;
 }
 
+<ST_IF>"defined" {
+       return DEFINED;
+}
+
+<ST_IF>"<<" {
+       return LEFT_SHIFT;
+}
+
+<ST_IF>">>" {
+       return RIGHT_SHIFT;
+}
+
+<ST_IF>"<=" {
+       return LESS_OR_EQUAL;
+}
+
+<ST_IF>">=" {
+       return GREATER_OR_EQUAL;
+}
+
+<ST_IF>"==" {
+       return EQUAL;
+}
+
+<ST_IF>"!=" {
+       return NOT_EQUAL;
+}
+
+<ST_IF>"&&" {
+       return AND;
+}
+
+<ST_IF>"||" {
+       return OR;
+}
+
+<ST_IF>[-+*/%<>&^|()] {
+       return yytext[0];
+}
+
+<ST_IF>{IDENTIFIER} {
+       yylval.str = xtalloc_strdup (yyextra, yytext);
+       return IDENTIFIER;
+}
+
 <ST_IF>{HSPACE}+
 
 <ST_IF>\n {
index 26432f203254ff29884b74a8b998f21b47f1cc25..0d3afa7af64c8ae9573d0a36633400dba5416357 100644 (file)
@@ -118,13 +118,24 @@ glcpp_parser_lex (glcpp_parser_t *parser);
 %parse-param {glcpp_parser_t *parser}
 %lex-param {glcpp_parser_t *parser}
 
-%token DEFINE ELIF ELSE ENDIF FUNC_MACRO IDENTIFIER IDENTIFIER_FINALIZED IF IFDEF IFNDEF INTEGER OBJ_MACRO NEWLINE SEPARATOR SPACE TOKEN UNDEF
+%token DEFINE DEFINED ELIF ELSE ENDIF FUNC_MACRO IDENTIFIER IDENTIFIER_FINALIZED IF IFDEF IFNDEF INTEGER OBJ_MACRO NEWLINE SPACE TOKEN UNDEF
 %type <ival> expression INTEGER punctuator
 %type <str> content FUNC_MACRO IDENTIFIER IDENTIFIER_FINALIZED OBJ_MACRO
 %type <argument_list> argument_list
 %type <string_list> macro parameter_list
 %type <token> TOKEN argument_word argument_word_or_comma
 %type <token_list> argument argument_or_comma replacement_list pp_tokens
+%left OR
+%left AND
+%left '|'
+%left '^'
+%left '&'
+%left EQUAL NOT_EQUAL
+%left '<' '>' LESS_OR_EQUAL GREATER_OR_EQUAL
+%left LEFT_SHIFT RIGHT_SHIFT
+%left '+' '-'
+%left '*' '/' '%'
+%right UNARY
 
 /* Hard to remove shift/reduce conflicts documented as follows:
  *
@@ -142,11 +153,7 @@ glcpp_parser_lex (glcpp_parser_t *parser);
 
 %%
 
-       /* We do all printing at the input level.
-        *
-        * The value for "input" is simply TOKEN or SEPARATOR so we
-        * can decide whether it's necessary to print a space
-        * character between any two. */
+        /* We do all printing at the input level. */
 input:
        /* empty */ {
                parser->just_printed_separator = 1;
@@ -350,11 +357,87 @@ directive:
        }
 ;
 
-/* XXX: Need to fill out with all operators. */
 expression:
        INTEGER {
                $$ = $1;
        }
+|      expression OR expression {
+               $$ = $1 || $3;
+       }
+|      expression AND expression {
+               $$ = $1 && $3;
+       }
+|      expression '|' expression {
+               $$ = $1 | $3;
+       }
+|      expression '^' expression {
+               $$ = $1 ^ $3;
+       }
+|      expression '&' expression {
+               $$ = $1 & $3;
+       }
+|      expression NOT_EQUAL expression {
+               $$ = $1 != $3;
+       }
+|      expression EQUAL expression {
+               $$ = $1 == $3;
+       }
+|      expression GREATER_OR_EQUAL expression {
+               $$ = $1 >= $3;
+       }
+|      expression LESS_OR_EQUAL expression {
+               $$ = $1 <= $3;
+       }
+|      expression '>' expression {
+               $$ = $1 > $3;
+       }
+|      expression '<' expression {
+               $$ = $1 < $3;
+       }
+|      expression RIGHT_SHIFT expression {
+               $$ = $1 >> $3;
+       }
+|      expression LEFT_SHIFT expression {
+               $$ = $1 << $3;
+       }
+|      expression '-' expression {
+               $$ = $1 - $3;
+       }
+|      expression '+' expression {
+               $$ = $1 + $3;
+       }
+|      expression '%' expression {
+               $$ = $1 % $3;
+       }
+|      expression '/' expression {
+               $$ = $1 / $3;
+       }
+|      expression '*' expression {
+               $$ = $1 * $3;
+       }
+|      '!' expression %prec UNARY {
+               $$ = ! $2;
+       }
+|      '~' expression %prec UNARY {
+               $$ = ~ $2;
+       }
+|      '-' expression %prec UNARY {
+               $$ = - $2;
+       }
+|      '+' expression %prec UNARY {
+               $$ = + $2;
+       }
+|      DEFINED IDENTIFIER %prec UNARY {
+               string_list_t *macro = hash_table_find (parser->defines, $2);
+               talloc_free ($2);
+               if (macro)
+                       $$ = 1;
+               else
+                       $$ = 0;
+       }
+|      '(' expression ')' {
+               $$ = $2;
+       }
 ;
 
 parameter_list:
diff --git a/tests/049-if-expression-precedence.c b/tests/049-if-expression-precedence.c
new file mode 100644 (file)
index 0000000..cea9352
--- /dev/null
@@ -0,0 +1,6 @@
+#if 1 + 2 * 3 + - (25 % 17 - + 1)
+failure with operator precedence
+#else
+success
+#endif
+
diff --git a/tests/050-if-defined.c b/tests/050-if-defined.c
new file mode 100644 (file)
index 0000000..9838cc7
--- /dev/null
@@ -0,0 +1,19 @@
+#if defined foo
+failure_1
+#else
+success_1
+#endif
+#define foo
+#if defined foo
+success_2
+#else
+failure_2
+#endif
+#undef foo
+#if defined foo
+failure_3
+#else
+success_3
+#endif
+
+
diff --git a/tests/051-if-relational.c b/tests/051-if-relational.c
new file mode 100644 (file)
index 0000000..c3db488
--- /dev/null
@@ -0,0 +1,35 @@
+#if 3 < 2
+failure_1
+#else
+success_1
+#endif
+
+#if 3 >= 2
+success_2
+#else
+failure_2
+#endif
+
+#if 2 + 3 <= 5
+success_3
+#else
+failure_3
+#endif
+
+#if 3 - 2 == 1
+success_3
+#else
+failure_3
+#endif
+
+#if 1 > 3
+failure_4
+#else
+success_4
+#endif
+
+#if 1 != 5
+success_5
+#else
+failure_5
+#endif