diff options
Diffstat (limited to '')
-rw-r--r-- | bin/.gitignore | 1 | ||||
-rw-r--r-- | bin/Makefile | 3 | ||||
-rw-r--r-- | bin/bit.y | 177 | ||||
-rw-r--r-- | bin/bitlex.l | 67 | ||||
-rw-r--r-- | bin/man1/bit.1 | 43 |
5 files changed, 144 insertions, 147 deletions
diff --git a/bin/.gitignore b/bin/.gitignore index f1d66fc3..1b9d0034 100644 --- a/bin/.gitignore +++ b/bin/.gitignore @@ -3,6 +3,7 @@ aes atch beef +bit bri brot config.mk diff --git a/bin/Makefile b/bin/Makefile index 50d60133..71540ce0 100644 --- a/bin/Makefile +++ b/bin/Makefile @@ -5,7 +5,7 @@ PREFIX = ~/.local MANDIR = $(PREFIX)/share/man CFLAGS += -Wall -Wextra -Wpedantic -LDLIBS = -lm -lutil -lz +LDLIBS = -ledit -lm -lutil -lz CFLAGS_tls = $(CFLAGS) -I$(LIBRESSL_PREFIX)/include LDFLAGS_tls = $(LDFLAGS) -L$(LIBRESSL_PREFIX)/lib @@ -18,6 +18,7 @@ LDLIBS_x11 = $(LDLIBS) -lX11 -include config.mk BINS += aes +BINS += bit BINS += dtch BINS += glitch BINS += hi diff --git a/bin/bit.y b/bin/bit.y index 8e9786da..637fe91c 100644 --- a/bin/bit.y +++ b/bin/bit.y @@ -25,27 +25,19 @@ #include <stdlib.h> #include <sysexits.h> -int yylex(void); -void yyerror(const char *str); +#define MASK(b) ((1ULL << (b)) - 1) #define YYSTYPE uint64_t -enum { RingLen = 64 }; -static struct { - uint64_t vals[RingLen]; - size_t len; -} ring; - -static void push(uint64_t val) { - ring.vals[ring.len++ % RingLen] = val; -} -static uint64_t get(size_t i) { - return ring.vals[i % RingLen]; +static void yyerror(const char *str) { + warnx("%s", str); } -%} +static int yylex(void); -%token Int Shl Shr Sar +static uint64_t result; + +%} %left '|' %left '^' @@ -56,18 +48,17 @@ static uint64_t get(size_t i) { %right '~' %left 'K' 'M' 'G' 'T' +%token Int + %% -input: - expr { push($1); } - | input ',' expr { push($3); } - | +start: + expr { result = $1; } ; expr: Int - | '_' { $$ = get(ring.len - 1); } - | '[' Int ']' { $$ = get($2); } + | '_' { $$ = result; } | '(' expr ')' { $$ = $2; } | expr 'K' { $$ = $1 << 10; } | expr 'M' { $$ = $1 << 20; } @@ -90,69 +81,74 @@ expr: %% -#include "bitlex.c" - -int yywrap(void) { - return 1; -} - -void yyerror(const char *str) { - if (yychar < 128 && isprint(yychar)) { - warnx("%s at '%c'", str, yychar); - } else { - warnx("%s at %d", str, yychar); +#define T(a, b) ((int)(a) << 8 | (int)(b)) + +static const char *input; + +static int lexInt(uint64_t base) { + for (yylval = 0; input[0]; ++input) { + uint64_t digit; + if (input[0] == '_') { + continue; + } else if (input[0] >= '0' && input[0] <= '9') { + digit = input[0] - '0'; + } else if (input[0] >= 'A' && input[0] <= 'F') { + digit = 0xA + input[0] - 'A'; + } else if (input[0] >= 'a' && input[0] <= 'f') { + digit = 0xA + input[0] - 'a'; + } else { + return Int; + } + if (digit >= base) return Int; + yylval *= base; + yylval += digit; } + return Int; } -static char *prompt(EditLine *el) { - (void)el; - static char buf[64]; - snprintf(buf, sizeof(buf), "[%zu]: ", ring.len); - return buf; -} - -static void print(size_t i) { - uint64_t val = get(i); +static int yylex(void) { + while (isspace(input[0])) input++; + if (!input[0]) return EOF; - int bits = val > UINT32_MAX ? 64 - : val > UINT16_MAX ? 32 - : val > UINT8_MAX ? 16 - : 8; - - char bin[65] = {0}; - for (int i = 0; i < 64; ++i) { - bin[i] = '0' + (val >> (63 - i) & 1); + if (input[0] == '\'' && input[1] && input[2] == '\'') { + yylval = input[1]; + input += 3; + return Int; } - printf( - "[%zu]: %"PRId64" 0x%0*"PRIX64" 0b%s", - i, (int64_t)val, bits >> 2, val, &bin[64 - bits] - ); - - if (val) { - if (!(val & (1ULL << 40) - 1)) { - printf(" %"PRId64"T", val >> 40); - } else if (!(val & (1 << 30) - 1)) { - printf(" %"PRId64"G", val >> 30); - } else if (!(val & (1 << 20) - 1)) { - printf(" %"PRId64"M", val >> 20); - } else if (!(val & (1 << 10) - 1)) { - printf(" %"PRId64"K", val >> 10); + if (input[0] == '0') { + if (input[1] == 'b') { + input += 2; + return lexInt(2); + } else if (input[1] == 'x') { + input += 2; + return lexInt(16); + } else { + input += 1; + return lexInt(8); } + } else if (isdigit(input[0])) { + return lexInt(10); } - if (val < 128 && isprint(val)) { - printf(" '%c'", (char)val); + switch (T(input[0], input[1])) { + case T('<', '<'): input += 2; return Shl; + case T('>', '>'): input += 2; return Shr; + case T('-', '>'): input += 2; return Sar; + default: return *input++; } +} - printf("\n"); +static char *prompt(EditLine *el) { + (void)el; + return ""; } int main(void) { HistEvent ev; History *hist = history_init(); if (!hist) err(EX_OSERR, "history_init"); - history(hist, &ev, H_SETSIZE, 64); + history(hist, &ev, H_SETSIZE, 100); history(hist, &ev, H_SETUNIQUE, 1); EditLine *el = el_init("bit", stdin, stdout, stderr); @@ -162,23 +158,46 @@ int main(void) { for (;;) { int len; - const char *line = el_gets(el, &len); - if (!len) break; + input = el_gets(el, &len); + if (len == 0) break; + if (len == 1) continue; + history(hist, &ev, H_ENTER, input); - HistEvent ev; - history(hist, &ev, H_ENTER, line); - - size_t i = ring.len; - - YY_BUFFER_STATE state = yy_scan_string(line); int error = yyparse(); - yy_delete_buffer(state); if (error) continue; - for (; i < ring.len; ++i) { - print(i); + int bits = result > UINT32_MAX ? 64 + : result > UINT16_MAX ? 32 + : result > UINT8_MAX ? 16 + : 8; + + printf("0x%0*"PRIX64" %"PRId64"", bits >> 2, result, (int64_t)result); + + if (bits == 8) { + char bin[9] = {0}; + for (int i = 0; i < 8; ++i) { + bin[i] = '0' + (result >> (7 - i) & 1); + } + printf(" 0b%s", bin); + } + + if (result < 128 && isprint(result)) { + printf(" '%c'", (char)result); } - printf("\n"); + + if (result) { + if (!(result & MASK(40))) { + printf(" %"PRIu64"T", result >> 40); + } else if (!(result & MASK(30))) { + printf(" %"PRIu64"G", result >> 30); + } else if (!(result & MASK(20))) { + printf(" %"PRIu64"M", result >> 20); + } else if (!(result & MASK(10))) { + printf(" %"PRIu64"K", result >> 10); + } + } + + printf("\n\n"); } el_end(el); diff --git a/bin/bitlex.l b/bin/bitlex.l deleted file mode 100644 index 4fac0a59..00000000 --- a/bin/bitlex.l +++ /dev/null @@ -1,67 +0,0 @@ -/* Copyright (C) 2019 C. McEnroe <june@causal.agency> - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -%option noinput -%option nounput - -%{ - -#include <stdint.h> - -static uint64_t parseInt(uint64_t base, const char *str) { - uint64_t num = 0; - for (const char *ch = str; *ch; ++ch) { - if (*ch == '_') continue; - num *= base; - if (*ch >= '0' && *ch <= '9') num += *ch - '0'; - if (*ch >= 'A' && *ch <= 'F') num += 0xA + *ch - 'A'; - if (*ch >= 'a' && *ch <= 'f') num += 0xA + *ch - 'a'; - } - return num; -} - -%} - -%% - -[ \t\n] ; - -0b[01_]+ { - yylval = parseInt(2, &yytext[2]); - return Int; -} -0[0-7_]+ { - yylval = parseInt(8, &yytext[1]); - return Int; -} -[0-9][0-9_]* { - yylval = parseInt(10, yytext); - return Int; -} -0x[0-9A-Fa-f_]+ { - yylval = parseInt(16, &yytext[2]); - return Int; -} -'.' { - yylval = yytext[1]; - return Int; -} - -"<<" return Shl; -">>" return Shr; -"->>" return Sar; - -. return yytext[0]; diff --git a/bin/man1/bit.1 b/bin/man1/bit.1 new file mode 100644 index 00000000..ddb26535 --- /dev/null +++ b/bin/man1/bit.1 @@ -0,0 +1,43 @@ +.Dd May 12, 2019 +.Dt BIT 1 +.Os +. +.Sh NAME +.Nm bit +.Nd a calculator +. +.Sh SYNOPSIS +.Nm +. +.Sh DESCRIPTION +.Nm +is an integer calculator. +Its syntax resembles that of C, +with the following additions: +. +.Bl -bullet +.It +Underscores are allowed in integer literals. +.It +The +.Sy 0b +prefix is used for binary literals. +.It +The +.Sy -> +operator is used for arithmetic shift. +.It +The postfix operators +.Sy K , +.Sy M , +.Sy G , +.Sy T +are used as constant multipliers. +.It +The symbol +.Sy _ +is used to refer to the previous result. +.El +. +.Sh SEE ALSO +.Xr operator 7 |