어휘구조란?

우리가 파이썬 코드를 작성하면, 파이썬은 그것을 어떻게 이해할까요?

x = 42 + y

우리 눈에는 "변수 x에 42와 y를 더한 값을 넣어라"라고 보이지만, 파이썬 입장에서는 그냥 문자들의 나열일 뿐입니다.

'x', ' ', '=', ' ', '4', '2', ' ', '+', ' ', 'y'

파이썬이 코드를 실행하려면 먼저 이 문자들을 의미 있는 단위로 쪼개야 합니다. 마치 우리가 책을 읽을 때 글자들을 단어로 인식하는 것처럼요.

토큰: 의미의 최소 단위

코드를 쪼갠 의미 있는 조각들을 토큰(Token)이라고 부릅니다.

x = 42 + y

# 파이썬이 보는 토큰들:
# NAME: 'x'
# OP: '='
# NUMBER: 42
# OP: '+'
# NAME: 'y'

자연어와 비교하면 더 쉽습니다:

문장: "나는 밥을 먹는다"
단어: ["나는", "밥을", "먹는다"]

코드: "x = 42"
토큰: [NAME:'x', OP:'=', NUMBER:42]

어휘 분석: 토큰으로 쪼개기

어휘 분석(Lexical Analysis)은 코드를 읽어서 토큰으로 쪼개는 과정입니다.
이것이 파이썬 인터프리터가 하는 첫 번째 일입니다.

[소스 코드]
    ↓
[어휘 분석] ← 이번 강좌의 주제
    ↓
[토큰 리스트]
    ↓
[구문 분석]
    ↓
...

왜 이런 과정이 필요할까요?

코드를 한 번에 이해하려면 너무 복잡하기 때문입니다. 그래서 파이썬은 단계별로 나눠서 처리합니다. 어휘 분석은 그 첫 단계입니다.

어휘구조분석기가 작동하는 원리

어휘 분석기는 상태 기계(State Machine)라는 방식으로 작동합니다.
상태 기계가 뭔지 어렵게 느껴질 수 있는데, 우리 주변에서 흔히 볼 수 있는 개념입니다.

State Machine의 예시

1. 사람의 배고픔 상태

우리의 배고픔 상태를 생각해봅시다:

stateDiagram-v2
    배고픔 --> 배부름: 식사
    배부름 --> 배고픔: 운동
  • 상태: 배고픔, 배부름
  • 전이(transition): 식사를 하면 배고픔에서 배부름으로
  • 다시 전이: 운동을 하면 배부름에서 배고픔으로

이것이 바로 상태 기계입니다! 특정 상태에 있다가, 입력이 들어오면 다른 상태로 바뀌는 시스템이죠.

2. 신호등

신호등도 상태 기계입니다:

stateDiagram-v2
    빨간불 --> 초록불: 30초 경과
    초록불 --> 노란불: 30초 경과
    노란불 --> 빨간불: 3초 경과
  • 상태: 빨간불, 노란불, 초록불
  • 전이: 시간이 지나면 상태가 바뀜
  • 규칙: 빨간불 → 초록불 → 노란불 → 빨간불 (반복)

3. 계산기의 입력 상태

계산기를 사용할 때를 생각해봅시다:

stateDiagram-v2
    시작 --> 숫자대기
    숫자대기 --> 연산자대기: 숫자 입력 (53, 10)
    연산자대기 --> 숫자대기: 연산자 입력 (+)
    연산자대기 --> 종료: (=) 입력

계산기는 항상 두 가지 상태 중 하나에 있습니다:
- 숫자를 기다리는 상태 (숫자대기)
- 연산자를 기다리는 상태 (연산자대기)

입력 "5 + 3 ="을 처리하는 과정:
1. 시작 → 숫자대기 → '53' 입력 → 연산자대기
2. 연산자대기 → '+' 입력 → 숫자대기
3. 숫자대기 → '10' 입력 → 연산자대기
4. 연산자대기 → '=' 입력 → 완료

이렇게 상태를 바꿔가며 입력을 처리하는 것이 상태 기계입니다.

어휘구조 분석 State Machine

이제 파이썬의 어휘 분석이 어떻게 작동하는지 살펴봅시다.

정수 인식하기

123이라는 문자열을 읽을 때의 상태 전이:

stateDiagram-v2
    [*] --> 시작
    시작 --> 숫자읽는중: 숫자 ('1')
    숫자읽는중 --> 숫자읽는중: 숫자 ('2', '3')
    숫자읽는중 --> [*]: 공백 또는 연산자

    note right of 숫자읽는중
        계속 숫자를 모음
        예: "123"
    end note

한 글자씩 읽으면서 "지금 숫자를 읽고 있구나"라는 상태를 유지하다가, 숫자가 아닌 문자를 만나면 토큰을 완성합니다.

결과: NUMBER 토큰: 123

실수도 인식하기

3.14처럼 소수점이 있으면 어떻게 될까요?

stateDiagram-v2
    [*] --> 시작
    시작 --> 정수읽는중: 숫자 ('3')
    정수읽는중 --> 정수읽는중: 숫자
    정수읽는중 --> 실수읽는중: 소수점 ('.')
    실수읽는중 --> 실수읽는중: 숫자 ('1', '4')
    정수읽는중 --> [*]: 공백/연산자
    실수읽는중 --> [*]: 공백/연산자

    note right of 실수읽는중
        소수점 이하 숫자들을 모음
        예: "3.14"
    end note

정수를 읽다가 .을 만나면 "아, 실수구나!" 하고 상태를 바꿔서 소수점 이하 숫자들을 계속 읽습니다.

결과: NUMBER 토큰: 3.14

여러 종류 토큰 인식하기

실제 파이썬 코드 x = 42 + y를 어떻게 읽을까요?

stateDiagram-v2
    [*] --> 시작
    시작 --> 식별자읽기: 문자 ('x')
    시작 --> 숫자읽기: 숫자 ('4')
    시작 --> 연산자: 연산자 ('+', '=')

    식별자읽기 --> 식별자읽기: 문자/숫자
    식별자읽기 --> 시작: 공백 (NAME 토큰 생성)

    숫자읽기 --> 숫자읽기: 숫자
    숫자읽기 --> 시작: 공백 (NUMBER 토큰 생성)

    연산자 --> 시작: (OP 토큰 생성)

    시작 --> [*]: 문자열 끝

코드 x = 42 + y 처리 과정:
1. x → 문자 → 식별자 읽기 → 공백 → NAME: 'x'
2. = → 연산자 → OP: '='
3. 42 → 숫자들 → 공백 → NUMBER: 42
4. + → 연산자 → OP: '+'
5. y → 문자 → 끝 → NAME: 'y'

최종 결과: [NAME:'x', OP:'=', NUMBER:42, OP:'+', NAME:'y']

이렇게 상태 기계를 사용하면 복잡한 코드를 체계적으로 토큰으로 쪼갤 수 있습니다!

파이썬의 어휘구조

파이썬만의 특별한 어휘 규칙들을 알아봅시다.

1. 들여쓰기도 토큰이다

파이썬의 가장 큰 특징은 들여쓰기가 문법이라는 것입니다.

def greet():
    print("hello")  # 들여쓰기 1단계
    if True:
        print("world")  # 들여쓰기 2단계

다른 언어들은 중괄호 {}를 사용하지만, 파이썬은 들여쓰기를 토큰으로 만듭니다:

# 파이썬이 보는 토큰들:
[
    NAME: 'def',
    NAME: 'greet',
    OP: '(',
    OP: ')',
    OP: ':',
    NEWLINE,
    INDENT,        # 들여쓰기 시작!
    NAME: 'print',
    ...
    NEWLINE,
    DEDENT,        # 들여쓰기 끝!
]

2. 여러 가지 문자열 표현

파이썬은 문자열을 다양하게 표현할 수 있습니다:

# 기본 문자열
s1 = 'hello'
s2 = "world"

# 여러 줄 문자열
s3 = """
여러 줄에 걸쳐
문자열을 쓸 수 있습니다
"""

# 이스케이프를 무시하는 Raw 문자열
s4 = r'\n은 줄바꿈이 아니라 그냥 \n 입니다'

# 변수를 넣을 수 있는 f-string
name = "파이썬"
s5 = f"안녕하세요, {name}!"  # "안녕하세요, 파이썬!"

3. 다양한 숫자 표현

파이썬은 숫자를 여러 방식으로 쓸 수 있습니다:

# 일반 숫자
a = 42

# 2진수 (0과 1만)
b = 0b1010  # 10

# 8진수 (0~7)
c = 0o12    # 10

# 16진수 (0~9, A~F)
d = 0xA     # 10

# 실수
e = 3.14

# 큰 숫자는 _로 구분 (읽기 쉽게)
f = 1_000_000  # 1000000

# 복소수
g = 3 + 4j

4. 실제 파이썬 토크나이저 확인하기

파이썬에는 토큰 분석을 직접 확인할 수 있는 tokenize 모듈이 있습니다.

코드 x = 42를 토큰으로 분석하면 이렇게 나옵니다:

NAME       : 'x'
OP         : '='
NUMBER     : '42'
NEWLINE    : '\n'
ENDMARKER  : ''

우리가 예상한 대로 NAME, OP, NUMBER 토큰으로 쪼개지는 걸 확인할 수 있습니다!

정리

배운 내용

  1. 어휘 분석: 코드를 토큰으로 쪼개는 첫 번째 단계
  2. 토큰: 의미 있는 최소 단위 (변수명, 숫자, 연산자 등)
  3. 상태 기계: 상태를 바꿔가며 입력을 처리하는 방식
  • 배고픔/배부름 (사람)
  • 신호등 (빨강/노랑/초록)
  • 계산기 (숫자 대기/연산자 대기)

파이썬의 특별함

  • 들여쓰기가 토큰 (INDENT, DEDENT)
  • 다양한 문자열 표현 (따옴표, f-string, raw 문자열)
  • 여러 진법의 숫자 (2진수, 8진수, 16진수)
  • tokenize 모듈로 직접 토큰 확인 가능

왜 중요한가?

어휘 분석을 이해하면:
- 파이썬이 코드를 어떻게 읽는지 알 수 있습니다
- 문법 오류를 더 잘 이해할 수 있습니다
- 나만의 언어를 만들 수도 있습니다!