スポンサーサイト

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

F#で入門 コンパイラ、インタプリタ編 文脈自由文法

 
前回までで、プログラムソースの構成要素としてのトークンを紹介しましたが、これを決定しただけでは、プログラムは意味をなしません。例えばトークンとしては「符号なしの数字」(トークン種別をNUM)と+(トークン種別をPLUSとします。)だけを使用することにしても、これを並べるとしたら、 
1,1++,1+3,+1++,89+23,12 
トークン種別の並びとしてはそれぞれ 
NUM,NUM PLUS,NUM PLUS NUM,PLUS NUM PLUS PLUS,NUM PLUS NUM,NUM 
というように、いろいろな場合が考えられるので、「どのような場合を許して、意味のあるものとして解釈するか」のルールを設定する必要があります。つまりトークン種別の並びのルールを設定するわけです。 
例えばNUM + NUM の並びを許すとします。 
しかしこれだけでは1 + 3は表せますが、1 + 2 + 5 + 9などは表すことができません。 
ここで、並びのルールの表現として、トークン種別の並びに名前をつけるという操作と、再帰的に定義できるということを許すことにします。 
例えば次のように書きます。 
 
Term = NUM  
Term = NUM PLUS Term 
 
両方とも左辺がTermですが、これは「Termはどちらの形でもいいですよ」という意味としてとってください。上のルールを(1)下を(2)とすると。 
(1)よりNUMはTermです。 
NUMはTermなのだから(2)よりNUM PLUS NUMもTermです。 
NUM PLUS NUMはTermなのだから(2)よりNUM PLUS NUM PLUS NUMもTermです。 
このようにして、続けていけば、NUM,NUM PLUS NUM,NUM PLUS NUM PLUS NUM,......はずっとTermであることが言えます。 
 
最終的にソースに現れるトークン種別を表す記号を終端記号(terminal) 
上のTermのように並び方のルールを表現するために導入される記号(実際的にはルール群の左辺に現れる記号)を非終端記号(nonterminal)といいます。 
並び方のルール自体は構文規則(syntax rule)といいます。 
 
次に(構文規則例1) 
(1)Term = NUM  
(2)Term = NUM PLUS Term 
をいくつかの別の形で表してみます。(Termは英語で項という意味です。) 
 
(構文規則例2) 
(1)Term = NUM 
(2)Term = Term PLUS NUM 
 
(構文規則例3) 
(1)Term = NUM Term2 
(2)Term2 = PLUS Term 
(3)Term2 = ε (注意 εは空列といい、なにもないことを表す。右辺が空列である規則を空規則という) 
 
構文規則例2でTermがNUM,NUM PLUS NUM,NUM PLUS NUM PLUS NUM,......を表すことは、すぐ分かると思いますので、構文規則例3を少し調べてみます。 
まず(1)Term = NUM Term2でTerm2として(3)を利用するとTerm = NUM ε 
εはなにもないことを表すので、Term = NUMとなります。 
次に(1)Term = NUM Term2でTerm2として(2)を利用するとTerm = NUM PLUS TermでNUMはTermだったのでTerm = NUM PLUS NUMよりNUM PLUS NUMもTermであることが分かります。 
同様に考えていけば構文規則例3でTermがNUM,NUM PLUS NUM,NUM PLUS NUM PLUS NUM,......を表すことが分かります。 
 
非終端記号を構文規則を利用して、置き換えて行くことを導出するといいます。 
「終端記号への置き換えの終わっていない非終端記号」の内最も左にあるものから順に置き換えていくことを最左導出といいます。(最も右にあるものから順に置き換えていくことは最右導出といいます) 
 
たとえば構文規則例2でのTermの最左導出ですが, 
Term = Term PLUS Term (構文規則例2の2) 
     = NUM PLUS Term (最も左にあるTerm(構文規則例2の1)を使って置き換える) 
     = NUM PLUS Term PLUS Term (構文規則例2の2)を利用 
     = NUM PLUS NUM PLUS Term(最も左にあるTerm(構文規則例2の1)を使って置き換える) 
     = NUM PLUS NUM PLUS NUM (全部終端記号となり終了) 
となります。 
では、構文規則を与えて最左導出する簡単なソフトを作ってみましたので、これを利用していろいろ導出してみたいと思います。 

1003-1.jpg

使う前に制限を書いておきます。構文規則としては、デフォルトでZ = Program EOFという規則が前提として与えられているものとします。またイプシロンはEPSILONとして入力します。(これは終端記号ではないのですが、終端記号の欄に表示されます。) 
 
あとはProgramの定義をして、Zがどのようなものを表せるかを最左導出してみるという作りになってます。 
 
まず一番上のテキストボックスに構文規則を入力します。 
上の構文規則例1を入力してみます。ただProgramの定義からはじめなくてないけないので、上のTermの代わりにProgramという名前で定義します。 
 
1003-2.jpg 
「適用」ボタンを押します。 

1003-3.jpg 

表現1で、最左非終端記号はProgramなので、これを左辺とする構文規則を構文規則リストボックスで選択して「導出」ボタンを押します。(2を選んでみます。) 

1003-4.jpg 
もう一回2を選んだあとで、1を選んでみると 

1003-5.jpg 

となりすべて終端記号となるので導出は終了です。 
 
このとき表現1テキストボックスには 
 NUM PLUS NUM PLUS NUM EOF 
 と表示されEOFより前が導出されたものを表します。 
  
 表現2テキストボックスには 
 (0 (2 NUM PLUS (2 NUM PLUS (1 NUM 1) 2) 2) EOF 0) 
 と表示されどのような構文規則が適用されたかが表されるようになっています。 
 入れ子状態になることに留意してください。 
  
 ログテキストボックスには 
 0:  Program EOF 
 2;  NUM PLUS Program EOF 
 2;  NUM PLUS NUM PLUS Program EOF 
 1;  NUM PLUS NUM PLUS NUM EOF 
 と表示されどの構文規則が適用され、導出されていっているかが表示されます。 
  
 導出結果は入れ子状態になるので、木ととても相性がよいので、よく木で表現されます。 
「具象抽象木の表示」ボタンを押すと木として表現されます。 
 
    ( 0)Z 
        ( 2)Program 
            NUM 
            PLUS 
            ( 2)Program 
                NUM 
                PLUS 
                ( 1)Program 
                    NUM 
        EOF 
 
構文規則の右側の要素を枝とするRose Treeとして表現されます。 
(0)Z = Program EOF 
(1)Program = NUM 
(2)Program = NUM PLUS Program 
との対応をみて下さい。(右辺のそれぞれの要素が枝となっています。) 
 
 
それでは表現2,3で同様にNUM PLUS NUM PLUS NUM EOFを導出したときにテキストボックス内に表示されるものを、のっけておきます。 
 
(構文規則例2) 
 
0:Z = Program EOF 
1:Program = NUM  
2:Program = Program PLUS NUM 
 
 NUM PLUS NUM PLUS NUM EOF 
 
 (0 (2 (2 (1 NUM 1) PLUS NUM 2) PLUS NUM 2) EOF 0) 
  
 0:  Program EOF 
 2;  Program PLUS NUM EOF 
 2;  Program PLUS NUM PLUS NUM EOF 
 1;  NUM PLUS NUM PLUS NUM EOF 
  
    ( 0)Z 
        ( 2)Program 
            ( 2)Program 
                ( 1)Program 
                    NUM 
                PLUS 
                NUM 
            PLUS 
            NUM 
        EOF 
         
(構文規則例3) 
 
0:Z = Program EOF 
1:Program = NUM Program2 
2:Program2 = PLUS Program 
3:Program2 = EPSILON    
 
NUM PLUS NUM PLUS NUM EPSILON EOF 
 
(0 (1 NUM (2 PLUS (1 NUM (2 PLUS (1 NUM (3 EPSILON 3) 1) 2) 1) 2) 1) EOF 0) 
 
 0:  Program EOF 
 1;  NUM Program2 EOF 
 2;  NUM PLUS Program EOF 
 1;  NUM PLUS NUM Program2 EOF 
 2;  NUM PLUS NUM PLUS Program EOF 
 1;  NUM PLUS NUM PLUS NUM Program2 EOF 
 3;  NUM PLUS NUM PLUS NUM EPSILON EOF 
  
    ( 0)Z 
        ( 1)Program 
            NUM 
            ( 2)Program2 
                PLUS 
                ( 1)Program 
                    NUM 
                    ( 2)Program2 
                        PLUS 
                        ( 1)Program 
                            NUM 
                            ( 3)Program2 
                                EPSILON 
        EOF 
 
 
では最後にこのプログラムのソースをつけておきます。 
(ソースの改変・流用はご自由にどうぞ。) 
 



 open System    
open System.Windows.Forms    
open System.Drawing    
 
//引数分の空白文字を作る補助関数 
let spaceStr(i) =  
    let sb = new System.Text.StringBuilder() 
    let rec addSpace count = 
        if count = i then sb.ToString() 
        else 
            sb.Append(" ") |> ignore 
            addSpace (count + 1) 
    addSpace 0  
 
 
//文法定義のエラー 
exception MyGramExcp of string 
 
type GramEle = 
    |LPAR of int 
    |TN  of string 
    |NTN of string 
    |RPAR of int  
 
//(1,"Program = DeclStmts PrintStmts",[LPAR(1);NTN("DeclStmts");TN("PrintStmes");RPAR(1)] 
type Gram = int*string*list<GramEle> 
 
 
//copeOneGram "Program = DeclStmts PrintStmts" 
//結果 (["Program"], ["DeclStmts"; "PrintStmts"]) 
let copeOneGram (inStr:string) = 
    let (lhd:string,rhd:string) = 
        match inStr.Split([|'='|]) with 
        |[|mlhd;mrhd|]  ->  (mlhd.Trim(),mrhd) 
        | _             ->  raise <| MyGramExcp(inStr)  
    let rhdElems =  
        rhd.Split([|' '|]) 
            |> List.ofArray 
            |> List.map (fun s -> s.Trim()) 
            |> List.filter (fun s -> s <> "") 
    ([lhd],rhdElems) 
 
 
//終端記号と非終端記号のSetを返す 
//getTN_NTN_Sets ["Program = DeclStmts PrintStmts";"DeclStmts = DeclStmt SEMI"] ;; 
//結果(set ["DeclStmts"; "Program"], set ["DeclStmt"; "PrintStmts"; "SEMI"]) 
let getTN_NTN_Sets (inStrLst:list<string>) = 
 
 
    //copeMulGram ["Program = DeclStmts PrintStmts";"DeclStmts = DeclStmt SEMI"]  
    // 結果(["Program"; "DeclStmts"], ["DeclStmts"; "PrintStmts"; "DeclStmt"; "SEMI"]) 
    let copeMulGram (inStrLst:list<string>) = 
        inStrLst 
            |>List.map copeOneGram 
            |> List.fold (fun (accLh,accRh) (lhLst,rhLst) -> (accLh @ lhLst, accRh @ rhLst)) ([],[]) 
 
    //makeTN_NTN_Set (["Program"; "DeclStmts"], ["DeclStmts"; "PrintStmts"; "DeclStmt"; "SEMI"]) 
    //結果(set ["DeclStmts"; "Program"], set ["DeclStmt"; "PrintStmts"; "SEMI"]) 
    let makeTN_NTN_Set ((inLhdStrLst:list<string>),(inRhdStrLst:list<string>)) = 
        let AllEles = (Set.ofList inLhdStrLst) + (Set.ofList inRhdStrLst)    
        let NTNs = Set.ofList inLhdStrLst 
        let TNs = AllEles - NTNs 
        (NTNs,TNs) 
     
    //↑3補助関数の定義ここまで↑ 
     
    inStrLst 
        |> copeMulGram 
        |> makeTN_NTN_Set 
 
//convOneLine2GramEle 1 "Program = DeclStmts PrintStmts" (set ["DeclStmts"; "Program"]) (set ["DeclStmt"; "PrintStmts"; "SEMI"]) 
// (1, "Program", [LPAR 1; NTN "DeclStmts"; TN "PrintStmts"; RPAR 1]) 
let convOneLine2GramEle (i:int) (inStr:string) (ntnSet:Set<string>) (tnSet:Set<string>) = 
    let str2GramEle str = 
        if Set.contains str tnSet then 
           TN(str) 
        else 
            NTN(str)  
     
    let (lhd,rhd) = copeOneGram inStr 
    (i,List.head lhd,LPAR(i)::(List.map str2GramEle rhd) @ [RPAR(i)]) 
 
//ここからtree用 
type embodyST = 
    |Leaf of string  
    |Node of (string * list<embodyST>) 
     
    member this.dispStr (inc :int)  = //inc = インシデント 
            match this with 
            |Leaf(str) 
                -> spaceStr(inc) + str + "\r\n"  
            |Node(str,lst)  
                -> spaceStr(inc) + str + "\r\n"  
                   + List.fold (fun state (ele:embodyST) -> state + (ele.dispStr (inc + 4)) ) "" lst  
 
let rec makeTreeSub (map:Map<int,string>) ((gEleLst:list<GramEle>),(acc:list<embodyST>)) = 
    match gEleLst with 
    |LPAR(i)::tl -> match (makeTreeSub map (tl,[])) with 
                    |remain,underNodes -> makeTreeSub map (remain,acc @ [Node(sprintf "(%2d)%s" i map.[i],underNodes)]) 
                    |_ -> failwith "error"  //起こらない 
                    
    |TN(str)::tl ->  makeTreeSub map (tl,acc @ [Leaf(str)]) 
    |RPAR(i)::tl ->  (tl,acc) 
    | []         -> ([],acc)  
    |_ -> failwith "error" //起こらない 
 
//tree用終わり 
 
let f2c x = x :> System.Windows.Forms.Control  
let base_gram_tb= new TextBox(Location = new Point(12, 48),Multiline = true,Name = "base_gram_tb",Size = new Size(729, 149),TabIndex = 0) 
let apply_btn= new Button(Location = new Point(128, 213),Name = "apply_btn",Size = new Size(330, 23),TabIndex = 1,Text = "適用",UseVisualStyleBackColor = true) 
let reset_btn= new Button(Location = new Point(81, 417),Name = "reset_btn",Size = new Size(135, 23),TabIndex = 5,Text = "リセット",UseVisualStyleBackColor = true) 
let deriv_btn= new Button(Location = new Point(361, 417),Name = "deriv_btn",Size = new Size(335, 23),TabIndex = 6,Text = "導出",UseVisualStyleBackColor = true) 
let exp1_tb= new TextBox(Location = new Point(12, 457),Multiline = true,Name = "exp1_tb",ScrollBars = ScrollBars.Vertical,Size = new Size(729, 70),TabIndex = 7) 
let exp2_tb= new TextBox(Location = new Point(12, 594),Multiline = true,Name = "exp2_tb",ScrollBars = ScrollBars.Vertical,Size = new Size(729, 74),TabIndex = 8) 
let log_tb= new TextBox(Location = new Point(12, 690),Multiline = true,Name = "log_tb",ScrollBars = ScrollBars.Vertical,Size = new Size(729, 117),TabIndex = 9) 
let label1= new Label(AutoSize = true,Location = new Point(12, 439),Name = "label1",Size = new Size(37, 12),TabIndex = 10,Text = "表現1") 
let label2= new Label(AutoSize = true,Location = new Point(12, 577),Name = "label2",Size = new Size(37, 12),TabIndex = 11,Text = "表現2") 
let label3= new Label(AutoSize = true,Location = new Point(16, 671),Name = "label3",Size = new Size(23, 12),TabIndex = 12,Text = "ログ") 
let label4= new Label(AutoSize = true,Location = new Point(10, 251),Name = "label4",Size = new Size(53, 12),TabIndex = 13,Text = "終端記号") 
let label5= new Label(AutoSize = true,Location = new Point(171, 251),Name = "label5",Size = new Size(65, 12),TabIndex = 14,Text = "非終端記号") 
let label6= new Label(AutoSize = true,Location = new Point(324, 251),Name = "label6",Size = new Size(53, 12),TabIndex = 15,Text = "構文規則") 
let label7= new Label(AutoSize = true,Location = new Point(12, 9),Name = "label7",Size = new Size(53, 12),TabIndex = 16,Text = "構文規則") 
let load_btn= new Button(Location = new Point(585, 4),Name = "load_btn",Size = new Size(75, 23),TabIndex = 17,Text = "Load",UseVisualStyleBackColor = true) 
let save_btn= new Button(Location = new Point(666, 4),Name = "save_btn",Size = new Size(75, 23),TabIndex = 18,Text = "Save",UseVisualStyleBackColor = true) 
let gram_lb= new ListBox(FormattingEnabled = true,ItemHeight = 12,Location = new Point(326, 266),Name = "gram_lb",Size = new Size(415, 136),TabIndex = 20) 
let ntn_lb= new ListBox(FormattingEnabled = true,ItemHeight = 12,Location = new Point(162, 266),Name = "ntn_lb",Size = new Size(143, 136),TabIndex = 21) 
let term_lb= new ListBox(FormattingEnabled = true,ItemHeight = 12,Location = new Point(18, 266),Name = "term_lb",Size = new Size(128, 136),TabIndex = 22) 
let error_tb= new TextBox(Location = new Point(12, 833),Multiline = true,Name = "error_tb",Size = new Size(729, 70),TabIndex = 23) 
let label8= new Label(AutoSize = true,Location = new Point(16, 814),Name = "label8",Size = new Size(32, 12),TabIndex = 24,Text = "エラー") 
let embodySTDisp_btn= new Button(Location = new Point(361, 533),Name = "embodySTDisp_btn",Size = new Size(369, 23),TabIndex = 25,Text = "具象抽象木の表示",UseVisualStyleBackColor = true) 
let label9= new Label(AutoSize = true,Location = new Point(366, 564),Name = "label9",Size = new Size(177, 12),TabIndex = 26,Text = "すべて終端記号にしてから実行のこと") 
let embodyST_tb= new TextBox(Location = new Point(755, 458),Multiline = true,Name = "embodyST_tb",ScrollBars = ScrollBars.Both,Size = new Size(387, 445),TabIndex = 27) 
let label10= new Label(AutoSize = true,Location = new Point(763, 435),Name = "label10",Size = new Size(65, 12),TabIndex = 28,Text = "具象抽象木") 
let label11= new Label(AutoSize = true,Location = new Point(97, 9),Name = "label11",Size = new Size(421, 12),TabIndex = 29,Text = "εはEPSILONとして入力(これは終端記号ではないが、下の終端記号欄に表示される。)") 
let label12= new Label(AutoSize = true,Location = new Point(101, 26),Name = "label12",Size = new Size(433, 12),TabIndex = 30,Text = "デフォルトでZ = Program EOFが文法に追加されます。Programの定義を必ずしてください。") 
let mainForm= new Form(AutoScaleDimensions = new SizeF(6.0f, 12.0f),AutoScaleMode = AutoScaleMode.Font,ClientSize = new Size(1154, 915),Name = "mainForm",Text = "FreeLang") 
[ f2c label12; f2c label11; f2c label10; f2c embodyST_tb; f2c label9; f2c embodySTDisp_btn; f2c label8; f2c error_tb; f2c term_lb; f2c ntn_lb; f2c gram_lb; f2c save_btn; f2c load_btn; f2c label7; f2c label6; f2c label5; f2c label4; f2c label3; f2c label2; f2c label1; f2c log_tb; f2c exp2_tb; f2c exp1_tb; f2c deriv_btn; f2c reset_btn; f2c apply_btn; f2c base_gram_tb] |> List.iter(fun cnt -> mainForm.Controls.Add cnt) 
 
type gramRule = int* string * list<GramEle> 
 
//base_gram_tbの内容をlist<string>として保持する値(ここより下の広域変数) 
let mutable base_gram_lst:list<string> = [] 
let mutable ntn_set  = Set.empty 
let mutable tn_set = Set.empty 
let mutable gramArr:gramRule [] = null 
let mutable curExpLst :list<GramEle> = [] 
//let mutable curGramIndex = 0 
 
//curExpLst の表示変換用1 
let convExp1 (cel:list<GramEle>) = 
    cel 
        |> List.map (fun ele -> match ele with 
                                |NTN(str) -> " " + str 
                                |TN(str) -> " " + str 
                                |_ -> "") 
        |> List.fold (fun state ele -> state +   ele) "" 
 
//curExpLst の表示変換用2 
let convExp2 (cel:list<GramEle>) = 
    cel 
        |> List.map (fun ele -> match ele with 
                                |LPAR(i) -> "(" + i.ToString()  
                                |NTN(str) -> str 
                                |TN(str) -> str 
                                |RPAR(i) ->  i.ToString() + ")" 
                     ) 
        |> List.fold (fun state ele -> state + " " +  ele) "" 
 
let leftMostRepGELst (inWholeCel:list<GramEle>) (inRep:gramRule) = 
    let (_,targetNTN,repedLst) = inRep 
    let rec leftMostRepGELstSub lst res = 
        match lst with 
        |NTN(str)::tl when str <> targetNTN-> inWholeCel  
        |NTN(str)::tl when str = targetNTN -> (List.rev res) @  repedLst @ tl  
        | ele :: tl                        -> leftMostRepGELstSub tl (ele::res)  
        | []                               -> inWholeCel 
    leftMostRepGELstSub inWholeCel [] 
 
let reset() = 
    if Array.length gramArr > 0 then 
        curExpLst <- let (_,_,firstRule) = gramArr.[0] // Z = Program EOFに対応する部分 
                     firstRule 
        exp1_tb.Text <- convExp1 curExpLst 
        exp2_tb.Text <- convExp2 curExpLst 
        log_tb.Text  <- " 0: " + (convExp1 curExpLst) 
    else 
        MessageBox.Show("文法を適用してから押してください") |> ignore 
 
 
//メインウィンドウのボタンへの関数登録  
 
 
apply_btn.Click.Add 
    (fun _ -> let tempLst =  base_gram_tb.Text.Split([|'\n'|]) 
                                 |> Array.map (fun str -> str.Trim()) 
                                 |> List.ofArray  
               
              base_gram_lst <- "Z = Program EOF" :: tempLst  
              let (tempNTN_Set,tempNT_Set) = getTN_NTN_Sets base_gram_lst                    
              ntn_set <- tempNTN_Set 
              tn_set  <- tempNT_Set 
              [ntn_lb;term_lb;gram_lb] |> List.iter (fun lb -> lb.Items.Clear()) 
              Set.iter (fun ele -> ntn_lb.Items.Add(ele) |> ignore ) ntn_set 
              Set.iter (fun ele -> term_lb.Items.Add(ele) |> ignore ) tn_set 
              //次の2行で文法番号とListBoxのインデックスとgramArrのインデックスは一致するようにしてある 
              List.iteri (fun i ele -> gram_lb.Items.Add((sprintf " %2d : " i) + ele)|>ignore) base_gram_lst 
              gramArr <- base_gram_lst    
                            |> List.mapi (fun i ele -> convOneLine2GramEle i ele ntn_set tn_set)  
                            |> Array.ofList 
              reset() 
              ) 
 
reset_btn.Click.Add 
    (fun _ -> reset()) 
 
deriv_btn.Click.Add 
    (fun _ -> try 
                let selectedGramIndex = gram_lb.SelectedIndex 
                let selectedGram = gramArr.[selectedGramIndex]  
                let replacedGramEleLst = leftMostRepGELst curExpLst selectedGram  
                curExpLst <- replacedGramEleLst 
                exp1_tb.Text <- convExp1 curExpLst 
                exp2_tb.Text <- convExp2 curExpLst 
                log_tb.Text  <- log_tb.Text + "\r\n" + (sprintf "%2d; " selectedGramIndex) + (convExp1 curExpLst) 
              with  
                | ex -> error_tb.Text <- ex.Message  
                   
    ) 
 
//Load  
load_btn.Click.Add  
    (fun _ -> try  
                let ofd = new OpenFileDialog(Filter = "GRAファイル(*.gra)|*.gra|すべてのファイル(*.*)|*.*")  
                if(ofd.ShowDialog() = DialogResult.OK) then  
                    use sr = new System.IO.StreamReader(ofd.FileName)  
                    base_gram_tb.Text <- sr.ReadToEnd()  
              with  
                | ex -> error_tb.Text <- ex.Message  
    )  
 
//Save  
save_btn.Click.Add  
    (fun _ -> try  
                let sfd = new SaveFileDialog(Filter = "GRAファイル(*.gra)|*.gra|すべてのファイル(*.*)|*.*",  
                                              RestoreDirectory = true)  
                if (sfd.ShowDialog() = DialogResult.OK) then  
                    use sw = new System.IO.StreamWriter(sfd.FileName)  
                    sw.Write(base_gram_tb.Text)  
              with  
                | ex -> error_tb.Text <- ex.Message  
                  
    )  
 
embodySTDisp_btn.Click.Add 
    (fun _ -> let gramStrMap = 
                    gramArr 
                      |> Array.map (fun (i,str,_) -> (i,str)) 
                      |> Map.ofArray 
              let (_,embodySt1) =  makeTreeSub gramStrMap (curExpLst,[]) 
              printfn "%A" embodySt1 
              embodyST_tb.Text <- (List.head embodySt1).dispStr(4) //返ってくるとき要素は一つ 
 
    )   
 
 
[<STAThread()>]   
do Application.Run(mainForm)   
スポンサーサイト

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

コメントの投稿

非公開コメント

プロフィール

T GYOUTEN

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

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

この人とブロともになる

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