实验五-编译-用语法制导方式生成中间代码生成器

合集下载

第5章语法制导翻译技术和中间代码生成精品PPT课件

第5章语法制导翻译技术和中间代码生成精品PPT课件

29.11.2020 编 译 原 理
4 воскресенье, 29 ноября 2020 г.
语义分析的任务
根据语义规则对识别出的各种语法成分析其含义, 进行初步翻译,生成相应的中间代码或直接生成目 标代码。
第一,审查每个语法结构的静态语义,即检查语法结构合法 的程序是否真正有意义。也称静态语义检查。(类型检查、 控制流的检查、一致性检查、相关名字的检查) 第二,如果静态语义正确,语义处理则要执行真正的翻译, 要么生成中间代码,要么生成实际的目标代码。(说明性语 句:填符号表;可执行性语句:生成中间代码)
• V:属性的有穷集合;每一个属性与某一个文法符号 相关联;用文法符号·属性表示
• E:表示属性的断言或谓词的有穷集合(语义规则); 每一个断言与文法的某个产生式相关联)
• 属性:综合属性(自下而上传递信息)、继承属性(
自上而下传递信息)
29.11.2020 编 译 原 理
9 воскресенье, 29 ноября 2020 г.
(2)翻译方案(自顶向下):
在产生式右部的适当位置,插入相应的语义动作,按照分 析的进程,执行遇到的语义动作。这是一种动作与分析交 错的实现方案。
29.11.2020 编 译 原 理
13 воскресенье, 29 ноября 2020 г.
翻译步骤
(1)分析输入符号串,建立分析语法树 (2)从分析树得到描述结点属性间依赖关系的依赖图,由 依赖图得到语义规则的计算次序 (3)进行语义规则的计算,得到翻译结果
区别和特点 4. 明确生成中间代码的目的,中间代码的几
种形式
29.11.2020 编 译 原 理
2 воскресенье, 29 ноября 2020 г.

编译原理中间代码生成

编译原理中间代码生成

编译原理中间代码生成在编译原理中,中间代码生成是编译器的重要阶段之一、在这个阶段,编译器将源代码转换成一种中间表示形式,这种中间表示形式通常比源代码抽象得多,同时又比目标代码具体得多。

中间代码既能够方便地进行优化,又能够方便地转换成目标代码。

为什么需要中间代码呢?其一,中间代码可以方便地进行编译器优化。

编译器优化是编译器的一个核心功能,它能够对中间代码进行优化,以产生更高效的目标代码。

在中间代码生成阶段,编译器可以根据源代码特性进行一些优化,例如常量折叠、公共子表达式消除、循环不变式移动等。

其二,中间代码可以方便地进行目标代码生成。

中间代码通常比较高级,比目标代码更具有表达力。

通过中间代码,编译器可以将源代码转换成与目标机器无关的形式,然后再根据目标机器的特性进行进一步的优化和转换,最终生成目标代码。

中间代码生成的过程通常可以分为以下几步:1.词法分析和语法分析:首先需要将源代码转换成抽象语法树。

这个过程涉及到词法分析和语法分析两个步骤。

词法分析将源代码划分成一个个的词法单元,例如标识符、关键字、运算符等等。

语法分析将词法单元组成树状结构,形成抽象语法树。

2.语义分析:在语义分析阶段,编译器会对抽象语法树进行静态语义检查,以确保源代码符合语言的语义规定。

同时,还会进行类型检查和类型推导等操作。

3.中间代码生成:在中间代码生成阶段,编译器会将抽象语法树转换成一种中间表示形式,例如三地址码、四元式、特定的中间代码形式等。

这种中间表示形式通常比较高级,能够方便进行编译器的优化和转换。

4.中间代码优化:中间代码生成的结果通常不是最优的,因为生成中间代码时考虑的主要是功能的正确性,并没有考虑性能的问题。

在中间代码生成之后,编译器会对中间代码进行各种优化,以产生更高效的代码。

例如常量折叠、循环优化、死代码删除等等。

5.中间代码转换:在完成了中间代码的优化之后,编译器还可以对中间代码进行进一步的转换。

这个转换的目的是将中间代码转换成更具体、更低级的形式,例如目标机器的汇编代码。

最新 编译原理语法制导翻译和中间代码生成

最新 编译原理语法制导翻译和中间代码生成
9
8.4中间代码
概述
何谓中间代码( Intermediate code) (Intermediate representation) (Intermediate language)
是源程序的一种内部表示 复杂性介于源语言和目标机语言之间
中间代码的作用:
使编译程序的逻辑结构更加简单明确 利于进行与目标机无关的优化 利于在不同目标机上实现同一种语言
12
The definition of postfix notation

the postfix notation for the expression a+b*c is abc*+. the expression are as follows:
1 The order of operands for expression in postfix notation is same with its original order. 2 Operator follows its operand, and there are no parentheses in postfix notation. 3 The operator appears in the order by the calculation order.
中间代码的形式:
逆波兰式、四元式、三元式、间接三元式、树
10
例 ; A + B * ( C - D ) + E / ( C - D ) ^N 逆波兰 A B C D - * + E C D – N ^ / + 四元式 (1) ( C D T1 T1 ) T2)
(2) ( * B (3) ( + A (4) ( C
T2 T3) D N T5 T6 T4) T5) T6) T7)

第5章语法制导翻译技术和中间代码生成

第5章语法制导翻译技术和中间代码生成

编译原理
2024年8月7日
25
逆波兰表示法(后缀式)
特点:运算符直接写在其运算对象之后。 • 不再有括号 • 运算对象出现的次序未变 • 求值过程简单,宜于用栈实现
后缀式的计算 用一个栈实现。 一般的计算过程是:自左至右扫描后缀式,每碰 到运算量就把它推进栈。每碰到k目运算符就把 它作用于栈顶的k个项,并用运算结果代替这k 个项。
④相关名字检查。有的语言中有时规定,同一名字 必须出现两次或多次。例如,Ada语言中,循环或程 序块可以有一个名字,它出现在这些结构的开头和结 尾,如同语句括号一般,编译程序必须检查它们的配 对情况。
编译原理
2024年8月7日
6
5.2 属性文法
附加了一组语属义性信和息运算(语义)规则的文法
1. 属性的表示
3
语义分析的任务
根据语义规则对识别出的各种语法成分析其含义, 进行初步翻译,生成相应的中间代码或直接生成目 标代码。
第一,审查每个语法结构的静态语义,即检查语法结构合法 的程序是否真正有意义。也称静态语义检查。(类型检查、 控制流的检查、一致性检查、相关名字的检查) 第二,如果静态语义正确,语义处理则要执行真正的翻译, 要么生成中间代码,要么生成实际的目标代码。(说明性语 句:填符号表;可执行性语句:生成中间代码)
编译原理
2024年8月7日
12
翻译步骤
(1)分析输入符号串,建立分析语法树 (2)从分析树得到描述结点属性间依赖关系的依赖图,由 依赖图得到语义规则的计算次序 (3)进行语义规则的计算,得到翻译结果
输入符号串 分析树 执行语义规则
翻译结果
编译原理
2024年8月7日
13
语法制导定义

中间代码生成实习指导

中间代码生成实习指导

中间代码生成实习指导编译器里核心的数据结构之一就是中间代码(Intermediate representation,简称IR)。

中间代码应当包含哪些信息,这些信息又应当有怎样的内部表示将会极大地影响到编译器的代码复杂程度、编译器的运行效率以及编译出来的目标代码的运行效率。

广义地说,编译器中根据输入程序所构造出来的绝大多数结构都被称为中间代码(或者更精确地译作“中间表示”)。

例如,我们之前所构造的词法流、语法树、带属性的语法树等等,都可以看作是一种中间代码。

使用中间代码的主要原因当然是为了方便我们在编程时的各种操作,毕竟如果我们在需要有关输入程序的任何信息时都只能重新去读入并处理输入程序的源代码的话,不仅会使得编译器的编写变得麻烦,也会大大减慢其运行效率。

况且经过前面两次实习我们都应该清楚,输入程序里包含的绝大部分编译器需要的信息都没有被显式地表达出来。

狭义地说,中间代码是编译器从源语言到目标语言之间采用的一种过渡性质的代码形式(这时它常被称作intermediate code)。

看到这里你可能会产生疑问:为什么编译器不能直接把输入程序直接翻译成目标代码,而是要额外地多一道手续,引入中间代码呢?这难道不是自己给自己找麻烦吗?实际上,引入中间代码有两个主要的好处:一方面,中间代码将编译器自然地分成了前端和后端两个部分。

当我们需要改变编译器的源语言或者目标语言时,如果采用中间代码,那么我们只需要替换原有编译器的前端或者后端,而不需要重写整个编译器。

另一方面,即使源语言和目标语言是固定的,采用中间代码也有利于编译器的模块化。

人们将编译器设计中的那些复杂但相关性又不是很大的任务分别放在前端和后端的各个模块之中,这样既简化了模块内部的处理,又使得我们能单独对每个模块进行调试与修改而不影响到其它模块。

下文中,如果不是特别说明,那么所有出现的“中间代码”都指的是本段所介绍的狭义的中间代码。

中间代码的分类中间代码的设计可以说更多的是一门艺术而不是技术。

精品课程编译原理-PPT课件第8章 语法制导与中间代码生成

精品课程编译原理-PPT课件第8章  语法制导与中间代码生成

(3)一致性检查。在很多场合要求对象只能被 定义一次。例如Pascal语言规定同一标识符在一 个分程序中只能被说明一次,同一case语句的标 号不能相同,枚举类型的元素不能重复出现等等。
(4)上下文相关性检查。比如,变量名字必 须先声明后引用;
(5)名字的作用域分析。各变量的作用域可 能是不一样的,要通过分析明确各变量的作用域。
例子: a:=b*c+b*d的相应三元组
①(*, b, c) b*c ②(*, b, d) b*d ③(+, (1),(2)) b*c+b*d ④(:=,(3), a) a:=b*c+b*d
例子:tri(A*B+C) =tri(A*B)||tri(c)||2:(+,①≥,C) =1:(*, A,B) A*B 2:(+,①,C) A*B+C
8.2.2 S-属性文法和自下而上翻译 一般的属性文法的翻译器很难建立,然 而L-属性文法的翻译器很容易建立。
L-属性文法的一个特例叫S-属性文法。 S-属性文法是只含有综合属性的属性文法。
8.2.3 L-属性文法在自下而上分析中实现 L-属性文法允许一次遍历就计算出所以的 属性值。
8.3 中间代码的形式
3*5+6的带注释的分析树
只使用综合属性.
T.val=3 F.val=3
E.val=15 T.val=15
*
L
E.val=21
+
F.val=5
T.val=6 F.val=6 digit.lexval=6
digit.lexval=5
digit.lexval=3
3*5+6的带注释的分析树
继承属性
一个结点的继承属性值是由此结点的父结点和/或兄弟结 点的某些属性来决定的。

中间生成代码实验报告(3篇)

中间生成代码实验报告(3篇)

第1篇一、实验目的本次实验旨在通过编写中间生成代码,加深对编译原理中中间代码生成过程的理解,掌握中间代码的表示方法、生成算法以及优化技术,并能够将高级语言翻译成相应的中间代码。

二、实验环境1. 操作系统:Windows 102. 编程语言:Java3. 开发工具:Eclipse三、实验内容1. 中间代码表示方法(1)选择中间代码表示方法:本次实验选择四元式作为中间代码的表示方法。

(2)定义四元式结构:四元式由四个字段组成,分别为操作符(OP)、操作数1(ARG1)、操作数2(ARG2)和结果(RESULT)。

2. 中间代码生成算法(1)选择源语言:以C语言为例,编写一个简单的C程序。

(2)编写分析器:对C程序进行词法分析、语法分析,生成抽象语法树(AST)。

(3)遍历AST:根据AST的结构,生成相应的中间代码。

(4)中间代码优化:对生成的中间代码进行优化,提高程序执行效率。

3. 实验步骤(1)创建Java项目,导入必要的库。

(2)编写词法分析器:识别C语言中的关键字、标识符、运算符、常数等。

(3)编写语法分析器:根据词法分析器的结果,构建抽象语法树(AST)。

(4)遍历AST:根据AST的结构,生成四元式中间代码。

(5)中间代码优化:对生成的中间代码进行优化。

(6)生成目标代码:将优化后的中间代码翻译成目标代码。

四、实验结果与分析1. 中间代码表示方法(1)四元式表示方法:本次实验采用四元式表示中间代码,具有以下特点:- 结构简单,易于理解。

- 便于优化。

- 可用于多种目标代码生成。

(2)四元式示例:```OP = ADDARG1 = t1ARG2 = t2RESULT = t3```2. 中间代码生成算法(1)词法分析器:识别C语言中的关键字、标识符、运算符、常数等。

(2)语法分析器:构建抽象语法树(AST),表示C程序的结构。

(3)遍历AST:根据AST的结构,生成四元式中间代码。

(4)中间代码优化:对生成的中间代码进行优化,提高程序执行效率。

编译原理第7章 语法制导翻译和中间代码生成

编译原理第7章  语法制导翻译和中间代码生成
语义规则描述的动作:
• 检查静态语义 • 生成中间代码/目标代码
语义处理
语义处理的环境:符号表 • 为语义分析提供类型、作用域等信息。 • 为代码生成提供类型、作用域、存储类别、
存储(相对)位置等信息。
语义处理
PL/0编译程序的语义处理(一)call语句的处理
if sym = callsym
then
源语言程序
词法分析

语法分析

处理Biblioteka 语义分析语 义 处 理
后 端
代码生成


汇编代码
语义处理
语义处理的任务: • 静态语义检查
• 静态语义:语法规则的良形式条件 • 静态语义检查:审查静态语义
• 动态语义处理
• 动态语义:程序单元执行的操作 • 动态语义处理:生成(中间/目标)代码
语义处理
语义处理的实现: • 属性文法:描述语义规则。 • 语法制导翻译:在语法分析的同时,执行
类型的基本概念
声明和定义,使用: • 声明:
• 程序通过声明语句把标识符的名称、类型和 作用域等信息传递给编译器。
• 声明语句本身传递名字和类型信息,声明语 句的位置传递作用域信息。
• 定义:
• 变量、类的声明就是定义。 • 函数可以先声明一个原型,在定义中再给出
实现的代码。
类型的基本概念
强类型语言和弱类型语言: • 强类型语言
第七章语法制导翻译和中间代码生成
7.1语义处理概述 7.2属性文法和语法制导翻译 7.3 中间代码生成(一些语句的翻译) 7.4符号表
7.1 语义处理(语义分析和中间代码生成)
在编译中的逻辑阶段
源语言程序
词法分析
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

。 -可编辑修改- 实验5 用语法制导方式生成中间代码生成器 一、实验目的 掌握语法制导定义和翻译的原理和技术,在语法分析器的基础上,加上语义分析,构造一个中间代码生成器。 二、实验内容 在实验四生成的语法分析器基础上加入语义动作,将源程序翻译为对应的中间代码序列。

三、实验要求 1. 个人完成,提交实验报告。实验报告必须包括设计的思路,以及测试报告(输入测试例子,输出结果)。 2. 实验报告中给出采用测试源代码片断,及其对应的三地址码形式(内部表示形式可以自行考虑)。 例如,程序片断 。

-可编辑修改- 对应的中间代码为:

四、实验过程 本次实验运用flex和bison工具进行中间代码的生成。并自动生成中间代码。 1. 首先创建一个example文件夹,该文件夹中包含有flex.exe 2. 用文本编译器编辑相应的flex文件mylex.l,此次mylex.l可以在上次实验的l文件上做一些修改,再利用flex将l文件生成相应的lex.yy.c程序,mylex.l的代码如下所示: mylex.l 。 -可编辑修改- %{ #include "myyacc.tab.h" %} delim [ \t\n\r] ws {delim}+ letter [A-Za-z] digit [0-9] id {letter}({letter}|{digit})* integer {digit}+ exponent E[+-]?{integer} number {integer}{exponent}? real integer(\.integer)?{exponent}? %option noyywrap %% "<"|"<="|">"|">="|"!="|"==" { filloperator(&yylval, yytext); return( REL); } if { return( IF ); } else { return( ELSE ); } while { return( WHILE ); } do { return( DO ); } for { return( FOR ); } switch { return( SWITCH ); } 。 -可编辑修改- case { return( CASE ); } default { return( DEFAULT ); } break { return( BREAK ); } true { return( TRUE ); } false { return( FALSE ); } int { return( INT ); } long { return( LONG ); } char { return( CHAR ); } bool { return( BOOL ); } float { return( FLOAT ); } double { return( DOUBLE ); } "&&" { return( AND ); } "||" { return( OR ); } "!" { return( '!'); } "++" { return( INC ); } "--" { return( DEC ); } "+" { return( '+' ); } "-" { return( '-' ); } "*" { return( '*' ); } "/" { return( '/' ); } "=" { return( '=' ); } "{" { return( '{' ); } 。 -可编辑修改- "}" { return( '}' ); } "[" { return( '[' ); } "]" { return( ']' ); } "(" { return( '(' ); } ")" { return( ')' ); } ";" { return( ';' ); } {ws} { } {id} { filllexeme(&yylval, yytext); return( ID ); } {number} { filllexeme(&yylval, yytext); return( NUMBER ); } {real} { filllexeme(&yylval, yytext); return( REAL ); } %% 在代码中,先定义正则定义,即对letter,digit,专用符号, 空格进行声明;接着在转换规则中,定义一些识别规则的代码。 完成词法分析后,就可以将获取的每一个词素用于语法分析器使用。 将mylex.l与myyacc.y相结合的方法是在每获得一个词素,则用return语句返回,即如果获得的是if,则return(if),并且在头文件中加入#include "myYacc.tab.h",则在myyacc中定义的类型在mylex中可利用,否则会出现返回的单元未定义的错误。 3. 用文本编译器编辑相应的bison文件myyacc.y,myyacc.y文件中,在每个生成式后加上语法制导翻译,主要是依据truelist和falselist来实现回填功能。编写完后,在myyacc.y中以头文件的方式加入自己编写的myyacc.h文件,编译即可。Myyacc.y的代码如下所示: 。 -可编辑修改- Myyacc.y %{ #include "myyacc.h" #define YYSTYPE node #include "myyacc.tab.h" int yyerror(); int yyerror(char* msg); extern int yylex(); codelist* list; %} %token BASIC NUMBER REAL ID TRUE FALSE %token INT LONG CHAR BOOL FLOAT DOUBLE %token REL %token IF ELSE WHILE DO BREAK FOR SWITCH CASE DEFAULT %token OR AND %left OR %left AND %right '!' %left '+' '-' %left '*' '/' %right UMINUS %right INC DEC 。 -可编辑修改- %% program : block { } ; block : '{' decls statementlist '}' { } ; decls : decls decl { } | { } ; decl : type ID ';' { } ; type : type '[' NUMBER ']' { } | BASIC { } ; statementlist : statementlist M statement { backpatch(list, $1.nextlist, $2.instr); $$.nextlist = $3.nextlist; } | statement { $$.nextlist = $1.nextlist; } ; Statement : IF '(' boolean ')' M statement ELSE N M statement { backpatch(list, $3.truelist, $5.instr); backpatch(list, $3.falselist, $9.instr); $6.nextlist = merge($6.nextlist, $8.nextlist); 。 -可编辑修改- $$.nextlist = merge($6.nextlist, $10.nextlist); } | IF '(' boolean ')' M statement { backpatch(list, $3.truelist, $5.instr); $$.nextlist = merge($3.falselist, $6.nextlist); } | WHILE M '(' boolean ')' M statement { backpatch(list, $7.nextlist, $2.instr); backpatch(list, $4.truelist, $6.instr); $$.nextlist = $4.falselist; gen_goto(list, $2.instr); } | DO M statement M WHILE '(' boolean ')' M ';' { backpatch(list, $3.nextlist, $4.instr); backpatch(list, $7.truelist, $9.instr); $$.nextlist = $7.falselist; gen_goto(list, $2.instr); } | FOR '(' assignment ';' M boolean ';' M assignment ')' N M statement { backpatch(list, $6.truelist, $12.instr); backpatch(list, $11.nextlist, $5.instr); backpatch(list, $13.nextlist, $8.instr); $$.nextlist = $6.falselist; gen_goto(list, $8.instr); } | BREAK ';' { } | '{' statementlist '}' { $$.nextlist = $2.nextlist; }

相关文档
最新文档