上一次修改AbstractValueNode
时添加了一个typeOf
成员函数,这个函数用来在编译时确定AbstractValueNode
的类型。相对于确定编译时值,确定类型要简单一些。
对于IntegerNode
和RealNode
,它们的成员函数实现依然是很简单的
AcceptType typeOfInt(void* node)
{
return INTEGER;
}
AcceptType typeOfReal(void* node)
{
return REAL;
}
而确定变量的类型,well,我们在符号表管理器中已经实现过这么一个函数
AcceptType typeOf(struct VariableNode* var);
现在摆在我们面前有两条路选,一是修改这个函数的参数类型,并在函数体内去转换这个参数类型,另一条路就是再加套一个这样的函数
AcceptType typeOfVar(void* node)
{
return typeOf((struct VariableNode*)node);
}
哪一种就随意了。
接下来又是运算节点的类型确定了。对于UnaryOperationNode
,仅需要
AcceptType typeOfUnaryOp(void* node)
{
struct UnaryOperationNode* self = (struct UnaryOperationNode*)node;
if (NOT == self->op && REAL ==
self->operand->typeOf(self->operand)) {
// 报错:实型数不可以作为条件
}
return self->operand->typeOf(self->operand);
}
注意报错以后仍然若无其事地返回,这样也是提升容错性的一种方法。在BinaryOperationNode
的对应函数中也用到这个方法
AcceptType typeOfBinaryOp(void* node)
{
struct BinaryOperationNode* self = (struct BinaryOperationNode*)node;
AcceptType leftType = self->leftOperand->typeOf(self->leftOperand),
rightType = self->rightOperand->typeOf(self->rightOperand);
if (ASSIGN == self->op) {
return leftType;
}
if (isLogicOperator(self->op) &&
(REAL == leftType || REAL == rightType)) {
// 报错:实型数不可以作为条件
}
return leftType > rightType ? leftType : rightType;
}
首先,如果这是一个赋值,那么赋值以后的类型由被赋值的变量决定,即取决于左值。最后一个?:
表达式看起来很奇怪,为什么要取两者中较大的一个呢?其实这是一个偷懒的做法,因为在定义时REAL
比INTEGER
大,所以这样做以后,如果两者中一个是INTEGER
一个是REAL
,那么会返回REAL
。不过这样做也有别的意思,比如要添加一个LONG
类型(比INTEGER范围更大的整型
),那么将它插入到枚举的中INTEGER
与REAL
之间即可──这个取较大语句会解决这些事情。
分享到:
相关推荐
压缩包中的“编译原理语法树”文件可能包含了使用yacc和lex构建的C++语法分析器的示例,以及它分析C++源代码后生成的语法树的可视化表示。通过查看这些示例,开发者可以更深入地理解编译器的工作原理,学习如何构建...
编译原理语法分析语义分析 语法分析(Syntax analysis或Parsing)和语法分析程序(Parser) 语法分析是编译过程的一个逻辑阶段。语法分析的任务是在词法分析的基础上将单词序列组合成各类语法短语,如“程序”,...
语法分析阶段,也称作解析,是将词法分析产生的token流按照语言的语法规则进行组织,形成语法树。这个树状结构直观地表示了程序的结构和语法规则。C语言使用上下文无关文法(Context-Free Grammar,CFG)来定义其...
这个阶段将词法分析产生的标记流转化为抽象语法树(AST),这是一种树形结构,表示了程序的语法结构。语法分析基于上下文无关文法(CFG)进行,通常由递归下降解析器或LR、LL、LALR等解析技术实现。如果源代码的词法...
6. **挑战与难点**:在实现语义分析时,常见的挑战包括处理类型不匹配、处理未声明的变量、处理作用域问题以及确保程序的逻辑正确性。Java的泛型、接口和多态性也可能增加复杂性,需要额外的处理。 7. **学习收获**...
这份“编译原理实验报告”涵盖了编译器设计中的关键步骤,包括语法分析、语义分析和词法分析,这些都是构建编译器的核心部分。下面将详细解释这些概念及其重要性。 1. **词法分析**:这是编译过程的第一步,也称为...
### 编译原理:词法分析-语法分析-语义分析 #### 一、词法分析(Lexical Analysis) 词法分析是编译过程的第一步,它的主要任务是从源程序中识别出一个个有意义的单词符号(Token)。在这个过程中,输入的是源程序...
例如,语义分析会确认变量在使用前已经被正确声明,操作数类型与运算符兼容,以及表达式的值符合预期。在这个阶段,编译器还会开始生成中间代码,如三地址码,这是向后端(目标代码生成)过渡的桥梁。 在使用...
《编译原理实验指导书-语义分析1》主要针对的是编译器设计中的一个重要阶段——语义分析。语义分析是编译器工作流程中的关键环节,它在语法分析之后,负责检查程序的语义正确性,确保代码符合语言规范,并生成相应的...
编译原理 实验 课程设计语义分析 语法分析 词法分析源代码极为一体的源文件
《编译原理:深入理解语义分析》 在计算机科学领域,编译原理是一门至关重要的课程,它探讨了如何将高级编程语言转化为机器可执行的指令。本资源是北京邮电大学大三学生的课程项目,专注于语义分析这一关键阶段。...
词法分析、SLR语法分析和SLR语义分析是编译器设计与实现的关键步骤,让我们逐一深入探讨这些概念。 首先,词法分析(Lexical Analysis)是编译过程的第一步。它将源代码按照字符流进行扫描,识别出有意义的符号单元...
这意味着每条语句必须在编译时就确定其数据类型。语义分析器会检查变量是否已正确定义,类型转换是否合法,以及运算符的操作数是否符合预期类型。此外,它还要处理类、接口、方法和成员的访问控制,确保遵循Java的...
在实现语义分析器时,通常会定义一套抽象语法树(AST)来表示源代码的结构。AST是对源代码的结构化表示,每个节点代表代码的一个部分,如变量声明、函数调用或算术操作。通过遍历AST,语义分析器可以方便地检查代码...
【编译原理 语义分析 实验报告】 实验的目的在于深入理解语法制导翻译的原理,这涉及到将解析器在语法分析阶段识别出的语法结构转换为中间代码的过程。语义分析是编译器设计中的关键步骤,它关注的是程序的意义而非...
这个“编译原理 语法分析、语义分析综合实验”涵盖了编译器设计中的两个核心步骤:语法分析和语义分析。通过这个实验,你将有机会深入理解这两者的工作原理,并通过实际操作来巩固理论知识。 语法分析是编译过程的...
在编译过程中,词法分析器将源代码分解为一个个符号,语法分析器则根据这些符号构造抽象语法树(AST)。当这两步完成后,语义分析器开始工作,它的主要任务包括: 1. **类型检查**:语义分析器会检查变量、常量和...
7. **中间代码生成**:在完成语义分析后,编译器通常会生成一种中间表示(IR),如三地址码或抽象语法树(AST)。这种表示形式简化了后续的优化和目标代码生成。 8. **实验报告**:在学习和研究编译原理时,实验...