01. 编译过程概述
编译器将源代码转换为可执行程序的过程。
编译的四个阶段:
- 词法分析:将字符流转换为记号流
- 语法分析:将记号流转换为抽象语法树(AST)
- 语义分析:检查类型、作用域等
- 代码生成:生成目标代码
text
# 编译过程示意
源代码 (Source Code)
|
v
[词法分析] (Lexical Analysis)
|
v
记号流 (Token Stream)
|
v
[语法分析] (Syntax Analysis)
|
v
抽象语法树 (AST)
|
v
[语义分析] (Semantic Analysis)
|
v
标注的 AST (Annotated AST)
|
v
[中间代码生成] (IR Generation)
|
v
中间表示 (IR)
|
v
[优化] (Optimization)
|
v
优化的 IR
|
v
[目标代码生成] (Code Generation)
|
v
目标代码 (Object Code)
|
v
[链接] (Linking)
|
v
可执行程序
# 示例:编译 C 程序
# gcc -O2 -o program main.c
# 分步执行
gcc -E main.c -o main.i # 预处理
gcc -S main.i -o main.s # 编译为汇编
gcc -c main.s -o main.o # 汇编为目标文件
gcc main.o -o program # 链接生成可执行文件02. 词法分析
词法分析器(Lexer)将源代码字符流转换为记号(Token)流。
记号类型:
- 关键字:if、else、while、int
- 标识符:变量名、函数名
- 字面量:数字、字符串
- 运算符:+、-、*、/、=
- 分隔符:;、(、)、{、}
python
# 词法分析器示例(Python 实现)
import re
# 定义记号类型
TOKEN_TYPES = [
('NUMBER', r'\d+'),
('IDENT', r'[a-zA-Z_][a-zA-Z0-9_]*'),
('PLUS', r'\+'),
('MINUS', r'-'),
('MULTIPLY', r'\*'),
('DIVIDE', r'/'),
('ASSIGN', r'='),
('LPAREN', r'\('),
('RPAREN', r'\)'),
('LBRACE', r'\{'),
('RBRACE', r'\}'),
('SEMICOLON', r';'),
('WHITESPACE', r'\s+'), # 忽略空白
]
# 关键字
KEYWORDS = {'if', 'else', 'while', 'int', 'return', 'void'}
def tokenize(code):
tokens = []
pos = 0
while pos < len(code):
match = None
for token_type, pattern in TOKEN_TYPES:
regex = re.compile(pattern)
match = regex.match(code, pos)
if match:
value = match.group()
if token_type == 'WHITESPACE':
pos = match.end()
break
elif token_type == 'IDENT' and value in KEYWORDS:
token_type = 'KEYWORD'
tokens.append((token_type, value))
pos = match.end()
break
if not match:
raise SyntaxError(f'Unexpected character at position {pos}')
return tokens
# 测试
code = 'int x = 10 + 20;'
tokens = tokenize(code)
for token_type, value in tokens:
print(f'{token_type}: {value}')03. 语法分析
语法分析器(Parser)将记号流转换为抽象语法树(AST)。
语法分析方法:
- 自顶向下:递归下降、LL 解析
- 自底向上:LR 解析、LALR 解析
- 混合方法:PEG 解析
python
# 简单的递归下降解析器
class Parser:
def __init__(self, tokens):
self.tokens = tokens
self.pos = 0
def current_token(self):
if self.pos < len(self.tokens):
return self.tokens[self.pos]
return None
def eat(self, expected_type):
token = self.current_token()
if token and token[0] == expected_type:
self.pos += 1
return token
raise SyntaxError(f'Expected {expected_type}, got {token}')
# 表达式解析
def expr(self):
node = self.term()
while self.current_token() and self.current_token()[0] in ('PLUS', 'MINUS'):
op = self.eat(self.current_token()[0])
right = self.term()
node = ('binop', op[1], node, right)
return node
def term(self):
node = self.factor()
while self.current_token() and self.current_token()[0] in ('MULTIPLY', 'DIVIDE'):
op = self.eat(self.current_token()[0])
right = self.factor()
node = ('binop', op[1], node, right)
return node
def factor(self):
token = self.current_token()
if token[0] == 'NUMBER':
self.pos += 1
return ('number', int(token[1]))
elif token[0] == 'IDENT':
self.pos += 1
return ('identifier', token[1])
elif token[0] == 'LPAREN':
self.eat('LPAREN')
node = self.expr()
self.eat('RPAREN')
return node
raise SyntaxError(f'Unexpected token: {token}')
# AST 节点示例
# 表达式: 1 + 2 * 3
# AST: ('binop', '+', ('number', 1), ('binop', '*', ('number', 2), ('number', 3)))知识测验
第 1/4 题正确 0
编译器的四个主要阶段是什么?