From aa2fe3ef1644a2ba92f06bd7d1180d0532a7c4f6 Mon Sep 17 00:00:00 2001 From: Werner Almesberger Date: Sun, 18 Mar 2012 13:24:12 -0300 Subject: [PATCH] b2: BOOM rewrite (WIP) --- b2/Makefile | 66 ++++++++++++++++ b2/bitset.h | 82 ++++++++++++++++++++ b2/boom.c | 4 + b2/chr.c | 102 +++++++++++++++++++++++++ b2/chr.h | 27 +++++++ b2/comp.c | 110 ++++++++++++++++++++++++++ b2/db.c | 82 ++++++++++++++++++++ b2/db.h | 66 ++++++++++++++++ b2/eval.c | 216 ++++++++++++++++++++++++++++++++++++++++++++++++++++ b2/lang.l | 59 ++++++++++++++ b2/lang.y | 206 +++++++++++++++++++++++++++++++++++++++++++++++++ b2/param.c | 82 ++++++++++++++++++++ b2/param.h | 99 ++++++++++++++++++++++++ b2/util.c | 40 ++++++++++ b2/util.h | 32 ++++++++ 15 files changed, 1273 insertions(+) create mode 100644 b2/Makefile create mode 100644 b2/bitset.h create mode 100644 b2/boom.c create mode 100644 b2/chr.c create mode 100644 b2/chr.h create mode 100644 b2/comp.c create mode 100644 b2/db.c create mode 100644 b2/db.h create mode 100644 b2/eval.c create mode 100644 b2/lang.l create mode 100644 b2/lang.y create mode 100644 b2/param.c create mode 100644 b2/param.h create mode 100644 b2/util.c create mode 100644 b2/util.h diff --git a/b2/Makefile b/b2/Makefile new file mode 100644 index 0000000..781f643 --- /dev/null +++ b/b2/Makefile @@ -0,0 +1,66 @@ +# +# Makefile - BOOM's Makefile +# +# 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. +# + +CFLAGS = -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 +LDLIBS = -lfl $(shell pkg-config --libs glib-2.0) + +YACC = bison -y +YYFLAGS = -v + +CC_normal := $(CC) +YACC_normal := $(YACC) +LEX_normal := $(LEX) +DEPEND_normal := $(CPP) $(CFLAGS) -MM -MG + +CC_quiet = @echo " CC " $@ && $(CC_normal) +YACC_quiet = @echo " YACC " $@ && $(YACC_normal) +LEX_quiet = @echo " LEX " $@ && $(LEX_normal) +GEN_quiet = @echo " GENERATE " $@ && +DEPEND_quiet = @$(DEPEND_normal) + +ifeq ($(V),1) + CC = $(CC_normal) + LEX = $(LEX_normal) + YACC = $(YACC_normal) + GEN = + DEPEND = $(DEPEND_normal) +else + CC = $(CC_quiet) + LEX = $(LEX_quiet) + YACC = $(YACC_quiet) + GEN = $(GEN_quiet) + DEPEND = $(DEPEND_quiet) +endif + +.PHONY: all clean + +all: boom + +boom: $(OBJS) + $(CC) $(CFLAGS) -o $@ $(OBJS) $(LDLIBS) + +lex.yy.c: lang.l y.tab.h + $(LEX) lang.l + +lex.yy.o: lex.yy.c y.tab.h + $(CC) -c $(CFLAGS) $(SLOPPY) lex.yy.c + +y.tab.c y.tab.h: lang.y + $(YACC) $(YYFLAGS) -d lang.y + +y.tab.o: y.tab.c + $(CC) -c $(CFLAGS) $(SLOPPY) y.tab.c + +clean: + rm -f $(OBJS) + rm -f lex.yy.c y.tab.c y.tab.h diff --git a/b2/bitset.h b/b2/bitset.h new file mode 100644 index 0000000..6b7f611 --- /dev/null +++ b/b2/bitset.h @@ -0,0 +1,82 @@ +/* + * bitset.h - Bit sets + * + * 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 BITSET_H +#define BITSET_H + +#include + +#include "bitset.h" + + +struct bitset { + uint64_t v; +}; + + +static inline void bitset_zero(struct bitset *b) +{ + b->v = 0; +} + + +static inline void bitset_set(struct bitset *b, int n) +{ + b->v |= (uint64_t) 1 << n; +} + + +static inline void bitset_clear(struct bitset *b, int n) +{ + b->v &= ~((uint64_t) 1 << n); +} + + +static inline int bitset_get(const struct bitset *b, int n) +{ + return !!(b->v & ((uint64_t) 1 << n)); +} + + +static inline int bitset_empty(const struct bitset *b) +{ + return !!b->v; +} + + +static inline int bitset_first(const struct bitset *b) +{ + int i; + + for (i = 0; i != sizeof(b->v)*8; i++) + if (b->v & ((uint64_t) 1 << i)) + return i; + return -1; +} + + +static inline int bitset_last(const struct bitset *b) +{ + int i = sizeof(b->v)*8; + + while (--i) + if (b->v & ((uint64_t) 1 << i)) + break; + return i; +} + + +static inline int bitset_common(const struct bitset *a, const struct bitset *b) +{ + return (a->v & b->v) != 0; +} + +#endif /* !BITSET_H */ diff --git a/b2/boom.c b/b2/boom.c new file mode 100644 index 0000000..31dbf45 --- /dev/null +++ b/b2/boom.c @@ -0,0 +1,4 @@ +int main(void) +{ + return 0; +} diff --git a/b2/chr.c b/b2/chr.c new file mode 100644 index 0000000..d813725 --- /dev/null +++ b/b2/chr.c @@ -0,0 +1,102 @@ +/* + * chr.h - Part characteristics + * + * 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 "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 field *f; + + for (f = fields; f; f = f->next) + if (f->name == name) + return f->fmt; + return NULL; +} + + +void field_add(const char *name, const struct format *fmt) +{ + struct field *field; + + if (field_find(name)) + 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; + else + fields = field; + curr_field = field; +} + + +void field_mark(void) +{ + if (mark) + mark->mark = curr_field; + mark = curr_field; +} + + +void field_release(void) +{ + curr_field = mark; + if (curr_field) + mark = curr_field->mark; +} + + +void field_add_selector(enum relop relop, const char *word) +{ + +} + + +void field_more_selectors(void) +{ + if (curr_field->fmt->ops != ¶m_ops_set) + ;//yyerrorf(" +} + + +void field_add_wildcard(void) +{ +} + diff --git a/b2/chr.h b/b2/chr.h new file mode 100644 index 0000000..73168df --- /dev/null +++ b/b2/chr.h @@ -0,0 +1,27 @@ +/* + * chr.h - Part characteristics + * + * 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 CHR_H +#define CHR_H + +#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); + +#endif /* !CHR_H */ diff --git a/b2/comp.c b/b2/comp.c new file mode 100644 index 0000000..2d2abeb --- /dev/null +++ b/b2/comp.c @@ -0,0 +1,110 @@ +/* + * comp.c - Parameter comparison + * + * 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 "bitset.h" +#include "param.h" + + +#define EQUAL(relop) ((relop) & (rel_le | rel_eq | rel_ge)) +#define LESS(relop) ((relop) & (rel_lt | rel_le)) +#define GREATER(relop) ((relop) & (rel_ge | rel_gt)) + + +static int do_comp_name(const char *a, enum relop relop, const char *b) +{ + int cmp; + + if (EQUAL(relop)) + return a == b; + cmp = strcmp(a, b); + assert(cmp); + if (cmp < 0) + return LESS(relop); + else + return GREATER(relop); +} + + +int comp_name(const struct value *a, enum relop relop, const struct value *b) +{ + return do_comp_name(a->u.name, relop, b->u.name); +} + + +static int do_comp_set(const struct bitset *a, enum relop relop, + const struct bitset *b) +{ + assert(!bitset_empty(a)); + assert(!bitset_empty(b)); + if (EQUAL(relop) && bitset_common(a, b)) + return 1; + if (LESS(relop) && bitset_first(a) < bitset_last(b)) + return 1; + if (GREATER(relop) && bitset_last(a) > bitset_first(b)) + return 1; + return 0; +} + + +int comp_set(const struct value *a, enum relop relop, const struct value *b) +{ + return do_comp_set(&a->u.set, relop, &b->u.set); +} + + +static int do_comp_abs(double a, enum relop relop, double b) +{ + if (a == b) + return EQUAL(relop); + if (a < b) + return LESS(relop); + else + return GREATER(relop); +} + + +int comp_abs(const struct value *a, enum relop relop, const struct value *b) +{ + return do_comp_abs(a->u.abs, relop, b->u.abs); +} + + +static int do_comp_rel(const struct rel_value *a, enum relop relop, + const struct rel_value *b) +{ + if (a->fract != b->fract) + return 0; + if (a->plus == b->plus && a->minus == b->minus) + return EQUAL(relop); + if (a->plus <= b->plus && a->minus <= b->minus) + return LESS(relop); + if (a->plus >= b->plus && a->minus >= b->minus) + return GREATER(relop); + return 0; +} + + +int comp_rel(const struct value *a, enum relop relop, const struct value *b) +{ + return do_comp_rel(&a->u.rel, relop, &b->u.rel); +} + + +int compare(const struct format *fmt, + const struct value *a, enum relop relop, const struct value *b) +{ + return fmt->ops->comp(a, relop, b); +} diff --git a/b2/db.c b/b2/db.c new file mode 100644 index 0000000..1f45359 --- /dev/null +++ b/b2/db.c @@ -0,0 +1,82 @@ +/* + * db.c - Parts database + * + * 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 "util.h" +#include "db.h" + + +static GTree *tree = NULL; + + +static gint comp(gconstpointer a, gconstpointer b) +{ + const struct part *pa = a; + const struct part *pb = b; + + /* + * Just subtracting the pointers may produce values outside the + * range of gint values. + */ + return pa->domain == pb->domain ? + pa->name < pb->name ? -1 : pa->name > pb->name ? 1 : 0 : + pa->domain < pb->domain ? -1 : 1; +} + + +struct part *part_lookup(const char *domain, const char *name) +{ + struct part part = { + .domain = domain, + .name = name, + }; + + if (!tree) + return NULL; + return g_tree_lookup(tree, &part); +} + + +struct part *part_add(const char *domain, const char *name) +{ + struct part part = { + .domain = domain, + .name = name, + }; + struct part *p; + + if (!tree) + tree = g_tree_new(comp); + p = g_tree_lookup(tree, &part); + if (!p) { + p = alloc_type(struct part); + p->stock = NULL; + p->next = p->prev = p; + g_tree_insert(tree, p, p); + } + return p; +} + + +void part_alias(struct part *a, struct part *b) +{ + struct part *tmp, *tmp2; + + tmp = a->next; + a->next = b; + b->prev->next = tmp; + + tmp2 = b->prev; + b->prev = a; + tmp->prev = tmp2; +} diff --git a/b2/db.h b/b2/db.h new file mode 100644 index 0000000..db6ec41 --- /dev/null +++ b/b2/db.h @@ -0,0 +1,66 @@ +/* + * db.h - Parts database + * + * 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 DB_H +#define DB_H + +struct exchange { + const struct currency *dst; + double factor; + struct exchange *next; +}; + +struct currency { + const char *name; + struct exchange *exchange; + struct currency *next; +}; + +struct price { + int qty; /* order quantity */ + double value; /* per quantity cost */ + const struct currency *curr; + int fract; /* 0 if > qty at same price; 1 if multiples of qty */ + struct price *next; /* next lower qty */ +}; + +struct provider { + const char *name; + double shipping; /* S&H cost */ + double minimum; /* minimum order */ + const struct currency *curr; + struct provider *next; +}; + +struct stock { + int avail; /* items in stock */ + int package; /* "natural" quantity (reel, tray, bag, etc.) */ + struct price *manual; /* single parts, for manual assembly only */ + double reeling; /* cost of converting "manual" to "fab"; <0 if n/a */ + struct price *fab; /* for automated assembly */ +} stock; + +struct part { + const char *domain; + const char *name; + struct param *param; /* NULL if @@@ */ + struct stock *stock; /* NULL if vendor part */ + struct part *next; /* alias loop (cyclic) */ + struct part *prev; +}; + + +struct part *part_lookup(const char *domain, const char *name); +struct part *part_add(const char *domain, const char *name); +void part_alias(struct part *a, struct part *b); + +#endif /* !DB_H */ diff --git a/b2/eval.c b/b2/eval.c new file mode 100644 index 0000000..dc3d804 --- /dev/null +++ b/b2/eval.c @@ -0,0 +1,216 @@ +/* + * eval.c - String to parameter + * + * 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 "bitset.h" +#include "param.h" + + +int eval_name(const struct format *fmt, const char *s, struct value *res) +{ + res->u.name = s; + return 1; +} + + +static int lookup_name(const struct names *name, const char *s) +{ + const struct equiv *eq; + int n; + + for (n = 0; name; n++) + for (eq = name->equiv; eq; eq = eq->next) + if (eq->name == s) + return n; + return -1; +} + + +int eval_set(const struct format *fmt, const char *s, struct value *res) +{ + int n; + + bitset_zero(&res->u.set); + n = lookup_name(fmt->u.set, s); + if (n < 0) + return 0; + bitset_set(&res->u.set, n); + return 1; +} + + +static int decode_mult(char c, double *mult) +{ + switch (c) { + case 'f': + *mult = 1e-15; + return 1; + case 'p': + *mult = 1e-12; + return 1; + case 'n': + *mult = 1e-9; + return 1; + case 'u': + *mult = 1e-6; + return 1; + case 'm': + *mult = 1e-3; + return 1; + case 'k': + *mult = 1e3; + return 1; + case 'M': + *mult = 1e6; + return 1; + default: + return 0; + } +} + + +static int strip_unit(const char *s, const char **stop, const char *unit, + double *mult) +{ + int n; + + n = strlen(unit); + if (*stop-n < s) + return 0; + if (!strcmp(*stop-n, unit)) + *stop -= n; + if (*stop > s) { + if (decode_mult((*stop)[-1], mult)) + (*stop)--; + else + *mult = 1; + + } else { + *mult = 1; + } + return 1; +} + + +int eval_abs(const struct format *fmt, const char *s, + struct value *res) +{ + const char *slash, *stop; + char *end; + double mult, a, b; + + stop = strchr(s, 0); + if (!strip_unit(s, &stop, fmt->u.abs, &mult)) + return 0; + slash = strchr(s, '/'); + if (!slash) { + res->u.abs = strtod(s, &end)*mult; + return end == stop; + } + a = strtod(s, &end); + if (end != slash) + return 0; + b = strtod(slash+1, &end); + if (end != stop) + return 0; + res->u.abs = a/b*mult; + return 1; +} + + +static int plusminus(const char *s, const char *slash, const char *stop, + double *plus, double *minus) +{ + char *end; + + if (s == slash || slash == stop) + return 0; + + /* -M/+P */ + if (*s == '-') { + if (slash[1] != '+') + return 0; + *minus = strtod(s+1, &end); + if (end != slash) + return 0; + *plus = strtod(slash+2, &end); + return end == stop; + } + + /* +P/-M */ + if (*s == '+') { + if (slash[1] != '-') + return 0; + *plus = strtod(s+1, &end); + if (end != slash) + return 0; + *minus = strtod(slash+2, &end); + return end == stop; + } + + /* M/P */ + *minus = strtod(s, &end); + if (end != slash) + return 0; + *plus = strtod(slash+1, &end); + return end == stop; +} + + +static int relative(const char *s, const char *stop, double *plus, + double *minus) +{ + const char *slash; + char *end; + + slash = strchr(s, '/'); + if (slash >= stop) + return 0; + if (slash) + return plusminus(s, slash, stop, plus, minus); + *plus = *minus = strtod(s, &end); + return *plus >= 0 && end == stop; +} + + +int eval_rel(const struct format *fmt, const char *s, + struct value *res) +{ + const char *perc, *stop; + double mult = 1; + + perc = strchr(s, '%'); + res->u.rel.fract = !!perc; + if (perc) { + if (perc[1]) + return 0; + return relative(s, perc, &res->u.rel.plus, &res->u.rel.minus); + } + assert(fmt->u.rel->ops == ¶m_ops_abs); + stop = strchr(s, 0); + if (!strip_unit(s, &stop, fmt->u.rel->u.abs, &mult)) + return 0; + if (!relative(s, perc, &res->u.rel.plus, &res->u.rel.minus)) + return 0; + res->u.rel.plus *= mult; + res->u.rel.minus *= mult; + return 1; +} + + +int evaluate(const struct format *fmt, const char *s, struct value *res) +{ + return fmt->ops->eval(fmt, s, res); +} diff --git a/b2/lang.l b/b2/lang.l new file mode 100644 index 0000000..766104d --- /dev/null +++ b/b2/lang.l @@ -0,0 +1,59 @@ +%{ +/* + * lang.l - BOOM syntax + * + * 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 "util.h" +#include "param.h" +#include "y.tab.h" + + +static int lineno = 1; + +%} + +%% + +[-_A-Za-z0-9()+./]+ { yylval.s = unique(yytext); + return WORD; } + +"<=" return TOK_LE; +">=" return TOK_GE; + +[ \t] ; +\n lineno++; +^#[^n]*\n lineno++; + +. return *yytext; + +%% + + +void yyerrorf(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + fprintf(stderr, "%d: ", lineno); + vfprintf(stderr, fmt, ap) ; + fprintf(stderr, "\n"); + va_end(ap); + exit(1); +} + + +void yyerror(const char *s) +{ + fprintf(stderr, "%d: %s\n", lineno, s); + exit(1); +} diff --git a/b2/lang.y b/b2/lang.y new file mode 100644 index 0000000..3a0e15a --- /dev/null +++ b/b2/lang.y @@ -0,0 +1,206 @@ +%{ +/* + * lang.y - BOOM grammar + * + * 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 "util.h" +#include "param.h" +#include "chr.h" + +#include "y.tab.h" + +%} + + +%union { + const char *s; + struct equiv *equiv; + struct names *names; + struct format *format; + enum relop relop; +}; + + +%token TOK_LE TOK_GE +%token WORD + +%type nameqs +%type names nameq +%type format +%type relop opt_relop + +%% + +all: + | nameset ';' + | rules + ; + +nameset: + '<' WORD '>' '=' names ';' + { + register_nameset($2, $5); + } + ; + +names: + nameq + { + $$ = $1; + } + | nameq '<' names + { + $$ = $1; + $$->next = $3; + } + ; + +nameq: + nameqs + { + $$ = alloc_type(struct names); + $$->equiv = $1; + $$->next = NULL; + } + ; + +nameqs: + WORD + { + $$ = alloc_type(struct equiv); + $$->name = $1; + $$->next = NULL; + } + | WORD '=' nameqs + { + $$ = alloc_type(struct equiv); + $$->name = $1; + $$->next = $3; + } + ; + +rules: + field '{' + { + field_mark(); + } + selections opt_wildcard '}' + { + field_release(); + } + ; + +selections: + | selectors ':' opt_fields rules selections + ; + +selectors: + selector + | selector '|' + { + field_more_selectors(); + } + selectors + ; + +selector: + opt_relop WORD + { + field_add_selector($1, $2); + } + ; + +opt_wildcard: + '*' ':' + { + field_add_wildcard(); + } + ; + +opt_relop: + { + $$ = rel_eq; + } + | relop + { + $$ = $1; + } + ; + +relop: + '=' + { + $$ = rel_eq; + } + | '<' + { + $$ = rel_le; + } + | '>' + { + $$ = rel_gt; + } + | TOK_LE + { + $$ = rel_le; + } + | TOK_GE + { + $$ = rel_ge; + } + ; + +opt_fields: + | '{' fields '}' + ; + +fields: + | field fields + ; + +field: + WORD ':' format + { + field_add($1, $3); + } + ; + +format: + '*' + { + $$ = alloc_type(struct format); + $$->ops = ¶m_ops_name; + } + | '<' WORD '>' + { + $$ = alloc_type(struct format); + $$->ops = ¶m_ops_set; + $$->u.set = find_nameset($2); + if (!$$->u.set) + yyerrorf("unknown name set \"%s\"", $2); + } + | '#' WORD + { + $$ = alloc_type(struct format); + $$->ops = ¶m_ops_abs; + $$->u.abs = $2; + } + | '%' WORD + { + $$ = alloc_type(struct format); + $$->ops = ¶m_ops_rel; + $$->u.rel = field_find($2); + if (!$$->u.rel) + yyerrorf("unknown field \"%s\"", $2); + } + ; diff --git a/b2/param.c b/b2/param.c new file mode 100644 index 0000000..1e2a47c --- /dev/null +++ b/b2/param.c @@ -0,0 +1,82 @@ +/* + * param.c - Parameters and values + * + * 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 "util.h" +#include "param.h" + + +static GTree *tree; + + +static int duplicate(const char *a, const struct equiv *b) +{ + while (b) { + if (a == b->name) + return 1; + b = b->next; + } + return 0; +} + + +static void check_duplicates(const struct names *n) +{ + const struct names *na, *nb; + const struct equiv *ea; + + for (na = n; na; na = na->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); + } +} + + +static gint comp(gconstpointer a, gconstpointer b) +{ + return a == b ? 0 : a < b ? -1 : 1; +} + + +void register_nameset(const char *name, const struct names *set) +{ + if (!tree) + tree = g_tree_new(comp); + if (g_tree_lookup(tree, name)) + yyerrorf("duplicate name set \"%s\"", name); + check_duplicates(set); + g_tree_insert(tree, (void *) name, (void *) set); +} + + +const struct names *find_nameset(const char *name) +{ + return tree ? g_tree_lookup(tree, name) : NULL; +} + + +#define MKOPS(type) \ + const struct param_ops param_ops_##type = { \ + .eval = eval_##type, \ + .comp = comp_##type, \ + } + + +MKOPS(name); +MKOPS(set); +MKOPS(abs); +MKOPS(rel); diff --git a/b2/param.h b/b2/param.h new file mode 100644 index 0000000..bc0753b --- /dev/null +++ b/b2/param.h @@ -0,0 +1,99 @@ +/* + * param.h - Parameters and values + * + * 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 PARAM_H +#define PARAM_H + +#include "bitset.h" + + +/* + * Parameter types: + * + * "name" arbitrary name + * "set" names from an ordered list + * "abs" absolute numeric value + * "rel" numeric value relative to another parameter + */ + + +enum relop { + rel_lt = 1 << 0, + rel_le = 1 << 1, + rel_eq = 1 << 2, + rel_ge = 1 << 3, + rel_gt = 1 << 4, +}; + +struct equiv { + const char *name; + struct equiv *next; +}; + +struct names { + struct equiv *equiv; /* equivalent value(s) */ + struct names *next; /* next/greater value */ +}; + +struct param_ops; + +struct format { + const struct param_ops *ops; + union { + const struct names *set; + const char *abs; /* unit name */ + const struct format *rel; + } u; +}; + +struct value { + union { + const char *name; + struct bitset set; + double abs; + struct rel_value { + double plus, minus; + int fract; /* 0: abs. offset; 1: fract. offs. */ + } rel; + } u; +}; + +struct param_ops { + int (*eval)(const struct format *fmt, const char *s, + struct value *res); + int (*comp)(const struct value *a, enum relop relop, + const struct value *b); +}; + + +void register_nameset(const char *name, const struct names *set); +const struct names *find_nameset(const char *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); +int eval_abs(const struct format *fmt, const char *s, struct value *res); +int eval_rel(const struct format *fmt, const char *s, struct value *res); +int evaluate(const struct format *fmt, const char *s, struct value *res); + +int comp_name(const struct value *a, enum relop relop, const struct value *b); +int comp_set(const struct value *a, enum relop relop, const struct value *b); +int comp_abs(const struct value *a, enum relop relop, const struct value *b); +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); + +extern const struct param_ops param_ops_name; +extern const struct param_ops param_ops_set; +extern const struct param_ops param_ops_abs; +extern const struct param_ops param_ops_rel; + +#endif /* !PARAM_H */ diff --git a/b2/util.c b/b2/util.c new file mode 100644 index 0000000..8b40791 --- /dev/null +++ b/b2/util.c @@ -0,0 +1,40 @@ +/* + * util.h - Utility functions + * + * 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 "util.h" + + +static GTree *tree = NULL; + + +static gint comp(gconstpointer a, gconstpointer b) +{ + return strcmp(a, b); +} + + +const char *unique(const char *s) +{ + char *u; + + if (!tree) + tree = g_tree_new(comp); + u = g_tree_lookup(tree, s); + if (!u) { + u = strdup(s); + g_tree_insert(tree, u, u); + } + return u; +} diff --git a/b2/util.h b/b2/util.h new file mode 100644 index 0000000..45ba2bf --- /dev/null +++ b/b2/util.h @@ -0,0 +1,32 @@ +/* + * util.h - Utility functions + * + * 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 UTIL_H +#define UTIL_H + +#include + + +#define alloc_size(s) \ + ({ void *alloc_size_tmp = malloc(s); \ + if (!alloc_size_tmp) \ + abort(); \ + alloc_size_tmp; }) + +#define alloc_type(t) ((t *) alloc_size(sizeof(t))) + + +const char *unique(const char *s); + +void yyerrorf(const char *fmt, ...); +void yyerror(const char *s); + +#endif /* !UTIL_H */