부제: Automatic Translation
12월 2일, 14주차 1강
* 개인 공부를 위해 정리한 것입니다. 정확한 내용은 꼭 본인이 공부하는 교재를 참고하시기 바랍니다.

컴파일러 디자인의 복잡도를 줄이기 위해 IR을 사용한다

- x=0, t1=0
- x에 t1 값을 할당
- t3에 x값을 할당
- t4에 1을 할당
- t2에 t3과 t4의 합을 할당
- t2를 write한 후 정지

- 초기화, sum=0, i=0
- 2:SKIP: 반복문 시작
- 조건 검사
- t4에 i값 복사
- t5에 10 복사
- t3에 t4<t5 결과 저장
- 조건이 거짓이면 3으로 점프
- 반복문 본문
- sum=sum+i를 계산해 sum에 저장
- i++ 연산을 수행
- 반복문 시작으로 돌아가기 위해 goto2
- 3:SKIP: 반복문 종료
- 출력 및 종료
- sum값을 출력하고 HALT

- 소스 언어과 타겟언어 사이의 자동변환 절차를 정의
- S: 변환하려는 소스 언어로 작성된 프로그램, T: 변환 결과로 얻어진 타겟언어로 작성된 프로그램
- 변환 절차를 통해 소스 프로그램 S를 타겟 프로그램 T로 변환
- 변환된 프로그램 T는 의미적으로 동등해야 함. 프로그램 S와 T는 같은 동작을 수행해야 함

- 프로그래밍 언어의 정의
- 구문 syntax: 프로그램의 구조를 정의하는 규칙의 집합
- 문법을 이해할 수 잇으며, 올바른 프로그램이 어떻게 작성되어야 하는지 명시
- concrete syntax: 프로그램의 완전한 구조를 정의. 사람이 읽고 작성할 때 사용하는 실제 구문
- 조건문 if(b) {c1} else {c2}처럼 완전한 문법. 프로그램을 작성하거나, 코드를 읽고 이해하는 데 사용
- abstract syntax: 추상적 구문, 프로그램의 핵심 구조만 정의. 구체적인 문법 요소 생략
- if b c1 c2처럼 간소화된 형태. 프로그램을 자동 생성, 분석, 최적화하는데 사용. 컴파일러 등에서 사용
- 의미 Semantics: 프로그램이 실행될 때의 의미를 정의하는 규칙의 집합
- 프로그램의 동작을 설명
- 특정 조건에서 실행 흐름이 어떻게 변화하는지 명시
- 구문 syntax: 프로그램의 구조를 정의하는 규칙의 집합



구체적인 문법과 추상적인 문법을 비교해보면 정말 최소화해서 설명하고 있음을 알 수 있음

- +는 서로소 합집합을 나타냄. 두 개의 겹치지 않는 집합을 더함

- inference rule
- 만약 A가 참이라면, B도 참이다. A: 가정, B: 결론
- 단순 가정: A가 참이면, B를 도출
- 공리 Axiom: 가정 없이 B가 참
- 다중 가정: A와 B가 둘 다 참이면 C가 참.
- Big-Step Operational Semantics
- 프로그램 실행의 전체 결과를 기반으로 의미를 정의
- 프로그램의 입력과 출력 상태를 바로 연결하여 설명



- 조건이 참일 때
- 메모리 상태 M에서 표현식 e를 평가해 값 n을 얻음
- 조건 확인: n!=0이면 e는 참
- 문장 실행: stmt1을 실행해 새로운 메모리 상태 M1으로 변환
- 결론: 전체 조건문은 M1 상태를 결과로 가짐
- 조건이 거짓일 때
- 메모리 상태 M에서 표현식 e를 형가해 값 0을 얻음
- 조건 확인: e=0이면 e는 거짓
- 문장 실행: stmt2를 실행해 새로운 메모리 상태 M1으로 전환
- 결론: 전체 조건문은 M1 상태를 결과로 가짐
- 추론 규칙의 기본 구조: 메모리 상태 M에서 문장 stmt를 실행했을 때 새로운 메모리 상태 M'을 얻는다
- 선언 decl: 선언을 수행하면 M'로 전환
- 왼쪽 값: lv을 평가해 위치 l을 얻음
- 표현식: 표현식을 평가해 값 v를 얻음

- 맨 위부터 순서대로
- declaration
- 변수 선언: 변수 x 선언 시, 현재 메모리 상태 M에 x를 0으로 초기화해 추가
- 배열 선언: 배열 x 선언하고, 크기를 표현식 e로 평가해 n을 얻음. 새로운 메모리 공간을 n만큼 할당하고 0으로 초기화
- statement 실행
- 할당: lv 왼쪽값을 평가해 위치 l을 갖고 표현식 e를 평가해 값 v를 얻는다. 메모리 M의 l 위치에 v를 저장한다
- 조건문
- 참인 경우: 조건 e를 평가해 n을 얻고, n!=0이면 stmt1을 실행해 M1으로 전환
- 거짓인 경우: 조건 e를 평가해 0이면 stmt2를 실행해 M1으로 전환
- 반복문
- 참인 경우: 조건 e를 평가해 참이면 stmt 실행, 다시 조건을 확인해 반복
- 거짓인 경우: 조건 e가 거짓이면 실행 종료
- 복합문: 첫 번째 문장을 실행해 M1 상태로 전환 후, 두 번째 문장을 실행해 최종상태 M2로 전환
- do-while 반복문: 본문 stmt를 먼저 실행한 후, 조건 e를 평가해 참이면 반복
- 읽기: 사용자 입력 값을 변수 x에 저장
- 쓰기: 표현식 e를 평가하고 결과를 출력. 메모리 M 상태는 변하지 않음

- lv: l value 왼쪽 값
- 변수: 변수 x는 메모리에서 변수 이름과 동일한 위치를 가리킴
- 배열:
- 배열 x[e]의 인덱스 e를 평가해 n1을 얻음
- x가 메모리 M에서 (a,n2)로 매핑된 배열임을 확인함
- n1이 배열 범위 내에 있는지 확인함
- 배열의 주소 a와 인덱스 n1을 리턴함
- expression: 왼쪽 값 lv를 평가해 위치 l을 찾음. 메모리 M에서 해당 위치의 값을 반환함
- 덧셈: 두 표현식 e1과 e2를 평가해 각각 n1,n2를 얻고, 두 값을 더함.
- 음수: 표현식 e를 평가해 음수를 계산
- 같음: 두 표현식 결과가 같으면 1(참)을 반환. 다름: 두 표현식 결과가 다르면 0(거짓)을 반환
- 크다: e1이 e2보다 크면 1을 반환
- 논리 합: e1 또는 e2 중 하나라도 참이면 1을 반환
- 논리곱: e1과 e2 모두 참이면 1을 반환
- 논리 부정: e가 거짓이면 참으로 반환

- skip: 아무것도 하지 않는 명령어, nop 역할
- 메모리 할당: alloc, 크기 n만큼 메모리 할당하고, 시작 주소를 변수 x에 저장
- 산술 연산: x=y bop z, x=y bop n, y와 z의 값을 이항 연산자(bop)로 계산해 x에 저장
- 단항 연산: x=uop y, 변수 y에 단항 연산자 uop 적용해 결과 x에 저장
- 변수 복사 및 상수 할당: x=y, x=n, x에 변수 y의 값 또는 상수 n 복사
- 점프: goto L
- 조건부 점프: if x goto L, if False x goto L
- 배열 접근: x=y[i], x[i]=y
- 입출력: read x, write x, 사용자 입력 값을 x에 저장하거나, x의 값을 출력

- 메모리 상태 = 주소(특정 메모리 위치)와 값의 매핑
- 주소: 일반 변수 이름+메모리 주소x주소에서 상대적 위치
- 값: 정수형 값+배열이나 동적 메모리의 시작 주소x해당 메모리 블록의 크기
- 메모리 주소
- 오프셋: 메모리 주소에서 상대적인 위치
- 크기: 메모리 블록의 크기

- skip: 메모리 상태 M은 변하지 않음
- alloc
- n 크기의 메모리 블록이 아직 할당되지 않은 경우에만 수행 가능.
- 새로운 주소 l에 크기 s의 블록 할당, 블록 초기값은 모두 0으로 설정. x는 블록의 시작 주소와 크기 가리킴
- 산술 및 논리 연산
- bop: 이항연산, y와 z의 값을 계산해 x에 저장. (덧셈, 곱셈, 크기 비교 등)
- uop: 단항 연산, 음수 변환, 논리 부정 등
- 변수 복사 및 상수 할당: y의 값을 x에 복사하거나 상수 n을 x에 저장
- 점프 명령: 무조건 점프 - 지정된 라벨 L로 이동, 조건부 점프 - x가 참이면 L로 점프, 거짓이면 다음 명령으로 진행
- 배열 접근:
- 읽기- y의 i번째 요소를 읽어 x에 저장. i는 유효 범위 내에 있어야 함
- 쓰기-x[i] 위치에 y값 저장, i가 유효한 범위 내에 있어야 함.
- 입출력:
- 읽기: 사용자로부터 입력값을 읽어 x에 저장. 출력: x의 값을 출력

- 첫 번째 명령 설정: 프로그램의 첫 번째 명령어를 instr로 설정. 프로그램은 항상 첫 번째 명령어부터 실행 시작
- 초기 메모리 상태 설정: 초기 메모리 상태 M을 빈 매핑으로 설정. M=[]은 메모리 공간 초기화. 변수에 아무 값도 할당x
- 반복수행
- 현재 명령어 instr이 HALT라면 프로그램 실행 종료
- 메모리 상태 업데이트, 현재 명령어 instr에 따라 메모리 상태 M' 계산. 메모리 상태 업데이트
- 다음 실행할 명령어 결정. goto L, if x goto L, if False x goto L. L로 점프.
- 그 외의 경우: 프로그램에서 instr 바로 뒤에 있는 명령어로 이동

- 상수 변환: 상수 n을 t라는 새로운 변수에 할당. t는 n의 값 가짐
- 변수 변환: x의 값을 t에 복사. t는 x의 값 가짐.
- 배열 접근 x[e]: e를 t1에 계산, 해당 명령어를 code로 기록. t2에 x[t1] 값을 저장하는 명령어 추가. t2는 x[e]값 가짐
- 덧셈: e1을 t1에 e2를 t2에 계산. t1+t2 결과를 t3에 저장. t3은 e1+e2의 값을 가짐.
- 부호 반전: e를 t1에 계산. -t1의 결과를 t2에 저장. t2는 -e의 값을 가짐.

- 상수 2가 변환되어 임시 변수 t에 저장
- 변수 x의 값이 임시변수 t에 복사
- 상수 1을 t1에 저장. x[t1]의 값을 계산해 t2에 저장. t2는 x[1]의 값 가짐
- 상수 2를 t1에 저장. 상수 3을 t2에 저장. t1과 t2의 합을 t3에 저장.
- 상수 5를 t1에 저장. -t1의 값을 t2에 저장. t2는 -5 값 가짐.
- 변수 x를 t1에 저장. 상수 1을 t2에 저장. t1+t2를 계산해 t3에 저장. 상수 2를 t4에 저장. y[t4] 계산해 t5에 저장. t3+t5를 계산해 t6에 저장.

- 대입 연산 x=e
- 식 e를 trans_e를 사용해 변환. trans_e는 (t1,code1)을 반환
- code1은 e를 계산하는 명령어 목록
- t1에 저장된 결과를 변수 x에 대입하는 명령어 추가
- 배열 대입 연산 x[e1]=e2
- e1과 e2를 각각 trans_e를 사용해 변환
- t1은 배열 인덱스 e1의 결과, t2는 대입할 값 e2의 결과
- [x[t1]]=t2]는 x[t1] 위치에 t2 값을 저장하는 명령어
- 입력 명령: read x 명령은 값을 읽어 x에 저장하는 단일 명령어로 변환
- 출력 명령:
- e를 trans_e를 사용해 변환
- code1은 e를 계산하는 명령어 목록, t1은 계산 결과
- [write t1] 명령어는 t1의 값을 출력

trans_s(if e stmt1 stmt2) =
(* e를 표현식으로 변환하여 결과를 얻는다. *)
let (t1, code1) = trans_e(e) (* t1: e의 결과를 저장할 임시 변수, code1: e를 계산하는 명령어 *)
(* stmt1과 stmt2를 각각 변환하여 명령어 목록을 얻는다. *)
let code_t = trans_s(stmt1) (* code_t: stmt1의 변환된 명령어 *)
let code_f = trans_s(stmt2) (* code_f: stmt2의 변환된 명령어 *)
in
(* e를 평가하는 코드 추가 *)
code1 @
(* 조건 결과에 따라 분기 *)
[if t1 goto lt] @ (* t1이 참이면 lt로 이동 *)
[goto lf] @ (* t1이 거짓이면 lf로 이동 *)
(* stmt1을 실행하기 전 레이블 추가 *)
[(lt, skip)] @ (* lt: stmt1의 시작 지점 *)
code_t @ (* stmt1의 명령어 추가 *)
(* stmt1 실행 후 조건문 끝으로 이동 *)
[goto lx] @ (* 조건문 종료 후 lx로 이동 *)
(* stmt2를 실행하기 전 레이블 추가 *)
[(lf, skip)] @ (* lf: stmt2의 시작 지점 *)
code_f @ (* stmt2의 명령어 추가 *)
(* stmt2 실행 후 조건문 끝으로 이동 *)
[goto lx] @ (* 조건문 종료 후 lx로 이동 *)
(* 조건문 종료 지점 레이블 추가 *)
[(lx, skip)] (* lx: 조건문 끝 *)

trans_s(while e stmt) =
(* 표현식 e를 변환하여 결과를 얻음 *)
let (t1, code1) = trans_e(e) (* t1: e의 결과를 저장하는 임시 변수, code1: e를 평가하는 명령어 *)
(* 본문 stmt를 변환하여 명령어 시퀀스를 얻음 *)
let code_b = trans_s(stmt) (* code_b: stmt의 변환된 명령어 *)
in
(* 루프 시작 지점 레이블 추가 *)
[(le, skip)] @ (* le: while 루프의 조건을 평가하는 시작 지점 *)
code1 @ (* 조건 e를 평가하는 명령어 추가 *)
[ifFalse t1 lx] @ (* 조건이 거짓이면 lx로 이동하여 루프를 종료 *)
code_b @ (* 루프 본문 실행 *)
[goto le] @ (* 본문 실행 후 다시 조건으로 돌아감 *)
[(lx, skip)] (* lx: 루프의 끝 지점 레이블 *)
trans_s(do stmt while e) =
(* do-while 루프는 stmt를 먼저 실행한 후, while 루프의 명령어를 추가 *)
trans_s(stmt) @ trans_s(while e stmt)

(* Declarations *)
trans_d(int x) =
[x = 0] (* 변수 x를 선언하고 초기값 0을 할당 *)
trans_d(int[n] x) =
[x = alloc(n)] (* 크기 n의 배열을 위해 메모리를 할당하고 x에 그 메모리 위치를 저장 *)
(* Blocks *)
trans_b(d1, ..., dn, s1, ..., sm) =
trans_d(d1) @ ... @ trans_d(dn) (* 모든 선언문 d1, ..., dn 변환 *)
@ trans_s(s1) @ ... @ trans_s(sm) (* 모든 명령문 s1, ..., sm 변환 *)

Examples:
1. x = 1 + 2
Translation steps:
t1 = 1; (* 임시 변수 t1에 값 1 저장 *)
t2 = 2; (* 임시 변수 t2에 값 2 저장 *)
x = t1 + t2; (* t1 + t2 계산 후 결과를 x에 저장 *)
2. x[1] = 2
Translation steps:
t1 = 1; (* 임시 변수 t1에 인덱스 값 1 저장 *)
t2 = 2; (* 임시 변수 t2에 값 2 저장 *)
x[t1] = t2; (* t2에 저장된 값을 x[t1]에 저장 *)
3. if (1) x = 1; else x = 2;
Translation steps:
t1 = 1; (* 조건식 1을 평가하고 t1에 저장 *)
if t1 goto l_true; (* t1(조건식)이 참이면 l_true로 이동 *)
goto l_false; (* 그렇지 않으면 l_false로 이동 *)
(l_true: skip); (* 참 분기 시작 레이블 *)
t2 = 1; (* 임시 변수 t2에 값 1 저장 *)
x = t2; (* t2의 값을 x에 저장 *)
goto l_exit; (* 참 분기 실행 후 종료 지점으로 이동 *)
(l_false: skip); (* 거짓 분기 시작 레이블 *)
t3 = 2; (* 임시 변수 t3에 값 2 저장 *)
x = t3; (* t3의 값을 x에 저장 *)
(l_exit: skip); (* 종료 레이블 *)
4. while (x < 10) x++;
Translation steps:
(l_begin: skip); (* 반복문 시작 레이블 *)
t1 = x; (* x의 값을 t1에 로드 *)
t2 = 10; (* 임시 변수 t2에 값 10 저장 *)
t3 = t1 < t2; (* 조건식 x < 10 평가 *)
ifFalse t3 goto l_exit; (* 조건이 거짓이면 l_exit로 이동 *)
t4 = x; (* x의 값을 t4에 로드 *)
t5 = t4 + 1; (* t4를 1 증가 *)
x = t5; (* 증가된 값을 x에 저장 *)
goto l_begin; (* 반복문 시작으로 이동 *)
(l_exit: skip); (* 종료 레이블 *)

'전공 > 프로그래밍 언어 및 컴파일러' 카테고리의 다른 글
Lec16.Optimization (1) - 14주차 2강 (0) | 2024.12.10 |
---|---|
Lec15.lR Translation (2) - 14주차 2강 (0) | 2024.12.10 |
Lec13.Semantic Analysis (4) - 13주차 1강/2강 (0) | 2024.12.09 |
Lec12.Semantic Analysis (3) - 13주차 1강 (0) | 2024.12.09 |
[Lec.Halting] Undecidability, Halting Problem - 11주차 2강 (0) | 2024.12.09 |