1
0
mirror of git://projects.qi-hardware.com/eda-tools.git synced 2024-10-01 11:32:53 +03:00

b2/: add parsing of substitution rules (WIP)

This commit is contained in:
Werner Almesberger 2012-05-20 11:18:18 -03:00
parent d8f5c95ecb
commit 9fd1dc56e7
9 changed files with 572 additions and 15 deletions

View File

@ -13,7 +13,8 @@ SHELL = /bin/bash
CFLAGS = -g -Wall $(shell pkg-config --cflags glib-2.0)
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)
YACC = bison -y
@ -83,4 +84,5 @@ spotless: clean
# ----- Experiments -----------------------------------------------------------
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
View 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:
$$
*/

View File

@ -26,6 +26,7 @@ static void usage(const char *name)
" -i inventory\n"
" -x currency exchange\n"
" -p providers\n"
" -s substitutions\n"
, name);
exit(1);
}
@ -46,6 +47,8 @@ int main(int argc, char **argv)
parse = parse_currencies;
else if (!strcmp(argv[i], "-p"))
parse = parse_providers;
else if (!strcmp(argv[i], "-s"))
parse = parse_substitutions;
else
usage(*argv);
} else {

View File

@ -18,9 +18,10 @@ void parse_characteristics(const char *name);
void parse_inventory(const char *name);
void parse_currencies(const char *name);
void parse_providers(const char *name);
void parse_substitutions(const char *name);
void yywarnf(const char *fmt, ...);
void yyerrorf(const char *fmt, ...);
void yyerror(const char *s);
void __attribute__((noreturn)) yyerrorf(const char *fmt, ...);
void __attribute__((noreturn)) yyerror(const char *s);
#endif /* !LANG_H */

View File

@ -26,6 +26,7 @@ extern int yyparse(void);
static int start_token;
static int expose_nl;
static int pattern;
static const char *file_name;
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);
start_token = start;
expose_nl = nl;
pattern = pat;
file_name = unique(name);
lineno = 1;
yyparse();
@ -60,31 +62,37 @@ static void do_parse(const char *name, int start, int nl)
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)
{
do_parse(name, START_CHAR, 1);
do_parse(name, START_CHAR, 1, 0);
}
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)
{
do_parse(name, START_EXCHANGE, 1);
do_parse(name, START_EXCHANGE, 1, 0);
}
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()+./]
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; }
<PAT>{PAT}* { BEGIN(ID);
yylval.s = stralloc(yytext);
return PATTERN; }
"=" { if (pattern)
BEGIN(PAT);
return '='; }
"<=" return TOK_LE;
">=" 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;
@ -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);
exit(1);

View File

@ -18,6 +18,7 @@
#include "param.h"
#include "chr.h"
#include "db.h"
#include "subst.h"
#include "lang.h"
#include "y.tab.h"
@ -81,13 +82,14 @@ static const struct field *top_field(void)
struct price *price;
struct stock *stock;
struct provider *prov;
struct subst *subst;
};
%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 <s> WORD
%token <s> WORD PATTERN
%type <num> int
%type <fnum> float
@ -104,6 +106,7 @@ static const struct field *top_field(void)
%type <price> prices price
%type <stock> stock
%type <prov> providers provider
%type <subst> block opt_block
%%
@ -113,6 +116,7 @@ all:
| START_INVENTORY inventory
| START_EXCHANGE exchange
| START_PROVIDERS providers
| START_SUBST substitutions
;
@ -554,3 +558,57 @@ provider:
$$->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
View 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
View 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 */

View File

@ -13,6 +13,7 @@
#define UTIL_H
#include <stdlib.h>
#include <string.h>
#define alloc_size(s) \
@ -24,6 +25,30 @@
#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);
#endif /* !UTIL_H */