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.
This commit is contained in:
Carl Worth 2010-05-12 12:17:10 -07:00
parent df2ab5b992
commit 33cc400714
5 changed files with 203 additions and 54 deletions

View file

@ -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 $^

View file

@ -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>{HSPACE}+
<ST_DEFINE>{IDENTIFIER} { BEGIN ST_DEFVAL; yylval = strdup (yytext); return IDENTIFIER; }
<ST_DEFINE>{IDENTIFIER} {
yylval.str = strdup (yytext);
return IDENTIFIER;
}
<ST_DEFVAL>{SPACE}+
<ST_DEFVAL>{DEFVAL} { BEGIN INITIAL; yylval = strdup (yytext); return DEFVAL; }
<ST_DEFINE>{TOKEN} {
yylval.str = strdup (yytext);
return TOKEN;
}
<ST_DEFINE>\n {
BEGIN INITIAL;
return NEWLINE;
}
<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;
}
%%

View file

@ -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");
}
;
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;
}
;
token: TOKEN { printf ("%s", _resolve_token (parser, $1)); free ($1); }
;
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;
list_t *replacement;
node_t *node;
while (1) {
replacement = hash_table_find (parser->defines, token);
if (replacement == NULL)
break;
token = replacement;
if (strcmp (token, orig) == 0)
break;
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);
}

10
glcpp.c
View file

@ -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;
}

25
glcpp.h
View file

@ -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 */