スポンサーサイト

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

F#で入門 コンパイラ、インタプリタ編 LL(1) director集合 構文解析表

 例えば次の構文規則を考えるとします。 
1:Program = DeclStmts PrintStmts 
2:DeclStmts = DeclStmt SEMI DeclStmts2 
3:DeclStmts2  = EPSILON 
4:DeclStmts2  = DeclStmts 
5:DeclStmt = INT VarDefs 
6:VarDefs = ID EQ NUM VarDefs2 
7:VarDefs2 = COMMA ID EQ NUM VarDefs2 
8:VarDefs2 = EPSILON 
9:PrintStmts = EPSILON 
10:PrintStmts = PrintStmt SEMI PrintStmts 
11:PrintStmt = EX VarRefs 
12:VarRefs = ID VarRefs2 
13:VarRefs2 = COMMA ID VarRefs2 
14:VarRefs2 = EPSILON 
 
ここまでnullable,first集合、follow集合とやってきたのは、例えば 
下向き構文解析でDeclStats2に対応する関数を書くときに 
//3:DeclStmts2  = EPSILON 
//4:DeclStmts2  = DeclStmts 
and declStats2 (remain:list<TokenKind>) = 
       match remain with 
       |(3の場合)-> なんたらかんたら  
       |(4の場合)-> どーしたこーした 
 
この時3,4の場合分けをトークン(終端記号)で行う必要があり、どのようなとき3か、どのようなとき4かを判別する方法を考えるためでした。 
 
4:DeclStmts2  = DeclStmtsを使用して導出されている場合は、DeclStamtsがnullableでない場合は、DeclStamtsのFirst集合の要素のどれかが現れ、DeclStamtsがnullableである場合(実際には前々回調べたようにこれはないのですが)は、DeclStamtsのFirst集合とFollow集合の和集合の要素のどれかが残りトークンの頭にあるはずです。 
また3:DeclStmts2  = EPSILONを使用して導出されている場合は、nullableですから、DeclStmts2のfollow集合の要素のどれかが残りトークンの頭にあるはずです。 
 
一般にX→αを使って終端記号まで導出していった場合、先頭に現れる終端記号の集合をX→αのDirector集合といいDirector(X→α)で表します。 
上でやったようにDirector(X→α)はαがnullableの時はFirst(α)とFollow(α)の和集合、 
αがnullableでないときはFirst(α)となります。 
 
例えばもし上の3と4のDirector集合が共通要素を持てば(実際には持ちませんが)、どちらの構文になっているのか判別不能ですので、LL(1)解析できません。 
 
実際には3:DeclStmts2  = EPSILONのDirector集合はset[EOF,EX] 
4:DeclStmts2  = DeclStmtsのDirector集合はset[INT]となり衝突していません。 
 
これを表形式で 
________________EOF______EX________INT 
DeclStmts2_______3_______3__________4 
 
というように表します。これはDeclStmts2が呼び出されている時に先頭トークンがEOFかEXならば3の形の導出がなされているのでその形として処理、先頭トークンがINTならば4の形の導出がなされているので、その形として処理することを分かりやすくまとめたもので構文解析表といいます。 
なお先頭トークンがEOF,EX,INTのどれでもない場合は構文エラーです。 
 
それでは構文番号と、Director集合を対応させるMapを求める関数を定義します。 
 
> let getNTN_DirectorMap  (inStrLst:list<string>) = 
    let (ntnSet,tnSet) = getNTN_TN__Sets inStrLst 
    let ntnNullableMap = getNTN_NullableMap inStrLst 
    let ntnFirstMap = getNTN_FirstMap inStrLst 
    let isNullableTokensLstPA (tokenLst:list<string>) = isNullableTokenLst (ntnSet,tnSet) ntnNullableMap tokenLst 
    let getFirstSetOfTokenLstPA (tokenLst:list<string>) = getFirstSetOfTokenLst (ntnSet,tnSet) ntnNullableMap  ntnFirstMap tokenLst 
    let ntnFollowMap = getNTN_FollowMap inStrLst 
    let gramsWithIndex = inStrLst 
                            |> List.map splitOneLineGram 
                            |> List.map (fun (index,lh,rhEles) -> (index,(lh,rhEles)))  
     
    let getNTN_DirectorSet (inHh:string,inRhEles:list<string>) = 
        if isNullableTokensLstPA inRhEles then 
            (getFirstSetOfTokenLstPA inRhEles) + ntnFollowMap.[inHh] 
        else 
            (getFirstSetOfTokenLstPA inRhEles) 
 
 
    gramsWithIndex 
        |> List.map (fun (index,(lh,rhEles)) -> (index, getNTN_DirectorSet (lh,rhEles))) 
        |> Map.ofList;; 
 
val getNTN_DirectorMap : string list -> Map<int,Set<string>> 
 
(実行例) 
> getNTN_DirectorMap testStrLst;; 
val it : Map<int,Set<string>> = 
  map 
    [(0, set ["INT"]); (1, set ["INT"]); (2, set ["INT"]); 
     (3, set ["EOF"; "EX"]); (4, set ["INT"]); (5, set ["INT"]); 
     (6, set ["ID"]); (7, set ["COMMA"]); (8, set ["SEMI"]); ...] 
 
 
次に構文解析表用のMapを作る関数を定義します。 
 
>let getParsingRelation (inStrLst:list<string>) = 
    let directorMap = getNTN_DirectorMap inStrLst 
    let gramsWithIndex = inStrLst 
                            |> List.map splitOneLineGram 
                            |> List.map (fun (index,lh,rhEles) -> (index,(lh,rhEles)))  
         
    let relationBetweenIndexAndNTN_namdAndDirecSetList 
        = [ for (index,(lh,rhEles)) in gramsWithIndex do 
                for direcEle in directorMap.[index] do 
                    yield (index,lh,direcEle) ] 
 
    let ParsingRelation 
        = relationBetweenIndexAndNTN_namdAndDirecSetList 
            |> List.fold (fun (stateMap:Map<string*string,Set<int>>)  (index,lh,direcEle)  ->       
                                    let tf = Map.tryFind (lh,direcEle) stateMap 
                                    match tf with 
                                    |Some(oldSet) -> Map.add (lh,direcEle) (oldSet + (Set.ofList [index])) stateMap 
                                    |None         -> Map.add (lh,direcEle) (Set.ofList [index]) stateMap 
                         ) 
                         Map.empty               
     
    ParsingRelation;; 
 
 
val getParsingRelation : string list -> Map<(string * string),Set<int>> 
 
(実行例) 
> getParsingRelation testStrLst;; 
val it : Map<(string * string),Set<int>> = 
  map 
    [(("DeclStmt", "INT"), set [5]); (("DeclStmts", "INT"), set [2]); 
     (("DeclStmts2", "EOF"), set [3]); (("DeclStmts2", "EX"), set [3]); 
     (("DeclStmts2", "INT"), set [4]); (("PrintStmt", "EX"), set [11]); 
     (("PrintStmts", "EOF"), set [9]); (("PrintStmts", "EX"), set [10]); 
     (("Program", "INT"), set [1]); ...] 
      
最後に今までやった関数をまとめて、構文規則を入力すると、nullable,First Set,Follow Set,Director Set,構文解析表を表示するウィンドウソフトにします。実行画面は次のようなもので、構文規則を入力して、「適用」ボタンを押すと、下に一覧が表示されます。

1009-1.jpg

1009-2.jpg


1009-3.jpg

全ソースは以下の通りです。
 全ソースは以下の通りです。 
 
open System    
open System.Windows.Forms    
open System.Drawing  
 
//文法定義のエラー 
exception MyGramExcp of string 
 
let STR_EPS ="EPSILON" 
 
///////////////////////////////// 
 
//splitOneLineGram "5:Program = DeclStmts PrintStmts" 
//結果 (5,"Program", ["DeclStmts"; "PrintStmts"]) 
let splitOneLineGram (inStr:string)= 
    let (lhdIndex,rhd) =  
        match inStr.Split([|':'|]) with 
        [|mlhd;mrhd|]  ->  (mlhd.Trim(),mrhd) 
        | _             ->  raise <| MyGramExcp(inStr)  
    let (lhd,rhd2) = 
        match rhd.Split([|'='|]) with 
        |[|mlhd;mrhd|]  ->  (mlhd.Trim(),mrhd) 
        | _             ->  raise <| MyGramExcp(inStr)  
    let rhdElems =  
        rhd2.Split([|' '|]) 
            |> List.ofArray 
            |> List.map (fun s -> s.Trim()) 
            |> List.filter (fun s -> s <> "") 
    (System.Int32.Parse(lhdIndex),lhd,rhdElems) 
 
//非終端記号と終端記号のSetを返す 
//getNTN_TN_Sets ["1:Program = DeclStmts PrintStmts";"2:DeclStmts = VAR SEMI";"3:PrintStmts = EPSILON"] 
//(set ["DeclStmts"; "PrintStmts"; "Program"], set ["SEMI"; "VAR"]) 
let getNTN_TN__Sets (inStrLst:list<string>) = 
    let (sumUpLhdSet,sumUpRhdSet) = 
        inStrLst 
            |> List.map splitOneLineGram 
            |> List.fold (fun (acclh,accrh)  (_,lhd,rhdLst) -> (lhd :: acclh,rhdLst @ accrh)) ([],[]) 
            |> (fun (hdLst,rhLst) -> (Set.ofList hdLst, Set.ofList rhLst)) 
    (sumUpLhdSet,sumUpRhdSet - sumUpLhdSet - (Set.ofList [STR_EPS])) 
 
let isNullableToken ((in_ntn,in_tn):Set<string>*Set<string>) (in_ntnNullableMap:Map<string,bool>)(inTokenName:string) = 
    if inTokenName = STR_EPS then  
         true 
    elif Set.contains inTokenName in_tn then 
         false 
    else 
        in_ntnNullableMap.[inTokenName] 
 
let isNullableTokenLst ((in_ntn,in_tn):Set<string>*Set<string>) (in_ntnNullableMap:Map<string,bool>)(inTokenNameLst:list<string>) = 
      List.forall (isNullableToken (in_ntn,in_tn) in_ntnNullableMap )inTokenNameLst //リスト中のすべてのtokenがnullableか 
           
let isNullableTokenLstLst ((in_ntn,in_tn):Set<string>*Set<string>) (in_ntnNullableMap:Map<string,bool>)(inTokenNameLstLst:list<list<string>>) = 
      List.exists (isNullableTokenLst (in_ntn,in_tn) in_ntnNullableMap ) inTokenNameLstLst//リスト中のどれかのtokenリストがnullableか 
 
//getNTN_NullableMap ["1:Program = DeclStmts SEMI PrintStmts";"2:DeclStmts = EPSILON";"3:PrintStmts = EPSILON";"4:PrintStmts = PRINT"] 
// map [("DeclStmts", true); ("PrintStmts", true); ("Program", false)] 
let getNTN_NullableMap (inStrLst:list<string>) = 
     
    let (ntnSet,tnSet) = getNTN_TN__Sets inStrLst 
     
    let grams = inStrLst 
                  |> List.map splitOneLineGram 
                  |> List.map (fun (_,lh,rhEles) -> (lh,rhEles)) //[("Program",["DeclStmts";"PrintStmts"]);("DeclStmts",["VAR";"SEMI"])] 
     
    let rec getNTN_NullableMapSub (inOldNullableMap:Map<string,bool>) (count:int) =  
        let nextNullableMap = 
            ntnSet 
                |> Set.fold (fun stateMap ele -> 
                                let targetGramsLstLst = 
                                    grams 
                                        |>List.filter (fun (ntnName,_) -> ntnName = ele) 
                                        |>List.map (fun (_,lst) -> lst) 
                                let thisEleNullable = 
                                    isNullableTokenLstLst(ntnSet,tnSet) inOldNullableMap targetGramsLstLst 
                                Map.add ele thisEleNullable stateMap 
                             ) 
                             Map.empty 
        if count > 10000 then 
            failwith "count error" 
        elif nextNullableMap = inOldNullableMap then 
            nextNullableMap 
        else 
            getNTN_NullableMapSub nextNullableMap (count + 1) 
     
    let initNullableMap = 
                ntnSet 
                    |> Set.map (fun ele -> (ele,false)) 
                    |> Map.ofSeq 
     
    getNTN_NullableMapSub initNullableMap 0 
 
//first集合を求める(トークン一つ用) 
let getFirstSetOfToken ((in_ntn,in_tn):Set<string>*Set<string>) (in_ntnFirstSetMap:Map<string,Set<string>>)(inTokenName:string) = 
    if inTokenName = STR_EPS then  
         Set.empty 
    elif Set.contains inTokenName in_tn then 
         Set.ofList ([inTokenName]) 
    else 
        in_ntnFirstSetMap.[inTokenName] 
 
//first集合を求める(トークンリスト用) 
let getFirstSetOfTokenLst ((in_ntn,in_tn):Set<string>*Set<string>) (in_ntnNullableMap:Map<string,bool>) 
                           (in_firstSetMap:Map<string,Set<string>>) (inTokenNameLst:list<string>) = 
      let isNullableTokenPartApply = isNullableToken (in_ntn,in_tn) in_ntnNullableMap    
       
      let rec getFirstSetOfTokenLstSub (tokenLst:list<string>)  = 
        match tokenLst with 
        |[] -> Set.empty 
        |hd::tl when isNullableTokenPartApply hd -> (getFirstSetOfToken (in_ntn,in_tn) in_firstSetMap hd) + (getFirstSetOfTokenLstSub tl) 
        |hd::tl                                  -> (getFirstSetOfToken (in_ntn,in_tn) in_firstSetMap hd) 
 
      getFirstSetOfTokenLstSub inTokenNameLst 
 
//first集合を求める(トークンリストのリスト) 
let getFirstSetOfTokenLstLst ((in_ntn,in_tn):Set<string>*Set<string>) (in_ntnNullableMap:Map<string,bool>) 
                          (in_firstSetMap:Map<string,Set<string>>) (inTokenNameLstLst:list<list<string>>) =   
 
    let getFirstSetOfTokenLstPartApply = getFirstSetOfTokenLst (in_ntn,in_tn) in_ntnNullableMap in_firstSetMap 
     
    List.fold (fun acc ele -> acc + (getFirstSetOfTokenLstPartApply ele)) Set.empty inTokenNameLstLst 
 
//first集合を求める 
let getNTN_FirstMap  (inStrLst:list<string>) = 
     
    let (ntnSet,tnSet) = getNTN_TN__Sets inStrLst 
    let ntnNullableMap = getNTN_NullableMap inStrLst 
 
    let grams = inStrLst 
                  |> List.map splitOneLineGram 
                  |> List.map (fun (_,lh,rhEles) -> (lh,rhEles)) //[("Program",["DeclStmts";"PrintStmts"]);("DeclStmts",["VAR";"SEMI"])] 
     
    let FisrtSetOfTokenLstLstPA = getFirstSetOfTokenLstLst (ntnSet,tnSet) ntnNullableMap 
     
    let rec getNTN_FirstMapSub (inOldFirstMap:Map<string,Set<string>>) (count:int) =  
        let nextFirstMap = 
            ntnSet 
                |> Set.fold (fun stateMap ele -> 
                                let targetGramsLstLst = 
                                    grams 
                                        |>List.filter (fun (ntnName,_) -> ntnName = ele) 
                                        |>List.map (fun (_,lst) -> lst) 
                                let thisEleFisrtSet = 
                                     FisrtSetOfTokenLstLstPA inOldFirstMap targetGramsLstLst 
                                Map.add ele thisEleFisrtSet stateMap 
                             ) 
                             Map.empty 
        if count > 10000 then 
            failwith "count error" 
        elif nextFirstMap = inOldFirstMap then 
            nextFirstMap 
        else 
            getNTN_FirstMapSub nextFirstMap (count + 1) 
     
    let initFirstMap = 
                ntnSet 
                    |> Set.map (fun ele -> (ele,Set.empty)) 
                    |> Map.ofSeq 
     
    getNTN_FirstMapSub initFirstMap 0 
 
//follow補助 
 
// getAfterTokens "DeclStmts1" ("PrintStmts1",["VarDef1";"DeclStmts1";"VarDef2";"VarDef3";"DeclStmts1";"VarDef4"]);; 
//val it : (string list * string) list = 
//  [(["VarDef4"], "PrintStmts1"); 
//   (["VarDef2"; "VarDef3"; "DeclStmts1"; "VarDef4"], "PrintStmts1")] 
let getAfterTokens (inStr:string) ((lhdStr,rhStrLst):string*list<string>) = 
    let rec getAfterTokensSub strLst res = 
        match strLst with 
        |hd::tl when hd = inStr -> getAfterTokensSub tl ((tl,lhdStr)::res) 
        |hd::tl                 -> getAfterTokensSub tl res 
        | [] -> res 
    getAfterTokensSub rhStrLst [] 
 
 
let getNTN_FollowMap  (inStrLst:list<string>) = 
    let (ntnSet,tnSet) = getNTN_TN__Sets inStrLst 
    let ntnNullableMap = getNTN_NullableMap inStrLst 
    let ntnFirstMap = getNTN_FirstMap inStrLst 
    let isNullableTokensLstPA (tokenLst:list<string>) = isNullableTokenLst (ntnSet,tnSet) ntnNullableMap tokenLst 
    let getFirstSetOfTokenLstPA (tokenLst:list<string>) = getFirstSetOfTokenLst (ntnSet,tnSet) ntnNullableMap  ntnFirstMap tokenLst 
    let grams = inStrLst 
                  |> List.map splitOneLineGram 
                  |> List.map (fun (_,lh,rhEles) -> (lh,rhEles)) //[("Program",["DeclStmts";"PrintStmts"]);("DeclStmts",["VAR";"SEMI"])] 
  
    let rec getNTN_FollowMapSub (inOldFollowMap:Map<string,Set<string>>) (count:int) =  
       let getFollowSet (afterTokens:list<string>,ntnName:string) = 
                if isNullableTokensLstPA afterTokens then 
                    (getFirstSetOfTokenLstPA afterTokens) + (inOldFollowMap.[ntnName]) 
                else 
                    (getFirstSetOfTokenLstPA afterTokens)                 
       let nextFollowMap = 
            ntnSet 
                |> Set.fold (fun stateMap ele -> 
                                let includeEleGrams = 
                                    grams 
                                      |> List.fold (fun state2 (ntnName2,tokenLst) 
                                                        -> state2 @ (getAfterTokens ele (ntnName2,tokenLst))) 
                                                    [] 
                                                     
                                let followSet = 
                                    includeEleGrams 
                                      |> List.fold (fun (state3:Set<string>) (afterTokens,ntnName) -> 
                                                    state3 + (getFollowSet (afterTokens,ntnName))) 
                                                    Set.empty 
                                Map.add ele followSet stateMap 
                             ) 
                             Map.empty 
       if count > 10000 then 
            failwith "count error" 
       elif nextFollowMap = inOldFollowMap then 
            nextFollowMap 
       else 
            getNTN_FollowMapSub nextFollowMap (count + 1) 
 
 
    let initFollowMap = 
                ntnSet 
                    |> Set.map (fun ele -> (ele,Set.empty)) 
                    |> Map.ofSeq 
     
    getNTN_FollowMapSub initFollowMap 0 
 
//directorMap キーは構文番号(整数) 値はSet<string> 
let getNTN_DirectorMap  (inStrLst:list<string>) = 
    let (ntnSet,tnSet) = getNTN_TN__Sets inStrLst 
    let ntnNullableMap = getNTN_NullableMap inStrLst 
    let ntnFirstMap = getNTN_FirstMap inStrLst 
    let isNullableTokensLstPA (tokenLst:list<string>) = isNullableTokenLst (ntnSet,tnSet) ntnNullableMap tokenLst 
    let getFirstSetOfTokenLstPA (tokenLst:list<string>) = getFirstSetOfTokenLst (ntnSet,tnSet) ntnNullableMap  ntnFirstMap tokenLst 
    let ntnFollowMap = getNTN_FollowMap inStrLst 
    let gramsWithIndex = inStrLst 
                            |> List.map splitOneLineGram 
                            |> List.map (fun (index,lh,rhEles) -> (index,(lh,rhEles)))  
     
    let getNTN_DirectorSet (inHh:string,inRhEles:list<string>) = 
        if isNullableTokensLstPA inRhEles then 
            (getFirstSetOfTokenLstPA inRhEles) + ntnFollowMap.[inHh] 
        else 
            (getFirstSetOfTokenLstPA inRhEles) 
 
 
    gramsWithIndex 
        |> List.map (fun (index,(lh,rhEles)) -> (index, getNTN_DirectorSet (lh,rhEles))) 
        |> Map.ofList              
 
 
//構文解析表のMapを作る。 
let getParsingRelation (inStrLst:list<string>) = 
    let directorMap = getNTN_DirectorMap inStrLst 
    let gramsWithIndex = inStrLst 
                            |> List.map splitOneLineGram 
                            |> List.map (fun (index,lh,rhEles) -> (index,(lh,rhEles)))  
         
    let relationBetweenIndexAndNTN_namdAndDirecSetList 
        = [ for (index,(lh,rhEles)) in gramsWithIndex do 
                for direcEle in directorMap.[index] do 
                    yield (index,lh,direcEle) ] 
 
    let ParsingRelation 
        = relationBetweenIndexAndNTN_namdAndDirecSetList 
            |> List.fold (fun (stateMap:Map<string*string,Set<int>>)  (index,lh,direcEle)  ->       
                                    let tf = Map.tryFind (lh,direcEle) stateMap 
                                    match tf with 
                                    |Some(oldSet) -> Map.add (lh,direcEle) (oldSet + (Set.ofList [index])) stateMap 
                                    |None         -> Map.add (lh,direcEle) (Set.ofList [index]) stateMap 
                         ) 
                         Map.empty               
     
    ParsingRelation 
 
 
let f2c x = x :> System.Windows.Forms.Control  
let base_gram_tb= new TextBox(Location = new Point(12, 31),Multiline = true,Name = "base_gram_tb",ScrollBars = ScrollBars.Both,Size = new Size(932, 166),TabIndex = 0) 
let apply_btn= new Button(Location = new Point(128, 213),Name = "apply_btn",Size = new Size(364, 23),TabIndex = 1,Text = "適用",UseVisualStyleBackColor = true) 
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(101, 12),TabIndex = 16,Text = "構文規則(入力用)") 
let load_btn= new Button(Location = new Point(783, 4),Name = "load_btn",Size = new Size(75, 23),TabIndex = 17,Text = "Load",UseVisualStyleBackColor = true) 
let save_btn= new Button(Location = new Point(864, 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(613, 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(923, 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 label1= new Label(AutoSize = true,Location = new Point(160, 9),Name = "label1",Size = new Size(176, 12),TabIndex = 25,Text = "文法番号:非終端記号 = トークン列") 
let nullable_tb= new TextBox(Location = new Point(14, 28),Multiline = true,Name = "nullable_tb",ScrollBars = ScrollBars.Both,Size = new Size(267, 291),TabIndex = 27) 
let firstSet_tb= new TextBox(Location = new Point(321, 28),Multiline = true,Name = "firstSet_tb",ScrollBars = ScrollBars.Both,Size = new Size(267, 291),TabIndex = 29) 
let followSet_tb= new TextBox(Location = new Point(628, 28),Multiline = true,Name = "followSet_tb",ScrollBars = ScrollBars.Both,Size = new Size(267, 291),TabIndex = 31) 
let tabControl1= new TabControl(Location = new Point(18, 417),Name = "tabControl1",SelectedIndex = 0,Size = new Size(921, 379),TabIndex = 32) 
let tabPage1= new TabPage(Location = new Point(4, 22),Name = "tabPage1",Padding = new Padding(3),Size = new Size(913, 353),TabIndex = 0,Text = "nullable FirstSet FollowSet",UseVisualStyleBackColor = true) 
let tabPage2= new TabPage(Location = new Point(4, 22),Name = "tabPage2",Padding = new Padding(3),Size = new Size(913, 353),TabIndex = 1,Text = "DirectorSet",UseVisualStyleBackColor = true) 
let tabPage3= new TabPage(Location = new Point(4, 22),Name = "tabPage3",Size = new Size(913, 353),TabIndex = 2,Text = "構文解析表",UseVisualStyleBackColor = true) 
let label9= new Label(AutoSize = true,Location = new Point(626, 9),Name = "label9",Size = new Size(59, 12),TabIndex = 34,Text = "Follow Set") 
let label3= new Label(AutoSize = true,Location = new Point(325, 9),Name = "label3",Size = new Size(49, 12),TabIndex = 33,Text = "First set") 
let label2= new Label(AutoSize = true,Location = new Point(15, 9),Name = "label2",Size = new Size(44, 12),TabIndex = 32,Text = "nullable") 
let directorSet_lv= new ListView(Location = new Point(15, 15),Name = "directorSet_lv",Size = new Size(871, 318),TabIndex = 0,UseCompatibleStateImageBehavior = false) 
let parsing_lv= new ListView(Location = new Point(21, 17),Name = "parsing_lv",Size = new Size(871, 318),TabIndex = 1,UseCompatibleStateImageBehavior = false) 
let label10= new Label(AutoSize = true,Location = new Point(361, 9),Name = "label10",Size = new Size(73, 12),TabIndex = 33,Text = "εはEPSILON") 
let mainForm= new Form(AutoScaleDimensions = new SizeF(6.0f, 12.0f),AutoScaleMode = AutoScaleMode.Font,ClientSize = new Size(952, 915),Name = "mainForm",Text = "nullable First Follow Director") 
[ f2c label10; f2c tabControl1; f2c label1; 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 apply_btn; f2c base_gram_tb] |> List.iter(fun cnt -> mainForm.Controls.Add cnt) 
[ f2c tabPage1; f2c tabPage2; f2c tabPage3] |> List.iter(fun cnt -> tabControl1.Controls.Add cnt) 
[ f2c label9; f2c label3; f2c label2; f2c nullable_tb; f2c followSet_tb; f2c firstSet_tb] |> List.iter(fun cnt -> tabPage1.Controls.Add cnt) 
[ f2c directorSet_lv] |> List.iter(fun cnt -> tabPage2.Controls.Add cnt) 
[ f2c parsing_lv] |> List.iter(fun cnt -> tabPage3.Controls.Add cnt) 
 
let clear () = 
    ntn_lb.Items.Clear() 
    term_lb.Items.Clear() 
    gram_lb.Items.Clear() 
    nullable_tb.Text <- "" 
    firstSet_tb.Text <- "" 
    followSet_tb.Text <- "" 
    directorSet_lv.Clear() 
    parsing_lv.Clear() 
    error_tb.Text <- "" 
 
 
apply_btn.Click.Add 
    (fun _ ->   clear() 
                try 
                    let tempLst =  base_gram_tb.Text.Split([|'\n'|]) 
                                     |> Array.map (fun str -> str.Trim()) 
                                     |> Array.filter(fun str -> str <> "") 
                                     |> List.ofArray  
               
                    let base_gram_lst = "0:Z = Program EOF" :: tempLst  
                    //非終端記号、終端記号の表示 
                    let (ntnSet,tnSet) = getNTN_TN__Sets  base_gram_lst 
                    Set.iter (fun ele -> ntn_lb.Items.Add(ele) |> ignore ) ntnSet 
                    Set.iter (fun ele -> term_lb.Items.Add(ele) |> ignore ) tnSet 
                    //構文規則の表示 
                    List.iter(fun str -> gram_lb.Items.Add(str) |> ignore ) base_gram_lst 
                    //nullableの表示 
                    let nullableMap = getNTN_NullableMap  base_gram_lst 
                    let nullableText =  
                         nullableMap 
                            |> Map.toList 
                            |> List.fold (fun state (str,bl) -> state + (sprintf "%s : %A \r\n" str bl )) "" 
                    nullable_tb.Text <- nullableText 
                    //First Setの表示 
                    let firstMap = getNTN_FirstMap base_gram_lst 
                    let firstSetText =  
                        firstMap 
                            |> Map.toList 
                            |> List.fold (fun state (str,set) -> state + (sprintf "%s : %A \r\n" str set)) "" 
                    firstSet_tb.Text <- firstSetText 
                    //Fellow Setの表示 
                    let followMap = getNTN_FollowMap base_gram_lst 
                    let followSetText =  
                        followMap 
                            |> Map.toList 
                            |> List.fold (fun state (str,set) -> state + (sprintf "%s : %A \r\n" str set)) "" 
                    followSet_tb.Text <- followSetText 
                    //Director Setの表示 
                    let directorMap = getNTN_DirectorMap base_gram_lst 
                    directorSet_lv.View <- View.Details 
                    directorSet_lv.GridLines <- true 
                    [new ColumnHeader(Text = "構文規則",Width = 600);(*表示文字構文規則で幅600の「列見出し」*)  
                     new ColumnHeader(Text = "Dirctror Set",Width = 271)] 
                        |> List.iter (fun col ->directorSet_lv.Columns.Add col |> ignore) 
                    base_gram_lst 
                        |>List.map (fun str -> (str,splitOneLineGram str)) 
                        |>List.map (fun (wholeStr,(index,_,_)) -> (wholeStr,(directorMap.[index]).ToString()))  
                        |>List.map (fun (wholeStr,dirctorSetStr) -> [| wholeStr;dirctorSetStr|]) 
                        |>List.map (fun arr -> new ListViewItem (arr)) 
                        |>List.iter (fun lvItem -> directorSet_lv.Items.Add(lvItem) |> ignore) 
                    //構文解析表の表示 
                    let parsingRelationMap = getParsingRelation base_gram_lst 
                    parsing_lv.View <- View.Details 
                    parsing_lv.GridLines <- true 
                    tnSet 
                        |> List.ofSeq 
                        |> List.map (fun tnStr -> new ColumnHeader(Text = tnStr,Width = 50)) 
                        |> List.append  [ new ColumnHeader(Text = "",Width = 250)] 
                        |> List.iter (fun col ->parsing_lv.Columns.Add col |> ignore) 
                    let parsingRealtionArrArr = 
                        [| for ntn in ntnSet do 
                              yield [| 
                                        yield ntn 
                                        for tn in tnSet do 
                                            let findRelation = Map.tryFind (ntn,tn) parsingRelationMap 
                                            match findRelation with 
                                            |Some(intSet) -> yield (List.ofSeq intSet).ToString() 
                                            |None         -> yield "" 
                                    |] 
                        |] 
 
                    parsingRealtionArrArr 
                      |> Array.map (fun (subArr:string[]) -> new ListViewItem(subArr)) 
                      |> Array.iter (fun lvItem -> parsing_lv.Items.Add(lvItem) |> ignore)  
 
 
                    //LL(1)解析の可能性表示 
                    for ntn in ntnSet do 
                        for tn in tnSet do 
                           let findRelation = Map.tryFind (ntn,tn) parsingRelationMap 
                           match findRelation with 
                           |Some(inSet) when Set.count inSet > 1  
                                -> error_tb.Text <- error_tb.Text + (sprintf "%s %s で衝突があります\n" ntn tn)  
                           |_ -> ()  
                     
 
                with 
                |MyGramExcp(str) -> error_tb.Text <- sprintf "構文規則の表記が不正です:%s" str   
                | ex -> error_tb.Text <- ex.Message  
    ) 
 
 
//Load  
load_btn.Click.Add  
    (fun _ -> try  
                let ofd = new OpenFileDialog(Filter = "GRA3ファイル(*.gra3)|*.gra3|すべてのファイル(*.*)|*.*")  
                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 = "GRA3ファイル(*.gra3)|*.gra3|すべてのファイル(*.*)|*.*",  
                                              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  
                  
    )  
 
[<STAThread()>]   
do Application.Run(mainForm)   
スポンサーサイト

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

コメントの投稿

非公開コメント

プロフィール

T GYOUTEN

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

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

この人とブロともになる

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