bcalc

cli bitcoin unit calculator
git clone git://jb55.com/bcalc
Log | Files | Refs | README | LICENSE

commit 22aa3b95e597972d18bd7200dc39f982f7e5ab2a
parent 5b18649ed4a2610a4c367b800133e6a84f11bd60
Author: William Casarin <jb55@jb55.com>
Date:   Sat, 16 Dec 2017 20:12:52 -0800

workingish

Diffstat:
A.gitignore | 4++++
AMakefile | 23+++++++++++++++++++++++
Mlexer.l | 29++++++++++++++++++-----------
Anum.c | 100+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mnum.h | 10++++++++++
Mparser.y | 27++++++++++++++++-----------
Dunit.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)); -}