Last active
          February 28, 2025 13:54 
        
      - 
      
- 
        Save righ1113/7805bc5ca88da23d2616a13c6a5ba016 to your computer and use it in GitHub Desktop. 
    Brainf*ck in Egison
  
        
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
  | # $ iex -S mix | |
| # > Bf.hello |> Bf.parse([]) |> Bf.run() | |
| defmodule Bf do | |
| # data | |
| # Module.register_attribute(__MODULE__, :hello, persist: true) | |
| # @hello "++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++." | |
| def hello do | |
| '++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.' | |
| end | |
| # parse | |
| def parse(data, acc) do | |
| case data do | |
| '' -> acc | |
| [93 | xs] -> {xs, acc} # ] | |
| [62 | xs] -> parse(xs, acc ++ [:Next]) # > | |
| [60 | xs] -> parse(xs, acc ++ [:Prev]) # < | |
| [43 | xs] -> parse(xs, acc ++ [:Inc]) # + | |
| [45 | xs] -> parse(xs, acc ++ [:Dec]) # - | |
| [46 | xs] -> parse(xs, acc ++ [:Write]) # . | |
| [44 | xs] -> parse(xs, acc ++ [:Read]) # , | |
| [91 | xs] -> {xs2, acc2} = parse(xs, []); parse(xs2, acc ++ [acc2]) # [ | |
| [_ | xs] -> parse(xs, acc) | |
| end | |
| end | |
| # run | |
| def run(code), do: (run_sub({List.duplicate(0, 30), 0, List.duplicate(0, 30)}, code); true) | |
| defp run_sub(d, code) do | |
| case {code, d} do | |
| {[], _ } -> d | |
| {[x |xs], {_, 0, _ } } when is_list(x) -> run_sub(d, xs) | |
| {[x |_ ], _ } when is_list(x) -> d |> run_sub(x) |> run_sub(code) # loop | |
| {[:Next |xs], {ls, c, [rx | rs2]}} -> run_sub({[c | ls], rx, rs2 }, xs) | |
| {[:Prev |xs], {[lx | ls2], c, rs}} -> run_sub({ls2, lx, [c | rs]}, xs) | |
| {[:Inc |xs], {ls, c, rs} } -> run_sub({ls, c + 1, rs }, xs) | |
| {[:Dec |xs], {ls, c, rs} } -> run_sub({ls, c - 1, rs }, xs) | |
| {[:Write|xs], {_, c, _ } } -> List.to_string([c]) |> IO.puts() ||| run_sub(d, xs) | |
| {[:Read |xs], _ } -> run_sub(d, xs) # omitted | |
| {[_ |xs], _ } -> run_sub(d, xs) | |
| end | |
| end | |
| defp left ||| right, do: (_ = left; right) | |
| end | 
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
  | # ############################################################################################################ | |
| # Claude 3.5 でコメント作成 | |
| # このBrainf_ckインタプリタのアルゴリズムを説明します: | |
| # クラス構造 | |
| # ・Brainf_ckクラスを定義し、メモリと現在のメモリ位置(MAR: Memory Address Register)を管理します | |
| # 初期化 | |
| # ・initializeメソッドで: | |
| # ・メモリ配列(@mem)を30,000要素、初期値0で作成 | |
| # ・メモリポインタ(@mar)を0に初期化 | |
| # 実行エンジン(execメソッド) | |
| # 主要な命令の処理: | |
| # 1.>: メモリポインタを1つ進める | |
| # 2.<: メモリポインタを1つ戻す | |
| # 3.+: 現在のメモリ位置の値を1増やす | |
| # 4.-: 現在のメモリ位置の値を1減らす | |
| # 5..: 現在のメモリ位置の値を文字として出力 | |
| # 6.[: | |
| # ・現在のメモリ値が0の場合、対応する]まで移動 | |
| # ・move_pcメソッドを使用して適切なジャンプ先を計算 | |
| # 7.]: | |
| # ・現在のメモリ値が0でない場合、対応する[まで戻る | |
| # ・同じくmove_pcメソッドを使用 | |
| # 括弧処理(move_pcメソッド) | |
| # ・再帰的に対応する括弧を検索 | |
| # ・パラメータ: | |
| # ・pro: プログラムテキスト | |
| # ・i: 現在の位置 | |
| # ・stop: 探索の終点 | |
| # ・sign: 探索方向(+1 or -1) | |
| # ・bracket: 探している括弧の種類 | |
| # ・d: 括弧の深さカウンタ | |
| # このインタプリタは再帰的な実装を採用しており、 | |
| # 各命令を順次処理しながら プログラムカウンタpc を管理し、プログラムの実行を制御しています。 | |
| # ############################################################################################################ | |
| class Brainf_ck | |
| def initialize = (@mar = 0; @mem = Array.new(30_000, 0)) | |
| def exec(pro, pc = 0, max = pro.length - 1) | |
| case pro[pc] | |
| when '>' then @mar += 1 | |
| when '<' then @mar -= 1 | |
| when '+' then @mem[@mar] += 1 | |
| when '-' then @mem[@mar] -= 1 | |
| when '.' then print @mem[@mar].chr | |
| when '[' then pc = move_pc(pro, pc + 1, max, 1, ']') if @mem[@mar].zero? | |
| when ']' then pc = move_pc(pro, pc - 1, 0, -1, '[') unless @mem[@mar].zero? | |
| end | |
| pc == max ? :true_end : exec(pro, pc + 1) | |
| end | |
| private | |
| def move_pc(pro, i, stop, sign, bracket, d = 0, d2 = pro[i] == '[' ? d + sign : (pro[i] == ']' ? d - sign : d)) | |
| if d.zero? && pro[i] == bracket then i # 対応する括弧発見 | |
| elsif i == stop then :pro_last | |
| else move_pc pro, i + sign, stop, sign, bracket, d2 | |
| end | |
| end | |
| end | |
| bf = Brainf_ck.new | |
| bf.exec '++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.' | 
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
  | -- | |
| -- Brainf*ck | |
| -- | |
| -- $ egison 4.1.3 | |
| -- > loadFile "bf2.egi" | |
| -- | |
| -- Pattern Function | |
| -- | |
| def bfLoopPatt := \pat1 => #'[' :: $x :: ~pat1 ++ #(pack [']', x]) | |
| -- | |
| -- Codes | |
| -- | |
| def parse code := parse' code 1 [] where | |
| parse' code mark acc := match code as string with | |
| | [] -> pack $ reverse acc | |
| | #'[' :: $xs -> parse' xs (mark + 1) ((itoc (mark + 48 )) :: '[' :: acc) | |
| | #']' :: $xs -> parse' xs (mark - 1) ((itoc (mark + 48 - 1)) :: ']' :: acc) | |
| | $x :: $xs -> parse' xs mark (x :: acc) | |
| def bf code := do{ run code (take 10 $ repeat1 0, 0, take 10 $ repeat1 0); write "" } where | |
| run code d := match (code, d) as (string, (list integer, integer, list integer)) with | |
| | ([], _ ) -> return d | |
| | ((bfLoopPatt _) ++ $xs, (_, #0, _) ) -> run xs d | |
| | ((bfLoopPatt $x) ++ $xs, _ ) -> run code $ io $ run x d -- loop | |
| | (#'>' :: $xs, ($ls, $c, $rx :: $rs2)) -> run xs (c :: ls, rx, rs2) | |
| | (#'<' :: $xs, ($lx :: $ls2, $c, $rs)) -> run xs (ls2, lx, c :: rs) | |
| | (#'+' :: $xs, ($ls, $c, $rs) ) -> run xs (ls, (c + 1), rs) | |
| | (#'-' :: $xs, ($ls, $c, $rs) ) -> run xs (ls, (c - 1), rs) | |
| | (#'.' :: $xs, (_, $c, _) ) -> do{ write $ pack [itoc c]; run xs d } | |
| | (#',' :: $xs, _ ) -> run xs d -- omitted | |
| | (_ :: $xs, _ ) -> run xs d | |
| -- | |
| -- Data | |
| -- | |
| -- 1m35s | |
| def hello := | |
| "++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++." | |
| -- | |
| -- Tests | |
| -- | |
| -- $ egison -t bf2.egi | |
| io $ bf $ parse hello | |
| def test5 := matchAll "[1ii[2abc]2xxx[2y[3]3]2df]1ggg" as string with | |
| | (bfLoopPatt $x) ++ $xs -> (x, xs) | |
  
    Sign up for free
    to join this conversation on GitHub.
    Already have an account?
    Sign in to comment