mirror of
git://projects.qi-hardware.com/eda-tools.git
synced 2024-11-26 08:19:42 +02:00
b2/: add parsing of substitution rules (WIP)
This commit is contained in:
parent
d8f5c95ecb
commit
9fd1dc56e7
@ -13,7 +13,8 @@ SHELL = /bin/bash
|
|||||||
|
|
||||||
CFLAGS = -g -Wall $(shell pkg-config --cflags glib-2.0)
|
CFLAGS = -g -Wall $(shell pkg-config --cflags glib-2.0)
|
||||||
SLOPPY = -Wno-unused -Wno-implicit-function-declaration
|
SLOPPY = -Wno-unused -Wno-implicit-function-declaration
|
||||||
OBJS = boom.o chr.o comp.o db.o dump.o eval.o param.o util.o lex.yy.o y.tab.o
|
OBJS = boom.o chr.o comp.o db.o dump.o eval.o param.o subst.o util.o \
|
||||||
|
lex.yy.o y.tab.o
|
||||||
LDLIBS = -lfl $(shell pkg-config --libs glib-2.0)
|
LDLIBS = -lfl $(shell pkg-config --libs glib-2.0)
|
||||||
|
|
||||||
YACC = bison -y
|
YACC = bison -y
|
||||||
@ -83,4 +84,5 @@ spotless: clean
|
|||||||
# ----- Experiments -----------------------------------------------------------
|
# ----- Experiments -----------------------------------------------------------
|
||||||
|
|
||||||
try:
|
try:
|
||||||
$(VALGRIND) ./boom HIERARCHY -c CHAR -x CURR -p PROVIDER -i INV
|
$(VALGRIND) ./boom HIERARCHY -c CHAR -x CURR -p PROVIDER -i INV \
|
||||||
|
-s SUBST
|
||||||
|
25
b2/SUBST
Normal file
25
b2/SUBST
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
REF=R[0-9]* {
|
||||||
|
T=R
|
||||||
|
VAL=.* { R=$$#R }
|
||||||
|
TOL = 5%
|
||||||
|
FN=.*% { TOL=${$#%} }
|
||||||
|
break REF
|
||||||
|
// end break again
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
pattern: () * ? .
|
||||||
|
subst: $1 ... $field
|
||||||
|
|
||||||
|
substring:
|
||||||
|
$1, $2, ...
|
||||||
|
variable:
|
||||||
|
$foo, ...
|
||||||
|
with curly braces:
|
||||||
|
${foo}, ...
|
||||||
|
unit conversion:
|
||||||
|
$foo#V
|
||||||
|
${1#R}
|
||||||
|
input variable:
|
||||||
|
$$
|
||||||
|
*/
|
@ -26,6 +26,7 @@ static void usage(const char *name)
|
|||||||
" -i inventory\n"
|
" -i inventory\n"
|
||||||
" -x currency exchange\n"
|
" -x currency exchange\n"
|
||||||
" -p providers\n"
|
" -p providers\n"
|
||||||
|
" -s substitutions\n"
|
||||||
, name);
|
, name);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
@ -46,6 +47,8 @@ int main(int argc, char **argv)
|
|||||||
parse = parse_currencies;
|
parse = parse_currencies;
|
||||||
else if (!strcmp(argv[i], "-p"))
|
else if (!strcmp(argv[i], "-p"))
|
||||||
parse = parse_providers;
|
parse = parse_providers;
|
||||||
|
else if (!strcmp(argv[i], "-s"))
|
||||||
|
parse = parse_substitutions;
|
||||||
else
|
else
|
||||||
usage(*argv);
|
usage(*argv);
|
||||||
} else {
|
} else {
|
||||||
|
@ -18,9 +18,10 @@ void parse_characteristics(const char *name);
|
|||||||
void parse_inventory(const char *name);
|
void parse_inventory(const char *name);
|
||||||
void parse_currencies(const char *name);
|
void parse_currencies(const char *name);
|
||||||
void parse_providers(const char *name);
|
void parse_providers(const char *name);
|
||||||
|
void parse_substitutions(const char *name);
|
||||||
|
|
||||||
void yywarnf(const char *fmt, ...);
|
void yywarnf(const char *fmt, ...);
|
||||||
void yyerrorf(const char *fmt, ...);
|
void __attribute__((noreturn)) yyerrorf(const char *fmt, ...);
|
||||||
void yyerror(const char *s);
|
void __attribute__((noreturn)) yyerror(const char *s);
|
||||||
|
|
||||||
#endif /* !LANG_H */
|
#endif /* !LANG_H */
|
||||||
|
37
b2/lang.l
37
b2/lang.l
@ -26,6 +26,7 @@ extern int yyparse(void);
|
|||||||
|
|
||||||
static int start_token;
|
static int start_token;
|
||||||
static int expose_nl;
|
static int expose_nl;
|
||||||
|
static int pattern;
|
||||||
static const char *file_name;
|
static const char *file_name;
|
||||||
static int lineno;
|
static int lineno;
|
||||||
|
|
||||||
@ -46,12 +47,13 @@ static void open_stdin(const char *name)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void do_parse(const char *name, int start, int nl)
|
static void do_parse(const char *name, int start, int nl, int pat)
|
||||||
{
|
{
|
||||||
open_stdin(name);
|
open_stdin(name);
|
||||||
|
|
||||||
start_token = start;
|
start_token = start;
|
||||||
expose_nl = nl;
|
expose_nl = nl;
|
||||||
|
pattern = pat;
|
||||||
file_name = unique(name);
|
file_name = unique(name);
|
||||||
lineno = 1;
|
lineno = 1;
|
||||||
yyparse();
|
yyparse();
|
||||||
@ -60,31 +62,37 @@ static void do_parse(const char *name, int start, int nl)
|
|||||||
|
|
||||||
void parse_hierarchy(const char *name)
|
void parse_hierarchy(const char *name)
|
||||||
{
|
{
|
||||||
do_parse(name, START_HIERARCHY, 0);
|
do_parse(name, START_HIERARCHY, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void parse_characteristics(const char *name)
|
void parse_characteristics(const char *name)
|
||||||
{
|
{
|
||||||
do_parse(name, START_CHAR, 1);
|
do_parse(name, START_CHAR, 1, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void parse_inventory(const char *name)
|
void parse_inventory(const char *name)
|
||||||
{
|
{
|
||||||
do_parse(name, START_INVENTORY, 1);
|
do_parse(name, START_INVENTORY, 1, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void parse_currencies(const char *name)
|
void parse_currencies(const char *name)
|
||||||
{
|
{
|
||||||
do_parse(name, START_EXCHANGE, 1);
|
do_parse(name, START_EXCHANGE, 1, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void parse_providers(const char *name)
|
void parse_providers(const char *name)
|
||||||
{
|
{
|
||||||
do_parse(name, START_PROVIDERS, 1);
|
do_parse(name, START_PROVIDERS, 1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void parse_substitutions(const char *name)
|
||||||
|
{
|
||||||
|
do_parse(name, START_SUBST, 0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
%}
|
%}
|
||||||
@ -96,6 +104,9 @@ void parse_providers(const char *name)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
ID [-_A-Za-z0-9()+./]
|
ID [-_A-Za-z0-9()+./]
|
||||||
|
PAT "\\"[^\t\n]|[^ \t\n\\]
|
||||||
|
|
||||||
|
%s ID PAT
|
||||||
|
|
||||||
%%
|
%%
|
||||||
|
|
||||||
@ -108,9 +119,17 @@ ID [-_A-Za-z0-9()+./]
|
|||||||
}
|
}
|
||||||
%}
|
%}
|
||||||
|
|
||||||
{ID}({ID}|"%")* { yylval.s = unique(yytext);
|
<INITIAL,ID>{ID}({ID}|"%")* { yylval.s = unique(yytext);
|
||||||
return WORD; }
|
return WORD; }
|
||||||
|
|
||||||
|
<PAT>{PAT}* { BEGIN(ID);
|
||||||
|
yylval.s = stralloc(yytext);
|
||||||
|
return PATTERN; }
|
||||||
|
|
||||||
|
"=" { if (pattern)
|
||||||
|
BEGIN(PAT);
|
||||||
|
return '='; }
|
||||||
|
|
||||||
"<=" return TOK_LE;
|
"<=" return TOK_LE;
|
||||||
">=" return TOK_GE;
|
">=" return TOK_GE;
|
||||||
|
|
||||||
@ -142,7 +161,7 @@ void yywarnf(const char *fmt, ...)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void yyerrorf(const char *fmt, ...)
|
void __attribute__((noreturn)) yyerrorf(const char *fmt, ...)
|
||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
|
|
||||||
@ -155,7 +174,7 @@ void yyerrorf(const char *fmt, ...)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void yyerror(const char *s)
|
void __attribute__((noreturn)) yyerror(const char *s)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "%s:%d: %s\n", file_name, lineno, s);
|
fprintf(stderr, "%s:%d: %s\n", file_name, lineno, s);
|
||||||
exit(1);
|
exit(1);
|
||||||
|
62
b2/lang.y
62
b2/lang.y
@ -18,6 +18,7 @@
|
|||||||
#include "param.h"
|
#include "param.h"
|
||||||
#include "chr.h"
|
#include "chr.h"
|
||||||
#include "db.h"
|
#include "db.h"
|
||||||
|
#include "subst.h"
|
||||||
#include "lang.h"
|
#include "lang.h"
|
||||||
|
|
||||||
#include "y.tab.h"
|
#include "y.tab.h"
|
||||||
@ -81,13 +82,14 @@ static const struct field *top_field(void)
|
|||||||
struct price *price;
|
struct price *price;
|
||||||
struct stock *stock;
|
struct stock *stock;
|
||||||
struct provider *prov;
|
struct provider *prov;
|
||||||
|
struct subst *subst;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
%token START_HIERARCHY START_CHAR START_INVENTORY
|
%token START_HIERARCHY START_CHAR START_INVENTORY
|
||||||
%token START_EXCHANGE START_PROVIDERS
|
%token START_EXCHANGE START_PROVIDERS START_SUBST
|
||||||
%token TOK_LE TOK_GE TOK_NL
|
%token TOK_LE TOK_GE TOK_NL
|
||||||
%token <s> WORD
|
%token <s> WORD PATTERN
|
||||||
|
|
||||||
%type <num> int
|
%type <num> int
|
||||||
%type <fnum> float
|
%type <fnum> float
|
||||||
@ -104,6 +106,7 @@ static const struct field *top_field(void)
|
|||||||
%type <price> prices price
|
%type <price> prices price
|
||||||
%type <stock> stock
|
%type <stock> stock
|
||||||
%type <prov> providers provider
|
%type <prov> providers provider
|
||||||
|
%type <subst> block opt_block
|
||||||
|
|
||||||
%%
|
%%
|
||||||
|
|
||||||
@ -113,6 +116,7 @@ all:
|
|||||||
| START_INVENTORY inventory
|
| START_INVENTORY inventory
|
||||||
| START_EXCHANGE exchange
|
| START_EXCHANGE exchange
|
||||||
| START_PROVIDERS providers
|
| START_PROVIDERS providers
|
||||||
|
| START_SUBST substitutions
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
||||||
@ -554,3 +558,57 @@ provider:
|
|||||||
$$->minimum = $4;
|
$$->minimum = $4;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
||||||
|
/* ----- Substitutions ----------------------------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
substitutions:
|
||||||
|
block
|
||||||
|
{
|
||||||
|
subst_finalize($1);
|
||||||
|
subst_dump(stderr, $1);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
block:
|
||||||
|
{
|
||||||
|
$$ = NULL;
|
||||||
|
}
|
||||||
|
| WORD '=' PATTERN opt_block block
|
||||||
|
{
|
||||||
|
if ($4) {
|
||||||
|
$$ = subst_match($1, $3);
|
||||||
|
$$->u.match.block = $4;
|
||||||
|
} else {
|
||||||
|
$$ = subst_assign($1, $3);
|
||||||
|
}
|
||||||
|
free((void *) $3);
|
||||||
|
$$->next = $5;
|
||||||
|
}
|
||||||
|
| WORD WORD
|
||||||
|
{
|
||||||
|
if (!strcmp($1, "break"))
|
||||||
|
$$ = subst_break($2);
|
||||||
|
else if (!strcmp($1, "again"))
|
||||||
|
$$ = subst_again($2);
|
||||||
|
else
|
||||||
|
yyerrorf("unknown keyword \"%s\"", $1);
|
||||||
|
}
|
||||||
|
| WORD
|
||||||
|
{
|
||||||
|
if (strcmp($1, "end"))
|
||||||
|
yyerrorf("unknown keyword \"%s\"", $1);
|
||||||
|
$$ = subst_end();
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
opt_block:
|
||||||
|
{
|
||||||
|
$$ = NULL;
|
||||||
|
}
|
||||||
|
| '{' block '}'
|
||||||
|
{
|
||||||
|
$$ = $2;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
349
b2/subst.c
Normal file
349
b2/subst.c
Normal file
@ -0,0 +1,349 @@
|
|||||||
|
/*
|
||||||
|
* subst.c - Substitution rules
|
||||||
|
*
|
||||||
|
* Copyright 2012 by Werner Almesberger
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <regex.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
#include "lang.h"
|
||||||
|
#include "subst.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* ----- Rule set construction --------------------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
static struct subst *alloc_subst(enum subst_type type)
|
||||||
|
{
|
||||||
|
struct subst *sub;
|
||||||
|
|
||||||
|
sub = alloc_type(struct subst);
|
||||||
|
sub->type = type;
|
||||||
|
sub->next = NULL;
|
||||||
|
return sub;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct subst *subst_match(const char *src, const char *re)
|
||||||
|
{
|
||||||
|
char error[1000];
|
||||||
|
struct subst *sub;
|
||||||
|
char *tmp;
|
||||||
|
int err, len;
|
||||||
|
|
||||||
|
sub = alloc_subst(st_match);
|
||||||
|
sub->u.match.src = src;
|
||||||
|
len = strlen(re);
|
||||||
|
tmp = alloc_size(len+3);
|
||||||
|
tmp[0] = '^';
|
||||||
|
memcpy(tmp+1, re, len);
|
||||||
|
tmp[len+1] = '$';
|
||||||
|
tmp[len+2] = 0;
|
||||||
|
err = regcomp(&sub->u.match.re, tmp, REG_EXTENDED);
|
||||||
|
free(tmp);
|
||||||
|
if (err) {
|
||||||
|
regerror(err, &sub->u.match.re, error, sizeof(error));
|
||||||
|
yyerrorf("%s", error);
|
||||||
|
}
|
||||||
|
return sub;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void end_chunk(struct chunk ***last, const char *start, const char *s)
|
||||||
|
{
|
||||||
|
struct chunk *c;
|
||||||
|
|
||||||
|
if (s == start)
|
||||||
|
return;
|
||||||
|
|
||||||
|
c = alloc_type(struct chunk);
|
||||||
|
c->type = ct_string;
|
||||||
|
c->u.s = stralloc_n(start, s-start);;
|
||||||
|
c->unit = NULL;
|
||||||
|
c->next = NULL;
|
||||||
|
**last = c;
|
||||||
|
*last = &c->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const char *parse_var(struct chunk *c, const char *s)
|
||||||
|
{
|
||||||
|
const char *t;
|
||||||
|
int braced;
|
||||||
|
|
||||||
|
if (!*s)
|
||||||
|
yyerror("trailing dollar sign");
|
||||||
|
|
||||||
|
braced = *s == '{';
|
||||||
|
if (braced)
|
||||||
|
s++;
|
||||||
|
|
||||||
|
t = s;
|
||||||
|
while (*t) {
|
||||||
|
if (braced && *t == '}')
|
||||||
|
break;
|
||||||
|
if (s == t && *t == '$') {
|
||||||
|
t++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!isalnum(*t))
|
||||||
|
break;
|
||||||
|
t++;
|
||||||
|
}
|
||||||
|
if (s == t)
|
||||||
|
yyerror("invalid variable name");
|
||||||
|
if (braced && !*t)
|
||||||
|
yyerror("unterminated variable name");
|
||||||
|
if (isdigit(*s)) {
|
||||||
|
if (t != s+1 || *s == '0')
|
||||||
|
yyerror("invalid variable name");
|
||||||
|
c->type = ct_sub;
|
||||||
|
c->u.sub = *s-'0';
|
||||||
|
} else if (isalnum(*s)) {
|
||||||
|
char *tmp;
|
||||||
|
|
||||||
|
c->type = ct_var;
|
||||||
|
tmp = stralloc_n(s, t-s);
|
||||||
|
c->u.var = unique(tmp);
|
||||||
|
free(tmp);
|
||||||
|
} else {
|
||||||
|
c->type = ct_sub;
|
||||||
|
c->u.sub = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*t != '#') {
|
||||||
|
if (braced) {
|
||||||
|
assert(*t == '}');
|
||||||
|
t++;
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
s = ++t;
|
||||||
|
while (*t) {
|
||||||
|
if (braced && *t == '}')
|
||||||
|
break;
|
||||||
|
if (!braced && t != s)
|
||||||
|
break;
|
||||||
|
t++;
|
||||||
|
}
|
||||||
|
if (s == t)
|
||||||
|
yyerror("invalid unit");
|
||||||
|
c->unit = stralloc_n(s, t-s);
|
||||||
|
if (braced) {
|
||||||
|
if (!*t)
|
||||||
|
yyerror("unterminated unit");
|
||||||
|
t++;
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static struct chunk *parse_pattern(const char *s)
|
||||||
|
{
|
||||||
|
struct chunk *res = NULL, **last = &res;
|
||||||
|
struct chunk *c;
|
||||||
|
const char *start = s;
|
||||||
|
|
||||||
|
while (*s) {
|
||||||
|
if (*s == '\\') {
|
||||||
|
if (!s[1])
|
||||||
|
yyerror("trailing backslash");
|
||||||
|
end_chunk(&last, start, s);
|
||||||
|
start = s+1;
|
||||||
|
s += 2;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (*s != '$') {
|
||||||
|
s++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
end_chunk(&last, start, s);
|
||||||
|
c = alloc_type(struct chunk);
|
||||||
|
c->unit = NULL;
|
||||||
|
c->next = NULL;
|
||||||
|
*last = c;
|
||||||
|
last = &c->next;
|
||||||
|
start = s = parse_var(c, s+1);
|
||||||
|
}
|
||||||
|
end_chunk(&last, start, s);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct subst *subst_assign(const char *dst, const char *pat)
|
||||||
|
{
|
||||||
|
struct subst *sub;
|
||||||
|
|
||||||
|
sub = alloc_subst(st_assign);
|
||||||
|
sub->u.assign.dst = dst;
|
||||||
|
sub->u.assign.pat = parse_pattern(pat);
|
||||||
|
return sub;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct subst *subst_end(void)
|
||||||
|
{
|
||||||
|
return alloc_subst(st_end);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct subst *subst_break(const char *block)
|
||||||
|
{
|
||||||
|
struct subst *sub;
|
||||||
|
|
||||||
|
sub = alloc_subst(st_break);
|
||||||
|
sub->u.tmp = block;
|
||||||
|
return sub;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct subst *subst_again(const char *block)
|
||||||
|
{
|
||||||
|
struct subst *sub;
|
||||||
|
|
||||||
|
sub = alloc_subst(st_again);
|
||||||
|
sub->u.tmp = block;
|
||||||
|
return sub;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ----- Jump resolution --------------------------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
struct parent {
|
||||||
|
const struct subst *sub;
|
||||||
|
const struct parent *parent;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static const struct subst *resolve_jump(const char *name,
|
||||||
|
const struct parent *parent)
|
||||||
|
{
|
||||||
|
while (parent) {
|
||||||
|
assert(parent->sub->type == st_match);
|
||||||
|
if (!strcmp(name, parent->sub->u.match.src))
|
||||||
|
return parent->sub;
|
||||||
|
parent = parent->parent;
|
||||||
|
}
|
||||||
|
yyerrorf("cannot find \"%s\"", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void recurse_fin(struct subst *sub, const struct parent *parent)
|
||||||
|
{
|
||||||
|
struct parent next = {
|
||||||
|
.sub = sub,
|
||||||
|
.parent = parent,
|
||||||
|
};
|
||||||
|
|
||||||
|
while (sub) {
|
||||||
|
switch (sub->type) {
|
||||||
|
case st_match:
|
||||||
|
recurse_fin(sub->u.match.block, &next);
|
||||||
|
case st_assign:
|
||||||
|
case st_end:
|
||||||
|
break;
|
||||||
|
case st_break:
|
||||||
|
case st_again:
|
||||||
|
sub->u.jump = resolve_jump(sub->u.tmp, parent);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
sub = sub->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void subst_finalize(struct subst *sub)
|
||||||
|
{
|
||||||
|
recurse_fin(sub, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ----- Dumping ----------------------------------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
#define INDENT 4
|
||||||
|
|
||||||
|
|
||||||
|
static void dump_chunks(FILE *file, const struct chunk *c)
|
||||||
|
{
|
||||||
|
while (c) {
|
||||||
|
switch (c->type) {
|
||||||
|
case ct_string:
|
||||||
|
fprintf(file, "%s", c->u.s);
|
||||||
|
break;
|
||||||
|
case ct_var:
|
||||||
|
fprintf(file, "${%s", c->u.var);
|
||||||
|
break;
|
||||||
|
case ct_sub:
|
||||||
|
if (c->u.sub)
|
||||||
|
fprintf(file, "${%d", c->u.sub);
|
||||||
|
else
|
||||||
|
fprintf(file, "${$");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
if (c->type != ct_string) {
|
||||||
|
if (c->unit)
|
||||||
|
fprintf(file, "#%s", c->unit);
|
||||||
|
fprintf(file, "}");
|
||||||
|
}
|
||||||
|
c = c->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void recurse_dump(FILE *file, const struct subst *sub, int level)
|
||||||
|
{
|
||||||
|
while (sub) {
|
||||||
|
fprintf(file, "%*s", INDENT*level, "");
|
||||||
|
switch (sub->type) {
|
||||||
|
case st_match:
|
||||||
|
fprintf(file, "%s=RE {\n", sub->u.match.src);
|
||||||
|
recurse_dump(file, sub->u.match.block, level+1);
|
||||||
|
fprintf(file, "%*s}\n", INDENT*level, "");
|
||||||
|
break;
|
||||||
|
case st_assign:
|
||||||
|
fprintf(file, "%s=", sub->u.assign.dst);
|
||||||
|
dump_chunks(file, sub->u.assign.pat);
|
||||||
|
fprintf(file, "\n");
|
||||||
|
break;
|
||||||
|
case st_end:
|
||||||
|
fprintf(file, "end\n");
|
||||||
|
break;
|
||||||
|
case st_break:
|
||||||
|
fprintf(file, "break %s\n", sub->u.jump->u.match.src);
|
||||||
|
break;
|
||||||
|
case st_again:
|
||||||
|
fprintf(file, "again %s\n", sub->u.jump->u.match.src);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
sub = sub->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void subst_dump(FILE *file, const struct subst *sub)
|
||||||
|
{
|
||||||
|
recurse_dump(file, sub, 0);
|
||||||
|
}
|
75
b2/subst.h
Normal file
75
b2/subst.h
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
* subst.h - Substitution rules
|
||||||
|
*
|
||||||
|
* Copyright 2012 by Werner Almesberger
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef SUBST_H
|
||||||
|
#define SUBST_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <regex.h>
|
||||||
|
|
||||||
|
|
||||||
|
enum chunk_type {
|
||||||
|
ct_string,
|
||||||
|
ct_var,
|
||||||
|
ct_sub,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct chunk {
|
||||||
|
enum chunk_type type;
|
||||||
|
union {
|
||||||
|
const char *s;
|
||||||
|
const char *var;
|
||||||
|
int sub; /* 0 if $$ */
|
||||||
|
} u;
|
||||||
|
const char *unit; /* NULL if no conversion specified */
|
||||||
|
struct chunk *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum subst_type {
|
||||||
|
st_match,
|
||||||
|
st_assign,
|
||||||
|
st_end,
|
||||||
|
st_break,
|
||||||
|
st_again,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct subst {
|
||||||
|
enum subst_type type;
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
const char *src;
|
||||||
|
regex_t re;
|
||||||
|
struct subst *block;
|
||||||
|
} match;
|
||||||
|
struct {
|
||||||
|
const char *dst;
|
||||||
|
struct chunk *pat;
|
||||||
|
} assign;
|
||||||
|
const struct subst *jump;
|
||||||
|
const char *tmp; /* jump target name; for subst_finalize */
|
||||||
|
} u;
|
||||||
|
struct subst *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct subst *subst_match(const char *src, const char *re);
|
||||||
|
struct subst *subst_assign(const char *dst, const char *pat);
|
||||||
|
struct subst *subst_end(void);
|
||||||
|
struct subst *subst_break(const char *block);
|
||||||
|
struct subst *subst_again(const char *block);
|
||||||
|
|
||||||
|
void subst_finalize(struct subst *sub);
|
||||||
|
|
||||||
|
void subst_dump(FILE *file, const struct subst *sub);
|
||||||
|
|
||||||
|
#endif /* !SUBST_H */
|
25
b2/util.h
25
b2/util.h
@ -13,6 +13,7 @@
|
|||||||
#define UTIL_H
|
#define UTIL_H
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
|
||||||
#define alloc_size(s) \
|
#define alloc_size(s) \
|
||||||
@ -24,6 +25,30 @@
|
|||||||
#define alloc_type(t) ((t *) alloc_size(sizeof(t)))
|
#define alloc_type(t) ((t *) alloc_size(sizeof(t)))
|
||||||
|
|
||||||
|
|
||||||
|
static inline char *stralloc(const char *s)
|
||||||
|
{
|
||||||
|
char *t;
|
||||||
|
|
||||||
|
t = strdup(s);
|
||||||
|
if (!t)
|
||||||
|
abort();
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline char *stralloc_n(const char *s, int n)
|
||||||
|
{
|
||||||
|
char *t;
|
||||||
|
|
||||||
|
t = alloc_size(n+1);
|
||||||
|
if (!t)
|
||||||
|
abort();
|
||||||
|
memcpy(t, s, n);
|
||||||
|
t[n] = 0;
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const char *unique(const char *s);
|
const char *unique(const char *s);
|
||||||
|
|
||||||
#endif /* !UTIL_H */
|
#endif /* !UTIL_H */
|
||||||
|
Loading…
Reference in New Issue
Block a user