나만의 언어만들기 1

easylogic·2025년 1월 3일
1 + 2 > 10;

대략 이런 구문이 있다고 칩시다. 이 구문은 아래와 같이 쪼갤 수 있습니다.

{ NUMBER, 1} 
{ PLUS }
{ NUMBER, 2}
{ GREATE_THAN } 
{ NUMBER, 10}
{ SEMICOLON }

이렇게 인지할 수 있는 최소 단위로 쪼갠 것을 Token 이라고 합니다.

이 토큰을 가지고 Parser 를 연결해서 실제 동작할 것 같은 의미로 구조화 시킵니다.

      [>]
  [+]    [10]
[1] [2]

이렇게 구조화 된 형태로 만든 것이 AST(추상 구문 트리)입니다.


그래서 어떤 언어의 기본적인 의미를 가지게 하려면 AST 까지는 만들어야 어떤 언어를 구축할 것인지 알 수 있습니다.

지금부터 해볼 것은 이 AST 까지 만들어내는 Parser(Lexer 를 포함한) 입니다.

Parser 를 만들 때는 ebnf 포맷을 통한 Parser Genenator 를 사용해도 되지만 그냥 한번 해봅시다. 어떤 것인지 맛은 보고 그 다음으로 넘어가면 좋으니깐요.


자, 이제 시작합니다.

먼저 Token 을 분리할 수 있는 Lexer 를 만들어 봅시다.

Token 이 의미를 가질려면 최소한의 의미있는 형태로 먼저 정해진 키워드나 기호를 만들어야 합니다.

그러기 위해서는 초기 언어를 설계해봐야겠죠?

어떤 것을 해보면 좋을까요? 계산기 로직을 한번 만들어 볼까요?


1 + 2 + 3 + (4 * 5) / 2 + 10 - 30 

대략 이정도 나열해보면 어떤 것을 구분 지어야 할지 조금 보일까요? 형태로 나열해봅시다.

NUMBER
PLUS : +
MULTIPLE : *
DIVIDE : /
MINUS : -
ParenStart : (
ParenEnd: )  

대략 이정도 Token 으로 쪼개야 합니다.

보통 여기서 질문이 올 수 있습니다.
공백은 토큰으로 안 만드나요?

공백을 토큰으로 만들 수 있지만 특별한 의미를 가지지 않기 때문에 굳이 토큰으로 취급하지 않고 그냥 넘깁니다.

형태가 나왔으니 하나의 문자열을 토큰으로 쪼개면 토큰의 배열이 될 것입니다.

const tokens = [
  ['NUMBER', 1],
  ['PLUS'],
  ['NUMBER', 2],
  ['PLUS'],
  ['NUMBER', 3],
  ['PLUS'],
  ['PARENSTART'],
  ['NUMBER', 4],
  ['MULTIPLE'],
  ['NUMBER', 5],
  ['PARENEND'],  
  ['DIVIDE']
  ['NUMBER', 2],
  ['PLUS'],
  ['NUMBER', 10],
  ['MINUS'],
  ['NUMBER', 30],
]

그래서 최종적으로 Lexer 가 만드는 결과물은 tokens 처럼 단순한 Token 의 나열이 됩니다.

이렇게 나열된 Token 을 가지고 Parser 는 하나씩 의미를 쌓아서 AST 를 만들게 됩니다.

profile
행복개발자

0개의 댓글