スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

F#で入門 コンパイラ、インタプリタ編 Whitespace(10)

 最後の実装はI/O(input/output)関連です。これに対しては4つの命令が定義されています。 
(1)tnss  スタックの一番上の数をchar型の値として出力する 
(2)tnst  スタックの一番上の数をint型の値として出力する 
(3)tnts  入力された値をchar型の値として、スタックの一番上の番地に書き込む 
(4)tntt  入力された値をint型の値として、スタックの一番上の番地に書き込む 
 
入出力については、コンソールアプリケーションにするかウィンドウズアプリケーションにするかで異なってくるので、コードの最初に、スロット用のmutableな関数ホルダを定義しておいて、実行直前に具体的関数を指定したいと思います。 
 
////////////////入出力用関数ホルダ//////////////// 
let mutable forInputFunc :(unit->string)    = (fun () -> "") 
let mutable forOutputFunc:(string->unit) = (fun _ -> ()) 
let mutable forStateDispFunc:(string->unit) = (fun _ -> ()) 
 
では順次実装していきます。 
 
(1)Command Type への追加 
名前はそれぞれTNCharOut,TNIntOut,TNCharRead,TNIntReadとします。 
 
    |TNCharOut 
    |TNIntOut 
    |TNCharRead 
    |TNIntRead 
 
(2)ComKindLstへの追加 
        (fun (rg:Regex) str -> createFromNothing rg str (fun () -> TNCharOut))); 
      ( new Regex("^tnst"), 
        (fun (rg:Regex) str -> createFromNothing rg str (fun () -> TNIntOut))); 
      ( new Regex("^tnts"), 
        (fun (rg:Regex) str -> createFromNothing rg str (fun () -> TNCharRead))); 
      ( new Regex("^tntt"), 
        (fun (rg:Regex) str -> createFromNothing rg str (fun () -> TNIntRead))); 
 
(3)対応する関数の追加 
     
let do_TNCharOut ((pc,stcLst,heapMap,rIndexLst):WState) = 
    match stcLst with 
    |v::rem -> forOutputFunc ((char v).ToString()) 
               (pc+1,rem,heapMap,rIndexLst)  
    |_      -> failwith(sprintf "index:%d スタックが空なので表示できません。" pc)   
                 
let do_TNIntOut ((pc,stcLst,heapMap,rIndexLst):WState) = 
    match stcLst with 
    |v::rem -> forOutputFunc (v.ToString()) 
               (pc+1,rem,heapMap,rIndexLst)  
    |_      -> failwith(sprintf "index:%d スタックが空なので表示できません。" pc)   
 
let do_TNCharRead ((pc,stcLst,heapMap,rIndexLst):WState) = 
    let inputVal = System.Char.Parse (forInputFunc()) 
    match stcLst with 
    |v::rem ->(pc+1,rem,(Map.add v (int inputVal) heapMap),rIndexLst)  
    |_      -> failwith(sprintf "index:%d スタックが空なので書き込みできません。" pc)   
 
let do_TNIntRead ((pc,stcLst,heapMap,rIndexLst):WState) = 
    let inputVal = System.Int32.Parse(forInputFunc()) 
    match stcLst with 
    |v::rem ->(pc+1,rem,(Map.add v inputVal heapMap),rIndexLst)  
    |_      -> failwith(sprintf "index:%d スタックが空なので書き込みできません。" pc)   
  
  
 (4)processCmdへの追加 
  
        |TNCharOut    -> do_TNCharOut t  |> processCmdSub 
        |TNIntOut     -> do_TNIntOut t   |> processCmdSub 
        |TNCharRead   -> do_TNCharRead t |> processCmdSub 
        |TNIntRead    -> do_TNIntRead t  |> processCmdSub 
 
なおデバック出力用の部分も次のように修正しておきます。 
let rec processCmd (cmds :Command[]) (startWState:WState) = 
    let labelMap = makeLabelMap cmds //ジャンプ命令等で使用する  
    forStateDispFunc (sprintf "ラベル::pc対応Map %A\n" labelMap) //デバック用 
    let rec processCmdSub  ((pc,stcLst,heapMap,rIndexLst) as t:WState) = 
        if pc < 0 || pc >= Array.length cmds then failwith (sprintf "index:%d pcが領域外です" pc) 
        forStateDispFunc (sprintf "%A\n" t)  //デバック用 
        let cur_cmd = cmds.[pc] //現在のプログラムカウンタにある命令をとってくる 
        forStateDispFunc (sprintf "%A\n" cur_cmd) //デバック用 
        match cur_cmd with 
        |SPush(num)   -> do_SPush num t  |> processCmdSub 
.......... 
 
入出力先を次のように指定しておきます。 
 
forStateDispFunc <- System.Console.Write   
forOutputFunc <- System.Console.Write 
forInputFunc <- System.Console.Read 
 
テストしてみます。 
 
> processCmd [|SPush(71);TNCharOut;FExit|]  
             (0,[],Map.empty,[]);; 
ラベル::pc対応Map map [] 
(0, [], map [], []) 
SPush 71 
(1, [71], map [], []) 
TNCharOut 
G(2, [], map [], []) 
FExit 
val it : unit = () 
 
> processCmd [|SPush(71);TNIntOut;FExit|]  
             (0,[],Map.empty,[]);; 
ラベル::pc対応Map map [] 
(0, [], map [], []) 
SPush 71 
(1, [71], map [], []) 
TNIntOut 
71(2, [], map [], []) 
FExit 
val it : unit = () 
 
> processCmd [|SPush(1001);TNCharRead;FExit|]  
             (0,[],Map.empty,[]);; 
ラベル::pc対応Map map [] 
(0, [], map [], []) 
SPush 1001 
(1, [1001], map [], []) 
TNCharRead 
G  <-こちらで入力 
(2, [], map [(1001, 71)], []) 
FExit 
val it : unit = () 
 
> processCmd [|SPush(1001);TNIntRead;FExit|]  
             (0,[],Map.empty,[]);; 
ラベル::pc対応Map map [] 
(0, [], map [], []) 
SPush 1001 
(1, [1001], map [], []) 
TNIntRead 
71 <-こちらで入力 
(2, [], map [(1001, 71)], []) 
FExit 
val it : unit = () 
 
ここまでの全コードは次の通りです。 

続きを読む

スポンサーサイト

テーマ : プログラミング
ジャンル : コンピュータ

プロフィール

T GYOUTEN

Author:T GYOUTEN
F#と英単語とフリーソフトと読書に興味があります。
ホームページでフリーソフトも公開しています。どぞ御贔屓に。

最新記事
最新コメント
最新トラックバック
月別アーカイブ
カテゴリ
フリーエリア
フリーエリア
blogram投票ボタン
検索フォーム
RSSリンクの表示
リンク
ブロとも申請フォーム

この人とブロともになる

QRコード
QRコード
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。