初brainf*ck
Rubyで作る奇妙なプログラミング言語 ~Esoteric Language~
- 作者: 原悠
- 出版社/メーカー: 毎日コミュニケーションズ
- 発売日: 2008/12/20
- メディア: 単行本(ソフトカバー)
- 購入: 8人 クリック: 148回
- この商品を含むブログ (70件) を見る
折角なのでループを再帰にしてみたりset系の命令を排して書いてみたりしたけど意味は全くないというか遅くなるだけ。ネタです。
(defun subnth (x n xs) (let ((len (length xs))) (if (<= len n) xs (nconc (butlast xs (- len n)) `(,x) (cdr (nthcdr n xs)))))) (defun jump (code) (if (null code) (error "error: unmatch parenthesis") (case (car code) (#\] (cdr code)) (#\[ (jump (jump (cdr code)))) (t (jump (cdr code)))))) (defun bf-rec (code pos tape ret) (if (null code) (values tape pos) (flet ((_ (e &key ((:code c) (cdr code)) ((:pos p) pos) ((:ret r) ret)) (bf-rec c p e r))) (case (car code) (#\+ (_ (subnth (1+ #1=(nth pos tape)) pos tape))) (#\- (_ (subnth (1- #1#) pos tape))) (#\. (princ (code-char #1#)) (_ tape)) (#\, (_ (subnth (char-code (read-char)) pos tape))) (#\< (_ tape :pos (1- pos))) (#\> (_ (if (< (1+ pos) (length tape)) tape (append tape '(0))) :pos (1+ pos))) (#\[ (if (= 0 #1#) (_ tape :code (jump (cdr code))) (_ tape :ret (cons (cdr code) ret)))) (#\] (if (= 0 #1#) (_ tape :ret (cdr ret)) (if ret (_ tape :code (car ret)) (error "error: unmatch parenthesis")))) (t (_ tape))))))
評価が終わるとテープの最後の状態とポジションを多値で返します。
]へのジャンプだけ別関数になってるのがとてもかっこわるい。
とりあえず実行
(defun bf-test () (let ((tape '(0))) (macrolet ((run (str) `(multiple-value-bind (l p) (bf-rec (coerce ,str 'list) 0 tape nil) (format t "~&~A:~A~%" l p)))) (run "++++++++[>++++++++<-]>+.") (run "+++++++++[>++++++++>+++++++++++>+++++<<<-]>.>++.+++++++..+++.>-.--- ---------.<++++++++.--------.+++.------.--------.>+.") (run "++++[>,.<-]"))))
結果
CL-USER> (bf-test) A (0 65):1 Hello, world! (0 72 100 33):3 asdfjkl; asdf (0 102):0 NIL
できたできた。後でマクロ版を書く。