diff --git a/b2/CURR b/b2/CURR new file mode 100644 index 0000000..c43151a --- /dev/null +++ b/b2/CURR @@ -0,0 +1,2 @@ +EUR USD 1.3214 GBP 1.62542 +GBP USD 0.615219 diff --git a/b2/Makefile b/b2/Makefile index d578867..e3db6b7 100644 --- a/b2/Makefile +++ b/b2/Makefile @@ -83,4 +83,4 @@ spotless: clean # ----- Experiments ----------------------------------------------------------- try: - $(VALGRIND) ./boom HIERARCHY -c CHAR -i INV + $(VALGRIND) ./boom HIERARCHY -c CHAR -x CURR -i INV diff --git a/b2/boom.c b/b2/boom.c index ad8c3bf..307ca4e 100644 --- a/b2/boom.c +++ b/b2/boom.c @@ -42,6 +42,7 @@ static void usage(const char *name) " file types:\n" " -c characteristics\n" " -i inventory\n" +" -x currency exchange\n" , name); exit(1); } @@ -58,6 +59,8 @@ int main(int argc, char **argv) parse = parse_characteristics; else if (!strcmp(argv[i], "-i")) parse = parse_inventory; + else if (!strcmp(argv[i], "-x")) + parse = parse_currencies; else usage(*argv); } else { diff --git a/b2/db.c b/b2/db.c index 12e508c..432554a 100644 --- a/b2/db.c +++ b/b2/db.c @@ -173,7 +173,7 @@ static void dump_stock(FILE *file, const struct stock *s) const struct price *p; fprintf(file, " %s %d %d %s %g", - s->cat, s->avail, s->package, "???", s->add); + s->cat, s->avail, s->package, s->curr->name, s->add); for (p = s->price; p; p = p->next) fprintf(file, " %d %g", p->qty, p->value); fprintf(file, "\n"); @@ -196,3 +196,64 @@ void part_dump(FILE *file, const struct part *part) if (part->stock) dump_stock(file, part->stock); } + + +/* ----- Currencies -------------------------------------------------------- */ + + +static struct currency *currencies = NULL; + + +const struct currency *currency_lookup(const char *name) +{ + const struct currency *c; + + for (c = currencies; c; c = c->next) + if (c->name == name) + break; + return c; +} + + +double currency_convert(const struct currency *from, const struct currency *to, + double value) +{ + const struct exchange *ex; + + for (ex = from->exchange; ex; ex = ex->next) + if (ex->dst == to) + return ex->rate*value; + fprintf(stderr, "cannot convert %s to %s\n", from->name, to->name); + exit(1); +} + + +struct currency *currency_add(const char *name) +{ + struct currency **c; + + for (c = ¤cies; *c; c = &(*c)->next) + if ((*c)->name == name) + return *c; + *c = alloc_type(struct currency); + (*c)->name = name; + (*c)->exchange = NULL; + (*c)->next = NULL; + return *c; +} + + +void currency_exchange(struct currency *from, const struct currency *to, + double rate) +{ + struct exchange **ex; + + for (ex = &from->exchange; *ex; ex = &(*ex)->next) + if ((*ex)->dst == to) + yyerrorf("exchange %s -> %s is already defined", + from->name, to->name); + *ex = alloc_type(struct exchange); + (*ex)->dst = to; + (*ex)->rate = rate; + (*ex)->next = NULL; +} diff --git a/b2/db.h b/b2/db.h index d5e92e4..85fb505 100644 --- a/b2/db.h +++ b/b2/db.h @@ -18,7 +18,7 @@ struct exchange { const struct currency *dst; - double factor; + double rate; /* dst = rate*src */ struct exchange *next; }; @@ -98,4 +98,11 @@ void part_finalize(struct part *part, const struct action *act); void part_add_stock(struct part *part, struct stock *stock); void part_dump(FILE *file, const struct part *part); +const struct currency *currency_lookup(const char *name); +double currency_convert(const struct currency *from, const struct currency *to, + double value); +struct currency *currency_add(const char *name); +void currency_exchange(struct currency *from, const struct currency *to, + double rate); + #endif /* !DB_H */ diff --git a/b2/lang.h b/b2/lang.h index ae61fca..6239d6b 100644 --- a/b2/lang.h +++ b/b2/lang.h @@ -16,6 +16,7 @@ void parse_hierarchy(void); void parse_characteristics(void); void parse_inventory(void); +void parse_currencies(void); void yywarnf(const char *fmt, ...); void yyerrorf(const char *fmt, ...); diff --git a/b2/lang.l b/b2/lang.l index ac27462..f74ee70 100644 --- a/b2/lang.l +++ b/b2/lang.l @@ -53,6 +53,14 @@ void parse_inventory(void) yyparse(); } +void parse_currencies(void) +{ + start_token = START_EXCHANGE; + expose_nl = 1; + lineno = 1; + yyparse(); +} + %} diff --git a/b2/lang.y b/b2/lang.y index 04b0bd9..708b8ff 100644 --- a/b2/lang.y +++ b/b2/lang.y @@ -24,6 +24,8 @@ static struct action hierarchy; +static struct currency *curr; + static struct field_stack { const struct field *field; @@ -82,6 +84,7 @@ static const struct field *top_field(void) %token START_HIERARCHY START_CHAR START_INVENTORY +%token START_EXCHANGE %token TOK_LE TOK_GE TOK_NL %token WORD @@ -106,6 +109,7 @@ all: START_HIERARCHY hierarchy | START_CHAR characteristics | START_INVENTORY inventory + | START_EXCHANGE exchange ; @@ -432,7 +436,9 @@ stock: $$->cat = $1; $$->avail = $2; $$->package = $3; - $$->curr = NULL; /* @@@ later -- currency($4); */ + $$->curr = currency_lookup($4); + if (!$$->curr) + yyerrorf("unknown currency %s", $4); $$->add = $5; $$->price = $6; } @@ -481,3 +487,36 @@ float: yyerrorf("\"%s\" is not a number", $1); } ; + + +/* ----- Currency exchange ------------------------------------------------- */ + + +exchange: + | TOK_NL + | currency exchange + ; + +currency: + WORD + { + curr = currency_add($1); + } + rates TOK_NL + ; + +rates: + | rate rates + ; + +rate: + WORD float + { + const struct currency *to; + + /* add and not lookup, since we just introduce the + currency here */ + to = currency_add($1); + currency_exchange(curr, to, $2); + } + ;