Add support for the structure of function-like macros.

We accept the structure of arguments in both macro definition and
macro invocation, but we don't yet expand those arguments. This is
just enough code to pass the recently-added tests, but does not yet
provide any sort of useful function-like macro.
This commit is contained in:
Carl Worth
2010-05-13 09:36:23 -07:00
parent 4abc3dec72
commit fcbbb46886
4 changed files with 214 additions and 34 deletions
+189 -25
View File
@@ -24,12 +24,19 @@
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <talloc.h>
#include "glcpp.h"
#define YYLEX_PARAM parser->scanner
typedef struct {
int is_function;
list_t *parameter_list;
list_t *replacement_list;
} macro_t;
struct glcpp_parser {
yyscan_t scanner;
struct hash_table *defines;
@@ -39,13 +46,32 @@ void
yyerror (void *scanner, const char *error);
void
_print_expanded_macro (glcpp_parser_t *parser, const char *macro);
_define_object_macro (glcpp_parser_t *parser,
const char *macro,
list_t *replacement_list);
void
_define_function_macro (glcpp_parser_t *parser,
const char *macro,
list_t *parameter_list,
list_t *replacement_list);
void
_print_expanded_object_macro (glcpp_parser_t *parser, const char *macro);
void
_print_expanded_function_macro (glcpp_parser_t *parser,
const char *macro,
list_t *arguments);
list_t *
_list_create (void *ctx);
void
_list_append (list_t *list, const char *str);
_list_append_item (list_t *list, const char *str);
void
_list_append_list (list_t *list, list_t *tail);
%}
@@ -57,9 +83,9 @@ _list_append (list_t *list, const char *str);
%parse-param {glcpp_parser_t *parser}
%lex-param {void *scanner}
%token DEFINE IDENTIFIER MACRO NEWLINE TOKEN UNDEF
%type <str> IDENTIFIER MACRO TOKEN string
%type <list> replacement_list
%token DEFINE FUNC_MACRO IDENTIFIER NEWLINE OBJ_MACRO TOKEN UNDEF
%type <str> FUNC_MACRO IDENTIFIER OBJ_MACRO TOKEN string
%type <list> argument argument_list parameter_list replacement_list
%%
@@ -77,16 +103,48 @@ content:
printf ("%s", $1);
talloc_free ($1);
}
| MACRO {
_print_expanded_macro (parser, $1);
talloc_free ($1);
}
| macro
| directive_with_newline
| NEWLINE {
printf ("\n");
}
;
macro:
FUNC_MACRO '(' argument_list ')' {
_print_expanded_function_macro (parser, $1, $3);
}
| OBJ_MACRO {
_print_expanded_object_macro (parser, $1);
talloc_free ($1);
}
;
argument_list:
/* empty */ {
$$ = _list_create (parser);
}
| argument {
$$ = _list_create (parser);
_list_append_list ($$, $1);
}
| argument_list ',' argument {
_list_append_list ($1, $3);
$$ = $1;
}
;
argument:
/* empty */ {
$$ = _list_create (parser);
}
| argument string {
_list_append_item ($1, $2);
talloc_free ($2);
}
| argument '(' argument ')'
;
directive_with_newline:
directive NEWLINE {
printf ("\n");
@@ -95,10 +153,23 @@ directive_with_newline:
directive:
DEFINE IDENTIFIER replacement_list {
talloc_steal ($3, $2);
hash_table_insert (parser->defines, $3, $2);
_define_object_macro (parser, $2, $3);
}
| UNDEF MACRO {
| DEFINE IDENTIFIER '(' parameter_list ')' replacement_list {
_define_function_macro (parser, $2, $4, $6);
}
| UNDEF FUNC_MACRO {
list_t *replacement = hash_table_find (parser->defines, $2);
if (replacement) {
/* XXX: Need hash table to support a real way
* to remove an element rather than prefixing
* a new node with data of NULL like this. */
hash_table_insert (parser->defines, NULL, $2);
talloc_free (replacement);
}
talloc_free ($2);
}
| UNDEF OBJ_MACRO {
list_t *replacement = hash_table_find (parser->defines, $2);
if (replacement) {
/* XXX: Need hash table to support a real way
@@ -115,17 +186,33 @@ replacement_list:
/* empty */ {
$$ = _list_create (parser);
}
| replacement_list string {
_list_append ($1, $2);
_list_append_item ($1, $2);
talloc_free ($2);
$$ = $1;
}
;
parameter_list:
/* empty */ {
$$ = _list_create (parser);
}
| IDENTIFIER {
$$ = _list_create (parser);
_list_append_item ($$, $1);
talloc_free ($1);
}
| parameter_list ',' IDENTIFIER {
_list_append_item ($1, $3);
talloc_free ($3);
$$ = $1;
}
;
string:
IDENTIFIER { $$ = $1; }
| MACRO { $$ = $1; }
| FUNC_MACRO { $$ = $1; }
| OBJ_MACRO { $$ = $1; }
| TOKEN { $$ = $1; }
;
@@ -144,7 +231,19 @@ _list_create (void *ctx)
}
void
_list_append (list_t *list, const char *str)
_list_append_list (list_t *list, list_t *tail)
{
if (list->head == NULL) {
list->head = tail->head;
} else {
list->tail->next = tail->head;
}
list->tail = tail->tail;
}
void
_list_append_item (list_t *list, const char *str)
{
node_t *node;
@@ -196,10 +295,20 @@ glcpp_parser_destroy (glcpp_parser_t *parser)
talloc_free (parser);
}
int
glcpp_parser_macro_defined (glcpp_parser_t *parser, const char *identifier)
macro_type_t
glcpp_parser_macro_type (glcpp_parser_t *parser, const char *identifier)
{
return (hash_table_find (parser->defines, identifier) != NULL);
macro_t *macro;
macro = hash_table_find (parser->defines, identifier);
if (macro == NULL)
return MACRO_TYPE_UNDEFINED;
if (macro->is_function)
return MACRO_TYPE_FUNCTION;
else
return MACRO_TYPE_OBJECT;
}
static void
@@ -208,15 +317,17 @@ _print_expanded_macro_recursive (glcpp_parser_t *parser,
const char *orig,
int *first)
{
list_t *replacement;
macro_t *macro;
node_t *node;
replacement = hash_table_find (parser->defines, token);
if (replacement == NULL) {
macro = hash_table_find (parser->defines, token);
if (macro == NULL) {
printf ("%s%s", *first ? "" : " ", token);
*first = 0;
} else {
for (node = replacement->head ; node ; node = node->next) {
list_t *replacement_list = macro->replacement_list;
for (node = replacement_list->head ; node ; node = node->next) {
token = node->str;
if (strcmp (token, orig) == 0) {
printf ("%s%s", *first ? "" : " ", token);
@@ -231,9 +342,62 @@ _print_expanded_macro_recursive (glcpp_parser_t *parser,
}
void
_print_expanded_macro (glcpp_parser_t *parser, const char *macro)
_define_object_macro (glcpp_parser_t *parser,
const char *identifier,
list_t *replacement_list)
{
macro_t *macro;
macro = xtalloc (parser, macro_t);
macro->is_function = 0;
macro->parameter_list = NULL;
macro->replacement_list = talloc_steal (macro, replacement_list);
hash_table_insert (parser->defines, macro, identifier);
}
void
_define_function_macro (glcpp_parser_t *parser,
const char *identifier,
list_t *parameter_list,
list_t *replacement_list)
{
macro_t *macro;
macro = xtalloc (parser, macro_t);
macro->is_function = 1;
macro->parameter_list = talloc_steal (macro, parameter_list);
macro->replacement_list = talloc_steal (macro, replacement_list);
hash_table_insert (parser->defines, macro, identifier);
}
void
_print_expanded_object_macro (glcpp_parser_t *parser, const char *identifier)
{
int first = 1;
macro_t *macro;
_print_expanded_macro_recursive (parser, macro, macro, &first);
macro = hash_table_find (parser->defines, identifier);
assert (! macro->is_function);
_print_expanded_macro_recursive (parser, identifier, identifier, &first);
}
void
_print_expanded_function_macro (glcpp_parser_t *parser,
const char *identifier,
list_t *arguments)
{
int first = 1;
macro_t *macro;
macro = hash_table_find (parser->defines, identifier);
assert (macro->is_function);
/* XXX: Need to use argument list here in the expansion. */
_print_expanded_macro_recursive (parser, identifier, identifier, &first);
}