Brainfuckコンパイラ

id:mzpさんがBrainfuckインタプリタを作っていたので、なんとなくBrainfuckからSchemeへのコンパイラを作ってみた。

こんな感じになってます。

(define (char->symbol c)
  (string->symbol #`",c"))

(define (inst-name->cont name k)
  (lambda (x)
    (k `((,(char->symbol name)) ,@x))))

(define (compile k)
  (let1 c (read-char)
    (if (eof-object? c)
	(k '())
	(case c
	  ((#\+ #\- #\> #\< #\. #\,)
	   (compile (inst-name->cont c k)))
	  ((#\[)
	   (compile
	    (lambda (x)
	      (compile
	       (lambda (y)
		 (k `((while (nonzero?) ,@x) ,@y)))))))
	  ((#\])
	   (k '()))
	  (else (compile k))))))

(define (bf->scm)
  (for-each write
	    `((define memory (make-vector 30000 0))
	      (define pointer 0)
	      (define (+) (inc! (ref memory pointer)))
	      (define (-) (dec! (ref memory pointer)))
	      (define (>) (inc! pointer))
	      (define (<) (dec! pointer))
	      (define (|,|) (set! (ref memory pointer) (char->integer (read-char))))
	      (define (|.|) (display (integer->char (ref memory pointer))))
	      (define (nonzero?) (not (zero? (ref memory pointer))))
	      (define (main args)
		,@(compile identity)))))

(define (main args)
  (bf->scm)
  0)


標準入力からBrainfuckのコードを渡してやると、標準出力にSchemeのコードが出力されます。

$ gosh bf2scm.scm < HELLOBF.BF > HELLOBF.scm
$ cat HELLOBF.scm
(define memory (make-vector 30000 0))(define pointer 0)(define (+) (inc! (ref memory pointer)))(define (-) (dec! (ref memory pointer)))(define (>) (inc! pointer))(define (<) (dec! pointer))(define (|,|) (set! (ref memory pointer) (char->integer (read-char))))(define (|.|) (display (integer->char (ref memory pointer))))(define (nonzero?) (not (zero? (ref memory pointer))))(define (main args) (>) (+) (+) (+) (+) (+) (+) (+) (+) (+) (while (nonzero?) (<) (+) (+) (+) (+) (+) (+) (+) (+) (>) (-)) (<) (|.|) (>) (+) (+) (+) (+) (+) (+) (+) (while (nonzero?) (<) (+) (+) (+) (+) (>) (-)) (<) (+) (|.|) (+) (+) (+) (+) (+) (+) (+) (|.|) (|.|) (+) (+) (+) (|.|) (while (nonzero?) (-)) (>) (+) (+) (+) (+) (+) (+) (+) (+) (while (nonzero?) (<) (+) (+) (+) (+) (>) (-)) (<) (|.|) (>) (+) (+) (+) (+) (+) (+) (+) (+) (+) (+) (+) (while (nonzero?) (<) (+) (+) (+) (+) (+) (>) (-)) (<) (|.|) (>) (+) (+) (+) (+) (+) (+) (+) (+) (while (nonzero?) (<) (+) (+) (+) (>) (-)) (<) (|.|) (+) (+) (+) (|.|) (-) (-) (-) (-) (-) (-) (|.|) (-) (-) (-) (-) (-) (-) (-) (-) (|.|) (while (nonzero?) (-)) (>) (+) (+) (+) (+) (+) (+) (+) (+) (while (nonzero?) (<) (+) (+) (+) (+) (>) (-)) (<) (+) (|.|) (while (nonzero?) (-)) (+) (+) (+) (+) (+) (+) (+) (+) (+) (+) (|.|))
$ gosh HELLOBF.scm
Hello World!
$