opg文法
OPG文法的语法分析优化策略

226 •电子技术与软件工程 Electronic Technology & Software Engineering程序设计• Program Design【关键词】语法单位 自底向上 OPG 终结符优先 优化语法分析方法中自上而下的分析是指从文法的开始符号出发,反复的选择产生式进行推导,最终推导出句型;自下而上分析是指从待分析的句型本身出发,逐步选择产生式进行归约,直至归约到文法的开始符号。
这两类分析都可以利用各种语法分析算法进行。
每种语法分析算法都有其优势和局限性,根据文法的类型,可以选择最优的语法分析算法进行语法分析。
1 OPG文法Chomsky 将文法分为短语文法、上下文有关文法、上下文无关文法和正规文法四类。
OPG 文法是上下文有关文法中的一种,该文法的特殊性在于任意两个终结符之间最多只存在<、=、>三种优先关系中的一种优先关系,文法的产生式中不会出现两个相邻的非终结符。
根据文法的特性可以推论该文法的任何句型也不会含有相邻的非终结符,这就为使用优化的OP 分析法进行句型分析奠定了基础。
2 规范归约归约与推导是一个逆过程,规范归约过程中一直本着最左的归约原则,每次分析过程中首先找到句型中的句柄,句柄是句型中的最左直接短语,之后根据产生式规则向左归约,用产生式的左部去替换产生式右部。
例如对OPG 文法G[E]:E →T|E+T T →F|T*F F →i|(E)的句型T+T*F+i 的分析如表1所示。
上述句型分析中每步都是在句型中寻找OPG 文法的语法分析优化策略文/关玉欣最左直接短语,也就是文法中某条产生式的右部。
进行最左归约实质上就是用某条产生式的左部非终结符去替换产生式的右部符号串。
根据句型的不同,归约的步骤也会有区别,但分析成功的标志就是归约到OPG 文法的开始符号,代表句型分析成功。
在上述的规范归约过程中,句型T+T*F+i 总归约次数为6。
3 优化的OP分析在自底向上的句型分析方法中,OP (Operator Priority )分析法仅考虑句型中终结符的优先关系,从而确定每一步分析过程中的句柄。
西理工编译原理试题集1-7

01-普通作业一(第一章)一、选择题(从备选项中选出一个或多个正确答案)。
1. 编译程序的源程序是高级语言编写的程序,目标程序是编写的程序。
A. 高级语言B. 汇编语言C. 机器语言D. 汇编语言或机器语言2. 编译程序是对进行翻译。
A. 高级语言B. 汇编语言C. 机器语言D. 自然语言3. 如果编译程序生成的目标程序是机器代码程序,则源程序的执行分为两个阶段。
A. 编译B. 汇编C. 运行D. 预处理4. 编译的工作过程一般划分为词法分析、、语义分析、中间代码生成、代码优化和目标代码生成若干阶段。
A. 表格管理B. 出错处理C. 语法分析D. 预处理5. 词法分析阶段的主要任务是识别。
A. 表达式B. 单词C. 语句D. 词组二、判断题(对于下列陈述中正确的说法选择回答“对”,否则选择回答“错”)。
1. 编译程序是一种常见的应用软件。
2. C语言的编译程序可以用C语言编写。
3. 编译方式与解释方式的区别之一在于是否生成目标程序。
4. 中间代码生成是编译程序不可或缺的部分。
5. 含有优化的编译程序执行效率高。
三、解释下列术语:(1)编译程序(2)源程序(3)目标程序(4)编译程序的前端(5)后端(6)遍四、一个典型的编译程序通常由哪些部分组成?各部分的主要功能是什么?并画出编译程序的总体结构图。
五、何谓翻译程序、编译程序和解释程序?它们三者之间有何种关系?参考答案:一、选择题1. D2. A3. AC4. C5. B二、判断题1.错2.对3.对4.错5.错三、(1)把用高级程序设计语言书写的源程序,翻译成等价的计算机汇编语言或机器语言书写的目标程序的翻译程序。
(2)源程序,是指未经编译的,按照一定的程序设计语言规范书写的,人类可读的文本文件。
(3)为源程序经编译可直接被计算机运行的机器码集合,在计算机文件上以.obj作扩展名。
(4)编译程序的前端通常指:词法分析、语法分析、语义分析等生成最终代码以前的一系列步骤。
编译原理(第2版)课后习题答案详解

第1 章引论第1 题解释下列术语:(1)编译程序(2)源程序(3)目标程序(4)编译程序的前端(5)后端(6)遍答案:(1)编译程序:如果源语言为高级语言,目标语言为某台计算机上的汇编语言或机器语言,则此翻译程序称为编译程序。
(2)源程序:源语言编写的程序称为源程序。
(3)目标程序:目标语言书写的程序称为目标程序。
(4)编译程序的前端:它由这样一些阶段组成:这些阶段的工作主要依赖于源语言而与目标机无关。
通常前端包括词法分析、语法分析、语义分析和中间代码生成这些阶段,某些优化工作也可在前端做,也包括与前端每个阶段相关的出错处理工作和符号表管理等工作。
(5)后端:指那些依赖于目标机而一般不依赖源语言,只与中间代码有关的那些阶段,即目标代码生成,以及相关出错处理和符号表操作。
(6)遍:是对源程序或其等价的中间语言程序从头到尾扫视并完成规定任务的过程。
第2 题一个典型的编译程序通常由哪些部分组成?各部分的主要功能是什么?并画出编译程序的总体结构图。
答案:一个典型的编译程序通常包含8 个组成部分,它们是词法分析程序、语法分析程序、语义分析程序、中间代码生成程序、中间代码优化程序、目标代码生成程序、表格管理程序和错误处理程序。
其各部分的主要功能简述如下。
词法分析程序:输人源程序,拼单词、检查单词和分析单词,输出单词的机内表达形式。
语法分析程序:检查源程序中存在的形式语法错误,输出错误处理信息。
语义分析程序:进行语义检查和分析语义信息,并把分析的结果保存到各类语义信息表中。
中间代码生成程序:按照语义规则,将语法分析程序分析出的语法单位转换成一定形式的中间语言代码,如三元式或四元式。
中间代码优化程序:为了产生高质量的目标代码,对中间代码进行等价变换处理。
目标代码生成程序:将优化后的中间代码程序转换成目标代码程序。
表格管理程序:负责建立、填写和查找等一系列表格工作。
表格的作用是记录源程序的各类信息和编译各阶段的进展情况,编译的每个阶段所需信息多数都从表格中读取,产生的中间结果都记录在相应的表格中。
opg文法 -回复

opg文法-回复[oPG文法] 是一种常用于游戏编程中的一种框架。
它允许开发人员通过简化代码和提供易于使用的功能来快速构建游戏。
本文将一步一步回答有关[oPG文法] 的问题,并深入探讨其在游戏开发中的应用。
一、什么是[oPG文法]?[oPG文法]是"Object Placement Grammar"的缩写,它是一种用于描述3D场景中对象布局的方法。
它基于文法理论,将场景的建模问题转化为语法规则的表示和应用。
通过这种方式,开发人员可以通过简单的规则和参数来生成复杂的场景,提供了一种简化游戏开发的方式。
二、如何使用[oPG文法]?使用[oPG文法]进行游戏开发的第一步是定义语法规则。
开发人员需要确定场景中需要生成的对象类型和其布局规则。
这些规则通常是基于开发人员的需求和设计目标而建立的。
一旦规则确定,开发人员可以使用[oPG 文法]定义一个语法,该语法包含了对象的类型和与之相关的布局规则。
三、[oPG文法]的基本组成部分[oPG文法]的基本组成部分包括终结符、非终结符、产生式和语法规则。
1. 终结符:指的是文法中的最基本的单位,它表示具体的对象类型或属性。
例如,在一个城市场景中,街道、建筑物和树木可以是终结符。
2. 非终结符:指的是可以根据产生式推导出其他符号的符号。
非终结符可以表示对象的组合、布局和变换。
例如,在一个城市场景中,街区、街道网格和街道排布可以是非终结符。
3. 产生式:指的是一条规则,用于描述如何从一个非终结符推导出一个或多个终结符或非终结符。
产生式也可以包含一些参数,用于控制对象的生成和布局。
例如,在一个城市场景中,可以使用产生式描述如何根据一个街道网格生成一个街区。
4. 语法规则:指的是一组产生式的集合,用于描述整个系统的生成过程。
语法规则由若干非终结符的起始符号和一组产生式组成。
例如,在一个城市场景中,语法规则可以包括街道网格、街区和街道的生成规则。
四、如何应用[oPG文法]进行游戏开发?[oPG文法]可以在游戏开发的各个阶段中应用,包括场景设计、关卡设计和游戏内容生成。
算符优先_实验报告

一、实验目的1. 理解算符优先分析法的原理和过程。
2. 掌握算符优先分析法的实现方法。
3. 通过实验加深对自底向上语法分析方法的理解。
二、实验内容1. 算符优先分析法原理介绍算符优先分析法是一种自底向上的语法分析方法,它通过比较相邻算符的优先次序来识别句型中的句柄,进而执行归约。
该方法的核心是确立文法的终结符之间的优先关系。
2. 实验步骤(1)判断文法是否为OG文法:OG文法要求所有产生式右部至少有一个终结符。
(2)判断文法是否为OPG文法:计算FIRSTVT集、LASTVT集,并构建算符优先矩阵。
(3)对句子进行分析:根据分析表判断句子是否为文法的句子。
(4)实现程序:从文件和键盘读取输入,将结果输出到指定文件和屏幕,并具有一致性。
3. 实验数据(1)文法:g[e]:e->e+t|t(2)测试句子:12+t, t+12, 12+13t, 12+t13三、实验过程1. 判断文法是否为OG文法根据给定的文法,我们可以看到所有产生式右部至少有一个终结符,因此该文法为OG文法。
2. 判断文法是否为OPG文法,并构建算符优先矩阵(1)计算FIRSTVT集FIRSTVT(e) = {t}FIRSTVT(t) = {t}(2)计算LASTVT集LASTVT(e) = {t}LASTVT(t) = {t}(3)构建算符优先矩阵| + - ( ) t e $+ > - - - > > -- > - - - > > -> > > > > > >( > > > > > > >) - - - - - - -t - - - - - - -e - - - - - - -$ - - - - - - -3. 对句子进行分析(1)分析句子“12+t”根据分析表,我们可以得到以下分析过程:12+t -> 12+t -> 12+t -> t -> t(2)分析句子“t+12”根据分析表,我们可以得到以下分析过程:t+12 -> t+12 -> t+12 -> t+12 -> t+12 -> t -> t (3)分析句子“12+13t”根据分析表,我们可以得到以下分析过程:12+13t -> 12+13t -> 12+13t -> 12+13t -> 12+13t -> t -> t(4)分析句子“12+t13”根据分析表,我们可以得到以下分析过程:12+t13 -> 12+t13 -> 12+t13 -> 12+t13 -> 12+t13 -> t13 -> t13 -> t13 -> t -> t四、实验结果1. 测试句子“12+t”分析结果:正确2. 测试句子“t+12”分析结果:正确3. 测试句子“12+13t”分析结果:正确4. 测试句子“12+t13”分析结果:正确五、实验总结通过本次实验,我们深入了解了算符优先分析法的原理和实现方法。
习题与答案-5-语法分析-自下而上-优先分析

第六章P1163.有文法G[S]:S—>V V—>T|ViT T—>F|T+F F—>)V*|( (1)给出( + ( i ( 的规范推导。
(2)指出句型F+Fi(的短语,句柄,素短语。
(3)G[S]是否OPG?若是,给出(1)中句子的分析过程。
3. G[S]: S—>VV—>T|ViTT—>F|T+FF—>)V*|((1)S S=>V=>ViT=>ViF=>Vi(=>Ti(=>T+Fi(=>T+(i(V =>F+(i(=>(+(I(V i TT FT + F (F (((2) S 短语 F , F+F , ( , F+Fi(句柄 FV 素短语F+F , (V i TT FT + F (F(3) V N FIRSTVT LASTVTF ) ( * (T ) ( + * ( +V ) ( + i * ( + iS ) ( + i * ( + i由V—>ViT得任意(LASTVT(V))>i , i<任意(FIRSTVT(T)) 由#S#得# = ##<任意(FIRSTVT(S)) , 任意(LASTVT(S))># 由T—>T+F得任意(LASTVT(T))>+ +<任意(FIRSTVT(F)) 由F—>)V*得)=* ) < 任意(FIRSTVT(V))任意(LASTVT(V))>* 由此构造运算符优先关系表如下:i + ) * ( #i > < < > < >+ > > < > < >) < < < = <* > > > >( > > > ># < < < < =由关系表中任何两符号只有一种关系知文法为OPG文法步栈当前符号余留串关系动作0 # (+(i(# #<( 移进1 #( + (i(# (>+ 归约2 #N + (i(# #<+ 移进3 #N+ ( i(# +<( 移进4 #N+( i (# (>i 归约5 #N+N i (# +>i 归约6 #N i (# #<i 移进7 #Ni ( # i<( 移进8 #Ni( # (># 移进9 #NiN # i># 归约10 #N # #=# 成功4.已知文法G[S]为:S—>S;G|G G—>G(T)|H H—>a|(S) T—>T+S|S (1)构造G[S]的算符优先关系表,并判断G[S]是否为算符优先文法。
自下而上语法分析
自下而上语法分析1、规约:自下而上的语法分析过程:分为简单优先分析法,算符优先分析法,LR分析法。
2、自下而上的语法分析过程思想:自下而上的语法分析过程是一个最左规约的过程,从输入串开始,朝着文法的开始符号进行规约,直到文法的开始符号为止的过程。
输入串在这里是指词法分析器送来的单词符号组成的二元式的有限序列。
3、自下而上的PDA(下推自动机)工作方式:“移近-规约”方式注:初态时栈内仅有栈顶符“#”,读头指在最左边的单词符号上。
语法分析程序执行的动作:◆移进:读入一个单词并压入栈内,读头后移◆规约:检查栈顶若干符号能否进行规约,若能,就以产生式左部代替该符号串,同时输出产生式编号。
◆识别成功:移近-规约的结局是栈内只剩下栈底符号和文法的开始符号,读头也指向语句的结束符。
◆识别失败。
4、判读一语句是否是该文法的合法语句(可以用语法树)5、优先分析器:简单优先分析法(理论简单,实际比较麻烦)算符优先分析法6、LR分析器7、相邻文法符号之间的优先关系◆在句型中,句柄内各相邻符号之间具有相同的优先级。
◆由于句柄要先规约,所以规定句柄两端符号的优先级要比位于句柄之外的相邻符号的优先级高。
(#的优先级是最低的。
)9、简单优先文法:定义:一个文法G,如果它不含ε的产生式,也不含任何右部相同的不同产生式,并且它的任何符号(X,Y)-X,Y是非终结符或终结符—或者没有关系,或者存在优先级相同或低于、高于等关系之一,则这是一个简单优先文法。
10、简短优先分析的思想1)简单优先矩阵:根据优先关系的定义:将简单优先文法中各文法符号之间的这种关系用一个矩阵表示,称作简单优先矩阵。
2)PDA读入一个单词后,比较栈顶符号和该单词的优先级,若栈顶符号优先级低于该单词,继续读入;若栈顶符号优先级高于或者等于读入符号,则找句柄进行规约,找不到句柄继续读入11、简单优先法的优缺点:1、优点:算法比较好理解。
2、缺点:适用范围小,分析表尺寸太大。
编译原理之OPG文法
编译原理之OPG文法OPG文法#include "string.h"#include "stdlib.h"#define STR_MAX 80 //串的最大长度#define MAX_NUM 100 //符号的最大个数#define MAX 32767 //文件中符号的最大个数char M[MAX_NUM][MAX_NUM];struct PRO{ //产生式类型char left;char right[STR_MAX];};struct VNstru{char vn;char firstVT[MAX_NUM];char lastVT[MAX_NUM];};char SOUR[STR_MAX]; //源文件名char OBJ[STR_MAX]; //目标文件名char ERR[STR_MAX]; //错误信息文件名FILE *INF; //源程序文件指针FILE *OUTF; //分析结果文件指针FILE *ERRF; //错误信息文件指针char OPG[MAX]; //存放上下文无关文法int OPGlen; //上下文无关文法长度VNstru VN[MAX_NUM]; //非终结符数组int VN_CNT; //非终结符个数char VT[MAX_NUM]; //终结符数组int VT_CNT; //终结符个数char S0; //开始符号PRO P[MAX_NUM]; //产生式数组int P_CNT; //产生式个数bool isIN(char ch,VNstru arr[]);//判别符号ch是否在arr数组中int isVN(char ch); //判别符号ch是否在VN数组中,存在则返回下标,否则返回-1int isVT(char ch); //判别符号ch是否在VT数组中,存在则返回下标,否则返回-1 void getOPG(); //从源文件取得OPG文法串void getVN_VT_S_P(); //从OPG文法提取VN,VT,S,Pvoid FirstVT(char ch,char firstVT[]); //求FirstVT[]集firstVTvoid LastVT(char ch,char lastVT[]); //求LastVT[]集lastVTbool O_P_G(); //判别是否是OPG文法void create_M(); //构造M[][]void leftphase(char str[],char substr[],char a); //求最左素短语substrvoid left_str(char w[],char subw[],int ip); //求剩余输入串subw bool isIN(char ch,VNstru arr[])//判别符号ch是否在arr数组中{for(int i=0;i<vn_cnt;i++)< p="">if(ch==arr[i].vn)return 1;return 0;}int isVN(char ch) //判别符号ch是否在VN数组中,存在则返回下标,否则返回-1{for(int i=0;i<vn_cnt;i++)< p="">{if(ch==VN[i].vn)return i;}return -1;}int isVT(char ch)//判别符号ch是否在VT数组中,存在则返回下标,否则返回-1{for(int i=0;i<vt_cnt;i++)< p="">{if(ch==VT[i])return i;}return -1;}void getOPG()//从源文件取得OPG文法串{OPGlen=0;char ch;while(!feof(INF)){ch=fgetc(INF);if(ch!=' ')OPG[OPGlen++]=ch;}OPG[OPGlen]='\0';pr int f("The OPG is :\n"); //将文法输出到屏幕puts(OPG);fpr int f(OUTF,"The OPG is :\n");fputs(OPG,OUTF); //将文法输出到文件}void getVN_VT_S_P()//从OPG文法提取VN,VT,S,P {VN_CNT=0;VT_CNT=0;P_CNT=0;int newPF=0; //是否进入新产生式的标志int rightLen=0;char prech,ch,nextch;for(int i=0;i<opglen;i++)< p="">{if(i!=0) prech=OPG[i-1]; //取文法文件中的前一个符号ch=OPG[i]; //取文法文件中的当前符号nextch=OPG[i+1]; //取文法文件中的下一个符号if(nextch=='~') //下一个符号是~,代表箭头{if(isVN(ch)==-1){ //当前符号不是已经识别到的VN VN[VN_CNT].vn=ch; //加入VNVN_CNT++;}P[P_CNT].left=ch; //记入新产生式的左部if(P_CNT==0)S0=ch; //第一条产生式的左部是开始符号i++; //跳过~}if(prech=='~'||prech=='|'){newPF=1; //进入新的产生式rightLen=0;}if(newPF==1){P[P_CNT].right[rightLen++]=ch;}if(nextch=='\n'||nextch=='|'){newPF=0; //一条产生式结束P_CNT++; //产生式个数加1P[P_CNT].left=P[P_CNT-1].left;i++; //跳过回车和|}}for(int j=0;j<opglen;j++)< p="">{ch=OPG[j];if(ch!='~'&&ch!='|'&&ch!='\n'&&isVN(ch)==-1&&isVT(ch)==-1&&ch!=' ') VT[VT_CNT++]=ch;}VT[VT_CNT++]='#';VT[VT_CNT]='\0';//输出VNpr int f("\nVN:\t");fpr int f(OUTF,"\nVN:\t");for(int x=0;x<vn_cnt;x++)< p="">{pr int f("%c",VN[x].vn);fpr int f(OUTF,"%c",VN[x].vn);}//输出VTpr int f("\nVT:\t%s\n",VT);fpr int f(OUTF,"\nVT:\t%s\n",VT);//输出Spr int f("S0:\t%c\n\n",S0);fpr int f(OUTF,"S0:%c\n\n",S0);//输出Pfor(int k=0;k<p_cnt;k++)< p="">{pr int f("P[%d]:\t%c-->%s\n",k,P[k].left,P[k].right);fpr int f(OUTF,"P[%d]:\t%c-->%s\n",k,P[k].left,P[k].right);}pr int f("\n");fpr int f(OUTF,"\n");}//FIRSTVT(B)={b|B=>b...或B=>Cb...}int f=0;void FirstVT(char ch,char firstVT[])//求非终结符的FirstVT集,存至firstVT中{if(isIN(ch,VN))for(int i=0;i<p_cnt;i++)< p="">{if(ch==P[i].left){int j=0;char a=P[i].right[j];//B->b...if(isVT(a)!=-1){firstVT[f++]=a;firstVT[f]='\0';}//B->Cb...if(isVN(a)!=-1 && isVT(P[i].right[j+1])!=-1){firstVT[f++]=P[i].right[j+1];firstVT[f]='\0';}//B->C,C->b...||Db...if(isVN(a)!=-1 && strlen(P[i].right)==1)FirstVT(a,firstVT);}}f=0; //f清零,便于重复调用此函数}//LASTVT(B)={a|B=>...a或B=>...aC}int l=0;void LastVT(char ch,char lastVT[])//求非终结符的LastVT集,存放至lastVT中{if(isIN(ch,VN))for(int i=0;i<p_cnt;i++)< p="">{if(ch==P[i].left){int j=strlen(P[i].right)-1; //'j'记录右部的最后一个字符位置char a=P[i].right[j];//B->...a;if(isVT(a)!=-1){lastVT[l++]=a;lastVT[l]='\0';}//B->...aC;if(isVN(a)!=-1 && isVT(P[i].right[j-1])!=-1) {lastVT[l++]=P[i].right[j-1];lastVT[l]='\0';}//B->C,C->...a||...aD;if(isVN(a)!=-1 && j==0)LastVT(a,lastVT);}}l=0; //l清零,便于重复调用此函数}bool O_P_G()//判别是否是OPG文法{//求所有非终结符的firstVT集for(int i=0;i<vn_cnt;i++)< p="">{char fvt[STR_MAX];FirstVT(VN[i].vn,fvt);strcpy(VN[i].firstVT,fvt);pr int f("FirstVT(%c)={ ",VN[i]);fpr int f(OUTF,"FirstVT(%c)={ ",VN[i]);for(int j=0;j<(int)strlen(fvt);j++){pr int f("%c ",fvt[j]);fpr int f(OUTF,"%c ",fvt[j]);}pr int f("}\n");fpr int f(OUTF,"}\n");}pr int f("\n");fpr int f(OUTF,"\n");//求所有非终结符的lastVT集for(i=0;i<vn_cnt;i++)< p="">{char lvt[STR_MAX];LastVT(VN[i].vn,lvt);strcpy(VN[i].lastVT,lvt);pr int f("LastVT(%c)={ ",VN[i]);fpr int f(OUTF,"LastVT(%c)={ ",VN[i]); for(int j=0;j<(int)strlen(lvt);j++){pr int f("%c ",lvt[j]);fpr int f(OUTF,"%c ",lvt[j]);}pr int f("}\n");fpr int f(OUTF,"}\n");}//判别是否是OPG文法for(i=0;i<p_cnt;i++)< p="">{int j=0;while(P[i].right[j+1]!='\0'){char ch=P[i].right[j];char nextch=P[i].right[j+1];if(isVN(ch)!=-1 && isVN(nextch)!=-1) {pr int f("\nThe GFG is not OPG !\n\n");fpr int f(OUTF,"\nThe GFG is not OPG !\n\n");return 0;}elsej++;}}return 1;}void create_M()//构造M[][]{//a=b 的情况: A->...ab... || A->...aBb...for(int i=0;i<p_cnt;i++)< p="">{int j=0;char prech=' ',ch=' ',nextch=' '; //当进入新的产生式时,要清空三字符的值;while(P[i].right[j]!='\0'){if(j!=0)prech=ch;ch=P[i].right[j];nextch=P[i].right[j+1];if(isVT(ch)!=-1 && isVT(nextch)!=-1) //A->..ab..{M[isVT(ch)][isVT(nextch)]='=';j++;continue;}if(isVT(ch)!=-1 && isVN(nextch)!=-1) //A->..aB...{j++;continue;}if(isVT(prech)!=-1 && isVN(ch)!=-1 && isVT(nextch)!=-1) //A->..aBb..{M[isVT(prech)][isVT(nextch)]='=';j++;continue;}elsej++;}//(while)}//(for)M[VT_CNT-1][VT_CNT-1]='='; //#=#//a...aB... 且b属于FirstVT(B);for(i=0;i<p_cnt;i++)< p="">{int j=0;char ch=' ',nextch=' ';while(P[i].right[j]!='\0'){ch=P[i].right[j];nextch=P[i].right[j+1];if(isVT(ch)!=-1 && isVN(nextch)!=-1) //A->..aB..;a<firstvt(b)< p="">{FirstVT(nextch,VN[isVN(nextch)].firstVT);for(int m=0;VN[isVN(nextch)].firstVT[m]!='\0';m++) M[isVT(ch)][isVT(VN[isVN(nextch)].firstVT[m])]='<'; j++;continue;}else if(isVN(ch)!=-1){j++;continue;}elsej++;}//(while)}//(for)for(int x=0;x<="" firstvt(s0);<="" p="">M[VT_CNT-1][isVT(VN[isVN(S0)].firstVT[x])]='<';//a>b的情况:A->...Bb... 且a属于LastVT(B);for(i=0;i<p_cnt;i++)< p="">{int j=0;char ch=' ',nextch=' ';while(P[i].right[j]!='\0'){ch=P[i].right[j];nextch=P[i].right[j+1];if(isVT(ch)!=-1) //A->..ab..||..aB..{j++;continue;}if(isVN(ch)!=-1 && isVT(nextch)!=-1) //A->..Bb..;LastVT[B]>b {LastVT(ch,VN[isVN(ch)].lastVT);for(int m=0;VN[isVN(ch)].lastVT[m]!='\0';m++)M[isVT(VN[isVN(ch)].lastVT[m])][isVT(nextch)]='>';j++;continue;}elsej++;}//(while)}//(for)for(x=0;x<(int)strlen(VN[isVN(S0)].lastVT);x++) //LastVT(S0) > #M[isVT(VN[isVN(S0)].lastVT[x])][VT_CNT-1]='>';}//(end)void leftphase(char str[],char substr[],char a)//求最左素短语,用substr存储{int slen=strlen(str);int begin,end=slen-1;for(int i=slen-1;i>0;i--){if(M[isVT(str[i])][isVT(a)]=='>'){if(M[isVT(str[i-1])][isVT(str[i])]=='<')begin=i;else{begin=i-1;continue;}}if(isVN(str[i]))continue;}int j=0;int b=begin; //必须将begin的值记录,因为while的循环条件与begin有关,否则会影响素短语的取值。
2005年编译原理试题A
一.选择题(60分,每小题2分,答案请填写在答题纸上)1.编译程序是对( )。
A.汇编程序的翻译B.高级语言程序的解释执行C.机器语言的执行D.高级语言的翻译2.构造编译程序应掌握( )。
A.源程序B.目标语言C.编译方法D.以上三项都是3.编译程序绝大多数时间花在( )上。
A.出错处理B.词法分析C.目标代码生成D.表格管理4.编译技术中描述单词符号的形成规则的常用工具有()。
A.正规文法B.正规式C.有穷自动机D.以上都是5.编译技术中常用()描述程序语言的语义。
A.正规文法B.上下文无法文法C.属性文法D.上下文有关文法6.词法分析器的输出结果是( )。
A.单词的种别编码B.单词在符号表中的位置C.单词的种别编码和自身值D.单词自身值7.以下( )不是DFA的组成部分。
A.有穷字母表B.初始状态集合C.终止状态集合D.有限状态集合8.正规式M1和M2等价是指( )。
A.Ml和M2的状态数相等B.M1和M2的有向边条数相等C.M1和M2所识别的语言集相等D.M1和M2状态数和有向边条数相等9. 下图所示的DFA M 接受的字集为( )。
A .以0开头的二进制数组成的集合B ,以0结尾的二进制数组成的集合C .含奇数个0的二进制数组成的集合D .含偶数个0的二进制数组成的集合 10. 有文法G (S ):S ->aA| a |bC A ->aS | bB B ->aC | bA | b C ->aB | bS则下列( )为L (G )中的句子。
A .a 100b 50ab 100 B .a 1000b 500aba C .a 500b 60aab 2a D .a 100b 40ab 10aa11. 文法G[S]:S →xSx | y 所识别的语言是( )。
A .xyxB .(xyx)*C .x n yx n (n ≥0)D .x*yx*12. 给定语言L 为:所有以0开头,后接零个或多个10组成的符号串的集合,则描述它的正规文法G[S]应为( )。
第6章自底向上优先分析法
第6章⾃底向上优先分析法⾃底向上分析⽅法,也称移进-归约分析法,粗略地说它的实现思想是对输⼊符号串⾃左向右进⾏扫描,并将输⼊符逐个移⼊⼀个后进先出栈中,边移⼊边分析,⼀旦栈顶符号串形成某个句型的句柄时,(该句柄对应某产⽣式的右部),就⽤该产⽣式的左部⾮终结符代替相应右部的⽂法符号串,这称为归约。
重复这⼀过程直到归约到栈顶中只剩⽂法的开始符号时则为分析成功,也就确认输⼊串是⽂法的句⼦。
本章将在介绍⾃底向上分析思想基础上,着重介绍算符优先分析法。
例6.1,设⽂法G[S]为:(1)S→aAcBe(2)A→b(3)A→Ab(4)B→d对输⼊串abbcde#进⾏分析,检查该符号串是否是G[S]的句⼦。
由于⾃底向上分析的移进-归约过程是⾃顶向下最右推导的逆过程,⽽最右推导为规范推导,⾃左向右的归约过程也称为规范归约。
容易看出对输⼊串abbcde的最右推导为:S aAcBe aAcde aAbcde abbcde由此我们可以构造它的逆过程即归约过程。
先设⼀个后进先出的符号栈,并把句⼦左括号”#”号放⼊栈底。
对上述分析过程也可看成⾃底向上构造语法树的过程,每步归约都是构造⼀棵⼦树,最后当输⼊串结束时刚好构造出整个语法树。
在上述移进-归约或⾃底向上构造语法树的过程中,考虑⼏个问题:u 何时移进?u 何时归约?u 将哪个字符串归约?当⼀个⽂法⽆⼆义性时,那么它对⼀个句⼦的规范推导是唯⼀的,规范规约也必然是唯⼀的。
因⽽每次归约时要找当前句型的句柄,也就是说,任何时候栈中的符号串和剩余的输⼊串组成⼀个句型,当句柄出现在栈顶符号串中时,则可⽤句柄归约,这样⼀直归约到输⼊串只剩结束符,⽂法符号栈中只剩开始符号。
由此可见,⾃底向上分析的关键问题是在分析过程中如何确定句柄,即如何知道何时在栈顶符号串中已形成某句型的句柄。
然⽽⾃底向上的分析算法很多,我们仅在本章和第7章介绍⽬前常⽤的算符优先分析和LR类分析法。
6.1 ⾃底向上优先分析法概述优先分析法⼜可分简单优先法和算符优先分析法。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
OPG文法
1. 什么是OPG文法?
OPG文法(Operator Precedence Grammar)是一种用于描述算术表达式的上下文
无关文法。
它通过使用操作符优先级来解析表达式,并使用一个优先级表来确定操作符之间的结合性。
在OPG文法中,每个终结符都有一个关联的优先级,而每个非终结符都有一个关联的产生式。
通过比较相邻操作符的优先级,可以确定正确的语法分析树。
2. OPG文法规则
OPG文法由终结符、非终结符和产生式组成。
以下是一些常见的OPG文法规则:•终结符:表示最基本的语言单位,如数字、运算符等。
•非终结符:表示由终结符组成的复杂语言单位,如表达式、项等。
•产生式:定义了如何将非终结符转换为其他非终结符或终结符。
下面是一个简单的示例OPG文法:
E -> E + T
E -> E - T
E -> T
T -> T * F
T -> T / F
T -> F
F -> ( E )
F -> id
在这个例子中,E、T和F分别表示表达式、项和因子。
每个产生式右侧的箭头表
示如何将左侧的非终结符转换为右侧的非终结符或终结符。
3. 操作符优先级和结合性
在OPG文法中,每个操作符都有一个关联的优先级。
较高优先级的操作符在语法分析树中较低优先级的操作符之上。
此外,每个操作符还有一个关联的结合性,用于处理相同优先级的操作符。
结合性可以是左结合(left-associative)或右结合(right-associative)。
左结合表
示从左到右计算,右结合表示从右到左计算。
例如,在常见的四则运算中,乘法和除法具有较高的优先级,并且具有左结合性。
这意味着乘法和除法会在加法和减法之前进行计算,并按从左到右的顺序进行计算。
4. OPG文法分析
使用OPG文法进行语法分析涉及两个主要步骤:构建预测分析表和使用该表进行分析。
4.1 构建预测分析表
预测分析表是一个二维表格,其中行表示当前状态,列表示输入符号。
每个单元格包含一个产生式编号或错误标记。
构建预测分析表的过程如下:
1.对于每个产生式A -> α,找到其右侧的第一个符号α。
2.如果α是终结符,则将产生式A -> α添加到表格中所有FIRST(α)的
单元格。
3.如果α是非终结符,则将产生式A -> α添加到表格中所有FOLLOW(A)
的单元格。
如果ε在FIRST(α)中,则还应该将产生式添加到表格中所
有对应终结符的单元格。
4.2 使用预测分析表进行分析
使用预测分析表进行语法分析的过程如下:
1.初始化栈和输入缓冲区,并将$(结束标记)放入缓冲区。
2.从输入缓冲区中读取一个符号,并查看栈顶的终结符和输入符号。
3.如果栈顶和输入符号相等,则将它们都弹出,并从缓冲区读取下一个符号。
4.否则,查找预测分析表中栈顶和输入符号对应的产生式编号。
如果没有找到
任何产生式编号,则表示出现了语法错误。
5.如果找到了产生式编号,将相应的产生式右侧推入栈中。
重复步骤2至5,直到完成语法分析或发现错误。
5. OPG文法的应用
OPG文法广泛用于编译器设计和实现中的语法分析阶段。
它可以用于解析和验证算术表达式,构建语法分析树,并生成中间代码。
在编译器中,OPG文法还可以与其他文法形式(如LL文法和LR文法)相结合,用于实现更复杂的语言特性。
6. 总结
OPG文法是一种用于描述算术表达式的上下文无关文法。
它使用操作符优先级和结合性来解析表达式,并通过预测分析表进行语法分析。
OPG文法在编译器设计和实现中起着重要作用,能够处理各种复杂的语言特性。
希望通过本文对OPG文法有一个清晰的认识,并理解其在语法分析中的应用。