summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarl Worth <cworth@cworth.org>2010-05-24 10:37:38 -0700
committerCarl Worth <cworth@cworth.org>2010-05-24 10:37:38 -0700
commitbcbd587b0f5312d85307785ee2df6e5906af4f7b (patch)
treeb44d1115168ddf3bb401c56a1938a6813718cbdc
parentb20d33c5c6fea8e392c26e9ab060efd14034f1f9 (diff)
Implement all operators specified for GLSL #if expressions (with tests).
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.
-rw-r--r--glcpp-lex.l45
-rw-r--r--glcpp-parse.y97
-rw-r--r--tests/049-if-expression-precedence.c6
-rw-r--r--tests/050-if-defined.c19
-rw-r--r--tests/051-if-relational.c35
5 files changed, 195 insertions, 7 deletions
diff --git a/glcpp-lex.l b/glcpp-lex.l
index 825ce3d370..84166fb76f 100644
--- a/glcpp-lex.l
+++ b/glcpp-lex.l
@@ -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 {
diff --git a/glcpp-parse.y b/glcpp-parse.y
index 26432f2032..0d3afa7af6 100644
--- a/glcpp-parse.y
+++ b/glcpp-parse.y
@@ -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
index 0000000000..cea935220f
--- /dev/null
+++ b/tests/049-if-expression-precedence.c
@@ -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
index 0000000000..9838cc747d
--- /dev/null
+++ b/tests/050-if-defined.c
@@ -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
index 0000000000..c3db488e0d
--- /dev/null
+++ b/tests/051-if-relational.c
@@ -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