brainf*ckインタプリタを書いたことがなければプログラマに非ずなどと言われることもあるようなので書いてみた。Gauche。
しかしプログラマには「hogehogeでなければプログラマに非ず」が多いですよね。ハードル高いの多いし。どうなってんだこの業界。
どの道ついてけないので、書けそうなものの中で面白そうなものをやってみる、というスタンス。
取りあえずHello worldが動くところまで書いたところ。replもつけてみた。コードがすごく納得できない状態なので、もう何度か書いてみたい。特にinterpretとparse(つまりメインディッシュ)がもうちょっとどうにかできないもんかと。
今回brainf*ckがどういう言語かちゃんと知って心惹かれました。面白い言語なんですねーこれ。しかも作るの簡単。なるほどlispと同じく使う人より実装する人の方が多い言語。lispと違うのは使う人がいなくて実装する人しかいないところか。
ソース
#!/usr/local/bin/gosh ;;; ;;; bfi - brainf*ck interpreter ;;; ;; sample - Hello world ;; >+++++++++[<++++++++>-]<.>+++++++[<++++>-]<+.+++++++..+++.[-]>++++++++[<++++>-]<.>+++++++++++[<+++++>-]<.>++++++++[<+++>-]<.+++.------.--------.[-]>++++++++[<++++>-]<+.[-]++++++++++. (use srfi-1) (use file.util) ; file->string (use gauche.parseopt) (define (usage) (print "Usage: bfi [options ...] [file]") (exit 1)) (define (interpret code ptr mem) (let rec ((code code)) (if (null? code) (values ptr mem) (begin (if (list? (car code)) (until (zero? (vector-ref mem ptr)) (rec (car code))) (case (car code) ((#\+)(inc! (vector-ref mem ptr))) ((#\-)(dec! (vector-ref mem ptr))) ((#\<)(dec! ptr)) ((#\>)(inc! ptr)) ((#\.)(write-byte (vector-ref mem ptr)) (flush)) ((#\,)(set! (vector-ref mem ptr)(read-byte (current-input-port)))))) (rec (cdr code)))))) (define (parse str) (let1 ls (string->list str) (let rec ((ls ls)(acc '())) (if (null? ls) (reverse acc) (case (car ls) ((#\+ #\- #\< #\> #\. #\,)(rec (cdr ls)(cons (car ls) acc))) ((#\[)(rec (let1 rest (drop-while (pa$ (complement equal?) #\])(cdr ls)) (if (null? rest) '() (cdr rest))) (cons (rec (cdr ls) '()) acc))) ((#\])(reverse acc)) (else (rec (cdr ls) acc))))))) (define (repl mem) (print ";; brainf*ck interactive shell") (print ";; q to exit.") (let rec ((ptr 0)(mem mem)) (display "bfi> ") (flush) (let1 input (read-line) (when (equal? input "q") (exit 0)) (receive (ptr mem) (interpret (parse (x->string input)) ptr mem) (rec ptr mem))))) (define (run-bf str mem) (interpret (parse str) 0 mem)) (define (main args) (let-args (cdr args) ((memory-size "m|memory-size=i" 1024) (interactive "i|interactive") (help "h|help" => usage) (else (opt . _) (print "Unknown option : " opt) (usage)) . rest) (let ((mem (make-vector memory-size 0))) (cond ((and (null? rest) interactive)(repl mem)) ((null? rest)(run-bf (port->string (current-input-port)) mem)) ((run-bf (file->string (car rest)) mem)) (else (usage))))))
使い方
$ bfi hello.bf Hello World!
$ echo '>+++++++++[<++++++++>-]<.>+++++++[<++++>-]<+.+++++++..+++.[-]>++++++++[<++++>-]<.>+++++++++++[<+++++>-]<.>++++++++[<+++>-]<.+++.------.--------.[-]>++++++++[<++++>-]<+.[-]++++++++++.' | bfi Hello World!
$ bfi -i ;; brainf*ck interactive shell ;; q to exit. bfi> >+++++++++[<++++++++>-]<.>+++++++[<++++>-]<+.+++++++..+++.[-]>++++++++[<++++>-]<.>+++++++++++[<+++++>-]<.>++++++++[<+++>-]<.+++.------.--------.[-]>++++++++[<++++>-]<+.[-]++++++++++. Hello World! bfi> q $
参考
- Schemeで適当にBrainFuckインタプリタ - hogeなlog
- SchemeでBrainFuck その2 - hogeなlog
- Scheme:Brainfuck
- Scheme:Brainfuck:別解
- Gauche で Brainf*ck を作ってみた。 - sirocco の書いてもすぐに忘れるメモ
0 件のコメント:
コメントを投稿