summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarl Worth <cworth@cworth.org>2010-05-20 22:27:07 -0700
committerCarl Worth <cworth@cworth.org>2010-05-20 22:27:07 -0700
commitb20d33c5c6fea8e392c26e9ab060efd14034f1f9 (patch)
tree0285aa21a9c693a155d02a1b1f715137b49f494c
parentd8327e575dd20fe696f3a44ada4bd4001b15db27 (diff)
Implement #if, #else, #elif, and #endif with tests.
So far the only expression implemented is a single integer literal, but obviously that's easy to extend. Various things including nesting are tested here.
-rw-r--r--glcpp-lex.l32
-rw-r--r--glcpp-parse.y109
-rw-r--r--glcpp.h12
-rw-r--r--tests/040-token-pasting.c2
-rw-r--r--tests/041-if-0.c5
-rw-r--r--tests/042-if-1.c5
-rw-r--r--tests/043-if-0-else.c7
-rw-r--r--tests/044-if-1-else.c7
-rw-r--r--tests/045-if-0-elif.c11
-rw-r--r--tests/046-if-1-elsif.c11
-rw-r--r--tests/047-if-elif-else.c11
-rw-r--r--tests/048-if-nested.c11
-rwxr-xr-xtests/glcpp-test2
13 files changed, 221 insertions, 4 deletions
diff --git a/glcpp-lex.l b/glcpp-lex.l
index 6138a9de12..825ce3d370 100644
--- a/glcpp-lex.l
+++ b/glcpp-lex.l
@@ -36,6 +36,7 @@
%x ST_DEFINE_OBJ_OR_FUNC
%x ST_DEFINE_PARAMETER
%x ST_DEFINE_VALUE
+%x ST_IF
%x ST_UNDEF
%x ST_UNDEF_END
@@ -44,11 +45,42 @@ NONSPACE [^[:space:]]
NEWLINE [\n]
HSPACE [ \t]
HASH ^{HSPACE}*#{HSPACE}*
+INTEGER [0-9]+
IDENTIFIER [_a-zA-Z][_a-zA-Z0-9]*
TOKEN [^[:space:](),]+
%%
+{HASH}if{HSPACE}* {
+ BEGIN ST_IF;
+ return IF;
+}
+
+{HASH}elif{HSPACE}* {
+ BEGIN ST_IF;
+ return ELIF;
+}
+
+<ST_IF>{INTEGER} {
+ yylval.ival = atoi (yytext);
+ return INTEGER;
+}
+
+<ST_IF>{HSPACE}+
+
+<ST_IF>\n {
+ BEGIN INITIAL;
+ return NEWLINE;
+}
+
+{HASH}endif{HSPACE}* {
+ return ENDIF;
+}
+
+{HASH}else{HSPACE}* {
+ return ELSE;
+}
+
{HASH}undef{HSPACE}* {
BEGIN ST_UNDEF;
return UNDEF;
diff --git a/glcpp-parse.y b/glcpp-parse.y
index aa758f7e43..26432f2032 100644
--- a/glcpp-parse.y
+++ b/glcpp-parse.y
@@ -89,6 +89,16 @@ _token_list_append_list (token_list_t *list, token_list_t *tail);
static void
glcpp_parser_pop_expansion (glcpp_parser_t *parser);
+static void
+_glcpp_parser_skip_stack_push_if (glcpp_parser_t *parser, int condition);
+
+static void
+_glcpp_parser_skip_stack_change_if (glcpp_parser_t *parser, const char *type,
+ int condition);
+
+static void
+_glcpp_parser_skip_stack_pop (glcpp_parser_t *parser);
+
#define yylex glcpp_parser_lex
static int
@@ -108,8 +118,8 @@ glcpp_parser_lex (glcpp_parser_t *parser);
%parse-param {glcpp_parser_t *parser}
%lex-param {glcpp_parser_t *parser}
-%token DEFINE FUNC_MACRO IDENTIFIER IDENTIFIER_FINALIZED OBJ_MACRO NEWLINE SEPARATOR SPACE TOKEN UNDEF
-%type <ival> punctuator
+%token DEFINE ELIF ELSE ENDIF FUNC_MACRO IDENTIFIER IDENTIFIER_FINALIZED IF IFDEF IFNDEF INTEGER OBJ_MACRO NEWLINE SEPARATOR 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
@@ -143,8 +153,12 @@ input:
}
| input content {
int is_token;
+ int skipping = 0;
+
+ if (parser->skip_stack && parser->skip_stack->type != SKIP_NO_SKIP)
+ skipping = 1;
- if ($2 && strlen ($2)) {
+ if ($2 && strlen ($2) && ! skipping) {
int c = $2[0];
int is_not_separator = ((c >= 'a' && c <= 'z') ||
(c >= 'A' && c <= 'Z') ||
@@ -301,6 +315,28 @@ directive:
| DEFINE IDENTIFIER '(' parameter_list ')' replacement_list NEWLINE {
_define_function_macro (parser, $2, $4, $6);
}
+| IF expression NEWLINE {
+ _glcpp_parser_skip_stack_push_if (parser, $2);
+ }
+| IFDEF IDENTIFIER NEWLINE {
+ string_list_t *macro = hash_table_find (parser->defines, $2);
+ talloc_free ($2);
+ _glcpp_parser_skip_stack_push_if (parser, macro != NULL);
+ }
+| IFNDEF IDENTIFIER NEWLINE {
+ string_list_t *macro = hash_table_find (parser->defines, $2);
+ talloc_free ($2);
+ _glcpp_parser_skip_stack_push_if (parser, macro == NULL);
+ }
+| ELIF expression NEWLINE {
+ _glcpp_parser_skip_stack_change_if (parser, "#elif", $2);
+ }
+| ELSE {
+ _glcpp_parser_skip_stack_change_if (parser, "else", 1);
+ }
+| ENDIF {
+ _glcpp_parser_skip_stack_pop (parser);
+ }
| UNDEF IDENTIFIER {
string_list_t *macro = hash_table_find (parser->defines, $2);
if (macro) {
@@ -314,6 +350,13 @@ directive:
}
;
+/* XXX: Need to fill out with all operators. */
+expression:
+ INTEGER {
+ $$ = $1;
+ }
+;
+
parameter_list:
/* empty */ {
$$ = _string_list_create (parser);
@@ -567,6 +610,8 @@ glcpp_parser_create (void)
parser->just_printed_separator = 1;
parser->need_newline = 0;
+ parser->skip_stack = NULL;
+
return parser;
}
@@ -581,6 +626,8 @@ glcpp_parser_destroy (glcpp_parser_t *parser)
{
if (parser->need_newline)
printf ("\n");
+ if (parser->skip_stack)
+ fprintf (stderr, "Error: Unterminated #if\n");
glcpp_lex_destroy (parser->scanner);
hash_table_dtor (parser->defines);
talloc_free (parser);
@@ -829,3 +876,59 @@ glcpp_parser_lex (glcpp_parser_t *parser)
break;
}
}
+
+static void
+_glcpp_parser_skip_stack_push_if (glcpp_parser_t *parser, int condition)
+{
+ skip_type_t current = SKIP_NO_SKIP;
+ skip_node_t *node;
+
+ if (parser->skip_stack)
+ current = parser->skip_stack->type;
+
+ node = xtalloc (parser, skip_node_t);
+
+ if (current == SKIP_NO_SKIP) {
+ if (condition)
+ node->type = SKIP_NO_SKIP;
+ else
+ node->type = SKIP_TO_ELSE;
+ } else {
+ node->type = SKIP_TO_ENDIF;
+ }
+
+ node->next = parser->skip_stack;
+ parser->skip_stack = node;
+}
+
+static void
+_glcpp_parser_skip_stack_change_if (glcpp_parser_t *parser, const char *type,
+ int condition)
+{
+ if (parser->skip_stack == NULL) {
+ fprintf (stderr, "Error: %s without #if\n", type);
+ exit (1);
+ }
+
+ if (parser->skip_stack->type == SKIP_TO_ELSE) {
+ if (condition)
+ parser->skip_stack->type = SKIP_NO_SKIP;
+ } else {
+ parser->skip_stack->type = SKIP_TO_ENDIF;
+ }
+}
+
+static void
+_glcpp_parser_skip_stack_pop (glcpp_parser_t *parser)
+{
+ skip_node_t *node;
+
+ if (parser->skip_stack == NULL) {
+ fprintf (stderr, "Error: #endif without #if\n");
+ exit (1);
+ }
+
+ node = parser->skip_stack;
+ parser->skip_stack = node->next;
+ talloc_free (node);
+}
diff --git a/glcpp.h b/glcpp.h
index 1537109ada..33ece8f92b 100644
--- a/glcpp.h
+++ b/glcpp.h
@@ -95,12 +95,24 @@ typedef struct expansion_node {
struct expansion_node *next;
} expansion_node_t;
+typedef enum skip_type {
+ SKIP_NO_SKIP,
+ SKIP_TO_ELSE,
+ SKIP_TO_ENDIF
+} skip_type_t;
+
+typedef struct skip_node {
+ skip_type_t type;
+ struct skip_node *next;
+} skip_node_t;
+
struct glcpp_parser {
yyscan_t scanner;
struct hash_table *defines;
expansion_node_t *expansions;
int just_printed_separator;
int need_newline;
+ skip_node_t *skip_stack;
};
void
diff --git a/tests/040-token-pasting.c b/tests/040-token-pasting.c
new file mode 100644
index 0000000000..caab3ba736
--- /dev/null
+++ b/tests/040-token-pasting.c
@@ -0,0 +1,2 @@
+#define paste(a,b) a ## b
+paste(one , token)
diff --git a/tests/041-if-0.c b/tests/041-if-0.c
new file mode 100644
index 0000000000..2cab677d3e
--- /dev/null
+++ b/tests/041-if-0.c
@@ -0,0 +1,5 @@
+success_1
+#if 0
+failure
+#endif
+success_2
diff --git a/tests/042-if-1.c b/tests/042-if-1.c
new file mode 100644
index 0000000000..874a25cf41
--- /dev/null
+++ b/tests/042-if-1.c
@@ -0,0 +1,5 @@
+success_1
+#if 1
+success_2
+#endif
+success_3
diff --git a/tests/043-if-0-else.c b/tests/043-if-0-else.c
new file mode 100644
index 0000000000..323351f9db
--- /dev/null
+++ b/tests/043-if-0-else.c
@@ -0,0 +1,7 @@
+success_1
+#if 0
+failure
+#else
+success_2
+#endif
+success_3
diff --git a/tests/044-if-1-else.c b/tests/044-if-1-else.c
new file mode 100644
index 0000000000..28dfc25c6f
--- /dev/null
+++ b/tests/044-if-1-else.c
@@ -0,0 +1,7 @@
+success_1
+#if 1
+success_2
+#else
+failure
+#endif
+success_3
diff --git a/tests/045-if-0-elif.c b/tests/045-if-0-elif.c
new file mode 100644
index 0000000000..e50f686d46
--- /dev/null
+++ b/tests/045-if-0-elif.c
@@ -0,0 +1,11 @@
+success_1
+#if 0
+failure_1
+#elif 0
+failure_2
+#elif 1
+success_3
+#elif 1
+failure_3
+#endif
+success_4
diff --git a/tests/046-if-1-elsif.c b/tests/046-if-1-elsif.c
new file mode 100644
index 0000000000..130515a01e
--- /dev/null
+++ b/tests/046-if-1-elsif.c
@@ -0,0 +1,11 @@
+success_1
+#if 1
+success_2
+#elif 0
+failure_1
+#elif 1
+failure_2
+#elif 0
+failure_3
+#endif
+success_3
diff --git a/tests/047-if-elif-else.c b/tests/047-if-elif-else.c
new file mode 100644
index 0000000000..e8f0838a9e
--- /dev/null
+++ b/tests/047-if-elif-else.c
@@ -0,0 +1,11 @@
+success_1
+#if 0
+failure_1
+#elif 0
+failure_2
+#elif 0
+failure_3
+#else
+success_2
+#endif
+success_3
diff --git a/tests/048-if-nested.c b/tests/048-if-nested.c
new file mode 100644
index 0000000000..fc4679c3be
--- /dev/null
+++ b/tests/048-if-nested.c
@@ -0,0 +1,11 @@
+success_1
+#if 0
+failure_1
+#if 1
+failure_2
+#else
+failure_3
+#endif
+failure_4
+#endif
+success_2
diff --git a/tests/glcpp-test b/tests/glcpp-test
index 25685eeabe..022a236712 100755
--- a/tests/glcpp-test
+++ b/tests/glcpp-test
@@ -5,5 +5,5 @@ for test in *.c; do
../glcpp < $test > $test.out
gcc -E $test -o $test.gcc
grep -v '^#' < $test.gcc > $test.expected
- diff -u $test.expected $test.out
+ diff -B -u $test.expected $test.out
done