Post on 02-Feb-2020
2012/04/23
言語処理系構成論(3)
岡山大学大学院自然科学研究科渡邊 誠也
1 2012/04/23
構文解析(syntax analysis)
2
2012/04/23
�#3
����������� Copyright (C) Nobuya WATANABE
コンパイラの構成(論理的構成)! フロントエンド(解析部)
! 字句解析 ! 構文解析! 意味解析! 中間コード生成
! バックエンド(合成部)! 最適化! コード生成
3
lexical
analysis
syntax
analysis
semantic
analysis
optimization
target code
generation
intermediate
code generation
source
program
object
program
frontend
backend
tables, etc.
(name,
symbol,
string, ...)
2012/04/23
�#3
����������� Copyright (C) Nobuya WATANABE
コンパイラの構成(論理的構成)! フロントエンド(解析部)
! 字句解析 ! 構文解析! 意味解析! 中間コード生成
! バックエンド(合成部)! 最適化! コード生成
3
lexical
analysis
syntax
analysis
semantic
analysis
optimization
target code
generation
intermediate
code generation
source
program
object
program
frontend
backend
tables, etc.
(name,
symbol,
string, ...)
2012/04/23
�#3
����������� Copyright (C) Nobuya WATANABE
構文解析(syntax analysis, parsing)! 字句解析が出力したトークンを読み込みながら,そのトークンの列がプログラミング言語の文法で許されているパターンと一致するかを解析! 許されているパターンであれば,トークンの列は構文規則にしたがって構成され,字句を葉とする解析木を生成
! 解析結果は,構文木と呼ばれる木構造として出力
4
lexical
analysis
source
program
syntax
analysis
request a token return a token
syntax tree
2012/04/23
�#3
����������� Copyright (C) Nobuya WATANABE
構文,制約,意味
! プログラミング言語は次の3つによって定義! プログラムの構成要素の構造を規定する構文(syntax)! 構文的に正しいプログラムを実行するために要求されるさまざまな制約(constraint)
! プログラムの構成要素がどのように実行されるかを定義する意味(semantics)
5
(例)C言語の if 文【構文】if (expr) stat1 else stat2
【制約】 expr は真偽値を表す型(算術式またはポインタ型)でなければならない【意味】まず expr を計算し,その値が真(0以外の値)であれば stat1 を実行.偽
であれば stat2 を実行.
2012/04/23
�#3
����������� Copyright (C) Nobuya WATANABE
構文,制約,意味
! プログラミング言語は次の3つによって定義! プログラムの構成要素の構造を規定する構文(syntax)! 構文的に正しいプログラムを実行するために要求されるさまざまな制約(constraint)
! プログラムの構成要素がどのように実行されるかを定義する意味(semantics)
! 構文と制約によって定義されるプログラミング言語全体の規定を文法(grammar)と呼ぶことが多い! 与えられたプログラムを実行するのに最低限必要な規定
! 構文解析について議論する際には,制約については言及しないのが普通,制約ぬきの文法(構文のみ)を単に「文法」と呼ぶことがある
6 2012/04/23
�#3
����������� Copyright (C) Nobuya WATANABE
内容! 構文解析を学習するのに必要な基礎知識
! プログラミング言語の形式的な記述! BNF, 拡張BNF
! 文法の基本的な概念や記法! 解析木とあいまい性! 演算子の優先順位と結合性! 文脈自由文法
! 構文解析法! 再帰的下向き構文解析! LR構文解析法(上向き構文解析法)
7
2012/04/23
�#3
����������� Copyright (C) Nobuya WATANABE
プログラミング言語の形式的な記述! プログラミング言語の文法の記述方法
! バッカス記法 BNF (Backus Naur Form, Backus Normal Form)! ALGOL60の文法記述のために開発された記法
! J. Backus, P. Naur: 正規言語を使って任意言語の構文を記述する方法(1959)
! 記述例〈program〉::= program〈identifier〉(〈identifier-list〉); 〈block〉. | program〈identifier〉;〈block〉.〈identifier-list〉::= 〈identifier〉| 〈identifier-list〉, 〈identifier〉
! 拡張BNF(Extended BNF)! 記述例
〈identifier-list〉::= {〈identifier〉, } 〈identifier〉
8
メタ記号(meta-symbol)
2012/04/23
�#3
����������� Copyright (C) Nobuya WATANABE
プログラミング言語の形式的な記述! プログラミング言語の文法の記述方法
! バッカス記法 BNF (Backus Naur Form, Backus Normal Form)! ALGOL60の文法記述のために開発された記法
! J. Backus, P. Naur: 正規言語を使って任意言語の構文を記述する方法(1959)
! 記述例〈program〉::= program〈identifier〉(〈identifier-list〉); 〈block〉. | program〈identifier〉;〈block〉.〈identifier-list〉::= 〈identifier〉| 〈identifier-list〉, 〈identifier〉
! 拡張BNF(Extended BNF)! 記述例
〈identifier-list〉::= {〈identifier〉, } 〈identifier〉
8
終端記号(terminal symbol)
2012/04/23
�#3
����������� Copyright (C) Nobuya WATANABE
プログラミング言語の形式的な記述! プログラミング言語の文法の記述方法
! バッカス記法 BNF (Backus Naur Form, Backus Normal Form)! ALGOL60の文法記述のために開発された記法
! J. Backus, P. Naur: 正規言語を使って任意言語の構文を記述する方法(1959)
! 記述例〈program〉::= program〈identifier〉(〈identifier-list〉); 〈block〉. | program〈identifier〉;〈block〉.〈identifier-list〉::= 〈identifier〉| 〈identifier-list〉, 〈identifier〉
! 拡張BNF(Extended BNF)! 記述例
〈identifier-list〉::= {〈identifier〉, } 〈identifier〉
8
非終端記号(nonterminal symbol)
2012/04/23
�#3
����������� Copyright (C) Nobuya WATANABE
プログラミング言語の形式的な記述! プログラミング言語の文法の記述方法
! バッカス記法 BNF (Backus Naur Form, Backus Normal Form)! ALGOL60の文法記述のために開発された記法
! J. Backus, P. Naur: 正規言語を使って任意言語の構文を記述する方法(1959)
! 記述例〈program〉::= program〈identifier〉(〈identifier-list〉); 〈block〉. | program〈identifier〉;〈block〉.〈identifier-list〉::= 〈identifier〉| 〈identifier-list〉, 〈identifier〉
! 拡張BNF(Extended BNF)! 記述例
〈identifier-list〉::= {〈identifier〉, } 〈identifier〉
8
0回以上の繰り返し
2012/04/23
�#3
����������� Copyright (C) Nobuya WATANABE
文法表記の例! ANSI C
! 識別子の並びidentifier-list: identifier identifier-list , identifier
! for文for ( expropt ; expropt ; expropt ) stat
! Java Language Specification
! Scheme
9 2012/04/23
�#3
����������� Copyright (C) Nobuya WATANABE
! 生成規則
! ε 規則
! 文法! 生成規則の集合! 出発記号
! 語彙(vocabulary)! 非終端記号! 終端記号
文法
10
A� �
A� �
PS
G = �P, S⇥
VN
VT
V = VN � VT
VN ⇥ VT = �
S � VN
記号列(空でもよい)
文法とは,生成規則の集合Pと,出発記号と呼ばれる記号Sとの組〈P, S〉
2012/04/23
�#3
����������� Copyright (C) Nobuya WATANABE
文法の例
11
P1 = {
}
E � T
T � FF � ( E )
T � T * F
E � E + T
F � i
VN = {E, T, F}
VT = {+, *, (, ), i}
V = VN � VT = {E, T, F, +, *, (, ), i}
! 文法! 生成規則集合
! 非終端記号
! 終端記号
! 語彙
左辺が同一の生成規則をまとめて,次のように表記することもあるP1 = {
}F � ( E )T � T * FE � E + T | T
| F| i
G1 = �P1, E⇥
四つ組で表記することもあるG = �VN , VT , P, S⇥
2012/04/23
�#3
����������� Copyright (C) Nobuya WATANABE
生成(produce)/ 還元(reduce)! 直接生成(directly produce)直接還元(directly reduce)
! 文法 に対して,記号列 と がそれぞれ , と書け,生成規則 が に含まれるとき, と表記し, は を直接生成するという
! は に直接還元されるという! 生成と還元
! 記号列 と に対して, となる記号列 が存在するとき, と表記
! または のとき, と表記し, は を生成するという.また, は に還元されるという
12
G = �VN , VT , P, S⇥ v wv = xAy w = x�y A� � P
v � w v w(u, w, x, y � (VN ⇥ VT )�)
w v
v w v ⇥ u1 ⇥ u2 · · ·⇥ un ⇥ wu1, u2, . . . , un(n � 1) v
+� w
v+� w v = w v
�� w v ww v
v に現れるいずれかの非終端記号Aを,Aを左辺とする生成規則A→αの右辺αで置き換えると,wが得られることを意味する
2012/04/23
�#3
����������� Copyright (C) Nobuya WATANABE
生成(produce)/ 還元(reduce)! 直接生成(directly produce)直接還元(directly reduce)
! 文法 に対して,記号列 と がそれぞれ , と書け,生成規則 が に含まれるとき, と表記し, は を直接生成するという
! は に直接還元されるという! 生成と還元
! 記号列 と に対して, となる記号列 が存在するとき, と表記
! または のとき, と表記し, は を生成するという.また, は に還元されるという
12
G = �VN , VT , P, S⇥ v wv = xAy w = x�y A� � P
v � w v w(u, w, x, y � (VN ⇥ VT )�)
w v
v w v ⇥ u1 ⇥ u2 · · ·⇥ un ⇥ wu1, u2, . . . , un(n � 1) v
+� w
v+� w v = w v
�� w v ww v
v に生成規則を1回以上適用すると,w が得られることを意味する
2012/04/23
�#3
����������� Copyright (C) Nobuya WATANABE
文形式,文,言語! 文形式(sentential form)
! 文法G= �P, S��に対して, のとき,x は G の文形式という
! 文(sentence)! x が終端記号だけからなるとき,x は G の文という
! 言語(language)! G の文全体の集合をL(G)と表記し,Gの定義する言語という
13
S�� x
E � E+T � T+T � T+T*F � F+T*F� F+T*i� F+F*i� F+i*i� i+i*i
G1の文形式【例】文法G1
2012/04/23
�#3
����������� Copyright (C) Nobuya WATANABE
文形式,文,言語! 文形式(sentential form)
! 文法G= �P, S��に対して, のとき,x は G の文形式という
! 文(sentence)! x が終端記号だけからなるとき,x は G の文という
! 言語(language)! G の文全体の集合をL(G)と表記し,Gの定義する言語という
13
S�� x
E � E+T � T+T � T+T*F � F+T*F� F+T*i� F+F*i� F+i*i� i+i*i G1の文
【例】文法G1
※無限に多くの文が存在
2012/04/23
�#3
����������� Copyright (C) Nobuya WATANABE
導出(derive)! 導出
! ある記号列 v に生成規則を何回か適用して, である記号列 w を求めることを,v から w を導出するという
! 最左導出(left-most derivation)! 記号列の中の最も左に位置する非終端記号に生成規則を適用する導出
! 最右導出(right-most derivation)! 記号列の中の最も右に位置する非終端記号に生成規則を適用する導出
14
v�� w
v �lm
w
v �rm
w v��
rmw
v��lm
w
2012/04/23
�#3
����������� Copyright (C) Nobuya WATANABE
解析木(parse tree)! 解析木
! 文法 G=〈P, S〉の文が,その出発記号 S から導出される様子を木構造で表現したもの
15
E
E
T
T
F
F
i i
i
+
*T
F
節(node)... Gの記号
P1 = {
}
E � T
T � FF � ( E )
T � T * F
E � E + T
F � i
文法G1における の解析木i+i*i
2012/04/23
�#3
����������� Copyright (C) Nobuya WATANABE
解析木(parse tree)! 解析木
! 文法 G=〈P, S〉の文が,その出発記号 S から導出される様子を木構造で表現したもの
15
E
E
T
T
F
F
i i
i
+
*T
F
節(node)... Gの記号
節Aからn個の節a1,a2,...anへ枝(edge)が延びる生成規則A→a1 ... anが存在する場合のみ
P1 = {
}
E � T
T � FF � ( E )
T � T * F
E � E + T
F � i
文法G1における の解析木i+i*i
2012/04/23
�#3
����������� Copyright (C) Nobuya WATANABE
あいまい性! あいまいな文(ambiguous sentence)
! 文法Gの文xに対して,xを導出する2つの異なる解析木が考えられるとき,x はあいまいな文であるという
! あいまいな文法! あいまいな文をもつ文法
【例】G2 = �P2, E�
文 に対して2つの異なる解析木が存在したがって,文 はあいまいな文.文法G2はあいまいな文法
16
P2 = { E � E+E | E*E | (E) | i }i+i*i
i+i*i
E
E
i
i i
+
*
E
E E
E
E
i
i i
+
* E
E E
2012/04/23
�#3
����������� Copyright (C) Nobuya WATANABE
あいまいな文法の例: C言語の if 文! C言語の文(statement)の文法
stat: if ( expr ) stat if ( expr ) stat else stat other
! あいまいな文の例! if (e1) if (e2) s1 else s2
! if (e1) { if (e2) s1 else s2}
! if (e1) { if (e2) s1 } else s2
17
if ( )
else
stat
statexpr
e1 if ( ) statexpr stat
e2 s1 s2
if ( ) else
stat
statexpr
e1 if ( ) statexpr
stat
e2 s1
s2
2012/04/23
�#3
����������� Copyright (C) Nobuya WATANABE
演算子の優先順位(precedence)と結合性(associativity)
! 演算子の優先順位! 算術式の中に2つの異なる演算子が連続して現れたとき,そのどちらを先に計算するかを決定する順番
! 例! 掛け算の演算子 * は足し算の演算子 + より優先順位が高い! x + y * z → x +(y * z)
! 結合性! 算術式の中に2つの同じ演算子が連続して現れたとき,そのどちらを先に計算するかを決定する順番
! 例! x - y - z → (x - y)- z! x + y + z → (x + y)+ z
18
演算子 - や + は,左結合的(left associative)であるという
2012/04/23
�#3
����������� Copyright (C) Nobuya WATANABE
演算子の優先順位,結合性の表記方法! 表記
! ある演算子op1とop2に対して,op1に続いてop2が現れたとき,! op1を先に計算する場合! op2を先に計算する場合
! 例
19
op1 <· op2
op1 >· op2
+ <· * = <· =- >· - + >· + + >· -
優先順位 左結合的 右結合的 優先順位: =左結合的
2012/04/23
�#3
����������� Copyright (C) Nobuya WATANABE
文法と演算子の優先順位・結合性! プログラミング言語の文法の定義
! 演算子の優先順位と結合性を生成規則の中に埋め込む方法! 埋め込まないで別途指定する方法
20
E
E
T
T
F
F
i i
i
+
*T
F
i + i * i の解析木
P1 = {
}F � ( E )T � T * FE � E + T | T
| F| i
文法 G1 = �P1, E⇥
+ <· *
2012/04/23
�#3
����������� Copyright (C) Nobuya WATANABE
! の条件1. の形の生成規則が存在し,かつ
2.ある非終端記号Cに対して
! の条件1. の形の生成規則が存在し,かつ
2.ある非終端記号Cに対して
文法と演算子の優先順位・結合性
21
op1 <· op2
A⇥ · · · op1B · · ·
B+⇥ C op2 · · ·
op1 >· op2
B+⇥ · · · op1 C
A
Bop1
op2C
op1 <· op2
A
B op2
op1 C
op1 >· op2A� · · · Bop2 · · ·
2012/04/23
�#3
����������� Copyright (C) Nobuya WATANABE
文脈自由文法(context-free grammar)! 文脈に拘束されずに生成規則を適用できる文法! ある非終端記号Aが文形式に現れていれば,Aの前後の記号に関係なく,Aを左辺とする生成規則を適用可能
! 通常のプログラミング言語は文脈自由文法によって定義
! 文脈依存文法(context sensitive grammar)! 文脈に拘束
22 2012/04/23
構文解析法
23
2012/04/23
�#3
����������� Copyright (C) Nobuya WATANABE
! プログラミング言語の構文解析! 様々な方法が考案! おおまかな分類
! 上向き構文解析法(bottom-up parsing)! 生成規則の右辺と一致 → 左辺の記号に置換 ... 還元(reduction)
! 入力記号列を葉(終端記号)として,葉(終端記号)から根(非終端記号)へ向かって解析を進めながら解析木を生成
! 下向き構文解析法(top-down parsing)! 記号列として次に何がくるかを仮定しながら解析を進めていく解析法
! 解析木を上(根)から下(葉)へ向かって解析
構文解析法
24
E
E
T
T
F
F
i i
i
+
*T
F
i + i * i の解析木
P1 = {
}F � ( E )T � T * FE � E + T | T
| F| i
2012/04/23
�#3
����������� Copyright (C) Nobuya WATANABE
さまざまな構文解析法! 再帰的下向き構文解析法(recursive descent parsing)
! LL(k)構文解析(Left-to-right scanning, Left-most derivation)
! LR構文解析法(LR parsing)! Left-to-right scanning, Right-most derivation in reverse
! SLR(1)構文解析法(Simple LR parsing)! LR(1)構文解析法! LALR(1)構文解析法(Lookahead LR parsing)
25
2012/04/23
�#3
����������� Copyright (C) Nobuya WATANABE
構文木(syntax tree)とその表現! 構文木
! 構文解析の結果として生成されるプログラムの内部表現! 例: a = b * c + (d - e)
26
! 構文木の表現! N組(N-tuple)と呼ばれる構造体を使用して表現
=
a
cb
-*
+
d e
=
+
* -
a
b c d e
N組...N個のメンバを持つ構造体
2012/04/23
�#3
����������� Copyright (C) Nobuya WATANABE
構文木とその表現(続き)! C言語でのN組の実現例
! tuple: N組へのポインタ型! token: トークンへのポインタ型
27
x1 = make_tuple(“*”, b, c);x2 = make_tuple(“-”, d, e);x3 = make_tuple(“+”, x1, x2);x4 = make_tuple(“=”, a, x3);
N組の生成例
int is_a(x)トークンの種別判
=
+
* -
a
b c d etuple make_tuple(A, a1, ..., an)
N組を生成する関数
節の値 枝
トークン x が終端記号 a に対応するかを判定【例】is_if ... キーワード if か?
2012/04/23
再帰的下向き構文解析
28 2012/04/23
�#3
����������� Copyright (C) Nobuya WATANABE
再帰的下向き構文解析法(recursive descent parsing)
! 非終端記号ごとに,解析関数(parsing function)を作成! 関数本体では,非終端記号を左辺とする生成規則を忠実に反映したコードを与える! 文法と構文解析プログラムの対応が明確! 文法を変更した場合にも,プログラムの修正が容易
29
2012/04/23
�#3
����������� Copyright (C) Nobuya WATANABE
解析関数! 生成規則
30
A� aAb | c
a1 a2 c1 b1 b2 $
p
Aに還元できるトークン列とは,■cのトークンが1つだけ,あるいは,■aのトークンで始まり,Aに還元できるトークン列が続き,bのトークンで終わる一連のトークン列
tuple parse_A() { token *prev = p, x, z; tuple y; if (is_a(x = *p++) && (y = parse_A()) && is_b(z = *p++)) return make_tuple(“A”, x, y, z); p = prev; if (is_c(x = *p++)) return x; p = prev; return NULL;}
トークンのベクタ
tuple parse() { tuple x = parse_A(); if (x && is_eof(*p)) return x; else syntax_error();}
入力トークン列全体を解析する関数2012/04/23
�#3
����������� Copyright (C) Nobuya WATANABE
左再帰(left recursion)! 文法が左再帰を含む→解析関数の再帰呼出が停止しない! 例: 直接の左再帰(immediate left recursion)
!
31
E � E + T | Ttuple parse_E() { token *prev = p; tuple x, y; if ((x = parse_E()) && is_plus(*p++) && (y = parse_T())) return make_tuple(“+”, x, y); p = prev; if (x = parse_T()) return x; p = prev; return NULL;}
! 間接的な左再帰も同様A� Ba | c
B � Ab | d
2012/04/23
�#3
����������� Copyright (C) Nobuya WATANABE
C言語における左再帰! 識別子のリスト
! 単純に右再帰に置き換えられない例
32
identifier-list:identifieridentifier-list , identifier
identifier-list:identifieridentifier , identifier-list
additive-expression:multiplicative-expressionadditive-expression + multiplicative-expressionadditive-expression - multiplicative-expression
右再帰に置き換え可能
左結合的が右結合的になってしまう
a - b + c = (a - b) + c ≠ a - (b + c) = a - b - c
C言語の文法に間接的な左再帰はない
2012/04/23
�#3
����������� Copyright (C) Nobuya WATANABE
同じ終端記号列を生成するような左再帰のない生成規則
左再帰の除去(left recursion elimination)! 直接の左再帰の除去
33
A� Aa | b
A⇥lm
Aa⇥lm
Aaa⇥lm
Aaaa⇥lm
· · ·⇥lm
Aan ⇥lm
ban
A� bA�
A� � aA� | �
A⇥rm
bA� ⇥rm
baA� ⇥rm
baaA� ⇥rm
· · ·⇥rm
banA� ⇥rm
ban
2012/04/23
�#3
����������� Copyright (C) Nobuya WATANABE
同じ終端記号列を生成するような左再帰のない生成規則
左再帰の除去(left recursion elimination)! 直接の左再帰の除去
33
A� Aa | b
A⇥lm
Aa⇥lm
Aaa⇥lm
Aaaa⇥lm
· · ·⇥lm
Aan ⇥lm
ban
A� bA�
A� � aA� | �
A⇥rm
bA� ⇥rm
baA� ⇥rm
baaA� ⇥rm
· · ·⇥rm
banA� ⇥rm
ban
tuple parse_A() { token *prev = p; if (is_b(y = *p++)) return parse_A1(y); p = prev; return NULL;}tuple parse_A1(tuple x) { token *prev = p, y; if (is_a(y = *p++)) return parse_A1(make_tuple(“A”, x, y)); p = prev; return x;}
入力トークンのポインタが進んでいる.まったく同じ状態で再帰呼出しされるわけでないので無限呼出にはならない
2012/04/23
�#3
����������� Copyright (C) Nobuya WATANABE
左再帰の除去! 直接の左再帰を含む生成規則の一般形
34
A⇥ A�1 | · · · | A�n | ⇥1 | · · · | ⇥m
A⇥ ⇥1A� | · · · | ⇥mA�
A� ⇥ �1A� | · · · | �nA� | ⇤
�i � V � �i A �i � V +ここで , は で始まらない.次で置き換えることで除去可能
【例】E � E + T | TT � T * F | FF � (E) | i
E � TE�
E� � + TE� | �T � FT �
T � � * FT � | �F � (E) | i
2012/04/23
�#3
����������� Copyright (C) Nobuya WATANABE
バックトラック! いくつかの選択肢が考えられるときに,そのうちの1つを試してみて失敗だったと判断した時点でもとの(その選択肢を選ぶ直前)の状態に戻す処理
35
A� aBcB � b | bd
【例】 tuple parse_A() { token *prev = p, x, z; tuple y; if (is_a(x = *p++) && (y = parse_B()) && is_c(z = *p++)) return make_tuple(“A”, x, y, z); p = prev; return NULL;}tuple parse_B() { token *prev = p, x, y; if (is_b(x = *p++)) return x; p = prev; if (is_b(x = *p++) && is_d(y = *p++)) return make_tuple(“B”, x, y); p = prev; return NULL;}
正しく動作しない(例: abdc)
parse_Aが再度parse_B
を呼出して,もう1つの生成規則を試みるよう指示する必要がある一般的には複雑な機構が必要
2012/04/23
�#3
����������� Copyright (C) Nobuya WATANABE
くくり出しによるバックトラックの回避! くくり出し(factoring)でバックトラックを回避可能
36
B � b | bd
B � b (d | �)
tuple parse_B() { token *prev = p, x, y; if (is_b(x = *p++)) { token *prev1 = p, y; if (is_d(y = *p++)) return make_tuple(“B”, x, y); p = prev1; return x; } p = prev; return NULL;}
のくくり出しb
A⇥ aBcB ⇥ C | DC ⇥ · · ·D ⇥ · · ·
! 生成規則が終端記号で始まらない場合は適用が困難
バックトラックのもう1つの大きな問題:
適切なエラーメッセージ出力が難しい
2012/04/23
�#3
����������� Copyright (C) Nobuya WATANABE
LL(k)構文解析法! バックトラックをしない再帰的下向き構文解析法! k個の入力トークンを先読みし,どの生成規則を適用するかを決定する方法
37
B � C | D! の解析関数で,次の入力トークン x を先読みし,1.もし なら parse_Cを呼び出す2.もし なら parse_Dを呼び出す3.どちらでもなければ,構文エラー
C+⇥ x · · ·
D+⇥ x · · ·
2012/04/23
�#3
����������� Copyright (C) Nobuya WATANABE
LL(1)文法 ー first集合とfollow集合 ー
! のfirst集合 ... から生成される記号列の先頭に現れる終端記号の全体
! A のfollow集合 ... Aの直後に現れる可能性のある終端記号の全体
! なら,! 常に,
38
! 文法 とその記号列G = �VN , VT , P, S⇥ � � (VN ⇥ VT )�
� �
First(�) = {a | a ⇤ VT , ��⇥ a · · · }
Follow(A) = {a | a ⇤ VT , S$ �⇥ · · ·Aa · · · }
$ � Follow(A) S�⇥ · · · A
$ � Follow(S)
�
a
a
A
S
2012/04/23
�#3
����������� Copyright (C) Nobuya WATANABE
LL(1)文法 ー director集合 ー! のdirector集合 ... 次にこの生成規則を使った場合に,入力トークン列の先頭に現れる可能性のある終端記号の全体
39
A� �
Director(A,�) =
�First(�) (unless �
�� ⇥)First(�) ⇥ Follow(A) (if �
�� ⇥)LL(1)文法
a
A
S
�
a
A
�
$
右辺だけが異なる任意の生成規則 と に対して,必ず
が成り立つ文法
A� � A� �Direcotr(A,�) ⇥Direcotr(A,⇥) = �
入力トークン列の先頭記号を見れば,次にどの生成規則を使用すべきか決定可能
2012/04/23
�#3
����������� Copyright (C) Nobuya WATANABE
Director集合の例! 文法
40
First(T �) = {*}First(E�) = {+}Follow(E) = Follow(E�) = {$, )}Follow(T ) = Follow(T �) = {+, $, )}Follow(F ) = First(T �) � Follow(T �) = {*, +, $, )}
First(E) = First(T ) = First(F ) = {(, i}
Director(E�, +TE�) ⇥Director(E�, �) = �Director(T �, *FT �) ⇥Director(T �, �) = �Director(F, (E)) ⇥Director(F, i) = �
E � TE�
E� � + TE� | �T � FT �
T � � * FT � | �F � (E) | i
LL(1)文法
Director(E�, +TE�) = {+}
Director(T �, *FT �) = {*}
Director(F, (E)) = {(}Director(F, i) = {i}
Director(E�, �) = First(�) � Follow(E�) = {$, )}
Director(T �, �) = First(�) � Follow(T �) = {+, $, )}
Director(E, TE�) = First(T ) = {(, i}
Director(T, FT �) = First(F ) = {(, i}
2012/04/23
�#3
����������� Copyright (C) Nobuya WATANABE
tuple parse_E() { if (is_lpar(*P) || is_i(*p)) { tuple x = parse_T(); return parse_E1(x); } else syntax_error();}tuple parse_E1(tuple x) { if (is_plus(*p)) { tuple y; p++; y = parse_T(); return parse_E1(make_tuple(“+”, x, y)); } else syntax_error();}
LL(1)構文解析法! Left-to-right scanning, Left-most derivation
! 入力トークン列を左から右へ読み込む(バックトラックがない)! 最左導出の順序で構文解析を行う
41
バックトラックがなくなったので1. 適切な時点で構文エラーを検出できる
2. pの値を保存しておく必要がない
非終端記号Aの解析関数入力トークンを調べ,Aを左辺とする生成規則のうちで,director集合にそのトークンを含むものを選択し(なければ構文エラー)構文解析を進める.
Director(E, TE�) = First(T ) = {(, i}
Director(E�, +TE�) = {+}
E � TE�
E� � + TE� | �T � FT �
T � � * FT � | �F � (E) | i
2012/04/23
�#3
����������� Copyright (C) Nobuya WATANABE
LL(1)構文解析法(続き)! 再帰的下向き構文解析法の一種
! 文法が左再帰を含む場合,左再帰を除去した文法を使用! 左辺が同じで,右辺が同じ記号で始まる生成規則が複数存在する場合! director集合には共通の終端記号が含まれる(LL(1)でない)! くくり出しが必要
42
! 変換後の文法は,もとの文法より読みづらくなるのが普通! 結果的に複雑な構文解析プログラムとなってしまうことも
生成規則に左再帰がなければ,直感的に理解しやすい構文解析プログラムを作成可能
もとの文法をそのまま使用する構文解析法 → LR構文解析法
文法を変更(変換)した場合,
2012/04/23
�#3
����������� Copyright (C) Nobuya WATANABE
まとめ! 構文解析に必要な基礎知識について説明
! プログラミングの形式的な表現方法! BNF! 拡張BNF
! 文法の基本的な概念や記法! 生成規則,生成,還元,文形式,文,言語! 導出,最左導出,最右導出
! 解析木とあいまい性! 演算子の優先順位と結合性
! 構文解析法! 再帰的下向き構文解析! LR構文解析法(上向き構文解析法) ... 次回
43