🎯 학습 목표와 중점 사항
✅ 이번 슬라이드에서 학습해야 할 내용
- 컴파일러란 무엇인가? (정의와 역할)
- 컴파일러의 입력과 출력
- 컴파일러의 구성 구조(Front-End, Back-End, Intermediate Code)
- 언어 종속(Language-dependent) vs 머신 종속(Machine-dependent)
🔍 중점적으로 공부해야 할 것
- "컴파일러는 어떤 작업을 하는가?" → 언어를 번역하는 자동화 도구라는 큰 그림을 기억할 것.
- 프론트엔드 vs 백엔드 구분 정확히 이해하기
- 중간 코드(IC)의 역할과 왜 분리해서 사용하는지
- 향후 LEX / YACC, IR(Intermediate Representation) 등과 어떻게 연결되는지 상상해볼 것
1️⃣ 번역기와 컴파일러
📌 컴파일러란?
"A compiler is a computer program which translates programs written in a particular high-level programming language into executable code for a specific target computer."
💡 쉽게 풀이하면?
- 고급 언어(High-level language) → 기계어(Object code)로 바꿔주는 번역기
- 예시: C 컴파일러(SPARC용)
→ C 소스 코드를 받아서 SPARC에서 실행 가능한 기계어를 생성
🔁 입력과 출력 흐름
[Source Programs]
↓
[Compiler]
↓
[Object Programs]
- 입력: C, Java 등 고급언어
- 출력: 어셈블리 언어, 머신 코드
2️⃣ Compiler Structure
📌 구성요소: Front-End / Intermediate Code / Back-End
[Source Program]
↓
┌───────────────┐
│ Front-End │ ← 언어 종속(Language Dependent)
│ ↓ │
│ Intermediate │
│ Code │ ← 언어와 머신 사이의 중간 단계
│ ↓ │
│ Back-End │ ← 머신 종속(Machine Dependent)
└───────────────┘
↓
[Object Program]
🔍 구성요소 설명
구분 |
설명 |
특징 |
Front-End |
- 소스 코드 분석 (어휘 분석, 구문 분석, 의미 분석) - 중간 코드 생성 |
언어에 종속 |
Intermediate Code (IC) |
- 플랫폼 독립적인 중간 표현 - 다양한 백엔드와 조합 가능 |
중간 표현이라 재사용 가능 |
Back-End |
- IC를 기반으로 최적화 및 기계어 코드 생성 |
기계에 종속 |
🧠 포인트 기억하기
- 같은 프론트엔드 + 다른 백엔드 = 여러 플랫폼으로 확장 가능
(예: C 컴파일러를 ARM에도, x86에도 쓰고 싶을 때!)
✅ 공부 팁 요약
학습 포인트 |
기억해야 할 것 |
컴파일러란? |
고급 언어 → 기계어로 바꾸는 번역기 |
입력-출력 구조 |
Source → Compiler → Object |
구조 분리 이유 |
언어와 머신을 각각 독립적으로 다루기 위함 |
IC의 역할 |
재사용성과 확장성을 위한 중간 표현 |
Front vs Back |
Front는 "언어 중심", Back은 "기계 중심" |
개념 |
핵심 키워드 |
반드시 이해해야 할 것 |
Cross Compiler |
타겟 머신 다름 |
컴파일 위치와 실행 위치가 다른 경우 |
Interpreter |
실행 즉시 변환 |
번역 없이 바로 실행. 결과 즉시 출력 |
Preprocessor |
전처리 |
컴파일 전 텍스트 수준 변환 수행 |
1️⃣ Cross Compiler (교차 컴파일러)
✅ 정의
"A cross-compiler is a program which is to run on machine A and produce target code for another machine B."
- 실행 환경과 목적 코드의 플랫폼이 다름
- 즉, 컴파일은 A 컴퓨터에서, 생성된 코드는 B 컴퓨터에서 실행
✅ 예시
- 스마트폰용 프로그램을 PC에서 컴파일 → 스마트폰에서 실행
- 임베디드 시스템 개발 시 자주 사용
✅ 구조 요약
[Source Program]
↓
[Compiler on A machine]
↓
[Target Code for machine B]
🔍 특징
- Front-End: 언어 종속
- Back-End: 기계(B 시스템) 종속
📌 용도
- downloading: 생성된 바이너리 파일을 B에 넣고 실행
- bootstrapping: 새로운 플랫폼용 컴파일러를 그 플랫폼에서 실행하기 위해 미리 만들어 놓는 기술
2️⃣ Interpreter (인터프리터)
✅ 정의
"An interpreter transforms a program directly into a sequence of machine actions and produces the results of the program."
✅ 구조 요약
[Source Program]
↓
[Interpreter]
↓ ↓
실행 결과 출력
🔍 특징
- 프로그램 전체를 번역하지 않고 한 줄씩 실행
- 대표 언어: Python, JavaScript
- 컴파일러에 비해 느리지만, 디버깅과 교육용에 적합
📌 용도 비교
항목 |
Compiler |
Interpreter |
목적 |
실제 운영 시스템 |
교육, 개발, 실험 |
처리 방식 |
전체 번역 후 실행 |
즉시 실행 |
출력물 |
Object 코드 생성 |
없음 (바로 실행됨) |
3️⃣ Preprocessor (전처리기)
✅ 정의
컴파일 전에 소스코드를 가공(확장)하여 컴파일러에 전달
✅ 구조 요약
[Source Program]
↓
[Preprocessor]
↓
[Extended Source Program]
↓
[Translator or Compiler]
↓
[Target Code]
🔍 주요 기능
- 매크로 치환:
#define
등
- 조건부 컴파일:
#ifdef
, #ifndef
등
- 파일 포함:
#include
등
✅ 대표 언어
- C 언어는 전처리기를 강하게 사용하는 대표적인 언어
✅ 학습 정리 요약
구분 |
설명 |
핵심 포인트 |
Cross Compiler |
실행 환경 ≠ 실행 대상 |
타겟 플랫폼용 코드 생성 |
Interpreter |
바로 실행 |
교육, 실험, 디버깅에 적합 |
Preprocessor |
컴파일 전 텍스트 조작 |
조건부 컴파일, 매크로 처리 |
구분 |
개념 |
학습 포인트 |
1 |
컴파일러 전체 구조 |
Front-End vs Back-End 구분, 각 단계의 역할 |
2 |
Lexical Analyzer (어휘 분석기) |
토큰 생성, 정규 표현식 기반 |
3 |
Syntax Analyzer (구문 분석기) |
문장 구조 분석, 구문 트리(파스트리) 생성 |
1️⃣ 컴파일러 구조 (General Compiler Structure)
📌 전체 흐름
[Source Code]
↓
Lexical Analyzer ⇒ Token
↓
Syntax Analyzer ⇒ Parse Tree
↓
Intermediate Code Generator ⇒ IR
↓
Code Optimizer ⇒ Optimized IR
↓
Target Code Generator ⇒ Object Code
✅ 주요 단계 요약
영역 |
구성 요소 |
주요 역할 |
종속성 |
Front-End |
Lexical, Syntax, Intermediate |
- 문법 오류 탐지 - 중간 코드 생성 |
언어 종속 |
Back-End |
Optimizer, Target Code Gen. |
- 최적화 - 기계어 변환 |
하드웨어 종속 |
2️⃣ Lexical Analyzer (어휘 분석기 / 스캐너)
✅ 역할
- Source Code → Token들의 시퀀스로 분리
- 각 토큰은 정수값 등으로 인코딩되어 내부에서 다루기 쉽게 됨
🔍 구성 흐름
소스 코드 if (a > 10)
↓
토큰: if ( a > 10 )
번호: 32 7 4 25 5 8
🧠 기억할 포인트
- 정규 표현식을 기반으로 구성
- 토큰 단위로 의미를 부여 (키워드, 식별자, 상수, 기호 등)
- 자동화 도구: LEX로 생성 가능
3️⃣ Syntax Analyzer (구문 분석기 / 파서)
✅ 역할
- 토큰들의 나열 → 문법 구조로 해석
- 구문 오류를 탐지하거나, 구문 트리(Parse Tree) 생성
🔍 출력 구조
ex) if (a > 10) a = 1;
↓
if
/ \
> =
/ \ / \
a 10 a 1
🧠 기억할 포인트
- 문법(Grammar)을 기반으로 파싱 수행
- 출력 형태: Parse Tree, Abstract Syntax Tree(AST)
- 자동화 도구: YACC로 생성 가능
- 구문 분석은 형식 언어 이론과 직결 (CFG 기반)
✅ 학습 요약 포인트
항목 |
키워드 |
핵심 정리 |
컴파일러 구조 |
Front-End / Back-End |
언어 종속과 기계 종속으로 나뉨 |
어휘 분석기 |
Token, 정규 표현식, LEX |
문자열 → 단어로 분리 |
구문 분석기 |
Parse Tree, 문맥 자유 문법(CFG), YACC |
문장 구조 분석 및 트리 생성 |
파트 |
학습 핵심 |
Intermediate Code Generator |
트리 기반 의미 분석, U-code 생성 원리 |
Code Optimizer |
최적화 목적과 기법 구분 (Local/Global) |
Target Code Generator |
기계어 생성 과정, 레지스터/메모리 관리 |
Error Recovery |
오류의 종류와 대응 전략 (Recovery vs Repair) |
3️⃣ Intermediate Code Generator
✅ 핵심 역할
- Semantic Analysis 포함: 타입 검사(Type Checking)
- 파싱 트리를 DFS(깊이 우선 탐색) 방식으로 읽고 중간 코드 생성
- 변수 주소 참조 방식: (base, offset) 형태
🔍 예시 해석
a = b + 1;
⇒ 트리 구조:
=
/ \
a +
/ \
b 1
⇒ U-Code 생성:
lod 1 2 ← b의 값 로드 (base=1, offset=2)
ldc 1 ← 상수 1
add ← 더하기
str 1 1 ← 결과를 a에 저장 (base=1, offset=1)
🧠 핵심 포인트
- 중간 코드는 플랫폼 독립적인 표현
- 향후 백엔드와 분리 가능한 핵심 자료
4️⃣ Code Optimizer
✅ 의미
- 선택적(optional) 단계지만, 실행 시간/공간 최적화 목적
- 주 목표:
✅ 최적화 기준
- 프로그램 의미 보존
- 평균 실행 속도 향상
- 최적화에 쓴 비용보다 이득이 클 것
✅ 최적화 기법
📌 Local Optimization
- 한 basic block 내에서 수행 (제어 흐름 없음)
- 대표 기법:
- Constant folding:
2 + 3
→ 5
- Redundant load/store 제거
- Algebraic simplification:
x * 1
→ x
- Strength reduction:
x * 2
→ x + x
📌 Global Optimization
- 제어 흐름을 포함한 전체 범위에서 수행
- 대표 기법:
- Common subexpression 제거
- Loop invariant 이동
- Unreachable code 제거
5️⃣ Target Code Generator
✅ 역할
- 중간 코드(IC 또는 최적화된 IC) → 기계어(Target Code)로 변환
✅ 주요 작업
- 명령어 선택 및 생성 (Instruction selection)
- 레지스터 관리
- 스토리지 할당 (변수 위치)
- 기계 종속적 최적화 수행
🧠 대표 도구
6️⃣ Error Recovery
✅ 개념
용어 |
의미 |
Error recovery |
에러가 다음 문장에 영향을 주지 않도록 복구 |
Error repair |
에러가 생겼을 때 직접 수정 시도 |
✅ Error 처리 구성 요소
- Detection (감지)
- Recovery (복구)
- Reporting (보고)
- Repair (수정)
✅ 에러의 종류
종류 |
예시 |
Syntax Error |
괄호 누락, 문장 종료 누락 등 |
Semantic Error |
타입 불일치, 정의되지 않은 변수 등 |
Run-time Error |
0으로 나누기, 포인터 오류 등 |
✅ 전체 흐름 요약
단계 |
주요 작업 |
핵심 키워드 |
Intermediate Code Generator |
의미 분석 + 중간 코드 |
트리 기반, (base, offset) |
Code Optimizer |
코드 효율 향상 |
Local vs Global, 의미 보존 |
Target Code Generator |
기계어 생성 |
명령어 선택, 레지스터 |
Error Recovery |
오류 감지 및 복구 |
Recovery vs Repair, Syntax/Semantic |
🎯 학습 목표 및 중점 사항
주제 |
학습 포인트 |
컴파일러 자동화 도구의 필요성 |
왜 compiler-compiler가 필요한가? |
주요 도구 종류 |
LEX, YACC, PGS, 자동 코드 생성기 |
입력/출력 구조 |
각 도구의 입력 자료 구조와 출력 산출물 이해 |
생성 대상 |
어휘 분석기, 구문 분석기, 타겟 코드 생성기 |
용어/형식 |
정규표현식, BNF/EBNF, AST 등과 연계 이해 |
1️⃣ 컴파일러 자동화 도구의 필요성
✅ 문제 상황
- N개의 언어 × M개의 머신 환경 → N × M개의 컴파일러 필요
- 수작업으로 만들기에는 확장성, 유지보수 측면에서 한계
✅ 해결책
- Compiler Generating Tool (Compiler-Compiler) 도입
- 입력: 언어 기술서 + 머신 기술서
- 출력: 해당 언어를 해당 머신에서 실행 가능한 컴파일러
2️⃣ Compiler-Compiler 모델
✅ 구성
[Language Description] + [Machine Description]
↓
Compiler-Compiler
↓
[해당 언어 → 해당 머신용 Compiler 생성]
✅ 사용 이론 및 도구
- Language: 문법 이론 (Grammar, CFG, BNF/EBNF)
- Machine: HDL, ISP, ISPS 등
- 대표 예시: YACC, LEX, PGS, LLVM
3️⃣ LEX (Lexical Analyzer Generator)
✅ 개요
- 정규표현식 기반 어휘 분석기 자동 생성 도구
- 입력: Regular Expression + Action Code
- 출력: Token Stream을 출력하는
lex.yy.c
✅ 작동 구조
[정규표현식 + 액션]
↓
LEX
↓
Lexical Analyzer (.c 파일)
↓
Token Stream 생성
4️⃣ PGS (Parser Generator System)
✅ 개요
- CFG(문맥 자유 문법) 기반 구문 분석기 자동 생성
- Grammar → Parsing Table → Parser
📌 예시 시스템
이름 |
작성자 |
특징 |
Stanford PGS |
John Hennessy |
AST 생성 중심 |
Wisconsin PGS |
C.N. Fisher |
Error Recovery 기능 강조 |
YACC |
UNIX 환경, C 기반 |
LEX와 연계 사용, Action Code 포함 가능 |
5️⃣ YACC (Yet Another Compiler Compiler)
✅ 구성 흐름
[정규표현식 + Action] → LEX → lex.yy.c (어휘 분석)
[문법 규칙 + Action] → YACC → y.tab.c (구문 분석)
lex.yy.c + y.tab.c → 실행 결과 생성
- LEX와 연동하여 전체 분석기 구축 가능
- UNIX 환경에서 실무용으로 가장 널리 쓰임
6️⃣ 자동 코드 생성기 (Automatic Code Generator)
✅ 역할
- 중간 코드(IC) → 기계어(Target Code) 자동 생성
✅ 구성
[Machine Description + Pattern]
↓
Code Generator Generator
↓
[Table 생성]
↓
Code Generator 실행
↓
Target Code 생성
✅ 핵심 구성 요소
- Table-Driven 방식: 각 명령어 생성 패턴 정의
- Driver Routine: 생성 테이블을 활용해 실제 코드 생성
- 도구 예시: CGA (Code Generating Algorithm)
✅ 전체 요약표
도구 |
생성 대상 |
기반 이론 |
특징 |
LEX |
Lexical Analyzer |
정규표현식 |
토큰 추출, lex.yy.c 생성 |
YACC |
Syntax Analyzer |
문맥 자유 문법 (CFG) |
파싱 테이블 및 트리, y.tab.c |
PGS |
Parser Generator |
CFG, AST |
스탠포드/위스콘신 등 버전 존재 |
Code Generator Generator |
Target Code Generator |
패턴 매칭, Table 기반 |
백엔드 자동화 목적 |
📌 학습 팁
- LEX는 정규 표현식과 직접적으로 연결, Regular Language 기반
- YACC는 문맥 자유 문법(CFG) 기반, 파싱 알고리즘 학습과 연계
- 자동 생성기의 목적은 결국 확장성과 유지보수성 향상
- 이후 LLVM 같은 현대 시스템이 이 구조를 얼마나 발전시켰는지 비교하면 좋음
🎯 학습 목표 및 중점 사항
학습 포인트 |
핵심 내용 |
PQCC와 ACK의 구조 차이 |
어떤 식으로 자동화를 구현했는가 |
중간 표현 방식 |
TCOL(PQCC), EM(ACK) 구조 이해 |
자동화 방식 |
Table-driven code generation, Abstract machine 기반 |
활용 배경 |
다양한 언어/머신 조합 대응을 위한 확장성 |
공통점 vs 차이점 |
공통 목표(컴파일러 자동화) + 구현 철학의 차이 |
1️⃣ PQCC (Production Quality Compiler Compiler)
✅ 개요
- W.A. Wulf (Carnegie-Mellon Univ.)
- 입력: 언어 기술(Language Description) + 머신 기술(Machine Description)
- 출력: PQC + Table → 최종 Object Code 생성
✅ 구조 (슬라이드 Page 28)
[Source Program]
↓
Front-End → TCOL 생성
↓
PQC + Table ← PQCC에서 생성
↓
[Object Code]
✅ 핵심 요소
- TCOL (Tree Code Object Language): 트리 기반 중간 표현, 문법+의미 정보 포함
- Pattern Matching 기반으로 코드 생성
- TCOL 순회 방식으로 타겟 코드 생성 (트리 워킹 기반)
2️⃣ ACK (Amsterdam Compiler Kit)
✅ 개요
- Andrew Tanenbaum (Vrije 대학)
- Front-End와 Back-End를 분리하고, EM이라는 추상 기계어(Abstract Machine Code)를 중간 표현으로 사용
✅ 구조 (슬라이드 Page 29)
[Source Program] (e.g. FORTRAN, PASCAL, C, ...)
↓
Front-End
↓ EM (중간 코드)
Back-End → [Object Code] (Intel, Motorola, Zilog, SPARC 등)
↓
[Interpreter] → 실행 결과
✅ 특징
- UNCOL(Universal Intermediate Language) 개념 기반
- Portable Compiler 제작에 유리
- EM 코드는 필요 시 해석기로 실행 가능
✅ PQCC vs ACK 비교표
항목 |
PQCC |
ACK |
설계자 |
W.A. Wulf |
Andrew Tanenbaum |
중간 표현 |
TCOL (트리 기반) |
EM (Abstract Machine Code) |
구조 |
Table 기반 자동 생성기 |
UNCOL 철학 기반 추상 머신 |
강점 |
정밀한 패턴 매칭, table 기반 생성 최적화 |
이식성(portability), 다양한 기계 대응 |
실행 방식 |
코드 생성 중심 |
해석기 통한 실행도 가능 |
🧠 학습 팁
- TCOL = 트리 구조 기반 표현 → 파싱 트리 기반의 연산 최적화에 강함
- EM = 추상 머신 코드 → 다양한 실제 머신으로의 매핑 유연
- 둘 다 결국 N개의 언어 × M개의 머신을 효과적으로 커버하려는 자동화 시도
- 현대의 LLVM이 이 철학을 잇는 현대 시스템 중 하나!