From 33cc400714f379ef13e876b4aedd0de8cb5d033d Mon Sep 17 00:00:00 2001 From: Carl Worth Date: Wed, 12 May 2010 12:17:10 -0700 Subject: [PATCH] Fix defines involving both literals and other defined macros. 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 | 7 ++ glcpp-lex.l | 34 +++++++--- glcpp-parse.y | 179 ++++++++++++++++++++++++++++++++++++++++---------- glcpp.c | 10 +-- glcpp.h | 25 ++++--- 5 files changed, 202 insertions(+), 53 deletions(-) diff --git a/Makefile b/Makefile index 38cc1f314a9..83519328bf6 100644 --- 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 $^ diff --git a/glcpp-lex.l b/glcpp-lex.l index a220fef76bf..f1a35607794 100644 --- a/glcpp-lex.l +++ b/glcpp-lex.l @@ -36,22 +36,40 @@ 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; +} + +{IDENTIFIER} { + yylval.str = strdup (yytext); + return IDENTIFIER; +} + +{TOKEN} { + yylval.str = strdup (yytext); + return TOKEN; +} -{HSPACE}+ -{IDENTIFIER} { BEGIN ST_DEFVAL; yylval = strdup (yytext); return IDENTIFIER; } +\n { + BEGIN INITIAL; + return NEWLINE; +} -{SPACE}+ -{DEFVAL} { BEGIN INITIAL; yylval = strdup (yytext); return DEFVAL; } +{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; +} %% diff --git a/glcpp-parse.y b/glcpp-parse.y index a3a661b8bef..eae96efb30a 100644 --- a/glcpp-parse.y +++ b/glcpp-parse.y @@ -24,61 +24,158 @@ #include #include +#include #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 token IDENTIFIER TOKEN +%type 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 d6c89df2f95..fcdc4ed8a0f 100644 --- a/glcpp.c +++ b/glcpp.c @@ -23,17 +23,19 @@ #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 5278e1b971b..6fea9333e85 100644 --- a/glcpp.h +++ b/glcpp.h @@ -26,22 +26,31 @@ #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 */ -- 2.30.2