语法制导定义,翻译方案,以及antlr实现_第1页
语法制导定义,翻译方案,以及antlr实现_第2页
语法制导定义,翻译方案,以及antlr实现_第3页
语法制导定义,翻译方案,以及antlr实现_第4页
语法制导定义,翻译方案,以及antlr实现_第5页
已阅读5页,还剩15页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

语法制导定义,翻译方案,以及antlr实现赵建华语法制导定义一般来说,在文法中的每个非终结符号都有对应于特定的文法结构。对于每个结构,都可以定义相应的属性。比如:每个语句对应的代码,每个表达式对应的类型,等等在不同的时候,我们对不同的属性感兴趣,也就给出不同的属性定义。语法制导定义语法制导定义中,规定了每个语法单位的属性值时如何由其他的语法单位的属性值确定。但是并不给出具体的计算次序。实际上,我们可以把语法制导定义看作是一种specification。它规定了各个属性应该满足怎么样的要求。语法制导定义的例子重写规则语义规则D::=TLD.idTable={(id,T.type)|idisinL.idList}T::=intT.type=intT::=realT.type=realL::=L1,idL.idList=L1.idList+{id}L::=idL.idList={id}语法制导定义在上面的例子中,D有一个属性idTable,表示在D对应的申明中定义的所有标志符。我们感兴趣的是D的idTable。为了定义idTable,我们引入了L的idList,T的type。书上面的定义实际上已经夹杂了一些实现方面的内容:addtype(id.entry,L.in)。但是还是比较好理解的。语法制导定义与翻译方案上面的例子里面没有规定如何计算各个属性的值。给定一个D对应的短语,我们可以画出相应的语法树,然后得到各个属性的值。而翻译方案给出了语法制导定义的具体实现。对于D的一个短语,在建立这个短语对应的语法树的过程中就可以按照翻译方案得到各个属性的值。翻译方案的抽象级别按照综合属性和继承属性的定义,我们可以确定每个属性应该在什么地方计算。比如,计算四则运算的翻译方案如下E::=E1+T {E.value=E1.value+T.value;}…但是这样做有的时候效率很低下:如果属性的值占用的内存非常大。有些工具不支持属性的引用(比如yacc?)。翻译方案的更加具体的实现有些值可以通过栈的方式来来传输:在LR(k)的分析过程中,栈里面的包含有归约得到的文法符号。我们可以在栈中每个符号的信息中加入一个指针,指向存放相应属性值的内存区域。也可以另外设立独立的栈来存放相应的值。比如书上的page219的例子。此时,翻译方案的操作顺序就非常重要了。翻译方案的更加具体的实现一些值可以通过全局变量来传递:有些属性的值所占用的内存非常大,如果使用拷贝的方式(包括栈或者直接传递)来传递,那么效率将非常低下。St::=ifEthenSt1elseSt2{}关于St的code属性。通过全局变量传递的时候要求能够做到增量计算。比如:语法制导定义要求St.code=E.code||St1.code||St2.code,…实现的时候不能够把这些code属性反复拷贝。翻译方案在写翻译方案的时候,如果对效率的要求不高,那么可以都使用属性直接应用和直接计算的方法。这样的翻译方案比较容易理解。关于代码生成的翻译方案书上面出现了两个版本:对code属性进行直接引用的方式。使用全局变量存放code的方式。两个版本的区别仅仅在于实现细节的不同。P248S::=IFETHENS1ELSES2 {E.true=newlabel;E.false=newlabel; S1.next=S.next;S2.next:=S.next; S.code=E.code||gencode(‘CMP’,E.place,“#1”) ||gencode(‘CJ=‘,E.true) ||gencode(‘GOTO’,E.false) ||gencode(E.true,‘:’)||S1.code ||gencode(‘GOTO’,S1.next) ||gencode(E.false,‘:’)||S2.code ||gencode(S.next,‘:’) }P252S::=IFETHENM1S1NELSEM2S2 { backpatch(E.truelist,M1.pos); backpatch(E.falselist,M2.pos); S.nextlist=merge(S1.nextlist,S2.nextlist); S.nextlist=merge(S.nextlist,N.nextlist);}E::=id1relopid2{E.truelist:=makelist(nextpos+2);E.falselist=makelist(nextpos+3);t:=newtemp;emit(‘MOV’,id1.place,t);emit(‘CMP’,t,id2.place);emit(‘CJ’||relop,‘_’);emit(‘GOTO’,‘_’)}实际存在一个全局变量存放code,前面的||操作实际上有emit函数不停添加代码的过程中完成了。P248和P252p252的方式可以使得我们避免使用标号,而直接使用代码的序号来完成跳转。原因是每个代码在全局中的位置已经确定。但是P252的更大的好处在于运行效率有很大的提高:不需要做code的合并操作。用antlr实现翻译方案如果使用对属性直接引用的方式,那么在antlr中有非常直接的对应方式。 typeExp returns[TypeInfo*tp] : tp=simpTypeExp | tp=structTypeExp ;使用全局数据传递的实现基本上也很直接。对于左递归的处理EE1+T{E.val=E1.val+T.val} |T{E.val=T.val}由于antlr允许使用EBNF的方式,所以上面的规则可以改写成为:ET(+T)*计算的规则成为ET{tmp=T.val;}(+T{tmp=tmp+T.val;})*{E.val=tmp;}关于LR技术主要目的是确定规范句型的句柄。文法G[E]:EE+T|T TT*F|F Fi|(E)对于规范句型的语法树,遍历其叶子节点的时候,在扫描完句柄之前,没有完备的语法子树出现。E+T*…TE关于LR技术在句柄之前的部分称为活前缀。活前缀需要满足的条件是什么呢?一个符号串是活前缀,iff我们可以构造这样的一个语法树的片断:其语法树的左边的叶子符合该符号串,并且不包含完备的子树。关于LR技术我们可以这样来画出一个活前缀的部分语法树:选择EE+T,然后选择TT*F。我们可以构造一个NFA来识别活前缀:初始状态对应于E.E+T,对于每个状态Vx.ay,有一个标记为a的弧到达Vxa.y。对于每个状态Vx.Uy,如果U是非终结符号,有一个空弧到达U.w。一个符号串是活前缀iff它是该

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论