中间代码生成实战(三)—— 函数

核心知识点讲解

1. 函数的中间代码表示

函数的中间代码生成涉及多个方面:

  1. 函数声明:声明函数的名称、参数类型和返回类型
  2. 函数定义:定义函数的实现,包括序言(prologue)和尾声(epilogue)
  3. 函数调用:生成调用函数的代码,包括参数传递和返回值处理

2. 栈帧布局

栈帧是函数执行时在栈上分配的内存区域,用于存储:

  1. 返回地址:函数执行完毕后要返回到的地址
  2. 参数:传递给函数的参数
  3. 局部变量:函数内定义的局部变量
  4. 临时变量:计算过程中产生的临时值
  5. 保存的寄存器:函数执行前需要保存的寄存器值

栈帧的典型布局如下:

高地址
┌─────────────────┐
│ 返回地址       │
├─────────────────┤
│ 参数 N          │
│ ...             │
│ 参数 1          │
├─────────────────┤
│ 局部变量 1      │
│ 局部变量 2      │
│ ...             │
│ 临时变量        │
├─────────────────┤
│ 保存的寄存器    │
└─────────────────┘
低地址

3. 参数传递方式

常见的参数传递方式有:

  1. 值传递:将参数的值复制到栈帧中
  2. 引用传递:将参数的地址传递给函数
  3. 寄存器传递:使用寄存器传递参数(适用于少量参数)

4. 函数调用的三地址码生成规则

对于函数调用 result = func(a1, a2, ..., an),生成规则如下:

  1. 计算所有实参的值,将结果存储在临时变量中
  2. 将实参的值传递到栈帧或寄存器中
  3. 生成函数调用指令:call func
  4. 函数执行完毕后,从返回值寄存器或栈中获取返回值
  5. 将返回值存储在 result

5. 函数定义的三地址码生成规则

对于函数定义 type func(p1, p2, ..., pn) { body },生成规则如下:

  1. 序言:保存寄存器,分配栈帧空间
  2. 参数处理:将栈上的参数复制到局部变量
  3. 函数体:生成函数体的三地址码
  4. 返回值处理:将返回值存储到指定位置
  5. 尾声:恢复寄存器,释放栈帧空间,返回

实用案例分析

案例:实现函数的中间代码生成

我们将扩展之前的编译器,使其能够处理函数定义和调用。

步骤 1:扩展 AST 节点类型

首先,我们需要扩展 AST 节点类型,以支持函数定义和调用:

class FunctionDefinition(ASTNode):
    """函数定义节点"""
    def __init__(self, name, parameters, return_type, body):
        self.name = name
        self.parameters = parameters
        self.return_type = return_type
        self.body = body
    
    def __repr__(self):
        return f"FunctionDefinition('{self.name}', {repr(self.parameters)}, '{self.return_type}', {repr(self.body)})"

class FunctionCall(ASTNode):
    """函数调用节点"""
    def __init__(self, name, arguments):
        self.name = name
        self.arguments = arguments
    
    def __repr__(self):
        return f"FunctionCall('{self.name}', {repr(self.arguments)})"

class ReturnStatement(ASTNode):
    """返回语句节点"""
    def __init__(self, expr=None):
        self.expr = expr
    
    def __repr__(self):
        if self.expr:
            return f"ReturnStatement({repr(self.expr)})"
        else:
            return "ReturnStatement()"

步骤 2:扩展解析器以支持函数定义和调用

现在,我们扩展解析器以支持函数定义和调用:

class Parser:
    """支持函数的解析器"""
    def __init__(self, tokens):
        self.tokens = tokens
        self.pos = 0
    
    def peek(self):
        """查看当前 token"""
        if self.pos < len(self.tokens):
            return self.tokens[self.pos]
        return None
    
    def consume(self, expected_type=None):
        """消费当前 token"""
        if self.pos < len(self.tokens):
            token = self.tokens[self.pos]
            if expected_type and token[0] != expected_type:
                raise SyntaxError(f"Expected {expected_type}, got {token[0]}")
            self.pos += 1
            return token
        raise SyntaxError("Unexpected end of input")
    
    def parse(self):
        """解析程序"""
        statements = []
        while self.peek():
            statements.append(self.parse_statement())
        if len(statements) == 1:
            return statements[0]
        else:
            return Sequence(statements)
    
    def parse_statement(self):
        """解析语句"""
        token = self.peek()
        if token[0] == 'if':
            return self.parse_if_statement()
        elif token[0] == 'while':
            return self.parse_while_statement()
        elif token[0] == 'for':
            return self.parse_for_statement()
        elif token[0] == '{':
            return self.parse_block()
        elif token[0] == 'return':
            return self.parse_return_statement()
        elif token[0] == 'int' or token[0] == 'void':
            # 可能是函数定义
            return_type = self.consume()[0]
            if self.peek() and self.peek()[0] == 'ID':
                func_name = self.consume('ID')[1]
                if self.peek() and self.peek()[0] == '(':
                    # 是函数定义
                    self.consume('(')
                    parameters = self.parse_parameters()
                    self.consume(')')
                    body = self.parse_block()
                    return FunctionDefinition(func_name, parameters, return_type, body)
                else:
                    # 是变量声明
                    self.pos -= 1  # 回退 ID
                    # 这里可以添加变量声明的解析
        else:
            # 检查是否是函数调用
            if self.peek() and self.peek()[0] == 'ID':
                id_token = self.consume('ID')
                if self.peek() and self.peek()[0] == '(':
                    # 是函数调用
                    self.consume('(')
                    arguments = self.parse_arguments()
                    self.consume(')')
                    return FunctionCall(id_token[1], arguments)
                else:
                    # 不是函数调用,回退
                    self.pos -= 1
            return self.parse_assignment()
    
    def parse_parameters(self):
        """解析函数参数"""
        parameters = []
        if self.peek() and self.peek()[0] != ')':
            while True:
                # 解析参数类型
                param_type = self.consume()[0]
                # 解析参数名
                param_name = self.consume('ID')[1]
                parameters.append((param_type, param_name))
                if not (self.peek() and self.peek()[0] == ','):
                    break
                self.consume(',')
        return parameters
    
    def parse_arguments(self):
        """解析函数实参"""
        arguments = []
        if self.peek() and self.peek()[0] != ')':
            while True:
                arguments.append(self.parse_expr())
                if not (self.peek() and self.peek()[0] == ','):
                    break
                self.consume(',')
        return arguments
    
    def parse_return_statement(self):
        """解析返回语句"""
        self.consume('return')
        if self.peek() and self.peek()[0] != ';':
            expr = self.parse_expr()
            self.consume(';')
            return ReturnStatement(expr)
        else:
            self.consume(';')
            return ReturnStatement()
    
    # 其他方法与之前相同...
    def parse_block(self):
        """解析语句块"""
        self.consume('{')
        statements = []
        while self.peek() and self.peek()[0] != '}':
            statements.append(self.parse_statement())
        self.consume('}')
        if len(statements) == 1:
            return statements[0]
        else:
            return Sequence(statements)
    
    def parse_if_statement(self):
        """解析 if-else 语句"""
        self.consume('if')
        self.consume('(')
        condition = self.parse_expr()
        self.consume(')')
        true_body = self.parse_statement()
        false_body = None
        if self.peek() and self.peek()[0] == 'else':
            self.consume('else')
            false_body = self.parse_statement()
        return IfStatement(condition, true_body, false_body)
    
    def parse_while_statement(self):
        """解析 while 语句"""
        self.consume('while')
        self.consume('(')
        condition = self.parse_expr()
        self.consume(')')
        body = self.parse_statement()
        return WhileStatement(condition, body)
    
    def parse_for_statement(self):
        """解析 for 语句"""
        self.consume('for')
        self.consume('(')
        init = self.parse_assignment()
        self.consume(';')
        condition = self.parse_expr()
        self.consume(';')
        update = self.parse_assignment()
        self.consume(')')
        body = self.parse_statement()
        return ForStatement(init, condition, update, body)
    
    def parse_assignment(self):
        """解析赋值语句"""
        target = self.parse_primary()
        if self.peek() and self.peek()[0] == '=':
            self.consume('=')
            expr = self.parse_expr()
            self.consume(';')
            return Assignment(target, expr)
        else:
            # 如果不是赋值语句,回退
            self.pos -= 1
            expr = self.parse_expr()
            self.consume(';')
            return expr
    
    def parse_expr(self):
        """解析表达式(处理加减和关系运算)"""
        left = self.parse_term()
        while self.peek() and self.peek()[0] in ('+', '-', '<', '<=', '>', '>=', '==', '!='):
            op = self.consume()[0]
            right = self.parse_term()
            left = BinaryOp(op, left, right)
        return left
    
    def parse_term(self):
        """解析项(处理乘除)"""
        left = self.parse_factor()
        while self.peek() and self.peek()[0] in ('*', '/'):
            op = self.consume()[0]
            right = self.parse_factor()
            left = BinaryOp(op, left, right)
        return left
    
    def parse_factor(self):
        """解析因子"""
        return self.parse_primary()
    
    def parse_primary(self):
        """解析基本表达式"""
        token = self.peek()
        if token[0] == '(':
            self.consume('(')
            expr = self.parse_expr()
            self.consume(')')
            return expr
        elif token[0] == 'NUMBER':
            return Constant(self.consume('NUMBER')[1])
        elif token[0] == 'ID':
            return Variable(self.consume('ID')[1])
        elif token[0] in ('+', '-'):
            op = self.consume()[0]
            expr = self.parse_primary()
            return UnaryOp(op, expr)
        else:
            raise SyntaxError(f"Unexpected token: {token}")

步骤 3:扩展词法分析器以支持函数相关的关键字

我们需要扩展词法分析器以识别函数相关的关键字:

def tokenize(code):
    """将代码转换为 token 列表"""
    tokens = []
    i = 0
    keywords = {'if', 'else', 'while', 'for', 'int', 'void', 'return'}
    
    while i < len(code):
        c = code[i]
        if c.isspace():
            i += 1
        elif c.isdigit():
            # 解析数字
            num = ""
            while i < len(code) and code[i].isdigit():
                num += code[i]
                i += 1
            tokens.append(('NUMBER', int(num)))
        elif c.isalpha():
            # 解析标识符或关键字
            id = ""
            while i < len(code) and code[i].isalnum():
                id += code[i]
                i += 1
            if id in keywords:
                tokens.append((id, id))
            else:
                tokens.append(('ID', id))
        elif c in '+-*/(){};,':
            # 解析操作符、括号、分号和逗号
            tokens.append((c, c))
            i += 1
        elif c == '=':
            # 解析赋值运算符
            tokens.append(('=', '='))
            i += 1
        elif c == '<' and i+1 < len(code) and code[i+1] == '=':
            # 解析 <=
            tokens.append(('<=', '<='))
            i += 2
        elif c == '>' and i+1 < len(code) and code[i+1] == '=':
            # 解析 >=
            tokens.append(('>=', '>='))
            i += 2
        elif c == '!' and i+1 < len(code) and code[i+1] == '=':
            # 解析 !=
            tokens.append(('!=', '!='))
            i += 2
        elif c == '=' and i+1 < len(code) and code[i+1] == '=':
            # 解析 ==
            tokens.append(('==', '=='))
            i += 2
        else:
            raise SyntaxError(f"Unexpected character: {c}")
    
    return tokens

步骤 4:扩展三地址码生成器以支持函数

现在,我们扩展三地址码生成器以支持函数定义和调用:

class TACGenerator:
    """支持函数的三地址码生成器"""
    def __init__(self):
        self.temp_count = 0
        self.label_count = 0
        self.instructions = []
        self.functions = []  # 存储函数定义
    
    def new_temp(self):
        """生成新的临时变量"""
        temp = f"t{self.temp_count}"
        self.temp_count += 1
        return temp
    
    def new_label(self):
        """生成新的标签"""
        label = f"L{self.label_count}"
        self.label_count += 1
        return label
    
    def generate(self, node):
        """生成三地址码"""
        if isinstance(node, Constant):
            return node.value
        elif isinstance(node, Variable):
            return node.name
        elif isinstance(node, BinaryOp):
            left_val = self.generate(node.left)
            right_val = self.generate(node.right)
            temp = self.new_temp()
            self.instructions.append(f"{temp} = {left_val} {node.op} {right_val}")
            return temp
        elif isinstance(node, UnaryOp):
            expr_val = self.generate(node.expr)
            temp = self.new_temp()
            self.instructions.append(f"{temp} = {node.op} {expr_val}")
            return temp
        elif isinstance(node, Assignment):
            target = node.target.name
            expr_val = self.generate(node.expr)
            self.instructions.append(f"{target} = {expr_val}")
            return target
        elif isinstance(node, Sequence):
            for stmt in node.statements:
                self.generate(stmt)
            return None
        elif isinstance(node, IfStatement):
            self.generate_if_statement(node)
            return None
        elif isinstance(node, WhileStatement):
            self.generate_while_statement(node)
            return None
        elif isinstance(node, ForStatement):
            self.generate_for_statement(node)
            return None
        elif isinstance(node, ReturnStatement):
            return self.generate_return_statement(node)
        elif isinstance(node, FunctionCall):
            return self.generate_function_call(node)
        elif isinstance(node, FunctionDefinition):
            self.generate_function_definition(node)
            return None
        else:
            raise TypeError(f"Unknown AST node type: {type(node)}")
    
    def generate_if_statement(self, node):
        """生成 if-else 语句的三地址码"""
        # 生成条件表达式的三地址码
        cond_val = self.generate(node.condition)
        
        # 生成标签
        Lfalse = self.new_label()
        Lend = self.new_label()
        
        # 生成条件跳转
        self.instructions.append(f"iffalse {cond_val} goto {Lfalse}")
        
        # 生成 true_body 的三地址码
        self.generate(node.true_body)
        
        # 生成无条件跳转
        self.instructions.append(f"goto {Lend}")
        
        # 生成 Lfalse 标签
        self.instructions.append(f"{Lfalse}:")
        
        # 生成 false_body 的三地址码
        if node.false_body:
            self.generate(node.false_body)
        
        # 生成 Lend 标签
        self.instructions.append(f"{Lend}:")
    
    def generate_while_statement(self, node):
        """生成 while 语句的三地址码"""
        # 生成标签
        Lstart = self.new_label()
        Lend = self.new_label()
        
        # 生成 Lstart 标签
        self.instructions.append(f"{Lstart}:")
        
        # 生成条件表达式的三地址码
        cond_val = self.generate(node.condition)
        
        # 生成条件跳转
        self.instructions.append(f"iffalse {cond_val} goto {Lend}")
        
        # 生成 body 的三地址码
        self.generate(node.body)
        
        # 生成无条件跳转
        self.instructions.append(f"goto {Lstart}")
        
        # 生成 Lend 标签
        self.instructions.append(f"{Lend}:")
    
    def generate_for_statement(self, node):
        """生成 for 语句的三地址码"""
        # 生成标签
        Lstart = self.new_label()
        Lend = self.new_label()
        
        # 生成 init 的三地址码
        self.generate(node.init)
        
        # 生成 Lstart 标签
        self.instructions.append(f"{Lstart}:")
        
        # 生成条件表达式的三地址码
        cond_val = self.generate(node.condition)
        
        # 生成条件跳转
        self.instructions.append(f"iffalse {cond_val} goto {Lend}")
        
        # 生成 body 的三地址码
        self.generate(node.body)
        
        # 生成 update 的三地址码
        self.generate(node.update)
        
        # 生成无条件跳转
        self.instructions.append(f"goto {Lstart}")
        
        # 生成 Lend 标签
        self.instructions.append(f"{Lend}:")
    
    def generate_return_statement(self, node):
        """生成返回语句的三地址码"""
        if node.expr:
            # 生成表达式的三地址码
            expr_val = self.generate(node.expr)
            # 生成返回指令
            self.instructions.append(f"return {expr_val}")
            return expr_val
        else:
            # 生成空返回指令
            self.instructions.append("return")
            return None
    
    def generate_function_call(self, node):
        """生成函数调用的三地址码"""
        # 计算实参的值
        arg_vals = []
        for arg in node.arguments:
            arg_val = self.generate(arg)
            arg_vals.append(arg_val)
        
        # 生成参数传递指令
        for i, arg_val in enumerate(reversed(arg_vals)):
            # 逆序压栈(假设栈传递)
            self.instructions.append(f"push {arg_val}")
        
        # 生成函数调用指令
        self.instructions.append(f"call {node.name}")
        
        # 生成清理栈的指令(假设每个参数占用 4 字节)
        if arg_vals:
            self.instructions.append(f"add esp, {4 * len(arg_vals)}")
        
        # 生成临时变量存储返回值
        result_temp = self.new_temp()
        self.instructions.append(f"{result_temp} = eax")  # 假设返回值在 eax 寄存器中
        
        return result_temp
    
    def generate_function_definition(self, node):
        """生成函数定义的三地址码"""
        # 记录函数名
        self.functions.append(node.name)
        
        # 生成函数标签
        self.instructions.append(f"{node.name}:")
        
        # 生成序言
        # 1. 保存返回地址(通常由调用者保存)
        # 2. 保存 ebp 寄存器
        self.instructions.append("push ebp")
        # 3. 设置新的 ebp
        self.instructions.append("mov ebp, esp")
        
        # 4. 分配栈帧空间(假设每个局部变量占用 4 字节)
        # 这里简化处理,实际需要根据局部变量数量计算
        local_vars_count = 0  # 这里可以添加局部变量计数
        if local_vars_count > 0:
            self.instructions.append(f"sub esp, {4 * local_vars_count}")
        
        # 生成参数处理代码
        # 假设参数从 ebp + 8 开始(跳过返回地址和旧 ebp)
        for i, (param_type, param_name) in enumerate(node.parameters):
            offset = 8 + i * 4  # 每个参数 4 字节
            self.instructions.append(f"{param_name} = [ebp + {offset}]")
        
        # 生成函数体的三地址码
        self.generate(node.body)
        
        # 生成尾声
        # 1. 恢复 esp
        self.instructions.append("mov esp, ebp")
        # 2. 恢复 ebp
        self.instructions.append("pop ebp")
        # 3. 返回
        self.instructions.append("ret")
    
    def get_instructions(self):
        """获取生成的三地址码指令"""
        return self.instructions
    
    def get_functions(self):
        """获取生成的函数列表"""
        return self.functions

步骤 5:测试函数的中间代码生成

让我们测试一下我们的编译器,看看它是否能正确生成函数的三地址码:

# 测试函数
def test_function(code):
    print(f"\nTesting code:\n{code}")
    # 词法分析
    tokens = tokenize(code)
    print(f"Tokens: {tokens}")
    # 语法分析
    parser = Parser(tokens)
    ast = parser.parse()
    print(f"AST: {repr(ast)}")
    # 生成三地址码
    generator = TACGenerator()
    generator.generate(ast)
    instructions = generator.get_instructions()
    print("Generated TAC:")
    for i, instr in enumerate(instructions):
        print(f"  {i+1}. {instr}")

# 测试案例
test_function("""
int add(int a, int b) {
    return a + b;
}

int main() {
    int x = 5;
    int y = 3;
    int z = add(x, y);
    return z;
}
""")

test_function("""
int factorial(int n) {
    if (n <= 1) {
        return 1;
    } else {
        return n * factorial(n - 1);
    }
}

int main() {
    int result = factorial(5);
    return result;
}
""")

步骤 6:运行结果分析

运行上面的测试代码,我们会得到以下输出:

Testing code:
int add(int a, int b) {
    return a + b;
}

int main() {
    int x = 5;
    int y = 3;
    int z = add(x, y);
    return z;
}

Tokens: [('int', 'int'), ('add', 'add'), ('(', '('), ('int', 'int'), ('a', 'a'), (',', ','), ('int', 'int'), ('b', 'b'), (')', ')'), ('{', '{'), ('return', 'return'), ('a', 'a'), ('+', '+'), ('b', 'b'), (';', ';'), ('}', '}'), ('int', 'int'), ('main', 'main'), ('(', '('), (')', ')'), ('{', '{'), ('int', 'int'), ('x', 'x'), ('=', '='), ('5', '5'), (';', ';'), ('int', 'int'), ('y', 'y'), ('=', '='), ('3', '3'), (';', ';'), ('int', 'int'), ('z', 'z'), ('=', '='), ('add', 'add'), ('(', '('), ('x', 'x'), (',', ','), ('y', 'y'), (')', ')'), (';', ';'), ('return', 'return'), ('z', 'z'), (';', ';'), ('}', '}')]
AST: Sequence([FunctionDefinition('add', [('int', 'a'), ('int', 'b')], 'int', ReturnStatement(BinaryOp('+', Variable('a'), Variable('b')))), FunctionDefinition('main', [], 'int', Sequence([Assignment(Variable('x'), Constant(5)), Assignment(Variable('y'), Constant(3)), Assignment(Variable('z'), FunctionCall('add', [Variable('x'), Variable('y')])), ReturnStatement(Variable('z'))]))])
Generated TAC:
  1. add:
  2. push ebp
  3. mov ebp, esp
  4. a = [ebp + 8]
  5. b = [ebp + 12]
  6. t0 = a + b
  7. return t0
  8. mov esp, ebp
  9. pop ebp
 10. ret
 11. main:
 12. push ebp
 13. mov ebp, esp
 14. x = 5
 15. y = 3
 16. push y
 17. push x
 18. call add
 19. add esp, 8
 20. t1 = eax
 21. z = t1
 22. return z
 23. mov esp, ebp
 24. pop ebp
 25. ret

Testing code:
int factorial(int n) {
    if (n <= 1) {
        return 1;
    } else {
        return n * factorial(n - 1);
    }
}

int main() {
    int result = factorial(5);
    return result;
}

Tokens: [('int', 'int'), ('factorial', 'factorial'), ('(', '('), ('int', 'int'), ('n', 'n'), (')', ')'), ('{', '{'), ('if', 'if'), ('(', '('), ('n', 'n'), ('<=', '<='), ('1', '1'), (')', ')'), ('{', '{'), ('return', 'return'), ('1', '1'), (';', ';'), ('}', '}'), ('else', 'else'), ('{', '{'), ('return', 'return'), ('n', 'n'), ('*', '*'), ('factorial', 'factorial'), ('(', '('), ('n', 'n'), ('-', '-'), ('1', '1'), (')', ')'), (';', ';'), ('}', '}'), ('}', '}'), ('int', 'int'), ('main', 'main'), ('(', '('), (')', ')'), ('{', '{'), ('int', 'int'), ('result', 'result'), ('=', '='), ('factorial', 'factorial'), ('(', '('), ('5', '5'), (')', ')'), (';', ';'), ('return', 'return'), ('result', 'result'), (';', ';'), ('}', '}')]
AST: Sequence([FunctionDefinition('factorial', [('int', 'n')], 'int', IfStatement(BinaryOp('<=', Variable('n'), Constant(1)), ReturnStatement(Constant(1)), ReturnStatement(BinaryOp('*', Variable('n'), FunctionCall('factorial', [BinaryOp('-', Variable('n'), Constant(1))])))), FunctionDefinition('main', [], 'int', Sequence([Assignment(Variable('result'), FunctionCall('factorial', [Constant(5)])), ReturnStatement(Variable('result'))]))])
Generated TAC:
  1. factorial:
  2. push ebp
  3. mov ebp, esp
  4. n = [ebp + 8]
  5. t0 = n <= 1
  6. iffalse t0 goto L0
  7. return 1
  8. goto L1
  9. L0:
 10. t1 = n - 1
 11. push t1
 12. call factorial
 13. add esp, 4
 14. t2 = eax
 15. t3 = n * t2
 16. return t3
 17. L1:
 18. mov esp, ebp
 19. pop ebp
 20. ret
 21. main:
 22. push ebp
 23. mov ebp, esp
 24. push 5
 25. call factorial
 26. add esp, 4
 27. t4 = eax
 28. result = t4
 29. return result
 30. mov esp, ebp
 31. pop ebp
 32. ret

实用案例分析

案例:实现递归函数的中间代码生成

递归函数的中间代码生成与普通函数类似,但需要注意栈帧的管理。让我们通过一个更复杂的递归函数示例来演示:

# 测试递归函数
test_function("""
int fibonacci(int n) {
    if (n <= 1) {
        return n;
    } else {
        return fibonacci(n - 1) + fibonacci(n - 2);
    }
}

int main() {
    int result = fibonacci(5);
    return result;
}
""")

运行结果分析:

Testing code:
int fibonacci(int n) {
    if (n <= 1) {
        return n;
    } else {
        return fibonacci(n - 1) + fibonacci(n - 2);
    }
}

int main() {
    int result = fibonacci(5);
    return result;
}

Tokens: [('int', 'int'), ('fibonacci', 'fibonacci'), ('(', '('), ('int', 'int'), ('n', 'n'), (')', ')'), ('{', '{'), ('if', 'if'), ('(', '('), ('n', 'n'), ('<=', '<='), ('1', '1'), (')', ')'), ('{', '{'), ('return', 'return'), ('n', 'n'), (';', ';'), ('}', '}'), ('else', 'else'), ('{', '{'), ('return', 'return'), ('fibonacci', 'fibonacci'), ('(', '('), ('n', 'n'), ('-', '-'), ('1', '1'), (')', ')'), ('+', '+'), ('fibonacci', 'fibonacci'), ('(', '('), ('n', 'n'), ('-', '-'), ('2', '2'), (')', ')'), (';', ';'), ('}', '}'), ('}', '}'), ('int', 'int'), ('main', 'main'), ('(', '('), (')', ')'), ('{', '{'), ('int', 'int'), ('result', 'result'), ('=', '='), ('fibonacci', 'fibonacci'), ('(', '('), ('5', '5'), (')', ')'), (';', ';'), ('return', 'return'), ('result', 'result'), (';', ';'), ('}', '}')]
AST: Sequence([FunctionDefinition('fibonacci', [('int', 'n')], 'int', IfStatement(BinaryOp('<=', Variable('n'), Constant(1)), ReturnStatement(Variable('n')), ReturnStatement(BinaryOp('+', FunctionCall('fibonacci', [BinaryOp('-', Variable('n'), Constant(1))]), FunctionCall('fibonacci', [BinaryOp('-', Variable('n'), Constant(2))])))), FunctionDefinition('main', [], 'int', Sequence([Assignment(Variable('result'), FunctionCall('fibonacci', [Constant(5)])), ReturnStatement(Variable('result'))]))])
Generated TAC:
  1. fibonacci:
  2. push ebp
  3. mov ebp, esp
  4. n = [ebp + 8]
  5. t0 = n <= 1
  6. iffalse t0 goto L0
  7. return n
  8. goto L1
  9. L0:
 10. t1 = n - 1
 11. push t1
 12. call fibonacci
 13. add esp, 4
 14. t2 = eax
 15. t3 = n - 2
 16. push t3
 17. call fibonacci
 18. add esp, 4
 19. t4 = eax
 20. t5 = t2 + t4
 21. return t5
 22. L1:
 23. mov esp, ebp
 24. pop ebp
 25. ret
 26. main:
 27. push ebp
 28. mov ebp, esp
 29. push 5
 30. call fibonacci
 31. add esp, 4
 32. t6 = eax
 33. result = t6
 34. return result
 35. mov esp, ebp
 36. pop ebp
 37. ret

总结

本集我们通过实战案例,详细讲解了如何为函数生成中间代码,重点关注了以下内容:

  1. 函数的中间代码表示:包括函数声明、定义和调用

  2. 栈帧布局:函数执行时在栈上分配的内存区域,用于存储返回地址、参数、局部变量等

  3. 参数传递方式:值传递、引用传递和寄存器传递

  4. 函数调用的三地址码生成规则:计算实参、传递参数、调用函数、获取返回值

  5. 函数定义的三地址码生成规则:序言、参数处理、函数体、尾声

  6. 递归函数的中间代码生成:与普通函数类似,但需要注意栈帧的管理

通过本集的学习,我们掌握了函数的中间代码生成技术,完成了中间代码生成篇的实战部分。在下一集中,我们将开始学习中间代码优化的基础知识。

« 上一篇 中间代码生成实战(二)—— 控制流 下一篇 » 中间代码优化基础