每个节点生成的指令都是一个长长的指令列表,那么得弄几个小工具将这些列表给连接起来。
// 将一个指令追加到表末尾
static struct List* appendIns(struct List* list, void* ins)
{
list->addTo(list, ins, list->count(list));
return list;
}
// 将 back 连接到 front 之后
static struct List* appendInsList(struct List* front, struct List* back)
{
while (0 != back->count(back)) {
appendIns(front, back->popElementAt(back, 0));
}
back->finalize(back);
return front;
}
// 这两个函数的返回值设计是为了支持链式操作,所以……
// 有些代码可能看起来很晕
指令生成,先挑简单的上。
BasicBlockNode
在符号表那里定义过两个函数 enterBasicBlock 和 leaveBasicBlock,现在它们要被调用了。
struct List* insBasicBlockNode(void* node)
{
struct BasicBlockNode* self = (struct BasicBlockNode*)node;
enterBasicBlock();
struct List* list = (struct List*)newArrayList(),* sublist;
struct AbstractSyntaxNode* sub = self->block;
while (NULL != sub) {
sublist = sub->createInstruction(sub);
appendInsList(list, sublist);
sub = sub->nextNode;
}
leaveBasicBlock();
return list;
}
这两个调用的中间,基本块的生成了内部每个语句的指令,将它们全部拼接在一起。
IntegerNode / RealNode
这两个嘛……
struct List* insIntegerNode(void* node)
{
struct List* list = (struct List*)newArrayList();
struct IntParamInstruction* loadInt = (struct IntParamInstruction*)
allocate(sizeof(struct IntParamInstruction));
loadInt->code = CONST_INT;
loadInt->param = ((struct IntegerNode*)node)->intValue;
appendIns(list, loadInt);
return list;
}
struct List* insRealNode(void* node)
{
struct List* list = (struct List*)newArrayList();
struct RealParamInstruction* loadReal = (struct RealParamInstruction*)
allocate(sizeof(struct RealParamInstruction));
loadReal->code = CONST_REAL;
loadReal->param = ((struct RealNode*)node)->realValue;
appendIns(list, loadReal);
return list;
}
小心,LOAD_XXXX 指的是从内存某个地址上取一个数到栈顶,而这里用到的是 CONST_XXX,是直接将指令中的常数放在栈顶。
ArithmaticNode
struct List* insArithmaticNode(void* node)
{
struct AbstractValueNode* arith = ((struct ArithmaticNode*)node)->arith;
AcceptType type = arith->typeOf(arith); // 取得算式的类型
struct List* insList = arith->createInstruction(arith);
struct IntParamInstruction* pop = (struct IntParamInstruction*)
allocate(sizeof(struct IntParamInstruction));
pop->code = POP; // 算式结束后,弹出栈顶的数
// 根据类型确定该怎么来弹
if (INTEGER == type) {
pop->param = INT_SIZE;
} else {
pop->param = REAL_SIZE;
}
appendIns(insList, pop);
return insList;
}
VariableNode
Q:这个难道会很简单?
A:有的时候我们得把架子搭在没有实现的东西上面。
struct List* insVariableNode(void* node)
{
struct List* getAddr = addrOfVar(node); // here,先用着再说
struct NoParamInstruction* loadVal = (struct NoParamInstruction*)
allocate(sizeof(struct NoParamInstruction));
loadVal->code = (INTEGER == ((struct VariableNode*)node)->typeOf(node)) ?
LOAD_INT : LOAD_REAL; // 确定类型
return appendIns(getAddr, loadVal); // 把 LOAD 指令加上
}
下回分解:
流程控制语句
分享到:
相关推荐
采用递归下降语法制导翻译法,对算术表达式、赋值语句进行语义分析并生成四元式序列。 实验的输入和输出 输入是语法分析提供的正确的单词串,输出为三地址指令形式的四元式序列。 例如:对于语句串 begin a:=2+3*4 x...
语法制导翻译和中间代码生成是编译器设计的关键步骤,它们在编译过程中起着至关重要的作用。首先,我们要回顾编译过程,它通常包括词法分析、语法分析、语义分析和代码生成等阶段。语义分析位于语法分析之后,主要...
例如,当解析到C语言中的if语句时,语法制导翻译会生成对应的条件判断和分支指令。 5. **编译原理实验**: 在学习和实践中,编译原理的实验通常涉及实现上述组件。学生可能需要编写词法分析器、语法分析器,并应用...
《编译原理语法制导翻译》 在计算机科学领域,编译原理是研究如何将高级编程语言转换为机器可理解的指令集的关键分支。语法制导翻译是编译器设计中的一种重要技术,它结合了语法分析和语义处理,以确保程序的正确性...
4. **语法制导翻译**:基于抽象语法树,编译器进行语义分析,检查程序的逻辑正确性。此阶段可能会执行类型检查和常量折叠等操作,并可能引入一些优化。同时,它会根据语法规则生成相应的中间代码。 5. **中间代码...
总结来说,"语义分析器--语法制导翻译绘制图形"项目提供了一个实践编译器设计的平台,涵盖了语义分析、语法制导翻译和图形绘制等多个重要概念。通过深入研究这个项目,开发者可以深化对编译原理的理解,掌握C++编程...
2. 编写语法分析器(通常使用递归下降或LL(1)、LR(1)方法),生成语法树。 3. 实现三地址码生成器,从语法树中提取计算路径并转换为三地址码指令。 4. 编写代码生成器,将三地址码转换为目标机器码。 在压缩包中的...
"基于语法制导翻译的表达式转换编译器"是一种利用特定规则集(语法规则)来指导源代码转换过程的编译器设计方法。本项目专注于中缀表达式到后缀表达式的转换,这是编译器前端词法分析、语法分析和语义分析的一个典型...
在树的每个节点上,编译器执行与该节点对应的语法制导规则,这可能包括计算值、生成目标代码指令、存储或传递数据等。这种做法使得编译器可以精确地按照源代码的语法结构生成目标代码,从而确保程序的正确性。 语法...
中间代码生成_表示形式、语法制导方法》主要探讨了编译器设计中的关键环节——中间代码生成,这是编译过程中的一个重要阶段,目的是为了便于优化和移植。本节内容主要包括三元式、逆波兰式、抽象语法树(AST)以及四...
语法制导翻译与中间代码生成是编译器设计中的关键步骤,主要涉及程序的静态语义审查、类型检查、控制流分析以及中间代码生成。在这个过程中,编译器不仅要确保程序符合语法规则,还要对其含义进行深入理解,以便生成...
它主要涉及三个核心过程:词法分析、语法分析和代码生成,而四元式在这个过程中起到重要作用。 首先,词法分析(Lexical Analysis)是编译器的第一步,它的任务是对源代码进行扫描,将源代码分解成一系列有意义的、...
1. **符号表管理**:符号表记录了程序中所有标识符的类型、作用域和关联地址,对于生成三地址代码至关重要,因为它提供了关于操作数的类型信息。 2. **数据类型转换**:编译器必须处理不同数据类型的运算,确保它们...
编译器通常分为几个阶段:词法分析、语法分析、语义分析和代码生成。三地址代码通常在语义分析后的优化阶段产生,作为代码生成的中间步骤。 二、三地址代码 三地址代码是一种低级的、三元操作符形式的IR。每个指令...
采用递归下降语法制导翻译法,对算术表达式、赋值语句进行语义分析并生成四元式序列。 三、实验的结果验证 1.输入是语法分析后提供的正确的单词串,输出为三地址指令形式的四元式序列。 给出语句串: begin_a:=2+3*...
采用递归下降语法制导翻译法,对算术表达式、赋值语句进行语义分析并生成四元式序列。 实验的输入和输出 输入是语法分析提供的正确的单词串,输出为三地址指令形式的四元式序列。 例如:对于语句串 begin a:=2+3*4;x...
《编译原理 实验报告》 实验一主要涵盖了词法分析...词法分析器通过正规式和状态图解析源代码,而语法制导定义和三地址代码生成则涉及到语义分析和代码生成。理解这些概念对于深入学习编译原理和开发编译器至关重要。
本项目“基于C语言实现简单语言递归下降语法制导翻译”深入探讨了这一主题,主要关注如何使用C语言来设计和实现一个编译器的核心部分——语义分析和中间代码生成。 首先,我们要理解什么是递归下降解析。递归下降是...