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.

beef.c 3.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  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. #include <err.h>
  17. #include <stdbool.h>
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include <sysexits.h>
  22. #include <time.h>
  23. enum {
  24. Cols = 80,
  25. Rows = 25,
  26. };
  27. static char page[Rows][Cols];
  28. static char get(int y, int x) {
  29. if (y < 0 || y >= Rows) return 0;
  30. if (x < 0 || x >= Cols) return 0;
  31. return page[y][x];
  32. }
  33. static void put(int y, int x, char v) {
  34. if (y < 0 || y >= Rows) return;
  35. if (x < 0 || x >= Cols) return;
  36. page[y][x] = v;
  37. }
  38. enum { StackLen = 1024 };
  39. static long stack[StackLen];
  40. static size_t top = StackLen;
  41. static void push(long val) {
  42. if (!top) errx(EX_SOFTWARE, "stack overflow");
  43. stack[--top] = val;
  44. }
  45. static long pop(void) {
  46. if (top == StackLen) return 0;
  47. return stack[top++];
  48. }
  49. static struct {
  50. int y, x;
  51. int dy, dx;
  52. } pc = { .dx = 1 };
  53. static void inc(void) {
  54. pc.y += pc.dy;
  55. pc.x += pc.dx;
  56. if (pc.y == -1) pc.y += Rows;
  57. if (pc.x == -1) pc.x += Cols;
  58. if (pc.y == Rows) pc.y -= Rows;
  59. if (pc.x == Cols) pc.x -= Cols;
  60. }
  61. static bool string;
  62. static bool step(void) {
  63. char ch = page[pc.y][pc.x];
  64. if (ch == '"') {
  65. string ^= true;
  66. } else if (string) {
  67. push(ch);
  68. inc();
  69. return true;
  70. }
  71. if (ch == '?') ch = "><^v"[rand() % 4];
  72. long x, y, v;
  73. switch (ch) {
  74. break; case '+': push(pop() + pop());
  75. break; case '-': y = pop(); x = pop(); push(x - y);
  76. break; case '*': push(pop() * pop());
  77. break; case '/': y = pop(); x = pop(); push(x / y);
  78. break; case '%': y = pop(); x = pop(); push(x % y);
  79. break; case '!': push(!pop());
  80. break; case '`': y = pop(); x = pop(); push(x > y);
  81. break; case '>': pc.dy = 0; pc.dx = +1;
  82. break; case '<': pc.dy = 0; pc.dx = -1;
  83. break; case '^': pc.dy = -1; pc.dx = 0;
  84. break; case 'v': pc.dy = +1; pc.dx = 0;
  85. break; case '_': pc.dy = 0; pc.dx = (pop() ? -1 : +1);
  86. break; case '|': pc.dx = 0; pc.dy = (pop() ? -1 : +1);
  87. break; case ':': x = pop(); push(x); push(x);
  88. break; case '\\': y = pop(); x = pop(); push(y); push(x);
  89. break; case '$': pop();
  90. break; case '.': printf("%ld ", pop()); fflush(stdout);
  91. break; case ',': printf("%c", (char)pop()); fflush(stdout);
  92. break; case '#': inc();
  93. break; case 'g': y = pop(); x = pop(); push(get(y, x));
  94. break; case 'p': y = pop(); x = pop(); v = pop(); put(y, x, v);
  95. break; case '&': x = EOF; scanf("%ld", &x); push(x);
  96. break; case '~': push(getchar());
  97. break; case '@': return false;
  98. break; default: if (ch >= '0' && ch <= '9') push(ch - '0');
  99. }
  100. inc();
  101. return true;
  102. }
  103. int main(int argc, char *argv[]) {
  104. srand(time(NULL));
  105. memset(page, ' ', sizeof(page));
  106. FILE *file = stdin;
  107. if (argc > 1) {
  108. file = fopen(argv[1], "r");
  109. if (!file) err(EX_NOINPUT, "%s", argv[1]);
  110. }
  111. int y = 0;
  112. char *line = NULL;
  113. size_t cap = 0;
  114. while (y < Rows && 0 < getline(&line, &cap, file)) {
  115. for (int x = 0; x < Cols; ++x) {
  116. if (line[x] == '\n' || !line[x]) break;
  117. page[y][x] = line[x];
  118. }
  119. y++;
  120. }
  121. free(line);
  122. while (step());
  123. return pop();
  124. }