Compile Process
프로그래머가 작성한 코드는 컴파일러에 의해 어셈블리어, 기계어로 변환됩니다.
그 과정은 크게 다음과 같습니다.
소스 코드를 Scanner(Lexical Analyzer)를 통해 Token으로 변환 하고, Parser(Syntax Analyzer)를 통해 Abstract Syntax Tree(추상 구문 트리)를 생성합니다. 해당 추상 구문 트리를 Semantic Analyzer를 통해 Annotated Tree를 생성하고 Source Code Optimizer를 통해 최적화하여 Intermediate Code(중간 코드)를 만들어냅니다. 그리고 Code Generator는 생성된 중간 코드로 Target Code(Assembly Code)를 생성해냅니다.
위 과정을 천천히 분석해보겠습니다.
Lexical Analyzer
Lexical Analyzer(어휘 분석기)는 프로그래머가 작성한 Source Code를 입력으로 받고, 그 코드들을 토큰으로 전부 변환합니다. 이 과정에서 Regular Expression, Finite Automata의 원리를 이용합니다.
ex)
Input =
C source Code
arr[i] = 4 + 2;
Output =
token = ID, lexeme = "arr"
token = LBRACKET, lexeme = "["
token = ID, lexeme = "i"
token = RBRACKET, lexeme = "]"
token = ASSIGN, lexeme = "="
token = NUM, lexeme = "4"
token = PLUS, lexeme = "+"
token = NUM, lexeme = "2"
token = SEMICOLON, lexeme = ";"
Syntax Analyzer
Syntax Analyzer(구문 분석기)는 Lexical Analyzer에서 생성된 Token Stream을 통해 Abstract Syntax Tree를 생성합니다.
이 과정에서 CFG와 PDA의 원리를 이용하여 Parsing 합니다. 따라서, 이 과정에서 해당 언어의 문법에 승인되는지, 모호성이 있는지 검사합니다.
프로그램 실행 시 Syntax Error가 발생하면 대부분 Syntax Analyzer 과정에서 문제가 생겼다고 보시면 됩니다.
Semantic Analyzer
Semantic Analyzer(의미 분석기)는 프로그래머가 작성한 코드가 의미론적으로 적합한지 검사하고 EBNF로 표기 가능한지 검사합니다. 이 과정에서 Attribute Grammar (속성 문법) 원리가 적용됩니다. 이 과정을 거쳐서 Annotated Tree를 생성합니다.
Attribute Grammar는 Syntax Analyzer를 통해 생성된 AST에 Semantic Attribute를 붙여줍니다.
ex) int a = "cbf" + 4; 라는 구문은 각각 토큰으로 떼어 보면 문법상 문제가 없지만, 정수형 변수의 의미를 가진 a에 문자열의 의미를 가진 "cbf"와 정수인 4의 합이 저장되는 것은 의미상 적합하지 않습니다.
Code Generator
Source Code Optimizer를 통해 최적화되어 생성된 Intermediate Code를 컴퓨터가 알아들을 수 있게 끔 Assembly Code로 변환합니다. ( 기계마다 사용하는 어셈블리어가 다르기 때문에( NASM, MASM 등등, Little endian, Big endian 차이 ), 기계와 독립적인 코드가 필요하기 때문에 Intermediate Code를 생성하고, 그것을 각 기계에 맞게 끔 변경)