Sign In
Programming Language

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

Y
Yerim
Category
  1. Programming Language

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

폰노이만 구조

컴퓨터의 기본 구조는 언어 설계에 매우 강하게 영향을 미쳐왔음
지난 60년 동안 널리 사용된 대부분의 언어는 폰노이만 구조에 기반하여 설계
데이터와 프로그램은 모두 동일한 기억 장소에 저장
명령어를 실행하는 중앙처리장치 (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
제어 전달
제어 전달 = PC가 바뀌는 것
제어가 운영체제로부터 사용자 프로그램으로 전달된다 → 사용자 모드
사용자 프로그램 실행이 완룐되면 제어는 다시 운영체제로 전달된다 →
관리자 모드
제어가 동시에 주어질 수는 없고, 사용자 프로그램이나 운영체제 중 하나만 제어를 가짐

컴퓨터의 구성요소

주요 구성 요소
내부 기억 장소: 프로그램과 데이터를 저장하는 장소
프로세서: 산술과 논리 연산과 같은 기본 연산
기계 명령어들의 집합을 구현하는 회로들의 모임
명령어 = 매크로 명령어 macroinstruction 또는 마이크로 명령어 microinstruction
프로세서가 제공하는 명령어로만 실제적인 컴퓨터 시스템을 설계, 개발하기 어려움
실제적인 설계 방법
기본 연산을 제공하는 매우 낮은 수준의 언어를 하드웨어로 구현
고급 언어로 작성된 프로그램에 대한 인터페이스를 시스템 소프트웨어가 생성하도록 요구
가상 컴퓨터의 계층적 인터페이스
가상 머신: 프로그래머들을 대상으로 각 언어를 위한 가상 컴퓨터
물리적으로 하나의 컴퓨터지만 언어마다 다른 컴퓨터로 인식한다
운영체제와 언어 구현 시스템은 컴퓨터의 기계어 인터페이스에 대한 상부 틀 형성
사용자에 대한 인터페이스를 제공하는 가상 컴퓨터로 고려될 수 있음
컴파일러가 다르면, 기계는 다르 종류의 가상 컴퓨터가 될 수 있음

프로그래밍 언어 구현 방법

컴파일 구현: C
순수 인터프리터 구현: Python
혼합형 구현: Java

컴파일러 구현 compiler implementation

프로그램을 기계어로 번역하는 구현
번역 과정이 완료되면 매우 빠른 프로그램 실행 가능
C, C++
원시 언어 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: 링킹을 수행하는 시스템 프로그램
run: exe까지 번역 후 실행
build: exe까지 번역
compile: .o까지 번역
이론적으로는 preprocessor, compiler, assembler로 구분되지만
컴파일러, 링커로 지칭하여 사용한다

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

컴파일러 구현과는 정반대에 위치하는 구현 방법
명령을 주고 실행하면 결과를 만들어낸다
프로그램은 어떠한 번역 과정 없이, 인터프리터라 불리는 또 다른 프로그램에 의해 해석됨
기계에 대한 소프트웨어 모의 실험으로 동작
인출-실행 사이클은 기계 명령어가 아닌, 고급 프로그램 문장을 다룸
JavaScript, PHP, Web 스크립트
컴파일 언어는 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 시스템으로 구현
Subscribe to 'Yerim-DevNote'
Subscribe to my site to be the first to receive notifications and emails about the latest updates, including new posts.
Join Slashpage and subscribe to 'Yerim-DevNote'!
Subscribe
👍