The repository formerly known as dotfiles
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

bit.y 4.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. /* Copyright (C) 2019 C. McEnroe <june@causal.agency>
  2. *
  3. * This program is free software: you can redistribute it and/or modify
  4. * it under the terms of the GNU Affero General Public License as published by
  5. * the Free Software Foundation, either version 3 of the License, or
  6. * (at your option) any later version.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU Affero General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU Affero General Public License
  14. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. */
  16. %{
  17. #include <ctype.h>
  18. #include <err.h>
  19. #include <inttypes.h>
  20. #include <stdint.h>
  21. #include <stdio.h>
  22. #include <stdlib.h>
  23. #include <sysexits.h>
  24. #define MASK(b) ((1ULL << (b)) - 1)
  25. static void yyerror(const char *str);
  26. static int yylex(void);
  27. #define YYSTYPE uint64_t
  28. static uint64_t vars[128];
  29. %}
  30. %right '='
  31. %left '|'
  32. %left '^'
  33. %left '&'
  34. %left Shl Shr Sar
  35. %left '+' '-'
  36. %left '*' '/' '%'
  37. %right '~'
  38. %left 'K' 'M' 'G' 'T'
  39. %token Int Var
  40. %%
  41. stmt:
  42. expr { vars['_'] = $1; }
  43. ;
  44. expr:
  45. Int
  46. | Var { $$ = vars[$1]; }
  47. | '(' expr ')' { $$ = $2; }
  48. | expr 'K' { $$ = $1 << 10; }
  49. | expr 'M' { $$ = $1 << 20; }
  50. | expr 'G' { $$ = $1 << 30; }
  51. | expr 'T' { $$ = $1 << 40; }
  52. | '~' expr { $$ = ~$2; }
  53. | '-' expr { $$ = -$2; }
  54. | expr '*' expr { $$ = $1 * $3; }
  55. | expr '/' expr { $$ = $1 / $3; }
  56. | expr '%' expr { $$ = $1 % $3; }
  57. | expr '+' expr { $$ = $1 + $3; }
  58. | expr '-' expr { $$ = $1 - $3; }
  59. | expr Shl expr { $$ = $1 << $3; }
  60. | expr Shr expr { $$ = $1 >> $3; }
  61. | expr Sar expr { $$ = (int64_t)$1 >> $3; }
  62. | expr '&' expr { $$ = $1 & $3; }
  63. | expr '^' expr { $$ = $1 ^ $3; }
  64. | expr '|' expr { $$ = $1 | $3; }
  65. | Var '=' expr { $$ = vars[$1] = $3; }
  66. ;
  67. %%
  68. static void yyerror(const char *str) {
  69. warnx("%s", str);
  70. }
  71. #define T(a, b) ((int)(a) << 8 | (int)(b))
  72. static const char *input;
  73. static int lexInt(uint64_t base) {
  74. for (yylval = 0; input[0]; ++input) {
  75. uint64_t digit;
  76. if (input[0] == '_') {
  77. continue;
  78. } else if (input[0] >= '0' && input[0] <= '9') {
  79. digit = input[0] - '0';
  80. } else if (input[0] >= 'A' && input[0] <= 'F') {
  81. digit = 0xA + input[0] - 'A';
  82. } else if (input[0] >= 'a' && input[0] <= 'f') {
  83. digit = 0xA + input[0] - 'a';
  84. } else {
  85. return Int;
  86. }
  87. if (digit >= base) return Int;
  88. yylval *= base;
  89. yylval += digit;
  90. }
  91. return Int;
  92. }
  93. static int yylex(void) {
  94. while (isspace(input[0])) input++;
  95. if (!input[0]) return EOF;
  96. if (input[0] == '\'' && input[1] && input[2] == '\'') {
  97. yylval = input[1];
  98. input += 3;
  99. return Int;
  100. }
  101. if (input[0] == '0') {
  102. if (input[1] == 'b') {
  103. input += 2;
  104. return lexInt(2);
  105. } else if (input[1] == 'x') {
  106. input += 2;
  107. return lexInt(16);
  108. } else {
  109. input += 1;
  110. return lexInt(8);
  111. }
  112. } else if (isdigit(input[0])) {
  113. return lexInt(10);
  114. }
  115. if (input[0] == '_' || islower(input[0])) {
  116. yylval = *input++;
  117. return Var;
  118. }
  119. switch (T(input[0], input[1])) {
  120. case T('<', '<'): input += 2; return Shl;
  121. case T('>', '>'): input += 2; return Shr;
  122. case T('-', '>'): input += 2; return Sar;
  123. default: return *input++;
  124. }
  125. }
  126. int main(void) {
  127. char *line = NULL;
  128. size_t cap = 0;
  129. while (0 < getline(&line, &cap, stdin)) {
  130. if (line[0] == '\n') continue;
  131. input = line;
  132. int error = yyparse();
  133. if (error) continue;
  134. uint64_t result = vars['_'];
  135. int bits = result > UINT32_MAX ? 64
  136. : result > UINT16_MAX ? 32
  137. : result > UINT8_MAX ? 16
  138. : 8;
  139. printf("0x%0*"PRIX64" %"PRId64"", bits >> 2, result, (int64_t)result);
  140. if (bits == 8) {
  141. char bin[9] = {0};
  142. for (int i = 0; i < 8; ++i) {
  143. bin[i] = '0' + (result >> (7 - i) & 1);
  144. }
  145. printf(" 0b%s", bin);
  146. }
  147. if (result < 128 && isprint(result)) {
  148. printf(" '%c'", (char)result);
  149. }
  150. if (result) {
  151. if (!(result & MASK(40))) {
  152. printf(" %"PRIu64"T", result >> 40);
  153. } else if (!(result & MASK(30))) {
  154. printf(" %"PRIu64"G", result >> 30);
  155. } else if (!(result & MASK(20))) {
  156. printf(" %"PRIu64"M", result >> 20);
  157. } else if (!(result & MASK(10))) {
  158. printf(" %"PRIu64"K", result >> 10);
  159. }
  160. }
  161. printf("\n\n");
  162. }
  163. }