update: doc
This commit is contained in:
parent
bb473e248c
commit
96e730f67b
|
|
@ -101,3 +101,59 @@ x = 3 + 4;
|
|||
4. `MOV x, R0` (将R0的值移动到变量x)
|
||||
|
||||
这样,我们就通过语法树实现了从源代码到三地址代码的转换。这个过程可以根据具体的语言和需求进行扩展和修改。
|
||||
|
||||
|
||||
|
||||
从提供的代码文件中,我们可以总结出三地址代码生成部分的实现方法如下:
|
||||
|
||||
### 1. 基本结构和初始化
|
||||
|
||||
- **GoTo3code 类**:负责将抽象语法树(AST)转换为三地址代码(TAC)。这个类包含了一系列的私有成员变量和方法,用于存储和生成三地址代码。
|
||||
|
||||
- **符号表(Scope)**:用于存储和管理变量、函数等符号信息。每个作用域(Scope)都包含变量符号表(para_symbols)和函数符号表(fun_symbols)。
|
||||
|
||||
- **TACBlock 和 TACLine**:三地址代码的基本单元是 TACLine,表示单个操作指令;而 TACBlock 表示一个代码块,包含多个 TACLine。
|
||||
|
||||
### 2. 代码生成流程
|
||||
|
||||
- **enterSourceFile 和 exitSourceFile**:在进入和退出源文件解析时,初始化和结束全局作用域。
|
||||
|
||||
- **FunctionDecl**:在函数声明时,创建新的 TACBlock,并将其添加到 TACBlocks(一个存储所有函数 TACBlock 的映射)中。
|
||||
|
||||
- **VarDecl 和 VarSpec**:在变量声明时,生成相应的三地址代码指令,如 `CREATLIST`(用于数组创建)和 `ASSIGN`(用于变量赋值)。
|
||||
|
||||
- **Assignment**:处理赋值语句,生成 `ASSIGN` 三地址代码指令。
|
||||
|
||||
- **ShortVarDecl**:处理简短变量声明,类似于 VarDecl,但通常用于循环或条件语句中。
|
||||
|
||||
- **IfStmt**:处理 if 语句,生成条件跳转指令(如 `IFEQ`、`IFNEQ` 等)。
|
||||
|
||||
- **ForStmt**:处理 for 循环,生成循环入口标签、条件检查、循环体和循环更新代码。
|
||||
|
||||
- **ReturnStmt**:处理 return 语句,生成函数返回值的三地址代码指令。
|
||||
|
||||
### 3. 辅助功能
|
||||
|
||||
- **CreateLocalVar**:创建局部变量名,用于临时变量或其他需要新变量的场景。
|
||||
|
||||
- **push_line**:将新的三地址代码指令添加到当前 TACBlock。
|
||||
|
||||
- **OperandTypereslove**:确定操作数的类型,如变量、立即数或指针。
|
||||
|
||||
- **is_digit**:检查字符串是否为数字,用于处理数组长度等。
|
||||
|
||||
- **Go23file 和 Go23file_**:将生成的三地址代码输出到文件。
|
||||
|
||||
### 4. 代码生成细节
|
||||
|
||||
- **操作数编码**:使用 `Operand` 结构表示操作数,包含值和类型。
|
||||
|
||||
- **操作码映射**:通过 `ToString` 函数将枚举类型的操作码映射为字符串,便于输出和调试。
|
||||
|
||||
- **条件语句和循环**:对于条件语句和循环,生成相应的跳转和标签指令,以实现控制流。
|
||||
|
||||
- **函数调用**:处理函数调用时,生成参数传递、函数调用和返回值处理的三地址代码。
|
||||
|
||||
### 总结
|
||||
|
||||
三地址代码生成部分的实现方法涉及到对源代码的深度优先遍历,根据语法树的结构生成相应的三地址代码指令。这个过程需要维护一个符号表来跟踪变量和函数的定义,以及一个代码块结构来存储生成的三地址代码。通过这种方式,可以将高级语言的控制流和数据流转换为低级的三地址代码表示,为后续的代码优化和目标代码生成打下基础。
|
||||
|
|
|
|||
|
|
@ -48,3 +48,63 @@ add R3, R1, R2
|
|||
在你的`Translator`类中,你需要为`MOV`、`ADD`等操作编写翻译规则,并将它们输出为上述汇编代码。
|
||||
|
||||
总结来说,将三地址代码翻译为汇编代码是一个涉及指令选择、寄存器分配和代码生成的过程。你需要在编译器后端实现这些步骤,并将它们集成到你的`main`函数中,以便将三地址代码转换为汇编代码。
|
||||
|
||||
|
||||
从提供的源代码文件中,我们可以总结出以下翻译规则、寄存器分配和指令调度的实现方法:
|
||||
|
||||
### 翻译规则
|
||||
|
||||
1. **基本块翻译(BlockTranslator.cpp)**:
|
||||
- 每个基本块(TACBlock)被翻译成一系列的汇编代码行(ASMLines)。
|
||||
- 翻译过程涉及到对每个TACLine的遍历,并根据操作码(TACOP)选择相应的翻译器(Translator)进行翻译。
|
||||
|
||||
2. **语句翻译(SentenceTranslator)**:
|
||||
- 对于每种类型的TACLine,如赋值(ASSIGN)、函数调用(CALL)、条件跳转(IF)等,都有专门的翻译器来处理。
|
||||
- 翻译器根据操作数的类型(立即数、变量、内存位置等)生成相应的汇编指令。
|
||||
|
||||
3. **寄存器和内存操作**:
|
||||
- 对于变量的存储位置,需要判断是存储在寄存器还是内存中,这由`SymbolManager`中的`encode_var`和`position`函数决定。
|
||||
|
||||
### 寄存器分配
|
||||
|
||||
1. **获取寄存器(SymbolManager.cpp)**:
|
||||
- `get_reg`函数尝试为一个变量分配一个寄存器,如果失败,则调用`get_replaced_reg`来找到一个可以替换的寄存器。
|
||||
- `get_replaced_reg`寻找不再使用的变量或者内存中有位置的变量,以决定哪个寄存器可以被替换。
|
||||
|
||||
2. **寄存器备份**:
|
||||
- 在进行操作之前,如果需要使用到特定的寄存器(如EAX、EBX),而这些寄存器中存储的值后续还需要使用,则需要将这些值备份到内存中。
|
||||
|
||||
3. **更新寄存器状态**:
|
||||
- 操作完成后,更新`SymbolManager`中的寄存器状态,如`set_avalue_reg`用于设置一个变量的寄存器值。
|
||||
|
||||
### 指令调度
|
||||
|
||||
1. **指令顺序**:
|
||||
- 指令的顺序通常由TACLine的顺序决定,翻译器按照TACLine的顺序生成汇编指令。
|
||||
|
||||
2. **栈操作**:
|
||||
- 在函数调用(CALL)和参数传递(PARA)时,需要对栈进行操作,如`push`和`pop`指令的使用。
|
||||
- `SymbolManager`中的`set_esp_bias`用于调整栈指针(ESP)的偏移。
|
||||
|
||||
3. **条件跳转和标签**:
|
||||
- 条件跳转(IF)和标签(LABEL)的翻译涉及到对跳转目标的识别和指令的生成。
|
||||
|
||||
### 具体实现方法
|
||||
|
||||
1. **寄存器分配策略**:
|
||||
- 使用`SymbolManager`中的`get_free_reg`来获取一个空闲的寄存器。
|
||||
- 如果没有空闲寄存器,使用`get_replaced_reg`来替换一个当前不活跃的寄存器。
|
||||
|
||||
2. **指令生成**:
|
||||
- 对于每个操作数,根据其存储位置(寄存器、内存或全局变量),生成相应的`mov`指令来移动值。
|
||||
- 对于计算操作,如`ADD`、`SUB`、`MUL`等,生成相应的汇编指令。
|
||||
|
||||
3. **内存管理**:
|
||||
- 使用`push`和`pop`指令来管理栈上的内存。
|
||||
- 对于局部变量,使用基于EBP的偏移来访问内存位置。
|
||||
|
||||
4. **函数调用和返回**:
|
||||
- 在函数调用前,将参数压入栈中。
|
||||
- 在函数返回时,从栈中弹出返回值。
|
||||
|
||||
这些源代码文件展示了一个编译器后端如何将三地址代码(TAC)翻译成汇编代码(ASM),涉及到寄存器分配、指令调度和内存管理等多个编译器优化阶段。每个翻译器都负责特定的操作码,而`SymbolManager`则负责跟踪和更新符号表信息,包括变量的存储位置和寄存器的使用情况。
|
||||
|
|
|
|||
Loading…
Reference in New Issue