编译器中间代码
㈠ 编译程序是不是一定要产生中间代码
是的,中间代码的意义就是微软推出.NET平台的意义
NET是Microsoft面向XMLWeb服务的平台,这种下一代的软件将使用一种统一、个性化的方式将我们的信息、设备和人员紧密联系在一起。
㈡ 正在做一个小型编译器,请问如何把中间表达式如何生成c语言
你的意思不是很明白。
我就简单说下一个我当时写一个简单编译器的流程吧
首先你得确定文法,然后再开始写编译器
1. 用flex写词法分析程序,具体的网上有很多资料。
2. 用yacc写语法分析程序,可以分几步来写
先写一个语法树生成程序,打印出语法树,可以进行简单的类型检查;
再使用语法制导的翻译方案,写一个中间代码生成程序。
3. 将中间代码翻译成汇编语言,优化就不做了太麻烦。
推荐龙书
㈢ 编译程序中间代码的生成对编译器的前端和后端有什么作用
编译器粗略分为词法分析,语法分析,类型检查,中间代码生成,代码优化,目标代码生成,目标代码优化。把中间代码生成及之前阶段划分问编译器的前端,那么后端与前端是独立的。后端只需要一种中间代码表示,可以是三地址代码或四元式等,而这些都与前端生成的方式无关。也就是不论你前端是用fortran还是c/c++,只要生成了中间代码表示就可以了,后端是不管你是用哪种语言生成的。
㈣ c程序经过编译后获得的中间代码文件还需要经过
开发一个C语言程序需要经过的四个步骤:编辑、编译、连接、运行。
C语言程序可以使用在任意架构的处理器上,只要那种架构的处理器具有对应的C语言编译器和库,然后将C源代码编译、连接成目标二进制文件之后即可运行。
1、预处理:输入源程序并保存(.C文件)。
2、编译:将源程序翻译为目标文件(.OBJ文件)。
3、链接:将目标文件生成可执行文件( .EXE文件)。
4、运行:执行.EXE文件,得到运行结果。
㈤ 编译器的组成及各部分的功能及作用
1. 词法分析 词法分析器根据词法规则识别出源程序中的各个记号(token),每个记号代表一类单词(lexeme)。源程序中常见的记号可以归为几大类:关键字、标识符、字面量和特殊符号。词法分析器的输入是源程序,输出是识别的记号流。词法分析器的任务是把源文件的字符流转换成记号流。本质上它查看连续的字符然后把它们识别为“单词”。 2. 语法分析 语法分析器根据语法规则识别出记号流中的结构(短语、句子),并构造一棵能够正确反映该结构的语法树。 3. 语义分析 语义分析器根据语义规则对语法树中的语法单元进行静态语义检查,如果类型检查和转换等,其目的在于保证语法正确的结构在语义上也是合法的。 4. 中间代码生成 中间代码生成器根据语义分析器的输出生成中间代码。中间代码可以有若干种形式,它们的共同特征是与具体机器无关。最常用的一种中间代码是三地址码,它的一种实现方式是四元式。三地址码的优点是便于阅读、便于优化。 5. 中间代码优化 优化是编译器的一个重要组成部分,由于编译器将源程序翻译成中间代码的工作是机械的、按固定模式进行的,因此,生成的中间代码往往在时间和空间上有很大浪费。当需要生成高效目标代码时,就必须进行优化。 6. 目标代码生成 目标代码生成是编译器的最后一个阶段。在生成目标代码时要考虑以下几个问题:计算机的系统结构、指令系统、寄存器的分配以及内存的组织等。编译器生成的目标程序代码可以有多种形式:汇编语言、可重定位二进制代码、内存形式。 7 符号表管理 符号表的作用是记录源程序中符号的必要信息,并加以合理组织,从而在编译器的各个阶段能对它们进行快速、准确的查找和操作。符号表中的某些内容甚至要保留到程序的运行阶段。 8 出错处理用户编写的源程序中往往会有一些错误,可分为静态错误和动态错误两类。所谓动态错误,是指源程序中的逻辑错误,它们发生在程序运行的时候,也被称作动态语义错误,如变量取值为零时作为除数,数组元素引用时下标出界等。静态错误又可分为语法错误和静态语义错误。语法错误是指有关语言结构上的错误,如单词拼写错、表达式中缺少操作数、begin和end不匹配等。静态语义错误是指分析源程序时可以发现的语言意义上的错误,如加法的两个操作数中一个是整型变量名,而另一个是数组名等。
㈥ 编译器笔记34-中间代码生成-布尔表达式的回填
基本思想:生成一个跳转指令时,暂时不指定该跳转指令的目标标号。这样的指令都被放入由跳转指令组成的列表中。同一个列表中的所有跳转指令具有相同的目标标号。等到能够确定正确的目标标号时,才去填充这些指令的目标标号。
B.truelist:指向一个包含跳转指令的列表,这些指令最终获得的目标标号就是当B为真时控制流应该转向的指令的标号。
B.falselist:指向一个包含跳转指令的列表,这些指令最终获得的目标标号就是当B为假时控制流应该转向的指令的标号。
为了处理跳转指令的列表我们构造了三个函数
上述的布尔表达式将被翻译成两条跳转指令。两条跳转指令的标号都不填写因为这两条跳转指令的标号都在等待回填,因此我们要把它放到相应的列表中。
第一条跳转指令的目标标号是B的真出口,因此我们把它放到B.truelist中。调用makelist函数生成一个只包含nextquad的列表,并把这个列表的指针赋值给truelist,这里的nextquad是指即将生成的下一条指令的标号,即gen('if' E1.addr relop E2.addr'goto_')这条指令的标号。
第二条跳转指令的目标标号是B的假出口,因此把这条跳转指令存放到B.falselist中。因此我们调用makelist函数生成一个只包含nextquad+1这样一个标号的列表,nextquad+1标号就是gen('goto_')这条指令的标号。
这样的话我们就将这两条指令分别放入到B.truelist和B.falselist中。
问:list中存的是对应跳转指令的标号?
当B定义为true时,此时可以确定布尔表达式的值为真,生成一条跳转到B的真出口的一条指令。由于此真出口的标号不能确定有待回填,我们把它放入到B.truelist中。
当B定义为false时,此时可以确定布尔表达式的值为假,生成一条跳转到B的假出口的一条指令。由于此真出口的标号不能确定有待回填,我们把它放入到B.falselist中。
对B的翻译与其对应的子表达式B1的翻译是相同的,因此B的属性值等于B1的属性值。
B的值与B1的值正好相反,因此将两个非终结符的属性进行对调。
B1.truelist中的这些指令都要跳转到B1的真出口,当B1为真的时候整个表达式的值就是为真的,因此B1的真出口就是B的真出口。要跳转到B1的真出口就是跳转到B的真出口,因此B1.truelist中的指令都要放到B.truelist中。
B2.truelist的指令都要跳转到真出口,当B2为真时整个表达式的值也为真,因此B2的真出口就是B的真出口。要跳转到B2的真出口就是要跳转到B的真出口,因此B2.truelist中的指令都要放到B.truelist中。
B1.falselist中的指令它们都是要跳转到B1的假出口,当B1的值为假的时候我们要进一步判断B2的值,因此B1的假出口就是B2的第一条指令,因此B1.falselist中的指令都要跳转到B2的第一条指令。
B2.falselist中的指令都要跳转到B2的假出口,当B2的值为假的时候那么整个布尔表达式的值也是假的。因此B2的假出口就是B的假出口,要跳转到B2的假出口也就是要跳转到B的假出口。B2.falselist中的指令都要放置到B.falselist中。
根据此示意图可以看出,在分析B2之前,要用B2的第一条指令的标号来回填B1.falselist中的各条指令。当然我们可以记录下B2的第一条指令的标号在归约时完成此回填动作。为了记下B2第一条指令的标号我们在非终结符B2之前插入一个标记非终结符M。与M关联的语义动作它的任务就是记录下B2的第一条语义动作的标号。我们给M设置一个综合属性quad,M.quad等于下一条指令的标号。因为我们把M放在B2之前,因此M.quad记录的是第二条指令的标号。根据翻译方案示意图,我们要用M.quad来回填B1.falselist中的各条指令,因此调用backpatch用M.quad回填B1.falselist中的各条属性。B.truelist是由B1.truelist和B2.truelist合并而成的,因此我们调用merge函数将B1.truelist和B2.truelist进行合并,将合并后的指针赋值给B.truelist。
注:因为这里我们定义的都是综合属性,从左向右扫描输入串。makelist函数生成一个只包含下一条指令的列表,并把指针赋值给B.trulist。我们假设下一条指令从100开始。gen(‘if ’ E 1 .addr relop E 2 .addr ‘goto _’)中E1.address等于a,relop就是小于号,E2.address等于b,引号中的字符串按字面值传递。下划线表示待回填的目标标号。
注:将栈顶中的空串归约成一个标记非终结符M
注:有四条指令是等待回填的,在B的truelist中有两条指令100和104,当B的真出口确定以后我们将用B的真出口的标号这两条指令。同理当B的假出口确定以后将会用B的假出口的标号回填此两条指令。
㈦ 什么是中间代码
是说编译后生成的中间代码吗?
简单说就是一种你看不懂,电脑也看不懂的代码。
打比方,你会说中文,另缺戚一个人会说英文,如果想要他听懂你说的话,就要伏老陵有一个懂英含瞎文又懂中文的人来翻译,中间代码就是这样一个角色,他把C语言翻译成计算机可以直接识别的语言,其实,计算机是看不懂C语言的,呵呵,整个翻译过程有些复杂就不详细说了。
㈧ 编译过程中,源程序为什么要通过中间代码生成目标程序
源程序是指程序员编写的代码,可以被编译程序编译为目标程序。
如果是c++,那么后缀为.cpp
目标程序是编译程序将源程序编译后的结果,如果是c++,那么后缀是.o
编译程序一般是编译器公司(比如微软
intel他们都生产编译器)做的,它将源代码转化为机器可识别的文件,经过链接,生成可执行程序。
解释程序即解释器,它不需要经过编译阶段即可根据用户源程序执行。
程序语言分编译类和解释类语言。
㈨ 有的编译程序中可能没有生成中间代码
在这部分内容中,我们主要讨论各类语句的翻译,包括辩指物声明语逗肢句、赋值语句、控制语句等。对这些语句的翻译方法携液直接决定了编译器底层的实现。
㈩ C# 为什么要弄成中间代码
1、因为c语言也不能说真正的跨平台,只是这种语言比较低级,各个平台的实现相对一致。
c语言的东西下载时还是会分平台的,比如for linux, for windows, for Mac等,不同平台的编译器对c的解释都有差异,所以只能说跨平台容易一些。
2、按微软的规划,以后的应用程序要从网上付费下载来使用,这样就带来下载软件的安全与否的问题,而C#经编译后形成的是中间代码,不可以在本地机器上直接执行,必须经过CLR转换成本地代码后才能执行。
这样,中间码可以顺利通过防火墙,而且安全性又有CLR来保证。