Computer Science

[CS] ๋‚˜๋งŒ์˜ ์ธํ„ฐํ”„๋ฆฌํ„ฐ๋ฅผ ๋งŒ๋“ค์–ด๋ณด์ž! (2): Parser ๋งŒ๋“ค๊ธฐ - ์ฒซ๋ฒˆ์งธ

YounghunJo 2025. 3. 15. 13:49
๋ฐ˜์‘ํ˜•

๐Ÿ”Š ํ•ด๋‹น ํฌ์ŠคํŒ…์€ ๋ฐ‘๋ฐ”๋‹ฅ๋ถ€ํ„ฐ ๋งŒ๋“œ๋Š” ์ธํ„ฐํ”„๋ฆฌํ„ฐ in go ์ฑ…์„ ์ฝ๊ณ  ๊ฐœ์ธ์ ์ธ ์ •๋ฆฌ ๋ชฉ์  ํ•˜์— ์ž‘์„ฑ๋œ ๊ธ€์ž…๋‹ˆ๋‹ค. ๋ณธ ํฌ์ŠคํŒ…์— ์‚ฌ์šฉ๋œ ์ž๋ฃŒ๋Š” ๋ชจ๋‘ ๋ณธ์ธ์ด ์ง์ ‘ ์žฌ๊ตฌ์„ฑํ•˜์—ฌ ์ž‘์„ฑํ•˜์˜€์Œ์„ ์•Œ๋ฆฝ๋‹ˆ๋‹ค.
 

์ถœ์ฒ˜: Yes24


์ง์ „ ํฌ์ŠคํŒ…์—์„œ ์šฐ๋ฆฌ๋Š” ์ž…๋ ฅ๋œ ์†Œ์Šค์ฝ”๋“œ ๋ฌธ์ž์—ด์„ ํ† ํฐํ™”์‹œํ‚ค๋Š” ๋ ‰์„œ๋ฅผ ์ง์ ‘ ๋งŒ๋“ค๊ณ  ํ…Œ์ŠคํŠธ๋ฅผ ํ•ด๋ณด์•˜๋‹ค. ์ด๋ฒˆ ํฌ์ŠคํŒ…์—์„œ๋Š” ์ด ๋ ‰์„œ๊ฐ€ ๋งŒ๋“ค์–ด๋‚ธ ํ† ํฐ๋“ค์„ ๊ฐ€์ง€๊ณ  AST(์ถ”์ƒ ๊ตฌ๋ฌธ ํŠธ๋ฆฌ)์™€ ๊ฐ™์€ ์ž๋ฃŒ๊ตฌ์กฐ๋กœ ๋ณ€ํ™˜์„ ์ˆ˜ํ–‰ํ•˜๋Š” ํŒŒ์„œ(Parser)๋ฅผ ๋งŒ๋“ค์–ด๋ณด๋„๋ก ํ•˜์ž. ํ•ด๋‹น ์ฑ•ํ„ฐ๋Š” ๋‚ด์šฉ์ด ๊ธธ์–ด์ง€๊ธฐ ๋•Œ๋ฌธ์— ๋ช‡ ๊ฐœ์˜ ํฌ์ŠคํŒ…์œผ๋กœ ๋‚˜๋ˆ„์–ด์„œ ๊ฒŒ์‹œํ•  ์˜ˆ์ •์ด๋‹ค. ์ด์ œ ํŒŒ์„œ๋ฅผ ๋งŒ๋“ค์–ด๋ณด๋Š” ์ฒซ ๊ฑธ์Œ์„ ๋‚ด๋”›์–ด๋ณด์ž.

1. Parser๋ž€ ๋ฌด์—‡์ผ๊นŒ?

ํŒŒ์„œ๋ฅผ ๋งŒ๋“ค์–ด๋ณด๊ธฐ ์ „, ์šฐ๋ฆฌ๋Š” ํŒŒ์„œ๋ผ๋Š” ๊ฒƒ์ด ๋ฌด์—‡์ด๊ณ  ์–ด๋–ค ์—ญํ• ์„ ํ•˜๋Š”์ง€ ์•Œ์•„์•ผ ๋งŒ๋“ค์–ด๊ฐ€๋ฉด์„œ ๊ทธ ์˜๋ฏธ๋ฅผ ์ œ๋Œ€๋กœ ์ดํ•ดํ•ด๋ณผ ์ˆ˜ ์žˆ์„ ๊ฒƒ์ด๋‹ค. ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ํ•ด๋ณธ ๊ฒฝํ—˜์ด ์žˆ๊ฑฐ๋‚˜ SQL ์ฟผ๋ฆฌ๋ฅผ ์ž‘์„ฑํ•˜๊ฑฐ๋‚˜ ํ•˜๊ฒŒ ๋˜๋ฉด ํ•œ ๋ฒˆ์ฏค์€ ํŒŒ์‹ฑ ์—๋Ÿฌ(Parsing Error)๋ผ๋Š” ๋ฉ”์„ธ์ง€๋ฅผ ์ ‘ํ•ด๋ณธ ์ ์ด ์žˆ์„ ๊ฒƒ์ด๋‹ค. ํŒŒ์„œ์˜ ์‚ฌ์ „์ ์ธ ์ •์˜๋Š” "(์ฃผ๋กœ ๋ฌธ์ž๋กœ ๋œ) ์ž…๋ ฅ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„ ํŒŒ์Šค ํŠธ๋ฆฌ, ์ถ”์ƒ ๊ตฌ๋ฌธํŠธ๋ฆฌ ๋“ฑ๊ณผ ๊ฐ™์€ ๊ณ„์ธต์„ ๊ฐ–๋Š” ์ž๋ฃŒ๊ตฌ์กฐ๋กœ ๋งŒ๋“ค์–ด๋‚ด๋Š” ์†Œํ”„ํŠธ์›จ์–ด ์ปดํฌ๋„ŒํŠธ"์ด๋‹ค. ์‰ฝ๊ฒŒ ๋งํ•˜๋ฉด ์šฐ๋ฆฌ๊ฐ€ ์ด์ „ ํฌ์ŠคํŒ…์—์„œ ์‚ดํŽด๋ณธ ๋ ‰์„œ๊ฐ€ ๋งŒ๋“ค์–ด๋‚ธ ํ† ํฐ๋“ค์„ ์ž๋ฃŒ๊ตฌ์กฐ๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ์…ˆ์ด๋‹ค. ์ด ๋ณ€ํ™˜ ๊ณผ์ •์„ ๊ฑฐ์น˜๋ฉด์„œ ํŒŒ์„œ๋Š” ๊ตฌ์กฐํ™”๋œ ํ‘œํ˜„์„ ๋”ํ•˜๊ธฐ๋„ ํ•˜๊ณ  ๊ตฌ๋ฌธ์ด ์˜ฌ๋ฐ”๋ฅธ์ง€ ๊ฒ€์‚ฌํ•˜๊ธฐ๋„ ํ•œ๋‹ค. ์ž ์‹œ ์ด์ „ ํฌ์ŠคํŒ…์—์„œ ์‚ฌ์šฉํ–ˆ๋˜ ์‚ฌ์ง„ ์ž๋ฃŒ๋ฅผ ๋‹ค์‹œ ๊ฐ€์ ธ์™€๋ณด์ž.

 

ํŒŒ์‹ฑ์€ ์–ธ์ œ ์ˆ˜ํ–‰๋˜๋Š” ๊ฑธ๊นŒ?

 

์œ„ ๊ทธ๋ฆผ์„ ๋ณด๋ฉด 'ํŒŒ์‹ฑ'์ด๋ผ๋Š” ๋™์ž‘์ด ์ˆ˜ํ–‰๋˜๋Š”๋ฐ, ์ด 'ํŒŒ์‹ฑ'์„ ์ˆ˜ํ–‰ํ•˜๋Š” ์ฃผ์ฒด๊ฐ€ ํŒŒ์„œ์ž„์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค. ๋ณดํŽธ์ ์œผ๋กœ ์‚ฌ์šฉ๋˜๊ณ  ์žˆ๋Š” ์ธํ„ฐํ”„๋ฆฌํ„ฐ, ๋‹จ์ ์ธ ์˜ˆ๋กœ, Python ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด์— ์‚ฌ์šฉ๋˜๋Š” ์ธํ„ฐํ”„๋ฆฌํ„ฐ๋ฅผ ๊ฐœ๋ฐœ์ž๋“ค์ด ์‚ฌ์šฉํ•˜๋ฉด์„œ ์ž์‹ ๋“ค์ด ์ž…๋ ฅํ•œ ์†Œ์Šค์ฝ”๋“œ๊ฐ€ ์ž๋ฃŒ๊ตฌ์กฐ๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ๊ฒƒ์„ ํ”ผ๋ถ€์— ์™€๋‹ฟ๊ฒŒ ๋Š๋ผ์ง€๋Š” ๋ชปํ•œ๋‹ค. ๋Œ€์ฒด ์™œ์ผ๊นŒ? ๊ทธ๊ฒƒ์€ ๋ฐ”๋กœ ์ธ๊ฐ„์ธ ๊ฐœ๋ฐœ์ž๋“ค์€ ํŒŒ์„œ๊ฐ€ ๋งŒ๋“ค์–ด๋‚ธ ์ž๋ฃŒ๊ตฌ์กฐ์— ์ต์ˆ™ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

 

ํŒŒ์„œ๊ฐ€ ๋งŒ๋“ค์–ด๋‚ด๋Š” ์ž๋ฃŒ๊ตฌ์กฐ ์ค‘ ์ธ๊ฐ„์ธ ๊ฐœ๋ฐœ์ž์—๊ฒŒ ์ต์ˆ™ํ•œ ๋Œ€ํ‘œ์ ์ธ ์˜ˆ์‹œ๊ฐ€ ์žˆ๋‹ค. ๋ฐ”๋กœ JSON ํŒŒ์„œ์ด๋‹ค. ๋Œ€๋ถ€๋ถ„์˜ ๊ฐœ๋ฐœ์ž๋“ค์€ JSON ์ด๋ผ๋Š” ์ž๋ฃŒ๊ตฌ์กฐ๋กœ ํŒŒ์‹ฑํ•ด๋ณธ ์ ์ด ์žˆ์„ ๊ฒƒ์ด๋‹ค. Python์—์„œ๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด JSON String์„ JSON ์ž๋ฃŒ๊ตฌ์กฐ, ํŒŒ์ด์ฌ์—์„œ๋Š” ๋”•์…”๋„ˆ๋ฆฌ ์ž๋ฃŒ๊ตฌ์กฐ๋กœ ํŒŒ์‹ฑ์„ ํ•ด๋ณธ์ ์ด ์žˆ์„ ๊ฒƒ์ด๋‹ค.

 

# https://www.w3schools.com/python/python_json.asp
import json

# some JSON:
x =  '{ "name":"John", "age":30, "city":"New York"}'

# parse x:
y = json.loads(x)

# the result is a Python dictionary:
print(y["age"])

 

์œ„ ์†Œ์Šค์ฝ”๋“œ๋ฅผ ํ•œ ๋ฒˆ์ด๋ผ๋„ ์‚ฌ์šฉํ•ด๋ณธ ์ ์ด ์žˆ์„ ๊ฒƒ์ด๋‹ค. ์ด๋Ÿฌํ•œ JSON ํŒŒ์„œ๋„ ์†Œ์Šค์ฝ”๋“œ์— ์‚ฌ์šฉ๋˜๋Š” ํŒŒ์„œ์™€ ๋ณธ์งˆ์ ์œผ๋กœ ๊ฐœ๋…์€ ๊ฐ™๋‹ค. ์ด '๋ณธ์งˆ์ ์œผ๋กœ ๊ฐ™์€ ๊ฐœ๋…'์ด๋ผ ํ•จ์€ ๋ฌธ์ž์—ด์„ ์ž…๋ ฅ๋ฐ›์•„์„œ ์–ด๋– ํ•œ ์ž๋ฃŒ๊ตฌ์กฐ๋กœ ํŒŒ์‹ฑํ•œ๋‹ค๋Š” ์ ์ด๋‹ค. ํ•˜์ง€๋งŒ JSON ํŒŒ์„œ๋Š” ์šฐ๋ฆฌ์—๊ฒŒ ์ต์ˆ™ํ•˜์ง€๋งŒ, ์†Œ์Šค์ฝ”๋“œ์˜ ํŒŒ์„œ๋Š” ์šฐ๋ฆฌ์—๊ฒŒ ์ต์ˆ™ํ•˜์ง€ ์•Š์€ ์ด์œ ๋Š” ๋‹จ์ˆœํžˆ ์†Œ์Šค์ฝ”๋“œ์˜ ํŒŒ์„œ๊ฐ€ ๋งŒ๋“ค์–ด๋‚ด๋Š” ์ž๋ฃŒ๊ตฌ์กฐ๋ฅผ ์šฐ๋ฆฌ๊ฐ€ ์ž์ฃผ ๋ณธ์ ์ด ์—†์„ ๋ฟ์ด๋‹ค. 

 

๋”ฐ๋ผ์„œ, ์šฐ๋ฆฌ๊ฐ€ JSON ์ด๋ผ๋Š” ์ž๋ฃŒ๊ตฌ์กฐ๋ฅผ ์ดํ•ดํ•˜๋ฉด JSON ํŒŒ์„œ๋ฅผ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋“ฏ์ด, ์†Œ์Šค์ฝ”๋“œ ํŒŒ์„œ๊ฐ€ ๋งŒ๋“ค์–ด๋‚ด๋Š” ์ž๋ฃŒ๊ตฌ์กฐ๋ฅผ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๊ธฐ๋งŒ ํ•œ๋‹ค๋ฉด ์šฐ๋ฆฌ๋Š” ์†Œ์Šค์ฝ”๋“œ ํŒŒ์„œ๊ฐ€ ์–ด๋–ค ์›๋ฆฌ๋กœ ๋™์ž‘ํ•˜๋Š”์ง€ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.

 

์ผ๋ฐ˜์ ์œผ๋กœ, ์†Œ์Šค์ฝ”๋“œ์˜ ํŒŒ์„œ๋“ค์ด ๋งŒ๋“ค์–ด๋‚ด๋Š” ์ž๋ฃŒ๊ตฌ์กฐ๋กœ๋Š” ๊ตฌ๋ฌธํŠธ๋ฆฌ(Syntax Tree) ๋˜๋Š” ์ถ”์ƒ๊ตฌ๋ฌธํŠธ๋ฆฌ(Abstract Syntax Tree, AST)๋ผ๊ณ  ๋ถ€๋ฅธ๋‹ค. '์ถ”์ƒ' ์ด๋ผ๋Š” ํ‚ค์›Œ๋“œ๊ฐ€ ๋ถ™์€ ์ด์œ ๋Š” ์†Œ์Šค์ฝ”๋“œ์—์„œ ๋ณด์ด๋Š” ์„ธ๋ถ€ ์ •๋ณด(์˜ˆ๋ฅผ ๋“ค์–ด, ์„ธ๋ฏธ์ฝœ๋ก , ์ค„ ๋ฐ”๊ฟˆ, ๊ณต๋ฐฑ, ์ฃผ์„, ๋Œ€๊ด„ํ˜ธ, ์ค‘๊ด„ํ˜ธ, ์†Œ๊ด„ํ˜ธ, ...๋“ค์€ ๊ตฌ๋ฌธํŠธ๋ฆฌ์—์„œ ์ƒ๋žต๋˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์ด๋Ÿฌํ•œ ์„ธ๋ถ€์ •๋ณด๋Š” ๋‹จ์ˆœํžˆ ํŒŒ์„œ๊ฐ€ AST๋ฅผ ๊ตฌ์„ฑํ•  ๋•Œ, ๊ตฌ์„ฑ ํ˜•ํƒœ๋ฅผ ์•Œ๋ ค์ฃผ๋Š” ์šฉ๋„๋กœ๋งŒ ์‚ฌ์šฉ๋  ๋ฟ์ด๋‹ค. ๋˜ํ•œ ์ด AST ํ˜•์‹์€ ๋ชจ๋“  ํŒŒ์„œ๊ฐ€ ์‚ฌ์šฉํ•˜๋Š” ๊ณตํ†ต์ ์ธ ํ˜•์‹์ด ์žˆ๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋‹ค. ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด๋งˆ๋‹ค ๋˜๋Š” ํŒŒ์„œ๋งˆ๋‹ค ๊ตฌํ˜„์ฒด๊ฐ€ ์•ฝ๊ฐ„ ์”ฉ์€ ๋‹ฌ๋ผ์ง„๋‹ค.

 

์ด์ œ ํŒŒ์„œ์— ๋Œ€ํ•œ ๋‚ด์šฉ์„ ์ •๋ฆฌํ•ด๋ณด์ž๋ฉด, ํŒŒ์„œ๋Š” ์†Œ์Šค์ฝ”๋“œ ๋ฌธ์ž์—ด์„ ์ž…๋ ฅ์œผ๋กœ ๋ฐ›์•„์„œ ์†Œ์Šค์ฝ”๋“œ๋ฅผ ํ‘œํ˜„ํ•˜๋Š” ์ž๋ฃŒ๊ตฌ์กฐ(ex. AST, ..)๋ฅผ ๋งŒ๋“ค์–ด๋‚ธ๋‹ค. ์ด ๋•Œ, ์ž๋ฃŒ๊ตฌ์กฐ๋ฅผ ๋งŒ๋“ค์–ด๋‚ด๋Š ๋™์•ˆ ํŒŒ์„œ๋Š” ์ž…๋ ฅ์„ ๋ถ„์„ํ•˜๊ฒŒ ๋˜๋Š”๋ฐ ์ด '๋ถ„์„'์ด๋ผ ํ•จ์€ ์ž…๋ ฅ์ด ์˜ˆ์ƒ ๊ตฌ์กฐ์— ๋งž๋Š”์ง€ ๊ฒ€์‚ฌํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ์ด ๊ฒ€์‚ฌํ•˜๋Š” ๊ณผ์ •์„ '๊ตฌ๋ฌธ ๋ถ„์„(Syntactic Analysis)'์ด๋ผ๊ณ ๋„ ํ•œ๋‹ค.

 

์ฐธ๊ณ ๋กœ, ์š”์ฆ˜์—๋Š” ํŒŒ์„œ๋ฅผ ์šฐ๋ฆฌ์ฒ˜๋Ÿผ ์ง์ ‘ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค๋Š” ์ด ํŒŒ์„œ ์ž์ฒด๋ฅผ ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•ด์ฃผ๋Š” ํŒŒ์„œ ์ œ๋„ค๋ ˆ์ดํ„ฐ๋ฅผ ์ด์šฉํ•˜๊ธฐ๋„ ํ•œ๋‹ค. ๋Œ€ํ‘œ์ ์ธ ํŒŒ์„œ ์ œ๋„ค๋ ˆ์ดํ„ฐ๋กœ๋Š” yacc, bison, ANTLR ๋“ฑ์ด ์žˆ๋‹ค. ์ด ํŒŒ์„œ ์ œ๋„ค๋ ˆ์ดํ„ฐ๋Š” ํŠน์ • ์–ธ์–ด์— ๋Œ€ํ•œ ๊ณต์‹์ ์ธ ์„ค๋ช…์ด ์ฃผ์–ด์กŒ์„ ๋•Œ, ์ถœ๋ ฅ์œผ๋กœ ํŒŒ์„œ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋„๊ตฌ์ด๋‹ค. ์ด '์ถœ๋ ฅ'๋ฌผ์€ ์†Œ์Šค์ฝ”๋“œ์ธ๋ฐ, ์ปดํŒŒ์ผ ๋˜๋Š” ์ธํ„ฐํ”„๋ฆฌํŒ…๋˜๋Š” ์ฝ”๋“œ์ด๋‹ค. ์ด ๋ถ€๋ถ„์— ๋Œ€ํ•œ ๊นŠ์€ ๋‚ด์šฉ์€ ๋‹ค๋ฃจ์ง€ ์•Š๋Š”๋‹ค. ๋‹จ์ง€ ํŒŒ์„œ๋ฅผ ์ง์ ‘ ์ƒ์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•๋„ ์žˆ์ง€๋งŒ ํŒŒ์„œ ์ œ๋„ค๋ ˆ์ดํ„ฐ๋ผ๋Š” ๋ณ„๋„์˜ ๋„๊ตฌ๋ฅผ ์ด์šฉํ•ด์„œ ํŒŒ์„œ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•๋„ ์žˆ๋‹ค๋Š” ์ ๋งŒ ์•Œ์•„๋‘๋„๋ก ํ•˜์ž.

 

ํŒŒ์„œ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•

 

๋งˆ์ง€๋ง‰์œผ๋กœ, ํŒŒ์„œ์˜ ํŒŒ์‹ฑ ์ „๋žต์— ๋Œ€ํ•ด์„œ๋„ ๊ฐ„๋‹จํžˆ ์•Œ์•„๋‘์ž. ํŒŒ์‹ฑ ์ „๋žต์—๋Š” ํฌ๊ฒŒ ์•„๋ž˜์™€ ๊ฐ™์€ ์ข…๋ฅ˜๋กœ ๊ตฌ๋ถ„ ๋œ๋‹ค.

 

ํŒŒ์‹ฑ ์ „๋žต์˜ ์ข…๋ฅ˜

 

์šฐ๋ฆฌ๊ฐ€ ๋งŒ๋“ค ํŒŒ์„œ์˜ ํŒŒ์‹ฑ ์ „๋žต์€ ํ•˜ํ–ฅ์‹์˜ ์žฌ๊ท€์  ํ•˜ํ–ฅ ํŒŒ์‹ฑ์—์„œ๋„ ํ•˜ํ–ฅ์‹ ์—ฐ์‚ฐ์ž ์šฐ์„ ์ˆœ์œ„ ํŒŒ์„œ๋ฅผ ๋งŒ๋“ค ๊ฒƒ์ด๋‹ค. ์ด ํŒŒ์„œ๋ฅผ ํ”„๋žซ ํŒŒ์„œ๋ผ๊ณ ๋„ ๋ถ€๋ฅธ๋‹ค. ํ•˜ํ–ฅ์‹์„ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ ๋Š” AST์˜ ๋ฃจํŠธ ๋…ธ๋“œ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์œผ๋กœ ์‹œ์ž‘ํ•ด์„œ ์ ์  ์•„๋ž˜์ชฝ์œผ๋กœ ํŒŒ์‹ฑํ•ด ๋‚˜๊ฐ„๋‹ค. ์ด๋Ÿฌํ•œ ์ „๋žต์€ ์ฒ˜์Œ ํŒŒ์„œ๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ์‚ฌ๋žŒ๋“ค์—๊ฒŒ ์ž์ฃผ ๊ถŒ์žฅ๋˜๋Š” ์ „๋žต์ด๋‹ค. ์™œ๋ƒํ•˜๋ฉด ์žฌ๊ท€์  ํ•˜ํ–ฅ ํŒŒ์„œ๊ฐ€ ๊ตฌ์„ฑํ•˜๋Š” AST์™€ ๊ทธ ์ƒ์„ฑ ๋ฐฉ์‹์ด ์‚ฌ๋žŒ์ด ์ƒ๊ฐํ•˜๋Š” ๋ฐฉ์‹๊ณผ ์œ ์‚ฌํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๋”ฐ๋ผ์„œ ์šฐ๋ฆฌ๋Š” ์žฌ๊ท€์  ํ•˜ํ–ฅ ํŒŒ์‹ฑ์˜ ํ•˜ํ–ฅ์‹ ์—ฐ์‚ฐ์ž ์šฐ์„ ์ˆœ์œ„ ํŒŒ์„œ๋ฅผ ๋งŒ๋“ค์–ด๋ณผ ๊ฒƒ์ด๋‹ค.

 

์ด์ œ ๊ฐ„๋‹จํ•˜๊ฒŒ ํŒŒ์„œ๊ฐ€ ๋ฌด์—‡์ด๊ณ , ์šฐ๋ฆฌ๊ฐ€ ๋งŒ๋“ค ํŒŒ์„œ๊ฐ€ ์–ด๋–ค ํŒŒ์‹ฑ ์ „๋žต์„ ๊ฐ€์ ธ๊ฐˆ์ง€๋„ ์•Œ์•„๋ณด์•˜๋‹ค. ์ด์ œ ๋ณธ๊ฒฉ์ ์œผ๋กœ ํŒŒ์„œ์˜ ๊ธฐ๋Šฅ์„ ํ•˜๋‚˜์”ฉ ๊ตฌํ˜„ํ•ด๋ณด์ž.

2. let ๋ฌธ ํŒŒ์‹ฑํ•˜๊ธฐ

์šฐ๋ฆฌ๋งŒ์˜ ํŒŒ์„œ์— ์ฒซ๋ฒˆ์งธ๋กœ ๋„์ž…ํ•ด๋ณผ ๊ธฐ๋Šฅ์€ Monkey ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด์˜ let ์„ ์–ธ๋ฌธ์„ ํŒŒ์‹ฑํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ์ฆ‰, ์•„๋ž˜์™€ ๊ฐ™์€ ์†Œ์Šค์ฝ”๋“œ๋ฅผ ์ž…๋ ฅ์œผ๋กœ ๋ฐ›์•˜์„ ๋•Œ, ํŒŒ์„œ๊ฐ€ ์ •ํ™•ํžˆ ํŒŒ์‹ฑ์„ ์ž˜ ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” ๊ฒƒ์ด ๋ชฉํ‘œ์ด๋‹ค.

 

let x = 5;
let y = 10;
let add = fn(a, b) {
  return a + b;
};

 

let ๋ฌธ์„ ์ •ํ™•ํžˆ ํŒŒ์‹ฑํ•œ๋‹ค๋Š” ๊ฒƒ์€ ํŒŒ์„œ๊ฐ€ let ๋ฌธ์ด ๋‹ด๊ณ  ์žˆ๋Š” ์ •๋ณด๋ฅผ ์ •ํ™•ํžˆ ํ‘œํ˜„ํ•˜๋Š” AST ์ž๋ฃŒ๊ตฌ์กฐ๋ฅผ ๋งŒ๋“ ๋‹ค๋Š” ๋œป์ด๋‹ค. let ๋ฌธ์„ ํŒŒ์‹ฑํ•˜๊ธฐ ์ „์— ์œ„์™€ ๊ฐ™์€ let ๋ฌธ์ด ์–ด๋–ค ์š”์†Œ๋“ค๋กœ ๊ตฌ์„ฑ๋˜์–ด ์žˆ๋Š”์ง€ ํŒŒ์•…ํ•  ํ•„์š”๊ฐ€ ์žˆ๋‹ค. ๊ทธ๋ž˜์•ผ '์ด ์š”์†Œ๋“ค'์„ ์ด์šฉํ•ด์„œ AST ์ž๋ฃŒ๊ตฌ์กฐ๋ฅผ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. 

 

์œ„ ์†Œ์Šค์ฝ”๋“œ๋Š” let ๋ฌธ 3๊ฐœ๋กœ ๊ตฌ์„ฑ๋œ ์ผ๋ จ์˜ ๋ช…๋ น๋ฌธ์ด๋‹ค. ๊ทธ๋ฆฌ๊ณ  let ๋ฌธ์€ 2๊ฐœ์˜ ๊ตฌ์„ฑ ์š”์†Œ๋กœ ๊ตฌ์„ฑ๋œ๋‹ค. ํ•˜๋‚˜๋Š” ์‹๋ณ„์ž์ด๊ณ , ๋‹ค๋ฅธ ํ•˜๋‚˜๋Š” ํ‘œํ˜„์‹์ด๋‹ค.

 

๋นจ๊ฐ„์ƒ‰์€ ์‹๋ณ„์ž, ํŒŒ๋ž€์ƒ‰์€ ํ‘œํ˜„์‹

 

ํ•œ ์ค„์˜ let ๋ช…๋ น๋ฌธ์€ ์‹๋ณ„์ž์™€ ํ‘œํ˜„์‹์œผ๋กœ ๊ตฌ์„ฑ๋œ๋‹ค. ์‹๋ณ„์ž๋Š” ๋นจ๊ฐ„์ƒ‰, ํ‘œํ˜„์‹์€ ํŒŒ๋ž€์ƒ‰ ๊ธ€์”จ์ด๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์œ„ ์†Œ์Šค์ฝ”๋“œ๋ฅผ ๋˜ 2๊ฐ€์ง€ ๊ตฌ์„ฑ์š”์†Œ๋กœ๋„ ๊ตฌ๋ถ„ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

ํšŒ์ƒ‰ ์„ , ๋„ค๋ชจ์นธ์€ ๋ช…๋ น๋ฌธ, ํŒŒ๋ž€์ƒ‰์€ ํ‘œํ˜„์‹

 

์œ„ ์ž๋ฃŒ์˜ ํšŒ์ƒ‰ ์„  ๋˜๋Š” ๋„ค๋ชจ์นธ์„ ์šฐ๋ฆฌ๋Š” 1๊ฐœ์˜ ๋ช…๋ น๋ฌธ์ด๋ผ๊ณ  ํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ํŒŒ๋ž€์ƒ‰ ๋ถ€๋ถ„์€ ํ‘œํ˜„์‹์ด๋ผ๊ณ  ํ•œ๋‹ค. ์ด ๋‘ ๊ฐœ ๊ฐ„์˜ ์ฐจ์ด์ ์ด ์žˆ๋Š”๋ฐ, ๋ช…๋ น๋ฌธ์€ ๊ฐ’์„ ๋งŒ๋“ค์ง€ ์•Š์ง€๋งŒ, ํ‘œํ˜„์‹์€ ๊ฐ’์„ ๋งŒ๋“ ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. ๋ฌผ๋ก  ์œ„์˜ ๊ฒฝ์šฐ์—์„œ ํ•จ์ˆ˜ ๋ฆฌํ„ฐ๋Ÿด ๋ถ€๋ถ„๋„ ํ‘œํ˜„์‹์œผ๋กœ ์ •์˜ํ•˜๊ธด ํ–ˆ์ง€๋งŒ ์ด๋ฅผ ํ‘œํ˜„์‹์œผ๋กœ ์ •์˜ํ• ์ง€ ๋ช…๋ น๋ฌธ์œผ๋กœ ์ •์˜ํ• ์ง€๋Š” ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด๋งˆ๋‹ค ๋‹ฌ๋ผ์ง„๋‹ค. ๋‹ค๋ฅธ ์˜ˆ๋กœ, if ๊ตฌ๋ฌธ๋„ if ๊ตฌ๋ฌธ ๋‚ด๋ถ€์—์„œ ๊ฐ’์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋„๋ก ์ง€์›ํ•˜๋Š” ์–ธ์–ด๋ผ๋ฉด if ๊ตฌ๋ฌธ์„ ํ‘œํ˜„์‹์œผ๋กœ ์ •์˜ํ•˜๊ฒŒ ๋œ๋‹ค.

 

์ด์ œ let๋ฌธ์˜ ๊ตฌ์„ฑ์š”์†Œ๋ฅผ ์‚ดํŽด๋ณด์•˜์œผ๋‹ˆ, ์šฐ๋ฆฌ๋Š” ์•ž์œผ๋กœ AST ์ž๋ฃŒ๊ตฌ์กฐ๋ฅผ ๋งŒ๋“ค๋•Œ ๋‘ ๊ฐ€์ง€ ์œ ํ˜•์˜ ๋…ธ๋“œ๋ฅผ ๋งŒ๋“ค์–ด ์‚ฌ์šฉํ•   ๊ฒƒ์ด๋‹ค. ํ•˜๋‚˜๋Š” ํ‘œํ˜„์‹ ํƒ€์ž…๊ณผ ํ•˜๋‚˜๋Š” ๋ช…๋ น๋ฌธ ํƒ€์ž…์ด๋‹ค. ํ•ด๋‹น ์œ ํ˜•์˜ ๋…ธ๋“œ๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด go ์–ธ์–ด์—์„œ interface ๋ผ๋Š” ๋ฌธ๋ฒ•์„ ์‚ฌ์šฉํ•  ๊ฒƒ์ด๋‹ค. ์†Œ์Šค์ฝ”๋“œ๋ฅผ ์‚ดํŽด๋ณด์ž.

 

// ast/ast.go
package ast

type Node interface {
	TokenLiteral() string
}

type Statement interface {
	Node
	statementNode()
}

type Expression interface {
	Node
	expressionNode()
}

 

๋จผ์ € Node ๋ผ๋Š” ํƒ€์ž…์„ ์ •์˜ํ•˜๊ณ  ํ•ด๋‹น ํƒ€์ž…์— TokenLiteral ์ด๋ผ๋Š” ๋ฉ”์†Œ๋“œ๋ฅผ ์ธํ„ฐํŽ˜์ด์Šค ์ค‘ ํ•˜๋‚˜๋กœ ์„ค์ •ํ–ˆ๋‹ค. ์ด์ œ Node ํƒ€์ž…์„ ๊ฐ–๋Š” ๊ฒƒ์€ TokenLiteral ์ด๋ผ๋Š” ๋ฉ”์†Œ๋“œ๋ฅผ ๋ฐ˜๋“œ์‹œ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•ด์•ผ ํ•œ๋‹ค. ์ด๋ ‡๊ฒŒ ๋‚˜๋จธ์ง€๋„ Statement, Expression ํƒ€์ž…์˜ ์ธํ„ฐํŽ˜์ด์Šค๋„ ๊ตฌํ˜„ํ–ˆ๋‹ค. Statement๋Š” ๋ช…๋ น๋ฌธ์„, Expression์€ ํ‘œํ˜„์‹์— ๋Œ€ํ•œ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์˜๋ฏธํ•œ๋‹ค. ์ด 2๊ฐœ์˜ ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ๊ฐ–๋Š” statementNode() ์™€ expressionNode() ๋ฉ”์†Œ๋“œ์˜ ๊ธฐ๋Šฅ์€ ์ถ”ํ›„์— ์†Œ๊ฐœํ•˜๊ธฐ๋กœ ํ•˜์ž. 

 

์ด์ œ AST ์ž๋ฃŒ๊ตฌ์กฐ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ์‹œ์ž‘์  ์ฆ‰, ๋ฃจํŠธ๋…ธ๋“œ๋ฅผ ์ƒ์„ฑํ•ด๋ณด๋„๋ก ํ•˜์ž.

 

// ast/ast.go
type Program struct {
	Statements []Statement
}

func (p *Program) TokenLiteral() string {
	if len(p.Statements) > 0 {
		return p.Statements[0].TokenLiteral()
	} else {
		return ""
	}
}

 

Program ์ด๋ผ๋Š” ๊ตฌ์กฐ์ฒด๋ฅผ ์ •์˜ํ–ˆ๊ณ , ํ•ด๋‹น ๊ตฌ์กฐ์ฒด์˜ ๋ฉค๋ฒ„๋กœ ์Šฌ๋ผ์ด์Šค ํ˜•ํƒœ์˜ Statement ํƒ€์ž…์˜ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ •์˜ํ–ˆ๋‹ค. ์ฆ‰, ์—ฌ๊ธฐ์—๋Š” ์ด์ œ ์—ฌ๋Ÿฌ ๊ฐœ์˜ ๋ช…๋ น๋ฌธ๋“ค์ด ๋“ค์–ด๊ฐ„๋‹ค. ์ผ๋ก€๋กœ, ์šฐ๋ฆฌ๊ฐ€ ์œ„์—์„œ ์‚ดํŽด๋ณด์•˜๋˜ ์•„๋ž˜์˜ let ๋ฌธ๋“ค์ด ๋“ค์–ด๊ฐ€๋Š” ์…ˆ์ด๋‹ค. 

 

let x = 5;
let y = 10;
let add = fn(a, b) {
  return a + b;
};

 

๋‹ค์Œ์€ Program ์ด๋ผ๋Š” ๊ตฌ์กฐ์ฒด๋ฅผ pointer recevier๋กœ ํ•˜๋Š” ๋ฉ”์†Œ๋“œ์ธ TokenLiteral์„ ์ •์˜ํ–ˆ๋‹ค. ์ด ๋ฉ”์†Œ๋“œ์˜ ์—ญํ• ์€ ๊ฐ„๋‹จํ•˜๋‹ค. Program ์ด๋ผ๋Š” ๊ตฌ์กฐ์ฒด์— ๋ช…๋ น๋ฌธ๋“ค์ด ๋“ค์–ด์žˆ์œผ๋ฉด ๊ฐ€์žฅ ์ฒซ๋ฒˆ์งธ ์š”์†Œ์— ์žˆ๋Š” Statement ํƒ€์ž… ์ธํ„ฐํŽ˜์ด์Šค์˜ TokenLiteral ๋ฉ”์†Œ๋“œ๋ฅผ ์žฌ๊ท€์ ์œผ๋กœ ํ˜ธ์ถœํ•˜๋ฉด ๋œ๋‹ค.(์—ฌ๊ธฐ์„œ ๊ฐ€์žฅ ์ฒซ๋ฒˆ์งธ ์š”์†Œ๋กœ ๊ณ ์ •๋˜์–ด ์žˆ๋Š” ์ด์œ ๋Š” ์ถ”ํ›„์— ์•Œ๊ฒŒ ๋œ๋‹ค)

 

AST ์ƒ์„ฑ์— ํ•„์š”ํ•œ ๊ธฐ์ดˆ์ ์ธ ๋ธ”๋ก์ธ Program ๊ตฌ์กฐ์ฒด๋ฅผ ์•Œ์•„๋ณด์•˜๋‹ค. ์ด์ œ๋Š” ์ •๋ง let ๋ฌธ์„ ํŒŒ์‹ฑํ•ด๋ณด์ž. ์˜ˆ๋ฅผ ๋“ค์–ด, let x = 5; ๋ผ๋Š” ๊ตฌ๋ฌธ์ด ์žˆ์„ ๋•Œ, ์–ด๋–ค ํ•„๋“œ๊ฐ€ ํ•„์š”ํ• ์ง€ ์ƒ๊ฐํ•ด๋ณด์ž. ๊ฐ€์žฅ ๋จผ์ € x ๋ผ๋Š” ๋ณ€์ˆ˜ ์ด๋ฆ„ ์ฆ‰, ์‹๋ณ„์ž๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ํ•„๋“œ๊ฐ€ ํ•„์š”ํ•˜๋‹ค. ๋‘ ๋ฒˆ์งธ๋กœ๋Š” ๋“ฑํ˜ธ(=) ์˜ค๋ฅธ์ชฝ์— ์žˆ๋Š” ํ‘œํ˜„์‹ ์ฆ‰, 5 ๋ผ๋Š” ๊ฒƒ์„ ๊ฐ€๋ฆฌํ‚ค๋Š” ํ•„๋“œ๊ฐ€ ํ•„์š”ํ•˜๋‹ค. ์ด ๋•Œ ์ฃผ์˜ํ•ด์•ผ ํ•  ์ ์€ 5 ๋ผ๋Š” ๋ฆฌํ„ฐ๋Ÿด ๊ฐ’ ๋ง๊ณ ๋„ ๊ทธ ๋’ค์— ๋ฌด์—‡์ธ๊ฐ€ ๋” ์žˆ๋Š” ๊ฒฝ์šฐ๋„ ์ปค๋ฒ„ํ•ด์•ผ ํ•œ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, let x = 5 * 10 + 12; ์ด๋Ÿฐ ์‹์œผ๋กœ๋„ ํ‘œํ˜„์‹์ด ํ‘œํ˜„๋  ์ˆ˜ ์žˆ๋‹ค. let x = 5 + add(5, 4); ์ด๋Ÿฐ ๊ฒƒ๋„ ๋งˆ์ฐฌ๊ฐ€์ง€์ด๋‹ค. ์ด๋Ÿฐ ๊ฒฝ์šฐ๋„ ์ปค๋ฒ„ํ•˜๊ธฐ ์œ„ํ•ด์„œ ์šฐ๋ฆฌ๋Š” (์•ž์„œ ๋ ‰์„œ ๊ตฌํ˜„ํ•  ๋•Œ ์ž์ฃผ ์‚ดํŽด๋ณด์•˜๋˜) ํ† ํฐ ํ•„๋“œ๋„ ํ•„์š”ํ•˜๋‹ค.

 

๋”ฐ๋ผ์„œ, let x = 5; ๋ผ๋Š” let ๋ฌธ์„ ํŒŒ์‹ฑํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” [1. ์‹๋ณ„์ž ํ•„๋“œ], [2. ํ‘œํ˜„์‹ ํ•„๋“œ], [3. ํ† ํฐ ํ•„๋“œ] ์ด 3๊ฐ€์ง€๊ฐ€ ํ•„์š”ํ•˜๋‹ค. ์ด๋ฅผ ์ •์˜ํ•œ ์†Œ์Šค์ฝ”๋“œ๋ฅผ ์‚ดํŽด๋ณด์ž.

 

// ast/ast.go
package ast

import (
	"monkey/token"
)

type LetStatement struct {
	Token token.Token
	Name  *Identifier
	Value Expression
}

func (ls *LetStatement) statementNode()       {}
func (ls *LetStatement) TokenLiteral() string { return ls.Token.Literal }

type Identifier struct {
	Token token.Token
	Value string
}

func (i *Identifier) expressionNode()      {}
func (i *Identifier) TokenLiteral() string { return i.Token.Literal }

 

๊ฐ€์žฅ ๋จผ์ € LetStatement ๋ผ๋Š” ์ด๋ฆ„์˜ ๊ตฌ์กฐ์ฒด๋ฅผ ์‚ดํŽด๋ณด์ž. ์ด๋ฆ„์—์„œ ์•Œ ์ˆ˜ ์žˆ๋“ฏ์ด ์ด ๊ตฌ์กฐ์ฒด๊ฐ€ let ๋ฌธ 1๊ฐœ๋ฅผ ์˜๋ฏธํ•œ๋‹ค. ์ด ๊ตฌ์กฐ์ฒด๊ฐ€ ๊ฐ–๋Š” ๋ฉค๋ฒ„๋“ค์€ ์ด 3๊ฐ€์ง€์ด๋‹ค.

 

  • Token: [3. ํ† ํฐ ํ•„๋“œ]๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ํ•„๋“œ(๋ณต์žกํ•œ ํ‘œํ˜„์‹์„ ์ถ”์ ํ•˜๊ธฐ ์œ„ํ•ด ํ•„์š”)
  • Name: [1. ์‹๋ณ„์ž]๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ํ•„๋“œ(์˜ ํฌ์ธํ„ฐ ๋ณ€์ˆ˜)
  • Value: [2. ํ‘œํ˜„์‹]์„ ๊ฐ€๋ฆฌํ‚ค๋Š” ํ•„๋“œ

์ด LetStatement ๊ตฌ์กฐ์ฒด๋Š” AST๋ฅผ ๊ตฌ์„ฑํ•˜๋Š” ๋…ธ๋“œ๋กœ ๋“ค์–ด๊ฐ€๋ฉด์„œ ๋ช…๋ น๋ฌธ์— ์†ํ•˜๋Š” ๋…ธ๋“œ์ด๊ธฐ ๋•Œ๋ฌธ์— Statement ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๋งŒ์กฑํ•ด์•ผ ํ•œ๋‹ค. ๋”ฐ๋ผ์„œ statementNode()์™€ TokenLiteral() ๋ฉ”์†Œ๋“œ๋ฅผ ์ธํ„ฐํŽ˜์ด์Šค๋กœ ๊ตฌํ˜„ํ•˜์˜€๋‹ค.

 

LetStatement ๊ตฌ์กฐ์ฒด ๋ฉค๋ฒ„ ์ค‘ Name ์ด๋ผ๋Š” ๋ฉค๋ฒ„๋Š” Identifier ๋ผ๋Š” ๊ตฌ์กฐ์ฒด์˜ ํฌ์ธํ„ฐ ๋ณ€์ˆ˜๋กœ ์ •์˜๋˜์—ˆ๋‹ค. ์ด Identifier ๊ตฌ์กฐ์ฒด ๋ณ€์ˆ˜๋Š” ๋ฌด์—‡์ธ์ง€ ์œ„ ์†Œ์Šค์ฝ”๋“œ์—์„œ ์‚ดํŽด๋ณด์ž. ํ•ด๋‹น ๊ตฌ์กฐ์ฒด๋Š” Token ๋ฉค๋ฒ„์™€ Value ๋ฉค๋ฒ„๋ฅผ ๊ฐ–๋Š”๋‹ค. ์ด ๊ตฌ์กฐ์ฒด์—์„œ ์ฃผ๋ชฉํ•  ์ ์€ Expression ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๋งŒ์กฑ์‹œํ‚ค๋„๋ก expressionNode()์™€ TokenLiteral() ๋ฉ”์†Œ๋“œ๋ฅผ ๊ตฌํ˜„์‹œ์ผฐ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. Identifier ๊ตฌ์กฐ์ฒด๋Š” '์‹๋ณ„์ž'๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ๊ฒƒ์ด๊ณ , ์ด๋Š” ํ‘œํ˜„์‹์ด ์•„๋‹˜์—๋„ ์™œ ํ‘œํ˜„์‹์ด ๊ฐ–๋Š” ๋…ธ๋“œ๊ฐ€ ๋งŒ์กฑ์‹œ์ผœ์•ผํ•˜๋Š” Expression ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ–ˆ์„๊นŒ? ์ด๋Š” Monkey ์–ธ์–ด๊ฐ€ ๋ฐ”๋กœ ์‹๋ณ„์ž๋ฅผ ์„ ์–ธํ•˜๊ณ  ์ •์˜ํ•˜๋Š” ๊ฒƒ์„ ํ•œ๋ฒˆ์— ํ•˜์—ฌ ๊ฐ’์„ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์šฐ๋ฆฌ๊ฐ€ ๊ณ„์† ์˜ˆ์‹œ๋ฅผ ๋“ค๊ณ  ์žˆ๋Š” let x = 5; ๊ตฌ๋ฌธ๋„ ์‹๋ณ„์ž๋ฅผ ์„ ์–ธํ•˜๊ณ  5๋ผ๋Š” ๊ฐ’์„ ์ •์˜ํ•˜์—ฌ ๊ฐ’์„ ์ƒ์„ฑํ•œ ๊ฒƒ์ด๋‹ค.

 

์ง€๊ธˆ๊นŒ์ง€ go ์–ธ์–ด๋กœ let ๋ฌธ์„ ํŒŒ์‹ฑํ•œ ๊ฒฐ๊ณผ๋กœ ์ƒ์„ฑ๋˜๋Š” AST ์ž๋ฃŒ๊ตฌ์กฐ๋ฅผ ๋„์‹ํ™”ํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

 

์ง€๊ธˆ๊นŒ์ง€ ๋งŒ๋“  AST ์ž๋ฃŒ๊ตฌ์กฐ์˜ ๋„์‹ํ™”

 

์ด์ œ ํŒŒ์„œ๋ฅผ ์ œ์ž‘ํ•˜๋Š” ์†Œ์Šค์ฝ”๋“œ๋ฅผ ์‚ดํŽด๋ณด์ž. 

 

// parser/parser.go
package parser

import (
	"monkey/ast"
	"monkey/lexer"
	"monkey/token"
)

type Parser struct {
	l         *lexer.Lexer
	curToken  token.Token
	peekToken token.Token
}

func New(l *lexer.Lexer) *Parser {
	p := &Parser{l: l}
	// ํ˜„์žฌ ์ดˆ๊ธฐ token ๊ฐ’์€ ๋นˆ ๋ฌธ์ž์ด๊ธฐ ๋•Œ๋ฌธ์—, curToken, peekToken์— ํ† ํฐ์„ ๋‹ด์œผ๋ ค๋ฉด 2๋ฒˆ ์ˆ˜ํ–‰
	p.nextToken()
	p.nextToken()
	return p
}

func (p *Parser) nextToken() {
	p.curToken = p.peekToken
	p.peekToken = p.l.NextToken()
}

func (p *Parser) ParseProgram() *ast.Program {
	return nil
}

 

์œ„ ์†Œ์Šค์ฝ”๋“œ๋Š” ๋ ‰์„œ๋ฅผ ์ž…๋ ฅ์œผ๋กœ ๋ฐ›์•„์„œ ๋ ‰์„œ๋ฅผ ๋ฉค๋ฒ„๋กœ๋Š” Parser ๊ตฌ์กฐ์ฒด ๋ณ€์ˆ˜๋ฅผ ์ •์˜ํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ฃผ์„์—๋„ ํ‘œ์‹œํ•ด๋‘์—ˆ์ง€๋งŒ ๋ ‰์„œ๊ฐ€ ํ† ํฐํ™”์‹œํ‚จ ํ† ํฐ๋“ค์„ ํŒŒ์„œ ๊ตฌ์กฐ์ฒด ๋ฉค๋ฒ„์ธ curToken, peekToken ๋ณ€์ˆ˜์— ์ตœ์ดˆ๋กœ ๋‹ด์•„๋‚ด๊ธฐ ์œ„ํ•ด 2๋ฒˆ nextToken ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค. ์ด nextToken ๋ฉ”์†Œ๋“œ๋Š” ๋ณ„ ๊ฒƒ์€ ์•„๋‹ˆ๊ณ , ์šฐ๋ฆฌ๊ฐ€ ์ด์ „ ํฌ์ŠคํŒ…์—์„œ ๊ตฌํ˜„ํ•œ ๋ ‰์„œ์˜ NextToken() ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์ด๋‹ค.(๊ธฐ์–ต์ด ๋‚˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ์ด์ „ ํฌ์ŠคํŒ… ์ฐธ์กฐ)

 

๊ทธ๋ฆฌ๊ณ  ParseProgram() ์ด๋ผ๋Š” Parser ๊ตฌ์กฐ์ฒด์˜ pointer ๋ณ€์ˆ˜๋ฅผ receive ํ•˜๋Š” ๋ฉ”์†Œ๋“œ๋Š” ํŒŒ์‹ฑ ํ›„์˜ ๊ฒฐ๊ณผ๋ฌผ์ธ AST ์ž๋ฃŒ๊ตฌ์กฐ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ํ•œ๋‹ค. ์ง€๊ธˆ์€ ๋”ฐ๋กœ ๊ตฌํ˜„ํ•œ ๊ฒƒ์ด ์—†๊ธฐ์— ๊ณง๋ฐ”๋กœ nil ์„ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ์„ค์ •ํ–ˆ๋‹ค.

 

๋ ‰์„œ๋ฅผ ๊ตฌํ˜„ํ•˜๊ณ  ํ…Œ์ŠคํŠธํ–ˆ์„ ๋•Œ์ฒ˜๋Ÿผ ํŒŒ์„œ๋„ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๊ณ , ์šฐ๋ฆฌ๊ฐ€ ๊ฐœ๋ฐœํ•˜๊ณ  ์žˆ๋Š” ํŒŒ์„œ๊ฐ€ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ํ†ต๊ณผํ•˜๋Š”์ง€ ์‚ดํŽด๋ณด์•„์•ผ ํ•œ๋‹ค. ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ถ€ํ„ฐ ์‚ดํŽด๋ณด์ž.

 

// parser/parser_test.go
package parser

import (
	"monkey/ast"
	"monkey/lexer"
	"testing"
)

func TestLetStatements(t *testing.T) {
	input := `
let x = 5;
let y = 10;
let foobar = 838383;
`
	// lexer(lexing is not run yet)
	l := lexer.New(input)
	// parser(parsing is not run yet)
	p := New(l)

	program := p.ParseProgram()
	if program == nil {
		t.Fatalf("ParseProgram() returned nill")
	}
	if len(program.Statements) != 3 {
		t.Fatalf("program.Statements does not contain 3 statements. got=%d",
			len(program.Statements))
	}

	tests := []struct {
		expectedIdentifier string
	}{
		{"x"},
		{"y"},
		{"foobar"},
	}

	for i, tt := range tests {
		stmt := program.Statements[i]
		if !testLetStatement(t, stmt, tt.expectedIdentifier) {
			return
		}
	}
}

func testLetStatement(t *testing.T, s ast.Statement, name string) bool {
	if s.TokenLiteral() != "let" {
		t.Errorf("s.TokenLiteral not 'let'. got=%q", s.TokenLiteral())
		return false
	}
    // type assertion(downcast from interface to struct)
	letStmt, ok := s.(*ast.LetStatement)
	if !ok {
		t.Errorf("s not *ast.LetStatement. got=%T", s)
		return false
	}

	if letStmt.Name.Value != name {
		t.Errorf("letStmt.Name.Value not '%s'. got=%s", name, letStmt.Name.Value)
		return false
	}

	if letStmt.Name.TokenLiteral() != name {
		t.Errorf("letStmt.Name.TokenLiteral() not '%s'. got=%s", name, letStmt.Name.TokenLiteral())
		return false
	}
	return true
}

 

input ๋ณ€์ˆ˜์—๋Š” ๋ ‰์‹ฑ ๋ฐ ํŒŒ์‹ฑ์˜ ๋Œ€์ƒ์ด ์†Œ์Šค์ฝ”๋“œ ๋ฌธ์ž์—ด์„ ์ •์˜ํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋ ‰์„œ์™€ ํŒŒ์„œ๋ฅผ ์ค€๋น„ํ•œ๋‹ค. tests ๋ณ€์ˆ˜๋ฅผ ๋ณด๋ฉด input์— ๋ช…์‹œํ•œ ์†Œ์Šค์ฝ”๋“œ ๋ฌธ์ž์—ด์— ๋งž๊ฒŒ๋” x, y , foobar ๋ผ๋Š” ๋ฌธ์ž์—ด์ด ๋‹ด๊ฒจ์žˆ๋Š” ๊ตฌ์กฐ์ฒด๋ฅผ ์ •์˜ํ•œ๋‹ค. ์ฆ‰, ์ผ์ข…์˜ ํ…Œ์ŠคํŠธ ๊ธฐ๋Œ“๊ฐ’์„ ๋ฏธ๋ฆฌ ์‚ฌ์ „์— ์ •์˜ํ•˜๊ณ  ์šฐ๋ฆฌ์˜ ํŒŒ์„œ๊ฐ€ ๋™์ž‘ํ–ˆ์„ ๋•Œ ๊ธฐ๋Œ“๊ฐ’๊ณผ ์ผ์น˜ํ•˜๋Š”์ง€ ๋ณด๊ธฐ ์œ„ํ•จ์ด๋‹ค.

 

tests ๊ตฌ์กฐ์ฒด ๊ธธ์ด๋งŒํผ ๋ฃจํ”„๋ฅผ ๋„๋Š”๋ฐ, program ์ด๋ผ๋Š” ๋ณ€์ˆ˜์— ์ •์˜๋œ AST ์ž๋ฃŒ๊ตฌ์กฐ์— ๋‹ด๊ฒจ์ง„ ๋ช…๋ น๋ฌธ ํ•˜๋‚˜์”ฉ์„ ๋น„๊ตํ•˜๋Š”๋ฐ ์ด ๋•Œ testLetStatement ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•ด ํ…Œ์ŠคํŠธํ•œ๋‹ค. ์ด testLetStatement ํ•จ์ˆ˜์˜ ๊ธฐ๋Šฅ์„ ์‚ดํŽด๋ณด์ž.

 

๊ฒ€์‚ฌํ•˜๊ณ  ์žˆ๋Š” ๋ช…๋ น๋ฌธ์€ Statement ํƒ€์ž…์— ์†ํ•˜๊ธฐ ๋•Œ๋ฌธ์— TokenLiteral ๋ฉ”์†Œ๋“œ๊ฐ€ ์ธํ„ฐํŽ˜์ด์Šค๋กœ ๊ตฌํ˜„๋˜์–ด ์žˆ์„ ๊ฒƒ์ด๊ณ , ์ด๋ฅผ ํ˜ธ์ถœํ•จ์œผ๋กœ์จ ๊ฒ€์‚ฌํ•˜๊ณ  ์žˆ๋Š” ๋ช…๋ น๋ฌธ์ด 'let' ๋ฌธ์ธ์ง€๋ฅผ ๋จผ์ € ํ™•์ธํ•œ๋‹ค.

 

๋‹ค์Œ์œผ๋กœ go ์–ธ์–ด์—์„œ Type Assertion ์ด๋ผ๋Š” ๋ฌธ๋ฒ•์ด ๋“ฑ์žฅํ•œ๋‹ค. ์ฆ‰, ๋ณ€์ˆ˜ s๋Š” Statement ๋ผ๋Š” ์ธํ„ฐํŽ˜์ด์Šค์ธ๋ฐ, ํ•ด๋‹น ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ LetStatement ๋ผ๋Š” ์ด๋ฆ„์˜ ๊ตฌ์กฐ์ฒด๋กœ downcasting ํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ์™œ๋ƒํ•˜๋ฉด ๋ฐ‘์—์„œ LetStatement ๊ตฌ์กฐ์ฒด ๋ฉค๋ฒ„ ๋ณ€์ˆ˜์ธ Name์— ์ ‘๊ทผํ•˜๊ธฐ ์œ„ํ•ด์„œ๋‹ค.

 

LetStatement์˜ Name ๋ฉค๋ฒ„๋Š” Identifier ๊ตฌ์กฐ์ฒด๋ฅผ ๋‹ด๊ณ  ์žˆ๋Š”๋ฐ, ๋จผ์ € Identifier ๊ตฌ์กฐ์ฒด์˜ Value ๋ฉค๋ฒ„์— ๋“ค์–ด์žˆ๋Š” ๊ฐ’์„ ํ™•์ธํ•œ๋‹ค. ์ด ๊ฐ’์—๋Š” ์‹๋ณ„์ž(ex. x, y, foobar)๊ฐ€ ๋“ค์–ด์žˆ์–ด์•ผ๋งŒ ํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ํ•ด๋‹น Identifer ๊ตฌ์กฐ์ฒด์˜ TokenLiteral() ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•ด์„œ ํ˜น์‹œ๋ผ๋„ ์‹๋ณ„์ž์— ํ‘œํ˜„์‹์ด ์—ฐ๊ฒฐ๋˜์–ด ์žˆ๋Š”์ง€ ์ฆ‰, ํ† ํฐ์ด ์žˆ๋Š”์ง€ ํ™•์ธํ•œ๋‹ค.

 

์ฐธ๊ณ ๋กœ, ์—ฌ๊ธฐ์„œ๋Š” LetStatement ๊ตฌ์กฐ์ฒด์˜ Value ๋ฉค๋ฒ„๋ฅผ ๊ฒ€์‚ฌํ•˜์ง€๋Š” ์•Š๋Š”๋ฐ, ์ถ”ํ›„์— ์ถ”๊ฐ€๋  ์˜ˆ์ •์ด๋‹ค. ์ง€๊ธˆ ๋‹น์žฅ์€ let ๋ฌธ ํŒŒ์‹ฑ์ด ๋™์ž‘ํ•˜๋Š”์ง€ ์—ฌ๋ถ€๋งŒ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•จ์ด๋ผ ์Šคํ‚ตํ•˜์˜€๋‹ค. 

 

์ด์ œ ์šฐ๋ฆฌ๋งŒ์˜ ํŒŒ์„œ์˜ ๊ธฐ๋Šฅ์„ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด์„œ ParseProgram() ์ด๋ผ๋Š” ์—”ํŠธ๋ฆฌํฌ์ธํŠธ ๋ฉ”์†Œ๋“œ์˜ ๋กœ์ง์— ์‚ด์„ ๋ถ™์—ฌ๋ณด์ž. ๋จผ์ € ์—”ํŠธ๋ฆฌํฌ์ธํŠธ ํ•จ์ˆ˜์˜ ์ƒ๊น€์ƒˆ๋ฅผ ๋ณด๊ณ , ๊ทธ ์•ˆ์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๋˜ ๋‹ค๋ฅธ ํ•จ์ˆ˜๊ฐ€ ์–ด๋–ค ๊ธฐ๋Šฅ์„ ํ•˜๋Š”์ง€ ์žฌ๊ท€์ ์œผ๋กœ ์‚ดํŽด๋ณด๋„๋ก ํ•˜์ž.

 

// parser/parser.go

func (p *Parser) ParseProgram() *ast.Program {
	program := &ast.Program{}
	program.Statements = []ast.Statement{}

	for p.curToken.Type != token.EOF {
		stmt := p.parseStatement()
		if stmt != nil {
			program.Statements = append(program.Statements, stmt)
		}
		p.nextToken()
	}
	return program
}

 

๋จผ์ € Program ์ด๋ผ๋Š” ๊ตฌ์กฐ์ฒด๋ฅผ ๋นˆ ๊ตฌ์กฐ์ฒด๋กœ ์„ ์–ธ ๋ฐ ์ •์˜ํ–ˆ๋‹ค. ์œ„์—์„œ ์ด์•ผ๊ธฐํ–ˆ๋‹ค์‹œํ”ผ Program ์ด๋ผ๋Š” ๊ตฌ์กฐ์ฒด๋Š” ํŒŒ์„œ๊ฐ€ ๋™์ž‘ํ•˜๋Š” ๊ฒฐ๊ณผ๋ฌผ์ธ AST ์ž๋ฃŒ๊ตฌ์กฐ๋ฅผ ์˜๋ฏธํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  Program ๊ตฌ์กฐ์ฒด์— Statments ๋ผ๋Š” ๋ฉค๋ฒ„๊ฐ€ ์žˆ๋Š”๋ฐ, ์ด ๋ฉค๋ฒ„์—๋Š” Statement ๋ผ๋Š” ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ์Šฌ๋ผ์ด์Šค ํ˜•ํƒœ๋กœ ์ •์˜๋˜๋Š”๋ฐ, ์—ฌ๊ธฐ์— ์—ฌ๋Ÿฌ ๊ฐœ์˜ ๋ช…๋ น์–ด๊ฐ€ ์ €์žฅ๋œ๋‹ค. ์ด Statements ๋ฉค๋ฒ„๋„ ๋นˆ ์Šฌ๋ผ์ด์Šค๋กœ ์ดˆ๊ธฐํ™”๋ฅผ ์ˆ˜ํ–‰ํ–ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋‚œ ๋’ค, ํ˜„์žฌ ํ† ํฐ์ด ์†Œ์Šค์ฝ”๋“œ์˜ ๋(EOF)์ด ๋‚˜์˜ค๊ธฐ ์ „๊นŒ์ง€ ํŒŒ์‹ฑ์„ ์ˆ˜ํ–‰ํ•˜๊ณ , ํŒŒ์‹ฑ์ด ์™„๋ฃŒ๋œ ๋ช…๋ น๋ฌธ ๋…ธ๋“œ๋Š” Statements ๋ฉค๋ฒ„ ์ฆ‰, ์Šฌ๋ผ์ด์Šค์— ์ถ”๊ฐ€๋˜์–ด AST ์ž๋ฃŒ๊ตฌ์กฐ๋ฅผ ์ ์  ํ˜•์„ฑํ•ด ๋‚˜๊ฐ€๊ฒŒ ๋œ๋‹ค.

 

์ด์ œ ์œ„ ์†Œ์Šค์ฝ”๋“œ์˜ p.parseStatement() ํ•จ์ˆ˜์˜ ์†Œ์Šค์ฝ”๋“œ๋ฅผ ์‚ดํŽด๋ณผ ์ฐจ๋ก€๋‹ค.

 

// parser/parser.go

func (p *Parser) parseStatement() ast.Statement {
	switch p.curToken.Type {
	case token.LET:
		return p.parseLetStatement()
	default:
		return nil
	}
}

 

ํ˜„์žฌ ๊ฐ€๋ฆฌํ‚ค๊ณ  ์žˆ๋Š” ํ† ํฐ์ด ๋ฌด์—‡์ธ์ง€๋ฅผ ๋ณด๊ณ , ๊ทธ ํ† ํฐ์— ๋งž๋Š” ํŒŒ์‹ฑ ํ•จ์ˆ˜๋ฅผ ๋˜ ํ•œ๋ฒˆ ํ˜ธ์ถœํ•œ๋‹ค. ํ˜„์žฌ ์šฐ๋ฆฌ๋Š” let ๋ฌธ๋งŒ์„ ํŒŒ์‹ฑํ•˜๋Š” ๊ฒƒ์„ ๊ธฐ๋Šฅ์œผ๋กœ ์ถ”๊ฐ€ํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— case ๊ตฌ๋ฌธ์— LET์— ๋Œ€ํ•œ ์กฐ๊ฑด๋ฌธ๋งŒ ์กด์žฌํ•œ๋‹ค. ์ด์ œ let ๋ฌธ์„ ์‹ค์งˆ์ ์œผ๋กœ ํŒŒ์‹ฑํ•˜๋Š” ์—ญํ• ์„ ํ•˜๋Š” p.parseLetStatment() ํ•จ์ˆ˜์˜ ์ƒ๊น€์ƒˆ๋ฅผ ์‚ดํŽด๋ณผ ์ฐจ๋ก€๋‹ค.

 

// parser/parser.go

func (p *Parser) parseLetStatement() *ast.LetStatement {
	stmt := &ast.LetStatement{Token: p.curToken}
	
	if !p.expectPeek(token.IDENT) {
		return nil
	}
	
	stmt.Name = &ast.Identifier{Token: p.curToken, Value: p.curToken.Literal}
	
	if !p.expectPeek(token.ASSIGN) {
		return nil
	}
	
	// This time, it is skipped !
	for !p.curTokenIs(token.SEMICOLON) {
		p.nextToken()
	}
	
	return stmt
}

 

let ๋ฌธ์„ ํŒŒ์‹ฑํ•˜๋Š” ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ€์žฅ ๋จผ์ € ์‚ฌ์ „์— ์ •์˜ํ•ด๋†“์€ let ๋ฌธ ๋…ธ๋“œ๋ฅผ ์ƒ์„ฑํ•  LetStatment ๋ผ๋Š” ๊ตฌ์กฐ์ฒด๋ฅผ ์ •์˜ํ•œ๋‹ค. ์ด ๋•Œ LetStatement ๊ตฌ์กฐ์ฒด์˜ Token ๋ฉค๋ฒ„์—๋Š” ํ˜„์žฌ ํ† ํฐ์ธ LET ํ† ํฐ์„ ํ• ๋‹นํ•˜๋ฉฐ ์„ ์–ธ ๋ฐ ์ •์˜ํ•œ๋‹ค. 

 

๊ทธ๋ฆฌ๊ณ  p.expectPeek() ๋ผ๋Š” ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•ด์„œ IDENT ํ† ํฐ ์ฆ‰, ์‹๋ณ„์ž ํ† ํฐ์ด let ํ† ํฐ ๋‹ค์Œ์— ์žˆ์„ ๊ฒƒ์„ ๊ธฐ๋Œ€ํ•œ๋‹ค. ๋งŒ์•ฝ ์‹๋ณ„์ž ํ† ํฐ์ด ๋“ฑ์žฅํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด nil ์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด expectPeek ํ•จ์ˆ˜๊ฐ€ ๋ฌด์Šจ ์—ญํ• ์„ ํ•˜๋Š”์ง€ ํ•œ ๋ฒˆ ์‚ดํŽด๋ณด์ž.

 

// parser/parser.go

func (p *Parser) expectPeek(t token.TokenType) bool {
	if p.peekTokenIs(t) {
		p.nextToken()
		return true
	} else {
		return false
	}
}

 

์ด๋ฒˆ์—” ๋˜ peekTokenIs ๋ผ๋Š” ํ•จ์ˆ˜๊ฐ€ ๋“ฑ์žฅํ–ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ๋˜ peekTokenIs ํ•จ์ˆ˜ ์ƒ๊น€์ƒˆ๋ฅผ ๋ณด์ž.

 

// parser/parser.go

func (p *Parser) peekTokenIs(t token.TokenType) bool {
	return p.peekToken.Type == t
}

 

peekTokenIs ํ•จ์ˆ˜๋Š” ํ˜„์žฌ ํ† ํฐ์˜ ๋‹ค์Œ ์œ„์น˜์— ์žˆ๋Š” ํ† ํฐ์ด ํ•ด๋‹น ํ•จ์ˆ˜์˜ ์ธ์ž๋กœ ๋“ค์–ด์˜จ ํ† ํฐ๊ณผ ๋™์ผํ•˜๋‹ค๋ฉด true๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ์ด์ œ ๋‹ค์‹œ expectPeek ํ•จ์ˆ˜๋กœ ๋Œ์•„๊ฐ€๋ณด๋ฉด, expectPeek ํ•จ์ˆ˜์˜ ์ธ์ž๋กœ ๋“ค์–ด์˜จ ํ† ํฐ์ด ๋‹ค์Œ ์œ„์น˜์— ์žˆ๋Š” ํ† ํฐ๊ณผ ์ผ์น˜ํ•œ๋‹ค๋ฉด ํ˜„์žฌ ์œ„์น˜๋ฅผ ๋‹ค์Œ ํ† ํฐ์ด ์žˆ๋Š” ์œ„์น˜๋กœ ์˜ฎ๊ธด ํ›„ true๋ฅผ ๋ฆฌํ„ดํ•œ๋‹ค.(์ฃผ๋ชฉํ•  ์ ์€ ์ด 'ํ˜„์žฌ ์œ„์น˜๋ฅผ ๋‹ค์Œ ํ† ํฐ์ด ์žˆ๋Š” ์œ„์น˜๋กœ ์˜ฎ๊ธฐ๋Š”' ํ•จ์ˆ˜์ธ p.nextToken() ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ์ˆœ๊ฐ„ ๋ ‰์„œ์˜ NextToken() ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•ด์„œ ๋ ‰์‹ฑ์„ ์ˆ˜ํ–‰ํ•œ๋‹ค!!) ์ด์ œ ๋‹ค์‹œ ์œ„๋กœ ์˜ฌ๋ผ๊ฐ€์„œ parseLetStatement() ํ•จ์ˆ˜์—์„œ p.expectPeek(token.IDENT) ํ•จ์ˆ˜๋ฅผ ํ•ด์„ํ•ด๋ณด์ž. ๊ฒฐ๊ตญ, ์ด ํ•จ์ˆ˜๋Š” ๋‹ค์Œ ์œ„์น˜์— ์žˆ๋Š” ํ† ํฐ์ด ์‹๋ณ„์ž ํ† ํฐ์ด๋ผ๋ฉด true๋ฅผ, ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด false๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ์•ž์— not ์—ฐ์‚ฐ(!)์ด ์žˆ์œผ๋ฏ€๋กœ if ๊ตฌ๋ฌธ์„ ํƒ€๋Š” ๊ฒฝ์šฐ๋Š” ๋‹ค์Œ ์œ„์น˜์— ์žˆ๋Š” ํ† ํฐ์ด ์‹๋ณ„์ž ํ† ํฐ์ด ์•„๋‹ ๊ฒฝ์šฐ์ด๋‹ค. ๊ฒฐ๊ตญ, ์ด ํ•จ์ˆ˜๊ฐ€ ์˜๋ฏธํ•˜๋Š” ๋ฐ”๋Š” let ๋ฌธ ๋‹ค์Œ์— ์‹๋ณ„์ž๊ฐ€ ๋ฐ˜๋“œ์‹œ ์™€์•ผ ํ•  ๊ฒƒ์ž„์„ ์•”์‹œํ•˜๊ณ , ๋งŒ์•ฝ ์‹๋ณ„์ž๊ฐ€ ๋“ฑ์žฅํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด nil์„ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ํ•œ ๊ฒƒ์ด๋‹ค.

 

๊ณ„์† parseLetStatement() ํ•จ์ˆ˜ ๋กœ์ง์„ ์‚ดํŽด๋ณด์ž. ๋ฐฉ๊ธˆ ์„ค๋ช…ํ•œ if ๊ตฌ๋ฌธ์„ ํƒ€์ง€ ์•Š์•˜์œผ๋ฉด ํ˜„์žฌ ์œ„์น˜์—๋Š” ์‹๋ณ„์ž ํ† ํฐ์ด ๋‹ด๊ฒจ ์žˆ๋Š” ์ƒํƒœ์ด๋‹ค. ๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— ์ด์ œ LetStatement ๊ตฌ์กฐ์ฒด์˜ Name ๋ฉค๋ฒ„๊ฐ€ Identifer ๊ตฌ์กฐ์ฒด๋ฅผ ์ •์˜ํ•œ๋‹ค. ์ด Identifer ๊ตฌ์กฐ์ฒด๋Š” ์‹๋ณ„์ž๋ฅผ ์˜๋ฏธํ•˜๋ฏ€๋กœ, ํ˜„์žฌ ์œ„์น˜์˜ ํ† ํฐ๊ณผ ๋ฆฌํ„ฐ๋Ÿด ๊ฐ’์„ ํ• ๋‹นํ•œ๋‹ค.

 

๋‹ค์Œ์œผ๋กœ !p.expectPeek(token.ASSIGN) ๊ตฌ๋ฌธ์„ ๋ณด์ž. ์šฐ๋ฆฐ ์ด๋ฏธ expectPeek ํ•จ์ˆ˜์˜ ์—ญํ• ์„ ์‚ดํŽด๋ณด์•˜์œผ๋ฏ€๋กœ, ๋ฐ”๋กœ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋‹ค. not ์—ฐ์‚ฐ๊นŒ์ง€ ํฌํ•จํ•ด์„œ !p.expectPeek(token.ASSIGN) ์„ ํ•ด์„ํ•œ๋‹ค๊ณ  ํ•˜๋ฉด, ํ•ด๋‹น if ๊ตฌ๋ฌธ์„ ํƒ€๋Š” ๊ฒฝ์šฐ๋Š” ๋‹ค์Œ ํ† ํฐ์ด ๋“ฑํ˜ธ(=) ํ† ํฐ์ด ๋“ฑ์žฅํ•˜์ง€ ์•Š์„ ๊ฒฝ์šฐ์ด๋‹ค. 

 

๊ทธ๋ฆฌ๊ณ  ๋งˆ์ง€๋ง‰์œผ๋กœ p.curTokenIs ๋ผ๋Š” ํ•จ์ˆ˜๊ฐ€ ๋“ฑ์žฅํ•œ๋‹ค. ์ด ํ•จ์ˆ˜์˜ ์ƒ๊น€์ƒˆ๋„ ์‚ดํŽด๋ณด์ž.

 

// parser/parser.go

func (p *Parser) curTokenIs(t token.TokenType) bool {
	return p.curToken.Type == t
}

 

curTokenIs ํ•จ์ˆ˜๋Š” peekTokenIs ํ•จ์ˆ˜์™€ ๊ฑฐ์˜ ๋™์ผํ•˜๋‹ค. ๋‹ค๋งŒ, ํ˜„์žฌ ํ† ํฐ์„ ์‚ดํŽด๋ณด๋Š”์ง€, ๋‹ค์Œ ํ† ํฐ์„ ์‚ดํŽด๋ณด๋Š”์ง€์˜ ์ฐจ์ด์ผ ๋ฟ์ด๋‹ค. ์ด curTokenIs ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ตฌ๋ฌธ์ธ !p.curTokenIs(token.SEMICOLON) ์„ ๋ณด๋ฉด ์„ธ๋ฏธ์ฝœ๋ก ์„ ๋งŒ๋‚  ๋•Œ ๊นŒ์ง€ for ๋ฃจํ”„๋ฅผ ๋Œ๋ฉด์„œ ๊ณ„์† nextToken ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค .

 

๊ทธ๋Ÿฐ๋ฐ ์œ„ ์†Œ์Šค์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด ํŒŒ์„œ๊ฐ€ ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ํ† ํฐ์ด ๋“ฑ์žฅํ•˜๊ฑฐ๋‚˜ ํ–ˆ์„ ๋•Œ ํ˜„์žฌ๋Š” ์—๋Ÿฌ๋ฅผ ๋”ฐ๋กœ ๋‚ด๋ฑ‰์ง€ ์•Š๊ณ  ์žˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฏ€๋กœ ์—๋Ÿฌ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ์ถ”๊ฐ€ํ•ด๋ณด์ž.

 

// parser/parser.go

type Parser struct {
	l         *lexer.Lexer
	curToken  token.Token
	peekToken token.Token
	errors    []string
}

func New(l *lexer.Lexer) *Parser {
	p := &Parser{
		l:      l,
		errors: []string{},
	}
	// ํ˜„์žฌ ์ดˆ๊ธฐ token ๊ฐ’์€ ๋นˆ ๋ฌธ์ž์ด๊ธฐ ๋•Œ๋ฌธ์—, curToken, peekToken์— ํ† ํฐ์„ ๋‹ด์œผ๋ ค๋ฉด 2๋ฒˆ ์ˆ˜ํ–‰
	p.nextToken()
	p.nextToken()
	return p
}

func (p *Parser) Errors() []string {
	return p.errors
}

func (p *Parser) peekError(t token.TokenType) {
	msg := fmt.Sprintf("expected next token to be %s, got %s instead", t, p.peekToken.Type)
	p.errors = append(p.errors, msg)
}

func (p *Parser) expectPeek(t token.TokenType) bool {
	if p.peekTokenIs(t) {
		p.nextToken()
		return true
	} else {
		p.peekError(t)
		return false
	}
}

 

์ง€๊ธˆ๊นŒ์ง€ ์ž‘์„ฑํ–ˆ๋˜ ์ฝ”๋“œ์— ์—๋Ÿฌ ๋ฉ”์„ธ์ง€๋ฅผ ๋‹ด๋„๋ก ๊ตฌ์กฐ์ฒด ๋ฉค๋ฒ„์— ์ถ”๊ฐ€ํ–ˆ๋‹ค. ์ด์ œ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ์— ํ•ด๋‹น ์—๋Ÿฌ๋ฅผ ๋‚ด๋ฑ‰๋Š” ๋กœ์ง์„ ์•„๋ž˜์ฒ˜๋Ÿผ ๋ฐ˜์˜ํ•ด๋ณด์ž. ์•„๋ž˜ ์ฝ”๋“œ๋Š” ๋ฐ˜์˜๋œ ์ฝ”๋“œ ์ผ๋ถ€๋งŒ ์ž‘์„ฑํ–ˆ๋‹ค.

 

// parser/parser_test.go

func TestLetStatements(t *testing.T) {
	input := `
let x = 5;
let y = 10;
let foobar = 838383;
`
	// lexer(lexing is not run yet)
	l := lexer.New(input)
	// parser(parsing is not run yet)
	p := New(l)

	program := p.ParseProgram()
	checkParserErrors(t, p)
	if program == nil {
		t.Fatalf("ParseProgram() returned nill")
	}
	...(์ƒ๋žต)...
}

func checkParserErrors(t *testing.T, p *Parser) {
	errors := p.Errors()
	if len(errors) == 0 {
		return
	}

	t.Errorf("parser has %d errors", len(errors))
	for _, msg := range errors {
		t.Errorf("parser error: %q", msg)
	}
	t.FailNow()
}

 

์ด์ œ ์•„๋ž˜์ฒ˜๋Ÿผ ์ผ๋ถ€๋Ÿฌ ์—๋Ÿฌ๋ฅผ ๋‚ด๋ฑ‰๋„๋ก ์ธํ’‹ ์†Œ์Šค์ฝ”๋“œ ๋ฌธ์ž์—ด์„ ์•„๋ž˜์ฒ˜๋Ÿผ ์ˆ˜์ •ํ•œ ํ›„, ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์ˆ˜ํ–‰ํ•ด๋ณด์ž.

 

// parser/parser_test.go

func TestLetStatements(t *testing.T) {
	input := `
let x 5;
let = 10;
let 838383;
`
(...์ƒ๋žต...)

 

go test ./parser

 

๊ทธ๋Ÿฌ๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ฝ˜์†”์— ์ถœ๋ ฅ์ด ๋œ๋‹ค.

 

 

๋ฉ”์„ธ์ง€๋ฅผ ๋ณด๋ฉด ๋“ฑํ˜ธ(=) ํ† ํฐ์„ ์˜ˆ์ƒํ–ˆ์ง€๋งŒ INT ํ† ํฐ์ด ๋“ฑ์žฅํ–ˆ๋‹ค๊ณ  ๋ฉ”์„ธ์ง€๊ฐ€ ๋‚˜์™”๋‹ค. ์ด๋Š” ์œ„ ์ธํ’‹์—์„œ let x 5; ์ด ๋ถ€๋ถ„์—์„œ ํŒŒ์‹ฑ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ ๊ฒƒ์ด๋‹ค. ๋‚˜๋จธ์ง€ ๋ฉ”์„ธ์ง€๋Š” ์Šค์Šค๋กœ ํ•œ ๋ฒˆ ์ƒ๊ฐํ•ด๋ณด์ž.

3. return ๋ฌธ ํŒŒ์‹ฑํ•˜๊ธฐ

์ง์ „ ๋ชฉ์ฐจ๊นŒ์ง€์˜ ๋‚ด์šฉ์„ ํ•™์Šตํ•˜๋ฉด์„œ ์šฐ๋ฆฌ๋งŒ์˜ ํŒŒ์„œ๊ฐ€ let ๋ฌธ์„ ํŒŒ์‹ฑํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ธฐ๋Šฅ์„ ์™„์„ฑํ–ˆ๋‹ค. ์œ„์—์„œ ๊ตฌํ˜„ํ–ˆ๋˜ ์ฃผ์š” ๋กœ์ง์„ ํ† ๋Œ€๋กœ return ๋ฌธ์„ ํŒŒ์‹ฑํ•ด๋ณด๋„๋ก ํ•˜์ž. ์šฐ๋ฆฌ์˜ ํŒŒ์„œ๊ฐ€ ํŒŒ์‹ฑํ•  ๋Œ€์ƒ์ธ Monkey ์–ธ์–ด์˜ return ๋ฌธ ์˜ˆ์‹œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

 

return 5;
return 10;
return add(15);

 

์œ„ ์˜ˆ์‹œ์ฝ”๋“œ๋ฅผ ๋ณด๋Š” ๊ฒƒ์ฒ˜๋Ÿผ return ๋ฌธ์˜ ๊ทœ์น™์€ return ์ด๋ผ๋Š” ํ† ํฐ์™€ ํ‘œํ˜„์‹, ๊ทธ๋ฆฌ๊ณ  ์„ธ๋ฏธ์ฝœ๋ก  ํ˜•์‹์œผ๋กœ ์ด๋ฃจ์–ด์ ธ ์žˆ๋‹ค.

 

๋จผ์ € return ๋ฌธ์„ ํŒŒ์‹ฑํ•ด์„œ ๋…ธ๋“œ๋กœ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•ด return ๊ตฌ๋ฌธ ๋…ธ๋“œ ๊ตฌ์กฐ์ฒด๋ฅผ ์ •์˜ํ•ด๋ณด์ž.

 

// ast/ast.go

type ReturnStatement struct {
	Token       token.Token
	ReturnValue Expression
}

func (rs *ReturnStatement) statementNode()       {}
func (rs *ReturnStatement) TokenLiteral() string { return rs.Token.Literal }

 

ReturnStatement ๋ผ๋Š” ์ด๋ฆ„์˜ ๊ตฌ์กฐ์ฒด๋กœ ์ •์˜ํ–ˆ๊ณ , ๋ฉค๋ฒ„๋Š” return ์ด๋ผ๋Š” ํ† ํฐ์„ ๋‹ด์„ Token ์ด๋ผ๋Š” ๋ฉค๋ฒ„์™€ ํ‘œํ˜„์‹์„ ๋‹ด์„ ReturnValue ๋ฉค๋ฒ„๋ฅผ ๊ฐ€์ง„๋‹ค. ๊ทธ๋ฆฌ๊ณ  ReturnStatement๋„ ๋…ธ๋“œ์˜ ์ผ์ข…์ด๊ธฐ ๋•Œ๋ฌธ์— statementNode() ๋ผ๋Š” ๋ฉ”์†Œ๋“œ์™€ TokenLiteral() ๋ฉ”์†Œ๋“œ๋ฅผ ์ •์˜ํ•จ์œผ๋กœ์จ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ถฉ์กฑ์‹œ์ผฐ๋‹ค.

 

์ด์ œ ๋‹ค์Œ์œผ๋กœ๋Š” return ๋ฌธ์„ ํŒŒ์‹ฑํ•˜๊ธฐ ์œ„ํ•œ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ถ€ํ„ฐ ์ž‘์„ฑํ•ด๋ณด์ž. ๊ทธ๋ฆฌ๊ณ  ๋‚œ ๋’ค์—๋Š” ํ…Œ์ŠคํŠธ ์ฝ”๋“œ์— ์ •์˜๋˜์–ด ์žˆ๋Š” return ๋ฌธ์„ ํŒŒ์‹ฑํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ํ•˜๋‚˜์”ฉ ์‚ดํŽด๋ณด์ž.

 

// parser/parset_test.go

func TestReturnStatements(t *testing.T) {
	input := `
return 5;
return 10;
return add(15);
`
	l := lexer.New(input)
	p := New(l)

	program := p.ParseProgram()
	checkParserErrors(t, p)

	if len(program.Statements) != 3 {
		t.Fatalf("program.Statements does not contain 3 statements. got=%d",
			len(program.Statements))
	}

	for _, stmt := range program.Statements {
		returnStmt, ok := stmt.(*ast.ReturnStatement) // type assertion: downcast from interface to struct
		if !ok {
			t.Errorf("stmt not *ast.ReturnStatement. got=%T", stmt)
			continue
		}
		if returnStmt.TokenLiteral() != "return" {
			t.Errorf("returnStmt.TokenLiteral not 'return'. got=%s", returnStmt.TokenLiteral())
		}
	}
}

 

๋กœ์ง ์ž์ฒด๋Š” ์ด์ „์— let ๋ฌธ์„ ํ…Œ์ŠคํŠธํ•˜๋Š” ์ฝ”๋“œ์™€ ๋™์ผํ•˜๋‹ค. ํŒŒ์‹ฑ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ํŠธ๋ฆฌ๊ฑฐ๋Š” program := p.ParseProgram() ๋ผ์ธ์—์„œ ์‹คํ–‰๋œ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ์šฐ๋ฆฌ๋Š” ์ด์ „์— ์ •์˜ํ–ˆ๋˜ p.ParseProgram() ํ•จ์ˆ˜์—๋‹ค๊ฐ€๋„ return ๋ฌธ์„ ํŒŒ์‹ฑํ•  ์ˆ˜ ์žˆ๋„๋ก ์ˆ˜์ •ํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค. ๋‹ค์‹œ p.ParseProgram() ํ•จ์ˆ˜ ์ƒ๊น€์ƒˆ๋ฅผ ๋ณด์ž.

 

// parser/parser.go

func (p *Parser) ParseProgram() *ast.Program {
	program := &ast.Program{}
	program.Statements = []ast.Statement{}

	for p.curToken.Type != token.EOF {
		stmt := p.parseStatement()
		if stmt != nil {
			program.Statements = append(program.Statements, stmt)
		}
		p.nextToken()
	}
	return program
}

 

์ด์ „์— ๋ดค๋˜ ๊ฒƒ๊ณผ ์ƒ๊น€์ƒˆ๊ฐ€ ๋™์ผํ•˜๋‹ค. ์œ„ ์†Œ์Šค์ฝ”๋“œ์—์„œ p.parseStatement() ๋ผ๋Š” ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋œ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ๋˜ ์šฐ๋ฆฌ๋Š” ์ด ํ•จ์ˆ˜๋ฅผ ๋”ฐ๋ผ๊ฐ€๋ณด์ž.

 

// parser/parser.go

func (p *Parser) parseStatement() ast.Statement {
	switch p.curToken.Type {
	case token.LET:
		return p.parseLetStatement()
	default:
		return nil
	}
}

 

parseStatement() ํ•จ์ˆ˜๋Š” ํ˜„์žฌ ์œ„์™€ ๊ฐ™์€ ์ƒ๊น€์ƒˆ๋ฅผ ๊ฐ–๊ณ  ์žˆ๋‹ค. ์ด์ „์— ์šฐ๋ฆฌ๊ฐ€ ์ž‘์„ฑํ–ˆ๋˜ ๊ฒƒ์ฒ˜๋Ÿผ ์•„์ง์€ let ๋ฌธ๋งŒ ํŒŒ์‹ฑํ•  ์ˆ˜ ์žˆ๋„๋ก ๋˜์–ด ์žˆ๋‹ค. ์—ฌ๊ธฐ์—๋‹ค๊ฐ€ ์šฐ๋ฆฌ๋Š” return ๋ฌธ๋„ ํŒŒ์‹ฑํ•  ์ˆ˜ ์žˆ๋„๋ก ์ถ”๊ฐ€ํ•ด์ฃผ๋„๋ก ํ•˜์ž.

 

// parser/parser.go

func (p *Parser) parseStatement() ast.Statement {
	switch p.curToken.Type {
	case token.LET:
		return p.parseLetStatement()
	case token.RETURN:
		return p.parseReturnStatement()
	default:
		return nil
	}
}

 

parseReturnStatement() ๋ผ๋Š” ํ•จ์ˆ˜๊ฐ€ ์ถ”๊ฐ€๋˜์—ˆ๋‹ค. ์ด๋ฒˆ์—๋Š” parseReturnStatement() ํ•จ์ˆ˜์˜ ์ƒ๊น€์ƒˆ๋ฅผ ๋ณผ ์ฐจ๋ก€๋‹ค.

 

// parser/parser.go

func (p *Parser) parseReturnStatement() *ast.ReturnStatement {
	stmt := &ast.ReturnStatement{Token: p.curToken}
	
	p.nextToken()
	
	// This time, it is skipped !
	for !p.curTokenIs(token.SEMICOLON) {
		p.nextToken()
	}
	return stmt
}

 

ReturnStatement ๊ตฌ์กฐ์ฒด๋ฅผ ์ •์˜ํ•˜๋Š”๋ฐ, ํ•ด๋‹น ๊ตฌ์กฐ์ฒด์˜ Token ๋ฉค๋ฒ„์— RETURN ํ† ํฐ(p.curToken)์ด ๋‹ด์•„์ค€๋‹ค. ๊ทธ๋ฆฌ๊ณ  parseLetStatement() ํ•จ์ˆ˜์™€๋Š” ๋‹ค๋ฅด๊ฒŒ ๋จผ์ € p.nextToken() ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•ด์ฃผ์–ด์„œ ํ˜„์žฌ ์œ„์น˜๋ฅผ ๋‹ค์Œ ํ† ํฐ์œผ๋กœ ์˜ฎ๊ฒจ์ค€๋‹ค. ์ฆ‰, ํ˜„์žฌ ์œ„์น˜๋Š” return ํ† ํฐ์— ์žˆ๋Š”๋ฐ, ์ด ์œ„์น˜๋ฅผ return ๋‹ค์Œ์— ์žˆ๋Š” ํ‘œํ˜„์‹์œผ๋กœ ์˜ฎ๊ธด๋‹ค๋Š” ์˜๋ฏธ์ด๋‹ค. 

 

๊ทธ๋ฆฌ๊ณ  parseLetStatement() ํ•จ์ˆ˜์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์•„์ง์€ ํ‘œํ˜„์‹์„ ํŒŒ์‹ฑํ•˜๋Š” ๋กœ์ง์„ ์ถ”๊ฐ€ํ•˜๋Š” ๋‹จ๊ณ„๋Š” ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์— parseReturnStatement() ํ•จ์ˆ˜์—์„œ๋„ ์„ธ๋ฏธ์ฝœ๋ก (;) ํ† ํฐ์„ ๋งˆ์ฃผํ•  ๋•Œ๊นŒ์ง€ ๊ณ„์† ํ† ํฐ์„ ๋‹ค์Œ ์œ„์น˜๋กœ ์˜ฎ๊ธด๋‹ค. ์—ฌ๊ธฐ๊นŒ์ง€์˜ ๋กœ์ง์„ ํ…Œ์ŠคํŠธํ•˜๊ธฐ ์œ„ํ•ด์„œ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰์‹œ์ผœ๋ณด์ž.

 

go test ./parser

 

์ฝ˜์†”์— ํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ๊ฐ€ ok๋กœ ๋‚˜์˜ค๋ฉด ์™„์„ฑ๋œ ๊ฒƒ์ด๋‹ค. ์•„์ง ์šฐ๋ฆฌ๊ฐ€ ๋งŒ๋“  ํŒŒ์„œ๊ฐ€ ํ‘œํ˜„์‹์„ ํŒŒ์‹ฑํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ์€ ์—†๋Š” ์ƒํƒœ์ง€๋งŒ, let ๋ฌธ๊ณผ return ๋ฌธ์„ ํŒŒ์‹ฑํ•  ์ˆ˜๋Š” ์žˆ๋Š” ๊ธฐ๋Šฅ๊นŒ์ง€ ๊ฐ–์ถ”์—ˆ๋‹ค. ์ด์ œ ๋‹ค์Œ ํฌ์ŠคํŒ…์—์„œ ํ‘œํ˜„์‹๋„ ํŒŒ์‹ฑํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ์„ ํƒ‘์žฌํ•ด๋ณด๋„๋ก ํ•˜์ž.

๋ฐ˜์‘ํ˜•