Transcript PPT
コンパイラ
2011年10月20日
酒居敬一@A468([email protected])
http://www.info.kochi-tech.ac.jp/k1sakai/Lecture/COMP/2011/index.html
1
構文解析
字句の列を入力とする。
字句の列は字句解析器から出力される。
字句の列として表されたプログラムが、文法のどの部分
に対応するかを解析する。
今回の内容
2
構文解析の概論
下向き構文解析法の説明
下向き構文解析法の問題点と解決法
構文解析の役割
プログラミング言語の文法はBNFなどで記述される。
それに基づいてソースプログラムの字句が解析される。
字句の列から文法で許される並びであるかどうか調べる。
許されなれない並びであればエラーとする。
許される並びであれば、解析木を生成し構文木を出力する。
さらに変数や関数の名前は名前表に出力する。
字句要求
ソース
プログラム
字句解析
字句出力
3
構文解析
構文木
名前表
構文規則(生成規則)
この例では、乗算は加算よりも
先に行うことを示している。
演算順序を文法で規定している。
【式の構文規則】
1. 式 → 項|式+項
2. 項 → 因子|項*因子
3. 因子 → 名前|(式)
非終端記号
式・項・因子・名前
終端記号
a・b・c
→
4
左辺の非終端記号を右辺に
書き換え可能であることを示す。
【文法G1】
1. 式 →
2. 式 →
3. 項 →
4. 項 →
5. 因子 →
6. 因子 →
7. 名前 →
式+項
項
項*因子
因子
(式)
名前
a|b|c
構文図式
BNFと記述力は変わらない。
直感的でわかりやすい。
[プログラム]
;
変数宣言
関数定義
[関数定義]
[変数宣言]
[ブロック]
5
返戻型
識別子
(
変数宣言
,
要素型
{
識別子
文
}
)
ブロック
[文]
変数宣言
=
識別子
;
式
;
関数呼出し
if
while
(
条件式
)
文
(
条件式
)
文
ブロック
return
[関数呼出し]
[式]
[項]
識別子
(
式
)
,
項
項
加減演算子
因数
因数
6
;
式
乗除演算子
[条件式]
式
式
==
[加減演算子]
!=
>
>=
<
<=
[乗除演算子]
+
-
[返戻型]
*
/
[数字]と[英字]は非終端記号なので、
本来はそれらも終端記号に至るまでの
定義が必要。しかし、省略されている。
前回のBNFの例でも省略されている。
要素型
void
英字
[識別子]
英字
数字
[整数]
7
数字
[要素型]
int
式a*(b+c)の解析木と構文木
式
項
項
文法解析ではこれらの木を生成する。
因子
解析木では葉に終端記号で
末端以外が非終端記号
式
因子
名前
式
項
項
因子
因子
*
名前
a
名前
a
*
(
b
解析木
8
+
c
)
+
b
構文木
c
構文解析法
一般にはふた通りに分類可能。
上向き構文解析。
解析木を下から生成していく。
右辺と一致する入力列を左辺に置き換える。
下向き構文解析。
解析木を上から生成していく。
生成可能な解析木を仮定し、一致するかどうかで解析をすすめる。
【文法G1】
1. 式
→
2. 式
→
3. 項
→
4. 項
→
5. 因子 →
6. 因子 →
7. 名前 →
9
式+項
項
項*因子
因子
(式)
名前
a|b|c
上向き構文解析法
式
式
解析木の下のほう、
終端記号の非終端記号の
置き換えから始まる解析法。
右辺が一致し左辺に置き換えることを
還元という。
項
項
因子
因子
因子
因子
名前
名前
名前
a
10
項
+
記号列:
a+b*c
7を適用:
名前+名前*名前
6を適用:
因子+因子*因子
3,4を適用:
因子+項*因子
⇒
項+項*因子
1,2を適用:
式+項
⇒
式
b
⇒
*
c
項+項
下向き構文解析法
解析木を根のほうから生成する。
木の形を仮定して葉に至るかどうかを調べる。
葉に至るまで木が完成しなければ、読み込んだ字句は戻して
別の形を探っていく。別の形が尽きたらエラーになる。
仮定⇔後戻り、を繰り返す。
void S(){
aを読む;
A();
bを読む;
dを読む;
void A(){
aを読む;
B();
cを読む;
}
直接導出の例
/* Bを読む */
/* Aを読む */
S aAbd
A cb | c
}
void A(){
cを読む;
bを読む;
または
/* 解析が失敗して後戻りが発生したら */
cを読む;
}
11
acbdの解析手順例
解析手順
入力記号
文法の適用
解析結果
a c b d S→a A b d
1
c b d
A→c b|c
3
c b d
c b
d a A b d
○
×
5
c b d
A→c b|c
6
c b d
c
7
b d a A b d
○
○
最も左にある非終端記号から解析を始めている。
○
2
4
a c b d a A b d
最左導出という。
文法の展開に失敗したら後戻りがある。
12
下向き構文解析の問題点
再帰的なプログラムで実現できない文法がある。
左再帰性の問題という。
再帰呼び出しが無限ループする。
void 式(){
式();
+を読む;
項();
}
左辺の非終端記号に対し、右辺に複数の生成規則
があるときに、どれを仮定すべきか一意に決まらない。
バックトラック問題という。
13
前のページの3~6のところ。
左再帰性の除去
問題のある文法。
A A |
これを次のように書き換える。
A A
A A |
一般には次の形をとるときが問題で、
A A1 | A 2 | | A m | 1 | 2 | | n
このように書き換える。
A 1 A | 2 A | | n A
A 1 A | 2 A | | m A |
14
バックトラック
バックトラック法で解は求まるが、やはり速いほうがいい。
そこで、共通部分がある場合にくくりだす。
A cb | c
次のように書き換える。
A cA
A b |
void A(){
cを読む;
bを読む;
または
/* 解析が失敗してバックトラックが発生したら */
何も読まない;
}
15
S aAbd
A cb | c
を
解析手順
S aAbd
A cA
A b |
に置き換えて解析。
入力記号
文法の適用
解析結果
a c b d S→a A b d
1
16
a c b d a A b d
○
2
c b d
A → c A'
3
c b d
4
b d
5
b d
6
d
a A b d
7
b d
A' → b |ε
8
b d a A b d
c A'
○
A' → b |ε
b
○
×
○
A 1 | 2 | | m | 1 | 2 | | n
の形の場合、
A A | 1 | 2 | | n
A 1 | 2 | | m
という形に文法を変形する。
バックトラックがなくなるわけではない。