bcalc

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

commit 5b18649ed4a2610a4c367b800133e6a84f11bd60
Author: William Casarin <jb55@jb55.com>
Date:   Sat, 16 Dec 2017 19:00:32 -0800

bcalc: init at something not working

Diffstat:
Alexer.l | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
Anum.h | 37+++++++++++++++++++++++++++++++++++++
Aparser.y | 68++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aunit.c | 54++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 211 insertions(+), 0 deletions(-)

diff --git a/lexer.l b/lexer.l @@ -0,0 +1,52 @@ + + +%option noyywrap + +%{ +#include <stdio.h> +#include <gmp.h> + +#define YY_DECL int yylex() + extern YYSTYPE yylval; + +#include "parser.tab.h" + +%} + +%% + +[ \t] ; // ignore all whitespace + +[mM]?[bB][tT][cC] { + int ism = yytext[0] == 'm' || yytext[0] == 'M'; + yylval.unit = ism? UNIT_MBTC : UNIT_BTC; + 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; +} + +[0-9]*\.[0-9]+ { + double d = atof(yytext); + yylval.dubs = d; + return T_FLOAT; +} + +[0-9]+ { + mpq_init(yylval.rval); + mpz_set_str(yylval.rval, yytext, 10); + return T_INT; +} + +\n {return T_NEWLINE;} +"+" {return T_PLUS;} +"-" {return T_MINUS;} +"*" {return T_MULTIPLY;} +"/" {return T_DIVIDE;} +"(" {return T_LEFT;} +")" {return T_RIGHT;} + +%% diff --git a/num.h b/num.h @@ -0,0 +1,37 @@ + +#ifndef UNIT_H +#define UNIT_H + +#include <stdint.h> + +#define MSATOSHI 100000000000LL +#define SATOSHI 100000000LL +#define FINNEY 10000000LL +#define BITS 1000000LL +#define MBTC 1000LL + +enum unit { + UNIT_BTC, + UNIT_MBTC, + UNIT_BITS, + UNIT_FINNEY, + UNIT_SATOSHI, + UNIT_MSATOSHI, +}; + +enum num_type { + TYPE_INT, + TYPE_FLOAT +}; + +struct num +{ + enum num_type type; + enum unit unit; + union { + int64_t intval; + double floatval; + }; +}; + +#endif /* UNIT_H */ diff --git a/parser.y b/parser.y @@ -0,0 +1,68 @@ + +%{ + +#include <stdio.h> +#include <num.h> +#include <stdlib.h> + +extern int yylex(); +extern int yyparse(); +extern FILE* yyin; + +char buffer[255]; + +void yyerror(const char* s); +%} + +%union { + int64_t intval; + double floatval; + enum units unit; +} + +%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 + +%start calc + +%% + +calc: + | calc line +; + +line: T_NEWLINE + | expr T_NEWLINE { mpq_out_str(stdout, 10, $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); } +; + +%% + +int main() { + yyin = stdin; + + do { + yyparse(); + } while(!feof(yyin)); + + return 0; +} + +void yyerror(const char* s) { + fprintf(stderr, "Parse error: %s\n", s); + exit(1); +} diff --git a/unit.c b/unit.c @@ -0,0 +1,54 @@ + +#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)); +}