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:
+147
-34
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user