PureScriptで作るBrainfuckインタプリタ 1/4 基礎部分の作成
Brainfuckの記事ではあるが、実はモナド変換子を使ってみたかっただけだったりする。 以下の3部の記事で構成されている。 インタプリタと基本的な命令の実装 (この記事) CUIでの入出力処理の実装 CUIでのインタプリタ可視化 Halogenを用いた入出力処理の実装 この記事でインタプリタの基本的な部分を実装し、 残りの3記事はインタプリタとはあまり関係ない話となる (とはいえ出力ができないと Hello, World すら書けないので、必要な記事ではある)。 Brainfuckインタプリタの構造 Brainfuckインタプリタは以下の情報を内部に持っているものとする。 program: 命令の列。 iptr: インストラクションポインタ。実行する命令の位置を示す。プログラムカウンタみたいなもの。 dptr: データポインタ。メモリ上のある位置を示す。 memory: メモリ。 インタプリタは以下の手順を踏む。 iptr番目の命令をprogramから読み取る。 読み取れなかったらプログラムを終了する。 命令に応じてmemory、dptrの書き換えだったり、入出力を行う。 iptrを1進め、手順1に戻る。 どんな命令があるのかについてはWikipedia参照。 準備 適当なディレクトリを作って、プロジェクトの初期化を行う。 % spago init 命令列の作成 src/Brainfuck/Command.pursを作成する。 Commandを定義。Showクラスのインスタンスにして、Charからの変換をする関数を作る。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 module Brainfuck.Command where import Prelude data Command = IncPtr -- "+" | DecPtr -- "-" | IncDat -- ">" | DecDat -- "<" | LBrace -- "[" | RBrace -- "]" | Output -- "." | Input -- "," | Nop -- otherwise instance Show Command where show = case _ of IncPtr -> ">" DecPtr -> "<" IncDat -> "+" DecDat -> "-" LBrace -> "[" RBrace -> "]" Output -> "." Input -> "," Nop -> "nop" fromChar :: Char -> Command fromChar = case _ of '>' -> IncPtr '<' -> DecPtr '+' -> IncDat '-' -> DecDat '[' -> LBrace ']' -> RBrace '.' -> Output ',' -> Input _ -> Nop 続いて、src/Brainfuck/Program.pursを作成。この後使う関数をまとめて読み込んでおく。 ...