summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarl Worth <cworth@cworth.org>2010-05-13 09:36:23 -0700
committerCarl Worth <cworth@cworth.org>2010-05-13 09:36:23 -0700
commitfcbbb4688641e46270ba0cd531639df9b964f697 (patch)
tree9116a800bc5a1778efe398cafdacc92abb090fd5
parent4abc3dec720933e78a266417cffb2ea7b16d497f (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--Makefile2
-rw-r--r--glcpp-lex.l20
-rw-r--r--glcpp-parse.y214
-rw-r--r--glcpp.h12
4 files changed, 214 insertions, 34 deletions
diff --git a/Makefile b/Makefile
index 7233150a80..c5472a86b3 100644
--- a/Makefile
+++ b/Makefile
@@ -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);
}
diff --git a/glcpp.h b/glcpp.h
index 39d6d5d0eb..69b3b840ae 100644
--- a/glcpp.h
+++ b/glcpp.h
@@ -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 */