2. Compiler Lecture Note, LL Parsing Page 2
I. 결정적 구문 분석
II. Recursive-descent 파서
III. Predictive 파서
VI. Predictive 파싱 테이블의 구성
V. Strong LL(k) 문법과 LL(k) 문법
목 차
3. Compiler Lecture Note, LL Parsing Page 3
I. 결정적 구문 분석
▶ Deterministic Top-Down Parsing
::= deterministic selection of production rules to be applied
in top-down syntax analysis.
▶ One pass nobackup
1. Input string is scanned once from left to right.
2. Parsing process is deterministic.
▶ Top-down parsing with nobackup
::= deterministic top-down parsing.
called LL parsing.
"Left to right scanning and Left parse"
4. Compiler Lecture Note, LL Parsing Page 4
▶ LL parsing
- backtracking이 없이 deterministic한 top-down parsing
⇒ 문법이 LL 조건 만족해야
- LL이란? Left-to-right scanning & Leftmost derivation
- 현재의 input symbol을 보고 적용될 생성규칙을 deterministic하게
선택
▶ How to decide which production is to be applied:
sentential form : 1 2 … i-1Xα
input string : 1 2 … i-1 i i+1 … n
X 1 | 2 ... | k ∈ P일 때,
i를 보고 X-production 중에 unique하게 결정.
the condition for no backtracking : FIRST와 FOLLOW가 필요.
(= LL condition)
5. FIRST
• 문법 G = (VN, VT, P, S)가 context-free 문법이고 A∈VN, a∈VT일 때, non-
terminal A에 대한 FIRST는 다음과 같이 정의
FIRST(A) = {a∈VT∪{} | A⇒a, ∈V*}.
non-terminal A로부터 유도되어 첫번째로 나타날 수 있는 terminal의 집합
– 예 : 다음 생성 규칙에서 각 non-terminal에 대한 FIRST
A → aB | B
B → bC | C
C → c
Compiler Lecture Note, LL Parsing Page 5
X
FIRST(X)
1. A ⇒ aB
A ⇒ B ⇒ bC
A ⇒ B ⇒ C ⇒ c
∴ FIRST(A) = {a, b, c}.
2. B ⇒ bC
B ⇒ C ⇒ c
∴ FIRST(B) = {b, c}.
3. C ⇒ c
∴ FIRST(C) = {c}.
6. • Non-terminal A가 을 유도할 수 있으면 A를 nullable하다고 부른다.
– A⇒ 이면 nullable하다.
• 두 개의 집합에 대한 연산자인 ring sum은 다음과 같이 정의 되면
기호 를 사용한다.
1. if A then A B = A
2. if A then A B = (A – {})∪B.
– Ring sum의 의미
• 첫 번째 피 연산자의 집합이 을 갖지 않으면 그 자신
• 을 포함하고 있으면 을 제외한 첫 번째 피 연산자와 두 번째 피 연산자를 합집합
한 것
– 예 : {a, b, c} {c, d} = {a, b, c}.
{a, b, c, } {c, d} = {a, b, c, d}.
{a, b, } {c, d, } = {a, b, c, d, }.
Compiler Lecture Note, LL Parsing Page 6
7. • FIRST(A1A2 ···An) = FIRST(A1) FIRST(A2) ··· FIRST(An)
– 스트링의 FIRST : nullable이 아닌 심벌까지의 FIRST를 합집합 한 것
– 각 생성 규칙에 따라 FIRST(X)를 계산하는 방법
1. X가 terminal이면 X의 FIRST는 자기 자신
FIRST(X) = {X} if X∈VT.
2. X → a 의 생성 규칙이 존재하면 a가 FIRST(X)에 포함
FIRST(X) = FIRST(X) ∪ {a} if X → a∈P and a∈VT.
또한, X가 –생성 규칙을 가지면 X의 FIRST에 이 포함
FIRST(X) = FIRST(X) ∪ {} if X → ∈P.
3. X → Y1Y2 ···Yk인 생성 규칙이 있을 때,
FIRST(X) = FIRST(X) ∪ FIRST(Y1Y2 ···Yk).
Compiler Lecture Note, LL Parsing Page 7
8. Compiler Lecture Note, LL Parsing Page 8
ex1) E TE E +TE |
T FT T FT |
F (E) | id
FIRST(E) = FIRST(T) = FIRST(F) = {(, id}
FIRST(E) = {+, }
FIRST(T) = {, }
ex2) PROGRAM begin d semi X end
X d semi X
X s Y
Y semi s Y |
FIRST(PROGRAM) = {begin}
FIRST(X) = {d,s}
FIRST(Y) = {semi, }
9. FOLLOW
• FOLLOW
– Non-terminal A가 nullable하면 FIRST(A)에 이 속하게 되어
FIRST를 가지고는 생성 규칙을 결정적으로 선택할 수 없음
– -생성 규칙을 갖는 문법에서는 non-terminal 다음에 오는 terminal 심벌이 의
미를 가짐
• 정의 : FOLLOW(A) = {a ∈ VT∪{$} | S ⇒ Aa, , ∈ V*}
– $ : 입력 스트링의 끝을 표기하는 마커 심벌(marker symbol)
– Non-terminal A의 FOLLOW란 시작 심벌로부터 유도될 수 있는 모든 문장 형
태에서 A 다음에 나오는 terminal 심벌의 집합
• FOLLOW를 계산하기 위해서는 모든 문장 형태를 고려해야 하나,
문장 형태는 생성 규칙의 rhs들로 이루어져 있으므로,
생성 규칙의 rhs를 이용하여 FOLLOW를 구할 수 있음.
Compiler Lecture Note, LL Parsing Page 9
10. • 각 생성 규칙의 형태에 따른 FOLLOW를 계산하는 방법
1. 시작 심벌은 $를 초기 값으로 갖는다.
FOLLOW(S) = {$}
2. 생성 규칙의 형태가 A→B , 일 때, FIRST()에서 를 제외한 terminal
심벌을 B의 FOLLOW에 추가한다.
if A→B , then FOLLOW(B) = FOLLOW(B) ∪(FIRST() – {}).
3. A→B 이거나, A→B 에서 FIRST()가 이 속하는 경우(즉 ⇒ ), A의
FOLLOW 전체를 B의 FOLLOW에 추가한다.
if A→B ∈ P or (A→B and ⇒ ) then
FOLLOW(B) = FOLLOW(B) ∪ FOLLOW(A).
– 계산 과정 3번의 의미
• 임의의 문장 형태에서 A 다음에 나올 수 있는 심벌은 모두 B 다음에 나올 수 있음
S ⇒ 1A2 ⇒ 1B2 ⇒ 1B2
• FOLLOW 속성으로 인하여 A→B, B→A 와 같은 형태의 생성 규칙을 갖고 있으
면 FOLLOW(A) = FOLLOW(B) 가 됨.
∵ 전자 형태의 생성 규칙으로부터 FOLLOW (A) ⊆ FOLLOW(B)
후자 형태의 생성 규칙으로부터 FOLLOW (A) ⊇ FOLLOW(B)
Compiler Lecture Note, LL Parsing Page 10
12. Compiler Lecture Note, LL Parsing Page 12
▶ LL condition
::= no backup condition
::= the condition for deterministic parsing of top-down method.
input : 12 ... i-1i ...n
derived string : 12...i-1X
X 1 | 2 ... | m
i를 보고 X-production들 중에서 X를 확장할 rule을
결정적으로 선택.
★ <LL condition> A | ∈ P,
1. FIRST() FIRST() =
2. if * , FOLLOW(A) FIRST() =
13. – 예 : 다음 문법을 가지고 스트링 i[e] ← e를 결정적으로 구문 분석할 수 있는지
알아보자
A → iB ← e
B → SB |
S → [eC] | .i
C → eC |
(1) LL 조건 테스트 :
Compiler Lecture Note, LL Parsing Page 13
1. NULLABLE = {B, C}
2. FIRST(A) = {i}
FIRST(B) = {[, ., }
FIRST(S) = {[, .}
FIRST(C) = {e, }
3. FOLLOW(A) = {$}
FOLLOW(B) = {←}
FOLLOW(S) = {[, ., ←}
FOLLOW(C) = {]}
4. FIRST 와 FOLLOW를 이용하여 LL 조건을 테스트
1) B → SB | 에서,
FIRST(SB) ∩ FOLLOW(B) = {[, .} ∩ {←} =
2) S → [eC] | .i 에서,
FIRST([eC]) ∩ FIRST(.i) = {[} ∩ {.}=
3) C → eC | 에서,
FIRST(eC) ∩ FOLLOW(C) = {e} ∩ {]}=
1. FIRST() ∩ FIRST() =
2. if ∈ FIRST() then FOLLOW(A) ∩ FIRST() =
14. (2) 좌측 유도 과정 :
<문장 형태> <입력 스트링>
A ⇒ iB ← e
⇒ iSB ← e
⇒ i[eC]B ← e
⇒ i[e]B ← e
⇒ i[e] ← e
1. 입력 스트링 첫 심벌 i를 보고 시작 심벌 A를 첫 번째 생성 규칙으로 확장
2. 생성된 문장 형태 iB ← e 에서 첫 심벌 i와 입력 스트링 i가 같으므로 다음 심벌 비
교
3. 문장 형태의 다음 심벌은 non-terminal B이고, 현재의 입력 심벌은 [이므로 B-생성
규칙 중에서 [를 유도 할 수 있는 생성 규칙 B → SB를 적용하여 유도
• 이와 같은 과정을 계속 진행하면 시작 심벌로부터 주어진 스트링을 결정적으로
유도할 수 있다.
– FIRST와 FOLLOW는 이와 같이 문장 형태에서 각 non-terminal 이 생성할 수
있는 스트링이 무엇인지를 가리켜 주어서 현재의 입력 심벌을 보고 생성 규
칙을 결정적으로 선택할 수 있게 해준다.
Compiler Lecture Note, LL Parsing Page 14
i[e] ← e
↑
i[e] ← e
↑
i[e] ← e
↑
i[e] ← e
↑
i[e] ← e
↑
15. Compiler Lecture Note, LL Parsing Page 15
ex) A aBc | Bc | dAa
B bB |
FIRST(A) = {a,b,c,d} FOLLOW(A) = {$,a}
FIRST(B) = {b, } FOLLOW(B) = {c}
1) A aBc | Bc | dAa에서,
FIRST(aBc) FIRST(Bc) FIRST(dAa)
= {a} {b,c} {d} =
2) B bB | 에서,
FIRST(bB) FOLLOW(B) = {b} {c} =
1), 2)에 의해 LL 조건을 만족한다.
16. II. Recursive-descent 파서
• LL 방법을 실제로 parsing algorithm으로 사용하는 syntax analyzer
– Recursive-descent parser
– Predictive parser
• Recursive-descent parser
– LL 방법의 일종
– 주어진 입력 스트링을 parsing하기 위하여 일련의 순환 프로시저(recursive
procedure)를 사용
– 각 순환 프로시저는 각 non-terminal 에 해당하는 것으로 non-terminal에 대한
유도를 프로시저 호출로 처리하는 방법
• Recursive-descent parser를 구현 하는 방법
– 각 non-terminal에 대한 프로시저를 작성-통합하여 전체적인 프로그램 구성
• 각 프로시저 내에서 입력 심벌에 따라 어떤 생성 규칙을 선택하느냐가 중요
• 한 생성 규칙을 적용했을 때 생성할 수 있는 terminal들을 알아야 함 :
“LOOKAHEAD”
• 현재의 입력 심벌이 한 생성 규칙의 LOOKAHEAD에 속하면 생성규칙으로 확장
할 수 있도록 프로시저 작성
Compiler Lecture Note, LL Parsing Page 16
17. • LOOKAHEAD 정의와 계산 방법
LOOKAHEAD(A → ) = FIRST( {| S ⇒ A ⇒ ⇒ ∈ VT
*}).
LOOKAHEAD(A → X1X2 ···Xn)
= FIRST(X1) FIRST(X2) ··· FIRST(Xn) FOLLOW(A).
– rhs의 FIRST가 되든지, rhs가 를 유도할 수 있으면 lhs의 FOLLOW 도 속함
– 생성 규칙의 형태에서, rhs가 terminal로 시작하는 생성 규칙의 LOOKAHEAD
는 바로 그 terminal 심벌만이 된다.
ex) LOOKAHEAD(A → a) = {a}
– 예 : 다음의 문법에서 생성 규칙의 LOOKAHEAD를 구하자.
E → TE‟ E' → +TE' |
T → FT‟ T' → *FT' |
F → (E) | id
LOOKAHEAD(E → TE') = FIRST(T) FIRST(E') FOLLOW(E)
= {(, id} {+, } {), $}
= {(, id}
LOOKAHEAD(E'→ +TE') = FIRST(+) FIRST(T) FIRST(E') FOLLOW(E')
= {+} {(, id} {+, } {), $}
= {+}
Compiler Lecture Note, LL Parsing Page 17
19. Compiler Lecture Note, LL Parsing Page 19
▶ Strong LL condition
Definition : A | ∈ P,
LOOKAHEAD(A ) LOOKAHEAD(A ) = .
Meaning : for each distinct pair of productions with the same
left-hand side, it can select the unique alternate
that derives a string beginning with the input symbol.
Definition : the grammar G is said to be strong LL(1)
if it satisfies the strong LL condition.
ex) G : S aSA |
A c
LOOKAHEAD(S aSA) = {a}
LOOKAHEAD(S ) = FOLLOW(S) = {$, c}
LOOKAHEAD(S aSA) LOOKAHEAD(S ) =
G는 strong LL(1)이다.
20. – 예 : 다음 문법이 strong LL(1) 문법인지를 살펴보자.
S → bRS | RcSa |
R → acR | b
먼저, 택일 생성 규칙에 대해 LOOKAHEAD를 구해야 한다.
1. LOOKAHEAD(S → bRS)
= FIRST(b) FIRST(R) FIRST(S) FOLLOW(S)
= {b} {a, b} {a, b, } {a, $}
= {b}
2. LOOKAHEAD(S → RcSa)
= FIRST(R) FIRST(c) FIRST(S) FIRST(a) FOLLOW(S)
= {a, b} {c} {a, b, } {a} {a, $}
= {a, b}
LOOKAHEAD(S → bRS) ∩ LOOKAHEAD(S → RcSa) = {b}
∴ strong LL 문법이 아니다.
– 위 문법이 strong LL 문법이 아니므로 syntax analysis 시 적용할 생성 규칙을
결정적으로 선택할 수 없다.
• 현재의 입력 심벌이 b이고 확장해야 될 non-terminal이 S일 때, 생성 규칙 S → bRS
와 S → RcSa 가 모두 b를 생성 하므로 어느 생성 규칙을 적용할지 알 수 없다.
Compiler Lecture Note, LL Parsing Page 20
21. Compiler Lecture Note, LL Parsing Page 21
▶ Implementation of Recursive-descent parser
If a grammar is strong LL(1), we can construct a parser for sentences of the
grammar using the following scheme.
a ∈ VT,
procedure pa; (* get_nextsymbol=scanner *)
begin
if nextsymbol = ta then get_nextsymbol
else error
end;
get_nextsymbol : 스캐너에 해당하는 루틴으로 입력 스트림으로부터
토큰 한 개를 읽어 전역변수 nextsymbol에 할당
- ta : terminal symbol a의 token number
22. Compiler Lecture Note, LL Parsing Page 22
A ∈ VN,
procedure pA;
begin
case nextsymbol of
LOOKAHEAD(A X1X2...Xm): for i := 1 to m do pXi;
LOOKAHEAD(A Y1Y2...Yn): for i := 1 to n do pYi;
:
LOOKAHEAD(A Z1Z2...Zr): for i := 1 to r do pZi;
LOOKAHEAD(A ): ;
otherwise: error
end (* case *)
end;
메인 프로그램 begin (* main *)
get_nextSymbol;
pS;
if nextSymbol = q$ then accept else error
end.
23. • 예 : 다음 문법을 위한 recursive-descent 프로시저를 구성하자
S → aAb
A → aS | b
Compiler Lecture Note, LL Parsing Page 23
(1) Terminal 심벌에 대한 프로시저
procedure pa;
begin
if nextSymbol = ta
then get_nextSymbol
else error
end; (* pa *)
procedure pb;
begin
if nextSymbol = tb
then get_nextSymbol
else error
end; (* pb *)
(2) Non-terminal 심벌에 대한 프로시저
procedure pS;
begin
if nextSymbol = ta
then begin pa; pA; pb end
else error
end; (* pS *)
procedure pA;
begin
case nextSymbol of
ta : begin pa; pS end;
tb : pb;
otherwise : error
end (* case *)
end; (* pA *)
24. Compiler Lecture Note, LL Parsing Page 24
▶ Improving the efficiency and structure of recursive-descent parser
1) Eliminating terminal procedures
::= In practice it is better not to write a procedure for each terminal.
Instead the action of advancing the input marker can always be initiated
by the nonterminal procedures. In this way many redundant tests can
be eliminated.
(1) Non -terminal S에 대한 프로시저 :
procedure pS
begin
if nextSymbol = qa then
begin get_nextSymbol;
pA;
if nextSymbol = qb then get_nextSymbol
else error
end
else error
end; (* pS *)
(2) Non -terminal A에 대한 프로시저 :
procedure pA;
begin
case nextSymbol of
qa : begin get_nextSymbol; pS end;
qb : get_nextSymbol;
otherwise : error
end (* case *)
end; (* pA *)
25. Compiler Lecture Note, LL Parsing Page 25
▶ Improving the efficiency and structure of recursive-descent parser
2) BNF EBNF : reduce the number of productions and nonterminals.
① repetitive part : { }
② optional part : [ ]
③ alternation : ( | )
ex) < IF_st > ::= ' if ' < cond > ' then ' < st > [ ' else ' < st > ]
procedure pIF;
begin if nextsymbol = tif then
begin get_nextsymbol; pCOND;
if nextsymbol = tthen then
begin get_nextsymbol; pST end
else error(10)
end
else error(20);
if nextsymbol = telse then
begin get_nextsymbol; pST end
end;
26. Compiler Lecture Note, LL Parsing Page 26
ex) <id_list> ::= ' id ' { ' , ' ' id ' }
procedure pID_LIST;
begin if nextsymbol = tid then
begin get_nextsymbol;
while (nextsymbol = tcomma) do
begin get_nextsymbol;
if nextsymbol = tid then get_nextsymbol
else error(100)
end
end
end;
• Recursive-descent 파서
– 생성 규칙에 대한 프로시저를 작성함으로써 syntax analyzer를
구현한 프로그램으로 생성규칙이 바뀔 때 마다 syntax analyzer
를 구현한 프로그램을 다시 고쳐야 하는 단점이 존재
27. Compiler Lecture Note, LL Parsing Page 27
[연습문제 7.8 (2)] 다음 grammar를 extended BNF로 바꾸고 그에 따른
recursive-descent parser를 위한 procedure를 작성하시오.
<D> ::= ' label ' <L> | ' integer ' <L>
<L> ::= <id> <R>
<R> ::= ' ; ' | ' , ' <L>
<D> ::= ( ' label ' | ' integer ' ) <id> {' , ' <id>} ' ; „
procedure pD;
begin if nextsymbol in [tlabel,tinteger] then
begin get_nextsymbol;
if nextsymbol = qid then
begin get_nextsymbol;
while (nextsymbol = qcomma) do
begin get_nextsymbol;
if nextsymbol = qid then get_nextsymbol else error(3)
end
end
else error(2);
if nextsymbol = qsemi then get_nextsymbol else error(4)
end
else error(1)
end;
*
<L> <id> (' , ' <id> )* ' ; '
28. Compiler Lecture Note, LL Parsing Page 28
III. Predictive Parsing
▶ Predictive parsing
::= a deterministic parsing method using a stack.
The stack contains a sequence of grammar symbols.
▶ Model of a predictive parser
Input
Output
Stack
a1 a2 ······ an$
X
$
···
Driver Routine
Predictive
Parsing Table
29. Compiler Lecture Note, LL Parsing Page 29
Current input symbol과 stack top symbol 사이의 관계에 따라 parsing.
The input buffer contains the string to be parsed, followed by $.
Initial configuration : STACK INPUT
$S $
Parsing table(LL) : parsing action을 결정지어 줌.
※ M[X,a] = r : stack top symbol이 X이고 current symbol이 a일 때,
r번 생성 규칙으로 expand.
r
terminals
nonterminals X
a
30. Compiler Lecture Note, LL Parsing Page 30
▶ Parsing Actions
X : stack top symbol, a : current input symbol
1. if X = a = $, then accept.
2. if X = a, then pop X and advance input.
3. if X ∈ VN, then if M[X,a] = r (X), then replace X by
else error.
– 예 : 다음은 주어진 문법에 따른 predictive 파싱 테이블이다.
주어진 문법 : 파싱 테이블 :
1. S → aSb 2. S → bA
3. A → aA 4. A → b
• Empty entry 는 error
• 스택 top이 S이고 현재 입력 심벌이 a이면 1번 생성 규칙으로 확장하라는 의미
VN
VT a b $
S 1 2
A 3 4
31. – Predictive 파서의 driver routine
• 주어진 입력 스트링을 왼쪽에서 오른쪽으로 읽어가며 현재의 입력 심벌
과 스택의 top 심벌에 따라 구문 분석을 수행
• 파싱 테이블은 이와 같은 파싱 행동을 제어한다.
– 파싱 행동의 종류와 의미
1. Pop : 스택의 top과 현재의 입력 심벌이 같은 경우로 스택의 top 심벌은 스
택에서 제거하고 현재 입력 심벌은 입력 스트링에서 제거
2. Expand : 스택의 top이 non-terminal인 경우로 생성 규칙을 적용하여 확장
M[A, a] = {A → XYZ}일 때, A를 스택에서 제거하고 rhs의 역순인 ZYX를
차례로 스택에 넣어 X가 스택 top이 되게 한다.
3. Accept : 스택이 top 심벌과 현재의 입력 심벌 모두가 $인 경우로 주어진
입 력 스트링이 올바른 스트링임을 알리고 파싱을 종료
4. Error : 스택의 top이 non-terminal 심벌인 경우로 그 심벌로부터 현재 보고
있는 입력 심벌을 결코 유도할 수 없음을 나타낸다.
Compiler Lecture Note, LL Parsing Page 31
32. Compiler Lecture Note, LL Parsing Page 32
• Predictive 파서의 구문 분석 방법
Algorithm Predictive_Parser_Action;
begin
repeat
if X ∈ VT∪{$} then
(* pop *)
if X = a then begin pop X; get_nextSymbol end else error fi
else (* X : non-terminal *)
(* expand *)
if M[X, a] = X → Y1Y2 ···Yk then 스택에서 X를 제거하고 rhs의
역순으로 YkYk-1 ···Y1 을 차례로 스택에 넣는다.
else error fi
fi
until X = a = $ (* accept : 스택에 $만 남을 때까지 반복 *)
end.
– X : 스택 top의 심벌
– a : 현재 입력 심벌
33. Compiler Lecture Note, LL Parsing Page 33
• 예 : 다음과 같이 문법과 그에 따른 predictive 파싱 테이블이 주어졌을 때, 스
트링 aabccd에 대한 구문 분석을 수행하고 그 결과로 좌 파스를 구해보자.
주어진 문법 : 1. S → aS 2. S → bA 파싱 테이블 :
3. A → d 4. A → ccA
파싱 테이블 을 이용한 predictive 구문 분석 :
VN
VT a b c d $
S 1 2
A 4 3
Step Stack Input Action parse
1 $S aabccd$ Expand 1 1
2 $Sa aabccd$ Pop & advance 1
3 $S abccd$ Expand 1 1 1
4 $Sa abccd$ Pop & advance 1 1
5 $S bccd$ Expand 2 1 1 2
6 $Ab bccd$ Pop & advance 1 1 2
7 $A ccd$ Expand 4 1 1 2 4
8 $Acc ccd$ Pop & advance & Pop & advance 1 1 2 4
9 $A d$ Expand 3 1 1 2 4 3
10 $d d$ Pop & advance 1 1 2 4 3
11 $ $ Accept 1 1 2 4 3
34. Compiler Lecture Note, LL Parsing Page 34
VI. Predictive 파싱 테이블의 구성
▶ main idea : If A is a production with a in FIRST(), then
the parser will expand A by when the current
input symbol is a. And if * , then we should
again expand A by when the current input symbol
is in FOLLOW(A).
▶ parsing table(LL):
M[X,a] = r : expand X with r-production
blank : error
VT a
X
VN
35. Compiler Lecture Note, LL Parsing Page 35
▶ Algorithm : for each production A,
1. a ∈ FIRST(), M[A,a] := <A>
2. if * , then b ∈ FOLLOW(A), M[A,b] := <A>.
ex) G: 1. E TE' 2. E' +TE' 3. E' 4. T FT'
5. T' FT' 6. T' 7. F (E) 8. F id
FIRST(E)=FIRST(T)=FIRST(F)={ ( , id }
FIRST(E')={ + , } FIRST(T')={ , }
FOLLOW(E) = FOLLOW(E') = { ) , $ }
FOLLOW(T) = FOLLOW(T') = { + , ) , $ }
FOLLOW(F) = { + , , ) , $ }
78F
6656T'
44T
332E'
11E
$)(*+idVTVN
36. Compiler Lecture Note, LL Parsing Page 36
• 예 : id * id + id
주어진 문법 : 파싱 테이블 :
1. E TE' 2. E' +TE' 3. E'
4. T FT‟ 5. T' FT' 6. T'
7. F (E) 8. F id
파싱 테이블 을 이용한 predictive 구문 분석 :
Step Stack Input Action parse
1 $E id * id + id$ Expand 1 1
2 $E‟T id * id + id$ Expand 4 1 4
3 $E‟T‟F id * id + id$ Expand 8 1 4 8
4 $E‟T‟id id * id + id$ Pop id & advance 1 4 8
5 $E‟T‟ * id + id$ Expand 5 1 4 8 5
6 $E‟T‟F* * id + id$ Pop * & advance 1 4 8 5
7 $E‟T‟F id + id$ Expand 8 1 4 8 5 8
8 $E‟T‟id id + id$ Pop id & advance 1 4 8 5 8
9 $E‟T‟ + id$ Expand 6 1 4 8 5 8 6
10 $E‟ + id$ Expand 2 1 4 8 5 8 6 2
11 $E‟T+ + id $ Pop + & advance 1 4 8 5 8 6 2
12 $E‟T id$ Expand 4 1 4 8 5 8 6 2
13 $E‟T‟F id$ Expand 8 & pop id & advance 1 4 8 5 8 6 2 8
14 $E‟T‟ $ Expand 6 & expand 3 1 4 8 5 8 6 2 8 6 3
78F
6656T'
44T
332E'
11E
$)(*+idVTVN
37. Compiler Lecture Note, LL Parsing Page 37
▶ LL(1) Grammar
::= a grammar whose parsing table has no multiply-defined entries.
multiply 정의되면 어느 rule로 expand해야 할 지 결정할 수 없기 때
문에 deterministic하게 parsing할 수 없다.
▶ LL(1) condition: A | ,
1. FIRST( ) FIRST() = .
2. if , then FOLLOW(A) FIRST() = .
ex) G : 1. S iCtSS' 2. S a 3. S' eS 4. S' 5. C b
FIRST(S) = {i,a} FOLLOW(S) = {$,e}
FIRST(S') = {e, } FOLLOW(S') = {$,e}
FIRST(C) = {b} FOLLOW(C) = {t}
• 위 문법은 LL(1) 문법이 아니다.
• 대부분의 경우 중복이 일어나지 않게 문법을 다시 쓰는 것이 보편적
*
3, 4
5C
4S'
12S
$tiebaVTVN
38. Compiler Lecture Note, LL Parsing Page 38
V. Strong LL(k) and LL(k) Grammars
▶ FIRSTk() = {| * , || = k or and || < k}
▶ G is said to be strong LL(k), for some fixed integer k > 0, if
whenever there are two leftmost derivations.
1. S * A * x∈ VT
*, and
2. S * A * y∈ VT
* such that
3. FIRSTk(x) = FIRSTk(y). It follows that
4. = .
▶ Meaning: Suppose we consider any state of the parse in which A is
the nonterminal currently being parsed and FIRSTk(x) is
the k-lookahead at the current point. Then, if the
k-lookahead is same, the two productions A and A
are identical. Any other information provided by the
closed portion and the open portion of the current state
of the parse will be disregarded.
39. Compiler Lecture Note, LL Parsing Page 39
▶ S A, : closed portion, : open portion
▶ Two states of the parse
FIRSTk(x) = FIRSTk(y) ===> = .
*
S
A
x
S
A
y
40. • LOOKAHEAD 정의를 k개의 심벌로 확장
k- LOOKAHEAD(A→) = FIRSTk({|S⇒A⇒⇒∈VT
*}).
그러면 Strong LL(k)는 임의의 생성 규칙 A → | 에 대하여
k- LOOKAHEAD(A→) ∩ k- LOOKAHEAD(A→ ) = 을 만족
– 어떤 고정된 k에 대해서 strong LL(k)의 조건을 만족하는 가를 검사하는 방법
• k의 값을 1부터 차례로 증가시켜 가면서 생성 규칙의 LOOKAHEAD를 구해서 위
조건을 적용
Compiler Lecture Note, LL Parsing Page 40
41. Compiler Lecture Note, LL Parsing Page 41
▶ Def) LL(k) grammar:
1. S A x ∈ VT
*, and
2. S A y ∈ VT
* such that
3. FIRSTk(x) = FIRSTk(y). It follows that
4. = .
ex) S aAaa | bAba
A b |
S S
a A a a b A b a
b
lookahead가 ba일 때 A b, A 중 어느 rule을 택할 수
있는가? 이제 본 symbol이 a이면 A b를 선택하고, b이면
A 를 선택한다. 따라서 SLL(2)는 아니며 LL(2)가 된다.
*
*
*
*
2-LOOKAHEAD(A→b) = {ba, bb}
2-LOOKAHEAD(A→) = {aa, ba}
∴ strong LL(2) 문법이 아니다.
42. Compiler Lecture Note, LL Parsing Page 42
▶ SLL(k) and LL(k)
▶ <theorem> strong LL(1) LL(1)
Proof) () clear!
() Suppose that G is not strong LL(1).
Then, by definition, there are two distinct productions
A and A such that,
S 1A1 11 111 111
S 2A2 22 222 222
and FIRST(11) = FIRST(22).
SLL(k)
LL(k)
*
*
*
*
*
*
43. Compiler Lecture Note, LL Parsing Page 43
Now we must prove that G is not LL(1).
1) 1= 2= , G is not LL(1).
Indeed, it is ambiguous.
2) one (or both) of 1 and 2 is not . 1 .
FIRST1(1 1) = FIRST1(1) = FIRST1(2 2).
but then,
S 2A2 22 2 12 212
S 2A2 22 2 22 222
satisfy the property
FIRST1(1 2) = FIRST1(1) = FIRST1(2 2).
Thus, by definition, G is not LL(1).
*
*
*
*
*
*