commit 22aa3b95e597972d18bd7200dc39f982f7e5ab2a
parent 5b18649ed4a2610a4c367b800133e6a84f11bd60
Author: William Casarin <jb55@jb55.com>
Date: Sat, 16 Dec 2017 20:12:52 -0800
workingish
Diffstat:
A | .gitignore | | | 4 | ++++ |
A | Makefile | | | 23 | +++++++++++++++++++++++ |
M | lexer.l | | | 29 | ++++++++++++++++++----------- |
A | num.c | | | 100 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
M | num.h | | | 10 | ++++++++++ |
M | parser.y | | | 27 | ++++++++++++++++----------- |
D | unit.c | | | 54 | ------------------------------------------------------ |
7 files changed, 171 insertions(+), 76 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -0,0 +1,4 @@
+/lex.yy.c
+/parser.tab.c
+/parser.tab.h
+/bcalc
diff --git a/Makefile b/Makefile
@@ -0,0 +1,23 @@
+
+BIN=bcalc
+GEN=parser.tab.c parser.tab.h lex.yy.c
+PREFIX ?= /usr/local
+SRCS=num.c
+
+all: $(BIN)
+
+parser.tab.c parser.tab.h: parser.y
+ bison -d parser.y
+
+lex.yy.c: lexer.l parser.tab.h
+ flex lexer.l
+
+install: $(BIN)
+ mkdir -p $(PREFIX)/bin
+ cp $(BIN) $(PREFIX)/bin
+
+$(BIN): $(GEN)
+ $(CC) -o $@ $(SRCS) parser.tab.c lex.yy.c
+
+clean:
+ rm -f $(GEN)
diff --git a/lexer.l b/lexer.l
@@ -1,13 +1,11 @@
-
-
%option noyywrap
%{
#include <stdio.h>
#include <gmp.h>
+#include "num.h"
#define YY_DECL int yylex()
- extern YYSTYPE yylval;
#include "parser.tab.h"
@@ -17,28 +15,37 @@
[ \t] ; // ignore all whitespace
+[bB][iI][tT][sS]? {
+ yylval.unit = UNIT_BITS;
+ return T_UNIT;
+}
+
[mM]?[bB][tT][cC] {
int ism = yytext[0] == 'm' || yytext[0] == 'M';
yylval.unit = ism? UNIT_MBTC : UNIT_BTC;
return T_UNIT;
}
+[fF][iI][nN][nN][eE][yY]? {
+ yylval.unit = UNIT_FINNEY;
+ return T_UNIT;
+}
+
[mM]?[sS][aA][tT][sS]? {
- int ism = yytext[0] == 'm' || yytext[0] == 'M';
- yylval.unit = ism ? UNIT_MSATOSHI : UNIT_SATOSHI;
- return T_UNIT;
+ int ism = yytext[0] == 'm' || yytext[0] == 'M';
+ yylval.unit = ism ? UNIT_MSATOSHI : UNIT_SATOSHI;
+ return T_UNIT;
}
[0-9]*\.[0-9]+ {
double d = atof(yytext);
- yylval.dubs = d;
+ yylval.floatval = d;
return T_FLOAT;
}
-[0-9]+ {
- mpq_init(yylval.rval);
- mpz_set_str(yylval.rval, yytext, 10);
- return T_INT;
+[0-9]+ {
+ yylval.intval = strtoll(yytext, NULL, 10);
+ return T_INT;
}
\n {return T_NEWLINE;}
diff --git a/num.c b/num.c
@@ -0,0 +1,100 @@
+
+#include <stdio.h>
+#include <assert.h>
+#include <math.h>
+#include <inttypes.h>
+#include "num.h"
+
+void
+num_init(struct num *num) {
+ num->type = TYPE_INT;
+ num->unit = UNIT_BTC;
+ num->intval = 0LL;
+}
+
+static int64_t
+num_to_msat(struct num *num) {
+ if (num->type == TYPE_FLOAT) {
+ double val = num->floatval;
+ switch (num->unit) {
+ case UNIT_MSATOSHI:
+ assert("fractional millisatoshis are not yet supported");
+ return (int64_t)val;
+ case UNIT_SATOSHI:
+ return (int64_t)(val * 1000);
+ case UNIT_FINNEY:
+ return (int64_t)(val * 10000);
+ case UNIT_BITS:
+ return (int64_t)(val * 100000);
+ case UNIT_MBTC:
+ return (int64_t)(val * 100000000);
+ case UNIT_BTC:
+ return (int64_t)(val * 100000000000);
+ }
+ }
+
+ int64_t val = num->intval;
+ switch (num->unit) {
+ case UNIT_MSATOSHI:
+ return val;
+ case UNIT_SATOSHI:
+ return val * 1000;
+ case UNIT_FINNEY:
+ return val * 10000;
+ case UNIT_BITS:
+ return val * 100000;
+ case UNIT_MBTC:
+ return val * 100000000;
+ case UNIT_BTC:
+ return val * 100000000000;
+ }
+}
+
+#define num_op (op)
+
+void
+num_add(struct num *dst, struct num *a, struct num *b) {
+ dst->type = TYPE_INT;
+ dst->unit = UNIT_MSATOSHI;
+ dst->intval = num_to_msat(a) + num_to_msat(b);
+}
+
+
+void
+num_sub(struct num *dst, struct num *a, struct num *b) {
+ dst->type = TYPE_INT;
+ dst->unit = UNIT_MSATOSHI;
+ dst->intval = num_to_msat(a) - num_to_msat(b);
+}
+
+void
+num_mul(struct num *dst, struct num *a, struct num *b) {
+ dst->type = TYPE_INT;
+ dst->unit = UNIT_MSATOSHI;
+ dst->intval = num_to_msat(a) * num_to_msat(b);
+}
+
+void
+num_div(struct num *dst, struct num *a, struct num *b) {
+ dst->type = TYPE_INT;
+ dst->unit = UNIT_MSATOSHI;
+ dst->intval = num_to_msat(a) / num_to_msat(b);
+ assert(fabs((double)dst->intval -
+ ((double)num_to_msat(a) / (double)num_to_msat(b))) <= 0.00005);
+}
+
+void
+num_assign(struct num *dst, struct num *a) {
+ dst->type = TYPE_INT;
+ dst->unit = UNIT_MSATOSHI;
+ dst->intval = num_to_msat(a);
+}
+
+
+void
+num_print(struct num *num) {
+ if (num->type == TYPE_FLOAT)
+ printf("%f ", num->floatval);
+ else
+ printf("%" PRId64, num->intval);
+}
diff --git a/num.h b/num.h
@@ -34,4 +34,14 @@ struct num
};
};
+
+
+void num_add(struct num *dst, struct num *a, struct num *b);
+void num_sub(struct num *dst, struct num *a, struct num *b);
+void num_mul(struct num *dst, struct num *a, struct num *b);
+void num_div(struct num *dst, struct num *a, struct num *b);
+void num_assign(struct num *dst, struct num *a);
+void num_init(struct num *num);
+void num_print(struct num *num);
+
#endif /* UNIT_H */
diff --git a/parser.y b/parser.y
@@ -1,10 +1,10 @@
-
%{
#include <stdio.h>
-#include <num.h>
#include <stdlib.h>
+#include "num.h"
+
extern int yylex();
extern int yyparse();
extern FILE* yyin;
@@ -17,18 +17,20 @@ void yyerror(const char* s);
%union {
int64_t intval;
double floatval;
- enum units unit;
+ enum unit unit;
+ struct num num;
}
%token<intval> T_INT
%token<floatval> T_FLOAT
%token<unit> T_UNIT
+
%token T_PLUS T_MINUS T_MULTIPLY T_DIVIDE T_LEFT T_RIGHT
%token T_NEWLINE T_QUIT
%left T_PLUS T_MINUS
%left T_MULTIPLY T_DIVIDE
-%type<rval> expr
+%type<num> expr
%start calc
@@ -39,15 +41,18 @@ calc:
;
line: T_NEWLINE
- | expr T_NEWLINE { mpq_out_str(stdout, 10, $1); printf("\n"); }
+ | expr T_NEWLINE { num_print(&$1); printf("\n"); }
;
-expr: T_INT { ; }
- | expr T_PLUS expr { mpq_add($$, $1, $3); }
- | expr T_MINUS expr { mpq_sub($$, $1, $3); }
- | expr T_MULTIPLY expr { mpq_mul($$, $1, $3); }
- | expr T_DIVIDE expr { mpq_div($$, $1, $3); }
- | T_LEFT expr T_RIGHT { mpq_init($$); mpq_set($$, $2); }
+expr: T_INT { num_init(&$$); }
+ | T_FLOAT { num_init(&$$); $$.floatval = $1; }
+ | T_INT T_UNIT { num_init(&$$); $$.intval = $1; $$.unit = $2; }
+ | T_FLOAT T_UNIT { num_init(&$$); $$.floatval = $1; $$.unit = $2; }
+ | expr T_PLUS expr { num_add(&$$, &$1, &$3); }
+ | expr T_MINUS expr { num_sub(&$$, &$1, &$3); }
+ | expr T_MULTIPLY expr { num_mul(&$$, &$1, &$3); }
+ | expr T_DIVIDE expr { num_div(&$$, &$1, &$3); }
+ | T_LEFT expr T_RIGHT { num_init(&$$); num_assign(&$$, &$2); }
;
%%
diff --git a/unit.c b/unit.c
@@ -1,54 +0,0 @@
-
-#include <assert.h>
-#include "num.h"
-
-void
-num_init(struct num *num) {
- num->type = TYPE_INT;
- num->unit = UNIT_BTC;
- num->intval = 0LL;
-}
-
-static int64_t
-num_to_msat(struct num *num) {
- if (num->type == TYPE_FLOAT) {
- double val = num->floatval;
- switch (num->unit) {
- case UNIT_MSATOSHI:
- assert("fractional millisatoshis are not yet supported");
- return (int64_t)val;
- case UNIT_SATOSHI:
- return (int64_t)(val * 1000);
- case UNIT_FINNEY:
- return (int64_t)(val * 10000);
- case UNIT_BITS:
- return (int64_t)(val * 100000);
- case UNIT_MBTC:
- return (int64_t)(val * 100000000);
- case UNIT_BTC:
- return (int64_t)(val * 100000000000);
- }
- }
-
- int64_t val = num->intval;
- switch (num->unit) {
- case UNIT_MSATOSHI:
- return val;
- case UNIT_SATOSHI:
- return val * 1000;
- case UNIT_FINNEY:
- return val * 10000;
- case UNIT_BITS:
- return val * 100000;
- case UNIT_MBTC:
- return val * 100000000;
- case UNIT_BTC:
- return val * 100000000000;
- }
-}
-
-
-int64_t
-num_add(struct num *a, struct num *b) {
- return (num_to_msat(a) + num_to_msat(b));
-}