# [프로그래밍 언어] 1. Preliminaries

## 컴퓨터 구조가 언어 설계에 미친 영향

---

### **폰노이만 구조**

- 컴퓨터의 기본 구조는 언어 설계에 매우 강하게 영향을 미쳐왔음

- 지난 60년 동안 널리 사용된 대부분의 언어는 **폰노이만 구조**에 기반하여 설계

![Image](https://upload.cafenono.com/image/slashpagePost/20250103/132845_oD1RjwGy0w6FEHiiiX?q=80&s=1280x180&t=outside&f=webp)

- 데이터와 프로그램은 모두 **동일한 기억 장소**에 저장

- 명령어를 실행하는 **중앙처리장치 (CPU)는 기억 장소로부터 떨어져 있음**

- 명령어와 데이터는 기억 장소로부터 CPU에 전달되어야 하고, 
- CPU의 연산 결과는 다시 기억 장소로 전달되어야 함

### **명령형 언어 imperative language**

- 폰 노이만 구조에 기반한 언어

- 주요 특징: **변수, 배정문, 반복문**

**변수**

- 데이터를 저장하는 공간, 기억장소 셀을 모델링

- **함수형 언어**에는 값을 바꿀 수 있는 변수가 존재하지 않는다

**배정문**

- `=` 연산자를 사용하여 변수에 값을 저장하는 명령

- CPU와 기억장소 간의 데이터 이동 연산 담당

- `a=10;` : 10이라는 값을 a라는 변수가 가리키는 메모리 주소에 넣는다

- `b=a;` : a라는 주소가 가리키는 메모리 주소에서 값을 가져온 다음 b가 가리키는 주소가 가리키는 메모리 주소에 저장

- 평가 결과 값이 배정문의 좌측이 표현하는 기억장소로 다시 전달된다

**반복문**

- 폰노이만 구조에서 반복 연산을 구현

- `for( ; ; ){A; B; C;}`: A, B, C를 **연속적으로 저장**하여 반복하는 것이 더 좋음

- 실행을 반복하는 것은 몇 개의 분기 명령어만으로 수행 가능

- 반복은 연속적으로 저장되기 때문에 **재귀함수보다 더 효율적**이다

### 함수형 언어

- 폰 노이만 구조에서는 함수형 언어모다 명령형 언어가 효율적으로 실행됨

- **비-폰 노이만 컴퓨터**가 설계될 때까지는 함수형 언어가 명령형 언어를 대체할 것 같지 않다고 전망 → 자바의 경우 함수형 언어 기능을 포함하는 형태로 발전

- 어떤 사람들은 함수형 언어의 사용보다 명령어 언어의 사용이 더 자연스럽다고 생각
- → 명령형 프로그래밍 언어의 사용이 우위를 차지할 것이라고 전망

### 기계 코드 프로그램 실행 원리

- 프로그램은 기억장소에 저장하여 CPU에서 실행된다

**인출-실행 사이클 fetch-execute cycle**

1. 실행될 명령어는 **기억장소 → 프로세서 CPU**

2. PC에 저장되어 있는 주소의 데이터를 가져온다

- **프로그램 계수기 Program Counter**
-  : 다음에 실행될 명령어의 주소를 저장하는 레지스터

- PC의 초기값은 운영체제와 결정한다

3. **fetch**: 메모리에서 CPU로 데이터를 가져옴

4. PC가 다음 명령어를 가리키도록 한다

5. **decode**: 가져온 명령어 해석

6. **execute**: 명령어 실행

**인출-실행 사이클 알고리즘**

```
initialize the program counter
repeat forever
	fetch the instruction pointed by the program counter
	increment the program counter to point at the next instruction
	decode the instruction (명령어 해석)
	execute the insturction (명령어 실행
end repeat
```

**제어 전달**

![Image](https://upload.cafenono.com/image/slashpagePost/20250103/133009_VCN3MWnRBM2wNp8BRz?q=80&s=1280x180&t=outside&f=webp)

- 제어 전달 = PC가 바뀌는 것

- 제어가 운영체제로부터 사용자 프로그램으로 전달된다 **→ 사용자 모드** 
- 사용자 프로그램 실행이 완룐되면 제어는 다시 운영체제로 전달된다 → **관리자 모드**

- 제어가 동시에 주어질 수는 없고, 사용자 프로그램이나 운영체제 중 하나만 제어를 가짐

### 컴퓨터의 구성요소

**주요 구성 요소**

- **내부 기억 장소**: 프로그램과 데이터를 **저장하는 장소**

- **프로세서**: 산술과 논리 연산과 같은 기본 연산

    - **기계 명령어들의 집합을 구현하는 회로들의 모임**

    - 명령어 = 매크로 명령어 macroinstruction 또는 마이크로 명령어 microinstruction

- 프로세서가 제공하는 명령어로만 실제적인 컴퓨터 시스템을 설계, 개발하기 어려움

**실제적인 설계 방법**

- 기본 연산을 제공하는 매우 낮은 수준의 언어를 하드웨어로 구현

- 고급 언어로 작성된 프로그램에 대한 인터페이스를 시스템 소프트웨어가 생성하도록 요구

![Image](https://upload.cafenono.com/image/slashpagePost/20250103/133029_uoYT84rmi28USYfDzq?q=80&s=1280x180&t=outside&f=webp)

**가상 컴퓨터의 계층적 인터페이스**

- **가상 머신**: 프로그래머들을 대상으로 각 언어를 위한 가상 컴퓨터
- 물리적으로 하나의 컴퓨터지만 언어마다 다른 컴퓨터로 인식한다

- 운영체제와 언어 구현 시스템은 컴퓨터의 기계어 인터페이스에 대한 상부 틀 형성

- 사용자에 대한 인터페이스를 제공하는 가상 컴퓨터로 고려될 수 있음

- 컴파일러가 다르면, 기계는 다르 종류의 가상 컴퓨터가 될 수 있음

## 프로그래밍 언어 구현 방법

---

- 컴파일 구현: C

- 순수 인터프리터 구현: Python

- 혼합형 구현: Java

### **컴파일러 구현 compiler implementation**

- 프로그램을 기계어로 번역하는 구현

- 번역 과정이 완료되면 매우 빠른 프로그램 실행 가능

- C, C++

![Image](https://upload.cafenono.com/image/slashpagePost/20250103/133048_M04zMz8Ybjokt7j8XI?q=80&s=1280x180&t=outside&f=webp)

**원시 언어 source language**

- 컴파일러가 번역하는 언어

**어휘 분석기 lexical analayzer**

- 원시 프로그램에 포함된 문자들을 어휘 단어로 구분 
- (식별자, 특수어, 연산자, 구분자 기호 등)

**구문 분석기 syntax analyzer**

- 어휘 단위들을 가져와 파스 트리를 생성

**중간코드 생성기 intermediate code generator**

- 원시 프로그램과 기계여 중간 수준 언어

- C언어 함순는 어셈블리어로 구현할 수 있다 (속도가 느린 컴퓨터에서 사용)

**코드 생성기 code generator**

- 중간 코드를 기계어 프로그램으로 변환

**심볼 테이블 symbol table**

- 컴파일 과정에서 데이터베이스로 사용

**링킹 linking**

- 컴파일러에 의해 생성된 기계어가 하드웨어 상에서 직접 실행

- 기계어는 대부분 다른 코드와 함께 실행

    - main 함수 내부에서 돌아가는 코드를 모두 작성하여 사용할 수 있지만, printf, scanf를 사용하지 못해 코드가 돌아가는 과정을 확인할 수 있다

    - 라이브러리, 다른 개발자의 코드와 함께 실행된다

- 운영체제로부터 프로그램을 요구

    - 시스템 라이브러리 → printf, scanf

- 시스템 프로그램이 사용자 프로그램에서 요구될 때
- → 컴파일러는 요구된 시스템에 대한 호출을 생성

    - 컴파일러에 의해 생성된 기계어 프로그램이 실행될 수 있기 전에

    - 그 요구된 프로그램을 운영체제로부터 찾아서 사용자 프로그램에 연결

- **링킹 연산 linking operation**

    - 시스템 프로그램의 시작 주소를 (print: 1000번지)

    - 사용자 프로그램 상의 시스템 프로그램 호출 위치에 저장 (Jump 1000)

- 적재 모듈 load modeul 또는 실행 가능 이미지 executable image

    - 사용자 코드와 시스템 코드를 합하여 부르는 이름

- “링킹 linking 과 적재 loading” 또는 “**링킹 linking**”

    - **시스템 프로그램들을 모아서 사용자 프로그램에 연결하는 과정**

    - **다른 사용자 프로그램을 사용자 프로그램에 연결하는 과정**

- **링커 linker**: 링킹을 수행하는 시스템 프로그램

![Image](https://upload.cafenono.com/image/slashpagePost/20250103/133115_MOcokMHNEOUYi2kbM9?q=80&s=1280x180&t=outside&f=webp)

- **run**: exe까지 번역 후 실행

- **build**: exe까지 번역

- **compile**: `.o`까지 번역

- 이론적으로는 preprocessor, compiler, assembler로 구분되지만 
- 컴파일러, 링커로 지칭하여 사용한다

![Image](https://upload.cafenono.com/image/slashpagePost/20250103/133127_j7OEtIJYRNhQM1iJKq?q=80&s=1280x180&t=outside&f=webp)

### **순수 인터프리터 구현 pure interpreter implementation**

- 컴파일러 구현과는 정반대에 위치하는 구현 방법

- 명령을 주고 실행하면 결과를 만들어낸다

- 프로그램은 어떠한 번역 과정 없이, 인터프리터라 불리는 또 다른 프로그램에 의해 해석됨

    - 기계에 대한 소프트웨어 모의 실험으로 동작

    - 인출-실행 사이클은 기계 명령어가 아닌, 고급 프로그램 문장을 다룸

- JavaScript, PHP, Web 스크립트

![Image](https://upload.cafenono.com/image/slashpagePost/20250103/133138_9ZRrF4kfg6X2nrQVj1?q=80&s=1280x180&t=outside&f=webp)

- 컴파일 언어는 PCU가 기계어로 실행, 인터프리터 언어도 동일한 CPU를 사용

- 특별한 PCU가 없는데도 모의실험을 할 수 있는 뛰어난 CPU가 있는 것처럼 동작

- 인터프리터도 내부적으로 기계어로 번역해야 프로그램 실행 가능
- → 하지만 기계어로 번역하지 않는 것처럼 보인다

- 원시 코드 줄과 배열의 이름을 쉽게 표현할 수 있다

**장점**

- 많은 원시-수준 source-level 디버깅 연산을 쉽게 구현할 수 있음
- → 한 줄씩 실행하기 때문에 어디서 오류가 발생하는지 발견하기 쉽다

**단점**

- 고급 언어 문장을 해석해야 하기 때문에실행 시간이 컴파일된 시스템보다 10배 ~ 100배 정도 느리다

- 원시 프로그램 외에도 심볼 테이블이 해석 과정에 존재해야 하기 때문에 더 많은 기억 공간이 요구된다

**파이썬**

- 인터프리터 언어처럼 동작

- 파이썬 소스 코드를 컴파일하여 바이트 코드로 만들어내어 빠른 속도를 보여준다
- → 혼합형 구현 방법과 비슷

- 해석 프로그램의 종류: C 파이썬, 자이썬, 기타

### **혼합형 구현 hybrid implementation**

- 컴파일러 구현과 순수 인터프리터 구현 간의 절충된 구현

- 고급 언어 프로그램을 **용이한 해석이 가능하도록** 설계뙨 중간 언어로 번역

- 순수 인터프리터 구현보다 빠름

**JAVA**

- 초창기 구현은 혼합형 구현

- 바이트 코드라고 불리는 중간 코드를 실행할 수 있는 바이트 코드 인터프리터에 의해 실행

- **Java 가상 기계 (JVM) = “바이트 코드 인터프리터” + “Run-Time System”**

    - 어떤 기계에 대해서도 이식성을 제공한다

- **바이트 코드 인터프리터**

    - 바이트까지 번역한 내용을 인터프리터에 넣어 바이트 코드를 이해하는 CPU가 있는 것처럼 동작한다

- **Run-Time System**

    - 환경에 따라 JVM이 설치되면 모두 돌아간다

    - JVM의 하드웨어적인 부분을 숨겨준다 → 추상화

    - 중간코드 인터프리터와 하드웨어 인터프리터를 모두 가지고 있는 것이 JVM

    - 자바가 느리다는 문제 발생 → 자바도 기계 코드로 변환

    - 현재는 더 빠른 실행을 위해 Java 바이트 코드를 기계 코드로 번역하는 시스템이 존재

**JIT Just-in-Time 구현 시스템**

- 프로그램을 중간 언어로 번역

- 순수 인터프리터는 번역하고 실행한 뒤 버리기 때문에 기계어 번역이 안되는 것처럼 보이지만, JIT는 메소드 호출 시 중간코드를 기계어로 번역

    - 프로그램 실행 중에 중간 언어 메소드가 호출될 때, 그 메소드를 기계 코드로 번역

    - 이 기계 코드 버전은 다음 번 호출에 대비하여 보관됨

- JIT 시스템은 Java 프로그램에 대해 널리 사용되고 있음 (사용하지 않는 것도 있음)

- .NET 언어는 모두 JIT 시스템으로 구현

For the site tree, see the [root Markdown](https://slashpage.com/yerim-devnote.md).
