2020년 9월 22일 13시 25분 (최근 수정: 2020년 9월 22일 13시 56분)
아래 내용은 인사이트 출판사의 제안으로 작성 중인 책의 초고입니다. 실제 출판 시에는 내용이 달라질 수 있습니다. 많은 의견 부탁드립니다.
문법과 의미는 프로그래밍 언어를 구성하는 가장 기본적인 요소이다. 1장에서 본 것처럼 표준 라이브러리나 생태계 같은 다른 요소도 있기는 하지만, 그 둘이 없어도 언어가 구성될 수 있다. 반면 문법과 의미가 없다면 언어가 언어로서 사용될 수 없다. 문법이 없으면 프로그램을 작성할 수 없고 의미가 없으면 프로그램을 실행할 수 없다. 프로그래밍 언어의 원리를 파악하는 데 있어 문법과 의미가 어떤 개념인지 이해하는 것은 중요하다. 이 장에서는 문법과 의미가 무엇인지 살펴본다.
문법은 그 언어로 작성된 프로그램이 어떻게 생겼는지, 즉 프로그램의 겉모습을 결정한다. 문법을 따르지 않는 코드는 프로그램이 될 수조차 없다. 다시 말해, 문법의 일차적 목표는 어떤 코드가 프로그램인지 아닌지 판별하는 것이다. 일상적으로 사람들이 자연어에 대해 이야기하면서 문법이라고 말하는 개념과 상당히 비슷하다고 볼 수 있다. “문장은 마침표, 물음표, 느낌표 중 하나로 끝나야 한다”는 규칙이 문법의 일부라면 “밥 먹었어.”나 “밥 먹었어?”는 글로서 인정받을 수 있겠지만, “밥 먹었어”는 글 취급을 받지 못하는 것이다.
이것이 문법이 하는 일의 전부는 아니다. “밥 먹었어.”와 “밥 먹었어?”는 둘 다 글이긴 하지만 같은 글은 아니다. “밥 먹었어.”는 “밥 먹었어”와 마침표의 결합으로 이루어진 글이고, “밥 먹었어?”는 “밥 먹었어”와 물음표의 결합으로 이루어진 글이다. 서로 다른 구조의 글인 것이다. 프로그래밍 언어의 문법 역시 코드가 프로그램인지 판단하는 것에 더해, 어떤 코드가 프로그램이 맞으면 그 프로그램의 구조를 표현할 수 있어야 한다. 이것이 문법의 두 번째 목표이다.
두 목표를 분리하는 것이 프로그래밍 언어를 엄밀히 정의하는 데 있어 유리하다. 그래서 프로그래밍 언어의 문법은 구체적 문법(concrete syntax)과 요약 문법(abstract syntax)으로 나누어진다. 코드가 프로그램이 맞는지 확인한다는 첫 목표는 구체적 문법이 담당하고 프로그램의 구조를 표현한다는 두 번째 목표는 요약 문법이 담당한다. 구체적 문법과 요약 문법이 만나 한 언어의 문법을 완성하는 것이다. 물론 그 둘이 하는 역할이 꽤나 다르기 때문에 각각 정의해 놓는다고 자석마냥 착 달라붙어 문법이 탄생하는 것은 아니다. 둘 사이를 이어줄 연결 고리가 필요하다. 파싱(parsing)1이 바로 그 연결 고리이다. 파싱은 구체적 문법을 만족하는 코드를 요약 문법이 표현하는 구조로 변경하는 과정이다.
문법이 프로그램의 겉모습을 결정했다면 의미는 프로그램의 속뜻을 결정한다. 어떤 프로그램이 있을 때 그 프로그램을 실행하면 무슨 일이 일어날지 정하는 것이 언어의 의미이다. “밥 먹었어.”는 필자가 밥을 먹었다는 사실을 표현하는 글이고 “밥 먹었어?”는 독자에게 밥을 먹었냐고 질문을 던지는 글이다. 이처럼 서로 다른 글이 서로 다른 뜻을 가지듯이, 언어의 의미는 서로 다른 프로그램이 각각 무엇을 의미하는지 정한다.
아직까지는 구체적 문법, 요약 문법, 의미에 대한 어렴풋한 느낌만 받을 수 있을 것이다. 이 장을 끝까지 읽은 뒤 다시 돌아와 앞의 설명을 보면 각각의 개념이 무엇인지 한층 더 명쾌하게 와닿을 것이라 생각한다.
‘구문 분석’이라고 번역하는 사람들도 있다.↩︎