# 3. ๐จ Top-Down Parsing (1) - Recursive Descent Parser
## 3.1 Top-Down Parsing โ Backtracking ํ์
> ยง2.4์์ Parse Tree(=CST)๋ฅผ ๋ณต์ํ๋(=CST Generator์์ ํ๋ ์ผ)
> ๋ ๊ฐ์ง ๋ฐฉ๋ฒ(Top-down / Bottom-up)์ ์๊ฐํ๋ค.
>
> ์ด ์ ๋ถํฐ๋ Top-down ๋ฐฉ์์ ๊ตฌ์ฒด์ ์ผ๋ก ๋ค๋ฃฌ๋ค.
> ๋จผ์ ๋จ์ํ ์๋ํ๋ฉด ์ด๋ค ๋ฌธ์ ๊ฐ ์๊ธฐ๋์ง, ๊ทธ ํด๊ฒฐ์ฑ
์ด Backtracking์์ ํ์ธํ๋ค.
>
> ยง3.2์์ Backtracking์ ์ฒด๊ณํํ ์๊ณ ๋ฆฌ์ฆ์ธ Recursive Descent Parsing์ ๋ค๋ฃฌ๋ค.
Top-down parsing์ $S$์์ ์์ํ์ฌ production์ ์ ํํ๋ฉฐ ์ ์ ํ์ฅํด๋๊ฐ๋ ๋ฐฉ์์ด๋ค.
$S \to \gamma_1 \to \gamma_2 \to \cdots \to \gamma_n \to s$
**๋ฌธ์ :** ์๋ชป๋ production์ ์ ํํ๋ฉด ๋ชฉํ ๋ฌธ์์ด๊ณผ ๋ค๋ฅธ ๋ฐฉํฅ์ผ๋ก ์ ๋๋ ์ ์๋ค.
**์์: ๋ง์
๋ฌธ๋ฒ**
```ebnf
S ::= E + S
| E
E ::= [number]
| ( S )
```
์
๋ ฅ: `(1+2+(3+4))+5`
```
S โ E โ ( S ) โ ( E ) โ ( 1 ) โ ์๋ชป๋ ์ ๋!
```
์ด๋ค ๊ท์น์ด ๋ฌธ์ ์์๊น?
```
// ๋๋์๊ฐ๊ธฐ
S โ E โ ( S ) โ ( E ) โ ( 1 ) // ๊ดํธ๋ฅผ ์ ๋ฐํ ์น๊ตฌ๋ฅผ ์ฐพ์
S โ E โ ( S ) โ ์ฌ๊ธฐ๊ฐ ๋ฌธ์ ?
S โ E โ 1 โ ์ด๋ ๊ฒ ๊ฐ๋ ์ด์ํจ
S โ E โ ๋ฌธ์ ๋ ์ฌ๊ธฐ!
```
**ํด๊ฒฐ์ฑ
: Backtracking**
โ ์๋ชป๋ ์ ํ์ ๊ฐ์งํ๋ฉด ์ด์ ์ํ๋ก ๋๋์๊ฐ ๋ค๋ฅธ production์ ์๋ํ๋ค.
## 3.2 ๐จ Recursive Descent Parsing โ ์ ์
> ยง3.1์์ Backtracking์ด Top-down parsing์ ํต์ฌ ์์ด๋์ด์์ ํ์ธํ๋ค.
> ์ด ์ ์์๋ Backtracking์ ๊ตฌ์ฒด์ ์ธ ์๊ณ ๋ฆฌ์ฆ์ผ๋ก ์ฒด๊ณํํ
> Recursive Descent Parsing์ ์ ์ํ๋ค.
> ยง3.3์์๋ ์ด ์๊ณ ๋ฆฌ์ฆ์ ํน์ง๊ณผ ํ๊ณ๋ฅผ ๋ถ์ํ๋ค.
### 3.2.1 ์
๋ ฅ ๋ฐ ๋ณ์
> ๐คโ๏ธ ์ด๊ฑด ๊ฒฐ๊ตญ Parser ๋ด๋ถ CST Generator์ ๋์์์ ์์ง ๋ง์!
Token์ด ๋ญ์๋์ง ํท๊ฐ๋ฆฐ๋ค๋ฉด? [[1. Lexer]] ์ค ยง1.4
Grammar๊ฐ ๋ญ์๋์ง ํท๊ฐ๋ฆฐ๋ค๋ฉด? [[#1.4 Language์ ์กฐ๊ฑด โ Grammar (๋ฌธ๋ฒ)]]๊ณผ [[#1.8 ์ด๋ค ๊ฒ์ Context-Free Grammar๋ผ๊ณ ํ๋๊ฐ?]] ์ฐธ๊ณ .
Tree๊ฐ ๋ญ์๋์ง ํท๊ฐ๋ฆฐ๋ค๋ฉด? [[#2.2.2 Syntax Tree ์ข
๋ฅ โ CST (Concrete Syntax Tree) = Parse Tree]] ์ฐธ๊ณ .
```pseudo
์
๋ ฅ:
(T, NT, S, P) // Grammar
tokens // Token ๋ฆฌ์คํธ
๋ณ์:
tree โ S // Tree node (์์ฑ: parent, children, rule)
// return ๋๋ Parse Tree(=CST)
focus โ S // ํ์ฌ ์ฒ๋ฆฌ ์ค์ธ Tree node
// CST๋ฅผ ๋ง๋ค์ด๊ฐ๋ ๊ณผ์ ์์
// "์ง๊ธ ์ด๋ ๋
ธ๋๋ฅผ ํ์ฅ/๋งค์นญํ๊ณ ์๋๊ฐ?
idx โ 0 // ํ์ฌ Token ์์น
// ์
๋ ฅ Token list์์ ์ด๋๊น์ง ์๋นํ๋๊ฐ?
stack โ [] // ์์ง ์ฒ๋ฆฌํ์ง ์์ ๋
ธ๋๋ค์ ์คํ
```
### 3.2.2 ๋ฉ์ธ ๋ฃจํ
```pseudo
while (true) do
if (focus โ NT) then
// Non-Terminal
// focus๊ฐ Non-terminal (์: CSTExpr, CSTStmt ๋ฑ)
// โ ์์ง ํ์ฅ์ด ์ ๋ ๋
ธ๋. production์ ์ ์ฉํด์ ์์ ๋
ธ๋๋ค๋ก ํผ์ณ์ผ ํจ
// โ ์: focus = S ์ด๋ฉด S โ E + S ๊ฐ์ rule์ ์ ํํด์
// E, +, S ์์์ผ๋ก ์ฐ๊ฒฐ
goto Case 1
else if (idx < len(tokens) && focus = tokens[idx]) then
// Terminal
// focus๊ฐ Terminal (์: IF, LPAREN, ID ๋ฑ ์ค์ ํ ํฐ)
// && ์์ง ์ฝ์ ํ ํฐ์ด ๋จ์ ์๊ณ (idx < len(tokens))
// && ํ์ฌ focus ๋
ธ๋๊ฐ ํ์ฌ ํ ํฐ๊ณผ ์ผ์นํ ๋ (focus = tokens[idx])
// โ "ํธ๋ฆฌ๊ฐ ๊ธฐ๋ํ๋ ํ ํฐ"๊ณผ "์ค์ ์
๋ ฅ ํ ํฐ"์ด ๋ง์ผ๋ฏ๋ก ์๋น
// โ ์: focus = IF, tokens[idx] = IF ์ด๋ฉด ๋งค์นญ ์ฑ๊ณต
goto Case 2
else if (idx = len(tokens) && stack = []) then
// โ
Success!
// focus๊ฐ ๋ญ์ง๋ ์ ์ค์
// ํ ํฐ์ ์ ๋ถ ์๋นํ๊ณ (idx = len(tokens))
// && ์คํ๋ ๋น์ด์์ (์ฒ๋ฆฌํ ๋
ธ๋๊ฐ ๋ ์์)
// โ ์
๋ ฅ ์ ์ฒด๋ฅผ ํธ๋ฆฌ๋ก ์์ ํ ์ปค๋ฒํ์ผ๋ฏ๋ก ํ์ฑ ์ฑ๊ณต!
return tree
else
// โ Backtrack!
// ์ ์ธ ์กฐ๊ฑด ๋ชจ๋ ํด๋น ์์. ์ฆ:
// 1) focus๋ Terminal์ธ๋ฐ tokens[idx]์ ๋ถ์ผ์น
// โ ์ฆ, ์๋ชป๋ production์ ์ ํํ์
// 2) ๋๋ ํ ํฐ์ด ๋จ์๋๋ฐ ์คํ์ด ๋น์ด๋ฒ๋ฆผ (์
๋ ฅ์ด ๋ ๋จ์๋๋ฐ ํธ๋ฆฌ๊ฐ ๋๋จ)
// โ ํ์ฌ ์ ํํ production์ด ํ๋ ธ์ผ๋ฏ๋ก ๋๋์๊ฐ์ ๋ค๋ฅธ production ์๋
goto Case 3
```
### 3.2.3 Case 1: Non-terminal ์ฒ๋ฆฌ โ Production
ํ์ฌ focus๊ฐ Non-terminal์ธ ๊ฒฝ์ฐ, ํด๋น Non-terminal์ rule ๋ฒํธ์ ํด๋นํ๋ production์ ์ ์ฉํ๋ค.
```pseudo
// Case 1: focus๊ฐ NT์ผ ๋ โ production์ ์ ์ฉํด์ ํธ๋ฆฌ๋ฅผ ํ์ฅ
// focus๋ฅผ ์ข๋ณ์ผ๋ก ๋์ ๋ (NT), ์ฐ๋ณ์ ์ค๋ ๊ฒ๋ค ฮฑโ ... ฮฑโ ๋ก ํ์
// P[focus][focus.rule] = focus ๋
ธ๋์ ์ ์ฉํ production ์ ํ
// ์: focus = S, focus.rule = 0 ์ด๋ฉด P[S][0] = S โ E + S
// ์ฆ,
// ฮฑโ = E, ฮฑโ = +, ฮฑโ = S
(focus -> ฮฑโ ... ฮฑโ) โ P[focus][focus.rule]
// ๋ค์์ ์ด ๋
ธ๋๋ก backtrackํ์ ๋ ๋ค์ production์ ์๋ํ๋๋ก +1
// ์: focus.rule = 0 โ 1 ๋ก ์ฌ๋ ค๋์ผ๋ฉด, backtrack ์ P[S][1] = S โ E ์๋
focus.rule โ focus.rule + 1
// ์ ํํ production์ ์ฐ๋ณ์ ์ค๋ ๊ฒ๋ค(ฮฑโ...ฮฑโ)์ ์ ๋ถ ์์ ๋
ธ๋๋ก ์ฐ๊ฒฐ
// โ ํธ๋ฆฌ๊ฐ ์ด ์์ ์ ํ์ฅ๋จ
// ์: focus = S, P[S][0] = S โ E + S ์ด๋ฉด
// S ๋
ธ๋์ E, +, S ์์ ๋
ธ๋ ์ธ ๊ฐ๊ฐ ์ฐ๊ฒฐ๋จ
for 1 โค i โค n do
connect(focus, ฮฑแตข)
// ฮฑโ ~ ฮฑโ์ ์คํ์ push (๋์ค์ ์ฒ๋ฆฌํ ๊ฒ๋ค)
// ๊ทธ๋ ๋ค๋ ๊ฑด ฮฑโ์ ์ง๊ธ ์ฒ๋ฆฌํ๊ฒ ๋ค๋ ๊ฑฐ!!
// ์ค๋ฅธ์ชฝ๋ถํฐ pushํด์ผ ๋์ค์ popํ์ ๋ ์ผ์ชฝ๋ถํฐ ์์๋๋ก ๋์ด
// ์: ฮฑโ = +, ฮฑโ = S ์ด๋ฉด S๋ฅผ ๋จผ์ push, +๋ฅผ ๋์ค์ push
// โ popํ๋ฉด +๊ฐ ๋จผ์ ๋์ด (left-most ์์ ์ ์ง)
for n โฅ i โฅ 2 do
stack.push(ฮฑแตข)
// ฮฑโ(๊ฐ์ฅ ์ผ์ชฝ ๊ธฐํธ)๋ก focus ์ด๋
// โ left-most derivation: ํญ์ ๊ฐ์ฅ ์ผ์ชฝ ๋
ธ๋๋ถํฐ ์ฒ๋ฆฌ
focus โ ฮฑโ
```
### 3.2.4 Case 2: Terminal ์ฒ๋ฆฌ โ ๋ค์์ผ๋ก
ํ์ฌ focus๊ฐ Terminal์ด๊ณ ํ์ฌ Token๊ณผ ์ผ์นํ๋ ๊ฒฝ์ฐ:
```pseudo
// Case 2: T
// "ํธ๋ฆฌ๊ฐ ๊ธฐ๋ํ๋ ํ ํฐ"๊ณผ "์ค์ ์
๋ ฅ ํ ํฐ"์ด ๋ง์ผ๋ฏ๋ก ์๋น
idx โ idx + 1 // ๋ค์ ํ ํฐ์ผ๋ก ์ด๋
focus โ stack.pop() // ์คํ์์ ๋ค์ ์ฒ๋ฆฌํ ๋
ธ๋ ๊บผ๋ด๊ธฐ
```
### 3.2.5 ๐จ Case 3: Backtrack โ ๋ฐฑํธ๋ or
๋งค์นญ ์คํจ ์, ๊ฐ์ฅ ์ต๊ทผ Non-terminal๋ก ์ฌ๋ผ๊ฐ ๋ค์ production์ ์๋ํ๋ค.
```pseudo
// Case 3: Backtrack โ
while (true) do
// ํ์ฌ ์คํจํ ๋
ธ๋๋ฅผ error๋ก ์ ์ฅ
error โ focus
????
// ๋ถ๋ชจ ๊ธฐ์ค์ผ๋ก error๊ฐ ๋ช ๋ฒ์งธ ์์์ธ์ง ์ธ๋ฑ์ค ์ ์ฅ
// โ ์ดํ stack/idx ๋ณต์ ๋ฒ์๋ฅผ ๊ณ์ฐํ ๋ ์ฌ์ฉ
error_idx โ focus.children.index(error)
// stack, idx๋ฅผ ์ด ๋
ธ๋(focus)๋ฅผ ํ์ฅํ๊ธฐ ์ ์ํ๋ก ๋ณต์
// โ error_idx ์ดํ ์์๋ค์ stack์์ pop
// โ error_idx > 0 ์ด๋ฉด idx๋ ์ผ์ชฝ ํ์ ๊ฐ ์๋นํ ํ ํฐ ์ด์ ์ผ๋ก ๋๋๋ฆผ
goto restore ๐
// focus์ ์์ ๋
ธ๋๋ฅผ ์ ๋ถ ์ ๊ฑฐ
// โ ๋ค์ production์ ์๋ก ์๋ํ๊ธฐ ์ํด ํธ๋ฆฌ๋ฅผ ๊นจ๋ํ๊ฒ ๋น์
goto remove_children ๐๏ธ
if (focus.rule = len(P[focus])) then
// focus์์ ๋ค์์ ์๋ํ P index = Focus๊ฐ ์๋ํ ์ ์๋ ๋ชจ๋ P len
// ์ด NT์ ๋ํด ์๋ํ production์ด ๋ ์ด์ ์์
if (focus = tree) then
// ๋ฃจํธ ๋
ธ๋๊น์ง ์ฌ๋ผ์๋๋ฐ๋ ์คํจ
// โ ์ด๋ค production ์กฐํฉ์ผ๋ก๋ ํ์ฑ ๋ถ๊ฐ โ ๊ตฌ๋ฌธ ์ค๋ฅ
raise Error
else
// ์์ง ์์ ๋ถ๋ชจ ๋
ธ๋๊ฐ ์์
// โ while ๋ฐ๋ณตํ์ฌ ํ ๋จ๊ณ ๋ ์๋ก ์ฌ๋ผ๊ฐ์ backtrack ๊ณ์
continue
else
// ์์ง ์๋ ์ ํ production์ด ๋จ์ ์์
// โ while ํ์ถ ํ ๋ฉ์ธ ๋ฃจํ์์ ๋ค์ production์ผ๋ก ์ฌ์๋
break
```
**๐ restore** (์ํ ๋ณต์):
```pseudo
// focus ๋ณต์
// โ ์คํจํ ๋
ธ๋์์ ๋ถ๋ชจ๋ก ์ฌ๋ผ๊ฐ
// โ ์ด์ ์ด ๋ถ๋ชจ ๋
ธ๋์ ๋ค์ production์ ์๋ํ ๊ฒ
focus โ focus.parent
// stack ๋ณต์
// โ error_idx ์ดํ ์์๋ค(์์ง ์ฒ๋ฆฌ ์ ํ ์ค๋ฅธ์ชฝ ํ์ ๋ค)์
// Case 1์์ stack.push ํ๋ ์ ๋ค์ด๋ฏ๋ก ๋ค์ popํด์ ๋๋๋ฆผ
// โ ์: error_idx = 1 ์ด๊ณ ์์์ด [E, +, S] ๋ฉด
// +, S ๋ ์์ง ์ฒ๋ฆฌ ์ ํ์ผ๋ stack์์ pop
for (error_idx + 1 โค i < len(focus.children)) do
stack.pop()
// idx ๋ณต์
// โ error_idx = 0 ์ด๋ฉด ์ผ์ชฝ ํ์ ๊ฐ ์์ผ๋ฏ๋ก
// ์๋นํ ํ ํฐ์ด ์์ โ idx ๋ณต์ ๋ถํ์
// โ error_idx โ 0 ์ด๋ฉด ์ผ์ชฝ ํ์ ๋ค์ด ์ด๋ฏธ ํ ํฐ์ ์๋นํ์ผ๋ฏ๋ก
// ๊ฐ์ฅ ์ผ์ชฝ ์์(children[0])์ ์ ์ผ ์ผ์ชฝ ๋ terminal์ ์ฐพ์์
// ๊ทธ ํ ํฐ ์์น๋ก idx๋ฅผ ๋๋๋ฆผ
// โ follow_left_child = ํด๋น ๋
ธ๋์์ ์ผ์ชฝ ์์์ ํ๊ณ ๋ด๋ ค๊ฐ
// ๊ฐ์ฅ ์ฒซ ๋ฒ์งธ terminal ๋
ธ๋๋ฅผ ๋ฐํํ๋ ํจ์
if (error_idx โ 0) then
terminal โ follow_left_child(focus.children[0])
idx โ tokens.index(terminal)
```
**๐๏ธ remove_children** (์์ ์ ๊ฑฐ):
```pseudo
for (child โ focus.children) do
disconnect(focus, child)
```
### 3.2.6 ์์: (์์๋ฅผ ๋ฐ๊พผ) ๋ง์
๋ฌธ๋ฒ
> ํ ํฐ์ ๊ฐ์ฅ ์ผ์ชฝ๋ถํฐ ๋ณด๊ณ , stack ๊ทธ๋ ค์ ์์๊ฐ๋ฉด์ ์ดํด ใฑใฑ
> ํ ๋ฒ ์ดํดํ ๊ฑฐ๋ผ ใฑใ
์๋ฏ
์
๋ ฅ: `(1+2+(3+4))+5`
```ebnf
S ::= E
| E + S
E ::= ( S )
| [number]
```
production ์ธ๋ฑ์ค ์ ๋ฆฌ:
- `P[S][0]` = `S โ E`
- `P[S][1]` = `S โ E + S`
- `P[E][0]` = `E โ ( S )`
- `P[E][1]` = `E โ [number]`
#### ์ด๊ธฐ ์ํ
```
tree : S
focus : S
idx : 0 โ (
stack : []
```
#### STEP 1 `Case 1` โ focus=S (NT), `P[S][0]` = `S โ E` ์ ์ฉ
```
tree : S
|
E โ focus
idx : 0 โ (
stack : []
```
#### STEP 2 `Case 1` โ focus=E (NT), `P[E][0]` = `E โ ( S )` ์ ์ฉ
```
tree : S
|
E
/ | \
( S ) โ focus=(
idx : 0 โ (
stack : [S, )]
```
#### STEP 3 `Case 2` โ focus=`(`, tokens\[0]=`(` โ
๋งค์นญ
```
tree : S
|
E
/ | \
( S ) โ focus=S
idx : 1 โ 1
stack : [)]
```
#### STEP 4 `Case 1` โ focus=S (NT), `P[S][0]` = `S โ E` ์ ์ฉ
```
tree : S
|
E
/ | \
( S )
|
E โ focus
idx : 1 โ 1
stack : [)]
```
#### STEP 5 `Case 1` โ focus=E (NT), `P[E][0]` = `E โ ( S )` ์ ์ฉ
```
tree : S
|
E
/ | \
( S )
|
E
/ | \
( S ) โ focus=(
idx : 1 โ 1
stack : [S, ), )]
```
#### STEP 6 `Case 3` โ โ focus=`(`, tokens[1]=`1` โ ๋ถ์ผ์น โ Backtrack
`E โ ( S )` ์คํจ. `P[E][1]` = `E โ [number]` ๋ก ์ฌ์๋.
restore: focus=E (๋ถ๋ชจ๋ก), idx=1 ์ ์ง, ์์ ์ ๊ฑฐ.
```
tree : S
|
E
/ | \
( S )
|
E โ focus (์์ ์ ๊ฑฐ๋จ, rule=1๋ก ์ฌ๋ผ๊ฐ)
idx : 1 โ 1
stack : [)]
```
#### STEP 7 `Case 1` โ focus=E (NT), `P[E][1]` = `E โ [number]` ์ ์ฉ
```
tree : S
|
E
/ | \
( S )
|
E
|
1 โ focus
idx : 1 โ 1
stack : [)]
```
#### STEP 8 `Case 2` โ focus=`1`, tokens[1]=`1` โ
๋งค์นญ
```
tree : S
|
E
/ | \
( S )
|
E
|
1 โ focus=) (stack.pop)
idx : 2 โ +
stack : [] โ pop ํ๋ฉด )
```
#### STEP 9 `Case 3` โ โ focus=`)`, tokens[2]=`+` โ ๋ถ์ผ์น โ Backtrack
`S โ E` ๋ก๋ `1` ๋ง ์๋นํ๊ณ ๋๋ฌ๋๋ฐ `)` ๊ฐ ์์ผ ํ๋๋ฐ `+` ๊ฐ ์ด.
restore: focus=S (๋ถ๋ชจ), idx=1, ์์(E) ์ ๊ฑฐ. `P[S][1]` = `S โ E + S` ๋ก ์ฌ์๋.
```
tree : S
|
E
/ | \
( S )
|
S โ focus (rule=1, ์์ ์ ๊ฑฐ๋จ)
idx : 1 โ 1
stack : [)]
```
#### STEP 10 `Case 1` โ focus=S (NT), `P[S][1]` = `S โ E + S` ์ ์ฉ
```
tree : S
|
E
/ | \
( S )
|
S
/ | \
E + S โ focus=E
idx : 1 โ 1
stack : [+, S, )]
```
#### STEP 11 `Case 1` โ focus=E (NT), `P[E][1]` = `E โ [number]` ์ ์ฉ
(์ด์ ์ `E โ ( S )` ๊ฐ ์คํจํ ์ ์๊ณ , ์ง๊ธ tokens[1]=`1` ์ด๋ฏ๋ก ๋ฐ๋ก [number] ์ ํ)
```
tree : S
|
E
/ | \
( S )
|
S
/ | \
E + S
|
1 โ focus
idx : 1 โ 1
stack : [+, S, )]
```
#### STEP 12 `Case 2` โ focus=`1`, tokens[1]=`1` โ
```
focus : + (stack.pop)
idx : 2 โ +
stack : [S, )]
```
#### STEP 13 `Case 2` โ focus=`+`, tokens[2]=`+` โ
```
focus : S (stack.pop)
idx : 3 โ 2
stack : [)]
```
#### STEP 14 `Case 1` โ focus=S (NT), `P[S][1]` = `S โ E + S` ์ ์ฉ
```
tree : S
|
E
/ | \
( S )
|
S
/ | \
E + S
| \
1 E + S โ focus=E
idx : 3 โ 2
stack : [+, S, )]
```
#### STEP 15 `Case 1` โ focus=E, `P[E][1]` = `E โ [number]` ์ ์ฉ
```
E
|
2 โ focus
idx : 3 โ 2
```
#### STEP 16 `Case 2` โ focus=`2`, tokens[3]=`2` โ
```
focus : + (stack.pop)
idx : 4 โ +
stack : [S, )]
```
#### STEP 17 `Case 2` โ focus=`+`, tokens[4]=`+` โ
```
focus : S (stack.pop)
idx : 5 โ (
stack : [)]
```
#### STEP 18 `Case 1` โ focus=S, `P[S][0]` = `S โ E` ์ ์ฉ
```
S
|
E โ focus
idx : 5 โ (
stack : [)]
```
#### STEP 19 `Case 1` โ focus=E, `P[E][0]` = `E โ ( S )` ์ ์ฉ
```
E
/ | \
( S ) โ focus=(
idx : 5 โ (
stack : [S, ), )]
```
#### STEP 20 `Case 2` โ focus=`(`, tokens[5]=`(` โ
```
focus : S (stack.pop)
idx : 6 โ 3
stack : [), )]
```
#### STEP 21 `Case 1` โ focus=S, `P[S][1]` = `S โ E + S` ์ ์ฉ
```
S
/ | \
E + S โ focus=E
idx : 6 โ 3
stack : [+, S, ), )]
```
#### STEP 22 `Case 1` โ focus=E, `P[E][1]` = `E โ [number]` ์ ์ฉ
```
E
|
3 โ focus
idx : 6 โ 3
```
#### STEP 23 `Case 2` โ focus=`3`, tokens[6]=`3` โ
```
focus : +
idx : 7 โ +
```
#### STEP 24 `Case 2` โ focus=`+`, tokens[7]=`+` โ
```
focus : S
idx : 8 โ 4
```
#### STEP 25 `Case 1` โ focus=S, `P[S][0]` = `S โ E` ์ ์ฉ
```
S
|
E โ focus
idx : 8 โ 4
```
#### STEP 26 `Case 1` โ focus=E, `P[E][1]` = `E โ [number]` ์ ์ฉ
```
E
|
4 โ focus
idx : 8 โ 4
```
#### STEP 27 `Case 2` โ focus=`4`, tokens[8]=`4` โ
```
focus : ) (stack.pop)
idx : 9 โ )
stack : [), )]
```
#### STEP 28 `Case 2` โ focus=`)`, tokens[9]=`)` โ
```
focus : ) (stack.pop)
idx : 10 โ )
stack : [)]
```
#### STEP 29 `Case 2` โ focus=`)`, tokens[10]=`)` โ
```
focus : + (stack.pop)
idx : 11 โ +
stack : [S]
```
#### STEP 30 `Case 2` โ focus=`+`, tokens[11]=`+` โ
```
focus : S (stack.pop)
idx : 12 โ 5
stack : []
```
#### STEP 31 `Case 1` โ focus=S, `P[S][0]` = `S โ E` ์ ์ฉ
```
S
|
E โ focus
idx : 12 โ 5
stack : []
```
#### STEP 32 `Case 1` โ focus=E, `P[E][1]` = `E โ [number]` ์ ์ฉ
```
E
|
5 โ focus
idx : 12 โ 5
stack : []
```
#### STEP 33 `Case 2` โ focus=`5`, tokens[12]=`5` โ
```
focus : stack.pop() โ ์คํ ๋น์ด์์
idx : 13 (= len(tokens))
stack : []
```
#### STEP 34 โ
**Success!** โ `idx = len(tokens) && stack = []`
์ต์ข
CST:
```
S
โโโ E
โโโ (
โโโ S
โ โโโ S
โ โโโ E
โ โ โโโ 1
โ โโโ +
โ โโโ S
โ โโโ E
โ โ โโโ 2
โ โโโ +
โ โโโ S
โ โโโ E
โ โโโ (
โ โโโ S
โ โ โโโ S
โ โ โโโ E
โ โ โ โโโ 3
โ โ โโโ +
โ โ โโโ S
โ โ โโโ E
โ โ โโโ 4
โ โโโ )
โโโ )
+ S
โโโ E
โโโ 5
```
## 3.3 Recursive Descent Parsing โ ํน์ง
> ยง3.2์์ Recursive Descent Parsing ์๊ณ ๋ฆฌ์ฆ์ ์์ ํ ์ ์ํ๋ค.
>
> ์ด์ ์ด ์๊ณ ๋ฆฌ์ฆ์ ์ฑ์ง์ ๋ถ์ํ๊ณ ,
> ํญ์ ์ฌ๋ฐ๋ฅด๊ฒ ๋์ํ๋์ง ์ง๋ฌธ์ ๋์ง๋ค.
>
> ยง3.4์์๋ ์ข
๋ฃ๋ฅผ ๋ณด์ฅํ์ง ๋ชปํ๋ Left-recursion ๋ฌธ์ ์ ๊ทธ ํด๊ฒฐ์ฑ
์ ๋ค๋ฃฌ๋ค.
### 3.3.1 `ํน์ง1` Left-most derivation
Recursive Descent Parsing์ ํญ์ Left-most derivation)๋ฅผ ๋ฐ๋ฅธ๋ค.
โ ์คํ ๊ตฌ์กฐ์ ํญ์ ๊ฐ์ฅ ์ผ์ชฝ์ Non-terminal์ ๋จผ์ ์ฒ๋ฆฌํ๊ธฐ ๋๋ฌธ.
### 3.3.2 `ํน์ง2` ํน์ง 2: ์ข
๋ฃ ์ฌ๋ถ
ํน๋ณํ ๋ฌธ๋ฒ์ด ์๋ ๊ฒฝ์ฐ์ ์๊ณ ๋ฆฌ์ฆ์ ๋๋๋ค.
ํ์ง๋ง ๋ค์ ์ ์์ ๋ณผ ์ ์๋ฏ, ํน์ ๋ฌธ๋ฒ์์๋ **๋ฌดํ ๋ฃจํ**์ ๋น ์ง ์ ์๋ค.
### 3.3.3 `ํน์ง3` Backtracking์ ๋นํจ์จ์ฑ
๋งค๋ฒ ์คํจํ ๋๋ง๋ค ์ด์ ์ํ๋ก ๋์๊ฐ์ ๋ค์ ์๋ํ๋ฏ๋ก, ์ต์
์ ๊ฒฝ์ฐ ์ง์ ์๊ฐ์ด ๊ฑธ๋ฆด ์ ์๋ค.
โ ์ค์ฉ์ ์ธ ํ์์์๋ Backtracking์ ํผํ๊ธฐ ์ํ ์ต์ ํ(look-ahead ๋ฑ)๊ฐ ํ์ํ๋ค.
## 3.4 Recursive Descent Parsing โ Left-Recursion ๋ฌธ์ ์ ํด๊ฒฐ
> ยง3.3์์ Recursive Descent Parsing์ด
> ํน์ ๋ฌธ๋ฒ์์ ์ข
๋ฃ๋์ง ์์ ์ ์๋ค๋ ์ ์ ์ง์ ํ๋ค.
>
> ๊ตฌ์ฒด์ ์ผ๋ก ์ด๋ค ๋ฌธ๋ฒ์ด ๋ฌธ์ ๊ฐ ๋๋์ง,
> ๊ทธ๋ฆฌ๊ณ ์ด๋ป๊ฒ ๊ณ ์น ์ ์๋์ง๋ฅผ ๋ค๋ฃฌ๋ค.
>
> ์ดํ ๊ฐ์์์๋ Backtracking ์์ฒด๋ฅผ ์์ ๋,
> ๋ณด๋ค ํจ์จ์ ์ธ Top-down parsing ๋ฐฉ๋ฒ์ ๋ค๋ฃฌ๋ค.
"Recursive Descent Parsing์ผ๋ก ํญ์ Parsing์ด ๊ฐ๋ฅํ ๊ฒ์ ์๋๋ค."
### 3.4.1 `๋ฌธ์ ` Left-recursion
**๋ฌธ์ ์์:** $S \to Sa,\quad S \to b$
- ์ด ๋ฌธ๋ฒ์ด ํํํ๋ ์ธ์ด: $ba^*$ (์ด ์ธ์ด๋ Regular โ Left-Regular ๋ฌธ๋ฒ)
- ํ์ง๋ง Recursive Descent Parsing์ ์ ์ฉํ๋ฉด:
```
S โ Sa โ Saa โ Saaa โ ...
```
$S$์์ ์ถ๋ฐํ๋ฉด ๊ฐ์ฅ ๋จผ์ $S \to Sa$๋ฅผ ์ ์ฉ โ ๋ค์ $S$๊ฐ ๋์ค๊ณ โ ๋ $S \to Sa$ โ **๋ฌดํ ๋ฃจํ**
**์ ์ด๋ฐ ์ผ์ด ์๊ธฐ๋?**
โ
1. Recursive Descent Parsing์ Left-most derivation์ ๋ฐ๋ฅด๋๋ฐ,
2. left-recursive ๋ฌธ๋ฒ์์๋
3. Terminal์ ๋ง๋๊ธฐ ์ ์
4. ๊ณ์ ๊ฐ์ Non-terminal๋ก ๊น๊ฒ ํ๊ณ ๋ค๊ธฐ ๋๋ฌธ.
### 3.4.2 `ํด๊ฒฐ` ์๋ก์ด NT ๋์
ํด Right-Recursive๋ก ๋ง๋ค๊ธฐ
#### 3.4.2.1 $S \to Sa,\quad S \to b$ ์์
๊ธฐ์กด:
$S \to Sa,\quad S \to b$
๋ณํ:
$S \to bS'$
$S' \to aS' \mid \epsilon$
์ด ๋ฌธ๋ฒ์ left-recursive๊ฐ ์์ผ๋ฏ๋ก Recursive Descent Parsing ๊ฐ๋ฅ.
#### 3.4.2.2 $S \to S\alpha_1 \mid S\alpha_2 \mid \cdots \mid S\alpha_n \mid \beta_1 \mid \beta_2 \mid \cdots \mid \beta_m$ ์์
๊ธฐ์กด:
$S \to S\alpha_1 \mid S\alpha_2 \mid \cdots \mid S\alpha_n \mid \beta_1 \mid \beta_2 \mid \cdots \mid \beta_m$
๋ณํ:
$S \to \beta_1 S' \mid \beta_2 S' \mid \cdots \mid \beta_m S'$ $S' \to \alpha_1 S' \mid \alpha_2 S' \mid \cdots \mid \alpha_n S' \mid \epsilon$
#### 3.4.2.3 $S \to A\alpha \mid \delta, \quad A \to S\beta$ ์์
๋ค์๊ณผ ๊ฐ์ด ์ง์ ์ ์ผ๋ก ๋ณด์ด์ง ์๋ ๊ฒฝ์ฐ๋ ์๋ค:
$S \to A\alpha \mid \delta, \quad A \to S\beta$
๋์
ํ๋ฉด: $S \to S\beta\alpha \mid \delta$ โ ์ฌ์ค์ left-recursive.
### 3.4.3 `ํด๊ฒฐ` ์ผ๋ฐ์ ์ธ Left-recursive โ Right-recursive
```pseudo
// Non-terminal๋ค์ ์์์ ์์๋ก ์ ๋ ฌ
// (์์์ ๋ฐ๋ผ ๊ฒฐ๊ณผ ๋ฌธ๋ฒ์ด ๋ฌ๋ผ์ง ์ ์์)
Non-terminal NT = {Aโ, ..., Aโ}์ ์ ๋นํ ์์๋ก ์ ๋ ฌ
for i = 1 to n do
for j = 1 to i - 1 do
// Aแตข โ Aโฑผฮณ ํํ์ production์ด ์์ ๋
// Aโฑผ์ ๋ชจ๋ production์ ๋์
ํด์
// ๊ฐ์ left-recursion์ ์ง์ ํํ๋ก ๋๋ฌ๋
// ์: Aโฑผ โ ฮดโ | ฮดโ ์ด๊ณ Aแตข โ Aโฑผฮณ ์ด๋ฉด
// Aแตข โ ฮดโฮณ | ฮดโฮณ ๋ก ๋ฐ๊ฟ
// โ ์ด ์์ ์์ Aโฑผ๋ ์ด๋ฏธ ์ฒ๋ฆฌ๊ฐ ๋๋ NT (j < i ์ด๋ฏ๋ก)
// ์ฆ Aโฑผ์ production์๋ Aแตข๋ณด๋ค ์์ NT๋ง ๋ฑ์ฅ์ด ๋ณด์ฅ๋จ
Aโฑผ โ ฮดโ | ฮดโ | ... | ฮดโ์ Aแตข โ Aโฑผฮณ์ ๋ํด
Aแตข โ ฮดโฮณ | ฮดโฮณ | ... | ฮดโฮณ๋ก ๋์ฒด
// j ๋ฃจํ๊ฐ ๋๋๋ฉด Aแตข์ ๋ชจ๋ ๊ฐ์ left-recursion์ด
// ์ง์ left-recursion ํํ๋ก ๋ณํ๋ ์ํ
// โ ์ด์ ์ง์ left-recursion๋ง ์ ๊ฑฐํ๋ฉด ๋จ
Aแตข์ ๋ํด์ ์ง์ Left-recursion ์ ๊ฑฐ
```
#### 3.4.3.1 $S \to A\alpha \mid \delta,\quad A \to S\beta$ ์์
1. Non-terminal ์ ๋ ฌ: $A, S$ ์์
2. $A$์ ๋ํด: ์๋ฌด ์ผ๋ ์ผ์ด๋์ง ์์
1. $A$๊ฐ `i=1`์ผ ๋, ์์ชฝ ๋ฃจํ๊ฐ `j = 1 to 0`. **0๋ฒ ๋** โ ๋ฃจํ ์์ฒด๊ฐ ์คํ์ด ์ ๋จ.
3. $S$์ ๋ํด:
- $A \to S\beta$์ด๊ณ $S$์๋ $A$๋ฅผ ์์ ์ฐ๋ production์ด ์์ผ๋ฏ๋ก ๋์
:
$S \to S\beta\alpha \mid \delta$
- Direct left-recursion ์ ๊ฑฐ:
$S \to \delta S',\quad S' \to \beta\alpha S' \mid \epsilon$
4. ์ต์ข
๋ฌธ๋ฒ: $S \to \delta S',\quad S' \to \beta\alpha S' \mid \epsilon$
> **๋จ, ์ด ์๊ณ ๋ฆฌ์ฆ๋ ํญ์ ์๋ํ๋ ๊ฑด ์๋๋ค.** ๋ฌธ๋ฒ์ $\epsilon$-production์ด๋ ์ฌ์ดํด(์: $A \to B,\ B \to A$)์ด ์์ผ๋ฉด ๋ณ๋ ์ฒ๋ฆฌ๊ฐ ํ์ํ๋ค.
## 3.5 ์ ๋ฆฌ
> ยง3.4์์ Left-recursion์ ์ ๊ฑฐํ๋ ๋ฐฉ๋ฒ์ ๋ค๋ค๋ค.
> ์ด๋ก์จ Recursive Descent Parsing์ ๊ฐ๋
, ์๊ณ ๋ฆฌ์ฆ, ํ๊ณ,
> ๊ทธ๋ฆฌ๊ณ ํ๊ณ๋ฅผ ๊ทน๋ณตํ๋ ๋ฐฉ๋ฒ(๋ฌธ๋ฒ ๋ณํ)์ ๋ชจ๋ ๋ค๋ค๋ค.
>
> ๋ค์ ๊ฐ์์์๋ Backtracking ์์ฒด๋ฅผ ์์ ๋
> ๋ณด๋ค ํจ์จ์ ์ธ Top-down parsing โ **LL(1) Parsing** ์ ๋ค๋ฃฌ๋ค.
- Recursive Descent Parsing์ **Top-down parsing์ ํ ๋ฐฉ๋ฒ**
- ํต์ฌ ์์ด๋์ด: **Backtracking**
- **Left-recursion์ด ์๋ ๋ฌธ๋ฒ์์๋ ๋์ํ์ง ์๋๋ค** (๋ฌดํ ๋ฃจํ)
- ํด๊ฒฐ: Left-recursive ๋ฌธ๋ฒ์ Right-recursive ๋ฌธ๋ฒ์ผ๋ก ๋ณํ
- Backtracking์ ๋นํจ์จ์ โ ๋ณด๋ค ํจ์จ์ ์ธ Top-Down Parsing์ด ํ์ํจ
---
# 4. Top-Down Parsing (2) - LL(1) Parser
## 4.1 Backtracking์ ์์ธ โ Production ์ ํ์ LL(k) Parsing์ผ๋ก ํ์ด๋ณด์
> ยง4.1์์๋ Recursive Descent Parsing์ ํต์ฌ ํ๊ณ์ธ backtracking์ด ์ ๋ฐ์ํ๋์ง ์ง๋๋ค. ์ด ์์ธ ํ์
์ด ยง4.2 ์ดํ์ ๋ฑ์ฅํ๋ LL(1) Parsing ์ ์ฒด์ ์ถ๋ฐ์ ์ด๋ค.
Recursive Descent Parsing์ non-terminal์ ๋ง๋ ๋๋ง๋ค production์ ํ๋ ๊ณจ๋ผ expandํ๋ค. ๋ฌธ์ ๋ **์ด๋ค production์ ๊ณจ๋ผ์ผ ํ ์ง ๋ชจ๋ฅธ๋ค๋ ๊ฒ**์ด๋ค. ์๋ชป ์ ํํ๋ฉด ํ๋ฆฐ ๊ฒ์ ์ธ์ํ๊ณ ๋๋์์์ผ ํ๋ค(backtracking).
์ด ๋นํจ์จ์ ์์ ๋ ค๋ฉด,
1. lookahead token์ ๋ณด๊ณ
2. **์ฌ๋ฐ๋ฅธ production์ ๋ฏธ๋ฆฌ ์์ธก**ํ ์ ์์ด์ผ ํ๋ค.
### 4.1.1 LL(k) Parsing
- **L**eft-to-right์ผ๋ก ์
๋ ฅ์ ์ฝ์ผ๋ฉด์
- **L**eft-most derivation์ ๊ตฌ์ฑํ๊ณ
- **k**๊ฐ์ token์ ๋ฏธ๋ฆฌ ์ดํด๋ณด๊ณ (lookahead) production์ ๊ฒฐ์ ํ๋ค.
- ๋ง์
๋ฌธ๋ฒ์์, E์ P๋ฅผ ์ ํํ ๋
- ๋ค์ token์ด 1์ด๋๊น
- \[number] ์ ํ
์ฐ๋ฆฌ๊ฐ ๋ค๋ฃจ๋ ๊ฒ์ k=1์ธ **LL(1) Parsing**์ด๋ค.
### 4.1.2 LL(1)์์ ์ฐ๋ฆฌ๊ฐ ํ์ด์ผ ํ ํต์ฌ ๋ฌธ์
$A \to \alpha \mid \beta$ ์ $a = \text{tokens}[\text{idx}+1]$ ์ด ์ฃผ์ด์ก์ ๋,
- `idx`๊ฐ ๋ญ์์ง? [[#3.2.1 ์
๋ ฅ ๋ฐ ๋ณ์]] ์ฐธ๊ณ !
$A \to \alpha$ ์ $A \to \beta$ **์ค ํ๋๋ฅผ backtracking ์์ด ์ ํ**ํ๋ ๊ฒ.
### 4.1.3 Recursive Descent Parsing๊ณผ์ ๋น๊ต โ ์ฌ์น์ฐ์ฐ ๋ฌธ๋ฒ
์๋์ ๋ฌธ์ ๋ฅผ, ์ด๋ฏธ ์๊ณ ์๋ Recursive Descent Parsing์ผ๋ก ํ์ด๋ณด์.
```plain
// ์ฌ์น์ฐ์ฐ ๋ฌธ๋ฒ 1: Left-Recursive
E ::= E + T
| E - T
| T
T ::= T * F
| T / F
| F
F ::= [id]
| [num]
| ( E )
```
`์ฌ์น์ฐ์ฐ ๋ฌธ๋ฒ 1`์ Left-Recursiveํจ.
โ Recursive Descent Parsing์ Left-Most Derivation์ ๋ฐ๋ฅด๋๋ฐ, [[#4.1.1 LL(k) Parsing]]
โ Left-Recursive๋ T๋ฅผ ๋ง๋๊ธฐ ์ ์ ๊ณ์ NT๋ก ๊ฐ
โ ๋ฌดํ ๋ฃจํ [[#3.4.1 `๋ฌธ์ ` Left-recursion]]
ํด๊ฒฐ์ ์ํด์๋,
[[#3.4.3 `ํด๊ฒฐ` ์ผ๋ฐ์ ์ธ Left-recursive โ Right-recursive]] ์ฒ๋ผ
Right-Recursive๋ก ๋ณํํด์ผ ํจ.
```plain
// ์ฌ์น์ฐ์ฐ ๋ฌธ๋ฒ 2: Left-Recursive๋ฅผ Right-Recursive๋ก ๋ณํ
E ::= T E'
E' ::= + T E'
| - T E'
|
T ::= F T'
T' ::= * F T'
| / F T'
|
F ::= [id]
| [num]
| ( E )
```
`์ฌ์น์ฐ์ฐ ๋ฌธ๋ฒ 2`๋ Right-Recursive
โ ์ด์ Recursive Descent Parsing ์๋ ๊ฐ๋ฅ.
```plain
// Recursive Descent Parsing ๊ณผ์ 1
Focus = E'
Tokens[idx] = -
```
์ฌ๊ธฐ์ ์ด๋ค Production์ ํํด์ผ ํ ๊น?
> [[#3.2 ๐จ Recursive Descent Parsing โ ์ ์]] ์ ๊ณผ์ ์ ๋ค์ ๋ณต๊ธฐํด๋ณด๋ฉด,
> Focus๊ฐ NT์ ์์ ๊ฒฝ์ฐ Case 1๋ก ๋์ด๊ฐ Production์ ๊ฒฐ์ ํ๋ค.
> ์ฌ๊ธฐ์๋ Focus๊ฐ E'์ ์์ผ๋ Case 1๋ก ๋์ด๊ฐ Production์ ๊ฒฐ์ ํด์ผ ํ๋ค.
์ฌ๊ธฐ์๋ 1๋ฒ์งธ(0-base) rule์ธ `E' โ - T E'` ์ ํํ๋ฉด,
`Tokens[idx] = -` ์ด๋ฏ๋ก,
๋ฐฑํธ๋ํน์ ์ข ํ๊ฒ ์ง๋ง Production ๊ณ ๋ฅด๋ ๋ฐ ์ฑ๊ณตํ๋ค.
```plain
// Recursive Descent Parsing ๊ณผ์ 2
Focus = E
Tokens[idx] = (
```
๋ค์ ๊ณผ์ ์ผ๋ก ๋์ด์์,
์ฌ๊ธฐ์๋ ์ด๋ค Production์ ํด์ผ ํ ๊น?
์ง๊ด์ ์ผ๋ก `(` ๋ฅผ ์๋นํ๊ณ ์ถ๋ค๋ฉด `F โ ( E )`๊ฐ ๋ง๋ ์ ํ์ด์ง๋ง,
๋ ๋ณต์กํ ๊ณผ์ ์ด ํ์ํ๋ค.
E์ production์ด `E โ T E'` ํ๋๋๊น ์ด๊ฑธ ์ ํํด ๋ณด์.
โ production์ด ํ๋๋ผ์ ๊ด์ฐฎ์๊น?
โ ๊ทผ๋ฐ `E โ T E'`๋ฅผ ์ ํํ๋ฉด T๋ก ๋ด๋ ค๊ฐ๊ณ ,
โ `T โ F T'`๋ก ๋ด๋ ค๊ฐ๊ณ
โ `F โ ( E )`... ์ด๋ ๊ฒ ๊ณ์ expandํด์ผ ํ๋ค.
โ ๊ฒฐ๊ตญ, ๊ฐ์ ๋ฌธ์ ๋ฅผ ๋ค์ ๋จ๊ณ์์ ๊ณ์ ๋ฐ๋ณต.
### 4.1.4 Recursive Descent Parsing๊ณผ์ ๋น๊ต โ ๊ฐ๋จํ ๋ฌธ๋ฒ
๋ค๋ฅธ ์์๋ฅผ ๋ณด์.
์ด๋ฒ์๋ Recursive Descent Parsing์ ์๋ํ๋ค.
```plain
// ๊ฐ๋จํ ๋ฌธ๋ฒ
S ::= A a
| B b
| c
A ::= x
|
B ::= y
|
```
ํ์ฑ ์คํ ์ค์ ์ด๋ฐ ๊ณผ์ ๋ ์์ ์ ์๋ค.
```plain
// Recursive Descent Parsing ๊ณผ์ 1
Focus = S
Tokens[idx] = a
```
์ฌ๊ธฐ์๋ ์ด๋ค Production์ ํํด์ผ ํ ๊น?
์ง๊ด์ ์ผ๋ก a๋ฅผ ์๋นํ๊ณ ์ถ๋ค๋ฉด
`S โ A a`์์ `A โ `๋ฅผ ์ป์ ์ ์์ผ๋ `S โ A a`๋ก ๊ฐ๋ ๊ฒ ๋ง์ง๋ง, ๊ทธ๋ด ์๊ฐ ์๋ค.
์ ๋ฐฉ๋ฒ์ด ์์ผ๋๊น ;;
A๊ฐ nullable์ด๋ผ `A a` ์์ ์ฒซ ํ ํฐ์ด `a`๊ฐ ๋ ์ ์๊ณ ,
B๋ nullable์ด์ง๋ง `B b` ์์ ์ฒซ ํ ํฐ์ `y` ์๋๋ฉด `b`์ง `a`๊ฐ ๋ ์ ์๋ค.
์ฆ ์ด๊ฑธ ํ๋จํ๋ ค๋ฉด,
"`A a` ๋ก๋ถํฐ ์ฒซ ๋ฒ์งธ๋ก ๋์ฌ ์ ์๋ terminal์ด ๋ญ๊ฐ"๋ฅผ **์ฒด๊ณ์ ์ผ๋ก ๊ณ์ฐ**ํด์ผ ํ๋ค
โ ์ฐ์ , FIRST๋ผ๋ ๊ฐ๋
์ ๋์
ํด๋ณด์.
## 4.2 FIRST(ฮณ) โ ฮต ์ ๋ ๊ฐ๋ฅ์ฑ์ ์ด๋ป๊ฒ ์ฐพ์ง?
> ยง4.1์์ "lookahead token์ ๋ณด๊ณ production์ ์์ธกํ์"๋ ์์ด๋์ด๋ฅผ ์ป์๋ค.
> ยง4.2์์๋ ๊ทธ ์์ธก์ ๊ทผ๊ฑฐ๊ฐ ๋๋ FIRST ์งํฉ์ ์ ์ํ๊ณ ๊ณ์ฐํ๋ ๋ฒ์ ๋ค๋ฃฌ๋ค.
>
> ๊ทธ๋ฐ๋ฐ ยง4.2.3์์ ๋ณด๋ฏ,
> FIRST๋ง์ผ๋ก๋ ฮต-production์ด ์๋ ๊ฒฝ์ฐ๋ฅผ ์ฒ๋ฆฌํ์ง ๋ชปํ๋ค.
> ์ด ๋ฌธ์ ๋ ยง4.3์ NULLABLE๊ณผ ยง4.4์ FOLLOW๋ก ์ด์ด์ง๋ค.
### 4.2.1 FIRST(ฮณ) ์ ์
> ๐ก $\gamma \in (T \cup NT)^+$ ์๋ค. NT, T ๋ค ํฌํจ๋ ๋ฌด์ธ๊ฐ์ธ๋ฐ $\epsilon$์ ์๋ ๊ฒ.
$\text{FIRST}(\gamma) = { a \in T \mid \gamma \Rightarrow^* a\beta \text{ for some } \beta }$
ฮณ๋ก๋ถํฐ ์ ๋๋ ์ ์๋ ๋ชจ๋ ๋ฌธ์ฅ์ **๊ฐ์ฅ ์ฒ์์ ๋ฑ์ฅํ ์ ์๋ terminal๋ค์ ์งํฉ**์ด๋ค.
#### 4.2.1.1 FIRST(ฮณ) ์์ โ ์ฌ์น์ฐ์ฐ ๋ฌธ๋ฒ
```
// ์ฌ์น์ฐ์ฐ ๋ฌธ๋ฒ
F ::= [id]
| [num]
| ( E )
// FIRST(ฮณ) ์์
FIRST(F) = { [id], [num], ( }
```
#### 4.2.1.2 FIRST(ฮณ) ํจ๊ณผ
- $A \to \gamma_1 \mid \gamma_2 \mid \cdots \mid \gamma_n$ ์ผ ๋,
- ๋ชจ๋ ์์ ๋ํด $\text{FIRST}(\gamma_i) \cap \text{FIRST}(\gamma_j) = \emptyset$ ์ด๋ฉด (์๋ก์์ด๋ฉด)
- $\forall i, j, \text{FIRST}(\gamma_i) \cap \text{FIRST}(\gamma_j) = \emptyset$
- lookahead token ํ๋๋ง ๋ณด๊ณ backtracking ์์ด production์ ๊ฒฐ์ ํ ์ ์๋ค.
โ ๊ทธ๋ผ ์ด๊ฑด ์ด๋ป๊ฒ ๊ณ์ฐํ ๊น?
### 4.2.2 FIRST(ฮณ) ๊ณ์ฐ ์์ด๋์ด โ NT๋ฅผ ๊ณ์ ํ์ฅํ์
| ๊ท์น ํํ | ๊ท๊ฒฐ |
| -------------------------------------- | ------------------------------------------- |
| $A \to a$ (T) | $\{a\} \subseteq \text{FIRST}(A)$ |
| $A \to B$ (NT) | $\text{FIRST}(B) \subseteq \text{FIRST}(A)$ |
| $A \to BC$, $B \to \epsilon \vert ...$ | $\text{FIRST}(C) \subseteq \text{FIRST}(A)$ |
์ธ ๋ฒ์งธ ๊ฒฝ์ฐ, $B$๊ฐ $\epsilon$์ ๋ง๋ค ์ **์์ ๋๋ง** C์ FIRST๊ฐ A์ FIRST์ ํฌํจ๋๋ค. ์ด๊ฒ์ด NULLABLE์ ํ์์ฑ์ผ๋ก ์ด์ด์ง๋ค.
### 4.2.3 FIRST ๊ณ์ฐ์ ํ๊ณ โ NULLABLE์ด ํ์ํ ์ด์
$A \to B,C$ ์ด๊ณ $B \to \epsilon$ ์ด ์ง์ ์์ง๋ง $B \Rightarrow^* \epsilon$ ์ธ ๊ฒฝ์ฐ,
๊ทธ ๊ฒฝ์ฐ์๋ B๊ฐ ์ฌ๋ผ์ง ์ ์์ผ๋๊น ๋ง์ฐฌ๊ฐ์ง๋ก FIRST(C) โ FIRST(A) ๊ฐ ์ฑ๋ฆฝํด์ผ ํ๋ค.
ํ์ง๋ง, ๋จ์ํ production ๊ท์น๋ง ๋ณด์์๋
B๊ฐ *์ต์ข
์ ์ผ๋ก* ์ฌ๋ผ์ง ์ ์๋์ง ์ ์ ์๋ค.
์ฆ, ฮต ์ ๋ ๊ฐ๋ฅ์ฑ - **NULLABLE** - ์ ๋ณ๋๋ก ๊ณ์ฐํด์ผ ํ๋ค.
## 4.3 NULLABLE(X) โ ฮต ์ ๋ ๊ฐ๋ฅ์ฑ ํ๋ณ
> ยง4.2.3์์ FIRST ๊ณ์ฐ์ด ๋งํ๋ ์ง์ ์ ํ์ธํ๋ค.
> P ์ฌ๋ฟ์ ๊ฑฐ์ณ ฮต์ผ๋ก ์ ๋๋ ๊ฒฝ์ฐ, ๋ฌธ๋ฒ๋ง ๋ด์๋ ์ ์ ์๋ค๋ ๊ฒ์ด๋ค.
>
> ยง4.3์์๋ ๊ทธ ๋งํ ์ง์ ์ ๋ซ์ด์ฃผ๋ NULLABLE์ ์ ์ํ๊ณ ์๊ณ ๋ฆฌ์ฆ์ผ๋ก ๊ณ์ฐํ๋ค.
> ์ด ๊ฒฐ๊ณผ๋ ยง4.2์ FIRST ์๊ณ ๋ฆฌ์ฆ๊ณผ ยง4.4์ FOLLOW ์๊ณ ๋ฆฌ์ฆ ๋ชจ๋์์ ์ฌ์ฉ๋๋ค.
### 4.3.1 NULLABLE(X) ์ ์
$X$๋ก๋ถํฐ $\epsilon$์ ์ ๋ํ ์ ์๋ค๋ฉด, NULLABLE($X$) = true.
์์์ผ๋ก ์ฐ๋ฉด,
$\text{NULLABLE}(X) = \text{true} \iff X \Rightarrow^* \epsilon$
โ ๊ทธ๋ผ ์ด๊ฑด ์ด๋ป๊ฒ ๊ณ์ฐํ ๊น?
### 4.3.2 NULLABLE(X) ๊ณ์ฐ ์์ด๋์ด โ NT๋ฅผ ๊ณ์ ํ์ฅํ์
[[#4.2.2 FIRST(ฮณ) ๊ณ์ฐ ์์ด๋์ด โ NT๋ฅผ ๊ณ์ ํ์ฅํ์]] ์ ๊ฐ์ ์์ด๋์ด!
์ต์ข
์ ์ผ๋ก $\epsilon$์ ๋ฟ๋ ๊ฒ ๋ชฉํ๋๊น, NT๋ฅผ ์ญ์ญ์ญ P๋ก ํ์ฅํ๋ฉฐ T๋ฅผ ์ฐพ์๊ฐ๋ฉด ๋๋ค.
### 4.3.3 NULLABLE(X) ์๊ณ ๋ฆฌ์ฆ โ ์ฝ๋
```
// NULLABLE(X) ๊ณ์ฐ ์๊ณ ๋ฆฌ์ฆ
์
๋ ฅ: (T, NT, S, P) // Grammar
๋ณ์:
// Map<T โช NT, bool>
// ์ด๊ธฐ๊ฐ: ๋ชจ๋ ฮฑ์ ๋ํด NULLABLE[ฮฑ] = false
NULLABLE โ {}
NULLABLE' // ์ด๋ฒ iteration์์ ๋ณํ๊ฐ ์์๋์ง ์ฒดํฌํ๊ธฐ ์ํ ๋ณต์ฌ๋ณธ
do
// ์ด๋ฒ ๋ฃจํ ์์ ์ ์ํ๋ฅผ ์ ์ฅ
NULLABLE' โ copy(NULLABLE)
// T, NT ์ค ํ๋์ธ ฮฑ์ ๋ํด
for ฮฑ โ T โช NT do
// ์ด๋ฏธ nullable๋ก ํ๋ช
๋ ๊ฑด ์คํต
if NULLABLE[ฮฑ] = true then continue
// ฮฑ๊ฐ T์ผ ๊ฒฝ์ฐ
elif ฮฑ โ T then
// ํฐ๋ฏธ๋์ ์ ๋ ฮต์ ์ ๋ํ ์ ์์
// ์ข๋ณ์ด๋๊น~
NULLABLE[ฮฑ] = false; continue
// ฮฑ๊ฐ T์ผ ๊ฒฝ์ฐ ๋ค ๊ฑธ๋ฌ์ก์ผ๋๊น
// ์ฌ๊ธฐ์๋ถํฐ ฮฑ๋ NT A
// A์ P ์งํฉ ์ค ํ๋ ฮณ๋ฅผ A๋ก ๋๊ณ , A์ ๋ํด
for A โ ฮณ โ P[A] do
// ฮณ = ฮณโฮณโ...ฮณโ ์ด๋ผ ํ ๋
if ฮณ = ฮต then
// production์ด ์ง์ ฮต์ด๋ฉด ๋ฐ๋ก nullable
NULLABLE[A] = true; break
elif all NULLABLE[ฮณแตข] = true then
// ฮณ๋ฅผ ๊ตฌ์ฑํ๋ ๋ชจ๋ ๊ธฐํธ๊ฐ nullable์ด๋ฉด
// A โ ฮณโฮณโ...ฮณโ โ* ฮต ์ด ๊ฐ๋ฅ
// ์ฆ A๋ nullable
NULLABLE[A] = true; break
// NULLABLE์ด ์ด๋ฒ ๋ฃจํ์์ ํ ๋ฒ๋ ์ ๋ฐ๋์์ผ๋ฉด ์ข
๋ฃ
// (๋ ์ด์ ์๋ก nullable๋ก ํ๋ช
๋ ๊ธฐํธ๊ฐ ์์)
while (NULLABLE โ NULLABLE')
```
### 4.3.4 NULLABLE(X) ์๊ณ ๋ฆฌ์ฆ โ ์ข
๋ฃ์ฑ
NULLABLE ๋งต์ ๊ฐ์ `false โ true` ๋ฐฉํฅ์ผ๋ก๋ง ๋ฐ๋ ์ ์๋ค.
$T \cup NT$๊ฐ ์ ํํ๋ฏ๋ก ๋ณ๊ฒฝ ๊ฐ๋ฅํ ํ์๋ ์ ํํ๊ณ ,
๊ทธ๋ฌ๋ฏ๋ก ์๊ณ ๋ฆฌ์ฆ์ ๋ฐ๋์ ์ข
๋ฃ๋๋ค.
### 4.3.4 NULLABLE(X) ์๊ณ ๋ฆฌ์ฆ โ ์์
```plain
// ์ฌ์น์ฐ์ฐ ๋ฌธ๋ฒ 3
S ::= E
E ::= T E'
E' ::= + T E'
| - T E'
|
T ::= F T'
T' ::= * F T'
| / F T'
|
F ::= S [id]
| [num]
| ( E )
```
NULLABLE์ ํ๋ก ํํํ๋ฉฐ ๋ฐ๋ผ๊ฐ ๋ณด์.
์์ ์ํ
| | NULLABLE |
| --- | -------- |
| S | false |
| E | false |
| E' | false |
| T | false |
| T' | false |
| F | false |
๊ณผ์
```plain
ฮฑ = S
ฮฑ๊ฐ NT์ด๋ฏ๋ก P[S]์ production ์ํ:
- S โ E
ฮณ = E, ฮณ = ฮต ์๋
NULLABLE[E] = false์ด๋ฏ๋ก all NULLABLE[ฮณแตข] = true ๋ถ๋ง์กฑ
โ NULLABLE[S] ๋ณํ ์์ (false ์ ์ง)
ฮฑ = E
ฮฑ๊ฐ NT์ด๋ฏ๋ก P[E]์ production ์ํ:
- E โ T E'
ฮณ = TE', ฮณ = ฮต ์๋
NULLABLE[T] = false์ด๋ฏ๋ก all NULLABLE[ฮณแตข] = true ๋ถ๋ง์กฑ
โ NULLABLE[E] ๋ณํ ์์ (false ์ ์ง)
ฮฑ = E'
ฮฑ๊ฐ NT์ด๋ฏ๋ก P[E']์ production ์ํ:
- E' โ + T E'
ฮณ = +TE', ฮณ = ฮต ์๋
NULLABLE[+] = false์ด๋ฏ๋ก ๋ถ๋ง์กฑ
- E' โ - T E'
ฮณ = -TE', ฮณ = ฮต ์๋
NULLABLE[-] = false์ด๋ฏ๋ก ๋ถ๋ง์กฑ
- E' โ ฮต
ฮณ = ฮต โ NULLABLE[E'] = true; break
โ NULLABLE[E'] = true๋ก ๋ณ๊ฒฝ! โ
ฮฑ = T
ฮฑ๊ฐ NT์ด๋ฏ๋ก P[T]์ production ์ํ:
- T โ F T'
ฮณ = FT', ฮณ = ฮต ์๋
NULLABLE[F] = false์ด๋ฏ๋ก ๋ถ๋ง์กฑ
โ NULLABLE[T] ๋ณํ ์์ (false ์ ์ง)
ฮฑ = E'
์ด๋ฏธ NULLABLE์ด๋ฏ๋ก ์คํต
ฮฑ = T'
ฮฑ๊ฐ NT์ด๋ฏ๋ก P[T']์ production ์ํ:
- T' โ * F T'
ฮณ = *FT', ฮณ = ฮต ์๋
NULLABLE[*] = false์ด๋ฏ๋ก ๋ถ๋ง์กฑ
- T' โ / F T'
ฮณ = /FT', ฮณ = ฮต ์๋
NULLABLE[/] = false์ด๋ฏ๋ก ๋ถ๋ง์กฑ
- T' โ ฮต
ฮณ = ฮต โ NULLABLE[T'] = true; break
โ NULLABLE[T'] = true๋ก ๋ณ๊ฒฝ! โ
ฮฑ = F
ฮฑ๊ฐ NT์ด๋ฏ๋ก P[F]์ production ์ํ:
- F โ [id]
NULLABLE[[id]] = false์ด๋ฏ๋ก ๋ถ๋ง์กฑ
- F โ [num]
NULLABLE[[num]] = false์ด๋ฏ๋ก ๋ถ๋ง์กฑ
- F โ ( E )
NULLABLE[(] = false์ด๋ฏ๋ก ๋ถ๋ง์กฑ
โ NULLABLE[F] ๋ณํ ์์ (false ์ ์ง)
// 1ํ ์ํ ๊ฒฐ๊ณผ:
// E', T'๋ง true๋ก ๋ฐ๋ โ NULLABLE โ NULLABLE' โ ๋ฃจํ ๊ณ์
// -----------------------------------------------
// 2๋ฒ์งธ iteration
ฮฑ = S
- S โ E
NULLABLE[E] = false โ ๋ถ๋ง์กฑ
โ ๋ณํ ์์
ฮฑ = E
- E โ T E'
NULLABLE[T] = false โ ๋ถ๋ง์กฑ (T'๊ฐ true์ฌ๋ T๊ฐ false๋ผ ์๋จ)
โ ๋ณํ ์์
ฮฑ = E' โ ์ด๋ฏธ true โ continue
ฮฑ = T
- T โ F T'
NULLABLE[F] = false โ ๋ถ๋ง์กฑ
โ ๋ณํ ์์
ฮฑ = T' โ ์ด๋ฏธ true โ continue
ฮฑ = F
- F โ [id], [num], (E)
์ ๋ถ false โ ๋ณํ ์์
// 2ํ ์ํ ๊ฒฐ๊ณผ:
// ์๋ฌด๊ฒ๋ ์ ๋ฐ๋ โ NULLABLE = NULLABLE' โ ์ข
๋ฃ!
// ์ต์ข
๊ฒฐ๊ณผ:
// E' = true, T' = true, ๋๋จธ์ง ์ ๋ถ false
```
์ต์ข
๊ฒฐ๊ณผ
| | NULLABLE |
| --- | -------- |
| S | false |
| E | false |
| E' | false |
| T | false |
| T' | false |
| F | false |
## 4.4 FIRST(ฮณ) โ NULLABLE์ ๋ฐ์ํ ์์ ํ ๋ฒ์
> ยง4.3์์ NULLABLE์ ๊ตฌํ๋ค.
> ยง4.4์์๋ ๊ทธ๊ฒ์ ์
๋ ฅ์ผ๋ก ๋ฐ์ FIRST๋ฅผ ์ฌ๋ฐ๋ฅด๊ฒ ๊ณ์ฐํ๋ ์๊ณ ๋ฆฌ์ฆ์ ์ ์ํ๋ค.
> ์ด FIRST ๊ฒฐ๊ณผ๋ ยง4.5์ FOLLOW ์๊ณ ๋ฆฌ์ฆ๊ณผ ยง4.6์ select ํจ์์์ ์ฌ์ฉ๋๋ค.
### 4.4.1 FIRST ์๊ณ ๋ฆฌ์ฆ โ ํต์ฌ ์๋ฆฌ
$A \to \alpha,\gamma,\beta$ ์ผ ๋, $\text{NULLABLE}(\alpha) = \text{true}$ ์ด๋ฉด
์ฆ,
$\alpha$๊ฐ NULLABLE์ด๋ฉด $\alpha$๊ฐ ์ ๋ถ ์ฌ๋ผ์ง๊ณ $\gamma$๊ฐ ์ฒซ ์๋ฆฌ์ ์ฌ ์ ์๋๋ฐ,
๊ทธ๋ ๋ค๋ฉด "$A$๋ก๋ถํฐ ์ ๋๋๋ ๋ฌธ์ฅ์ ๋งจ ์ฒซ terminal์ด $\gamma$์์ ๋์ฌ ์ ์์ผ๋ฏ๋ก"
$\text{FIRST}(\gamma) \subseteq \text{FIRST}(A)$
### 4.4.2 FIRST ์๊ณ ๋ฆฌ์ฆ โ ์ฝ๋
```
์
๋ ฅ: (T, NT, S, P) // Grammar
NULLABLE // ์์ ๊ณ์ฐํ NULLABLE ๋งต. Map<NT, bool>
๋ณ์:
// ๊ฐ ๊ธฐํธ์ FIRST ์งํฉ์ ์ ์ฅ. ์ด๊ธฐ๊ฐ์ ๋ชจ๋ ๊ณต์งํฉ
FIRST โ {} // Map<T โช NT, Set<T>>
FIRST' // ์ด๋ฒ iteration์์ ๋ณํ๊ฐ ์์๋์ง ์ฒดํฌํ๊ธฐ ์ํ ๋ณต์ฌ๋ณธ
do
FIRST' โ copy(FIRST)
for ฮฑ โ T โช NT do
if ฮฑ โ T then
// ํฐ๋ฏธ๋ a์ FIRST๋ ์๊ธฐ ์์
// ex) FIRST(+) = {+}
FIRST[a] = {a}; continue
// ์ฌ๊ธฐ์๋ถํฐ ฮฑ๋ non-terminal A
for A โ ฮณ โ P[A] do
// ฮณ = ฮณโฮณโ...ฮณโ (๊ฐ ฮณแตข๋ T ๋๋ NT)
// ฮณ๋ฅผ ๋๋ฉฐ
for 1 โค i โค n do
if i = 1 then
// ์ฒซ ๋ฒ์งธ ๊ธฐํธ์ FIRST๋ ๋ฌด์กฐ๊ฑด A์ FIRST์ ํฌํจ
// ex) A โ B C ์์ FIRST(B) โ FIRST(A)
FIRST[A] = FIRST[A] โช FIRST[ฮณโ]
elif NULLABLE[ฮณแตขโโ] = false then
// ๋ฐ๋ก ์ ๊ธฐํธ ฮณแตขโโ์ด nullableํ์ง ์์ผ๋ฉด
// ฮณแตขโโ์ด ๋ฐ๋์ ๋ญ๊ฐ๋ฅผ ๋ง๋ค์ด๋ด๋ฏ๋ก
// ฮณแตข ์ดํ๋ ์ฒซ ๋ฒ์งธ๋ก ์ฌ ์ ์์ โ ๋ ๋ณผ ํ์ ์์
break
else
// ฮณแตขโโ์ด nullableํ๋ฉด ฮณแตขโโ์ด ์ฌ๋ผ์ง ์ ์์ผ๋ฏ๋ก
// ฮณแตข๊ฐ ์ฒซ ๋ฒ์งธ๋ก ์ฌ ์ ์์
// โ FIRST[ฮณแตข] โ FIRST[A]
FIRST[A] = FIRST[A] โช FIRST[ฮณแตข]
// FIRST๊ฐ ์ด๋ฒ ๋ฃจํ์์ ํ ๋ฒ๋ ์ ๋ฐ๋์์ผ๋ฉด ์ข
๋ฃ
// (๋ ์ด์ ์ถ๊ฐ๋ ์์๊ฐ ์์)
while (FIRST โ FIRST')
```
### 4.4.3 FIRST ์๊ณ ๋ฆฌ์ฆ โ ์ข
๋ฃ์ฑ
FIRST ์งํฉ์ ์์๋ ์ถ๊ฐ๋ง ๋๊ณ ์ญ์ ๋์ง ์๋๋ค.
Terminal ์งํฉ์ด ์ ํํ๋ฏ๋ก ๋ฐ๋์ ์ข
๋ฃ๋๋ค.
### 4.4.4 FIRST ์๊ณ ๋ฆฌ์ฆ โ ์์
์ด๊ธฐ ์ํ
(๋ชจ๋ ๋น์ด ์์)
| ๊ธฐํธ | NULLABLE | FIRST |
| --- | -------- | ----- |
| S | false | |
| E | false | |
| E' | true | |
| T | false | |
| T' | true | |
| F | false | |
๊ณผ์
๋์ค์ ์๊ฐ ๋๋ฉด ๋ณด์; ์ดํด๋ ํ์ผ๋๊น
์ต์ข
๊ฒฐ๊ณผ
| ๊ธฐํธ | NULLABLE | FIRST |
| --- | -------- | ------------------ |
| S | false | { [id], [num], ( } |
| E | false | { [id], [num], ( } |
| E' | true | { +, - } |
| T | false | { [id], [num], ( } |
| T' | true | { *, / } |
| F | false | { [id], [num], ( } |
## 4.5 FOLLOW(ฮณ) โ NULLABLEํ production ์ ํ์ ์ํ ๋๊ตฌ
> ยง4.4๊น์ง ๊ตฌํ FIRST๋ง์ผ๋ก๋ ๋ง์ ๊ฒฝ์ฐ production์ ๊ฒฐ์ ํ ์ ์๋ค.
> ๊ทธ๋ฌ๋ ยง4.5.1์ ์์์ฒ๋ผ, focus๊ฐ NULLABLEํ non-terminal์ด๊ณ lookahead token์ด FIRST์ ์์ ๋๋ "ฮต-production์ ์ ํํด๋ ๋๋๊ฐ?"๋ฅผ ํ๋จํ ์ ์๋ค. ยง4.5์์๋ ์ด ํ๋จ์ ๊ฐ๋ฅํ๊ฒ ํ๋ FOLLOW๋ฅผ ์ ์ํ๊ณ ๊ณ์ฐํ๋ค. FIRST์ FOLLOW๊ฐ ๋ชจ๋ ์ค๋น๋๋ฉด ยง4.6์ select ํจ์๋ฅผ ์์ฑํ ์ ์๋ค.
### 4.5.1 FOLLOW๊ฐ ํ์ํ ์ํฉ
๋ค์ Recursive Descent Parsing์ ์ํ ์ค์ผ ๋,
```
Focus = E'
Tokens[idx] = )
E' ::= + T E'
| - T E'
|
```
lookahead `)`๋ FIRST(E')์ ์๋ค. ๊ทธ๋ ๋ค๋ฉด $E' \to \epsilon$์ ์ ํํด๋ ๋๋๊ฐ?
โ `)` ๊ฐ E' ๋ค์์ ์ฌ ์ ์๋ token์ด๋ผ๋ฉด ๊ฐ๋ฅํ๋ค. ์ด๊ฒ์ด FOLLOW์ด๋ค.
### 4.5.2 FOLLOW(ฮณ) ์ ์
$\text{FOLLOW}(\gamma) = { a \in T \mid \exists, \alpha, \beta,, S \Rightarrow^* \alpha,\gamma,a,\beta }$
ฮณ์ **๋ฐ๋ก ์ค๋ฅธ์ชฝ์ ๋ฑ์ฅํ ์ ์๋ terminal๋ค์ ์งํฉ**.
- $\{)\} \subseteq \text{FOLLOW}(E)$
- $F \to (E)$ ์์ E ์ค๋ฅธ์ชฝ์ `)`
- $\text{FOLLOW}(S) = \{\$\}$ โ S๋ ์์ ๊ธฐํธ์ด๋ฏ๋ก ์ค๋ฅธ์ชฝ์ EOF($)๋ง
### 4.5.3 FOLLOW ์๊ณ ๋ฆฌ์ฆ โ ํต์ฌ ์๋ฆฌ
| ๊ท์น ํํ | ๊ท๊ฒฐ |
| --------------------------------------------------------------------------------- | ------------------------------------------------------ |
| $A \to \alpha \gamma \beta \delta$, $\text{NULLABLE}(\beta) = \text{true}$ | $\text{FIRST}(\delta) \subseteq \text{FOLLOW}(\gamma)$ |
| $A \to \alpha \gamma \beta \delta$, $\text{NULLABLE}(\beta\delta) = \text{true}$ | $\text{FOLLOW}(A) \subseteq \text{FOLLOW}(\gamma)$ |
| | |
- ฮณ ๋ฐ๋ก ๋ค์์ ฮฒ๊ฐ ์๋๋ฐ, ฮฒ๊ฐ nullable์ด๋ฉด ฮฒ๊ฐ ์ฌ๋ผ์ง ์ ์์.
- ๊ทธ๋ฌ๋ฉด ฮณ ๋ค์์ ฮด๊ฐ ๋ฐ๋ก ์ฌ ์ ์์ผ๋๊น,
- ฮด์ ์ฒซ ๋ฒ์งธ terminal๋ค์ด ฮณ์ FOLLOW์ ํฌํจ.
- ๋ง์ฐฌ๊ฐ์ง๋ก, ฮฒฮด๊ฐ NULLABLE์ด๋ฉด ฮฒฮด๊ฐ ๋ชจ๋ ์ฌ๋ผ์ง ์ ์์.
- ๊ทธ๋ฌ๋ฉด ฮณ ์ดํ๊ฐ ์ ๋ถ ์ฌ๋ผ์ง ์ ์์.
- ๊ทธ๋ ๋ค๋ฉด ฮณ ๋ค์์ ์ฌ ์ ์๋ ๊ฒ ๊ณง $A$ ๋ค์์ ์ฌ ์ ์๋ ๊ฒ๊ณผ ๊ฐ์์ง.
> ๐ก $\text{NULLABLE}(\beta\delta) = \text{NULLABLE}(\beta) \wedge \text{NULLABLE}(\delta)$
### 4.5.4 FOLLOW ์๊ณ ๋ฆฌ์ฆ โ ์ฝ๋
```
์
๋ ฅ: (T, NT, S, P), NULLABLE, FIRST
๋ณ์: FOLLOW โ {} // MAP<T U NT, Set<T>>
FOLLOW' โ {} // ๋ณต๋ถํด์ iteration๋ง๋ค ํ์ธ์ฉ
do
FOLLOW' โ copy(FOLLOW)
for ฮฑ โ T โช NT do
// ํฐ๋ฏธ๋์ production์ ์ข๋ณ์ด ๋ ์ ์์ผ๋ฏ๋ก ์ถ์ ํ ํ์ ์์
if ฮฑ โ T then continue
// ์ฌ๊ธฐ์๋ถํฐ ฮฑ๋ non-terminal A
for A โ ฮณ โ P[A] do
// ฮณ = ฮณโ ฮณโ โฆ ฮณโ
// ฮณ ์์ ๊ฐ ๊ธฐํธ ฮณแตข์ ๋ํด FOLLOW๋ฅผ ๊ณ์ฐ
for 1 โค i โค n do
if โj โ {i+1,โฆ,n} NULLABLE(ฮณโฑผ) then
// ฮณแตข ๋ค์ ๋ชจ๋ ๊ธฐํธ(ฮณแตขโโโฆฮณโ)๊ฐ ์ ๋ถ nullable์ด๋ฉด
// ฮณแตข ์ดํ๊ฐ ์ ๋ถ ์ฌ๋ผ์ง ์ ์์
// โ ฮณแตข๊ฐ ์ฌ์ค์ A์ ๋งจ ๋์ด ๋๋ฏ๋ก
// โ A ๋ค์์ ์ค๋ ๊ฒ์ด ๊ณง ฮณแตข ๋ค์์ ์ฌ ์ ์์
FOLLOW(ฮณแตข) = FOLLOW(ฮณแตข) โช FOLLOW(A)
for i < j โค n do
if โk โ {i+1,โฆ,j-1} NULLABLE(ฮณโ) then
// ฮณแตข์ ฮณโฑผ ์ฌ์ด์ ๋ชจ๋ ๊ธฐํธ๊ฐ nullable์ด๋ฉด
// ๊ทธ ์ฌ์ด๊ฐ ์ ๋ถ ์ฌ๋ผ์ ธ์ ฮณโฑผ๊ฐ ฮณแตข ๋ฐ๋ก ๋ค์์ ์ฌ ์ ์์
// โ ฮณโฑผ์ ์ฒซ terminal์ด ฮณแตข ๋ค์์ ์ฌ ์ ์์
FOLLOW(ฮณแตข) = FOLLOW(ฮณแตข) โช FIRST(ฮณโฑผ)
while (FOLLOW โ FOLLOW')
```
### 4.5.5 FOLLOW ์๊ณ ๋ฆฌ์ฆ โ ์ข
๋ฃ์ฑ
FOLLOW ์งํฉ๋ ๋จ์กฐ ์ฆ๊ฐํ๋ฉฐ Terminal ์งํฉ์ด ์ ํํ๋ฏ๋ก ๋ฐ๋์ ์ข
๋ฃ๋๋ค.
### 4.5.6 FOLLOW ์๊ณ ๋ฆฌ์ฆ โ ์์
์ ์ด๊ฒ๋ ๋์ค์ ใ
ใด๊ธํจ์ง๊ธ
|๊ธฐํธ|NULLABLE|FIRST|FOLLOW|
|---|---|---|---|
|S|false|[id] [num] (|$|
|E|false|[id] [num] (|$ )|
|E'|true|+ -|$ )|
|T|false|[id] [num] (|$ + - )|
|T'|true|* /|$ + - )|
|F|false|[id] [num] (|$ + - * / )|
## 4.6 LL(1) Parsing ์๊ณ ๋ฆฌ์ฆ โ select์ Parsing Table
> ยง4.2~4.5์์ NULLABLE, FIRST, FOLLOW๋ฅผ ๋ชจ๋ ๊ตฌํ๋ค.
> ยง4.6์์๋ ์ด ์ธ ๊ฐ์ง๋ฅผ ์ค์ production ์ ํ ํจ์ select๋ก ํตํฉํ๊ณ ,
> ์ด๋ฅผ 2D ํ
์ด๋ธ๋ก ๊ตฌํํ์ฌ O(1)์ production์ ๊ฒฐ์ ํ๋ Parsing Table์ ๋ง๋ ๋ค.
### 4.6.1 LL(1) Parsing ์๊ณ ๋ฆฌ์ฆ โ ์ฝ๋ โ select๊ฐ ๋ญ๊น?
```pseudo
// ์ ์ฒด
์
๋ ฅ: (T, NT, S, P) // Grammar
tokens // Token๋ค์ list (Lexer๊ฐ ์คฌ์ผ๋!)
๋ณ์:
tree โ S // ํ์คํธ๋ฆฌ์ ๋ฃจํธ ๋
ธ๋ (์์ฑ: parent, children, rule)
focus โ S // ํ์ฌ ์ฒ๋ฆฌ ์ค์ธ ํธ๋ฆฌ ๋
ธ๋
idx โ 0 // ํ์ฌ ์ฝ๊ณ ์๋ token์ ์์น
stack โ [] // ์์ง ์ฒ๋ฆฌํ์ง ์์ ๋
ธ๋๋ค์ ์์๋๋ ์คํ
while (true) do
if (focus โ NT) then
// focus๊ฐ non-terminal์ด๋ฉด production์ ์ ํํด expand
goto Case 1
else if (idx < len(tokens) && focus = tokens[idx]) then
// focus๊ฐ terminal์ด๊ณ ํ์ฌ token๊ณผ ์ผ์นํ๋ฉด ์๋น
goto Case 2
else if (idx = len(tokens) && stack = []) then
// ๋ชจ๋ token์ ์๋นํ๊ณ ์คํ๋ ๋น์์ผ๋ฉด ํ์ฑ ์ฑ๊ณต
return tree
// LL(1)์์๋ backtracking ์์
// else goto Case 3 // Backtrack โ ์ญ์ ๋จ
```
```pseudo
// Case 1
// Recursive Descent ๋ฒ์ (์ญ์ ๋จ):
// (focus โ ฮฑโ...ฮฑโ) โ P[focus][focus.rule]
// focus.rule โ focus.rule + 1
// โ production์ ์์๋๋ก ํ๋์ฉ ์๋ํ์ (backtracking ๋ฐ์ ์์ธ)
// ๊ธฐ์กด Recursive Descent์์ ์ฐจ์ด
// production์ `focus.rule` ์์๋ก ์๋ํ๋ ๋์ ,
// Parsing Table ์กฐํ ํ ๋ฒ์ผ๋ก production์ ๋ฐ๋ก ๊ฒฐ์ .
// ๊ทธ๋ฌ๋ฏ๋ก Backtracking๋ ์ฌ๋ผ์ง๋ค.
// LL(1) ๋ฒ์ :
// select๋ก lookahead token์ ๋ณด๊ณ production์ ๋ฑ ํ๋ ๊ฒฐ์
(focus โ ฮฑโ...ฮฑโ) โ select(P, focus, tokens[idx+1])
for 1 โค i โค n do
// ์ ํํ production์ ๊ธฐํธ๋ค์ ํธ๋ฆฌ์ ์์์ผ๋ก ์ฐ๊ฒฐ
connect(focus, ฮฑแตข)
for n โฅ i โฅ 2 do
// ์ฒซ ๋ฒ์งธ(ฮฑโ) ๋นผ๊ณ ๋๋จธ์ง๋ฅผ ์ญ์์ผ๋ก ์คํ์ push
// (๋์ค์ ์์๋๋ก ์ฒ๋ฆฌํ๊ธฐ ์ํด)
stack.push(ฮฑแตข)
// ์ฒซ ๋ฒ์งธ ์์์ ๋ค์ focus๋ก
focus โ ฮฑโ
```
```pseudo
// Case 2
// focus๊ฐ terminal์ด๊ณ ํ์ฌ token๊ณผ ์ผ์นํ๋ ์ํฉ
// ํ์ฌ token์ ์๋นํ๊ณ ๋ค์ token์ผ๋ก ์ด๋
idx โ idx + 1
// ์คํ์์ ๋ค์์ผ๋ก ์ฒ๋ฆฌํ ๋
ธ๋๋ฅผ ๊บผ๋
focus โ stack.pop()
```
### 4.6.2 LL(1) Parsing ์๊ณ ๋ฆฌ์ฆ โ select(P, focus, lookahead)
#### 4.6.2.1 select โ ์์ด๋์ด
select๋ ๊ฒฐ๊ตญ ์ด๋ค Production์ ๊ณจ๋ผ์ผ ํ๋์ง ์ ํํจ.
focus๊ฐ A๊ณ , A -> a | b | c ... ๋ญ ์ด๋ฐ ์์ผ๋ก ์๋ค๊ณ ์น๋ฉด,
production์ด ์ฌ๋ฌ ๊ฐ์ผ ๋, lookahead token์ ๋ณด๊ณ **์ด๋ค production์ ๊ณจ๋ผ์ผ ํ๋๊ฐ**๋ฅผ ๊ฒฐ์ !
focus $\leftarrow \alpha$ ์ ๋ํด:
focus๊ฐ $\alpha$๋ก ์ ๊ฐ๋๋ ๊ฒฝ์ฐ์,
focus๊ฐ A์ผ ๋, $A \to \alpha$ ๋ผ๋ production ํ๋ณด์ ๋ํด:
**๊ฒฝ์ฐ 1:** $\text{lookahead} \in \text{FIRST}(\alpha)$ ์ด๋ฉด โ $\alpha$๋ฅผ ์ ๊ฐํ์ ๋ ์ฒซ ๋ฒ์งธ๋ก lookahead๊ฐ ๋์ฌ ์ ์์ผ๋๊น โ **$A \to \alpha$ ์ ํ**
**๊ฒฝ์ฐ 2:** $\text{NULLABLE}(\alpha) = \text{true}$ ์ด๊ณ $\text{lookahead} \in \text{FOLLOW}(\alpha)$ ์ด๋ฉด โ $\alpha$๊ฐ ํต์งธ๋ก ์ฌ๋ผ์ง ์ ์๊ณ , ์ฌ๋ผ์ง ํ์ lookahead๊ฐ ๋ฐ๋ก ์ฌ ์ ์์ผ๋๊น โ **$A \to \alpha$ ์ ํ**
๋ ๋ค ํด๋น ์์ผ๋ฉด โ ์ด production์ ํ๋ณด์์ ํ๋ฝ.
| ์กฐ๊ฑด | ์ ํ |
| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------- |
| $\text{lookahead} \in \text{FIRST}(\alpha)
lt;br>โ $\alpha$๋ฅผ ์ ๊ฐํ์ ๋ ์ฒซ ๋ฒ์งธ๋ก ๋์ฌ ์ ์๋ ๊ฒ๋ค ์ค์<br>โ lookahead๊ฐ ์์ผ๋๊น<br>โ **$A \to \alpha$ ์ ํ** | focus $\leftarrow \alpha$ ์ ํ |
| $\text{NULLABLE}(\alpha) = \text{true}$ ์ด๊ณ $\text{lookahead} \in \text{FOLLOW}(\alpha)lt;br>โ $\alpha$๊ฐ ํต์งธ๋ก ์ฌ๋ผ์ง ์ ์๊ณ ,<br>โ ์ฌ๋ผ์ง ํ์ ๊ทธ ๋ค๋ก lookahead๊ฐ ๋ฐ๋ก ์ฌ ์ ์์ผ๋๊น <br>โ **$A \to \alpha$ ์ ํ**<br> | focus $\leftarrow \alpha$ ์ ํ |
#### 4.6.2.2 select โ ์์
**๋ฌธ๋ฒ**
```
S ::= E
E ::= T E'
E' ::= + T E'
| - T E'
| ฮต
T ::= F T'
T' ::= * F T'
| / F T'
| ฮต
F ::= [id]
| [num]
| ( E )
```
**NULLABLE / FIRST / FOLLOW ํ**
| |NULLABLE|FIRST|FOLLOW|
|---|---|---|---|
|S|false|[id] [num] (|$|
|E|false|[id] [num] (|$ )|
|E'|true|+ -|$ )|
|T|false|[id] [num] (|$ + - )|
|T'|true|* /|$ + - )|
|F|false|[id] [num] (|$ + - * / )|
**select ํ** = Parsing Table
| | + | - | * | / | [id] | [num] | ( | ) | $ |
| --- | ------- | ------- | ------- | ------- | ------ | ------- | ----- | --- | --- |
| S | | | | | SโE | SโE | SโE | | |
| E | | | | | EโTE' | EโTE' | EโTE' | | |
| E' | E'โ+TE' | E'โ-TE' | | | | | | E'โ | E'โ |
| T | | | | | TโFT' | TโFT' | TโFT' | | |
| T' | | | T'โ*FT' | T'โ/FT' | | | | T'โ | T'โ |
| F | | | | | Fโ[id] | Fโ[num] | Fโ(E) | | |
### 4.6.3 LL(1) Parsing ์๊ณ ๋ฆฌ์ฆ โ Parsing Table
select๋ฅผ 2์ฐจ์ ํ
์ด๋ธ๋ก ๊ตฌํํ ๊ฒ.
- **Row**: focus (non-terminal)
- **Column**: lookahead (terminal)
- **Entry**: ์ ํํ production
- **๋น ์นธ**: ์ค๋ฅ(Error)
| | + | - | * | / | [id] | [num] | ( | ) | $ |
| --- | ------- | ------- | ------- | ------- | ------ | ------- | ----- | --- | --- |
| S | | | | | SโE | SโE | SโE | | |
| E | | | | | EโTE' | EโTE' | EโTE' | | |
| E' | E'โ+TE' | E'โ-TE' | | | | | | E'โ | E'โ |
| T | | | | | TโFT' | TโFT' | TโFT' | | |
| T' | | | T'โ*FT' | T'โ/FT' | | | | T'โ | T'โ |
| F | | | | | Fโ[id] | Fโ[num] | Fโ(E) | | |
## 4.7 LL(1) Parsing์ ํ๊ณ โ Conflict
> ยง4.6์ Parsing Table์ด ์ ๋์ํ๋ ค๋ฉด ๊ฐ ์นธ์ production์ด **์ ํํ ํ๋**์ฌ์ผ ํ๋ค. ยง4.7์์๋ ์นธ์ production์ด ๋ ๊ฐ ์ด์ ๋ค์ด์ค๋ ์ถฉ๋(Conflict) ์ํฉ๊ณผ ๊ทธ ํด๊ฒฐ ์ ๋ต์ ๋ค๋ฃฌ๋ค.
### 4.7.1 FIRST/FIRST Conflict โ Left Factoring์ผ๋ก ํด๊ฒฐ
$A \to \alpha \mid \beta$ ์ผ ๋ $\text{FIRST}(\alpha) \cap \text{FIRST}(\beta) \neq \emptyset$ (์๋ก์๊ฐ ์๋) ๊ฒฝ์ฐ
โ ๊ฐ์ lookahead์ production์ด ๋ ๊ฐ ๋์๋๋ค. (Parsing Table์ ํ ์นธ์ ๋ P๊ฐ ๋ค์ด์จ๋ค)
**๋ํ ์์ธ: Left-recursion**
```
E ::= E + a | b
โ FIRST(E + a) = FIRST(E) = { b }
โ FIRST(b) = { b }
โ ์ถฉ๋!
```
**Left-recursion์ด ์์ด๋ ๋ฐ์ ๊ฐ๋ฅ**
```
S ::= E
| E a
E ::= b
|
```
E๊ฐ nullable์ด๋๊น:
- FIRST(E) = {b} ์ด๊ณ NULLABLE(E) = true
- FIRST(E a) = FIRST(E) โช {a} = {b, a} (E๊ฐ nullable์ด๋๊น a๋ ํฌํจ)
๊ทธ๋ฌ๋ฉด select ํ์์ focus = S, lookahead = `b` ์ผ ๋:
(๋ฌธ๋ฒ ๋ณด๊ณ ์๊ฐํด๋ณด๋ฉด)
- SโE : b โ FIRST(E) โ ๊ฒฝ์ฐ 1 โ ํด๋น
- SโE a : b โ FIRST(E a) โ ๊ฒฝ์ฐ 1 โ ํด๋น
โ ๊ฐ์ ์นธ์ ๋ ๊ฐ โ **FIRST/FIRST Conflict**
**ํด๊ฒฐ: Right-recursion์ผ๋ก ๋ณํ + Left Factoring**
๊ณตํต prefix๋ฅผ factoringํ์ฌ ๋ถ๋ฆฌํ๋ค.
```
// ์๋ณธ (์ถฉ๋)
S ::= E
| E a
E ::= b
|
// Left Factoring ํ
// S์ ์ฐ๋ณ์ด E, E a๋ฏ๋ก E๋ผ๋ ๊ณตํต prefix๊ฐ ์์
// ๊ทธ๋ฌ๋๊น ๋๋จธ์ง ๋ถ๋ถ์ S'๋ก ๋บ
S ::= E S'
S' ::=
| a
E ::= b
|
```
๊ทธ๋ฌ๋ฉด select ํ์์:
- focus = S์ผ ๋๋ ๋ฌด์กฐ๊ฑด SโE S' ํ๋๋ฟ โ conflict ์์
- focus = S'์ผ ๋ lookahead๊ฐ `a`๋ฉด S'โa, `