语义分析及中间代码生成程序设计原理与实现技术--实验报告及源代码北京交通大学

合集下载

语义分析与中间代码生成

语义分析与中间代码生成
F.node:= E.node
⑻ F → id
F.node := mkleaf(id, id.entry)
⑼ F → num
F.node := mkleaf(num, num.val)
*
生成dag的语法制导定义
*
7.2 声明语句的翻译
声明语句的作用 为程序中用到的变量或常量名指定类型 类型的作用 类型检查:类型检查的任务是验证程序运行时的行为是否遵守语言的类型的规定,也就是是否符合该语言关于类型的相关规则。 辅助翻译:编译器从名字的类型可以确定该名字在运行时所需要的存储空间。在计算数组引用的地址、加入显式的类型转换、选择正确版本的算术运算符以及其它一些翻译工作时同样需要用到类型信息。 编译的任务 在符号表中记录被说明对象的属性(种别、类型、相对地址、作用域……等) ,为执行做准备
P→MD M→ {offset := 0 }
*
7.2.4 过程内声明语句的翻译
*
enter(x,real,0)
offset=0
offset=8
T.type=real T.width=8
offset=12
T.type=integer T.width=4
enter(i,integer,8)
D→id : T {enter( , T.type, offset ); offset := offset + T.width}
7.2.1 类型表达式
*
*
5.类型构造符record作用于由域名和域类型所形成的表达式也是类型表达式。记录record是一种带有命名域的数据结构,可以用来构成类型表达式。例如,下面是一段Pascal程序段: type row = record address: integer; lexeme: array[1..15] of char end; var table : array [1..10] of row; 该程序段声明了表示下列类型表达式的类型名row: record ((address×integer)×(lexeme×array (1..15, char)))

语义分析和中间代码生成

语义分析和中间代码生成
整理课件
7.1 中 间 语 言
本书常用的三地址语句
• 赋值语句x := y op z, x := op y, x := y
• 无条件转移goto L • 条件转移if x relop y goto L • 过程调用param x 和call p , n • 过程返回 return y • 索引赋值x := y[i]和 x[i] := y • 地址和指针赋值x := &y,x := y和x := y
7.2 说 明 语 句
处理嵌套过程中的说明语句
P M D {addwidth (top (tblptr), top (offset) ); pop(tblptr); pop (offset) }
M {t := mktable (nil); push(t, tblprt); push (0, offset) }
• (3)
x: integer;
• (4)
procedure readarray
• (5)
var i: integer;
• (6)
begin…a…end{readarray}
• (7)
procedure exchange(i,j:integer);
• (8)
begin
• (9)
x:=a[i]; a[i]:=a[j]; a[j]:=x
二维数组 • 列为主
A[1, 1], A[2, 1], A[1, 2], A[2, 2], A[1, 3], A[2, 3]
整理课件
7.3 赋 值 语 句
二维数组 • 列为主
A[1, 1], A[2, 1], A[1, 2], A[2, 2], A[1, 3], A[2, 3] • 行为主

lab14语义分析报告报告材料与中间代码生成

lab14语义分析报告报告材料与中间代码生成

实验报告封面课程名称:编译原理课程代码:SS2027任课老师:彭小娟实验指导老师: 彭小娟实验报告名称:实验十四:语义分析与中间代码生成1学生姓名:学号:教学班:递交日期:签收人:我申明,本报告内的实验已按要求完成,报告完全是由我个人完成,并没有抄袭行为。

我已经保留了这份实验报告的副本。

申明人(签名):实验报告评语与评分:评阅老师签名:彭小娟一、实验名称:语义分析与中间代码生成1二、实验日期: 年 月 日三、实验目的:1. 理解相关概念:中间代码、三地址码,各种语句的目标代码结构2. 掌握三地址码(三元式、四元式、DAG 图),3. 理解赋值语句三地址代码的翻译模式四、实验用的仪器和材料:(操作系统:CPU :内存:硬盘:软件:)硬件:PC 人手一台软件:office五、实验的步骤和方法:1. 给出下面中缀式的逆波兰表示(后缀式),后缀式的中缀式表示/*)(*)/(*++-+-+-++e d c ab d c b a e d c b anot A or not (C or not D)2. 请将表达式-(a+b)*(c+d)-(a+b+c)分别表示成三元式、四元式序列。

3. 按7.3节所说的方法,写出下面赋值句)A+=的自下而上语法制导B-(*:DC翻译过程。

给出所产生的三地址代码。

六、数据记录和计算:七、实验结果或结论:(总结)八、备注或说明:可写上实验成功或失败的原因,实验后的心得体会、建议等。

九、引用参考文献:即在本实验中所引用的之資料。

语义分析与中间代码生成

语义分析与中间代码生成

语法分析程序
ifs( ) { token = getnexttoken(); If(token!="if") error; token= getnexttoken(); bexp(); token = getnexttoken(); If(token!="then") error; token = getnexttoken(); ST_SORT();//调用函数处理then后的可 执行语句 token = getnexttoken(); If(token!= "else") error;
语法分析程序 语法制导的翻译 token = getnexttoken(); { q = nxq; gencode(j, —, —, 0); ST_SORT();//处理else后 backpatch(e.fc, nxq); //已知假出 口e.fc 的可执行语句 t.chain = merg(s1.chain, q); } getnexttoken(token);
语义分析与中间代码生成
实验目的:通过本实验,加深对语法分析 作用的理解,掌ห้องสมุดไป่ตู้语义分析和中间代码生 成的方法并编程实现语义分析以及生成中 间代码!
实验内容:根据语义分析和中间代码生成 的原理,设计并实现实现语义分析以及生 成中间代码!
原理概述
语义分析是以语法分析的结果———语法树为输入,产生 与源程序功能等价的中间代码。中间代码的形式可以是三 元式,间接三元式,四元式等。 语义分析的任务包括:(1)静态语义检查:如:类型、 运算、数组维数、越界等的检查;(2)语义的处理:如: 变量的存储分配、表达式的求值、语句的翻译(生成中间 代码) 语义分析可以采用多种分析技术,如语法制导的翻译。语 法制导的翻译实际上就是在语法分析的基础上,当分析完 一个正确的语法单位后,添加相应的语义信息,直接生成 相应的四元式表。因此,本部分的程序可以和语法分析程 序合为一体,在语法分析得到正确的语法成分的基础上, 在适当的位置添加语义成分。

算符优先语法分析设计原理与实现技术实验报告及源代码北京交通大学

算符优先语法分析设计原理与实现技术实验报告及源代码北京交通大学

算符优先语法分析设计原理与实现技术XXX 1028XXX 计科1XXX 班功能描述能够有效识别以下算符优先文法E T E+T | E-TT T T*F | T/F | FF T (E) | i所描述算术表达式.主要数据结构描述程序结构描述设计方法2. 根据算符优先矩阵算数表达式的词法分析结果进行语法分析,分析算法为:数据结构:符号栈S ---存放所有读进的符号(计数i)K ---符号栈使用深度a ---工作单元R, Q ---变量分析算法:先找最左素短语的尾部(>)再找最左素短语的头部(<)以分析表达式i+i*i为例,详细过程如下:■算符优先关系矩阵例:舖入串i+i*i 的界苻优先分析过程(査界替优先关系矩体)1#N + N**<i■11# N + N*'■ 1#1#N + N J* N+<*># 接受# N + N#<+>## N结论:汁详iJt 文法的命法句子函数原型功能描述void in it()各种初始化操作,主要是建立符号与整 数、整数与行列号、整数与符号之间的映 射,也包括各全局变量的初始化void isVt(i nt )判断某整数所代表的符号是否是终结符##<i# i#<i>-l- #N#<+# N + +<i# N + i +<i>* # N+ N+<*分析栈优先关系号或’#'void comp(i nt a, int b) r比较两整数所代表的字符的优先关系—void adva nce() 从输入文件中读入一个词bool parser() 算符优先分析函数,根据算符优先矩阵进行语法分析int main (i nt argc, char *argv[]) 主函数,参数argv[1]代表输入文件函数调用关系程序执行图S(l)=#;i=l;k=Q;k~k+1: R=siiLrQ=SG); j=j-ij=j-i l| t=i 11i=讦丄;S(i)=R程序测试测试用例一:(a+b*c)+d+e+a*c/b 首先调用实验一的词法分析程序,得到如下分析结果:(19, '(')(12, 'a')(14, '+')(12, 'b')(16, '*')(12, 'c')(20, ')')(14, '+')(12, 'd')(14, '+')(12, 'e')(14, '+')(12, 'a')(16, '*')(12, 'c')(17, '/')(12, 'b')在以此分析结果作为本程序实验结果的输入,得到如下分析结果:taw Cf'v/indov^5\system32\cmd.exe该结果显示了详细的分析过程,且表明该表达式是一个符合该文法的表达式测试用例二:(a+b*c)+d*-a*c+(a+b同样调用实验--的词法分析程序,得到如下结果:(19, '(')(12, 'a')(14, '+')(12, 'b')(16, '*')(12, 'c')(20, ')')(14, '+') (12, 'd') (16, '*') (15, '-') (12, 'a') (16, '*') (12, 'c') (14, '+') (19, '(') (12, 'a') (14, '+') (12, 'b')以此分析结果作为本实验程序的输入,得到如下语法分析结果:实验结果表明,在分析过程中出现了错误,分析过程未完成,该样例是一个非法的表达式.学习总结按算符优先关系所确定的应被规约的子串恰好是当前举行的最左素短语.尽管算符优先分析也属于自底向上语法分析的范畴,但却不是严格的从左至右的规范分析,每步所得的句型自然也不是一个规范句型.采用上述策略进行算符优先分析时,尽管我们也指出了每一最左素短语应规约到的非终结符号,然而每次在查找最左素短语时,起主导作用的是终结符号间的优先关系,两终结符号之间究竟是哪个非终结符号无关宏旨.// operator_prior.cpp : Defines the entry point for the console application.//#include "stdafx.h"#include <stdio.h>#include <ctype.h>#include <map>#include <vector>#include <string>#define ID 12#define ADD 14#define SUB 15#define MUL 16#define DIV 17#define LP 19#define RP 20#define EOI 31#define SHARP 32#define EQ 0#define BT 1#define LT 2#define UD 3#define N_Base 1000 using namespace std;FILE *fp;int lookahead, yylineno;bool success;map<int, int> intToint; map<char, int> charToint; map<int, char> intTochar; string grammer[8] = {"E+T", "E-T", "T","T*F", "T/F", "F","(E)", n:n};int prior_matrix[9][9] = {{BT, BT, LT, LT, LT, BT, LT, BT},{BT, BT, LT, LT, LT, BT, LT, BT},{BT, BT, BT, BT, LT, BT, LT, BT},{BT, BT, BT, BT, LT, BT, LT, BT},{LT, LT, LT, LT, LT, EQ, LT, UD},{BT, BT, BT, BT, UD, BT, UD, BT},{BT, BT, BT, BT, UD, BT, UD, BT},{LT, LT, LT, LT, LT, UD, LT, EQ}};void init() {success = true;yylineno = 0;intToint[ADD] = 0; intToint[SUB] = 1;intToint[MUL] = 2; intToint[DIV] = 3;intToint[LP] = 4; intToint[RP] = 5;intToint[ID] = 6; intToint[SHARP] = 7;charToint['+'] = ADD; charToint['-'] = SUB;charToint['*'] = MUL; charToint['/'] = DIV;charToint['('] = LP; charToint[')'] = RP;charToint['i'] = ID;intTochar[ADD] = '+'; intTochar[SUB] = '-';intTochar[MUL] = '*'; intTochar[DIV] = '/';intTochar[LP] = '('; intTochar[RP] = ')';intTochar[ID] = 'i'; intTochar[SHARP] = '#';intTochar[N_Base] = 'N';}bool isVt(int a) {if (a >= N_Base) return false;else return true;}int comp(int a, int b) { int x = intToint[a];int y = intToint[b]; return prior_matrix[x][y]; }void advance() {if (fscanf(fp, "(%d", &lookahead) == EOF) { lookahead = SHARP;} else {char ch;do {ch = fgetc(fp);if (ch == '\n' || ch == EOF) break; } while (true);} yylineno++;}void parser() {int stack[100], top = 0;int i, j, k, ii, jj;stack[top++] = SHARP;advance();do {for (i = 0; i < top; i++) {printf("%c", intTochar[stack[i]]);}printf("\t%c\n", intTochar[lookahead]);for (i = top - 1; i >= 0; i--) { if (isVt(stack[i])) break;}int res = comp(stack[i], lookahead);if (res == LT || res == EQ) { stack[top++] = lookahead; advance();} else if (res == BT) {int temp = stack[i]; for (j = i - 1; j >= 0; j--) {if (isVt(stack[j])) {if (comp(stack[j], temp) == LT) {break;} else {temp = stack[j];}}}for (k = 0; k < 8; k++) {if ((int)grammer[k].length() == top - 1 - j) {ii = j + 1;jj = 0;do {if (grammer[k].at(jj) >= 'A' && grammer[k].at(jj) <= 'Z'){ if (isVt(stack[ii])) break;} else {if (charToint[grammer[k].at(jj)] != stack[ii]) break;}ii++;jj++;} while (ii < top && jj < (int)grammer[k].length());if (ii >= top) break;}}if (k >= 8) {success = false;return ;}top = j + 1;stack[top++] = N_Base;} else {success = false;return ;}if (stack[0] == SHARP && stack[1] == N_Base&& stack[2] == SHARP) { printf("#N#\n"); break;}} while (true);success = true;}int main(int argc, char *argv[]) {if (argc == 2) {fp = fopen(argv[1], "r");init();parser();if (success) printf("This is a legal expression."); else printf("Thisis a illegal expression.");} else {printf(" 参数错误!\n");}return 0;。

《编译原理教程》第四章语义分析和中间代码生成

《编译原理教程》第四章语义分析和中间代码生成

控制流分析和数据流分析案例
总结词
控制流分析和数据流分析是编译器设计中两种重要的 语义分析技术。
详细描述
在控制流分析案例中,我们以一个具有条件语句和循环 的程序为例,分析其控制流图(Control Flow Graph, CFG)。CFG是一个有向图,用于表示程序中各个基本块 之间的控制流程关系。通过CFG,编译器可以检测到潜 在的程序错误,如死代码和无限循环。在数据流分析案 例中,我们使用数据流方程来跟踪程序中变量的值在执 行过程中的变化。我们以一个简单的程序为例,该程序 包含一个变量在函数调用后被修改的情况。通过数据流 分析,我们可以确定变量的最新值,以便在后续的语义 分析中使用。
定义
三地址代码是一种中间代码形式,它由一系列的三元组操作数和 操作符组成。
特点
三地址代码具有高度规范化,易于分析和优化,且易于转换成目 标代码。
常见形式
常见的三地址代码有三种基本形式,即加法、减法和赋值。
循环优化
定义
循环优化是指在编译过程中,对循环结构进行优化, 以提高目标代码的执行效率。
常见方法
将源程序分解成一个个的词素或标记。
语法分析
根据语言的语法规则,将词素或标记组合成一个个的语句或表达式。
语义分析
对语法分析得到的语句或表达式进行语义检查,确保其语义正确。
中间代码生成
基于语义分析的结果,生成中间代码。
02
语义分析技术
类型检查
类型检查是编译过程中对源代码进行语义分析的重要环节,其主要目的是 确保源代码பைடு நூலகம்类型安全。
常见的循环优化方法包括循环展开、循环合并、循环 嵌套等。
优化效果
通过循环优化,可以减少循环的次数,提高程序的执 行效率。

语义分析与中间代码生成

语义分析与中间代码生成
cout<<"输入串\t\t 符号栈\t 语义栈\t 生成四元式\t"<<endl;
char ch;
char subInput;
do {
string sbSym,sbSem,sbTag3;
char sbTag1,sbTag2;
if (IsVT(stSymbol[top]) == 1)
i = top ;
for(int j=0; j<= top; j++){
sbSym += stSymbol[j];//栈中内容
sbSem += stSemantic[j];
}
string temp;
temp = Action(stSymbol[i],sbTag1,sbTag2,i,sbTag3);
cout<<setw(10)<<input<<setw(12)<<sbSym<<setw(16)<<sbSem<<setw(16)<<temp<<endl;
(3)E→E-Temit(-,E.place,T.place,E.place);
(4)T→T*Femit(*,T.place,F.place,T.place);
(5)T→T/Femit(/,T.place,F.place,T.place);
(6)F→P^Femit(^,P.place,F.place,F.place);
实验内容:
可选择LL1分析法、算符优先分析法、LR分析法之一,实现如下表达式文法的语法制导翻译过程。文法G[E]如下所示:
E→E+T | E-T | T

LL(1)语法分析设计原理与实现技术实验 实验报告及源代码 北京交通大学

LL(1)语法分析设计原理与实现技术实验 实验报告及源代码 北京交通大学

LL(1)语法分析设计原理与实现技术实验计科100X班 10284XXX程序设计功能实现LL(1)分析中控制程序(表驱动程序);完成以下描述算术表达式的LL(1)文法的LL(1)分析程序。

G[E]: E→TE′E′→ATE′|εT→FT′T′→MFT′|εF→(E)|iA→+|-M→*|/说明:终结符号i 为用户定义的简单变量,即标识符的定义。

主要数据结构描述由文法可得:对于E:FIRST( E )= {(, i }对于E’: FIRST( E’ ) ={+,−,ε}对于T: FIRST( T )= ={(, i }对于T’: FIRST( T’)= ={*,∕,ε}对于F: FIRST( F )= ={(, i }对于A: FIRST( A )= ={+, - }对于M: FIRST(M)= ={*, / }由此我们容易得出各非终结符的FOLLOW集合如下:FOLLOW( E )= { ),#}FOLLOW(E’) ={ ),#}FOLLOW( T ) ={+,−,),#}FOLLOW( T’ ) = FOLLOW( T ) ={+,−,),#}FOLLOW( F )=FIRST(T’)\ε∪FOLLOW(T’)={*,∕,+,−,),#}FOLLOW( A )= { (, i }FOLLOW( M )= { (, i}文法LL(1)的预测分析表(表1):表1. LL(1)预测分析表注:为编程方便,在程序中,将E’、T’改为G、S程序结构描述1.设计方法:程序通过从文本文档读入数据,将所读数据以空格、回车或者退格为标示符,分为字符串,对字符串进行词法分析,最后将所有字符串按序输出到结果文档中,并在结果文档中标明每个字符串的类别序号。

2、程序中主要函数定义和调用关系如下:函数:void print()作用:输出分析栈void print1();作用:输出剩余串int main();作用:主要逻辑功能程序执行图如下:实验结果测试用例1:i+i*i#测试用例2:i-i++#实验总结相对于递归下降分析法,LL(1)分析法更为有效.采用此种方法的分析器由一张预测分析表(LL(1)分析表)、一个控制程序(表驱动程序)和一个分析栈组成,预测分析表中个元素的含义是:或者指出当前推到所应使用过的产生式,或者指出输入符号串中存在语法错误.LL(1)分析法的局限在于:只能分析LL(1)文法或者某些非LL(1)文法,但需先将其改造成LL(1)文法。

6语义分析与中间代码生成

6语义分析与中间代码生成

D T.type = real L.in = real
real
L.in = real


c.entry
L.in = real
b.entry
a.entry
每一个L结点处都带有继承属性in的分析树
D type T real 4 in L 5 in L , 6
7 9 in L 10 a 1
8 b 2 entry
1、属性文法(syntax-directed definitions): 定义翻译所必须的语义属性和语义规则, 一般不涉及计算顺序。是对上下文无关文法的 推广。
2、翻译模式(translation schemes): 给出语义规则进行计算的顺序。
6.1 语法制导翻译
属性文法(attribute grammar)是在上下文无关文 法的基础上,为文法每个终结符和非终结符配备若干 相关的属性,这些属性代表与文法符号相关信息,
T real
L L1,id L id
T.type :=real
L1.in :=L.in addtype(id.entry, L.in) addtype(id.entry, L.in)
D T.type = real L.in = real L.in = real ,
real
addtype(c.entry, real)
c 3 entry
,
entry
2. 计算顺序 ◆拓扑排序 一个有向非循环图的拓扑排序是图中 结点的任何顺序m1,m2,…,mk,使得 边必须是从序列中前面的结点指向后面的 结点,也就是说,如果mi→mj是mi到mj的 一条边,那么在 序列中mi必须出现在mj的 前面。
D type T real 4 in L 5 in L , 6

语义分析及中间代码生成程序设计原理与实现技术--实验报告及源代码-北京交通大学

语义分析及中间代码生成程序设计原理与实现技术--实验报告及源代码-北京交通大学

语义分析及中间代码生成程序设计原理与实现技术XXX 1028XXX2 计科1XXX班1.程序功能描述完成以下描述赋值语句和算术表达式文法的语法制导生成中间代码四元式的过程。

G[A]:A→V:=EE→E+T∣E-T∣T→T*F∣T/F∣FF→(E)∣iV→i说明:终结符号i 为用户定义的简单变量,即标识符的定义。

2. 设计要求(1)给出每一产生式对应的语义动作;(2)设计中间代码四元式的结构(暂不与符号表有关)。

(3)输入串应是词法分析的输出二元式序列,即某算术表达式“实验项目一”的输出结果。

输出为输入串的四元式序列中间文件。

(4)设计两个测试用例(尽可能完备),并给出程序执行结果四元式序列。

3.主要数据结构描述:本程序采用的是算符优先文法,文法以及算符优先矩阵是根据第四次实验来修改的,所以主要的数据结构也跟第四次差不多,主要为文法的表示,FirstVT集和LastVT集以及算符优先矩阵:算符优先矩阵采用二维字符数组表示的:char mtr[9][9]; //算符优先矩阵4.程序结构描述:本程序一共有8功能函数:void get(); //获取文法void print(); //打印文法void fun(); //求FirstVT 和 LastVTvoid matrix(); //求算符优先矩阵void test(); //测试文法int cmp(char a,char b); 比较两个运算符的优先级 1 0 -1void out(char now,int avg1,int avg2); //打印四元式int ope(char op,int a,int b); //定义四元式计算方法5.实验代码详见附件6.程序测试6.1 功能测试程序运行显示如下功能菜单:选择打印文法:选择构造FirstVt集和LastVT集:选择构造算符优先矩阵:6.2 文法测试测试1:1+2*3测试2:2+3+4*5+(6/2)7.学习总结本次实验完成了语义及中间代码生成的设计原理与实现,所采用的方法为算符优先分析方法,首先根据文法求出此文法的FirstVT集和LastVT集,然后根据他们求出此文法的算符优先矩阵。

编译原理实验四语义分析及中间代码生成

编译原理实验四语义分析及中间代码生成

编译原理实验四语义分析及中间代码⽣成⼀、实验⽬的(1)通过上机实验,加深对语法制导翻译原理的理解,掌握将语法分析所识别的语法范畴变换为某种中间代码的语义翻译⽅法。

(2)掌握⽬前普遍采⽤的语义分析⽅法─语法制导翻译技术。

(3)给出 PL/0 ⽂法规范,要求在语法分析程序中添加语义处理,对于语法正确的表达式,输出其中间代码;对于语法正确的算术表达式,输出其计算值。

⼆、实验内容(1)语义分析对象重点考虑经过语法分析后已是正确的语法范畴,本实验重点是语义⼦程序。

已给 PL/0 语⾔⽂法,在实验⼆或实验三的表达式语法分析程序⾥,添加语义处理部分,输出表达式的中间代码,⽤四元式序列表⽰。

(2) PL/0 算术表达式的语义计算:PL/0 算术表达式,例如:2+35 作为输⼊。

输出: 17PL/0 表达式的中间代码表⽰:PL/0 表达式,例如: a(b+c)。

输出: (+,b,c,t1)(,a,t1,t2)三、设计思想1.原理属性⽂法:是在上下⽂⽆关⽂法的基础上为每个⽂法符号(终结符或⾮终结符)配备若⼲个相关的“值”(称为属性)。

属性:代表与⽂法符号相关的信息,和变量⼀样,可以进⾏计算和传递。

综合属性:⽤于“⾃下⽽上”传递信息。

在语法树中,⼀个结点的综合属性的值,由其⼦结点的属性值确定。

S—属性⽂法:仅仅使⽤综合属性的属性⽂法。

语义规则: 属性计算的过程即是语义处理的过程。

对于⽂法的每⼀个产⽣式配备⼀组属性的计算规则,则称为语义规则。

(1)终结符只有综合属性,它由词法分析器提供。

(2)⾮终结符既可以有综合属性也可以有继承属性,⽂法开始符号的所有继承属性作为属性计算前的初始值。

(3)产⽣式右边符号的继承属性和产⽣式左边符号的综合属性都必须提供⼀个计算规则。

(4)产⽣式左边符号的继承属性和产⽣式右边符号的综合属性由其它产⽣式的属性规则计算。

⼀遍扫描的处理⽅法: 与树遍历的属性计算⽅法不同,⼀遍扫描的处理⽅法是在语法分析的同时计算属性值,⽽不是语法分析构造语法树之后进⾏属性的计算,⽽且⽆需构造实际的语法树。

编译原理系列实验四语义分析与中间代码生成

编译原理系列实验四语义分析与中间代码生成

编译原理系列实验四语义分析与中间代码⽣成最后⼀次实验!⽬录实验四语义分析与中间代码⽣成实验⽬的通过上机实习,加深对语法制导翻译原理的理解,掌握将语法分析所识别的语法范畴变换为某种中间代码的语义翻译⽅法。

掌握⽬前普遍采⽤的语义分析⽅法──语法制导翻译技术。

给出 PL/0 ⽂法规范,要求在语法分析程序中添加语义处理,对于语法正确的表达式,输出其中间代码;对于语法正确的算术表达式,输出其计算值。

题⽬【问题描述】在实验⼆或实验三的表达式语法分析程序⾥,添加语义处理部分。

对于语法正确的表达式,输出其中间代码,⽤四元式序列表⽰;对于语法正确的算术表达式,输出其计算值。

例如:当输⼊为2+35时,程序输出为17;当输⼊为a(b+c)时,程序输出为四元式:(+,b,c,t1)(,a,t1,t2)要求源程序能智能判断这两种情况,并输出相应结果。

【输⼊形式】(1) PL/0算术表达式的语义计算。

PL/0算术表达式,例如:2+35作为输⼊。

(2)PL/0表达式的中间代码表⽰。

输⼊:PL/0表达式,例如: a*(b+c)。

【输出形式】2+35作为输⼊时,输出为17a(b+c)作为输⼊时,输出为(+,b,c,t1)(*,a,t1,t2)源程序#include <iostream>#include<bits/stdc++.h>using namespace std;/**词法分析及其结果存储**/pair<string, string> lexRes[50]; // 词法分析结果,每个pair的first如"ident",second如"a"int lexI = 0; // lexRes的指针void lexical()/*词法分析:读⼊⼀⾏字符串,处理该字符串的词法分析结果⾄lexRes*//*lexI终为lexRes的长度,即单词数*/{// 读⼊输⼊串string inputs; // 如,a*(b+c)cin >> inputs;// 初始化词典map<string,string> words;std::map<string,string>::iterator it;words["+"]="plus";words["-"]="minus";words["*"]="times";words["/"]="slash";words["="]="eql";words["("]="lparen";words[")"]="rparen";// 开始分析int insize=inputs.length();string word; // 输⼊符号,如"a"/"123"{// 空⽩符跳过while(inputs[i] == ' ' || inputs[i] == '\n')i++;// 标志符/基本字捕捉if(isalpha(inputs[i])){// 拿出⼀个标志符/基本字word = inputs[i++];while(isalpha(inputs[i]) || isdigit(inputs[i]))word += inputs[i++];// 在map中找到相应的词性,并输出it = words.find(word);if(it != words.end())lexRes[lexI++] = make_pair(words[word], word);// cout << "(" << words[word] << "," << word << ")" << endl; elselexRes[lexI++] = make_pair("ident", word);// cout << "(ident" << "," << word << ")" << endl;i--;}// 常数else if(isdigit(inputs[i])){// 拿出常数word=inputs[i++];while(isdigit(inputs[i]))word+=inputs[i++];lexRes[lexI++] = make_pair("number", word);//cout << "(number" << "," << word << ")" << endl;i--;}// <、<=号else if(inputs[i]=='<'){word=inputs[i++];if(inputs[i]=='>'){word+=inputs[i];lexRes[lexI++] = make_pair(words[word], word);// cout << "(" << words[word] << "," << word << ")" << endl; }else if(inputs[i]=='='){word+=inputs[i];lexRes[lexI++] = make_pair(words[word], word);// cout << "(" <<words[word] << "," << word << ")" << endl; }else if(inputs[i]!=' '||!isdigit(inputs[i])||!isalpha(inputs[i])){lexRes[lexI++] = make_pair(words[word], word);// cout << "(" << words[word] << "," << word << ")" << endl; }else{//cout << "error!" << endl;}i--;}// >、>=else if(inputs[i]=='>'){word=inputs[i++];if(inputs[i]=='='){word+=inputs[i];lexRes[lexI++] = make_pair(words[word], word);// cout<<"("<<words[word]<<","<<word<<")"<<endl;}else if(inputs[i]!=' '||!isdigit(inputs[i])||!isalpha(inputs[i])){lexRes[lexI++] = make_pair(words[word], word);// cout<<"("<<words[word]<<","<<word<<")"<<endl;}else{//cout<<"error!"<<endl;}i--;}//:=else if(inputs[i]==':'){word=inputs[i++];if(inputs[i]=='='){word+=inputs[i];lexRes[lexI++] = make_pair(words[word], word);// cout<<"("<<words[word]<<","<<word<<")"<<endl;}else{//cout<<"error!"<<endl;}//i--;}//其他的基本字word=inputs[i];it=words.find(word);if(it!=words.end()){lexRes[lexI++] = make_pair(words[word], word);// cout<<"("<<words[word]<<","<<word<<")"<<endl; }else{//cout<<"error!"<<endl;}}}}/**四元式相关,被调⽤**/struct quad{string result;string arg1;string arg2;string op;};struct quad quad[50]; // 四元式数组int quaI = 0; // 指向四元式的指针void emit(string op, string arg1, string arg2, string result)/*发射⼀⾏四元式*/{quad[quaI].op = op;quad[quaI].arg1 = arg1;quad[quaI].arg2 = arg2;quad[quaI].result = result;quaI++;}int tI = 1; // 记录当前是t1/t2...t⼏了string newT()/*产⽣⼀个t1/t2...*/{stringstream ss;ss << tI;string ti = "t" + ss.str();tI++;return ti;}/**⾮算数表达式的递归下降分析及四元式⽣成**/// 指针前进int sym=0; // 正在处理的单词void advance(){++sym;if(sym > lexI){cout << "ERROR!sym指针越界";exit(0);}}string E();string T();string F();string F()/*因⼦分析*/{string arg;if(lexRes[sym].first == "ident"){arg = lexRes[sym].second;advance();}else if(lexRes[sym].first == "number"){arg = lexRes[sym].second;advance();}else if(lexRes[sym].first == "lparen"){advance();arg = E();if(lexRes[sym].first == "rparen"){advance();}else{cout << "ERROR!未能匹配右括号!语法错误\n";exit(0);}}}string T()/*项分析*/{string op, arg1, arg2, result;arg1 = F();while(lexRes[sym].first == "times" || lexRes[sym].first == "slash"){ op = lexRes[sym].second;advance();arg2 = F();result = newT();emit(op, arg1, arg2, result);arg1 = result;}return arg1;}string E()/*表达式分析*/{string op, arg1, arg2, result;if(lexRes[sym].first == "plus" || lexRes[sym].first == "minus"){advance();}arg1 = T();while(lexRes[sym].first == "plus" || lexRes[sym].first == "minus"){ op = lexRes[sym].second;advance();arg2 = T();result = newT();emit(op, arg1, arg2, result);arg1 = result;}return arg1;}/**算数表达式的递归下降分析及四元式⽣成**/int E_();int T_();int F_();int F_(){int arg;if(lexRes[sym].first == "ident"){cout << "算数表达式含变量,⽆法计算\n";exit(0);}else if(lexRes[sym].first == "number"){arg = atoi(lexRes[sym].second.c_str());advance();}else if(lexRes[sym].first == "lparen"){advance();arg = E_();if(lexRes[sym].first == "rparen"){advance();}else{cout << "ERROR!未能匹配右括号!语法错误\n";exit(0);}}return arg;}int T_()/*项分析*/{string op;int arg1, arg2, result;arg1 = F_();while(lexRes[sym].first == "times" || lexRes[sym].first == "slash"){ op = lexRes[sym].second;advance();arg2 = F_();if(op == "*"){result = arg1 * arg2;arg1 = result;}else{result = arg1 / arg2;arg1 = result;}else {cout << "除数为0,出错!\n";exit(0);}}}return arg1;}int E_()/*表达式分析*/{string op;int arg1, arg2, result;if(lexRes[sym].first == "plus" || lexRes[sym].first == "minus"){advance();}arg1 = T_();while(lexRes[sym].first == "plus" || lexRes[sym].first == "minus"){op = lexRes[sym].second;advance();arg2 = T_();if(op == "+"){result = arg1 + arg2;arg1 = result;}else{result = arg1 - arg2;arg1 = result;}}return arg1;}int main(){lexical();if(lexRes[0].first == "number"){cout << E_();}else{E();for(int i=0; i<quaI; i++){cout<<'('<<quad[i].op<<','<<quad[i].arg1<<','<<quad[i].arg2<<','<<quad[i].result<<')'<<endl; }}return 0;}。

编译原理语义分析与中间代码生成实验报告

编译原理语义分析与中间代码生成实验报告

编译原理语义分析与中间代码生成实验报告专题6_语法制导翻译程序设计原理与实现技术***-***** 李若森计科1301一、实验目的语法制导的基本概念;目标代码结构分析的基本方法;赋值语句语法制导生成四元式的基本原理和方法;该过程包括语法分析和语义分析过程。

二、实验内容2.1 实验项目完成以下描述赋值语句和算术表达式文法的语法制导生成中间代码四元式的过程。

G[A]:A→V=EE→E+T|E-T|T T→T*F|T/F|F F→(E)|i V→i2.2 设计说明终结符号i为用户定义的简单变量,即标识符的定义。

2.3 设计要求(1) 设计语法制导翻译过程,给出每一产生式对应的语义动作;(2) 设计中间代码四元式的结构(暂不与符号表有关);(3) 输入串应是词法分析的输出二元式序列,即某算术表达式“专题1”的输出结果。

输出为输入串的四元式序列中间文件;(4) 设计两个测试用例(尽可能完备),并给出程序执行结果。

2.4 任务分析重点解决赋值语句文法的改写和语义动作的添加。

三、实现过程3.1 扩展文法G[s]:S→AA→V=EE→E+T|E-T|T T→T*F|T/F|F F→(E)|i V→i3.2 非终结符FOLLOW集FOLLOW(S) = { # } FOLLOW(A) = { # } FOLLOW(V) = { = }FOLLOW(E) = { +, -, ), # }FOLLOW(T) = { +, -, *, /, ), # } FOLLOW(F) = { +, -, *, /, ), # }3.3 LR(0)分析器的构造设DFA M的一个状态为i,该状态识别出的所有活前缀的有效项目集为Ci。

则DFA M的状态集Q={C0, C1, C2, … , Cn}=C。

C称为文法的LR(0)有效项目集规范族。

对Ci有三种操作:求文法的LR(0)有效项目集规范族C的算法:由上述算法可求得有效项目集规范族C={C0, C1, C2, … , C19}。

第7章 语义分析和中间代码生成

第7章 语义分析和中间代码生成
22
树与其他中间代码的关系 树表示的中间代码与后缀式和三地址码之间有着内在的联系。 对树进行深度优先的后序遍历,得到的线性序列就是后缀式,或 者说后缀式是树的一个线性化序列;而对于每棵父子关系的子树, 父亲节点作为操作符,两个孩子节点作为操作数,恰好组成一个 三元式,且父亲节点的序号成为三元式的序号。为每个三元式序 号赋一个临时变量,就不难将三元式转换为四元式。
14
将if-then-else看作一个完整的操作符,则e、x和 y分别是三 个操作数,这显然是一个三元运算。根据后缀式的特点,它的后 缀式可以写为: e x y if-then-else 但是,这样的表示有个弱点。按照计算次序,e、x和y均需计算, 而实际上,根据条件e的取值,计算x则不计算y,计算y则不计算 x。因此可以将后缀式改写为: e p1 jez x p2 jump y
15
其中,p1和p2分别是标号,p1 jez表示e的结果为0(假)则转 向p1,p2 jump表示无条件转向p2。与exy if-then-else相比较,操 作符if-then-else被分解,首先计算e,根据e的结果是否为真,决 定计算x还是计算y。
16
7.1.2 图表示法
抽象语法树是一种图形化的中间表示,它是分析树的浓 缩表示。描述了源程序在语义上的层次结构。 后缀表示是语法树的一种线性表示。 有向无环图也是一种中间表示。和语法树相比,它以更紧 凑的方式给出同样的信息,因为公共子表达式标识出来了。 在考虑代码优化时,有向无环图比语法树更适用。
19
/ D + C
A
规约过程
图 x:=(a+b)*(a+b)图形表示的中间代码 (a) 树表示;(b) DAG表示
20
(1)E

LR 分析方法程序设计原理与实现技术实验报告及源代码 北京交通大学

LR 分析方法程序设计原理与实现技术实验报告及源代码 北京交通大学
lr分析方法程序设计原理与实现技术实验报告及源代码北京交通大学lr分析方法程序设计原理与实现技术xxx1028xxx计科1xxx通过设计编写和构造lr0项目集规范簇和lr分析表对给定的符号串进行lr析的程序了解构造lr0分析表的步骤对文法的要求能够从文法出发生成lr0分析表并对给定的符号串进行分析
LR 分析方法程序设计原理与实现技术
分析失败:aAcAd
分析成功:acd
7. 实验总结:
本次实验按照书上的相应步骤,一步一步按照要求来完成实现,最终文成了给定文 法的分析程序。首先是获取文法,文法的获取是采用直接输入的方法,保存成预先设定 的结构体,然后根据文法,对文法编号,求出项目集规范族,然后再构造 LR(0)分析 表,最后根据分析表来判断输入符号串是否为此文法产生的语言。
sign = 0;
for(int i = 0;i < pro[0].data.size();i ++){
for(int j = 0;j < pro[0].data[i].right.size();j ++){
char ch = pro[0].data[i].right[j][1];
if(ch <= 'Z' && ch >= 'A' && pro[0].data[i].sign == 0){ //
cout << " 文法获取完成"
<< endl;
cout << "****************************************" << endl;
cout << endl;

第5章 语义分析与中间代码生成

第5章 语义分析与中间代码生成

2020/6/16 编 译 原 理
2020年6月16日
5
静态语义检查
①类型检查。
②控制流检查,确保控制语句有合法的转向点。例 如,C语言中的break语句使控制跳离包括该语句的 最小的switch,while或for语句。如果不存在包括它 的这样的语句,则应报错。
2020/6/16 编 译 原 理
2020/6/16 编 译 原 理
2020年6月16日
2020/6/16 编 译 原 理
2020年6月16日
28
(6)过程调用语句param x 和call p , n。源程序中的过程 调用语句p(x1,x2,…,xn)可以产生如下的三地址代码: param x1 param x2 …
param xn call p, n
其中n为实参个数。过程返回语句形如return y,其中y为过 程返回的一个值。
2020/6/16 编 译 原 理
2020年6月16日
13
翻译步骤
(1)分析输入符号串,建立分析语法树 (2)从分析树得到描述结点属性间依赖关系的依赖图,由 依赖图得到语义规则的计算次序 (3)进行语义规则的计算,得到翻译结果
输入符号串 分析树 执行语义规则
翻译结果
2020/6/16 编 译 原 理
2020年6月16日
16
L E.val = 14 n
E.val = 2
+ T.val = 12
T.val = 2
T.val = 3 *
F.val = 4
F.val = 2
F.val = 3
i.lexval = 4
i.lexval = 2 i.lexval = 3
2+3*4的注释分析树

编译原理课件07语义分析和中间代码产生

编译原理课件07语义分析和中间代码产生

语义分析阶段中的关键问题和 挑战
语义分析阶段面临着许多关键问题和挑战,例如识别复杂的语义错误、处理 不完整的代码等。
在处理大型程序时,编译器需确保语义分析的效率和准确性,并能处理各种 语法结构。
中间代码的定义和作用
中间代码是一种介于高级语言和底层机器代码之间的形式,它是一种可读性 较强且易于生成和优化的表示。
语义分析的基本任务和目标
语义分析的主要任务是识别和验证程序中的语义错误,例如类型不匹配、变量未定义等。 它的目标是确保程序的语义是一致的,以便于理解和执行。语义语义分析使用了各种技术和方法,包括符号表、类型检查、控制流分析等。 符号表用于记录变量和函数的信息,类型检查用于比较表达式和操作数的类 型是否一致。 控制流分析用于检测条件语句、循环语句和函数调用等代码块的流程。
编译原理课件07语义分析 和中间代码产生
在这一节中,我们将学习关于语义分析和中间代码产生的定义、概述以及它 们在编译过程中的作用。我们将探讨语义分析的任务、方法和挑战,以及中 间代码产生的基本原理和实际应用。
语义分析和中间代码产生的定义和概述
语义分析是编译过程中的重要阶段,用于分析程序的意义和语法结构,并生成中间代码。中间代码产生是将高 级语言代码转换为更低级的可执行形式的过程。 在这一阶段,编译器将检查语法的正确性和静态语义的正确性,以确保程序在执行时没有语法错误。 语义分析和中间代码产生是编译器的核心部分,它们直接影响了程序的性能和可读性。
中间代码作为编译器和解释器的输入,是程序在执行前的一个中间阶段,并 可用于代码优化和跨平台编译。
中间代码产生的基本原理和方法
中间代码产生的基本原理是将程序的语义结构转换为一系列指令序列,这些指令不依赖于具体的计算机体系结 构。 中间代码生成的方法包括源代码到抽象语法树的转换、语法树到中间代码的转换等。

编译原理教程04语义分析和中间代码生成

编译原理教程04语义分析和中间代码生成
编译原理教程04 语义分 析和中间代码生成
在本教程中,我们将探讨编译原理中的两个重要主题:语义分析和中间代码 生成。了解它们的定义、步骤、技术和应用,提升编译器质量和效率。
语义分析的定义和作用
1 作用
确保源代码符合语法和语义规则,并检测隐藏的错误和不一致性。
中间代码的定义和作用
1 作用
在后续编译过程中提供统一的中间表示,方便目标代码生成和优化。
常见的语义分析和中间代码生成技术
1 语义分析器的类型和实现方法
包括语法制导翻译、类型检查和静态分析等不同技术。
拟机代码和抽象语法树转换。
语义分析和中间代码生成的应用和意义
1 提高编译器的效率和质量
2 支持
通过优化和错误检测,生成更高效和可靠 的目标代码。
语义分析的步骤
词法分析
将源代码转换为单词流。
语法分析
根据语法规则构建语法树。
语义处理
对语法树执行语义规则验 证和错误检测。
中间代码生成的步骤
生成语法树
通过语法分析构建抽象语法树或其他中间表示。
生成中间代码
将抽象语法树转换为可执行的中间代码。
语义分析和中间代码生成的关系
1 重要性
语义分析的准确性和质量对中间代码生成阶段至关重要。
帮助开发人员开发更强大和易于维护的程 序。

中间代码生成实验报告

中间代码生成实验报告

中间代码生成实验报告中间代码生成实验报告一、引言在计算机编程领域中,中间代码生成是编译器的一个重要阶段。

它将源代码转化为一种中间表示形式,以便于后续的优化和目标代码生成。

本实验旨在通过实现一个简单的中间代码生成器,深入理解编译器的工作原理和中间代码的作用。

二、实验背景中间代码是一种介于源代码和目标代码之间的表示形式。

它通常是一种抽象的、与机器无关的形式,具有较高的可读性和可维护性。

中间代码生成是编译器的一个重要阶段,它将源代码转化为中间代码,为后续的优化和目标代码生成提供基础。

三、实验目的本实验的主要目的是通过实现一个简单的中间代码生成器,加深对编译器工作原理的理解,并掌握中间代码的生成过程。

具体目标包括:1. 学习使用编程语言实现中间代码生成算法;2. 理解中间代码的数据结构和语义;3. 掌握将源代码转化为中间代码的过程;4. 分析和优化生成的中间代码。

四、实验设计与实现本实验采用C++语言实现一个简单的中间代码生成器。

具体步骤如下:1. 词法分析:使用词法分析器对输入的源代码进行扫描,将其划分为一个个的词法单元。

2. 语法分析:使用语法分析器对词法单元进行解析,构建语法树。

3. 语义分析:对语法树进行语义分析,检查语法的正确性,并生成中间代码。

4. 中间代码生成:根据语义分析的结果,生成对应的中间代码。

5. 中间代码优化:对生成的中间代码进行优化,提高执行效率和代码质量。

6. 目标代码生成:将优化后的中间代码转化为目标代码。

五、实验结果与分析经过实验,我们成功实现了一个简单的中间代码生成器,并生成了相应的中间代码。

通过对生成的中间代码进行分析,我们发现其中存在一些冗余和不必要的指令,可以进一步进行优化。

例如,可以通过常量折叠、死代码删除等技术,减少中间代码的长度和执行时间。

六、实验总结通过本次实验,我们深入理解了中间代码生成的过程和作用,并通过实践掌握了中间代码生成器的实现方法。

在实验过程中,我们遇到了一些困难和挑战,但通过不断的学习和尝试,最终取得了满意的结果。

第4章 语义分析和中间代码生成

第4章  语义分析和中间代码生成

val[TOP]=lexval (注:lexval为i的整
这个文法的LR分析表见表3.20。
第4章 语义分析和中间代码生成
我们扩充分析栈工作的总控程序功能,使其在完 成语法分析的同时也能完成语义分析工作(这时的语法 分析栈已成为语义分析栈);即在用某一个规则进行归 约之后,调用相应的语义子程序完成与所用产生式相 应的语义动作,并将每次工作后的语义值保存在扩充 后的“语义值”栈中。图4–2表示算术表达式7+9*5# 的语法树及各结点值,而表4.1则给出了根据表3.20用 LR语法制导翻译方法得到的该表达式的语义分析和计 值过程。
第4章 语义分析和中间代码生成
D
T
L
int
L , id2
id1
图4–3 属性信息传递情况示意
第4章 语义分析和中间代码生成
4.3 几种常见的中间语言
4.3.1 抽象语法树 抽象语法树也称图表示,是一种较为流行的中间语言
表示形式。在抽象语法树表示中,每一个叶结点都表示 诸如常量或变量这样的运算对象,而其它内部结点则表 示运算符。抽象语法树不同于前述的语法树,它展示了 一个操作过程并同时描述了源程序的层次结构。
第4章 语义分析和中间代码生成
注意,语法规则中包含的某些符号可能起标点符号 作用也可能起解释作用。如赋值语句语法规则:
S→V=e 其中的赋值号“=”仅起标点符号作用,其目的是
把V与e分开;而条件语句语法规则: S→if(e)S1; else S2
第4章 语义分析和中间代码生成
其中的保留字符号if和else起注释作用,说明当布 尔表达式e为真时执行S1,否则执行S2;而“;”仅起 标点符号作用。可以看出,上述语句的本质部分是V、 e和Si。当把语法规则中本质部分抽象出来而将非本质 部分去掉后,便得到抽象语法规则。这种去掉不必要 信息的做法可以获得高效的源程序中间表示。上述语 句的抽象语法规则为:
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

语义分析及中间代码生成程序设计原理与实现技术--实验报告及源代码北京交通大学语义分析及中间代码生成程序设计原理与实现技术XXX 1028XXX2 计科1XXX班1. 程序功能描述完成以下描述赋值语句和算术表达式文法的语法制导生成中间代码四元式的过程。

G[A]:A?V:=EE?E+T?E-T?T?T*F?T/F?FF?(E)?iV?i说明:终结符号i 为用户定义的简单变量,即标识符的定义。

2. 设计要求(1)给出每一产生式对应的语义动作;(2)设计中间代码四元式的结构(暂不与符号表有关)。

(3)输入串应是词法分析的输出二元式序列,即某算术表达式“实验项目一”的输出结果。

输出为输入串的四元式序列中间文件。

(4)设计两个测试用例(尽可能完备),并给出程序执行结果四元式序列。

3. 主要数据结构描述:本程序采用的是算符优先文法,文法以及算符优先矩阵是根据第四次实验来修改的,所以主要的数据结构也跟第四次差不多,主要为文法的表示,FirstVT集和LastVT集以及算符优先矩阵:struct info{char left;vector<string> right;vector<char> first;vector<char> last;};算符优先矩阵采用二维字符数组表示的:char mtr[9][9]; //算符优先矩阵4. 程序结构描述:本程序一共有8功能函数:void get(); //获取文法void print(); //打印文法void fun(); //求FirstVT 和 LastVTvoid matrix(); //求算符优先矩阵void test(); //测试文法int cmp(char a,char b); 比较两个运算符的优先级 1 0 -1void out(char now,int avg1,int avg2); //打印四元式a,int b); //定义四元式计算方法 int ope(char op,int 5. 实验代码详见附件6. 程序测试6.1 功能测试程序运行显示如下功能菜单:选择打印文法:选择构造FirstVt集和LastVT集:选择构造算符优先矩阵:6.2 文法测试测试1:1+2*3测试2:2+3+4*5+(6/2)7. 学习总结本次实验完成了语义及中间代码生成的设计原理与实现,所采用的方法为算符优先分析方法,首先根据文法求出此文法的FirstVT集和LastVT集,然后根据他们求出此文法的算符优先矩阵。

由于此文法和第四次文法基本相同,只是多了一条赋值语句,所以采用的规则和第四次基本相同。

在分析阶段,每当遇到有规约的项目,判断一下,打印出此部运算的四元式,这样一步一步分析,知道输入的算术表达式计算分析完毕。

由于本次实验部分代码和第四次实验的代码比较相似,只需增加一点四元式的分析计算打印过程,就能够顺利完成本次实验。

通过这次实验,我对语义分析以及中间代码部分有了一定的提高,对以后的学习有了一定程度上的帮助。

// lb6.cpp : 定义控制台应用程序的入口点。

//#include "stdafx.h" #include <iostream> #include <string> #include <VECTOR> #include <stack>using namespace std;struct info{char left;vector<string> right; vector<char> first; vector<char> last; };vector<info> lang; char mtr[9][9]; //算符优先矩阵stack<char> sta;void get(); //获取文法void print(); //打印文法void fun(); //求FirstVT 和 LastVT void matrix(); //求算符优先矩阵void test(); //测试文法int cmp(char a,char b); //比较两个运算符的优先级 10 -1void out(char now,int avg1,int avg2); //打印四元式int ope(char op,int a,int b); //定义四元式计算方法int main(){int choose;while(1){cout << "****************************************" << endl;cout << " 获取文法请按 1" << endl;cout << " 打印文法请按 2" << endl;cout << " 构造FirstVT集和LastVT集请按 3" << endl;cout << " 构造优先关系矩阵请按 4" << endl;cout << " 文法测试请按 5" << endl;cout << " 结束请按 0" << endl;cout << "****************************************" << endl; cout << endl;cin >> choose;if(choose == 0)break;switch(choose){case 1: get(); break;case 2: print(); break;case 3: fun(); break;case 4: matrix(); break;case 5: test(); break;default:break;}}return 0;}void get(){info temp,temp1,temp2;temp.left = 'E';temp.right.push_back("E+T");temp.right.push_back("E-T");temp.right.push_back("T");temp.right.push_back("i");temp1.left = 'T';temp1.right.push_back("T*F");temp1.right.push_back("T/F");temp1.right.push_back("F");temp2.left = 'F';temp2.right.push_back("(E)");temp2.right.push_back("i");lang.push_back(temp);lang.push_back(temp1);lang.push_back(temp2);cout << "****************************************" << endl; cout << " 文法获取完成" << endl;cout << "****************************************" << endl; cout << endl;}void print(){cout << "****************************************" << endl; for(int i = 0;i < lang.size();i ++){for(int j = 0;j < lang[i].right.size();j ++){cout << lang[i].left << " --> ";cout << lang[i].right[j] << endl;}}cout << "****************************************" << endl; cout << endl;}void fun(){int i,j,sign = 0,sign1 = 0;for(i = 0;i < lang.size();i ++){for(j = 0;j < lang[i].right.size();j ++){string temp = lang[i].right[j]; //获取右部if(temp[0] > 'Z' || temp[0] < 'A'){ //终结符lang[i].first.push_back(temp[0]);}else if(temp.length() >= 2){ //终结符if(temp[1] > 'Z' || temp[1] < 'A'){lang[i].first.push_back(temp[1]);}}}}for(i = 0;i < lang.size();i ++){for(j = 0;j < lang[i].right.size();j ++){string temp = lang[i].right[j]; //获取右部if((temp[0] > 'Z' || temp[0] < 'A') && temp.length() == 1){ // 终结符lang[i].last.push_back(temp[0]);}else if(temp.length() >= 3){ //终结符if(temp[1] > 'Z' || temp[1] < 'A')lang[i].last.push_back(temp[1]);else if(temp[2] > 'Z' || temp[2] < 'A') //终结符lang[i].last.push_back(temp[2]);}}}while(sign == 0){ //迭代FirstVTsign = 1;for(i = 0;i < lang.size();i ++){for(j = 0;j < lang[i].right.size();j ++){string temp = lang[i].right[j]; //获取右部if(temp.length() == 1 && (temp[0] <= 'Z' && temp[0] >= 'A')){//可以迭代for(int k = 0;k < lang.size();k ++){if(lang[k].left == temp[0]){ //找到了,添加元素for(int p = 0;p < lang[k].first.size();p ++){sign1 = 0;char ch = lang[k].first[p];for(int q = 0;q < lang[i].first.size();q++){if(lang[i].first[q] == ch){ //包含了sign1 = 1;}}if(sign1 == 0){lang[i].first.push_back(ch);sign = 0;}}}}}}}}sign = 0;while(sign == 0){ //迭代LastVTsign = 1;for(i = 0;i < lang.size();i ++){for(j = 0;j < lang[i].right.size();j ++){string temp = lang[i].right[j]; //获取右部if(temp.length() == 1 && (temp[0] <= 'Z' && temp[0] >= 'A')){//可以迭代for(int k = 0;k < lang.size();k ++){if(lang[k].left == temp[0]){ //找到了,添加元素for(int p = 0;p < lang[k].last.size();p ++){sign1 = 0;char ch = lang[k].last[p];for(int q = 0;q < lang[i].last.size();q++){if(lang[i].last[q] == ch){ //包含了sign1 = 1;}}if(sign1 == 0){lang[i].last.push_back(ch);sign = 0;}}}}}}}}cout << "****************************************" << endl; cout << "FirstVT:" << endl;for(i = 0;i < lang.size();i ++){cout << lang[i].left << " : ";for(j = 0;j < lang[i].first.size();j ++){cout << lang[i].first[j] << " ";}cout << endl;}cout << endl;cout << "LasttVT:" << endl;for(i = 0;i < lang.size();i ++){cout << lang[i].left << " : ";for(j = 0;j < lang[i].last.size();j ++){cout << lang[i].last[j] << " ";}cout << endl;}cout << "****************************************" << endl; cout << endl;}void matrix(){int i,j;for(i = 0;i < 9;i ++){ //初始化for(j = 0;j < 9;j ++){mtr[i][j] = 'n';}}string temp = "+-*/()i#";for(i = 1;i < 9;i ++){mtr[i][0] = temp[i - 1];mtr[0][i] = temp[i - 1]; }vector<string> str;for(i = 0;i < lang.size();i ++){ //aU a < FirstVT(U)for(j = 0;j < lang[i].right.size();j ++){string ss = lang[i].right[j];string ok = "";if(ss.length() > 2){if((ss[0] > 'Z' || ss[0] < 'A') && (ss[1] <= 'Z' && ss[1] >= 'A')){ //aUok = "";ok += ss[0];ok += ss[1];str.push_back(ok);}if((ss[1] > 'Z' || ss[1] < 'A') && (ss[2] <= 'Z' && ss[2] >= 'A')){ //aUok = "";ok += ss[1];ok += ss[2];str.push_back(ok);}}}}for(i = 0;i < str.size();i ++){for(j = 1;j < 9;j ++){if(mtr[j][0] == str[i][0]){ //Find a Then Find FirstVt(U) for(int k = 0;k < lang.size();k ++){if(lang[k].left == str[i][1]){ //Find Ufor(int p = 0;p < lang[k].first.size();p ++){for(int q = 1;q < 9;q ++){if(mtr[q][0] == lang[k].first[p]){mtr[j][q] = '<';}}}}}}}}str.clear();for(i = 0;i < lang.size();i ++){ //Ua LastVT(U) > afor(j = 0;j < lang[i].right.size();j ++){string ss = lang[i].right[j];string ok = "";if(ss.length() > 2){if((ss[1] > 'Z' || ss[1] < 'A') && (ss[0] <= 'Z' && ss[0] >= 'A')){ //Uaok = "";ok += ss[0];ok += ss[1];str.push_back(ok);}if((ss[2] > 'Z' || ss[2] < 'A') && (ss[1] <= 'Z' && ss[1] >= 'A')){ //Uaok = "";ok += ss[1];ok += ss[2];str.push_back(ok);}}}}for(i = 0;i < str.size();i ++){for(j = 1;j < 9;j ++){if(mtr[0][j] == str[i][1]){ //Find a Then Find LastVt(U)for(int k = 0;k < lang.size();k ++){if(lang[k].left == str[i][0]){ //Find Ufor(int p = 0;p < lang[k].last.size();p ++){for(int q = 1;q < 9;q ++){if(mtr[0][q] == lang[k].last[p]){mtr[q][j] = '>';}}}}}}}}str.clear();for(i = 0;i < lang.size();i ++){ //ab aUb a = bfor(j = 0;j < lang[i].right.size();j ++){string ss = lang[i].right[j];string ok = "";if(ss.length() > 2){if((ss[1] > 'Z' || ss[1] < 'A') && (ss[0] > 'Z' || ss[0] < 'A')){ //aaok = "";ok += ss[0];ok += ss[1];str.push_back(ok);}if((ss[2] > 'Z' || ss[2] < 'A') && (ss[1] > 'Z' || ss[1] < 'A')){ //aaok = "";ok += ss[1];ok += ss[2];str.push_back(ok);}if((ss[2] > 'Z' || ss[2] < 'A') && (ss[0] > 'Z' || ss[0] < 'A')){ //aUaok = "";ok += ss[0];ok += ss[2];str.push_back(ok);}}}}for(i = 0;i < str.size();i ++){for(j = 1;j < 9;j ++){if(str[i][0] == mtr[j][0]){for(int k = 1;k < 9;k ++){if(mtr[0][k] == str[i][1]){mtr[j][k] = '=';}}}}}for(i = 0;i < lang[0].first.size();i ++){ //#for(j = 1;j < 9;j ++){if(lang[0].first[i] == mtr[0][j]){mtr[8][j] = '<';}}}for(i = 0;i < lang[0].first.size();i ++){ //#for(j = 1;j < 9;j ++){if(lang[0].first[i] == mtr[j][0]){mtr[j][8] = '>';}}}mtr[8][8] = '=';cout << "****************************************" << endl; for(i = 0;i < 9;i ++){for(j = 0;j < 9;j ++){if(mtr[i][j] != 'n')cout << mtr[i][j] << " ";elsecout << " ";}cout << endl;}cout << "****************************************" << endl; cout << endl;}void test(){cout << "****************************************" << endl; cout << "请输入算术表达式:" << endl;string str;cin >> str;str += '#';int i,j,k;stack<int> data;stack<char> op;op.push('#');char now = 'n'; //记录当前栈顶操作符int sign = 0;for(i = 0;i < str.length();i ++){sign = 0;if(str[i] >= '0' && str[i] <= '9'){ //操作数int temp = str[i] - '0';data.push(temp);}else{ //运算符op.push(str[i]);sign = 1;}if(now != 'n' && sign == 1){ //有可比性,并且操作符栈有更新if(!op.empty()){char top = op.top(); //栈顶元素while(cmp(now,top) == 1){ //需要规约int avg1 = data.top();data.pop();int avg2 = data.top();data.pop();out(now,avg2,avg1); //打印四元式data.push(ope(now,avg2,avg1));op.pop();op.pop();if(!op.empty()){now = op.top();}else{now = 'n';}op.push(top);}if(cmp(now,top) == 0){ op.pop();op.pop();if(!op.empty()){now = op.top();}else{char temp = '=';if(!data.empty()){int da = data.top(); out(temp,da,0);}}}}}else{ //不需要比较if(!op.empty()){now = op.top();}}}}int cmp(char a,char b){int i,j;for(i = 1;i < 9;i ++){if(mtr[i][0] == a){for(j = 1;j < 9;j ++){if(mtr[0][j] == b){if(mtr[i][j] == '>'){ return 1;}else if(mtr[i][j] == '='){ return 0;}else if(mtr[i][j] == '<'){ return -1;}}}}}return 2;}void out(char now,int avg1,int avg2){cout << "****************************************" << endl;cout << now << " ," << avg1 << " ," << avg2 << " ," <<ope(now,avg1,avg2)<< endl;cout << "****************************************" << endl;cout << endl; }int ope(char op,int a,int b){if(op == '+'){return a + b; }if(op == '-'){return a - b;}if(op == '*'){return a * b; }if(op == '/'){return a / b; }if(op == '='){return a;}return 0;}。

相关文档
最新文档