Add support for the structure of function-like macros.
authorCarl Worth <cworth@cworth.org>
Thu, 13 May 2010 16:36:23 +0000 (09:36 -0700)
committerCarl Worth <cworth@cworth.org>
Thu, 13 May 2010 16:36:23 +0000 (09:36 -0700)
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.

Makefile
glcpp-lex.l
glcpp-parse.y
glcpp.h

index 7233150a80b33503e38c81bba5adb21abf3b53f2..c5472a86b3c3f5a2505362b72a65b1930766b5af 100644 (file)
--- 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/*~
index 3622db939e748b19796852254d8b047adac7f6bc..c6e545aa8ed2802d92794d16f2529d8fdf96ee7a 100644 (file)
@@ -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;
index 4d6475497bf9688a7b190f5a44f8ff4fd65f31f8..2e40db525b8ec02ae167c8cb46c8692d083c214e 100644 (file)
 
 #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 39d6d5d0ebb2812d2d365c6785b564ca94fd4ce0..69b3b840aed8670934f53c39709ed05c9574eccd 100644 (file)
--- 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 */