Chapter 01. 서론
프로그래밍 언어론 원리와 실제 - 창병모 교수님
1.1 프로그래밍 언어란 무엇인가?
1) 프로그래밍 언어란 무엇인가?
- 프로그래밍 언어: 계산 과정을 기계가 읽을 수 있고 사람이 읽을 수 있도록 기술하기 위한 일종의 표기법. 즉, 기계가 해석할 수 있고 사람이 이해할 수 있어야 함
- 계산(Computation): 컴퓨터가 할 수 있는 연산들을 나타내며 덧셈, 뺄셈, 비교와 같은 데이터 조작, 문자 입출력과 같은 텍스트 처리, 정보 저장 및 검색 등을 의미
- 기계 읽기(machine readability): 효율적인 번역 혹은 실행이 가능해야 함을 뜻함
- 사람 읽기(human readability): 사람이 쉽게 프로그래밍할 수 있도록 편의성을 제공해야 하며 컴퓨터 연산들이 이해하기 쉬운 형태로 추상화 혹은 요약되어야 한다는 점을 의미함
2) 프로그래밍 언어의 중요성
- 소프트웨어의 발전은 프로그래밍 언어를 매개로 하여 발전함
- 언어에 따라 사고방식이 달라짐
- 절차형(명령형) 언어(procedual language) → 계산과정의 절차를 기술하는 것
- 함수형 언어(functional language)
- 논리 언어(logic language) → 논리 규칙 형태로 작성
- 객체-지향 언어(object-oriented language)
3) 주요 주제
- 주요 언어 이론
- 구문론(syntax): 문장을 구성하는 방법
- 의미론(semantics): 작성된 문장의 의미를 결정
- 타입 시스템(type system): 타입의올바른 사용법
- 프로그래밍 언어의 설계
- 동기, 원리
- 샘플 언어 설계
- 프로그래밍 언어의 구현 기술
- 주요 구현 기술
- 샘플 언어의 인터프리터
- 주요 프로그래밍 패러다임
- 명령형 언어
- 객체지향 언어
- 함수형 언어
- 논리 언어
- 프로그래밍 언어의 역사
- 기계어나 어셈블이어와 같은 저급 언어의 문제점을 해결하기 위한 고급 프로그래밍 언어의 개발은 1950년대부터 시작되어 지금까지 계속됨
- 이러한 고급 언어의 발전과 더불어 컴퓨터 및 소프트웨어의 발전이 계속되고 있음
1.2 프로그래밍 언어의 종류
1) 프로그래밍 패러다임
명령형 프로그래밍 (procedual(절차형)/ imperative programming) |
|
함수형 프로그래밍 (functional programming) |
|
논리 프로그래밍 (logic programming) |
|
객체지향 프로그래밍 (object-oriented programming) |
|
2) 함수형 언어(Functional language)
- 기본 모델
- 수학 함수를 기반으로 하는 언어. 즉, 프로그램의 계산 과정을 수학 함수의 수행으로 간주하는 언어
- 프로그램: 매개변수로 입력을 받아 처리한 후에 반환 값을 출력하는 함수
- 함수
- 함수 정의(definition)
- 함수 호출(function call)
- 매개변수(parameter)
- 반환값(return value)
- 특징
- 변수 및 대입문이 없음 → 함수의 매개변수를 통해서 값을 전달할 수 있음
- 자기호출(recursion)에 의한 반복
- 루프 같은 반복문 없음 → 재귀호출(recursive call)을 통해서 할 수 있음
- 순수한 함수 수행은 부수 효과(상태 변경 혹은 데이터 수정)를 허용하지 않음
- 예제: 함수형 언어 ML을 이용하여 계승(factorial)을 계산하는 함수
f(0) = 1 // 0! = 1
f(n) = n * f(n-1) // n! = n * (n-1)!
수학적으로 계승 함수 f는 위와 같이 정의할 수 있음
fun fact(n:int) : int =
if n<=1 then 1
else n * fact(n-1);
함수 f를 ML 언어를 이용하여 위와 같이 작성할 수 있음
이 함수는 int 타입의 값을 매개변수로 받아 int 타입의 값을 반환한다고 선언되어 있음
매개변수 n의 값이 0이면 반환 값이 1이며 그렇지 않은 경우에는 n-1 계승을 계산한 결과인 fact(n-1) 값과 n 값을 곱한 값이 반환됨
- 장점
- 프로그래밍 모델이 기계 모델과 무관함
- 수학을 기반으로 하고 있으므로 프로그램의 의미를 명확하게 파악할 수 있음
- 예: Lisp, ML, Scheme, Haskell
3) 논리 언어(Logic language)
- p → q 형태의 술어 논리(predicate logic)를 기반으로 함
- 선언적으로 프로그래밍하는 언어
- 프로그램: 문제에 대한 사실 혹은 규칙을 표현하는 논리 문장들의 집합. 즉, 문제를 해결하는 방법보다 문제가 무엇인지 논리 문장들로 표현하는 논리 문장들로 구성됨
- 예: 계승을 논리 언어인 Prolog를 이용하여 논리 문장들로 작성
fact(0, 1).
fact(N, V) :- N > 0, fact(N-1, V1), V is N * V1.
?- fact(3, X)
첫 번째 규칙: 0의 계승은 1이라는 사실 표현
두 번째 규칙: N이 0보다 클 때 적용될 수 있으며 이때 N의 계승 V는 N-1의 계승이 V1이면 N*V1이라는 것을 표현
증명하는 것을 계산하는 것으로 간주함
* ':-' 기호를 기준으로 오른쪽이 가정이고 왼쪽이 결론
- 특징
- 루프나 선택문 등의 제어 추상화가 없음
- 제어는 하부 시스템(해석기)에 의해 제공됨
- 변수는 메모리 위치가 아니라 부분 결과 값에 대한 이름임
- 장점
- 기계-독립적이고 정확한 의미구조를 가지고 있음
- 선언적 프로그래밍이 가능
- Prolog: 대표적인 논리언어로 인공지능, 자연어 처리 등의 분야에서 많이 사용됨
4) 객체지향 언어(Object-oriented language)
- 실세계를 모의실험 하기 위한 언어로 고안됨 → 즉, 실제 세계에 있는 사물을 컴퓨터에서 표현하기 위해 고안된 것
- 객체 개념을 기반으로 하는 프로그래밍 스타일
- 객체(Object): 속성과 관련 행동(함수, 메소드)들의 모음으로 표현
- 계산과정(computation): 객체들 사이의 상호작용(메소드 호출)
- 클래스(class)
- 클래스는 객체에 대한 타입 정의
- 객체는 클래스의 한 실체(instance)임
1.3 프로그래밍 언어의 역사
- 프로그램 저장 방식의 범용 컴퓨터의 등장과 함께 프로그래밍은 중요한 문제가 됨
- 초기의 프로그램은 기계어 또는 기계어를 표현하는 기호화 코드를 사용하는 어셈블리어를 사용하여 작성함
- 어셈블리어와 같은 '저급(low-level)' 언어를 사용한 프로그래밍은 너무 어렵고 비생산적인 단점을 가짐
- 저급 언어의 단점을 보완하기 위해 고급 언어의 개발이 1950년부터 시작됨
1) 1950년대: 고급 프로그래밍 언어의 시작
FORTRAN (FORmula TRANslation) |
|
COBOL (COmmon Business-Oriented Language) |
|
LISP (List Processor) |
|
2) 1960년대: 프로그래밍 언어의 다양성
Algol60 |
|
Algol68 |
|
PL/I |
|
Simula-67 |
|
BASIC |
|
3) 1970년대: 단순성 및 새로운 언어의 추구
PASCAL |
|
C언어 |
|
Prolog |
|
Scheme |
|
ML |
|
4) 1980년대: 추상 자료형과 객체 지향
Ada |
|
Modula |
|
Smalltalk |
|
C++ |
|
5) 1990년대: 인터넷 언어와 새로운 시도
Python |
|
Java |
|
JavaScript |
|
6) 2000년대: 새로운 미래를 향하여
C# |
|
Scala |
|
Objective-C와 Swift |
|
1.4 추상화와 명령형 언어의 발전
1) 프로그래밍 언어 발전 과정
- 최초의 프로그램 저장 방식의 컴퓨터 ENIAC가 만들어지면서 프로그래밍 언어가 개발되기 시작함
- 이때 만들어진 컴퓨터는 폰 노이만(Von Neuman) 모델 컴퓨터이며 초창기 프로그램은 컴퓨터에 명령하는 기계어 명령어들의 집합이었음
- 프로그램 저장 방식의 범용 컴퓨터의 등장으로 프로그래밍은 중요한 문제가 됨
- 초기의 프로그램은 기계어로 작성하였는데 이후 이것은 기계어를 표현하는 기호화 코드를 사용하는 어셈블리어로 발전
- 하지만 어셈블리어 역시 기계에 매우 의존적이었으며, 구문 역시 자연어와 동떨어져 있었음 → 저급(low-level) 언어
2) 폰 노이만 모델 컴퓨터
- 프로그램 내장 방식 컴퓨터: stored-program computer
- 프로그램은 명령어와 데이터로 구성되며 작성된 프로그램은 실행을 위해 먼저 주 메모리에 적재되어야 함
- 메모리에 저장된 명령어 순차 실행
- CPU는 순차적으로 메모리에 저장된 명령어를 실행함
- PC: 다음 실행할 명령어를 가리키는 레지스터
- 명령어: 메모리에 저장된 값을 조작 혹은 연산
- 인출-해석-실행(fetch-decode-execute) wnrl
- CPU는 주 메모리 내에 저장되어 있는 프로그램의 명령어를 한 번에 하나씩 읽어 들여 해석하고 실행함
3) 명령형 언어(Imperative language)
- 명령형 프로그래밍 언어는 폰 노이만 모델 컴퓨터의 연산을 흉내 내거나 추상화하는 것으로부터 시작되었음
- 예: Fortran, C, Basic
- 폰 노이만 모델 컴퓨터의 특징을 많이 가지고 있음
- 순차적 명령어 실행
- 메모리 위치를 나타내는 변수 사용
- 대입문을 사용한 변수 값 변경
- 사람의 필요보다는 컴퓨터 모델을 기반으로 한 언어
4) 추상화(Abstraction)
- 추상화는 실제적이고 구체적인 개념들을 요약하여 보다 높은 수준의 개념을 유도하는 과정
- 명령형 언어는 컴퓨터의 데이터, 연산, 명령어 등을 추상화
- 무엇을 요약하여 추상화하느냐에 따라 데이터 추상화와 명령어 추상화가 있음
- 데이터 추상화(Data Abstraction)
- 데이터 추상화는 저수준의 데이터나 자료형들을 요약하고 추상화하여 보다 고차원의 새로운 자료형 또는 자료구조를 만드는 과정을 의미
- 기본 추상화: 기본적인 데이터와 관련된 간단한 추상화 ex) 변수, 자료형
- 변수: 데이터 값을 저장하는 메모리 위치 ex) 메모리 120 번지를 추상화하여 변수 x라고 할 수 있음
- 자료형: 값들의 종류에 대한 이름 ex) int, float, double
- 복잡하고 구조적: 관련된 여러 값이나 변수들의 모음을 요약하여 추상화 ex) 배열, 레코드
- 프로그래밍 언어는 이러한 추상화된 개념을 제공하고 프로그래머는 이러한 개념을 기반으로 프로그래밍함
- 제어 추상화(Control abstraction)
- 제어: 프로그램 내의 명령어의 실행 순서를 의미함. 따라서 제어는 명령어 실행 순서를 제어한다는 것을 의미
- 제어 추상화는 실행 흐름을 나타내는 저수준 명령어들을 요약하고 추상화하여 보다 높은 수준의 제어구조를 만드는 과정
- 기본 추상화: 몇 개의 기계어 명령어들을 하나의 문장으로 요약 ex) 대입문, goto문(jump 명령어의 요약)
- 구조적 제어 추상화: 테스트 내의 중첩된 기계어 명령어들을 하나의 문장으로 요약 ex) if, switch, for, while 문
- 프로시저(함수, 메소드) 추상화
- 선언: 일련의 계산 과정을 하나의 이름으로 요약해서 정의
- 호출: 이름과 실 매개변수를 이용하여 호출
A부터 실행을 시작하여 GOTO B를 만나면 B이하 부분을 실행하고 다시 되돌아옴
레이블 B 이하의 일련의 계산 과정을 하나의 이름으로 요약해서 정의하는 것이 함수 혹은 프로시저 정의라고 함
GOTO B: 함수 호출
GOTO C: 함수로부터의 리턴
- 제어 추상화의 장점
- 기계에 대한 추상화된 관점 혹은 개념을 제공하므로 이러한 개념을 이용하면 보다 쉽게 프로그래밍할 수 있음
- 다른 제어 관련 문장들과 쉽게 중첩되어 사용될 수 있게 해 주므로 이러한 추상화된 개념을 이용하면 보다 복잡한 프로그램을 쉽게 작성할 수 있음
- 특히 프로시저 추상화는 크고 복잡한 프로그램을 쉽게 작성할 수 있는 여러 개의 프로시저로 구분하여 작성하게 함으로써 프로그래밍의 복잡도를 줄일 수 있음
5) 추상 자료형(Abstract Data Type)
- 데이터 추상화와 제어 추상화를 통합해 만든 자료형
- 데이터와 관련된 연산들을 캡슐화하여 정의한 자료형 ex) 스택 자료형(스택을 표현하기 위한 자료구조와 push, pop 등과 같은 연산들을 한데 묶어 추상 자료형으로 정의)
- Modual-2의 모듈, Ada의 패키지, C++, Java 등이 클래스에서 사용
1.5 프로그래밍 언어의 정의 및 구현
1) 프로그래밍 언어의 정의 방법
- 어휘 구조(lexial structure)
- 언어에서 사용하는 단어의 구조, 철자법 등을 의미
- 구문법(syntax)
- 구성요소를 이용하여 문장/프로그램을 구성하는 방법
- 문법을 이용하여 기술할 수 있음
- Context-free grammar in BNF(Backus-Naur Form)
- 의미론(semantics)
- 문장/프로그램의 의미를 정하는 것
- 자연어 혹은 수학적으로 기술
2) 프로그래밍 언어 구현
- 인터프리터
- 소스 프로그램을 입력받아 구문법에 맞게 작성되었는지 검사하고 그 의미를 파악하여 의미에 맞게 동작하도록 해석함
- 프로그램 내의 문장을 해석할 때 입력 혹은 출력 문을 만나면 사용자로부터 입력을 받거나 사용자에게 출력함
- 컴파일러
- 소스 프로그램을 입력받아 구문법에 맞게 작성되었는지 검사하고 그 의미를 파악하여 의미에 맞게 동작하도록 기계어 명령어들로 번역
- 기계어 프로그램을 목적 프로그램(target program)이라고 하며 이 프로그램이 실행됨
- 프로그램 실행 중에 입력 혹은 출력 문을 만나면 사용자로부터 입력을 받거나 사용자에게 출력함
- 구문 분석(syntax analyzer or parser): 컴파일러나 인터프리터가 소스 프로그램을 입력받아 그 프로그램이 구문법에 맞게 작성되어 있는지 검사하는 것
- 어휘 분석(lexical analyzer or scanner): 구문 분석에 앞서 소스 프로그램을 토큰이라는 의미 있는 어휘 단위로 분리하는 것
- 의미 분석(semantic analyzer): 구문 분석 이후 변수 중복 선언 검사, 타입 검사 등을 통해 의미에 맞게 사용되고 있는지 검사
- 의미에 따라 컴파일러는 코드를 생성하고 인터프리터는 해석하여 실행함
소스 프로그램을 입력으로 받아 어휘 분석, 구문 분석, 그리고 의미 분석을 수행하고
컴파일러는 목적 코드를 생성하고 인터프리터는 해석하여 실행함
'Study > Programming Language' 카테고리의 다른 글
[PL] Chapter 04. 변수 및 유효범위 (2) | 2022.04.25 |
---|---|
[PL] Chapter 03. 언어 설계와 파서 구현 (0) | 2022.04.24 |
[PL] Chapter 02. 구문법(Syntax) (0) | 2022.04.24 |