`
NeuronR
  • 浏览: 58971 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
社区版块
存档分类
最新评论

[指令生成]语法制导的指令生成[接口]

阅读更多

    继续向语法树节点结构中追加成员。

 

#define memberAbstractSyntaxNode              \
    unsigned int line;                        \
    struct AbstractSyntaxNode* nextNode;      \
    struct List* (*createInstruction)(void*); \
    void (*delNode)(void*);                   \
    void (*printree)(void*, int); /***********/
// AbstractSyntaxNode 增加成员 createInstruction
// 产生该语法树节点对应的指令 List

#define memberAbstractValueNode        \
    memberAbstractSyntaxNode           \
    int (*staticInt)(void*, int*);     \
    int (*staticReal)(void*, double*); \
    AcceptType (*typeOf)(void*);       \
    struct List* (*addressOf)(void*);
// AbstractValueNode 增加成员 addressOf
// 产生这个值节点对应的加载地址的指令 List
// 对于非法的左值, 如表达式, 这个函数返回 NULL

 

 

    这篇文章将谈及我们需要实现的接口和它们的功能。

 

    对于每类节点的指令生成模块,函数命名方式为

        ins + 类名

        struct List* insIntegerNode(void*);

就是为 IntegerNode 生成指令的函数,它将在 newIntegerNode 函数(希望大家还记得这些函数)中被赋值:

        node->createInstruction = insIntegerNode;

其它类型与这个例子非常类似,就不一一赘述了。下面谈谈各类型指令生成是要干什么。

// 进入基本块和退出基本块
// 函数将连接块内所有语句的指令, 此外还将与符号表进行交互
struct List* insBasicBlockNode(void*);

// 一元 / 二元运算节点
// 加载它们的子节点(运算数)的指令, 并进行对应的运算(例外参见后文)
// 执行它们生成的指令, 结果是让运行栈栈顶存放一个值, 而不是一个地址
struct List* insBinaryOperationNode(void*);
struct List* insUnaryOperationNode(void*);

// 常数节点生成的指令将加载一个常数到运行栈栈顶
struct List* insIntegerNode(void*);
struct List* insRealNode(void*);

// 分支控制生成的指令将根据运行栈栈顶的整数值, 调节执行方式
struct List* insIfElseNode(void*);
// 循环控制除了生成循环控制相关的指令
// 还会维护一个循环栈
// 而 BreakNode 将根据循环栈来确定该跳出哪个循环
// insBreakNode 包含语义容错
struct List* insWhileNode(void*);
struct List* insBreakNode(void*);

// IO 是一个统称
// 实际上, Read 与 Write 生成的指令很不一样
// Read 执行时, 要求运行栈栈顶是一个地址
// 然后根据类型读入数据并送往该地址
// 而 Write 要求栈顶是值, 并写出该值
// 指令执行之后, 将弹走栈顶
struct List* insIONode(void*);

// 一个算术节点会干什么?
// 它并不是仅仅调用子节点的指令生成就完了
// 注意到, 当一个运算结束之后, 运行栈栈顶总会有一个值
// 因此为了维护栈指针, 算术节点会根据子节点的数据类型调整栈指针
struct List* insArithmaticNode(void*);

// 声明节点主要工作是与符号表打交道
// 以及对变量进行初始化
// 包含语义容错
struct List* insDeclarationNode(void*);

// 将变量的运行时值取到栈顶
// 包含语义容错
struct List* insVariableNode(void*);

有一点很有趣的是,无论是x86指令集,还是Jerry指令集,都不包含与/或/非(逻辑运算,不是位运算)这些运算,也就是说我们必须完成条件短路,所以虽然 BinaryOperationNode 就只有一个指令生成入口,但是这个入口会根据运算符的不同而进入三个不同的模块中

// 运算符是 = 那么进行赋值指令生成
static struct List* insAssignment(void*);

// 运算符是 && 或 || 进行逻辑短路
static struct List* insLogicShortcut(void*);

// 此外生成一般运算指令
static struct List* insNormalBinaryOp(void*);

为了方便判断,在 const.h 中 AcceptType 旁边添加这些宏

#define isArithOperator(x) (PLUS <= (x) && (x) < ASSIGN)
#define isLogicOperator(x) (AND <= (x) && (x) <= NOT)

 

    而对于取地址函数,就目前的情况来看只有两种——变量地址,和无法取到地址。这些接口如下

// 取变量的地址, 指令运行时执行结束将会在栈顶引入该变量的地址
struct List* addrOfVar(void*);

// 其它
struct List* cantRetrieveAddr(void*);

记得将它们在 newVariableNode 等函数中绑定到对应的 addressOf 域中。

分享到:
评论

相关推荐

    yyfx.rar_4 3 2 1_C语法制导翻译_三地址_实验3递归下降_语法制导翻译

    采用递归下降语法制导翻译法,对算术表达式、赋值语句进行语义分析并生成四元式序列。 实验的输入和输出 输入是语法分析提供的正确的单词串,输出为三地址指令形式的四元式序列。 例如:对于语句串 begin a:=2+3*4 x...

    第8章 语法制导翻译和中间代码生成

    语法制导翻译和中间代码生成是编译器设计的关键步骤,它们在编译过程中起着至关重要的作用。首先,我们要回顾编译过程,它通常包括词法分析、语法分析、语义分析和代码生成等阶段。语义分析位于语法分析之后,主要...

    c词法分析器语法分析器语法制导翻译

    例如,当解析到C语言中的if语句时,语法制导翻译会生成对应的条件判断和分支指令。 5. **编译原理实验**: 在学习和实践中,编译原理的实验通常涉及实现上述组件。学生可能需要编写词法分析器、语法分析器,并应用...

    编译原理语法制导翻译

    《编译原理语法制导翻译》 在计算机科学领域,编译原理是研究如何将高级编程语言转换为机器可理解的指令集的关键分支。语法制导翻译是编译器设计中的一种重要技术,它结合了语法分析和语义处理,以确保程序的正确性...

    编译原理 内容包括语言和文法、词法分析、语法分析、语法制导翻译、中间代码生成、存储管理、代码优化和目标代码生成

    4. **语法制导翻译**:基于抽象语法树,编译器进行语义分析,检查程序的逻辑正确性。此阶段可能会执行类型检查和常量折叠等操作,并可能引入一些优化。同时,它会根据语法规则生成相应的中间代码。 5. **中间代码...

    语义分析器--语法制导翻译绘制图形

    总结来说,"语义分析器--语法制导翻译绘制图形"项目提供了一个实践编译器设计的平台,涵盖了语义分析、语法制导翻译和图形绘制等多个重要概念。通过深入研究这个项目,开发者可以深化对编译原理的理解,掌握C++编程...

    编译原理实验c源代码

    二、语法制导的三地址码 三地址码是一种简单的中间表示(IR)形式,它以指令的形式表示计算过程,每个指令通常包含三个地址:操作符、操作数1和操作数2。例如,"x = y + z" 可以转化为 "x = add(y, z)"。这种表示...

    基于语法制导翻译的表达式转换编译器(中缀表达式转后缀表达式)

    "基于语法制导翻译的表达式转换编译器"是一种利用特定规则集(语法规则)来指导源代码转换过程的编译器设计方法。本项目专注于中缀表达式到后缀表达式的转换,这是编译器前端词法分析、语法分析和语义分析的一个典型...

    语法制导翻译

    在树的每个节点上,编译器执行与该节点对应的语法制导规则,这可能包括计算值、生成目标代码指令、存储或传递数据等。这种做法使得编译器可以精确地按照源代码的语法结构生成目标代码,从而确保程序的正确性。 语法...

    编译原理及实现技术:20.中间代码生成_表示形式、语法制导方法.ppt

    中间代码生成_表示形式、语法制导方法》主要探讨了编译器设计中的关键环节——中间代码生成,这是编译过程中的一个重要阶段,目的是为了便于优化和移植。本节内容主要包括三元式、逆波兰式、抽象语法树(AST)以及四...

    编译原理,词法分析,语法分析,四元式生成翻译程序设计

    它主要涉及三个核心过程:词法分析、语法分析和代码生成,而四元式在这个过程中起到重要作用。 首先,词法分析(Lexical Analysis)是编译器的第一步,它的任务是对源代码进行扫描,将源代码分解成一系列有意义的、...

    语法制导翻译与中间代码生成PPT学习教案.pptx

    语法制导翻译与中间代码生成是编译器设计中的关键步骤,主要涉及程序的静态语义审查、类型检查、控制流分析以及中间代码生成。在这个过程中,编译器不仅要确保程序符合语法规则,还要对其含义进行深入理解,以便生成...

    编译原理 三地址代码生成器

    三地址代码生成器就是在这个阶段介入,它遍历AST,为每个节点生成对应的三地址指令。 在Turbo C3.0这样的编译器环境下,开发者可以实现自己的三地址代码生成器。虽然Turbo C3.0是一款较老的编译器,但其C语言编译器...

    编译原理三地址代码生成C++实现

    编译器通常分为几个阶段:词法分析、语法分析、语义分析和代码生成。三地址代码通常在语义分析后的优化阶段产生,作为代码生成的中间步骤。 二、三地址代码 三地址代码是一种低级的、三元操作符形式的IR。每个指令...

    编译原理 实验报告

    《编译原理 实验报告》 实验一主要涵盖了词法分析...词法分析器通过正规式和状态图解析源代码,而语法制导定义和三地址代码生成则涉及到语义分析和代码生成。理解这些概念对于深入学习编译原理和开发编译器至关重要。

    语义分析&&编译原理实验

    采用递归下降语法制导翻译法,对算术表达式、赋值语句进行语义分析并生成四元式序列。 三、实验的结果验证 1.输入是语法分析后提供的正确的单词串,输出为三地址指令形式的四元式序列。 给出语句串: begin_a:=2+3*...

    基于C语言实现简单语言递归下降语法制导翻译(编译原理)【100012399】

    本项目“基于C语言实现简单语言递归下降语法制导翻译”深入探讨了这一主题,主要关注如何使用C语言来设计和实现一个编译器的核心部分——语义分析和中间代码生成。 首先,我们要理解什么是递归下降解析。递归下降是...

    赋值语句的语法翻译及语义分析

    此外,编译器还可能进行优化,例如对于 "x = x + 1" 这样的语句,编译器可能会生成更为高效的指令序列,避免不必要的重复读取和写入。这就是所谓的"副作用"概念,编译器需要理解并妥善处理。 在实际的编译过程中,...

Global site tag (gtag.js) - Google Analytics