12.3,E,-15, 12.3,E5,+,=, >,<,…, 3.2 字句解析のプログラム (1)一般的構成 ソースプログラム 1文(テキスト 数値/文字列/ 名前/区切り記号 単純字句解析 12.3,E,-15, 12.3,E5,+,=, >,<,…, while, if,・・・,”abcdefg” 1文読込み (注釈部分の削除) 文構成単位の 字句解析 トークン ソース プログラム ファイル エディタ用 テキスト ボックス 12.3E-15, 12.3E5 ==,++,+=, >=, … , while, if,・・・, “abcdefg” 構文解析
(2)1文読込み(注釈部分の削除) VBに似た言語の1文読込み ①1行に1文が基本。 ②1行に複文のときコロン(:)で区切る ③複数行にまたがるときはアンダーライン(_)を最後に付ける。 ④注釈の先頭はシングルクォート(‘)
1文読込みの状態遷移 状態遷移図 通常 モード 文字列内部 引用符直後 エラー 終了 【演習】C言語の1文読み込みの状態遷移図を書け。 行終り 通常 モード 文字列内部 引用符(“) 引用符(“) 引用符直後 行終り エラー 引用符(“) 引用符以外の文字 継続指定“ _” 行終りまで無視(継続行用) 行終り以外 行終り 行終り以外 行終りまで無視(注釈用) 注釈指定“‘” 行終り 行終り “:”または行終り 終了 【演習】C言語の1文読み込みの状態遷移図を書け。 ①8進数はないものとする。 ②\n,\”等の記法が許されるものとする。
参考(1) 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 Alltext = Microsoft.VisualBasic.Right(Alltext, LN - 2) ElseIf CH2 = "//" Then Do While Alltext <> "" If CH2 = vbCrLf Then Exit Do End If Loop
参考(2) 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 Exit Do End If Alltext = Microsoft.VisualBasic.Right(Alltext, LN - 1) Loop scanComment = " " Else scanComment = CH1 If CH1 = """" Then ScanMode = 1 ElseIf CH1 = "\" Then ScanMode = 2 Case 1 参考(2)
参考(3) If CH1 = """" Then ScanMode = 0 ElseIf CH1 = "\" Then End If Case 2 scanComment = CH1 LN = Microsoft.VisualBasic.Len(Alltext) Alltext = Microsoft.VisualBasic.Right(Alltext, LN - 1) Case 3 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)単純字句解析 状態遷移図 エラー 終了 【演習】C言語を意識した単純字句解析の状態遷移図を書け。 半角・全角空白 またはタブコード 行終り 通常 モード 文字列 内部 引用符(“) 引用符(“) 引用符 直後 文終り エラー 区切記号 (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 Loop setString = Str & R
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 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 Alltext = R & Alltext : setNumber = Str Exit Function End If 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 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」等の表現 ②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); else if(token1.type=="Delimiter" && token1.str==”<" && } // 後半省略
(5)1文の形態による字句解析の構成の違い ①行が基本的な文の区切りを示す。 (複数行にわたるときは継続の指定を行う) FORTRAN, BASIC, COBOL SA 1文取出し LA1 1文バッファ LA0 ②ブロック内の最初と最後を示す記号 (begin-end,{})等があるもの。 ALGOL,PL/I, C, C++,JAVA, C# SA LA1 LA0 1文字取出し