MercuryでBrainfuckインタープリターを作成する

ハブでのBrainfuckMercuryでの実験1週間続け、彼のバージョンのインタープリターを作成しました。 水星に関する「紹介」記事を提出しなかったことを事前に謝罪します。 実際、彼女は執筆中です。

それまでの間、Mercury言語のいくつかの機能を同時に説明するソリューションコードを提供します。



:- module bf. :- interface. :- import_module io. :- pred main(io::di, io::uo) is det. :- implementation. :- import_module list, string, char, solutions, require, int. :- type bf_cmd ---> plus; minus; step; back; print; cycle(list(bf_cmd)). :- type bf_state ---> bf_state( left :: list(int), cell :: int, right :: list(int) ). hello_world = "++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++\ .>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.\ ------.--------.>+.>.". squares_1_to_1000 = "++++[>+++++<-]>[<+++++>-]+<+[\ >[>+>+<<-]++>>[<<+>>-]>>>[-]++>[-]+\ >>>+[[-]++++++>>>]<<<[[<++++++++<++>>-]+<.<[>----<-]<]\ <<[>>>>>[>>>[-]+++++++++<[>-<-]+++++++++>[-[<->-]+[<<<]]<[>+<-]>]<<-]<<-\ ]". fib_1_to_100 = "+++++++++++\ >+>>>>++++++++++++++++++++++++++++++++++++++++++++\ >++++++++++++++++++++++++++++++++<<<<<<[>[>>>>>>+>\ +<<<<<<<-]>>>>>>>[<<<<<<<+>>>>>>>-]<[>++++++++++[-\ <-[>>+>+<<<-]>>>[<<<+>>>-]+<[>[-]<[-]]>[<<[>>>+<<<\ -]>>[-]]<<]>>>[>>+>+<<<-]>>>[<<<+>>>-]+<[>[-]<[-]]\ >[<<+>>[-]]<<<<<<<]>>>>>[+++++++++++++++++++++++++\ +++++++++++++++++++++++.[-]]++++++++++<[->-<]>++++\ ++++++++++++++++++++++++++++++++++++++++++++.[-]<<\ <<<<<<<<<<[>>>+>+<<<<-]>>>>[<<<<+>>>>-]<-[>>.>.<<<\ [-]]<<[>>+>+<<<-]>>>[<<<+>>>-]<<[<+>-]>[<+>-]<<<-]". prog_to_ast(Prog) = Ast :- to_char_list(Prog, Chars), solutions(pred(Ast_::out) is nondet :- ast(Ast_, Chars, []:list(char)), Asts), ( Asts = [], error("Program invalid (parse error)!") ; Asts = [Ast|_] ). :- mode ast(out, in, out) is multi. ast([plus|Cmds]) --> ['+'], ast(Cmds). ast([minus|Cmds]) --> ['-'], ast(Cmds). ast([step|Cmds]) --> ['>'], ast(Cmds). ast([back|Cmds]) --> ['<'], ast(Cmds). ast([print|Cmds]) --> ['.'], ast(Cmds). ast([cycle(Cycle)|Cmds]) --> ['['], ast(Cycle), [']'], ast(Cmds). ast([]) --> []. execute_ast([], !State) --> []. execute_ast([Cmd|Cmds], !State) --> execute_cmd(Cmd, !State), execute_ast(Cmds, !State). execute_cmd(plus, bf_state(L,C,R), bf_state(L, C+1, R)) --> []. execute_cmd(minus, bf_state(L,C,R), bf_state(L, C-1, R)) --> []. execute_cmd(step, bf_state(L,C,R), bf_state([C|L], H, T)) --> {R = [], H=0, T=[]; R = [H|T]}. execute_cmd(back, bf_state(L,C,R), bf_state(T, H, [C|R])) --> {L = [], H=0, T=[]; L = [H|T]}. execute_cmd(print, S @ bf_state(_,C,_), S) --> print(char.det_from_int( C ):char). execute_cmd(Cmd @ cycle(Cmds), !.S @ bf_state(_,C,_), !:S) --> ( {C \= 0} -> execute_ast(Cmds, !S), execute_cmd(Cmd, !S) ; [] ). execute_str(Prog) --> {Ast = prog_to_ast(Prog)}, execute_ast(Ast, bf_state([], 0, []), _). main --> execute_str(hello_world), nl, execute_str(squares_1_to_1000), nl, execute_str(fib_1_to_100).
      
      







そして、すぐにこのプログラムの出力:



 D:\stuff\test\mercury>bf.exe Hello World! 0 1 4 9 16 25 36 49 64 81 100 121 ... < > 9025 9216 9409 9604 9801 10000 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89
      
      







私の決定について少し。 これは、2つの段階で構成されてい

  1. ASTのテキストBrainfuckプログラムを変換します(抽象構文ツリー)
  2. ウッドバージョンAST


最初の段階では、たとえば '+++ >> [+-] <'などのBFコードから、リスト[プラス、プラス、プラス、ステップ、ステップ、サイクル([プラス、マイナス])の形式でAST構造を取得します。戻る]。 非決定的な述語astはこれに責任があります。 この概念について完全に明確でない人のために、これが複数のソリューションを返すことができる述語であることを簡略化します。これらのソリューションは、バックトラッキングを通じてソートされ、これとその述語で構成される表現全体が真実ではありません。 この原則は、詳細な検索方法を使用してプログラムテキストを解析するパーサーを作成する便利さに基づいています(このアプローチには多くの欠点がありますが、このトピックはこのharbratopikaで詳しく説明されています )。 (すなわち、ブラケット構造を修正)分析と共に、この段階で自動的構文の正しさをチェックすることは注目に値します。 正しくない場合、ターゲットast(Ast_、Chars、[]:list(char))は失敗し、「Program invalid(parse error)!」というエラーが表示されます。 第備考:で書かれたAST述語DCGの水銀の言語だけでなく、多くの伝統的なPrologによって支持されている表記法、。



2番目のステージ(execute_ *述語が責任を負う)では、結果の構文ツリーが「計算」されます。 各execute_ *述語は、入力としてセルリボンの初期状態を取り、brainfuckプログラムのASTに従ってそれを変更し、この述語を適用した後の結果を生成します(ご存じのように、関数型言語は可変データ構造を許容できません)。



ここで、テープのステータスを設定する構造に注意する必要があります。 ご存知のように、(正しく)選択されたデータ構造により、(最適な)実装アルゴリズムとその複雑さが決まります。 bf_state(LeftCells、細胞、RightCells):この場合、ベルト構造は、2つのリストによって決定され、数が選択されています。 このアプローチでは、セルを増減するとCellが+ -1だけ変更され、左(右)に移動します。これにより、リストヘッドが左(右)セルからセルの場所に移動し、セル自体が右(左)セルヘッドに移動します(まあ、特別な場合)左(右)セルの空のリストの場合、割り当てセル= 0)。



このビューの利点:



もう一つ説明。 !水銀と呼ばれる状態変数にS不可解なエントリにと変数.Sのカップルで、:!! mode'amiとSとアウト。 これは、前から次へパラメータを渡すことで述語を連鎖するのに便利です。 記録する



some_pred(In, Out) :- pred1(In, In1), pred2(In1, In2), pred3(In2, Out).







と同等:



some_pred(!.S, !:S) :- pred1(!.S, !:S), pred2(!.S, !:S), pred3(!.S, !:S). %







これは次と同等です:



some_pred(!S) :- pred1(!S), pred2(!S), pred3(!S).







またはDCG表記として:



some_pred --> pred1, pred2, pred3.







しかし、これと水銀のその他の特徴については別の記事で詳しく説明しています=)



All Articles