summary refs log tree commit diff
path: root/bin/bit.y
diff options
context:
space:
mode:
Diffstat (limited to 'bin/bit.y')
-rw-r--r--bin/bit.y196
1 files changed, 102 insertions, 94 deletions
diff --git a/bin/bit.y b/bin/bit.y
index 0a9bc7ce..1119bce6 100644
--- a/bin/bit.y
+++ b/bin/bit.y
@@ -1,4 +1,4 @@
-/* Copyright (C) 2019  C. McEnroe <june@causal.agency>
+/* Copyright (C) 2019  June 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
@@ -26,15 +26,19 @@
 
 #define MASK(b) ((1ULL << (b)) - 1)
 
-static void yyerror(const char *str);
-static int yylex(void);
-
 #define YYSTYPE uint64_t
 
+static int yylex(void);
+static void yyerror(const char *str);
+static void print(uint64_t val);
+
 static uint64_t vars[128];
 
 %}
 
+%token Int Var
+
+%left '$'
 %right '='
 %left '|'
 %left '^'
@@ -45,12 +49,12 @@ static uint64_t vars[128];
 %right '~'
 %left 'K' 'M' 'G' 'T'
 
-%token Int Var
-
 %%
 
 stmt:
-	expr { vars['_'] = $1; }
+	| stmt expr '\n' { print(vars['_'] = $2); printf("\n"); }
+	| stmt expr ',' { print(vars['_'] = $2); }
+	| stmt '\n'
 	;
 
 expr:
@@ -62,7 +66,9 @@ expr:
 	| expr 'G' { $$ = $1 << 30; }
 	| expr 'T' { $$ = $1 << 40; }
 	| '~' expr { $$ = ~$2; }
-	| '-' expr { $$ = -$2; }
+	| '&' expr %prec '~' { $$ = MASK($2); }
+	| '+' expr %prec '~' { $$ = +$2; }
+	| '-' expr %prec '~' { $$ = -$2; }
 	| expr '*' expr { $$ = $1 * $3; }
 	| expr '/' expr { $$ = $1 / $3; }
 	| expr '%' expr { $$ = $1 % $3; }
@@ -75,33 +81,26 @@ expr:
 	| expr '^' expr { $$ = $1 ^ $3; }
 	| expr '|' expr { $$ = $1 | $3; }
 	| Var '=' expr { $$ = vars[$1] = $3; }
+	| expr '$' { $$ = $1; }
 	;
 
 %%
 
-static void yyerror(const char *str) {
-	warnx("%s", str);
-}
-
-#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] == '_') {
+	yylval = 0;
+	for (int ch; EOF != (ch = getchar());) {
+		uint64_t digit = base;
+		if (ch == '_') {
 			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 {
+		} else if (isdigit(ch)) {
+			digit = ch - '0';
+		} else if (isxdigit(ch)) {
+			digit = 0xA + toupper(ch) - 'A';
+		}
+		if (digit >= base) {
+			ungetc(ch, stdin);
 			return Int;
 		}
-		if (digit >= base) return Int;
 		yylval *= base;
 		yylval += digit;
 	}
@@ -109,86 +108,95 @@ static int lexInt(uint64_t base) {
 }
 
 static int yylex(void) {
-	while (isspace(input[0])) input++;
-	if (!input[0]) return EOF;
-
-	if (input[0] == '\'' && input[1] && input[2] == '\'') {
-		yylval = input[1];
-		input += 3;
+	int ch;
+	while (isblank(ch = getchar()));
+	if (ch == '\'') {
+		yylval = 0;
+		while (EOF != (ch = getchar()) && ch != '\'') {
+			yylval <<= 8;
+			yylval |= ch;
+		}
 		return Int;
-	}
-
-	if (input[0] == '0') {
-		if (input[1] == 'b') {
-			input += 2;
+	} else if (ch == '0') {
+		ch = getchar();
+		if (ch == 'b') {
 			return lexInt(2);
-		} else if (input[1] == 'x') {
-			input += 2;
+		} else if (ch == 'x') {
 			return lexInt(16);
 		} else {
-			input += 1;
+			ungetc(ch, stdin);
 			return lexInt(8);
 		}
-	} else if (isdigit(input[0])) {
+	} else if (isdigit(ch)) {
+		ungetc(ch, stdin);
 		return lexInt(10);
-	}
-	
-	if (input[0] == '_' || islower(input[0])) {
-		yylval = *input++;
+	} else if (ch == '_' || islower(ch)) {
+		yylval = ch;
 		return Var;
-	}
-
-	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++;
+	} else if (ch == '<') {
+		char ne = getchar();
+		if (ne == '<') {
+			return Shl;
+		} else {
+			ungetc(ne, stdin);
+			return ch;
+		}
+	} else if (ch == '-' || ch == '>') {
+		char ne = getchar();
+		if (ne == '>') {
+			return (ch == '-' ? Sar : Shr);
+		} else {
+			ungetc(ne, stdin);
+			return ch;
+		}
+	} else {
+		return ch;
 	}
 }
 
-int main(void) {
-	char *line = NULL;
-	size_t cap = 0;
-	while (0 < getline(&line, &cap, stdin)) {
-		if (line[0] == '\n') continue;
-
-		input = line;
-		int error = yyparse();
-		if (error) continue;
-
-		uint64_t result = vars['_'];
-
-		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);
-		}
+static void yyerror(const char *str) {
+	warnx("%s", str);
+}
 
-		if (result < 128 && isprint(result)) {
-			printf(" '%c'", (char)result);
+static const char *Codes[128] = {
+	"NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL",
+	"BS",  "HT",  "NL",  "VT",  "NP",  "CR",  "SO",  "SI",
+	"DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB",
+	"CAN", "EM",  "SUB", "ESC", "FS",  "GS",  "RS",  "US",
+	[127] = "DEL",
+};
+
+static void print(uint64_t val) {
+	int bits = val > UINT32_MAX ? 64
+		: val > UINT16_MAX ? 32
+		: val > UINT8_MAX ? 16
+		: 8;
+	printf("0x%0*"PRIX64" %"PRId64"", bits >> 2, val, (int64_t)val);
+	if (bits == 8) {
+		char bin[9] = {0};
+		for (int i = 0; i < 8; ++i) {
+			bin[i] = '0' + (val >> (7 - i) & 1);
 		}
-
-		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(" %#"PRIo64" 0b%s", val, bin);
+	}
+	if (val < 128) {
+		if (isprint(val)) printf(" '%c'", (char)val);
+		if (Codes[val]) printf(" %s", Codes[val]);
+	}
+	if (val) {
+		if (!(val & MASK(40))) {
+			printf(" %"PRIu64"T", val >> 40);
+		} else if (!(val & MASK(30))) {
+			printf(" %"PRIu64"G", val >> 30);
+		} else if (!(val & MASK(20))) {
+			printf(" %"PRIu64"M", val >> 20);
+		} else if (!(val & MASK(10))) {
+			printf(" %"PRIu64"K", val >> 10);
 		}
-
-		printf("\n\n");
 	}
+	printf("\n");
+}
+
+int main(void) {
+	while (yyparse());
 }