mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2025-12-28 03:50:13 +01:00
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:
parent
df2ab5b992
commit
33cc400714
5 changed files with 203 additions and 54 deletions
7
Makefile
7
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 $^
|
||||
|
|
|
|||
34
glcpp-lex.l
34
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>{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;
|
||||
}
|
||||
|
||||
%%
|
||||
|
|
|
|||
181
glcpp-parse.y
181
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");
|
||||
}
|
||||
;
|
||||
|
||||
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
10
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;
|
||||
}
|
||||
|
|
|
|||
25
glcpp.h
25
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 */
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue