Fix defines involving both literals and other defined macros.
authorCarl Worth <cworth@cworth.org>
Wed, 12 May 2010 19:17:10 +0000 (12:17 -0700)
committerCarl Worth <cworth@cworth.org>
Wed, 12 May 2010 19:25:34 +0000 (12:25 -0700)
We now store a list of tokens in our hash-table rather than a single
string. This lets us replace each macro in the value as necessary.

This code adds a link dependency on talloc which does exactly what we
want in terms of memory management for a parser.

The 3 tests added in the previous commit now pass.

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

index 38cc1f314a9330933ab1c24d5f5199dedf86d5ec..83519328bf6011c1fb6b440e3847a5bcea6c3a53 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,13 @@
+# Debug symbols by default, but let the user avoid that with something
+# like "make CFLAGS=-O2"
+CFLAGS = -g
+
+# But we use 'override' here so that "make CFLAGS=-O2" will still have
+# all the warnings enabled.
 override CFLAGS += -Wall -Wextra -Wwrite-strings -Wswitch-enum -Wno-unused
 
 glcpp: glcpp.o glcpp-lex.o glcpp-parse.o hash_table.o
+       gcc -o $@ -ltalloc $^
 
 %.c %.h: %.y
        bison --debug --defines=$*.h --output=$*.c $^
index a220fef76bfaf0cc81380ab7dbfdeb31512497e7..f1a356077947815b9b3b7efcd1ae82262e55a4d8 100644 (file)
 
 SPACE          [[:space:]]
 NONSPACE       [^[:space:]]
-NOTNEWLINE     [^\n]
+NEWLINE                [\n]
 HSPACE         [ \t]
 HASH           ^{HSPACE}*#
 IDENTIFIER     [_a-zA-Z][_a-zA-Z0-9]*
-DEFVAL         {NONSPACE}{NOTNEWLINE}*
+TOKEN          {NONSPACE}+
+
 %%
 
-{HASH}define           { BEGIN ST_DEFINE; return DEFINE; }
+{HASH}define{HSPACE}*  {
+       BEGIN ST_DEFINE;
+       return DEFINE;
+}
+
+<ST_DEFINE>{IDENTIFIER}        {
+       yylval.str = strdup (yytext);
+       return IDENTIFIER;
+}
+
+<ST_DEFINE>{TOKEN} {
+       yylval.str = strdup (yytext);
+       return TOKEN;
+}
 
-<ST_DEFINE>{HSPACE}+
-<ST_DEFINE>{IDENTIFIER}        { BEGIN ST_DEFVAL; yylval = strdup (yytext); return IDENTIFIER; }
+<ST_DEFINE>\n {
+       BEGIN INITIAL;
+       return NEWLINE;
+}
 
-<ST_DEFVAL>{SPACE}+
-<ST_DEFVAL>{DEFVAL}    { BEGIN INITIAL; yylval = strdup (yytext); return DEFVAL; }
+<ST_DEFINE>{SPACE}+
 
        /* Anything we don't specifically recognize is a stream of tokens */
-{NONSPACE}+            { yylval = strdup (yytext); return TOKEN; }
+{NONSPACE}+ {
+       yylval.str = strdup (yytext);
+       return TOKEN;
+}
 
 %%
index a3a661b8befcb1d5c9a22abf031c309b8a18b4dc..eae96efb30a4ccd2372f7797d88a779940bce1af 100644 (file)
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <talloc.h>
 
 #include "glcpp.h"
 
 #define YYLEX_PARAM parser->scanner
 
+struct glcpp_parser {
+       yyscan_t scanner;
+       struct hash_table *defines;
+};
+
 void
 yyerror (void *scanner, const char *error);
 
-const char *
-_resolve_token (glcpp_parser_t *parser, const char *token);
+void
+_print_resolved_token (glcpp_parser_t *parser, const char *token);
+
+list_t *
+_list_create (void *ctx);
+
+void
+_list_append (list_t *list, const char *str);
 
 %}
 
+%union {
+       char *str;
+       list_t *list;
+}
+
 %parse-param {glcpp_parser_t *parser}
 %lex-param {void *scanner}
 
-%token DEFINE
-%token DEFVAL
-%token IDENTIFIER
-%token TOKEN
+%token DEFINE IDENTIFIER NEWLINE TOKEN
+%type <str> token IDENTIFIER TOKEN
+%type <list> replacement_list
 
 %%
 
-input:         /* empty */
-       |       content
+input:
+       /* empty */
+|      content
 ;
 
-content:       token
-       |       directive
-       |       content token
-       |       content directive
+content:
+       token {
+               _print_resolved_token (parser, $1);
+               free ($1);
+       }
+|      directive
+|      content token {
+               _print_resolved_token (parser, $2);
+               free ($2);
+       }
+|      content directive
 ;
 
-directive:     DEFINE IDENTIFIER DEFVAL {
-       hash_table_insert (parser->defines, $3, $2);
-}
+directive:
+       DEFINE IDENTIFIER replacement_list NEWLINE {
+               char *key = talloc_strdup ($3, $2);
+               free ($2);
+               hash_table_insert (parser->defines, $3, key);
+               printf ("\n");
+       }
 ;
 
-token:         TOKEN { printf ("%s", _resolve_token (parser, $1)); free ($1); }
+replacement_list:
+       /* empty */ {
+               $$ = _list_create (parser);
+       }
+
+|      replacement_list token {
+               _list_append ($1, $2);
+               free ($2);
+               $$ = $1;
+       }
+;
+
+token:
+       TOKEN { $$ = $1; }
+|      IDENTIFIER { $$ = $1; }
 ;
 
 %%
 
+list_t *
+_list_create (void *ctx)
+{
+       list_t *list;
+
+       list = talloc (ctx, list_t);
+       if (list == NULL) {
+               fprintf (stderr, "Out of memory.\n");
+               exit (1);
+       }
+
+       list->head = NULL;
+       list->tail = NULL;
+
+       return list;
+}
+
+void
+_list_append (list_t *list, const char *str)
+{
+       node_t *node;
+
+       node = talloc (list, node_t);
+       if (node == NULL) {
+               fprintf (stderr, "Out of memory.\n");
+               exit (1);
+       }
+
+       node->str = talloc_strdup (node, str);
+       if (node->str == NULL) {
+               fprintf (stderr, "Out of memory.\n");
+               exit (1);
+       }
+               
+       node->next = NULL;
+
+       if (list->head == NULL) {
+               list->head = node;
+       } else {
+               list->tail->next = node;
+       }
+
+       list->tail = node;
+}
+               
 void
 yyerror (void *scanner, const char *error)
 {
        fprintf (stderr, "Parse error: %s\n", error);
 }
 
-void
-glcpp_parser_init (glcpp_parser_t *parser)
+glcpp_parser_t *
+glcpp_parser_create (void)
 {
+       glcpp_parser_t *parser;
+
+       parser = talloc (NULL, glcpp_parser_t);
+       if (parser == NULL) {
+               fprintf (stderr, "Out of memory.\n");
+               exit (1);
+       }
+
        yylex_init (&parser->scanner);
        parser->defines = hash_table_ctor (32, hash_table_string_hash,
                                           hash_table_string_compare);
+
+       return parser;
 }
 
 int
@@ -88,27 +185,43 @@ glcpp_parser_parse (glcpp_parser_t *parser)
 }
 
 void
-glcpp_parser_fini (glcpp_parser_t *parser)
+glcpp_parser_destroy (glcpp_parser_t *parser)
 {
        yylex_destroy (parser->scanner);
        hash_table_dtor (parser->defines);
+       talloc_free (parser);
 }
 
-const char *
-_resolve_token (glcpp_parser_t *parser, const char *token)
+static void
+_print_resolved_recursive (glcpp_parser_t *parser,
+                          const char *token,
+                          const char *orig,
+                          int *first)
 {
-       const char *orig = token;
-       const char *replacement;
-
-       while (1) {
-               replacement = hash_table_find (parser->defines, token);
-               if (replacement == NULL)
-                       break;
-               token = replacement;
-               if (strcmp (token, orig) == 0)
-                       break;
+       list_t *replacement;
+       node_t *node;
+
+       replacement = hash_table_find (parser->defines, token);
+       if (replacement == NULL) {
+               printf ("%s%s", *first ? "" : " ", token);
+               *first = 0;
+       } else {
+               for (node = replacement->head ; node ; node = node->next) {
+                       token = node->str;
+                       if (strcmp (token, orig) == 0) {
+                               printf ("%s%s", *first ? "" : " ", token);
+                               *first = 0;
+                       } else {
+                               _print_resolved_recursive (parser, token, orig, first);
+                       }
+               }
        }
-
-       return token;
 }
 
+void
+_print_resolved_token (glcpp_parser_t *parser, const char *token)
+{
+       int first = 1;
+
+       _print_resolved_recursive (parser, token, token, &first);
+}
diff --git a/glcpp.c b/glcpp.c
index d6c89df2f95fdeda495662d9f14507776476f6b7..fcdc4ed8a0f53f4d785cbb37290e39b02887172c 100644 (file)
--- a/glcpp.c
+++ b/glcpp.c
 
 #include "glcpp.h"
 
+extern int yydebug;
+
 int
 main (void)
 {
-       glcpp_parser_t parser;
+       glcpp_parser_t *parser;
        int ret;
 
-       glcpp_parser_init (&parser);
+       parser = glcpp_parser_create ();
 
-       ret = glcpp_parser_parse (&parser);
+       ret = glcpp_parser_parse (parser);
 
-       glcpp_parser_fini (&parser);
+       glcpp_parser_destroy (parser);
 
        return ret;
 }
diff --git a/glcpp.h b/glcpp.h
index 5278e1b971be40e5cafcef9076f0c25670f58852..6fea9333e858e84de7f2768710261838fa328819 100644 (file)
--- a/glcpp.h
+++ b/glcpp.h
 
 #include "hash_table.h"
 
-#define YYSTYPE char *
 #define yyscan_t void*
 
-typedef struct {
-       yyscan_t scanner;
-       struct hash_table *defines;
-} glcpp_parser_t;
+/* Some data types used for parser value. */
 
-void
-glcpp_parser_init (glcpp_parser_t *parser);
+
+typedef struct node {
+       const char *str;
+       struct node *next;
+} node_t;
+
+typedef struct list {
+       node_t *head;
+       node_t *tail;
+} list_t;
+
+typedef struct glcpp_parser glcpp_parser_t;
+
+glcpp_parser_t *
+glcpp_parser_create (void);
 
 int
 glcpp_parser_parse (glcpp_parser_t *parser);
 
 void
-glcpp_parser_fini (glcpp_parser_t *parser);
+glcpp_parser_destroy (glcpp_parser_t *parser);
 
 /* Generated by glcpp-lex.l to glcpp-lex.c */