summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarl Worth <cworth@cworth.org>2010-05-12 12:17:10 -0700
committerCarl Worth <cworth@cworth.org>2010-05-12 12:25:34 -0700
commit33cc400714f379ef13e876b4aedd0de8cb5d033d (patch)
treeeb0fcb9c900079aebdab63af41d001af56e9736d
parentdf2ab5b99237ab0b6760226554b133a5ccd11579 (diff)
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.
-rw-r--r--Makefile7
-rw-r--r--glcpp-lex.l34
-rw-r--r--glcpp-parse.y179
-rw-r--r--glcpp.c10
-rw-r--r--glcpp.h25
5 files changed, 202 insertions, 53 deletions
diff --git a/Makefile b/Makefile
index 38cc1f314a..83519328bf 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 a220fef76b..f1a3560779 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;
+}
+
+<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;
+}
%%
diff --git a/glcpp-parse.y b/glcpp-parse.y
index a3a661b8be..eae96efb30 100644
--- a/glcpp-parse.y
+++ b/glcpp-parse.y
@@ -24,61 +24,158 @@
#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 d6c89df2f9..fcdc4ed8a0 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 5278e1b971..6fea9333e8 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 */