Brainfuck compiler
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.

bf.c 3.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <stdint.h>
  5. #include <assert.h>
  6. #include <errno.h>
  7. #define exit_fatal(...) \
  8. do { \
  9. fprintf (stderr, "fatal: " __VA_ARGS__); \
  10. exit (EXIT_FAILURE); \
  11. } while (0)
  12. // --- Safe memory management --------------------------------------------------
  13. static void *
  14. xmalloc (size_t n)
  15. {
  16. void *p = malloc (n);
  17. if (!p)
  18. exit_fatal ("malloc: %s\n", strerror (errno));
  19. return p;
  20. }
  21. static void *
  22. xrealloc (void *o, size_t n)
  23. {
  24. void *p = realloc (o, n);
  25. if (!p && n)
  26. exit_fatal ("realloc: %s\n", strerror (errno));
  27. return p;
  28. }
  29. // --- Dynamically allocated strings -------------------------------------------
  30. struct str
  31. {
  32. char *str; ///< String data, null terminated
  33. size_t alloc; ///< How many bytes are allocated
  34. size_t len; ///< How long the string actually is
  35. };
  36. static void
  37. str_init (struct str *self)
  38. {
  39. self->alloc = 16;
  40. self->len = 0;
  41. self->str = strcpy (xmalloc (self->alloc), "");
  42. }
  43. static void
  44. str_ensure_space (struct str *self, size_t n)
  45. {
  46. // We allocate at least one more byte for the terminating null character
  47. size_t new_alloc = self->alloc;
  48. while (new_alloc <= self->len + n)
  49. new_alloc <<= 1;
  50. if (new_alloc != self->alloc)
  51. self->str = xrealloc (self->str, (self->alloc = new_alloc));
  52. }
  53. static void
  54. str_append_data (struct str *self, const void *data, size_t n)
  55. {
  56. str_ensure_space (self, n);
  57. memcpy (self->str + self->len, data, n);
  58. self->len += n;
  59. self->str[self->len] = '\0';
  60. }
  61. static void
  62. str_append_c (struct str *self, char c)
  63. {
  64. str_append_data (self, &c, 1);
  65. }
  66. // --- Main --------------------------------------------------------------------
  67. int
  68. main (int argc, char *argv[])
  69. {
  70. struct str program; str_init (&program);
  71. struct str data; str_init (&data);
  72. int c;
  73. while ((c = fgetc (stdin)) != EOF)
  74. str_append_c (&program, c);
  75. if (ferror (stdin))
  76. exit_fatal ("can't read program\n");
  77. FILE *input = fopen ("/dev/tty", "rb");
  78. if (!input)
  79. exit_fatal ("can't open terminal for reading\n");
  80. size_t dataptr = 0;
  81. str_append_c (&data, 0);
  82. for (size_t i = 0; i < program.len; i++)
  83. {
  84. switch (program.str[i])
  85. {
  86. long pairs;
  87. case '>':
  88. assert (dataptr != SIZE_MAX);
  89. dataptr++;
  90. if (dataptr == data.len)
  91. str_append_c (&data, 0);
  92. break;
  93. case '<':
  94. assert (dataptr != 0);
  95. dataptr--;
  96. break;
  97. case '+': data.str[dataptr]++; break;
  98. case '-': data.str[dataptr]--; break;
  99. case '.':
  100. fputc (data.str[dataptr], stdout);
  101. break;
  102. case ',':
  103. data.str[dataptr] = c = fgetc (input);
  104. assert (c != EOF);
  105. break;
  106. case '[':
  107. if (data.str[dataptr]) break;
  108. for (pairs = 0; i < program.len; i++)
  109. {
  110. switch (program.str[i])
  111. {
  112. case '[': pairs++; break;
  113. case ']': pairs--; break;
  114. }
  115. if (!pairs)
  116. break;
  117. }
  118. assert (!pairs);
  119. break;
  120. case ']':
  121. if (!data.str[dataptr]) break;
  122. for (pairs = 0; i != SIZE_MAX; i--)
  123. {
  124. switch (program.str[i])
  125. {
  126. case '[': pairs--; break;
  127. case ']': pairs++; break;
  128. }
  129. if (!pairs)
  130. break;
  131. }
  132. assert (!pairs);
  133. break;
  134. default:
  135. break;
  136. }
  137. }
  138. return 0;
  139. }