✨ 본 포스트는 CONCEPTS OF PROGRAMMING LANGUAGES 교재를 기반으로 작성되었습니다
Language Evaluation Criteria
프로그래밍 언어를 평가하는 수 많은 척도 중 주요 4가지 척도
1. Readability
- simplicity
- orthogonality
- data type
- 적을 수록 writability ⬇️ readability ⬆️
- syntax consideration
2. Wriability
- readability와 writability은 대부분 일치하나, 상반되는 경우도 존재함
- abstraction
- expressivity
3. Reliabiltiy
- 코드를 작성했을 때 예상한대로 돌아갈 확률
- type checking
- exception handling
- Aliasing
Python, C, Java의 reliability 순위
1. java
2. c (pointer)
3. python (dynamic type)
4. Cost
- time
- money
- reliability가 높을수록 유지보수에 드는 cost가 감소
5. 기타
- portability
- python
- java
- c
- generality
- c
- java
- python
- well-definedness
PL의 디자인에 영향을 미치는 요소
👉 Computer Hardware Architecture
- PL은
폰 노이만 아키텍처
로 알려진 아키텍처를 중심으로 개발됨
- 해당 언어들은 아래와 같은 특징을 가짐
- Data and programs stored in memory
- Memory is separate from CPU
- Instructions and data are piped from memory to CPU
- Basis for imperative languages
- Variables model memory cells
- Assignment statements model piping
- Iteration is efficient
🚨 Von Neumann Bottleneck
- 컴퓨터의 속도 : 컴퓨터의 메모리와 프로세서 간의 연결 속도에 따라 결정됨
- CPU의 발전으로 인해 프로그램 실행 속도가 종종 연결 속도보다 훨씬 빨라지게 되었고, 이에 따른 병목 현상 발생
- Memory Wall
- Memory의 발전 속도가 더뎌 CPU와 Memory의 갭 차이가 점점 더 커짐
Language Categories
Imperative
- variables, assignment statements, iteration을 사용
- OOP, Scripting, Visual Language 포함
- 예시: C, Java, Perl, JavaScript, Python, C++
Functional
- 수학 함수를 기반으로 하는 함수형 언어
- 매개 변수를 입력을 받아 처리하고 반환값을 출력하며, 모든 과정이 함수 호출로만 구성되어 있음
- 모든 로직은 함수 내부에만 구성되어 있으며, 변수에 대한 변화 X
- 구성요소
- 특징
- 변수 및 대입문 X
- recursion에 의한 반복 호출
- Loop와 같은 반복문 X
- 예시: LISP, Scheme, ML, F#, Haskell
fun fact(n : int) : int =
if n <= 1 then 1
else n * fact(n-1);
Logic
- p→q 형태의 술어 논리 기반 언어
- 선언적으로 프로그래밍하는 언어
- 프로그램 문제를 해결하는 방법보다 문제가 무엇인지를 논리 문장들로 표현함
- 특징
- 기계독립적이며 정확한 의미구조를 가짐
- 선언적 프로그래밍 → define에 집중
- 증명하는 것을 계산하는 것으로 간주
- 제어 추상화 없음 (루프, 선택문)
- 변수 : 부분 결과 값에 대한 이름
- 예시: Prolog
fact(0,1).
fact(N, V) :- N > 0, fact(N-1, V1), V is N * V1. //and조건으로 만족한다면
?- fact(3, X) //팩트와 명제를 통해 값을 도출
Implementation Methods
프로그램을 구현하는 3가지 방법
프로그램 언어 구현은 아래 3가지 요소를 통해 이뤄짐
1. 입력 받은 소스 프로그램이 구문법, 즉 Syntax에 맞는지 검사
2. 소스 프로그램이 의미, 즉 Semantics에 맞게 동작하도록 해석
3. 기계어 명령어로 변환
1. Compilation
- 소스 파일을 기계어로 번역함
- 컴파일을 시킨 시점에 실행됨
- 실행 가능한 바이트 파일로 변환해 배포함
- C와 같이 상용 프로그램을 만드는 언어들은 컴파일을 기반으로 함
- 장점 : 빠른 실행 속도
컴파일은 아래와 같은 과정을 거침
1. Lexical Analysis
- 토큰을 분석하는 단계
lexeme
: 최소의 어휘 단위
token
: lexeme을 종류별로 모아둔 집합
- 문장의 의미있는 단위를 뽑아내는 과정
2. Syntax Analysis
- 문법을 분석하는 단계
- 이를
Parsing
이라고 부르며, Parse Tree
를 그리며 문장을 Parsing함
- 문법상 문제가 있다면, 즉 Parse Tree가 그려지지 않는다면 이는 Syntax Error를 뜻함
3. Semantics Analysis
- 문장을 해석하는 단계
- 무슨 동작을 할 지 결정하며, 이를 기반으로 중간 코드를 작성함
4. Optimization
- 3, 4번을 반복하며 코드를 최적화하는 단계
- 더 이상 최적화가 불가능하면, Generation 단계로 이동
5. Code Generation
- 최종적으로 기계어 Translation을 진행하는 단계
- 중간 코드를 기계어로 번역함
2. Pure Interpretation
- 런타임에 소스 코드를 기계어로 변환함
- 더 많은
SPACE
를 요구함
- Python, JS와 같은 언어들이 기반으로 함
- 장점 : 하드웨어에 대한 의존성을 없앰
- 단점 : 최적화가 불가능하며, 이 때문에 속도가 느림
- 런타임에 변환하기 때문에 변환 과정에 있어서 중복 처리가 발생하기 때문
3. Hybrid Implementation Systems
- compiler와 pure interpreter를 합침
- 프로그램을
intermediate code
로 변환함
- Java의 JVM
- 장점 : interpretation보다 빠른 속도
hybrid implementation system은 아래와 같은 과정을 거침
1. Lexical Analyzer
2. Syntax Analyzer
3. Intermediate code generator
4. Interpreter