프로그래밍 언어의 정의
프로그래밍 언어는 프로그램 작성에 사용되는 언어로, 컴퓨터가 수행할 수 있고 사람이 읽을 수 있는 형태로 계산을 나타내는 표기 체계이다. 프로그래밍 언어의 특징은 다음과 같다.
- 프로그래밍 언어는 말이 아닌 글 형태로 사용된다.
- 프로그래밍 언어는 엄밀한 규칙을 따르고 있다.
- 프로그래밍 언어는 기계에 명령을 전달하는 단방향성을 띤다. 그러나 최근에는 사람이 읽기 쉬운 프로그램 언어를 작성하는 능력이 요구된다. 즉, 가독성을 고려해야 하기에 양방향성의 특성도 지닌다.
프로그래밍 언어의 기능
프로그래밍 언어가 제공하는 기본 기능은 크게 3가지가 있다.
- 작성력(Writability): 프로그래머의 의도를 나타낼 수 있도록 하는 충분한 구성 요소를 갖춰야 한다.
- 가독성(Readability): 가독성은 프로그램 유지보수에 있어 매우 중요하며, 작성된 프로그램을 쉽게 해독할 수 있도록 해야 한다.
- 실행 가능성(Executability): 프로그래밍 언어로 작성한 프로그램은 반드시 컴퓨터에서 실행할 수 있어야 한다. 따라서, 문제 해결 아이디어를 구체적으로 실행 가능한 형태로 나타내는 "구현" 능력이 중요하다.
프로그래밍 언어는 위의 세 가지 기본 기능을 달성하기 위하여, 다양한 부가 기능을 제공하는데 이를 간단하게 두 가지로 요약 가능하다.
- 추상화(Abstraction): 어떤 대상을 간략하게 추려 나타내는 방법으로, 구체적인 대상에서 원하는 특징을 잡아 간략하게 나타내는 것이다.
- 모듈화(Modularization): 복잡한 대상을 나누어 구성하는 것이다. 이때, 모듈화를 통한 분할 뿐만 아니라 연결에도 신경을 써야 한다.
모든 프로그래밍 언어는 공통적으로 3가지 특성을 가진다.
- 기계적(Mechanical): 프로그램은 기계적으로 처리할 수 있어야 한다. 따라서 엄밀한 규칙에 따라서 정의된다.
- 구조적(Structural): 프로그램은 복잡한 구조로 나타낼 수 있어야 한다. 자료 구조, 제어 구조와 같은 구조를 통해 복잡성을 처리할 수 있다.
- 가변적(Variable): 프로그래밍 언어는 시대의 필요에 따라 바뀔 수 있다. 즉, 프로그래밍 언어는 시대에 따라 필요한 기능들이 새롭게 추가되는 형태로 발전한다.
컴퓨터 구조는 프로그래밍 언어에 제약사항을 가하고, 프로그래머는 프로그래밍 언어에 다양한 기능을 요구한다. 이 사시에서 프로그래밍 언어는 다양한 스펙트럼으로 존재하는데, 이는 추상화 수준에 따라 달라진다.
추상화 수준은 서로의 변환 가능성을 통해서 개략적으로 가늠 가능하다. 예를 들어 Python과 C 사이의 변환 가능성을 보면 Python 코드를 C 코드로 변환하는 것은 쉬우나, C코드를 Python 코드로 변환하는 것은 어렵다. C언어보다 Python이 추상화가 더 높은 것이다.
즉, 추상화 수준은 고급 언어와 저급 언어를 구분짓는 잣대이다. 이때, 고급 언어로 작성된 프로그램은 특정 기계에 한정되지 않고 여러 기계에서 수행 가능하고, 저급 언어로 작성된 프로그램은 작성된 기계에서만 실행 가능하다.
프로그래밍 언어의 구성 요소
프로그래밍 언어를 이루는 구성 요소는 다음과 같다.
데이터 (Data)
데이터는 어떤 자료를 프로그램이 처리할 수 있는 형태로 나타낸 것이다. 컴퓨터가 표현 가능한 데이터는 모두 이진수 형태로 나타난다. 컴퓨터가 처리하는 데이터를 크게 "이진 데이터"와 "텍스트 데이터" 이렇게 두 가지로 나눌 수 있다.
- 이진 데이터(Binary Data): 이진수의 나열로 이루어진 데이터로, 대부분 정수 형태로 나타난다. 실수 표현이 필요한 경우 "부동소수점 표현"을 사용한다. 이미지. 음악, 비디오 파일들은 이진 데이터로 분류된다.
- 텍스트 데이터(Text Data): 문자열을 나타내는 데이터로, 각 문자에 대응하는 이진 표현의 관계를 알아야 한다(코드), "ASCII 코드" 방식과 "유니코드" 방식이 있다.
연산 (Operation)
데이터를 처리하는 방법을 "연산"이라고 하고, 특별한 연산을 수행하는 함수를 "연산자"라고 한다. 프로그래밍 언어에서는 수식과 문장, 두 가지 구조를 통하여 연산을 나타낸다.
- 수식(Expression): 값을 나타내는 표현으로, 연산자가 없어도 값을 나타낼 수 있다면 수식이 된다. (Ex: 변수, 2, 45, 5+7... etc)
- 문장(Statement): 처리를 나타내는 표현으로, 계산 뿐만 아니라 프로그램의 수행의 흐름을 바꾸거나 값을 출력하는 등의 모든 처리에 관한 과정이다.
명령어 (Command)
특정 작업을 지시하는 단어를 "명령어"라고 한다. 프로그래밍 언어가 기본적으로 제공하는 연산을 "원시 연산(Primitive Operation)"이라고 하고, 프로그래머가 직접 연산을 정의한 것을 "사용자 정의 연산(User-Defined Operation)"이라고 한다. 원시 연산에는 포함되지 않으나, 사용자가 자주 사용할 만한 연산을 미리 정의한 것을 "라이브러리(Library)"라고 한다.
서브프로그램 (Subprogram)
코드에 이름을 부여한 것으로, 전체 프로그램을 이루는 작은 코드블록을 "서브프로그램"이라고 한다. 서브프로그램을 이용하면 프로그램 구조화에 도움이 되고, 반복적인 작업을 줄일 수 있다. 서브프로그램은 값 반환 여부에 따라 두 가지로 분류된다.
- 함수(Function): 연산 수행 결과 값을 반환하는 서브프로그램이다.
- 프로시저(Procedure): 결과 값을 반환하지 않는 서브프로그램이다.
타입 (Type)
타입이란 데이터 집합과 연산 집합을 합친 개념으로, 데이터형 또는 자료형이라고도 불린다. 타입은 연산의 안전성을 위하여 필요하다.
$f(x) : A \rightarrow B$ 이면, $a \in A$인 모든 $a$ 에 대하여 $f(a) \in B$ 이다.
이 성질이 만족되면 그 프로그램은 타입 안전하다. 타입이 안전하다는 것은 타입 오류가 발생하지 않는다는 것을 의미한다.
타입 안전성 측면에서 프로그래밍 언어는 "강타입 언어", "약타입 언어", "무타입 언어"로 분류된다.
- 강타입 언어(Strongly Typed): 타입 오류를 모두 검출하는 언어
- 약타입 언어(Weakly Typed): 타입 오류를 검출하나, 일부 타입 오류를 허용하는 언어
- 무타입 언어(Typeless): 타입 선언문도 없고, 어떤 대상의 타입이 계속 변경될 수 있는 언어
모듈 (Module)
독립적인 프로그램 구성 단위를 "모듈"이라고 한다. 서브프로그램 또한 모듈의 일종이다. 모듈을 내부와 외부를 구별하고 독자적인 이름공간(namespace)을 차지한다.
모듈은 여러 개발자들이 협업할 때 유용하고, 이름 충돌(name clash)를 해결할 때도 도움이 된다.
프로그래밍 언어의 두 가지 측면
프로그래밍 언어는 프로그램을 작성하는 방식에 대해 규칙을 정하고 있고, 그 규칙을 따르지 않을 경우 프로그래밍 언어의 컴파일러나 인터프리터는 프로그램을 실행할 수 없다.
프로그램 형태에 관한 이론을 "구문론(Syntax)"이라고 하고, 프로그램 수행 의미에 관한 이론을 "의미론(Semantics)"이라고 한다.
- 구문론(Syntax): 프로그램을 어떤 형태로 만들어야 하는지 세세하고 나열하고, 프로그램 형태를 규정한다. (Ex, 작성한 프로그램, 데이터, 연산.. etc)
- 의미론(Semantics): 실행 중인 프로그램(프로세스)를 생각하면서 프로그램을 작성해야 한다. (Ex, 실행 시 프로세스, 메모리, 실행 흐름... etc)