Syntax Analysis Part 3
COMP321 Compiler โ Syntax Analysis Part 3
Kyungpook National University | Hwisoo So | Spring 2026
๐ 1ํ์ด์ง โ ์ ๋ชฉ
Syntax Analysis โ 3
๊ตฌ๋ฌธ ๋ถ์ โ 3
์ด๋ฒ ๊ฐ์๋ Syntax Analysis (๊ตฌ๋ฌธ ๋ถ์)์ ์ธ ๋ฒ์งธ ํํธ๋ค.
์ฆ ์ง๊ธ๋ถํฐ๋ ์ปดํ์ผ๋ฌ์์ Lexical Analysis(ํ ํฐํ) ๋ค์ ๋จ๊ณ, ๋ฌธ์ฅ ๊ตฌ์กฐ๋ฅผ ์ดํดํ๋ ๋จ๊ณ๋ฅผ ๋ค๋ฃจ๋ ๋ด์ฉ์ด๋ค.
- Hwisoo So โ ์ํ์ (๊ฐ์ ๋ด๋น ๊ต์)
- Kyungpook National University โ ๊ฒฝ๋ถ๋ํ๊ต
- COMP321 Compiler Spring 2026 โ ์ปดํ์ผ๋ฌ ๊ณผ๋ชฉ, 2026๋ ๋ดํ๊ธฐ
๐ผ ๊ทธ๋ฆผ ์ค๋ช
- ๊ฐ์ด๋ฐ: โSyntax Analysis โ 3โ
- ์๋: ๊ต์ ์ด๋ฆ + ํ๊ต ๋ก๊ณ
- ์ค๋ฅธ์ชฝ ์: ๊ณผ๋ชฉ ์ ๋ณด
์ด ํ์ด์ง๋ ์์ ํ ํ์ง(slide cover)๋ค. ๋ด์ฉ ์์, ๋จ์ํ ๊ฐ์ ์์ ์๋ฆผ ์ญํ .
๐ 2ํ์ด์ง โ Outlook (์ ์ฒด ๊ฐ์)
Syntax Analysis COMP321@KNU
Outlook
์ ์ฒด ๊ฐ์ / ์งํ ๋ด์ฉ
| ํญ๋ชฉ | ์ํ |
|---|---|
| Syntax and Semantics of Programming Languages | โ ์๋ฃ |
| Specifying the Syntax of a programming language | โ ์๋ฃ |
| CFGs, BNF and EBNF | โ ์๋ฃ โ CFG, BNF, EBNF (๋ฌธ๋ฒ ์ ์ ํ์๋ค) |
| Grammar transformations | โ ์๋ฃ โ Left factoring, left recursion ์ ๊ฑฐ ๋ฑ |
| Top-down parsing (LL) | โ ์๋ฃ |
| Recursive descent (LL) parser construction | โ ์ง๊ธ ์ฌ๊ธฐ |
| LL Grammars | ์์ |
| AST Construction | ์์ |
| Parse trees vs. ASTs | ์์ |
| Chomskyโs Hierarchy | ์์ |
์ง๊ธ ์์น
๐ Parsing ์ค์์๋ Recursive Descent Parser ๋ถ๋ถ ์์
๐ 3ํ์ด์ง โ Recursive Descent Parsing
Recursive Descent Parsing
์ฌ๊ท ํ๊ฐ ํ์ฑ
Recursive descent parsing is a straightforward LL (top-down) parsing method.
์ฌ๊ท ํ๊ฐ ํ์ฑ์ ๋จ์ํ LL(ํํฅ์) ํ์ฑ ๋ฐฉ๋ฒ์ด๋ค.
- LL = Left to right + Leftmost derivation
- top-down ๋ฐฉ์
- ๊ตฌํ ์ฌ์ / ํจ์ ํธ์ถ ๊ตฌ์กฐ๋ก ๋ง๋ ๋ค
We will now look at how to develop a recursive descent parser from an EBNF specification.
์ด์ EBNF ๋ช ์ธ๋ก๋ถํฐ ์ฌ๊ท ํ๊ฐ ํ์๋ฅผ ๋ง๋๋ ๋ฐฉ๋ฒ์ ์ดํด๋ณธ๋ค.
ํต์ฌ: ๋ฌธ๋ฒ โ ์ฝ๋๋ก ๋ณํ
Key idea: the parse tree structure corresponds to the callerโcallee relationship of parsing procedures that call each other at runtime.
ํต์ฌ ์์ด๋์ด: ํ์คํธ๋ฆฌ ๊ตฌ์กฐ๋ ์คํ ์ ์๋ก ํธ์ถํ๋ ํ์ฑ ํจ์๋ค์ ํธ์ถ ๊ด๊ณ์ ๋์๋๋ค.
โ ํต์ฌ ๊ฐ๋ : ํ์คํธ๋ฆฌ ๊ตฌ์กฐ = ํจ์ ํธ์ถ ๊ตฌ์กฐ
Sentence
โโโ Subject
โโโ Verb
โโโ Object
โ ์ค์ ์ฝ๋:
parseSentence()
-> parseSubject()
-> parseVerb()
-> parseObject()
์ฆ ํธ๋ฆฌ = ํจ์ ํธ์ถ ํธ๋ฆฌ
๐ 4ํ์ด์ง โ Recursive Descent Parser Construction Example
Recursive Descent Parser Construction Example
์ฌ๊ท ํ๊ฐ ํ์ ๊ตฌ์ฑ ์์
๋ฌธ๋ฒ ์ ์
Sentence ::= Subject Verb Object .
Subject ::= I | a Noun | the Noun
Object ::= me | a Noun | the Noun
Noun ::= cat | mat | rat
Verb ::= like | is | see | sees
| ๊ท์น | ์๋ฏธ |
|---|---|
| Sentence | ์ฃผ์ด + ๋์ฌ + ๋ชฉ์ ์ด + โ.โ |
| Subject | I / a+๋ช ์ฌ / the+๋ช ์ฌ |
| Object | me / a+๋ช ์ฌ / the+๋ช ์ฌ |
| Noun | cat / mat / rat |
| Verb | like / is / see / sees |
Define a procedure parseN for each non-terminal N
๊ฐ non-terminal N๋ง๋ค parseN ํจ์๋ฅผ ์ ์ํ๋ค.
parseSentence()
parseSubject()
parseObject()
parseNoun()
parseVerb()
โ ํต์ฌ ๊ท์น: ๋ฌธ๋ฒ โ ํจ์ 1:1 ๋งคํ
| ๋ฌธ๋ฒ | ํจ์ |
|---|---|
| Sentence | parseSentence |
| Subject | parseSubject |
| Object | parseObject |
| Noun | parseNoun |
| Verb | parseVerb |
๐ผ ๊ทธ๋ฆผ ์ค๋ช
- ์ฌ๋ผ์ด๋ ์๋จ: ๋ฌธ๋ฒ
- ํ๋จ: ํจ์ ๋ฆฌ์คํธ
- ์๋ฏธ: ๋ฌธ๋ฒ์ ์ฝ๋๋ก ๊ทธ๋๋ก ์ฎ๊ธด๋ค
๐ 5ํ์ด์ง โ Recursive Descent Parser Construction Example (ํด๋์ค ๊ตฌ์กฐ)
Recursive Descent Parser Construction Example
ํ์ ํด๋์ค ๋ผ๋
class MicroEnglishParser:
def __init__(self):
self.currentToken = None # ํ์ฌ ํ ํฐ์ ์ ์ฅํ๋ ๋ณ์
# Auxiliary methods will go here (๋ณด์กฐ ํจ์๋ค์ด ์ฌ๊ธฐ์ ๋ค์ด๊ฐ๋ค)
# Parsing methods will go here (ํ์ฑ ํจ์๋ค์ด ์ฌ๊ธฐ์ ๋ค์ด๊ฐ๋ค)
โ parser๋ ํญ์ ํ์ฌ ํ ํฐ์ ํ๋ ๋ณด๊ณ ํ๋จํ๋ค.
์ ์ฒด ๊ตฌ์กฐ:
Parser ํด๋์ค
โโโ currentToken
โโโ auxiliary methods (accept ๋ฑ)
โโโ parsing methods (parseX)
๐ผ ๊ทธ๋ฆผ ์ค๋ช
- ์ฌ๋ผ์ด๋ ๋ฐ์ค ์: ํด๋์ค ๊ตฌ์กฐ
- ์ฃผ์์ผ๋ก ์์ญ ๋๋
- ์๋ฏธ: ์ค์ ๊ตฌํ ๋ผ๋
๐ฅ 1~5ํ์ด์ง ํต์ฌ ์ ๋ฆฌ
- Recursive Descent Parser ์ ์ โ LL(top-down) ๋ฐฉ์ / ํจ์ ํธ์ถ ๊ธฐ๋ฐ ํ์ฑ
- ๊ฐ์ฅ ์ค์ํ ๊ฐ๋ โ ํ์คํธ๋ฆฌ = ํจ์ ํธ์ถ ๊ตฌ์กฐ
- ๊ตฌํ ์๋ฆฌ โ Non-terminal โ ํจ์ / Terminal โ accept()
- ์ฝ๋ ๊ตฌ์กฐ
Parser โโโ currentToken โโโ accept() โโโ parseX()
๐ 6ํ์ด์ง โ Recursive Descent Parser Construction: Auxiliary Methods
Recursive Descent Parser Construction: Auxiliary Methods
์ฌ๊ท ํ๊ฐ ํ์ ๊ตฌ์ฑ: ๋ณด์กฐ ๋ฉ์๋
class MicroEnglishParser:
def __init__(self, scanner):
self.scanner = scanner # scanner๋ฅผ ์ ์ฅํ๋ค
self.currentToken = None # ํ์ฌ ํ ํฐ ์ด๊ธฐํ
def accept(self, expectedToken):
if self.currentToken == expectedToken:
# get next token from scanner
self.currentToken = self.scanner.scan() # ๋ค์ ํ ํฐ์ผ๋ก ์ด๋
else:
report a syntax error # ๋ฌธ๋ฒ ์ค๋ฅ ๋ฐ์
โ ์ด์ parser๋ scanner์ ์ฐ๊ฒฐ๋๋ค: input โ scanner โ parser
accept ํจ์์ ์ญํ (ํต์ฌ ์ค์)
| ๋์ | ์ค๋ช |
|---|---|
| ํ์ฌ ํ ํฐ ๊ฒ์ฌ | expectedToken๊ณผ ์ผ์น ์ฌ๋ถ ํ์ธ |
| ๋ง์ผ๋ฉด | ๋ค์ ํ ํฐ์ผ๋ก ์ด๋ |
| ํ๋ฆฌ๋ฉด | ์๋ฌ ๋ฐ์ |
accept("if")
โ "if"๊ฐ ์๋๋ฉด ๋ฐ๋ก ์๋ฌ
๐ accept ํจ์ = parser์ ํต์ฌ primitive
๐ผ ๊ทธ๋ฆผ ์ค๋ช
- ์ฌ๋ผ์ด๋: ํด๋์ค + accept ํจ์ ์ฝ๋
- ์๋ฏธ: parser ๋์์ ์ต์ ๋จ์ ์ ์
๐ 7ํ์ด์ง โ Recursive Descent Parser Construction: Parsing Methods
Recursive Descent Parser Construction: Parsing Methods
ํ์ฑ ๋ฉ์๋
Sentence ::= Subject Verb Object .
๋ฌธ์ฅ โ ์ฃผ์ด + ๋์ฌ + ๋ชฉ์ ์ด + โ.โ
def parseSentence(self):
parseSubject() # ์ฃผ์ด ํ์ฑ
parseVerb() # ๋์ฌ ํ์ฑ
parseObject() # ๋ชฉ์ ์ด ํ์ฑ
self.accept('.') # "."์ ๊ธฐ๋ํ๊ณ ์๋นํ๋ค
โ ๋ฌธ๋ฒ ๊ทธ๋๋ก ์ฝ๋ํ๋จ
Sentence ::= A B C .
โ
parseA()
parseB()
parseC()
accept('.')
๐ ์์ ํ ๊ธฐ๊ณ์ ๋ณํ
๐ผ ๊ทธ๋ฆผ ์ค๋ช
- ์: ๋ฌธ๋ฒ
- ์๋: ์ฝ๋
- 1:1 ๋์ ๊ฐ์กฐ
๐ 8ํ์ด์ง โ Recursive Descent Parser: Parsing Methods (Subject)
Recursive Descent Parser: Parsing Methods
parseSubject ๊ตฌํ
Subject ::= I | a Noun | the Noun
์ฃผ์ด๋: I / a + ๋ช ์ฌ / the + ๋ช ์ฌ
def parseSubject(self):
if self.currentToken == 'I':
self.accept('I')
elif self.currentToken == 'a':
self.accept('a')
parseNoun()
elif self.currentToken == 'the':
self.accept('the')
parseNoun()
else:
report a syntax error
| โ **์ ํ ๊ตฌ์กฐ ( | ) ์ฒ๋ฆฌ ๋ฐฉ์:** |
A ::= X | Y | Z
โ
if token == X:
elif token == Y:
elif token == Z:
else error
๐ FIRST set ๊ธฐ๋ฐ ์ ํ
๐ผ ๊ทธ๋ฆผ ์ค๋ช
- ์: ๋ฌธ๋ฒ
- ์๋: if-elif ์ฝ๋
- โ์ ํ๋ฌธ = ์กฐ๊ฑด๋ฌธโ ๋ณํ
๐ 9ํ์ด์ง โ Recursive Descent Parser: Parsing Methods (Noun)
Recursive Descent Parser: Parsing Methods
parseNoun ๊ตฌํ
Noun ::= cat | mat | rat
๋ช ์ฌ๋: cat / mat / rat
def parseNoun(self):
if self.currentToken == 'cat':
self.accept('cat')
elif self.currentToken == 'mat':
self.accept('mat')
elif self.currentToken == 'rat':
self.accept('rat')
else:
report a syntax error
โ ์์ ๋์ผ ํจํด: ์ ํ๋ฌธ โ if-elif
๐ 10ํ์ด์ง โ Recursive Descent Parser: Parsing Methods (Object, Verb โ ๋น์นธ)
Recursive Descent Parser: Parsing Methods
parseObject / parseVerb (๋ฏธ์์ฑ ์ํ)
Object ::= me | a Noun | the Noun
Verb ::= like | is | see | sees
def parseObject(self):
? (๋ฏธ์์ฑ)
def parseVerb(self):
? (๋ฏธ์์ฑ)
โ ์ด ํ์ด์ง๋ ์ผ๋ถ๋ฌ ๋น์๋ โ ํ์์ด ์ง์ ๊ตฌํํด๋ณด๊ฒ ํจ
์ด๋ป๊ฒ ์ฑ์์ผ ํ๋์ง (ํต์ฌ)
parseObject:
if token == 'me':
elif token == 'a':
elif token == 'the':
parseVerb:
if token in ('like', 'is', 'see', 'sees'):
๐ผ ๊ทธ๋ฆผ ์ค๋ช
- ์: ๋ฌธ๋ฒ
- ์๋: ๋น ์ฝ๋
- โ์ด๊ฑธ ๋๊ฐ ์ฑ์๋ผโ ๊ตฌ์กฐ
๐ฅ 6~10ํ์ด์ง ํต์ฌ ์์ฝ
-
accept ํจ์ โ ํ ํฐ ๊ฒ์ฌ + ๋ค์ ํ ํฐ ์ด๋ / ํ๋ฆฌ๋ฉด ์๋ฌ
-
๋ณํ ๊ท์น (ํต์ฌ ์๊ธฐ)
| ๋ฌธ๋ฒ | ์ฝ๋ |
|---|---|
| A ::= B C | parseB(); parseC(); |
| A ::= x | accept(x) |
| A ::= X | Y | if-elif |
- ํต์ฌ ๊ตฌ์กฐ โ parser๋ ๊ฒฐ๊ตญ
if / ํจ์ํธ์ถ / accept์ด 3๊ฐ๋ก ๋๋จ
๐ 11ํ์ด์ง โ Recursive Descent Parser: Parsing Methods (Object, Verb โ ์์ฑ)
Recursive Descent Parser: Parsing Methods
parseObject / parseVerb ์์ฑ๋ณธ
Object ::= me | a Noun | the Noun
Verb ::= like | is | see | sees
def parseObject(self):
if self.currentToken == 'me':
self.accept('me')
elif self.currentToken == 'a':
self.accept('a')
parseNoun()
elif self.currentToken == 'the':
self.accept('the')
parseNoun()
def parseVerb(self):
if self.currentToken in ('like', 'is', 'see', 'sees'):
self.acceptIt() # ํ์ฌ ํ ํฐ์ ๊ทธ๋๋ก ์๋นํ๋ค
โ acceptIt() vs accept(token)
| ํจ์ | ์๋ฏธ |
|---|---|
| accept(x) | ํน์ ํ ํฐ x ๊ธฐ๋ |
| acceptIt() | ๊ทธ๋ฅ ํ์ฌ ํ ํฐ ์๋น |
๐ parseVerb๋: โ์ด๋ค ๋์ฌ๋ ์๊ด์๊ณ , ๊ทธ๋ฅ ํ๋ ์๋นโ
๐ผ ๊ทธ๋ฆผ ์ค๋ช
- ์ฌ๋ผ์ด๋: Object, Verb ๋ฌธ๋ฒ + ์์ฑ ์ฝ๋
- ์ด์ ํ์ด์ง(๋น์นธ)๋ฅผ ์ฑ์ด ์์ฑ๋ณธ
๐ 12ํ์ด์ง โ Systematic Development of a RD Parser
Systematic Development of a RD Parser
์ฌ๊ท ํ๊ฐ ํ์์ ์ฒด๊ณ์ ์ธ ๊ฐ๋ฐ ๋ฐฉ๋ฒ
(1) Express grammar in EBNF
๋ฌธ๋ฒ์ EBNF๋ก ํํํ๋ค.
(2) Grammar Transformations:
๋ฌธ๋ฒ ๋ณํ ์ํ
- Left factorization and left recursion elimination
- ์ข์ธก ์ธ์๋ถํด์ ์ข์ธก ์ฌ๊ท ์ ๊ฑฐ
(3) Create a parser class with
parser ํด๋์ค๋ฅผ ๋ง๋ ๋ค.
private variable currentTokenmethods to call the scanner: accept and acceptIt
(4) Convert EBNF into a RD parser
EBNF๋ฅผ RD parser๋ก ๋ณํํ๋ค.
- Implement private parsing methods โ ํ์ฑ ๋ฉ์๋ ๊ตฌํ
- add private parseN method for each nonterminal N โ ๊ฐ non-terminal๋ง๋ค parseN ํจ์ ์ถ๊ฐ
- public parse method that:
- gets the first token from the scanner (์ฒซ ํ ํฐ์ scanner์์ ๊ฐ์ ธ์ด)
- calls parseS (S is the start symbol of the grammar)
- ensure that all tokens are consumed upon return from parseS()
โ RD parser ๋ง๋๋ ์ ์ฐจ = ์ํ ํต์ฌ
โ ๋ฌธ๋ฒ ์์ฑ
โก ๋ฌธ๋ฒ ๋ณํ
โข parser ๊ตฌ์กฐ ์์ฑ
โฃ ์ฝ๋๋ก ๋ณํ
๐ 13ํ์ด์ง โ MiniC: Systematic Development of an RD Parser (1 & 2)
MiniC: Systematic Development of an RD Parser (1 & 2)
Common prefixes require left-factorization:
๊ณตํต ์ ๋์ด๊ฐ ์์ผ๋ฉด left-factorization ํ์
๊ธฐ์กด ๋ฌธ๋ฒ:
program ::= ( function-def | variable-def )*
ํ๋ก๊ทธ๋จ์ ํจ์ ์ ์ ๋๋ ๋ณ์ ์ ์ ๋ฐ๋ณต
โ ๋ฌธ์ :
typespec ID ...
typespec ID ...
๋ ๋ค ๊ฐ์ ์์ โ LL parser์์ ์ ํ ๋ถ๊ฐ
๋ณํ ํ:
program ::= ( typespec ID (VarPart | FuncPart) )*
๊ณตํต ๋ถ๋ถ(typespec ID)์ ๋จผ์ ๋นผ๊ณ ๋ถ๊ธฐ
โ left factoring:
A ::= X Y | X Z
โ
A ::= X (Y | Z)
๐ LL parser์์ ํ์
๐ผ ๊ทธ๋ฆผ ์ค๋ช
- ์: ์๋ ๋ฌธ๋ฒ
- ์๋: ๋ณํ๋ ๋ฌธ๋ฒ
- ๊ณตํต prefix ์ ๊ฑฐ ๊ณผ์ ์๊ฐํ
๐ 14ํ์ด์ง โ Left Recursion Elimination
Left recursion elimination
์ข์ธก ์ฌ๊ท ์ ๊ฑฐ
๊ธฐ์กด ๋ฌธ๋ฒ (left recursion):
add-expr ::= mult-expr
| add-expr "+" mult-expr
| add-expr "-" mult-expr
๋ง์ ํํ์ ์ ์
โ ๋ฌธ์ : left recursion โ add-expr โ add-expr ... โ RD parser์์ ๋ฌดํ ์ฌ๊ท ๋ฐ์
๋ณํ ํ:
add-expr ::= mult-expr ( ("+" | "-") mult-expr )*
mult-expr ๋ค์ +,- ๋ฐ๋ณต ๊ตฌ์กฐ
โ left recursion ์ ๊ฑฐ ๊ณต์:
A โ A ฮฑ | ฮฒ
โ
A โ ฮฒ ฮฑ*
๐ ์ฌ๊ท โ while๋ฌธ์ผ๋ก ๋ฐ๋
๐ผ ๊ทธ๋ฆผ ์ค๋ช
- ์: ์ฌ๊ท ๊ตฌ์กฐ
- ์๋: ๋ฐ๋ณต ๊ตฌ์กฐ
๐ 15ํ์ด์ง โ Developing a RD Parser for MiniC
Developing a RD Parser for MiniC
MiniC.py์ ์ปดํ์ผ๋ฌ ์คํ ์ฝ๋
def compileProgram(self, sourceName):
self.scanner = Scanner(source) # scanner ์์ฑ
self.reporter = ErrorReporter() # ์๋ฌ ๋ฆฌํฌํฐ ์์ฑ
self.parser = Parser(scanner, reporter) # parser ์์ฑ
self.parser.parse() # ํ์ฑ ์คํ
boolean successful = (self.reporter.numErrors == 0) # ์๋ฌ 0์ด๋ฉด ์ฑ๊ณต
if successful:
print("Compilation was successful.")
else:
print("Compilation was unsuccessful.")
โ ์ปดํ์ผ๋ฌ ์ ์ฒด ํ๋ฆ:
source
โ scanner
โ parser
โ errorReporter
โ ๊ฒฐ๊ณผ ์ถ๋ ฅ
๐ parser๋ ์ ์ฒด pipeline์ ์ผ๋ถ
๐ฅ 11~15ํ์ด์ง ํต์ฌ ์์ฝ
- parseObject / parseVerb ์์ฑ โ ์ ํ๋ฌธ ์ฒ๋ฆฌ ๊ตฌ์กฐ ์์ฑ
- RD parser ๋ง๋๋ ์ ์ฐจ (์ํ ํต์ฌ)
- EBNF ์์ฑ โ left factoring โ left recursion ์ ๊ฑฐ โ ์ฝ๋ ๋ณํ
- ๋ฌธ๋ฒ ๋ณํ ์ด์ โ LL parser์์ ์ ํ ๊ฐ๋ฅํ๊ฒ ๋ง๋ค๊ธฐ
- ์ปดํ์ผ๋ฌ ์ ์ฒด ๊ตฌ์กฐ โ scanner โ parser โ error ์ฒ๋ฆฌ
๐ 16ํ์ด์ง โ The Error Reporter (ErrorReport.py)
The Error Reporter (ErrorReport.py)
์๋ฌ ๋ฆฌํฌํฐ
class ErrorReporter:
def __init__(self):
self.numErrors = 0 # ์๋ฌ ๊ฐ์๋ฅผ 0์ผ๋ก ์ด๊ธฐํ
def reportError(self, m, tok, pos):
print("ERROR: ", end="")
for c in m:
if c == "%":
print(tok, end="") # % ์๋ฆฌ์ ํ ํฐ ์ฝ์
else:
print(c, end="")
print(" " + str(pos.StartCol) + ".." + str(pos.EndCol)
+ ", line" + str(pos.StartLine) + ".") # ์๋ฌ ์์น ์ถ๋ ฅ
self.numErrors += 1 # ์๋ฌ ๊ฐ์ ์ฆ๊ฐ
์์
reportError("Type specifier instead of % expected", ...)
โ ์ถ๋ ฅ: ERROR: Type specifier instead of IF expected 9..10, line 22.
โ โ%โ์ ์ญํ : ๋ฉ์์ง ํ ํ๋ฆฟ์ % ์๋ฆฌ์ ํ ํฐ ์ฝ์
๐ ์ถ๋ ฅ ํ์: ๋ฉ์์ง ํ ํ๋ฆฟ + ํ ํฐ + ์์น
๐ 17ํ์ด์ง โ MiniC Parser: Reporting Errors and Throwing Exceptions
MiniC Parser: Reporting errors and throwing exceptions
์๋ฌ ์ฒ๋ฆฌ ๋ฐ ์์ธ ๋ฐ์
def syntaxError(self, messageTemplate, tokenQuoted):
pos = self.currentToken.GetSourcePos() # ํ์ฌ ํ ํฐ ์์น ๊ฐ์ ธ์ค๊ธฐ
self.errorReporter.reportError(messageTemplate, tokQuoted, pos) # ์๋ฌ ์ถ๋ ฅ
raise SyntaxError() # ์์ธ ๋ฐ์
class SyntaxError(Exception):
def __init__(self, message=""):
super().__init__(message) # ๋ถ๋ชจ ํด๋์ค(Exception) ์ด๊ธฐํ
์์
syntaxError("Type specifier instead of % expected", ...)
โ ERROR: Type specifier instead of IF expected ...
โ ํ๋ฆ:
syntaxError()
โ reportError()
โ raise exception
๐ exception์ ์ฐ๋ ์ด์ : ํ์ฑ ์ค๋จ + ์์๋ก ์๋ฌ ์ ๋ฌ
๐ 18ํ์ด์ง โ Exception Handling in the MiniC Parser
Exception Handling in the MiniC Parser
MiniC ํ์์์ ์์ธ ์ฒ๋ฆฌ
def parse(self):
self.currentToken = self.scanner.scan() # ์ฒซ ํ ํฐ ์ฝ๊ธฐ
try:
self.parseProgram() # ํ๋ก๊ทธ๋จ ํ์ฑ
if currentToken.kind != Token.EOF:
self.syntaxError("% not expected after end of program", ...)
# ํ๋ก๊ทธ๋จ ๋ ๋ค์ ์ด์ํ ํ ํฐ โ ์๋ฌ
except SyntaxError as s:
return None # ์คํจ ์ None ๋ฐํ
โ ์ ์ฒด ๊ตฌ์กฐ:
try:
parseProgram()
except:
์๋ฌ ์ฒ๋ฆฌ
๐ ์๋ฏธ: ์๋ฌ ๋ฐ์ โ exception โ ์ฌ๊ธฐ์ catch
๐ผ ๊ทธ๋ฆผ ์ค๋ช
- ์ฌ๋ผ์ด๋: try-except ๊ตฌ์กฐ ๊ฐ์กฐ
- parser์ โ์ต์์ ์์ ์ฅ์นโ
๐ 19ํ์ด์ง โ Algorithm to Convert EBNF into a RD Parser
Algorithm to convert EBNF into a RD parser
EBNF โ RD parser ๋ณํ ์๊ณ ๋ฆฌ์ฆ
def parseN(self) { parse X() }
N ::= X โ parseN์ parseX ํธ์ถ
The conversion โฆ is so โmechanicalโ that it can easily be automated!
์ด ๋ณํ์ ๋งค์ฐ ๊ธฐ๊ณ์ ์ด๋ผ ์๋ํ ๊ฐ๋ฅํ๋ค.
We can describe the algorithm by a set of mechanical rewrite rules.
๊ธฐ๊ณ์ ๋ณํ ๊ท์น์ผ๋ก ์ค๋ช
๊ฐ๋ฅํ๋ค.
โ ์ง์ง ์ค์: ๋ฌธ๋ฒ โ ์ฝ๋ ๋ณํ์ ๊ท์น ๊ธฐ๋ฐ
๐ผ ๊ทธ๋ฆผ ์ค๋ช
- ์ฌ๋ผ์ด๋: ๋ฌธ๋ฒ โ ํจ์ ๋ณํ ํ์ดํ
๐ 20ํ์ด์ง โ Algorithm to Convert EBNF into a RD Parser (๊ท์น)
Algorithm to convert EBNF into a RD parser
๋ณํ ๊ท์น ์์ธ
| ๋ฌธ๋ฒ ์์ | ๋ณํ ์ฝ๋ | ์ค๋ช |
|---|---|---|
terminal t |
self.accept(t) |
t๋ฅผ ๊ธฐ๋ํ๊ณ ์๋น |
non-terminal N |
self.parseN() |
parseN ํธ์ถ |
| ฮต (๋น ๋ฌธ์์ด) | # do nothing |
์๋ฌด๊ฒ๋ ํ์ง ์์ |
X Y (์์) |
self.parseX(); self.parseY() |
X ํ์ฑ ํ Y ํ์ฑ |
โ ๋ณํ ๊ท์น ์ ๋ฆฌ (์ํ ํต์ฌ):
terminal t โ accept(t)
non-terminal N โ parseN()
ฮต โ ์๋ฌด๊ฒ๋ ์ ํจ
X Y โ ์์๋๋ก ํธ์ถ
๐ผ ๊ทธ๋ฆผ ์ค๋ช
- ์ฌ๋ผ์ด๋: ๊ฐ ๊ท์น โ ์ฝ๋ ๋ณํ
- โ์์ ๊ธฐ๊ณ์ ๋ณํ ๊ท์นโ
๐ฅ 16~20ํ์ด์ง ํต์ฌ ์์ฝ
- ์๋ฌ ์ฒ๋ฆฌ ๊ตฌ์กฐ โ reportError โ ๋ฉ์์ง ์ถ๋ ฅ / syntaxError โ exception ๋ฐ์
- parser ์ ์ฒด ํ๋ฆ โ scan โ parse โ error handling
- EBNF โ ์ฝ๋ ๋ณํ ๊ท์น (ํต์ฌ ์๊ธฐ)
tโaccept(t)NโparseN()- ฮต โ nothing
XYโ ์์ฐจ ํธ์ถ
๐ ์ฌ๊ธฐ๊น์ง ์ดํดํ๋ฉด RD parser ๊ตฌํ 80% ๋๋ ์ํ๋ค.
๐ 21ํ์ด์ง โ Algorithm to Convert EBNF into a RD Parser (์ ํ/๋ฐ๋ณต)
Algorithm to convert EBNF into a RD parser
์ ํ ( | ) ๊ณผ ๋ฐ๋ณต ( * ) ๋ณํ
parsing X | Y
match self.currentToken.kind:
cases in FIRST[X]:
parse X
cases in FIRST[Y]:
parse Y
case _:
report syntax error
FIRST[X]: X๋ก๋ถํฐ ์์ํ ์ ์๋ terminal๋ค์ ์งํฉ
FIRST [X] denotes the set of terminal symbols that start sentences derived from X.
parsing X*
while self.currentToken.kind is in FIRST[X]:
parse X()
โ ํต์ฌ ๋ณํ ๊ท์น (๋งค์ฐ ์ค์):
1. ์ ํ ( | )
X | Y
โ
if token โ FIRST[X]:
parseX()
elif token โ FIRST[Y]:
parseY()
else:
error
2. ๋ฐ๋ณต ( * )
X*
โ
while token โ FIRST[X]:
parseX()
๐ ์ด ๋ ๊ฐ๊ฐ RD parser ํต์ฌ์ด๋ค.
๐ผ ๊ทธ๋ฆผ ์ค๋ช
- ์: ์ ํ ๊ตฌ์กฐ
- ์๋: ๋ฐ๋ณต ๊ตฌ์กฐ
- FIRST ์งํฉ ๊ธฐ๋ฐ ๋ถ๊ธฐ
๐ 22ํ์ด์ง โ Example: parseExpr
Example: parseExpr
Expr ::= AndExpr ( "||" AndExpr )*
| Expr๋ AndExpr ๋ค์ (โ | ย | โ AndExpr)๊ฐ 0๋ฒ ์ด์ ๋ฐ๋ณต |
def parseExpr(self):
self.parseAndExpr() # ๋จผ์ AndExpr ํ์ฑ
while self.currentToken.kind == Token.OR: # ํ์ฌ ํ ํฐ์ด OR(||)์ด๋ฉด ๋ฐ๋ณต
self.acceptIt() # "||" ์๋น
self.parseAndExpr() # ๋ค์ AndExpr ํ์ฑ
โ 21ํ์ด์ง ๊ท์น ์ ์ฉ:
( X )*
โ
while condition:
X
๐ ์๋ฏธ:
a || b || c
โ
parseAndExpr()
while '||':
parseAndExpr()
๐ผ ๊ทธ๋ฆผ ์ค๋ช
- ์: ๋ฌธ๋ฒ
- ์๋: ์ฝ๋
- ๋ฐ๋ณต ๊ตฌ์กฐ โ while๋ฌธ
๐ 23ํ์ด์ง โ Example: parseProgram
Example: parseProgram
program ::= ( (VOID|INT|BOOL|FLOAT) ID ( FunPart | VarPart ) )*
ํ๋ก๊ทธ๋จ์: ํ์ + ID + (ํจ์ or ๋ณ์), ์ด ๊ตฌ์กฐ๊ฐ ๋ฐ๋ณต๋จ
def parseProgram(self):
while self.isTypeSpecifier(self.currentToken.kind): # ํ์ฌ ํ ํฐ์ด ํ์
์ด๋ฉด ๋ฐ๋ณต
self.acceptIt() # ํ์
์๋น
self.accept(Token.ID) # ID ์๋น
if self.currentToken.kind == Token.LEFTPAREN: # "("์ด๋ฉด
self.parseFunPart() # ํจ์ ํ์ฑ
else:
self.parseVarPart() # ๋ณ์ ํ์ฑ
isTypeSpecifier is true iff the current Token is either Token.VOID, Token.INT, Token.BOOL or Token.FLOAT.
โ isTypeSpecifier๋ ํ ํฐ์ด void/int/bool/float์ผ ๋ true
โ ๊ตฌ์กฐ:
while ํ์
:
ํ์
ID
if '(':
ํจ์
else:
๋ณ์
| ๐ **์ ํ ( | )** ๊ณผ ๋ฐ๋ณต ( * ) ๋ ๋ค ํฌํจ๋ ์์ ํ ์์ |
๐ผ ๊ทธ๋ฆผ ์ค๋ช
- ์ฌ๋ผ์ด๋: ๋ฌธ๋ฒ โ ์ฝ๋
- ์ค์ ์ปดํ์ผ๋ฌ ์์ค ์ฝ๋
๐ 24ํ์ด์ง โ Outlook (์ ์ฒด ์ ๋ฆฌ)
Outlook
์ ์ฒด ์ ๋ฆฌ
| ํญ๋ชฉ | ์ํ |
|---|---|
| Syntax and Semantics of Programming Languages | โ ์๋ฃ |
| Specifying the Syntax | โ ์๋ฃ |
| Top-down parsing (LL) | โ ์๋ฃ |
| Recursive descent (LL) parser construction | โ ์๋ฃ |
| LL Grammars | ์์ |
| AST Construction | ์์ |
| Parse trees vs. ASTs | ์์ |
| Chomskyโs Hierarchy | ์์ |
โ ์ง๊ธ๊น์ง: RD parser ๊ตฌํ ์๋ฃ
โ ๋ค์: AST / LL grammar
๐ฅ 21~24ํ์ด์ง ํต์ฌ ์์ฝ (์ง์ง ์ค์)
1. ์ ํ๋ฌธ ( | )
if token โ FIRST[X]:
parseX()
elif token โ FIRST[Y]:
parseY()
2. ๋ฐ๋ณต๋ฌธ ( * )
while token โ FIRST[X]:
parseX()
3. RD parser ํต์ฌ ๊ตฌ์กฐ 4๊ฐ
| ์์ | ์ฝ๋ |
|---|---|
| terminal | accept() |
| non-terminal | parseN() |
| ์ ํ | if / elif |
| ๋ฐ๋ณต | while |
4. ์ ์ฒด ํ๋ฆ
EBNF
โ ๋ฌธ๋ฒ ๋ณํ
โ FIRST ๊ธฐ๋ฐ ๋ถ๊ธฐ
โ ํจ์ ์ฝ๋ ์์ฑ
๐ฅ ์ ์ฒด ๊ฐ์ ํต์ฌ ์์ฝ (1~24ํ์ด์ง)
RD parser ๋ง๋๋ ์ ์ฐจ
โ EBNF ๋ฌธ๋ฒ ์์ฑ
โก Grammar Transformations (left factoring, left recursion ์ ๊ฑฐ)
โข Parser ํด๋์ค ์์ฑ (currentToken, accept, acceptIt)
โฃ EBNF โ ์ฝ๋ ๋ณํ
EBNF โ ์ฝ๋ ๋ณํ ๊ท์น ์์ ์ ๋ฆฌ
| ๋ฌธ๋ฒ | ์ฝ๋ |
|---|---|
terminal t |
accept(t) |
non-terminal N |
parseN() |
| ฮต | nothing |
X Y |
parseX(); parseY(); |
X \| Y |
if FIRST[X]... elif FIRST[Y]... |
X* |
while FIRST[X]: parseX() |
ํต์ฌ ํจ์ ์ ๋ฆฌ
| ํจ์ | ์ญํ |
|---|---|
accept(t) |
ํน์ ํ ํฐ t ๊ธฐ๋ํ๊ณ ์๋น, ํ๋ฆฌ๋ฉด ์๋ฌ |
acceptIt() |
ํ์ฌ ํ ํฐ ๊ทธ๋ฅ ์๋น |
syntaxError() |
์๋ฌ ์ถ๋ ฅ + exception ๋ฐ์ |
parseN() |
non-terminal N ํ์ฑ |
Leave a comment