3.2 字句解析のプログラム (1)一般的構成

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文字取出し