《FOR循环语句的翻译程序设计(递归下降法、输出四元式表.doc》由会员分享,可在线阅读,更多相关《FOR循环语句的翻译程序设计(递归下降法、输出四元式表.doc(19页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、武汉理工大学编译原理课程设计说明书1、系统描述21.1、实验思想21.2、设计内容21.3、翻译过程21.3.1、词法分析:21.3.2、语法分析:31.3.3、中间代码生成:41.3.4、属性文法:42、递归下降法42.1、递归下降法的主要思想:42.2、用程序表示递归子程序的内部结构:423、递归下降法对文法的限制:53、语法制导翻译53.1、翻译任务的处理过程53.2、语法制导翻译:533、基于属性文法的处理方法64、中间代码形式的描述及中间代码序列的结构设计65、简要的分析与概要设计65.1、词法分析:65.2源代码85.3 运行结果156、测试方法和测试结果166.1测试过程166.
2、2测试结论187、课程设计总结188、参考文献201、系统描述1.1、实验思想通过设计、编制、调试一个FOR循环语句的语法及语义分析程序,加深对语法及语义分析原理的理解,实现词法分析程序对单词序列的词法检查和分析,并且实现对单词序列的语法分析、语义分析以及中间代码生成。1.2、设计内容本设计按照要求设计出for语句的简单文法,并使用递归下降分析法对用户输入的程序进行分析和翻译。对下列正确的程序输入: for i=1 step 1 until 10 do k=j #结果程序要对该输入进行词法分析,然后利用递归下降的分析法对词法分析得到的单词序列进行语法分析,经过语法制导翻译显示出等价的三地址表示
3、的中间代码。对于错误的程序输入,如:For i=1 step 1 until 10 k=j#结果程序要指出程序出错。1.3、翻译过程1.3.1、 词法分析:词法分析是计算机科学中将字符序列转换为单词(Token)序列的过程。进行语法分析的程序或者函数叫作词法分析器(Lexical analyzer,简称Lexer),也叫扫描器(Scanner)。词法分析器一般以函数的形式存在,供语法分析器调用。词法分析是编译过程中的第一个阶段,在语法分析前进行 。也可以和语法分析结合在一起作为一遍,由语法分析程序调用词法分析程序来获得当前单词供语法分析使用。简化设计、改进编译效率、增加编译系统的可移植性。词法
4、分析是编制一个读单词的过程,从输入的源程序中,识别出各个具有独立意义的单词,即基本保留字、标识符、常数、运算符、分隔符五大类。并依次输出各个单词的内部编码及单词符号自身值。单词的分类主要分为五类:1. 关键字:由程序语言定义的具有固定意义的标识 符。也称为保留字或基本字。2. 标识符:用来表示程序中各种名字的字符串。3. 常 数:常数的类型一般有整型、实型、布尔型、文字型。4. 运算符:如+、 、*、/ 等。5. 界限符:如逗号、分号、括号等。词法分析器输出的单词符号常表示成如下的二元式:(单词种别,单词符号的属性值)1.3.2、语法分析:语法分析是编译过程的一个逻辑阶段。语法分析的任务是在的
5、基础上将单词序列组合成各类语法短语,如“程序”,“语句”,“表达式”等等.语法分析程序判断源程序在结构上是否正确.源程序的结构由上下文无关文法描述.语法分析程序可以用YACC等工具自动生成。语法分析是编译程序的核心部分,其主要任务是确定语法结构,检查语法错误,报告错误的性质和位置,并进行适当的纠错工作。语法分析的主要工作:是识别由词法分析给出的单词序列是否是给定的正确句子(程序)。语法分析常用的方法:自顶向下的语法分析和自底向上的语法分析两大类。此次设计中语法分析中主要通过递归下降分析法对语法分析处理过程进行控制,使输出的三地址表示的翻译的工作有条不紊的进行,同时识别语法分析中的语法错误。递归
6、下降法主要采用自顶向下方法,即从文法的开始符号开始进行分析,逐渐推导的往下构造语法树,使其树叶正好构造出所给定的源程序串。自顶向下方法的关键是确定在推导过程中选择候选式的问题。当进行推导时,一个非终结符可能对应多个产生式,这样我们就无法事先知道应该用哪个产生式,因此实用都作了一些限制。以便在任何情况下都能确定应该用的产生式。自顶向下的主要思想是从开始符出发导出句型并一个符号一个符号地与给定终结符串进行匹配。如果全部匹配成功,则表示开始符号可推导出给定的终结符串。因此判定给定终结符号串是正确句子。词法分析程序和语法分析程序的关系:1.3.3、中间代码生成:中间代码,也称中间语言,是复杂性介于源程
7、序语言和机器语言的一种表示形式。为了使编译程序有较高的目标程序质量,或要求从编译程序逻辑结构上把与机器无关和与机器有关的工作明显的分开来时,许多编译程序都采用了某种复杂性介于源程序语言和机器语言之间的中间语言。中间代码(语言)是一种特殊结构的语言,编译程序所使用的中间代码有多种形式。按其结构分常见的有逆波兰式(后缀式)、三地址代码(三元式、四元式)和树形表示(抽象语法树)、DAG表示。本次课程设计要实现的是三地址表示。1.3.4、属性文法:对于文法的每个产生式都配备了一组属性的计算规则,称为语义规则。所谓语法制导的翻译指的是在语法分析过程中,完成这些语义规则描述的动作,从而实现语义处理。 一个
8、属性文法包含一个上下文无关文法和一系列语义规则,这些语义规则附在文法的每个产生式上。形式上讲,属性文法是一个三元组 :A=(G,V,F), 其中:G:是一个上下文无关文法;V:有穷的属性集,每个属性与文法的一个终结符或非终结符相连,这些属性代表与文法符号相关信息;F:关于属性的属性断言或一组属性的计算规则(称为语义规则) 。 断言或语义规则与一个产生式相联,只引用该产生式左端或右端的终结符或非终结符相联的属性。 2、递归下降法递归下降法又称递归子程序法。在程序语言的语法定义中有许多采用递归定义。我们在对它进行语法分析时,编制的处理程序也采取递归的方式,可使其结构简单易读。但由于频繁地调用子程序
9、大大地降低了分析速度。2.1、递归下降法的主要思想:对每个非终结符按其产生式结构写出相应语法分析子程序。因为文法递归相应子程序也递归,子程序的结构与产生式结构几乎一致。所以称此种方法称为递归子程序法或递归下降法。2.2、用程序表示递归子程序的内部结构: 设A是一个非终结符: A1 A2 An 则写(A) if charfirst(1 ) then(1 ) else if charfirst(2 ) then (2 ) else if charfirst(n ) then (n) else ERROR其中(i)表示调用处理符号串i的子程序。对A的任一右部i 设为: i = y1 y2 yn 则定
10、义( i) begin(y1);(y2);(yn) end其中yj可分为下列两种情况(j=1,n):1) yjVT,则 ( yj) if char yj then ERROR else READ(char)2) yjVN,则(yj)表示调用关于yj的递归子程序。23、递归下降法对文法的限制:1、任一非终结符B都不是左递归的,否则会产生死循环。2、对A的任意两个右部i , j ,有:first(i)first(j)= 。First(i)表示i所能导出串的第一个符号的集合。显然,每个i的first(i)是互不相同的,否则则无法判断应执行哪个(i )。 3、语法制导翻译3.1、翻译任务的处理过程编译
11、程序的整个任务就是把源程序翻译为目标程序。实际上可以把每个编译阶段都看作是完成一定翻译任务的处理过程:词法分析阶段把字符流翻译为单词流,语法分析阶段把单词流翻译为语法树,目标代码生成阶段把语法树翻译为汇编语言等等。 3.2、语法制导翻译:在语法分析过程中,随着分析的步步进展,每当进行推导或归约时,同步的去执行每个产生式所附带的语义规则描述的语义动作(或语义子程序),这样进行翻译的办法称作语法制导翻译。 所谓属性依赖图是一个有向图,用于描述分析树中的属性和属性间的相互依赖关系。33、基于属性文法的处理方法输入串语法树 依赖图 计算语义规则顺序语法分析树遍历执行语义规则语义规则的计算可能产生代码,
12、在符号表中存取信息,给出出错信息或执行其它动作。对输入串的翻译也就是根据语义规则进行计算的结果。4、中间代码形式的描述及中间代码序列的结构设计本次设计,使用的中间代码为四元式四元式有四个组成成分:算符op,第一和第二运算对象ARG1和ARG2,运算结果RESULT。例如:有中缀式a:b*cb*c,求其等价的四元式。 四元元式 编号 算符 左对象 右对象 中间结果 op arg1 arg2 result(1) minus c t1(2) b t1 t2(3) minus c t3(4) b (3) t4(5) (4) (2) t5(6) assign a 设计并生成的结果程序,最终需要将用户输入
13、的程序经过词法分析和语法分析,生成如上所述的式表示的中间代码形式。5、简要的分析与概要设计程序由词法分析和语法分析两部分构成: - 19 - 5.1、词法分析:int buffer()/载入 int i=0; cout输入程序,以#作为结束标志。endl; for(int n=0;n=MAX;n+) for(;i=65&ch=97&ch=48&ch=57) return(true); else return(false); char GetChar(int i)/读取字符 char ch; ch=stri; return(ch); char GetBC(char ch)/判断是不是空格或者换行
14、,如果是,直接读取下一个字符直道不再空白为止 if(ch=32|ch=10) turn+; ch=GetChar(turn); ch=GetBC(ch);/递归实现 return(ch); else return(ch); void Concat()/连接,即为strtoken赋值 strTokenn=ch; n+; int Reserve()/以单词为单位查找保留字,是则返回编码,不是则返回0,用来区分标志符和保留字 if(strcmp(strToken, DIM0)=0)/调用strcmp函数实现, return(1); else if(strcmp(strToken,for0)=0) r
15、eturn(2); else if(strcmp(strToken,step0)=0) return(3); else if(strcmp(strToken,until0)=0) return(4); else if(strcmp(strToken,do0)=0) return(5); else return(6); void clear() n=0; ch=GetChar(+turn); ch=NULL; turn=turn-1; kind=7; cout(; for(int i=0;iwordi=strTokeni; coutwordi; cout,kind)wordi=0; clear(
16、);x+; else if(ch=) kind=8; recordx-word0=; recordx+-sort=kind; cout(=,kind)endl; else couterror input!endl; 5.2源代码#include #include#include#include char a50 ,b50,d200,e10;char ch;int n1,i1=0,flag=1,n=5;int total=0;/*步骤计数器*/int E();int E1();int T();int G();/*E*/int S();/*T*/int F();void input();void
17、input1();void output(); void main() /*递归分析*/ int f,p,j=0; char x; d0=E; d1=; d2=; d3=T; d4=G; d5=#; printf(请输入字符串(长度TGt,total);total+; flag=1; input(); input1(); f=T(); if (f=0) return(0); t=G(); if (t=0) return(0); else return(1); int E() int f,t; printf(%dtE-TGt,total);total+; e0=E;e1=;e2=;e3=T;e4
18、=G;e5=#; output(); flag=1; input(); input1(); f=T(); if (f=0) return(0); t=G(); if (t=0) return(0); else return(1);int T() int f,t; printf(%dtT-FSt,total);total+; e0=T;e1=;e2=;e3=F;e4=S;e5=#; output(); flag=1; input(); input1(); f=F(); if (f=0) return(0); t=S(); if (t=0) return(0); else return(1);in
19、t G() int f; if(ch=+) bi1=ch; printf(%dtG-+TGt,total);total+; e0=G;e1=;e2=;e3=+;e4=T;e5=G;e6=#; output(); flag=0; input();input1(); ch=a+i1; f=T(); if (f=0) return(0); G(); return(1); printf(%dtG-t,total);total+; e0=G;e1=;e2=;e3=;e4=#; output(); flag=1; input();input1(); return(1);int S() int f,t; i
20、f(ch=*) bi1=ch;printf(%dtS-*FSt,total);total+; e0=S;e1=;e2=;e3=*;e4=F;e5=S;e6=#; output(); flag=0; input();input1(); ch=a+i1; f=F(); if (f=0) return(0); t=S(); if (t=0) return(0); else return(1); printf(%dtS-t,total);total+; e0=S;e1=;e2=;e3=;e4=#; output(); flag=1; ai1=ch; input();input1(); return(1
21、); int F() int f; if(ch=() bi1=ch;printf(%dtF-(E)t,total);total+; e0=F;e1=;e2=;e3=(;e4=E;e5=);e6=#; output(); flag=0; input();input1(); ch=a+i1; f=E(); if (f=0) return(0); if(ch=) bi1=ch;printf(%dtF-(E)t,total);total+; flag=0;input();input1(); ch=a+i1; else printf(errorn); return(0); else if(ch=i) b
22、i1=ch;printf(%dtF-it,total);total+; e0=F;e1=;e2=;e3=i;e4=#; output(); flag=0;input();input1(); ch=a+i1; else printf(errorn);return(0); return(1);void input() int j=0; for (;j=i1-flag;j+) printf(%c,bj); /*输出分析串*/ printf(tt); printf(%ctt,ch); /*输出分析字符*/ void input1() int j; for (j=i1+1-flag;j;dn+2=#;n
23、=n+2;i=n; i=i-2; while(di!=&i!=0) i=i-1; i=i+1; while(di!=e0) i=i+1; q=i; m=q;k=q; while(dm!=) m=m-1; m=m+1; while(m!=q) dn=dm;m=m+1;n=n+1; dn=#; for(j=3;ej!=#;j+) dn=ej; n=n+1; k=k+1; while(dk!=) dn=dk;n=n+1;k=k+1; dn=#; system(pause);5.3 运行结果 1) 在文件中输入:i+i*i# 运行结果如下图所示:2)在文件中输入:i+i-# 运行结果如下图所示:6、测
24、试方法和测试结果6.1测试过程针对所设计的关于for循环语句的翻译程序,分别用正确的程序和有错误的程序进行测试,测试出结果程序的可用性和健壮性。测试中分别使用了一个合法程序和两个非法程序,对结果程序进行测试,具体的测试程序、测试过程和测试结果如下:for循环语句语法分析过程:输入程序: for(d=3;df;d+) for(c=b;c3;c+) c=b/a+2*3; a=c*d+b+6/2; 合法程序。得到运行结果如图所示:输入合法程序:for(i=3;ifor(A)GA-D id PD-E id O FE-id=FF-idP-+|-O- G-GBB-ID=S1s1-TE1T-FT1E1-+T
25、E1|&|-TE1T1-*FT1|&|-TE1X-B|&*/当输入的程序缺少do时,将会提示error do,表明输入出错。又因为该文法实现的设计是i=j这一赋值语句,当缺少了赋值符号“=”时,系统将会提醒赋值语句缺少赋值运算符这一错误现象。存在问题:对于含有非法输入符号的程序,结果程序没有很好地处理,程序健壮性不强。例如当我输入的程序为:For i=1 step -1 until 10 do k=j#,该程序处理时把-1的负号给省略掉了,把这一语句和语句For i=1 step 1 until 10 do k=j#当做相同的进行处理。这是程序设计考虑不周到的地方。7、课程设计总结 在做本次试
26、验之前我对递归下降原理不是很了解,在查阅了相关资料后,对此有了深入了解,只要理解了分析方法的实现原理,编写程序判断出入字符串是否满足给定的文法比较简单。通过阅读大量相关书籍,利用网络查找各种资料,根据相关知识,我终于写出了符合递归下降法的关于for语句的属性文法。 此次设计对for语句进行了全面词法分析和语法分析,并得到了用于分析for 语句的结果程序。结果程序能对用户输入的程序代码进行分析,判断是否存在词法错误和语法错误,如果出现错误,向用户给出提示,如果没有错误,则生成于输入程序等价的中间代码,方便后续编译过程工作。本课程设计是for循环语句的翻译程序,包括词法分析部分、语法分析部分和中间
27、代码生成部分。词法分析阶段是编译过程的第一个阶段,是编译的基础。这个阶段的任务是从左到右一个字符一个字符地读入源程序,即对构成源程序的字符流进行扫描然后根据构词规则识别单词。语法分析部分采用递归下降分析方法进行语法分析,判断给出的符号串是否为该文法识别的句子。中间代码生成器部分主要实现三元式的生成,将用中缀式表示的算术表达式转换为用三元式表示的算术表达式。在整个编译器设计过程中,遇到了很多意想不到的困难,其主要原因是对各个部分要实现的功能考虑不够周全,例如对空白符、跳格符、回车符和换行符等编辑性字符的处理,及删除注解等。这些在程序设计初期实现都比较困难,经过努力,在后期这些问题都得到了比较有效
28、的解决。在语法分析的设计过程中,程序相当复杂,需要利用到大量的编译原理,其中在对输入字符串的移进和归约冲突得不到很好的处理,造成了调试的困难。通过多次调试,最终构造出来分析表并调试成功。 通过本次课程设计,将编译的理论知识应用于实践,加深了对课本理论知识的理解,更好的掌握了编译技术的基本方法,了解了编译程序的一般分析过程,并且通过对for语句编译程序的设计和实现,对for语句也加深了认识和理解。此次课程设计对自己的编程能力的提升有很大帮助。8、参考文献1张素琴、吕映芝、蒋维杜、戴桂兰等编译原理(第二版)清华大学出版社2005年2月2何炎祥编译原理(第二版)武汉:华中科技大学出版社2005年8月