/eg/brainfuck.scm
https://github.com/msullivan/LazyK · Scheme · 188 lines · 95 code · 23 blank · 70 comment · 0 complexity · 2888f803093fc06373cf20bfe39ba466 MD5 · raw file
- ;; Brainfuck in Lazy K.
- ;; Copyright 2002 Ben Rudiak-Gould. Distributed under the GPL.
- ;;
- ;; This is not a Brainfuck interpreter, but a direct translation of
- ;; Brainfuck instructions into Lazy K code, just as
- ;;
- ;; + ++*p;
- ;; [ while (*p) {
- ;;
- ;; and so on is a direct translation of Brainfuck instructions into
- ;; C code. A Brainfuck program such as .[.+] is equivalent to
- ;; (bf-prolog (bf-write (bf-begin (bf-write (bf-inc (bf-end bf-epilog)))))).
- ;; The enclosed bf2lazy.c program performs this translation automatically.
- ;;
- ;; Implementation details:
- ;;
- ;; The functions communicate among themselves to obtain references to
- ;; whichever nearby instructions they need. In the case of [ this is the
- ;; following instruction and the instruction after the matching ]; in the
- ;; case of ] it is the following instruction and the matching [; in all
- ;; other cases it is the following instruction only. References to later
- ;; functions are passed to the left as return values, and references to
- ;; earlier functions are passed to the right as arguments. The bf-prolog
- ;; guard function creates a blank memory store and passes it to the first
- ;; real instruction. The bf-epilog function appends end-of-file to the
- ;; output, which causes Lazy K execution to terminate.
- ;;
- ;; The Brainfuck memory store is unbounded in extent in both directions from
- ;; the origin, and is initialized to all zeroes. It is represented as
- ;; (cur,left,right), where cur holds the current cell and left and right are
- ;; (infinite) lists of the cells to the left and right of the current cell,
- ;; nearest first. Each memory cell holds an 8-bit value, implemented in a
- ;; similar way as a pair of lists of #f with #t guards on either end,
- ;; representing 0. Supporting unbounded integer values would have been
- ;; easier; however, I discovered that many existing Brainfuck programs rely
- ;; on [-] zeroing a cell even when its value has been decremented below
- ;; zero, and this, together with the reasonable requirement that -+ be
- ;; always a no-op, forces the use of modular arithmetic.
- ;;
- ;; The length of translated programs could be substantially reduced by
- ;; moving most of the logic of the Brainfuck operations into bf-prolog and
- ;; turning bf-inc, etc. into simple selector functions, but that wouldn't be
- ;; as much fun.
- ;;
- ;; In many cases certain function arguments below are implicit, because I
- ;; optimized the functions by changing (lambda (x) (f x)) to f (thus hiding
- ;; the existence of x in this example). This isn't really necessary, since
- ;; Lazier performs this optimization itself, but it's fun.
- ;;
- ;; I haven't checked to see what will happen if the brackets aren't
- ;; balanced, or if the Brainfuck programs tries to read past end-of-file; it
- ;; may not be pretty.
- ;;
- ;; Unfortunately, every Brainfuck program I've run under Lazy K leaks
- ;; memory, even if its resource usage in Brainfuck space is constant. I
- ;; haven't yet discovered why this happens.
- ;;
- ;;
- ;; a top-level function (bf-*):
- ;; - is passed a list of (second-level func for next instr., second-level func for after next ], ...)
- ;; - returns an updated version of same
- ;;
- ;; a second-level function:
- ;; is passed third-level func for the previous [ test
- ;; returns a third-level func for self
- ;;
- ;; a third-level function:
- ;; is passed cur, left, right, input
- ;; returns output
- ;;
- (load "../lazier.scm")
- (load "../prelude.scm")
- (lazy-def 'bf-begin ; [
- '(lambda (fwd-list)
- (cons (lambda (back)
- ((lambda (x) (x x))
- (lambda (self)
- (lambda (cur)
- ((if (car (car cur))
- ((car (cdr fwd-list)) back)
- ((car fwd-list) (self self)) )
- cur )))))
- (cdr (cdr fwd-list)) )))
- (lazy-def 'bf-end ; ]
- '(lambda (fwd-list)
- (cons (lambda (back) back)
- fwd-list )))
- (lazy-def 'bf-inc ; +
- '(lambda (fwd-list)
- (cons (lambda (back)
- (lambda (cur)
- ((car fwd-list)
- back
- ((lambda (a b)
- (if (car b) (cons b a) (cons a b)) )
- (cons #f (car cur))
- (cdr (cdr cur)) ))))
- (cdr fwd-list) )))
- (lazy-def 'bf-dec ; -
- '(lambda (fwd-list)
- (cons (lambda (back)
- (lambda (cur)
- ((car fwd-list)
- back
- (cur (lambda (a b)
- (if (car a)
- (cons (cdr b) (cons #f a))
- (cons (cdr a) (cons #f b)) ))))))
- (cdr fwd-list) )))
- (lazy-def 'bf-left ; <
- '(lambda (fwd-list)
- (cons (lambda (back)
- (lambda (cur left right)
- ((car fwd-list)
- back
- (car left)
- (cdr left)
- (cons cur right) )))
- (cdr fwd-list) )))
- (lazy-def 'bf-right ; >
- '(lambda (fwd-list)
- (cons (lambda (back)
- (lambda (cur left right)
- ((car fwd-list)
- back
- (car right)
- (cons cur left)
- (cdr right) )))
- (cdr fwd-list) )))
- (lazy-def 'bf-read ; ,
- '(lambda (fwd-list)
- (cons (lambda (back)
- (lambda (cur left right input)
- ((car fwd-list)
- back
- (cons (((car input) (cons #f)) (k #t))
- (((car input) cdr) (cdr ((256 (cons #f)) (k #t)))) )
- left
- right
- (cdr input) )))
- (cdr fwd-list) )))
- (lazy-def 'bf-write ; .
- '(lambda (fwd-list)
- (cons (lambda (back)
- (lambda (cur left right input)
- (cons (count-to-true (car cur))
- ((car fwd-list) back cur left right input) )))
- (cdr fwd-list) )))
- (lazy-def 'count-to-true
- '((lambda (x) (x x))
- (lambda (self lst)
- (if (car lst) 0 (1+ (self self (cdr lst)))) )))
- (lazy-def 'bf-prolog
- '((lambda (cell-list)
- (lambda (fwd-list)
- ((car fwd-list)
- i
- (car cell-list)
- cell-list
- cell-list )))
- (list-of (cons (k #t) (cdr ((256 (cons #f)) (k #t))))) ))
- (lazy-def 'bf-epilog
- '(k (lambda (back)
- (lambda (cur left right input)
- end-of-output ))))