From 6bb8b03ef80cc8cedf7f46cd61bb5a4c64d73168 Mon Sep 17 00:00:00 2001 From: Werner Almesberger Date: Wed, 25 Apr 2012 17:14:39 -0300 Subject: [PATCH] b2/: first tentative version of hierarchy parser, with example --- b2/HIERARCHY | 7 ++ b2/Makefile | 4 +- b2/boom.c | 50 ++++++++++++- b2/chr.c | 208 ++++++++++++++++++++++++++++++++++++++------------- b2/chr.h | 45 +++++++++-- b2/dump.c | 63 ++++++++++++++++ b2/eval.c | 4 +- b2/lang.l | 1 + b2/lang.y | 166 +++++++++++++++++++++++++++++++++++----- b2/param.c | 41 +++++++++- b2/param.h | 11 +++ 11 files changed, 512 insertions(+), 88 deletions(-) create mode 100644 b2/HIERARCHY create mode 100644 b2/dump.c diff --git a/b2/HIERARCHY b/b2/HIERARCHY new file mode 100644 index 0000000..c41e209 --- /dev/null +++ b/b2/HIERARCHY @@ -0,0 +1,7 @@ + = R { + R: { R:#R TOL:%R }; + C: { C:#F TOL:%C }; + L: { L:#H TOL:%L }; +} diff --git a/b2/Makefile b/b2/Makefile index 47fa068..a4ab7b1 100644 --- a/b2/Makefile +++ b/b2/Makefile @@ -11,9 +11,9 @@ SHELL = /bin/bash -CFLAGS = -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 -OBJS = boom.o chr.o comp.o db.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 util.o lex.yy.o y.tab.o LDLIBS = -lfl $(shell pkg-config --libs glib-2.0) YACC = bison -y diff --git a/b2/boom.c b/b2/boom.c index 31dbf45..1d194c3 100644 --- a/b2/boom.c +++ b/b2/boom.c @@ -1,4 +1,52 @@ -int main(void) +/* + * boom.c - BOOM, main function + * + * 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 +#include +#include +#include + + +extern int yyparse(void); + + +static void usage(const char *name) { + fprintf(stderr, "usage: %s [file]\n", name); + exit(1); +} + + +int main(int argc, char **argv) +{ + int fd; + + switch (argc) { + case 1: + break; + case 2: + fd = open(argv[1], O_RDONLY); + if (fd < 0) { + perror(argv[1]); + exit(1); + } + if (dup2(fd, 0) < 0) { + perror("dup2"); + exit(1); + } + break; + default: + usage(*argv); + } + (void) yyparse(); return 0; } diff --git a/b2/chr.c b/b2/chr.c index d813725..8e98283 100644 --- a/b2/chr.c +++ b/b2/chr.c @@ -10,93 +10,193 @@ */ +#include + #include "util.h" #include "param.h" #include "chr.h" -struct condition { - struct value value; - enum relop relop; - struct condition *next; -}; - -struct selector { - struct condition *cond; - struct selector *next; -}; - -struct field { - const char *name; - const struct format *fmt; - struct field *mark; - struct selector *sel; - struct field *next; -}; - -static struct field *fields = NULL, *curr_field = NULL, *mark = NULL; - - -const struct format *field_find(const char *name) +const struct format *field_find(const char *name, const struct field *tail) { - const struct field *f; - - for (f = fields; f; f = f->next) - if (f->name == name) - return f->fmt; + while (tail) { + if (tail->name == name) + return tail->fmt; + tail = tail->prev; + } return NULL; } -void field_add(const char *name, const struct format *fmt) +/* ----- Construction of the field hierarchy ------------------------------- */ + + +struct field *field_new(const char *name, const struct format *fmt, + const struct field *prev) { struct field *field; - if (field_find(name)) + if (field_find(name, prev)) yyerrorf("duplicate field \"%s\"", name); field = alloc_type(struct field); field->name = name; field->fmt = fmt; - field->mark = (void *) 1; /* poison */ field->sel = NULL; - if (curr_field) - curr_field->next = field; + field->any.fields = NULL; + field->any.rules = NULL; + field->next = NULL; + field->prev = NULL; + return field; +} + + +struct selector *field_selector(void) +{ + struct selector *sel; + + sel = alloc_type(struct selector); + sel->cond = NULL; + sel->act.fields = NULL; + sel->act.rules = NULL; + sel->next = NULL; + return sel; +} + + +struct condition *field_condition(enum relop relop, const char *word) +{ + struct condition *cond; + + cond = alloc_type(struct condition); + cond->value.u.name = word; + cond->relop = relop; + cond->next = NULL; + return cond; +} + + +void field_finalize(struct field *field) +{ + const struct selector *sel; + struct condition *cond; + + for (sel = field->sel; sel; sel = sel->next) + for (cond = sel->cond; cond; cond = cond->next) + if (!evaluate(field->fmt, cond->value.u.name, + &cond->value)) + yyerrorf("invalid value in selection"); + /* @@@ indicate exact location */ +} + + +/* ----- Dumping ----------------------------------------------------------- */ + + +#define INDENT 8 + + +static void dump_fields(FILE *file, const struct field *field, int level); + + +static void dump_set_decl(FILE *file, const struct names *first_name) +{ + const char *name; + + name = nameset_rev_lookup(first_name); + assert(name); + fprintf(file, "<%s>", name); +} + + +static void dump_field_decl(FILE *file, const struct field *field) +{ + if (field->fmt->ops == ¶m_ops_name) + fprintf(file, "*"); + else if (field->fmt->ops == ¶m_ops_set) + dump_set_decl(file, field->fmt->u.set); + else if (field->fmt->ops == ¶m_ops_abs) + fprintf(file, "#%s", field->fmt->u.abs); + else if (field->fmt->ops == ¶m_ops_rel) + fprintf(file, "%%%s", field->fmt->u.rel->u.abs); else - fields = field; - curr_field = field; + abort(); } -void field_mark(void) +static void dump_action(FILE *file, const struct action *act, int level) { - if (mark) - mark->mark = curr_field; - mark = curr_field; + const struct field *field; + + if (act->fields) { + fprintf(file, " {"); + for (field = act->fields; field; field = field->next) { + fprintf(file, " %s:", field->name); + dump_field_decl(file, field); + } + fprintf(file, " }\n"); + } else { + fprintf(file, "\n"); + } + dump_fields(file, act->rules, level+1); } -void field_release(void) +static void dump_one_field(FILE *file, const struct field *field, int level) { - curr_field = mark; - if (curr_field) - mark = curr_field->mark; + const struct selector *sel; + const struct condition *cond; + + fprintf(file, "%*s%s:", level*INDENT, "", field->name); + dump_field_decl(file, field); + + fprintf(file, " {\n"); + + for (sel = field->sel; sel; sel = sel->next) { + fprintf(file, "%*s", level*INDENT+INDENT/2, ""); + for (cond = sel->cond; cond; cond = cond->next) { + if (cond != sel->cond) + fprintf(file, "|"); + switch (cond->relop) { + case rel_lt: + fprintf(file, "<"); + break; + case rel_le: + fprintf(file, "<="); + break; + case rel_eq: + break; + case rel_ge: + fprintf(file, ">"); + break; + case rel_gt: + fprintf(file, ">="); + break; + default: + fprintf(file, "?"); + } + dump(file, field->fmt, &cond->value); + } + fprintf(file, ": "); + dump_action(file, &sel->act, level); + } + if (field->any.fields || field->any.rules) { + fprintf(file, "%*s*:", level*INDENT+INDENT/2, ""); + dump_action(file, &field->any, level); + } + fprintf(file, "%*s}\n", level*INDENT, ""); } -void field_add_selector(enum relop relop, const char *word) +static void dump_fields(FILE *file, const struct field *field, int level) { - + while (field) { + dump_one_field(file, field, level); + field = field->next; + } } -void field_more_selectors(void) +void field_dump(FILE *file, const struct field *field) { - if (curr_field->fmt->ops != ¶m_ops_set) - ;//yyerrorf(" + dump_fields(file, field, 0); } - - -void field_add_wildcard(void) -{ -} - diff --git a/b2/chr.h b/b2/chr.h index 73168df..706fbe0 100644 --- a/b2/chr.h +++ b/b2/chr.h @@ -13,15 +13,46 @@ #ifndef CHR_H #define CHR_H +#include + #include "param.h" -void field_add(const char *name, const struct format *fmt); -const struct format *field_find(const char *name); -void field_mark(void); -void field_release(void); -void field_add_selector(enum relop relop, const char *word); -void field_more_selectors(void); -void field_add_wildcard(void); +struct field; + +struct action { + struct field *fields; + struct field *rules; +}; + +struct condition { + struct value value; + enum relop relop; + struct condition *next; +}; + +struct selector { + struct condition *cond; + struct action act; + struct selector *next; +}; + +struct field { + const char *name; + const struct format *fmt; + struct selector *sel; + struct action any; + struct field *next; + const struct field *prev; +}; + + +const struct format *field_find(const char *name, const struct field *tail); +struct field *field_new(const char *name, const struct format *fmt, + const struct field *prev); +struct selector *field_selector(void); +struct condition *field_condition(enum relop relop, const char *word); +void field_finalize(struct field *field); +void field_dump(FILE *file, const struct field *field); #endif /* !CHR_H */ diff --git a/b2/dump.c b/b2/dump.c new file mode 100644 index 0000000..761940a --- /dev/null +++ b/b2/dump.c @@ -0,0 +1,63 @@ +/* + * dump.c - Dump a value (for debugging) + * + * 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 + +#include "bitset.h" +#include "param.h" + + +void dump_name(FILE *file, const struct format *fmt, const struct value *v) +{ + fprintf(file, "%s", v->u.name); +} + + +void dump_set(FILE *file, const struct format *fmt, const struct value *v) +{ + const struct names *name; + int first = 1; + int i; + + i = 0; + for (name = fmt->u.set; name; name = name->next) { + if (bitset_get(&v->u.set, i)) { + fprintf(file, "%s%s", first ? "" : "|", + name->equiv->name); + first = 0; + } + i++; + } +} + + +void dump_abs(FILE *file, const struct format *fmt, const struct value *v) +{ + fprintf(file, "%g%s", v->u.abs, fmt->u.abs); +} + + +void dump_rel(FILE *file, const struct format *fmt, const struct value *v) +{ + if (v->u.rel.fract) + fprintf(file, "-%f/+%f%%", + v->u.rel.minus*100, v->u.rel.plus*100); + else + fprintf(file, "-%g/+%g%s", + v->u.rel.minus, v->u.rel.plus, fmt->u.rel->u.abs); +} + + +void dump(FILE *file, const struct format *fmt, const struct value *v) +{ + fmt->ops->dump(file, fmt, v); +} diff --git a/b2/eval.c b/b2/eval.c index dc3d804..06f317d 100644 --- a/b2/eval.c +++ b/b2/eval.c @@ -30,10 +30,12 @@ static int lookup_name(const struct names *name, const char *s) const struct equiv *eq; int n; - for (n = 0; name; n++) + for (n = 0; name; n++) { for (eq = name->equiv; eq; eq = eq->next) if (eq->name == s) return n; + name = name->next; + } return -1; } diff --git a/b2/lang.l b/b2/lang.l index 766104d..ebbe5f8 100644 --- a/b2/lang.l +++ b/b2/lang.l @@ -15,6 +15,7 @@ #include "util.h" #include "param.h" +#include "chr.h" #include "y.tab.h" diff --git a/b2/lang.y b/b2/lang.y index 3a0e15a..1bd4d61 100644 --- a/b2/lang.y +++ b/b2/lang.y @@ -12,6 +12,7 @@ #include +#include #include "util.h" #include "param.h" @@ -19,6 +20,41 @@ #include "y.tab.h" + +static struct field_stack { + const struct field *field; + struct field_stack *next; +} *field_stack = NULL; + + +static void push_field(const struct field *field) +{ + struct field_stack *entry; + + entry = alloc_type(struct field_stack); + entry->field = field; + entry->next = field_stack; + field_stack = entry; +} + + +static void pop_field(void) +{ + struct field_stack *entry; + + assert(field_stack); + entry = field_stack; + field_stack = entry->next; + free(entry); +} + + +static const struct field *top_field(void) +{ + return field_stack ? field_stack->field : NULL; +} + + %} @@ -28,6 +64,10 @@ struct names *names; struct format *format; enum relop relop; + struct field *field; + struct selector *sel; + struct condition *cond; + struct action act; }; @@ -38,12 +78,19 @@ %type names nameq %type format %type relop opt_relop +%type /*rules*/ opt_rule rule opt_fields fields field +%type selectors +%type conditions condition +%type opt_wildcard action %% all: - | nameset ';' - | rules + rule + { + field_dump(stderr, $1); + } + | nameset all ; nameset: @@ -89,41 +136,101 @@ nameqs: } ; +/* + * @@@ for now, we can't select on a collective of fields. maybe later, with + * a syntax change. + * rules: - field '{' { - field_mark(); + $$ = NULL; } - selections opt_wildcard '}' + | rule rules { - field_release(); + $$ = $1; + $$->next = $2; + } + ; +*/ + +opt_rule: + { + $$ = NULL; + } + | rule + { + $$ = $1; } ; -selections: - | selectors ':' opt_fields rules selections +rule: + field + { + $1->prev = top_field(); + push_field($1); + } + '{' selectors opt_wildcard '}' + { + $$ = $1; + $$->sel = $4; + $$->any = $5; + $$->next = NULL; + field_finalize($$); + pop_field(); + } ; selectors: - selector - | selector '|' { - field_more_selectors(); + $$ = NULL; + } + | conditions ':' action selectors + { + $$ = field_selector(); + $$->cond = $1; + $$->act = $3; + $$->next = $4; } - selectors ; -selector: +conditions: + condition + { + $$ = $1; + } + | condition '|' conditions + { + $$ = $1; + $$->next = $3; + } + ; + +condition: opt_relop WORD { - field_add_selector($1, $2); + $$ = field_condition($1, $2); } ; opt_wildcard: - '*' ':' { - field_add_wildcard(); + $$.fields = NULL; + $$.rules = NULL; + } + | '*' ':' action + { + $$ = $3; + } + ; + +action: + { + push_field(top_field()); + } + opt_fields opt_rule ';' + { + $$.fields = $2; + $$.rules = $3; + pop_field(); } ; @@ -161,17 +268,38 @@ relop: ; opt_fields: + { + $$ = NULL; + } | '{' fields '}' + { + $$ = $2; + } ; fields: - | field fields + { + $$ = NULL; + } + | field + { + push_field($1); + } + fields + { + $$ = $1; + $$->next = $3; + pop_field(); + $$->prev = top_field(); + if ($3) + $3->prev = $1; + } ; field: WORD ':' format { - field_add($1, $3); + $$ = field_new($1, $3, top_field()); } ; @@ -199,7 +327,7 @@ format: { $$ = alloc_type(struct format); $$->ops = ¶m_ops_rel; - $$->u.rel = field_find($2); + $$->u.rel = field_find($2, top_field()); if (!$$->u.rel) yyerrorf("unknown field \"%s\"", $2); } diff --git a/b2/param.c b/b2/param.c index 1e2a47c..b07f533 100644 --- a/b2/param.c +++ b/b2/param.c @@ -36,12 +36,14 @@ static void check_duplicates(const struct names *n) const struct equiv *ea; for (na = n; na; na = na->next) { - for (ea = na->equiv; ea; ea = ea->next) + for (ea = na->equiv; ea; ea = ea->next) { if (duplicate(ea->name, ea->next)) yyerrorf("duplicate name \"%s\"", ea->name); - for (nb = na->next; nb; nb = nb->next) - if (duplicate(ea->name, nb->equiv)) - yyerrorf("duplicate name \"%s\"", ea->name); + for (nb = na->next; nb; nb = nb->next) + if (duplicate(ea->name, nb->equiv)) + yyerrorf("duplicate name \"%s\"", + ea->name); + } } } @@ -69,10 +71,41 @@ const struct names *find_nameset(const char *name) } +struct lookup_data { + const struct names *first_name; + const char *name; +}; + + +static gboolean rev_traverse(gpointer key, gpointer value, gpointer data) +{ + struct lookup_data *d = data; + + if (d->first_name == value) { + d->name = key; + return TRUE; + } + return FALSE; +} + + +const char *nameset_rev_lookup(const struct names *first_name) +{ + struct lookup_data data = { + .first_name = first_name, + .name = NULL, + }; + + g_tree_foreach(tree, rev_traverse, (void *) &data); + return data.name; +} + + #define MKOPS(type) \ const struct param_ops param_ops_##type = { \ .eval = eval_##type, \ .comp = comp_##type, \ + .dump = dump_##type, \ } diff --git a/b2/param.h b/b2/param.h index bc0753b..dd4360c 100644 --- a/b2/param.h +++ b/b2/param.h @@ -13,6 +13,8 @@ #ifndef PARAM_H #define PARAM_H +#include + #include "bitset.h" @@ -72,11 +74,14 @@ struct param_ops { struct value *res); int (*comp)(const struct value *a, enum relop relop, const struct value *b); + void (*dump)(FILE *file, const struct format *fmt, + const struct value *v); }; void register_nameset(const char *name, const struct names *set); const struct names *find_nameset(const char *name); +const char *nameset_rev_lookup(const struct names *first_name); int eval_name(const struct format *fmt, const char *s, struct value *res); int eval_set(const struct format *fmt, const char *s, struct value *res); @@ -91,6 +96,12 @@ int comp_rel(const struct value *a, enum relop relop, const struct value *b); int compare(const struct format *fmt, const struct value *a, enum relop relop, const struct value *b); +void dump_name(FILE *file, const struct format *fmt, const struct value *v); +void dump_set(FILE *file, const struct format *fmt, const struct value *v); +void dump_abs(FILE *file, const struct format *fmt, const struct value *v); +void dump_rel(FILE *file, const struct format *fmt, const struct value *v); +void dump(FILE *file, const struct format *fmt, const struct value *v); + extern const struct param_ops param_ops_name; extern const struct param_ops param_ops_set; extern const struct param_ops param_ops_abs;