28 — 첫 컴파일러 — 아주 작은 언어
컴파일러는 글을 읽고 그 뜻을 판단합니다. 여러분은 이미 그중 가장 어려운
부분을 27에서 썼습니다: 줄을 나누고, 첫 단어를 읽고,
그 단어로 갈라지는 것입니다. 컴파일러는 그 일을 프로그램의 모든 줄에 되풀이할
뿐입니다. 이 가이드는 진짜 컴파일러의 씨앗 — add와 mul 명령이 있는 아주
작은 언어 — 을 만들고 examples/tiny-compiler.nme 예제와 비교합니다.
단계
파이프라인을 보세요. 아무리 큰 컴파일러라도 반복 속에서 세 단계만 합니다: 글 줄을 읽고, 단어로 나누고, 단어를 해석합니다. 여러분 언어의 유일한 일은 각 줄에 답하는 것입니다:
실행해 보기 →# 파이프라인: 읽기, 나누기, 해석 line = "add 2 3" parts = line.split() 말해 int(parts[1]) + int(parts[2])실행하면
5가 출력됩니다 — 언어가add 2 3줄에 줄 답과 같습니다.해석기 전체를
mini.ko.nme한 파일로 저장합니다:
실행해 보기 →# 아주 작은 계산기 언어: add 2 3, mul 4 5, 또는 quit. # 실행: nme 실행 mini.ko def run_command(parts): verb = parts[0] if verb == "add": return int(parts[1]) + int(parts[2]) elif verb == "mul": return int(parts[1]) * int(parts[2]) else: return "모르는 명령입니다" 말해 "미니 언어 — add 2 3, mul 4 5, 또는 quit." while True: 물어봐 line, "다음 줄? " 만약 line == "quit": 말해 "안녕히 가세요!" break parts = line.split() if len(parts) == 3: result = run_command(parts) 말해 result else: 말해 "형식: add 2 3 또는 mul 4 5"실행하고 작은 프로그램을 넣어 보세요:
printf 'add 2 3\nmul 4 5\nsub 9 2\nquit\n' | nme 실행 mini.ko미니 언어 — add 2 3, mul 4 5, 또는 quit. 다음 줄? 5 다음 줄? 20 다음 줄? 모르는 명령입니다 다음 줄? 안녕히 가세요!add 2 3은5로,mul 4 5는20으로 답하고,sub 9 2는 아직 명령이 아니라 모르는 명령 메시지를 받습니다.해석은 함수입니다.
verb = parts[0]이 첫 단어에 이름을 붙이고, 동사에 대한if가 명령마다 갈래 하나로 나눕니다. 둘째와 셋째 단어는int(parts[1])과int(parts[2])로 숫자가 됩니다:
실행해 보기 →def run_command(parts): verb = parts[0] if verb == "add": return int(parts[1]) + int(parts[2]) elif verb == "mul": return int(parts[1]) * int(parts[2]) else: return "모르는 명령입니다"마지막
else가 오류 처리입니다: 모르는 동사는 크래시 대신 메시지로 돌아옵니다.반복이 파이프라인입니다.
물어봐로 줄을 읽고,quit에서 멈추고,.split()으로 나누고,len(parts) == 3으로 모양을 지키고, 해석해 출력합니다:
실행해 보기 →while True: 물어봐 line, "다음 줄? " 만약 line == "quit": 말해 "안녕히 가세요!" break parts = line.split() if len(parts) == 3: result = run_command(parts) 말해 result else: 말해 "형식: add 2 3 또는 mul 4 5"examples/tiny-compiler.nme예제는 진짜 (아주 작은) 컴파일러입니다: 터미널 대신 목록에서 소스 줄을 읽고, 출력으로 Python 코드를 만듭니다:
실행해 보기 →# examples/tiny-compiler.nme의 일부 python_lines = [] for line in tiny_source: words = line.split() if words[0] == "말하기": text = " ".join(words[1:]) python_lines.append(f"print({text!r})")각 줄을 나누고 첫 단어를 확인해
print(...)줄을 만듭니다 — 숫자 대신 만들어진 Python이 답일 뿐 같은 읽기 → 나누기 → 해석 파이프라인입니다. 숫자 대신answer = 5를 만드는 생성 갈래를 더하면 해석기가 컴파일러로 바뀝니다.영어 쌍둥이
mini.nme는 같은def를 쓰고 반복을ask,if,show로 씁니다:
실행해 보기 →def run_command(parts): verb = parts[0] if verb == "add": return int(parts[1]) + int(parts[2]) while True: ask line, "Next line? " if line == "quit": show "Goodbye!" break parts = line.split() result = run_command(parts) show result같은 파이프 입력이 두 언어에서 답합니다.
직접 해보기
run_command에 sub와 div 명령을 더해 보세요: sub는 뺄셈
(int(parts[1]) - int(parts[2]))이고 div는 나눗셈입니다. 그다음 프로그램에
sub 9 2와 div 12 3을 넣어 모르는 명령 메시지가 사라지는 것을
보세요.
배운 것
- 컴파일러는 글을 읽고 단어로 나누고 각 줄을 해석합니다.
- 동사에 대한
if가 달린run_command(parts)함수가 분기입니다. split()은 줄을 자르고int()는 글을 숫자로 바꿉니다.- 읽기 → 나누기 → 해석 파이프라인이 진짜 컴파일러의 씨앗입니다.