diff options
-rw-r--r-- | bin/bit.y | 183 | ||||
-rw-r--r-- | bin/bitlex.l | 67 |
2 files changed, 250 insertions, 0 deletions
diff --git a/bin/bit.y b/bin/bit.y new file mode 100644 index 00000000..4bf8e2d0 --- /dev/null +++ b/bin/bit.y @@ -0,0 +1,183 @@ +/* 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/>. + */ + +%{ + +#include <ctype.h> +#include <err.h> +#include <histedit.h> +#include <inttypes.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <sysexits.h> + +int yylex(void); +void yyerror(const char *str); + +#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]; +} + +%} + +%token Int Shl Shr Sar + +%left '|' +%left '^' +%left '&' +%left Shl Shr Sar +%left '+' '-' +%left '*' '/' '%' +%right '~' +%left 'K' 'M' 'G' + +%% + +input: + expr { push($1); } + | input ',' expr { push($3); } + | + ; + +expr: + Int + | '_' { $$ = get(ring.len - 1); } + | '[' Int ']' { $$ = get($2); } + | '(' expr ')' { $$ = $2; } + | expr 'K' { $$ = $1 << 10; } + | expr 'M' { $$ = $1 << 20; } + | expr 'G' { $$ = $1 << 30; } + | '~' expr { $$ = ~$2; } + | '-' expr { $$ = -$2; } + | expr '*' expr { $$ = $1 * $3; } + | expr '/' expr { $$ = $1 / $3; } + | expr '%' expr { $$ = $1 % $3; } + | expr '+' expr { $$ = $1 + $3; } + | expr '-' expr { $$ = $1 - $3; } + | expr Shl expr { $$ = $1 << $3; } + | expr Shr expr { $$ = $1 >> $3; } + | expr Sar expr { $$ = (int64_t)$1 >> $3; } + | expr '&' expr { $$ = $1 & $3; } + | expr '^' expr { $$ = $1 ^ $3; } + | expr '|' expr { $$ = $1 | $3; } + ; + +%% + +#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); + } +} + +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); + + 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); + } + + printf( + "[%zu]: %"PRId64" 0x%0*"PRIX64" 0b%s", + i, (int64_t)val, bits >> 2, val, &bin[64 - bits] + ); + + if (val) { + 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 (val < 128 && isprint(val)) { + printf(" '%c'", (char)val); + } + + printf("\n"); +} + +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_SETUNIQUE, 1); + + EditLine *el = el_init("bit", stdin, stdout, stderr); + if (!el) err(EX_IOERR, "el_init"); + el_set(el, EL_PROMPT, prompt); + el_set(el, EL_HIST, history, hist); + + for (;;) { + int len; + const char *line = el_gets(el, &len); + if (!len) break; + + 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); + } + printf("\n"); + } + + el_end(el); + history_end(hist); +} diff --git a/bin/bitlex.l b/bin/bitlex.l new file mode 100644 index 00000000..4fac0a59 --- /dev/null +++ b/bin/bitlex.l @@ -0,0 +1,67 @@ +/* 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]; |