mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-05-09 02:28:10 +02:00
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.
This commit is contained in:
parent
d8327e575d
commit
b20d33c5c6
13 changed files with 221 additions and 4 deletions
32
glcpp-lex.l
32
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;
|
||||
|
|
|
|||
109
glcpp-parse.y
109
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 ($2 && strlen ($2)) {
|
||||
if (parser->skip_stack && parser->skip_stack->type != SKIP_NO_SKIP)
|
||||
skipping = 1;
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
|
|||
12
glcpp.h
12
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
|
||||
|
|
|
|||
2
tests/040-token-pasting.c
Normal file
2
tests/040-token-pasting.c
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
#define paste(a,b) a ## b
|
||||
paste(one , token)
|
||||
5
tests/041-if-0.c
Normal file
5
tests/041-if-0.c
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
success_1
|
||||
#if 0
|
||||
failure
|
||||
#endif
|
||||
success_2
|
||||
5
tests/042-if-1.c
Normal file
5
tests/042-if-1.c
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
success_1
|
||||
#if 1
|
||||
success_2
|
||||
#endif
|
||||
success_3
|
||||
7
tests/043-if-0-else.c
Normal file
7
tests/043-if-0-else.c
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
success_1
|
||||
#if 0
|
||||
failure
|
||||
#else
|
||||
success_2
|
||||
#endif
|
||||
success_3
|
||||
7
tests/044-if-1-else.c
Normal file
7
tests/044-if-1-else.c
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
success_1
|
||||
#if 1
|
||||
success_2
|
||||
#else
|
||||
failure
|
||||
#endif
|
||||
success_3
|
||||
11
tests/045-if-0-elif.c
Normal file
11
tests/045-if-0-elif.c
Normal file
|
|
@ -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
|
||||
11
tests/046-if-1-elsif.c
Normal file
11
tests/046-if-1-elsif.c
Normal file
|
|
@ -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
|
||||
11
tests/047-if-elif-else.c
Normal file
11
tests/047-if-elif-else.c
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
success_1
|
||||
#if 0
|
||||
failure_1
|
||||
#elif 0
|
||||
failure_2
|
||||
#elif 0
|
||||
failure_3
|
||||
#else
|
||||
success_2
|
||||
#endif
|
||||
success_3
|
||||
11
tests/048-if-nested.c
Normal file
11
tests/048-if-nested.c
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
success_1
|
||||
#if 0
|
||||
failure_1
|
||||
#if 1
|
||||
failure_2
|
||||
#else
|
||||
failure_3
|
||||
#endif
|
||||
failure_4
|
||||
#endif
|
||||
success_2
|
||||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue