The Annotated Python Language Reference #2

2. 구문 분석

파이썬 프로그램은 파서(parser) 에 의해 읽힌다. 파서의 입력은 구문 분석기(lexical analyzer) 가 만들어내는 토큰(token) 들의 스트림이다. 이 장에서는 구문 분석기가 어떻게 파일을 토큰들로 분해하는지 설명한다.

APLR

구문 분석기가 만들어내는 토큰들의 목록은 token 모듈에서 제공됩니다. tokenize 모듈로 파이썬 소스 파일의 구문 분석을 수행할 수도 있습니다.

파이썬은 프로그램 텍스트를 유니코드 코드값으로 읽는다; 소스 파일의 인코딩은 인코딩 선언을 통해 지정될 수 있고, 기본값은 UTF-8이다. 자세한 내용은 PEP 3120 에 나온다. 소스 파일을 디코딩할 수 없을 때는 SyntaxError 가 발생한다.

2.1. 줄 구조(Line structure)

파이썬 프로그램은 여러 개의 논리적인 줄(logical lines) 들로 나뉜다.

2.1.1. 논리적인 줄

논리적인 줄의 끝은 NEWLINE 토큰으로 표현된다. 문법이 허락하지 않는 이상 (예를 들어 복합문에서 문장들 사이) 문장은 논리적인 줄 간의 경계를 가로지를 수 없다. 논리적인 줄은 명시적이거나 묵시적인 줄 결합(line joining) 규칙에 따라 하나 이상의 물리적인 줄(physical lines) 들로 구성된다.

APLR

편집기 상에서 여러 줄로 표현된 텍스트가, 구문 분석 과정에서 하나의 논리적인 줄로 합쳐질 수 있습니다. 이렇게 물리적인 줄이 논리적인 줄로 합쳐지는 규칙은 명시적인 줄 결합묵시적인 줄 결합 에서 설명합니다. 구문 분석의 결과로 텍스트는 일련의 토큰들로 변환되는데, 논리적인 줄의 끝을 나타내는 토큰이 NEWLINE 입니다. 이 후의 단계에서는 논리적인 줄만이 사용됩니다. if 문이나 for 문과 같은 복합문들은 여러개의 논리적인 줄로 구성될 수 있지만, 단순문은 하나의 논리적인 줄로만 구성됩니다.

2.1.2. 물리적인 줄

물리적인 줄은 줄의 끝을 나타내는 시퀀스로 끝나는 문자들의 시퀀스다. 소스 파일에는 플랫폼들의 표준 줄 종료 시퀀스들이 모두 사용될 수 있다 - ASCII LF (개행문자)를 사용하는 유닉스 형, ASCII 시퀀스 CR LF(캐리지 리턴 다음에 오는 개행 문자)를 사용하는 윈도우 형, ASCII CR(캐리지 리턴)을 사용하는 예전의 매킨토시 형. 이 형태들은 플랫폼의 종류와 관계없이 동등하게 사용할 수 있다.

APLR

줄의 끝이 여러개의 문자로 표현될 수 있기 때문에 시퀀스라고 표현하고 있습니다. 가령 윈도우에서는 CR 과 LF 두 문자를 연속으로 붙여서 줄의 끝을 표현합니다. 하지만 파이썬은 현재 사용되고 있는 플랫폼에 관계 없이 세가지 형태를 모두 줄의 끝으로 인식합니다. 이 때문에 어떤 플랫폼에서 소스 파일을 편집했는지에 관계없이 모든 플랫폼에서 실행될 수 있습니다.

파이썬을 내장할 때는, 소스 코드 문자열은 반드시 줄 종료 문자에 표준 C 관행(ASCII LF를 표현하는 \n 문자로 줄이 종료된다)을 적용해서 파이썬 API로 전달되어야 한다.

APLR

파이썬을 내장한다는 것은, 파이썬 인터프리터 확장 및 내장 에서 설명하는 방법으로 별도의 응용프로그램에 파이썬 인터프리터를 내장시킨다는 뜻입니다. 이 경우 PyRun_SimpleString() 와 같은 API 를 사용해서 파이썬 코드를 실행하는데, 소스 파일에 등장하는 LF, CR LF, CR 들을 모두 \n 로 변환해서 전달해야한다는 뜻입니다.

2.1.3. 주석

주석은 문자열 리터럴에 포함되지 않는 해시 문자(#)로 시작하고 물리적인 줄의 끝에서 끝난다. 묵시적인 줄 결합 규칙이 유효하지 않은 이상, 주석은 논리적인 줄을 종료시킨다. 주석은 문법이 무시한다; 토큰으로 만들어지지 않는다.

2.1.4. 인코딩 선언

파이썬 스크립트의 첫 번 째나 두 번째 줄에 있는 주석이 정규식 coding[=:]\s*([-\w.]+) 과 매치되면, 이 주석은 인코딩 선언으로 처리된다. 이 정규식의 첫 번째 그룹은 소스 코드 파일의 인코딩 이름을 지정한다. 인코딩 선언은 줄 전체에 홀로 나와야 한다. 만약 두 번째 줄이라면, 첫 번째 줄 역시 주석만 있어야 한다. 인코딩 선언의 권장 형태는 두 개다. 하나는

# -*- coding: <encoding-name> -*-

인데 GNU Emacs에서도 인식된다. 다른 하나는

# vim:fileencoding=<encoding-name>

인데 Bram Moolenaar 의 VIM에서 인식된다.

APLR

주석이 이 정규식과 일치하는 부분을 포함하고 있기만 하면 됩니다. 널리 사용되는 두 편집기와 호환되게 만드는 영리한 정규식입니다. 이 정규식의 ([-\w.]+) 와 매치되는 부분에서 인코딩 이름을 추출합니다.

인코딩 선언이 발견되지 않으면 기본 인코딩은 UTF-8이다. 여기에 더해, 파일의 처음이 UTF-8 BOM (b'\xef\xbb\xbf')이면 파일 인코딩이 UTF-8으로 선언된 것으로 본다. (이 방식은 마이크로소프트의 notepad 에서 지원된다.)

APLR

BOM (Byte Order Mark) 은, 유니코드로 인코딩된 파일이 어떤 형식으로 기록되어 있는지를 표시하기 위해 파일의 처음에 삽입하는 표식입니다. 유니코드는 UTF-8 외에도 여러가지 방식으로 표현될 수 있는데, 이 중에는 UTF-8 와는 달리, 기록되는 값이 어떤 바이트 순서를 갖느냐가 지정될 필요가 있는 것들이 있습니다. 가령 UTF-16 은 리틀 엔디언 (Little-endian) 과 빅 엔디언 (Big-endian) 두가지 방식으로 기록될 수 있는데, 각각 b'\xff\xfe'b'\xfe\xff' 라는 BOM 으로 이 중 어떤 것을 사용하고 있는지 표시할 수 있습니다. 파이썬 파서는 UTF-8 이외의 BOM 은 지원하지 않습니다. (즉 UTF-8 이외의 BOM 은 BOM 으로 인식하지 않고, 구문 분석기의 입력으로 들어가기 때문에 결국 SyntaxError 를 일으킵니다.)

APLR

BOM 과 인코딩 선언을 동시에 사용하고, 둘이 서로 다른 주장을 하면 SyntaxError 를 일으킵니다. 하지만 같은 주장을 하는 경우도, 인코딩 이름으로 utf-8 이 아니라 utf8 같은 별칭을 사용하면 SyntaxError 를 일으키는데, 이 경우는 버그로 보아도 무방할듯합니다.

인코딩이 선언되면, 인코딩 이름은 파이썬이 인식할 수 있어야 한다. 인코딩은 문자열 리터럴, 주석, 식별자를 포함한 모든 구문 분석에서 모두 사용된다.

APLR

파이썬이 인식할 수 있는 인코딩 이름은 표준 라이브러리의 codecs 모듈에서 정의되고 있습니다.

APLR

인코딩 선언을 발견하면 파이썬은 해당 코덱의 디코더를 사용하여 스크립트를 디코딩한 후, 구문 분석기의 다음 단계로 전달합니다. 때문에 코덱은 파이썬 소스 파일의 전처리기를 제작하는데 사용될 수 있습니다. 물론 이 코덱은 스크립트를 실행하거나 import 하기 전에 등록되어 있어야 합니다. import 의 경우는 사전에 코덱을 등록하면되지만, 스크립트를 직접 실행하는 경우에도 동작하게 하기 위해서는 sitecustomize.pyusercustomize.py 파일에 코덱을 등록하는 코드를 삽입하는 방법을 쓸 수 있습니다.

2.1.5. 명시적인 줄 결합

둘 이상의 물리적인 줄은 역 슬래시 문자(\)를 사용해서 논리적인 줄로 결합할 수 있다: 물리적인 줄이 문자열 리터럴이나 주석의 일부가 아닌 역 슬래시 문자로 끝나면, 역 슬래시와 뒤따르는 개행 문자가 제거된 채로, 현재 만들어지고 있는 논리적인 줄에 합쳐진다. 예를 들어:

if 1900 < year < 2100 and 1 <= month <= 12 \
   and 1 <= day <= 31 and 0 <= hour < 24 \
   and 0 <= minute < 60 and 0 <= second < 60:   # 올바른 날짜 처럼 보인다
        return 1

역 슬래시로 끝나는 줄은 주석이 포함될 수 없다. 역 슬래시는 주석을 결합하지 못한다. 역 슬래시는 문자열 리터럴을 제외한 어떤 토큰도 결합하지 못한다 (즉, 문자열 리터럴 이외의 어떤 토큰도 역 슬래시를 사용해서 두 줄에 나누어 기록할 수 없다.). 문자열 리터럴 밖에 있는 역 슬래시가 앞에서 언급한 장소 이외의 곳에 등장하는 것은 문법에 어긋난다.

APLR

주석 끝에 붙는 역 슬래시는 주석의 일부일 뿐 명시적 줄 결합으로 보지 않습니다. 주석 앞에 붙는 역 슬래시는 문법에 어긋납니다.

APLR

역 슬래시와 개행 문자 사이에는 공백 문자를 포함해서 어떤 것도 등장할 수 없습니다. 역 슬래시 다음에 공백 문자가 오면 SyntaxError 를 일으킵니다.

2.1.6. 묵시적인 줄 결합

괄호(()), 꺾쇠괄호([]), 중괄호({})가 사용되는 표현은 역 슬래시 없이도 여러 개의 물리적인 줄로 나눌 수 있다. 예를 들어:

month_names = ['Januari', 'Februari', 'Maart',      # 이 것들은
               'April',   'Mei',      'Juni',       # 연 중 달들을
               'Juli',    'Augustus', 'September',  # 나타내는 네덜란드
               'Oktober', 'November', 'December']   # 이름입니다

묵시적으로 이어지는 줄들은 주석을 포함할 수 있다. 이어지는 줄들의 들여쓰기는 중요하지 않다. 중간에 빈 줄이 들어가도 된다. 묵시적으로 줄 결합하는 줄 들 간에는 NEWLINE 토큰이 만들어지지 않는다. 묵시적으로 이어지는 줄들은 삼중 따옴표 된 문자열들에서도 등장할 수 있는데 (아래를 보라), 이 경우는 주석이 포함될 수 없다.