/eg/brainfuck.scm

https://github.com/msullivan/LazyK · Scheme · 188 lines · 95 code · 23 blank · 70 comment · 0 complexity · 2888f803093fc06373cf20bfe39ba466 MD5 · raw file

  1. ;; Brainfuck in Lazy K.
  2. ;; Copyright 2002 Ben Rudiak-Gould. Distributed under the GPL.
  3. ;;
  4. ;; This is not a Brainfuck interpreter, but a direct translation of
  5. ;; Brainfuck instructions into Lazy K code, just as
  6. ;;
  7. ;; + ++*p;
  8. ;; [ while (*p) {
  9. ;;
  10. ;; and so on is a direct translation of Brainfuck instructions into
  11. ;; C code. A Brainfuck program such as .[.+] is equivalent to
  12. ;; (bf-prolog (bf-write (bf-begin (bf-write (bf-inc (bf-end bf-epilog)))))).
  13. ;; The enclosed bf2lazy.c program performs this translation automatically.
  14. ;;
  15. ;; Implementation details:
  16. ;;
  17. ;; The functions communicate among themselves to obtain references to
  18. ;; whichever nearby instructions they need. In the case of [ this is the
  19. ;; following instruction and the instruction after the matching ]; in the
  20. ;; case of ] it is the following instruction and the matching [; in all
  21. ;; other cases it is the following instruction only. References to later
  22. ;; functions are passed to the left as return values, and references to
  23. ;; earlier functions are passed to the right as arguments. The bf-prolog
  24. ;; guard function creates a blank memory store and passes it to the first
  25. ;; real instruction. The bf-epilog function appends end-of-file to the
  26. ;; output, which causes Lazy K execution to terminate.
  27. ;;
  28. ;; The Brainfuck memory store is unbounded in extent in both directions from
  29. ;; the origin, and is initialized to all zeroes. It is represented as
  30. ;; (cur,left,right), where cur holds the current cell and left and right are
  31. ;; (infinite) lists of the cells to the left and right of the current cell,
  32. ;; nearest first. Each memory cell holds an 8-bit value, implemented in a
  33. ;; similar way as a pair of lists of #f with #t guards on either end,
  34. ;; representing 0. Supporting unbounded integer values would have been
  35. ;; easier; however, I discovered that many existing Brainfuck programs rely
  36. ;; on [-] zeroing a cell even when its value has been decremented below
  37. ;; zero, and this, together with the reasonable requirement that -+ be
  38. ;; always a no-op, forces the use of modular arithmetic.
  39. ;;
  40. ;; The length of translated programs could be substantially reduced by
  41. ;; moving most of the logic of the Brainfuck operations into bf-prolog and
  42. ;; turning bf-inc, etc. into simple selector functions, but that wouldn't be
  43. ;; as much fun.
  44. ;;
  45. ;; In many cases certain function arguments below are implicit, because I
  46. ;; optimized the functions by changing (lambda (x) (f x)) to f (thus hiding
  47. ;; the existence of x in this example). This isn't really necessary, since
  48. ;; Lazier performs this optimization itself, but it's fun.
  49. ;;
  50. ;; I haven't checked to see what will happen if the brackets aren't
  51. ;; balanced, or if the Brainfuck programs tries to read past end-of-file; it
  52. ;; may not be pretty.
  53. ;;
  54. ;; Unfortunately, every Brainfuck program I've run under Lazy K leaks
  55. ;; memory, even if its resource usage in Brainfuck space is constant. I
  56. ;; haven't yet discovered why this happens.
  57. ;;
  58. ;;
  59. ;; a top-level function (bf-*):
  60. ;; - is passed a list of (second-level func for next instr., second-level func for after next ], ...)
  61. ;; - returns an updated version of same
  62. ;;
  63. ;; a second-level function:
  64. ;; is passed third-level func for the previous [ test
  65. ;; returns a third-level func for self
  66. ;;
  67. ;; a third-level function:
  68. ;; is passed cur, left, right, input
  69. ;; returns output
  70. ;;
  71. (load "../lazier.scm")
  72. (load "../prelude.scm")
  73. (lazy-def 'bf-begin ; [
  74. '(lambda (fwd-list)
  75. (cons (lambda (back)
  76. ((lambda (x) (x x))
  77. (lambda (self)
  78. (lambda (cur)
  79. ((if (car (car cur))
  80. ((car (cdr fwd-list)) back)
  81. ((car fwd-list) (self self)) )
  82. cur )))))
  83. (cdr (cdr fwd-list)) )))
  84. (lazy-def 'bf-end ; ]
  85. '(lambda (fwd-list)
  86. (cons (lambda (back) back)
  87. fwd-list )))
  88. (lazy-def 'bf-inc ; +
  89. '(lambda (fwd-list)
  90. (cons (lambda (back)
  91. (lambda (cur)
  92. ((car fwd-list)
  93. back
  94. ((lambda (a b)
  95. (if (car b) (cons b a) (cons a b)) )
  96. (cons #f (car cur))
  97. (cdr (cdr cur)) ))))
  98. (cdr fwd-list) )))
  99. (lazy-def 'bf-dec ; -
  100. '(lambda (fwd-list)
  101. (cons (lambda (back)
  102. (lambda (cur)
  103. ((car fwd-list)
  104. back
  105. (cur (lambda (a b)
  106. (if (car a)
  107. (cons (cdr b) (cons #f a))
  108. (cons (cdr a) (cons #f b)) ))))))
  109. (cdr fwd-list) )))
  110. (lazy-def 'bf-left ; <
  111. '(lambda (fwd-list)
  112. (cons (lambda (back)
  113. (lambda (cur left right)
  114. ((car fwd-list)
  115. back
  116. (car left)
  117. (cdr left)
  118. (cons cur right) )))
  119. (cdr fwd-list) )))
  120. (lazy-def 'bf-right ; >
  121. '(lambda (fwd-list)
  122. (cons (lambda (back)
  123. (lambda (cur left right)
  124. ((car fwd-list)
  125. back
  126. (car right)
  127. (cons cur left)
  128. (cdr right) )))
  129. (cdr fwd-list) )))
  130. (lazy-def 'bf-read ; ,
  131. '(lambda (fwd-list)
  132. (cons (lambda (back)
  133. (lambda (cur left right input)
  134. ((car fwd-list)
  135. back
  136. (cons (((car input) (cons #f)) (k #t))
  137. (((car input) cdr) (cdr ((256 (cons #f)) (k #t)))) )
  138. left
  139. right
  140. (cdr input) )))
  141. (cdr fwd-list) )))
  142. (lazy-def 'bf-write ; .
  143. '(lambda (fwd-list)
  144. (cons (lambda (back)
  145. (lambda (cur left right input)
  146. (cons (count-to-true (car cur))
  147. ((car fwd-list) back cur left right input) )))
  148. (cdr fwd-list) )))
  149. (lazy-def 'count-to-true
  150. '((lambda (x) (x x))
  151. (lambda (self lst)
  152. (if (car lst) 0 (1+ (self self (cdr lst)))) )))
  153. (lazy-def 'bf-prolog
  154. '((lambda (cell-list)
  155. (lambda (fwd-list)
  156. ((car fwd-list)
  157. i
  158. (car cell-list)
  159. cell-list
  160. cell-list )))
  161. (list-of (cons (k #t) (cdr ((256 (cons #f)) (k #t))))) ))
  162. (lazy-def 'bf-epilog
  163. '(k (lambda (back)
  164. (lambda (cur left right input)
  165. end-of-output ))))