3.2 字句解析のプログラム (1)一般的構成 ソースプログラム 1文(テキスト 1文読込み (注釈部分の削 除) ソース プログラム ファイル エディタ用 テキスト ボックス 単純字句解析 12.3,E,-15, 12.3,E5,+, =, >,<,…, while, if,・・・,”abcdefg” 数値/文字列/ 名前/区切り記号 文構成単位の 字句解析 トークン 12.3E-15, 12.3E5 ==,++,+=, >=, … , while, if,・・・, “abcdefg” 構文解析 (2)1文読込み(注釈部分の削除) VBに似た言語の1文読込み ①1行に1文が基本。 ②1行に複文のときコロン(:)で区切る ③複数行にまたがるときはアンダーライン(_)を最後に付ける。 ④注釈の先頭はシングルクォート(‘) 1文読込みの状態遷移 状態遷移図 行終り 通常 モード 引用符(“) 文字列 内部 引用符(“) 引用符 直後 行終り エラー 引用符(“) 引用符以外の文字 継続指定“ _” 行終りまで無視 (継続行用) 行終り 行終り以外 行終り以外 注釈指定“‘” 行終り 行終りまで無視 (注釈用) 行終り “:”または行終り 【演習】C言語の1文読み込みの状態遷移図を書け。 ①8進数はないものとする。 ②\n,\”等の記法が許されるものとする。 終了 Private Alltext As String Private ScanMode As Short Private Function scanComment() As String Dim CH1, CH2 As String: Dim LN As Integer CH1 = Microsoft.VisualBasic.Left(Alltext, 1) Select Case ScanMode Case 0 CH2 = Microsoft.VisualBasic.Left(Alltext, 2) If CH1 = " " Or CH1 = " " Or CH1 = vbTab Then LN = Microsoft.VisualBasic.Len(Alltext) Alltext = Microsoft.VisualBasic.Right(Alltext, LN - 1) scanComment = " " ElseIf CH2 = vbCrLf Then LN = Microsoft.VisualBasic.Len(Alltext) Alltext = Microsoft.VisualBasic.Right(Alltext, LN - 2) scanComment = " " ElseIf CH2 = "//" Then LN = Microsoft.VisualBasic.Len(Alltext) Alltext = Microsoft.VisualBasic.Right(Alltext, LN - 2) Do While Alltext <> "" CH2 = Microsoft.VisualBasic.Left(Alltext, 2) If CH2 = vbCrLf Then LN = Microsoft.VisualBasic.Len(Alltext) Alltext = Microsoft.VisualBasic.Right(Alltext, LN - 2) Exit Do End If LN = Microsoft.VisualBasic.Len(Alltext) Alltext = Microsoft.VisualBasic.Right(Alltext, LN - 1) Loop scanComment = " " 参考(1) ElseIf CH2 = "/*" Then LN = Microsoft.VisualBasic.Len(Alltext) Alltext = Microsoft.VisualBasic.Right(Alltext, LN - 2) Do While Alltext <> "" CH2 = Microsoft.VisualBasic.Left(Alltext, 2) If CH2 = "*/" Then LN = Microsoft.VisualBasic.Len(Alltext) Alltext = Microsoft.VisualBasic.Right(Alltext, LN - 2) Exit Do End If LN = Microsoft.VisualBasic.Len(Alltext) Alltext = Microsoft.VisualBasic.Right(Alltext, LN - 1) Loop scanComment = " " Else scanComment = CH1 LN = Microsoft.VisualBasic.Len(Alltext) Alltext = Microsoft.VisualBasic.Right(Alltext, LN - 1) If CH1 = """" Then ScanMode = 1 ElseIf CH1 = "\" Then ScanMode = 2 End If End If Case 1 scanComment = CH1 LN = Microsoft.VisualBasic.Len(Alltext) Alltext = Microsoft.VisualBasic.Right(Alltext, LN - 1) 参考(2) If CH1 = """" Then ScanMode = 0 ElseIf CH1 = "\" Then ScanMode = 3 End If Case 2 scanComment = CH1 LN = Microsoft.VisualBasic.Len(Alltext) Alltext = Microsoft.VisualBasic.Right(Alltext, LN - 1) ScanMode = 0 Case 3 scanComment = CH1 LN = Microsoft.VisualBasic.Len(Alltext) Alltext = Microsoft.VisualBasic.Right(Alltext, LN - 1) ScanMode = 1 End Select End Function Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click Dim R, Str As String Alltext = TextBox1.Text Str = "" : ScanMode = 0 Do While Alltext <> "" R = scanComment() TextBox2.Text = TextBox2.Text & R MsgBox(Alltext & vbCrLf & "→[" & R & "] Scan Mode=" & ScanMode) Loop End Sub End Class 参考(3) 状態遷移図 (3)単純字句解析 半角・全角空白 またはタブコード 通常 モード 区切記号 行終り 引用符(“) 文字列 引用符(“) 引用符 内部 文終り 直後 (1文字) エラー 引用符(“) 引用符以外の文字 文終り 数字 小数点、数字以外 数字 数字 モード 小数点 小数点 小数部 モード 数字 数字以外 英字 英数字以外 終了 英数字 識別子 モード 小数部モードの結果、 得られた文字列が“.”だけの場合、 “.”を区切り記号としてみなす。 【演習】C言語を意識した単純字句解析の状態遷移図を書け。 引用符で囲まれたキャラクタ, 二重引用符で囲まれた文字列, \n, \”等の記法を意識すること。 Cの単純字句解析参考(その1) Private Function setWordData(ByVal tp As String, ByVal st As String) As WordData setWordData.Type = tp setWordData.Str = st End Function Private Function setString() Dim Str, R As String Str = """" : R = scanComment() Do While R <> """" If R = "\" Then Str = Str & R : R = scanComment() If R = "" Then MsgBox("文法エラー。二重引用符が不足しています。") R = """" Exit Do End If End If Str = Str & R : R = scanComment() Loop setString = Str & R End Function Cの単純字句解析参考(その2) Private Function setChar() Dim Str, R As String Str = "'" : R = scanComment() Do While R <> "'" If R = "\" Then Str = Str & R : R = scanComment() If R = "" Then MsgBox("文法エラー。二重引用符が不足しています。") R = "'" Exit Do End If End If Str = Str & R : R = scanComment() Loop setChar = Str & R End Function Cの単純字句解析参考(その3) Private Function setNumber(ByVal RR As String) Dim Str, R As String : R = RR If R <> "." Then Str = RR : R = scanComment() Do While Asc(R) >= Asc("0") And Asc(R) <= Asc("9") Str = Str & R : R = scanComment() Loop If R <> "." Then Alltext = R & Alltext : setNumber = Str Exit Function End If End If Str = Str & R : R = scanComment() Do While Asc(R) >= Asc("0") And Asc(R) <= Asc("9") Str = Str & R : R = scanComment() Loop Alltext = R & Alltext setNumber = Str End Function Cの単純字句解析参考(その4) Private Function setName(ByVal RR As String) Dim Str, R As String R = RR : Str = RR : R = scanComment() Do While (Asc(R) >= Asc("A") And Asc(R) <= Asc("Z")) Or _ (Asc(R) >= Asc("a") And Asc(R) <= Asc("z")) Or _ (Asc(R) >= Asc("0") And Asc(R) <= Asc("9")) Or R = "_" Str = Str & R R = scanComment() Loop Alltext = R & Alltext setName = Str End Function Cの単純字句解析参考(その4) Private Function LA0() As WordData Dim R, Str As String: Str = "" : ScanMode = 0: R = scanComment() Do While Alltext <> "" And (R = " " Or R = "") R = scanComment() Loop If (R = " " Or R = "") And Alltext = "" Then LA0.Type = "EOF”: LA0.Str = "" ElseIf R = """" Then LA0.Type = "String”: LA0.Str = setString() ElseIf R = "'" Then LA0.Type = "Char”: LA0.Str = setChar() ElseIf R = "\" Then LA0.Type = "Code”: LA0.Str = R & scanComment() ElseIf R = "." Then LA0.Type = "Number”: LA0.Str = setNumber(R) If LA0.Str = "." Then LA0.Type = "Delimiter" ElseIf Asc(R) >= Asc("0") And Asc(R) <= Asc("9") Then LA0.Type = "Number”: LA0.Str = setNumber(R) ElseIf (Asc(R) >= Asc("A") And Asc(R) <= Asc("Z")) Or _ (Asc(R) >= Asc("a") And Asc(R) <= Asc("z")) Or R = "_" Then LA0.Type = "Name”: LA0.Str = setName(R) Else LA0.Type = "Delimiter”: LA0.Str = R End If End Function Cの単純字句解析参考(その5) Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click Dim S As WordData Alltext = TextBox1.Text TextBox2.Text = "" Do While Alltext <> "" S = LA0() TextBox2.Text = TextBox2.Text & vbCrLf & S.Type & " Value=""" & S.Str & """" Loop End Sub End Class (4)文構成単位としての字句解析 ①浮動小数点等としての「123.5E-23」、「34.E5」等の表現 数値「123.5」、 名前「E」、区切り記号「-」、数値 「23」 数値「34.」、 名前「E5」 ②16進数「0X0FEC」等の表現 数値「0」、 名前「X0FEC」 ③8進数「0276」(先頭が0で始まる) ④複数文字列からなる演算子(==, ++, ||など) ⑤2単語以上からなるがひとつの意味になるもの(BASICに多 い) select case, end if, do while, loop until, … 先読みしてこれらを判定する C#プログラム例(その1) private bool E_exp(string str) // E<数字列>のチェック { if(str.Length<2) return false; if(str[0]!='E' && str[0]!='e') return false; for(int i=1;i<str.Length;i++) if(該当文字(数字,str[i])<0) return false; return true; } private void set_TokenX(string type, string str) // トークンのセット { tokenX[numTokenX].type=type; tokenX[numTokenX].str=str; numTokenX++; } private void combineDelimiter(string str1, string str2) // 区切り記号の接続 { set_TokenX("Delimiter",str1+str2); } C#プログラム例(その2) private void LA1() { numTokenX=0; WordData token1,token2,token3,token4; token1=LA0();token2=LA0();token3=LA0();token4=LA0(); // 先読み while(token1.type!="End") { if( token1.type=="Number" && token2.type=="Name" && token2.str=="E" && token3.type=="Delimiter" && (token3.str=="+" || token3.str=="-")&& token4.type=="Number") { set_TokenX("Number",token1.str+token2.str+token3.str+token4.str); token1=LA0();token2=LA0();token3=LA0();token4=LA0(); } else if( token1.type=="Number" && token2.type=="Name" && E_exp(token2.str)) { set_TokenX("Number",token1.str+token2.str); token1=token3;token2=token4;token3=LA0();token4=LA0(); } else if(token1.type=="Delimiter" && token1.str==">" && token2.type=="Delimiter" && token2.str=="=" ) { combineDelimiter(token1.str,token2.str); token1=token3;token2=token4;token3=LA0();token4=LA0(); } else if(token1.type=="Delimiter" && token1.str==”<" && token2.type=="Delimiter" && token2.str=="=" ) { combineDelimiter(token1.str,token2.str); token1=token3;token2=token4;token3=LA0();token4=LA0(); } // 後半省略 (5)1文の形態による字句解析の構成の違い ①行が基本的な文の区切りを示す。 (複数行にわたるときは継続の指定を行う) FORTRAN, BASIC, COBOL ②ブロック内の最初と最後を示す記号 (begin-end,{})等があるもの。 ALGOL,PL/I, C, C++,JAVA, C# SA 1文取出し LA1 1文バッファ LA0 SA LA1 LA0 1文字取出し
© Copyright 2024 ExpyDoc