[1강 Summary]
– 기계어 : 프로세스 직접 제어 비트 시퀀스(두 정수 조합)
– 어셈블리어 : 연산자를 기호로 표현(연산기호 약어), 기계어와 1:1 매핑
– 컴파일러: 고급 수준 언어를 어셈블리어나 기계어로 변환 작업 수행
– 언어의 진화 : goto -> 구조화(loop,switch) -> 객체지향 -> 스크립팅
– 특수 목적 위한 언어 : Lisp(상징적, 복잡 데이터 구조용), C(시스), prolog(데이터간논리적추론)
– 개개인 선호별 언어 다르다
– 성공적인 언어 특징 : 다양한 관점 고려되어 언어의 좋음 결정
(표현력, 쉬운 사용 및 구현, 무료, 표준안, 오픈소스, 훌륭한 컴파일러, 경제성등)
– 프로그램 언어 분류 : 선언형(컴퓨터가 무슨일하는지 집중) / 명령형(컴퓨터가 어떻게 일을하는지 집중)
– 선언형 언어 세부분류
1) 함수형 언어 : 재귀와 람다 기반 (Lisp, ML, Haskell)
2) 데이터 흐름 언어 : 정보의 흐름을 모델화 (Id, val)
3) 논리형 언어 : 명확관계 성립 값 탐색 시도 (prolog, SQL)
– 명령형 언어 세부분류
1) 폰노이만(절차적) 언어 : 함수, 표현통해 메모리의 값 변경 기반(Fortran, C, Basic)
2) 객체지향 언어 : 반독립 객체(변수+메소드)들간 상호작용 기반(C++, java)
3) 스크립팅 언어 : 접합(다른언어,라이브러리 연동) 주안, 절차적 언어의 부분 집합(php,Js,python)
– 오늘날 언어들은 서로의 특성 여러개 보유해서 명확한 구분은 불가능
– 컴파일(Compilation) : 전체코드를 컴파일러를 통해 target program으로 번역, 이후 실행시 input값을 target에 넣어서 실행
– 인터프리트(Interpretation) : 코드를 한줄씩 읽으며 input값 넣은상태로 통역 (기계어가 고급 수준 언어인 VM) : 한번만 읽음
– 컴파일 특징 : 더 나은 수행력(컴파일시점에 target 으로 번역해둬서 실행시 빠른 실행 가능 – early binding)
– 인터프리트 특징 : 유연함, 더 나은 에러 진단, 실행시점에 통역 – late binding
– preprocessor(initial translator) : 전처리기. 전처리문(#define #ifdef등) 통해 필요한 코드부분만 활성화 / 주석, 공백 미리 제거
– 프로그래밍 언어 구현 전략 : 전처리기 / target program으로 어셈블리어(기계 독립성) / Java의 JIT
– JIT : 코드 처음실행할때 인터프리터 이용해 자주 쓰이는부분 캐싱해, JIT 컴파일러에서 이 캐싱된 코드를 이용해 빠른 실행 유도
– 컴파일 과정에서 프론트엔드와 백엔드
1) 프론트엔드 : 소스 프로그램이 무슨 의미인지 알아내는 역할
2) 백엔드 : 정해진 목표 프로그램으로 구현 역할
– 컴파일 과정
1) 스캐너 : 공백제거, 주석제거, 낱말 분석(글자글자를 의미있는 토큰화) / 토큰 흐름 추출 / int 1num;
2) 파셔 : 토큰들 순서대로 배치여부 확인(문맥적 오류 확인) / parser tree 추출 / int num (;없음)
3) 시맨틱 검사 : 논리적 오류 검사 (정적, 동적 분류) / 추상적 문맥 트리 추출 /
– 정적 시맨틱 검사 : 컴파일 시점 수행 / 변수, 문법 검증 / int num = 20.301;
– 동적 시맨틱 검사 : 실행 시점 수행 / 변수초기화, overflow, 포인터유효 검증 / int[10212] = 100;
– 인터피리터와 컴파일러는 프론트엔드 과정 동일(공유)하지만, 인터프리터는 중간코드를 바로 실행하는 차이점 존재.
[1강 연습문제]
Q1.
기계어와 어셈블리어의 차이점이 무엇인가?
A1.
기계어는 프로세서 직접제어하는 기계친화적인 언어.
어셈블리어는 확실힌 명령어(mnemonics)을 사용해 기계어와 1:1매핑되고, 보다 사람 친화적인 언어이다.
Q2.
어떤 부분에서 고등언어가 어셈블리어보다 나은가?
그리고, 프로그램을 어셈블리어로 만드는 경우가 아직도 있는가?
A2.
고등수준 언어는 우리가 사용하는 말과 비슷한 형태로 보여지기때문에 더욱 쉽게 사용하고 이해할수 있기에, 작업속도를 향상시킨다.
또한 고등수준언어는 기계어로 바로 번역되는게 아니라, 어셈블리어로 번역되는데
이는 기계마다 다른 기계어에 일일히 고등수준에서 대응하지 않고 어셈블리어로 번역해,
어셈블리어를 기계별 기계어로 번역해주는 방식을 이용한다.(플랫폼 독립성)
Q3.
왜이리 많은 프로그래밍 언어가 존재하는가?
A3.
1) 진화(Evolution)적 요인. 더 나은 방법으로 프로그래밍 하는 방법 생겨남
2) 사회적, 경제적 요인 : 특수목적을 위한 언어, 개개인별로 선호하는 언어가 다름
Q4.
무엇이 프로그래밍 언어의 성공을 결정 짓는가?
A4.
하나의 특성이 프로그래밍 언어의 성공을 결정짓지 못한다.
여러가지 요인(표현력, 쉬운사용, 구현, 무료제공, 표준안, 오픈소스, 훌륭한 컴파일러, 경제성등)들이 존재.
Q5.
주어진 카테고리별 언어들 예시 3개를 들어라 : 폰노이만, 함수, 객체지향
논리언어 두가지를 말해라.
오늘날 널리 사용되는 언어 두가지를 말해라.
A5.
폰노이만 언어 : C, Fortran, Ada83
함수형 언어 : Lisp/Scheme, ML, Haskell
객체지향 언어 : Java, C++, C#
논리유추 언어 : prolog. SQL
오늘날 널리 사용되는 언어 : JAVA, C# 등
+) 언어의 분류
선언형 언어 - 함수형 언어, 데이터 흐름 언어(ID,Val,Sisal), 논리유추 기반 언어
명령형 언어 - 폰노이만 언어, 객체지향 언어, 스크립팅 언어(PHP, JS, Python등) 로 분류된다.
Q6.
선언형(Declarative) 언어와 명령형(Imperative) 언어를 구분짓는 척도는 무엇인가?
A6.
이 둘을 구분짓는 기준은 해당 언어를 사용했을때, 컴퓨터가 어떤것에 집중하는지에 따라 구분된다.
선언형 언어는 컴퓨터가 무엇(What)을 하는지에 집중하고,
명령형 언어는 컴퓨터가 어떻게(How) 하는지에 집중한다.
Q7.
어떤 단체가 Ada 발전의 가장 큰 기여를 했는가?
A7.
US Department of Defense
Q8.
일반적으로 첫번째 고급 수준 프로그래밍 언어로 고려되는 언어는?
A8.
FORTRAN
Q9.
첫번째 함수형 언어는 무엇인가?
A9.
LISP
Q10.
왜 현재 언어들은 앞서봤던 선언형, 명령형와 그 세부구조처럼 명확히 구분되지 않는가?
A10.
현재 사용되는 대부분의 언어들이 한가지 특성만 가지고 있는게 아니라 여러가지 특성들을 혼합해서 사용하고 있어 명확한 구분이 불가능하다.
Q11.
인터프리트와 컴파일의 차이에 대해 설명해라.
각각의 장단점은 무엇인가?
A11.
# 인터프리트
: 원본 프로그램을 각 줄마다 통역(줄에서 에러 확인 가능)
: 원본 프로그램을 바로 기계어로 변환
: 유연함 / 더 나은 진단 / 실행 시점에 변역
# 컴파일
: 원본 프로그램을 전체 한번 훑고 타겟 프로그램으로 변환(translate), 컴파일 시점(이후이를 OS가 실행)
: 전체 소스코드를 변환한뒤 에러를 보고.
: 빠른 실행
Q12.
자바는 컴파일되는가 인터프리트 되는가?
A12.
자바는 둘다한다.
자바컴파일러는 자바 프로그램을 target code(중간 코드) 인 ‘자바 바이트 코드’로 변환
이 바이트 코드를 인터프리트(자주 사용하는 코드 캐싱) 이후 이 코드를 JIT 컴파일러로 기계어로 변환
+ 각 언어별 구현 전략
+ preprocessor(Initial translater)
+ target program으로 어셈블리어
Q13.
컴파일러와 전처리기(preprocessor) 차이점
A13.
C 기준으로 컴파일러로 컴파일하기전에 전처리 작업을 수행한다.
전처러기는 사전 처리 작업을 한다. (#include, #define #if #ifdef와 같은 지시문 처리)
단순 텍스트 조작일 뿐. 이후 명령어 처리를 컴파일러가 한다.
Q17.
JIT(just-in-time) 컴파일러란?
A17.
동적 컴파일 ( 프로그램 실행 시점에서 필요한 부분을 즉석으로 컴파일 하는 방식) 을 의미.
(인터프리터가 더 맞는 표현)
Java에서 같은 코드를 매번 해석하는 대신 처음 실행될 때 인터프리트를 하면서
자주 쓰이는 코드를 캐싱한 뒤 이후에는 캐싱된 코드를 가져다 쓰기 때문에
인터프리터의 느린 실행 속도를 개선할 수 있다. ( = Java 컴파일러 컴파일 방식)
Q22.
컴파일 주요과정을 나열하고, 각 과정에서 무엇을 수행하는지 서술해라.
A22.
1) 스캐너
: 공백제거, 주석제거, 문자열 읽으면서 토큰화(낱말 분석)
2) 파서(parser)
: 토큰들 배치 순서 검사후 parser tree 생성 ( = 문법적 오류 검사)
3) 시맨틱 분석후, 중간 코드 생성
: 변수, 타입과 같은 논리적 오류 검사
(이과정을 컴파일시점, 실행시점에 하냐에 따라 정적, 동적 나뉨)
4) 타겟 코드 생성후 최적화(옵션)
Q23.
인터프리터 과정을 나열해라
A23.
스캐너, 파서, 시맨틱 분석후 중간 코드 생성 까지 동일.
이후 이 생성된 중간코드와 input값을 tree-walk routines에 넣어 output 도출한다.
Q24.
스캐너에서 파셔로 전달된 양식, 파셔에서 시맨틱 분석기로 넘어간 양식,
시멘틱 분석기에서 중간코드 생성기로 넘어간 양식이 뭔지 서술해라.
A24.
스캐너 -> 파셔 : 토큰들의 흐름
파셔 -> 시맨틱 분석기 : parser tree
시맨틱 분석기 -> 중간코드 생성기 : 추상화된 문맥 트리(간략화된 parser tree)
Q25.
컴파일러의 프론트엔드와 백엔드를 나누는 기준은 무엇인가?
A25.
프론트엔드는 소스프로그램이 무슨 의미를 가지고 있는지 알아내는 역할이고
백엔드는 정해진 목표 프로그램으로 구현하는 역할을 맡고있다.
Q28.
정적 시맨틱과 동적 시맨틱의 차이점을 서술해라.
A28.
컴파일 과정중 시맨틱 분석을 컴파일 시점 / 실행 시점 에 하냐에 따라 나뉜다.
[Exercise]
1.1
컴퓨터 프로그램에서 에러는 언제 에러가 감지되었는지에 따라 구분된다.
만약 컴파일 시점에 감지되었다면, 컴파일러의 어떤 부분에서 감지했는가.
선호하는 명령형 언어를 사용해, 아래 주어진 각 경우에 해당되는 예시를 제공해라.
(a) 어휘 오류, scanner로 감지
(b) 문맥 오류, parser로 감지
(c) 정적 시맨틱 오류, 시맨틱 분석으로 감지
(d) 동적 시맨틱 오류, 컴파일러의 코드 생성기에 의해 감지
A1.1
(a) scanner는 공백제거, 주석제거, 코드 한글자식 분석해 토큰화 하는 작업을 수행.
1
|
int 1number; # 사용 불가능한 식별자
|
cs |
(b) parser는 토큰들을 트리화 시켜 문맥적 오류 검사 수행.
1
|
int number # 문맥적 오류(;없음)
|
cs |
(c) 정적 시맨틱 오류 : 컴파일 시점에 변수, 문법 검증(논리적 오류 검사)
1
|
int k = 10.201; # 변수 오류
|
cs |
(d) 동적 시맨틱 오류 : 실행 시점에 변수 초기화, 포인터 유효값, overflow 검증(논리적 오류 검사)
C와 Fortran과 같은 명령형 언어들은 일반적으로 컴파일되고,
실행 시점까지 대부분의 사항들이 해결되지 않는 스크립팅 언어들은 인터프리트된다.
그러면 인터프리트는 단순히 컴파일이 불가능할 때 “해야 할 일”인가, 아니면
컴파일러가 있어도 인터프리트 함으로써 얻을수 있는 이득이 있는가?
A1.3
인터프리터는 소스 코드를 한줄씩 읽어 바로바로 통역해 들어온 input을 처리하는 특성을 가지고 있다.
따라서, 인터프리터는 언어의 유연함과 더 나은 에러 진단을 하는 장점이 있어,
많은사람들에게 선호된다.
그리고, 오늘날의 대부분 언어들이 이 두가지를 혼합해 사용하기도 한다.
예를 들어 java같은 경우에,
자바에서 컴파일러를 통해 소스코드를 중간코드를 바꾸고,
처음 실행할때 자주 사용하는 코드들을 인터프리터를 통해 캐싱한다.
이후 JIT 컴파일러를 통해 캐싱된 코드를 가져와 써서 더 빠르게 실행한다.
이 방법으로 자바 실행 시간을 대폭 감소 시켰다.
'[프로그래밍 언어론] > 언어론 연습문제' 카테고리의 다른 글
프로그래밍 언어론 7강 연습문제 (0) | 2019.12.15 |
---|---|
프로그래밍 언어론 6강 연습문제 (0) | 2019.12.07 |
프로그래밍 언어론 3강 연습문제 (0) | 2019.11.01 |