diff options
author | Carl Worth <cworth@cworth.org> | 2010-05-13 09:36:23 -0700 |
---|---|---|
committer | Carl Worth <cworth@cworth.org> | 2010-05-13 09:36:23 -0700 |
commit | fcbbb4688641e46270ba0cd531639df9b964f697 (patch) | |
tree | 9116a800bc5a1778efe398cafdacc92abb090fd5 | |
parent | 4abc3dec720933e78a266417cffb2ea7b16d497f (diff) |
Add support for the structure of function-like macros.
We accept the structure of arguments in both macro definition and
macro invocation, but we don't yet expand those arguments. This is
just enough code to pass the recently-added tests, but does not yet
provide any sort of useful function-like macro.
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | glcpp-lex.l | 20 | ||||
-rw-r--r-- | glcpp-parse.y | 214 | ||||
-rw-r--r-- | glcpp.h | 12 |
4 files changed, 214 insertions, 34 deletions
@@ -22,4 +22,4 @@ test: clean: rm -f glcpp-lex.c glcpp-parse.c *.o *~ - rm -f tests/*.out tests/*.gcc tests/*.expected + rm -f tests/*.out tests/*.gcc tests/*.expected tests/*~ diff --git a/glcpp-lex.l b/glcpp-lex.l index 3622db939e..c6e545aa8e 100644 --- a/glcpp-lex.l +++ b/glcpp-lex.l @@ -38,7 +38,7 @@ NEWLINE [\n] HSPACE [ \t] HASH ^{HSPACE}*# IDENTIFIER [_a-zA-Z][_a-zA-Z0-9]* -TOKEN {NONSPACE}+ +TOKEN [^[:space:](),]+ %% @@ -53,12 +53,22 @@ TOKEN {NONSPACE}+ {IDENTIFIER} { yylval.str = xtalloc_strdup (yyextra, yytext); - if (glcpp_parser_macro_defined (yyextra, yylval.str)) - return MACRO; - else - return IDENTIFIER; + switch (glcpp_parser_macro_type (yyextra, yylval.str)) + { + case MACRO_TYPE_UNDEFINED: + return IDENTIFIER; + break; + case MACRO_TYPE_OBJECT: + return OBJ_MACRO; + break; + case MACRO_TYPE_FUNCTION: + return FUNC_MACRO; + break; + } } +[(),] { return yytext[0]; } + {TOKEN} { yylval.str = xtalloc_strdup (yyextra, yytext); return TOKEN; diff --git a/glcpp-parse.y b/glcpp-parse.y index 4d6475497b..2e40db525b 100644 --- a/glcpp-parse.y +++ b/glcpp-parse.y @@ -24,12 +24,19 @@ #include <stdio.h> #include <stdlib.h> +#include <assert.h> #include <talloc.h> #include "glcpp.h" #define YYLEX_PARAM parser->scanner +typedef struct { + int is_function; + list_t *parameter_list; + list_t *replacement_list; +} macro_t; + struct glcpp_parser { yyscan_t scanner; struct hash_table *defines; @@ -39,13 +46,32 @@ void yyerror (void *scanner, const char *error); void -_print_expanded_macro (glcpp_parser_t *parser, const char *macro); +_define_object_macro (glcpp_parser_t *parser, + const char *macro, + list_t *replacement_list); + +void +_define_function_macro (glcpp_parser_t *parser, + const char *macro, + list_t *parameter_list, + list_t *replacement_list); + +void +_print_expanded_object_macro (glcpp_parser_t *parser, const char *macro); + +void +_print_expanded_function_macro (glcpp_parser_t *parser, + const char *macro, + list_t *arguments); list_t * _list_create (void *ctx); void -_list_append (list_t *list, const char *str); +_list_append_item (list_t *list, const char *str); + +void +_list_append_list (list_t *list, list_t *tail); %} @@ -57,9 +83,9 @@ _list_append (list_t *list, const char *str); %parse-param {glcpp_parser_t *parser} %lex-param {void *scanner} -%token DEFINE IDENTIFIER MACRO NEWLINE TOKEN UNDEF -%type <str> IDENTIFIER MACRO TOKEN string -%type <list> replacement_list +%token DEFINE FUNC_MACRO IDENTIFIER NEWLINE OBJ_MACRO TOKEN UNDEF +%type <str> FUNC_MACRO IDENTIFIER OBJ_MACRO TOKEN string +%type <list> argument argument_list parameter_list replacement_list %% @@ -77,16 +103,48 @@ content: printf ("%s", $1); talloc_free ($1); } -| MACRO { - _print_expanded_macro (parser, $1); - talloc_free ($1); - } +| macro | directive_with_newline | NEWLINE { printf ("\n"); } ; +macro: + FUNC_MACRO '(' argument_list ')' { + _print_expanded_function_macro (parser, $1, $3); + } +| OBJ_MACRO { + _print_expanded_object_macro (parser, $1); + talloc_free ($1); + } +; + +argument_list: + /* empty */ { + $$ = _list_create (parser); + } +| argument { + $$ = _list_create (parser); + _list_append_list ($$, $1); + } +| argument_list ',' argument { + _list_append_list ($1, $3); + $$ = $1; + } +; + +argument: + /* empty */ { + $$ = _list_create (parser); + } +| argument string { + _list_append_item ($1, $2); + talloc_free ($2); + } +| argument '(' argument ')' +; + directive_with_newline: directive NEWLINE { printf ("\n"); @@ -95,10 +153,23 @@ directive_with_newline: directive: DEFINE IDENTIFIER replacement_list { - talloc_steal ($3, $2); - hash_table_insert (parser->defines, $3, $2); + _define_object_macro (parser, $2, $3); + } +| DEFINE IDENTIFIER '(' parameter_list ')' replacement_list { + _define_function_macro (parser, $2, $4, $6); + } +| UNDEF FUNC_MACRO { + list_t *replacement = hash_table_find (parser->defines, $2); + if (replacement) { + /* XXX: Need hash table to support a real way + * to remove an element rather than prefixing + * a new node with data of NULL like this. */ + hash_table_insert (parser->defines, NULL, $2); + talloc_free (replacement); + } + talloc_free ($2); } -| UNDEF MACRO { +| UNDEF OBJ_MACRO { list_t *replacement = hash_table_find (parser->defines, $2); if (replacement) { /* XXX: Need hash table to support a real way @@ -115,17 +186,33 @@ replacement_list: /* empty */ { $$ = _list_create (parser); } - | replacement_list string { - _list_append ($1, $2); + _list_append_item ($1, $2); talloc_free ($2); $$ = $1; } ; +parameter_list: + /* empty */ { + $$ = _list_create (parser); + } +| IDENTIFIER { + $$ = _list_create (parser); + _list_append_item ($$, $1); + talloc_free ($1); + } +| parameter_list ',' IDENTIFIER { + _list_append_item ($1, $3); + talloc_free ($3); + $$ = $1; + } +; + string: IDENTIFIER { $$ = $1; } -| MACRO { $$ = $1; } +| FUNC_MACRO { $$ = $1; } +| OBJ_MACRO { $$ = $1; } | TOKEN { $$ = $1; } ; @@ -144,7 +231,19 @@ _list_create (void *ctx) } void -_list_append (list_t *list, const char *str) +_list_append_list (list_t *list, list_t *tail) +{ + if (list->head == NULL) { + list->head = tail->head; + } else { + list->tail->next = tail->head; + } + + list->tail = tail->tail; +} + +void +_list_append_item (list_t *list, const char *str) { node_t *node; @@ -196,10 +295,20 @@ glcpp_parser_destroy (glcpp_parser_t *parser) talloc_free (parser); } -int -glcpp_parser_macro_defined (glcpp_parser_t *parser, const char *identifier) +macro_type_t +glcpp_parser_macro_type (glcpp_parser_t *parser, const char *identifier) { - return (hash_table_find (parser->defines, identifier) != NULL); + macro_t *macro; + + macro = hash_table_find (parser->defines, identifier); + + if (macro == NULL) + return MACRO_TYPE_UNDEFINED; + + if (macro->is_function) + return MACRO_TYPE_FUNCTION; + else + return MACRO_TYPE_OBJECT; } static void @@ -208,15 +317,17 @@ _print_expanded_macro_recursive (glcpp_parser_t *parser, const char *orig, int *first) { - list_t *replacement; + macro_t *macro; node_t *node; - replacement = hash_table_find (parser->defines, token); - if (replacement == NULL) { + macro = hash_table_find (parser->defines, token); + if (macro == NULL) { printf ("%s%s", *first ? "" : " ", token); *first = 0; } else { - for (node = replacement->head ; node ; node = node->next) { + list_t *replacement_list = macro->replacement_list; + + for (node = replacement_list->head ; node ; node = node->next) { token = node->str; if (strcmp (token, orig) == 0) { printf ("%s%s", *first ? "" : " ", token); @@ -231,9 +342,62 @@ _print_expanded_macro_recursive (glcpp_parser_t *parser, } void -_print_expanded_macro (glcpp_parser_t *parser, const char *macro) +_define_object_macro (glcpp_parser_t *parser, + const char *identifier, + list_t *replacement_list) +{ + macro_t *macro; + + macro = xtalloc (parser, macro_t); + + macro->is_function = 0; + macro->parameter_list = NULL; + macro->replacement_list = talloc_steal (macro, replacement_list); + + hash_table_insert (parser->defines, macro, identifier); +} + +void +_define_function_macro (glcpp_parser_t *parser, + const char *identifier, + list_t *parameter_list, + list_t *replacement_list) +{ + macro_t *macro; + + macro = xtalloc (parser, macro_t); + + macro->is_function = 1; + macro->parameter_list = talloc_steal (macro, parameter_list); + macro->replacement_list = talloc_steal (macro, replacement_list); + + hash_table_insert (parser->defines, macro, identifier); +} + +void +_print_expanded_object_macro (glcpp_parser_t *parser, const char *identifier) { int first = 1; + macro_t *macro; + + macro = hash_table_find (parser->defines, identifier); + assert (! macro->is_function); + + _print_expanded_macro_recursive (parser, identifier, identifier, &first); +} + +void +_print_expanded_function_macro (glcpp_parser_t *parser, + const char *identifier, + list_t *arguments) +{ + int first = 1; + macro_t *macro; + + macro = hash_table_find (parser->defines, identifier); + assert (macro->is_function); + + /* XXX: Need to use argument list here in the expansion. */ - _print_expanded_macro_recursive (parser, macro, macro, &first); + _print_expanded_macro_recursive (parser, identifier, identifier, &first); } @@ -52,9 +52,15 @@ glcpp_parser_parse (glcpp_parser_t *parser); void glcpp_parser_destroy (glcpp_parser_t *parser); -int -glcpp_parser_macro_defined (glcpp_parser_t *parser, - const char *identifier); +typedef enum { + MACRO_TYPE_UNDEFINED, + MACRO_TYPE_OBJECT, + MACRO_TYPE_FUNCTION +} macro_type_t; + +macro_type_t +glcpp_parser_macro_type (glcpp_parser_t *parser, + const char *identifier); /* Generated by glcpp-lex.l to glcpp-lex.c */ |