1、编译原理实验消除文法的左递归编译原理实验报告实验名称:消除文法的左递归实验时间:2015/5/28院系:管理与信息工程学院班级:12级计算机科学与技术学号:0124姓名:刘杨凡1.实验目的:输入:任意的上下文无关文法。 输出:消除了左递归的等价文法。2.实验原理:1直接左递归的消除假设非终结符 P 的规则为:P Pa/ B其中,B是不以P开头的符号串。那么,我们可以把 P的规则改写为如下的非直 接左递归形式: PBPP oP / 这两条规则和原来的规则是等价的,即两种形式从 P推出的符号串是相同的。设有简单表达式文法 GE:EE+T/ TTT*F/ FF(E)/ I 经消除直接左递归后得到如下
2、文法:ETEE +TE/ TFTT *FT/ F(E)/ I考虑更一般的情况,假定关于非终结符 P的规则为P Pal / Po2 / P an / Bi/ B / 和其中,a (1 = 1, 2,n)都不为而每个B (j= 1, 2,m)都不以P开 头,将上述规则改写为如下形式即可消除 P的直接左递归:P Bi P/ B P/ Bm PP a1 P / a2 P / an P /2间接左递归的消除直接左递归见诸于表面, 利用以上的方法可以很容易将其消除, 即把直接左 递归改写成直接右递归。 然而文法表面上不存在左递归并不意味着该文法就不存 在左递归了。有些文法虽然表面上不存在左递归,但却隐藏着
3、左递归。例如,设 有文法 GS:S Qc/ cQRb/ bR Sa/ a虽不具有左递归,但S、Q、R都是左递归的,因为经过若干次推导有S Qc Rbc SabcQ Rb Sab QcabR Sa Qca Rbca就显现出其左递归性了,这就是间接左递归文法。消除间接左递归的方法是, 把间接左递归文法改写为直接左递归文法, 然后 用消除直接左递归的方法改写文法。如果一个文法不含有回路,即形如 P P的推导,也不含有以&为右部的产生式,那么就可以采用下述算法消除文法的所有左递归。消除左递归算法:(1)把文法G的所有非终结符按任一顺序排列,例如, Ai, A2,,An。(2)for (i = 1 ;
4、i=n; i+)for (j= 1; j=i 1; j+) 把形如Aif AjY的产生式改写成 Aif1 丫/ 62 丫/ &丫 其中Ajf 61 / 6 / &是关于的Aj全部规则; 消除Ai规则中的直接左递归;(3)化简由( 2)所得到的文法,即去掉多余的规则。 利用此算法可以将上述文法进行改写,来消除左递归。首先,令非终结符的排序为 R、Q、S。对于R,不存在直接左递归。把R代 入到Q中的相关规则中,贝U Q的规则变为Qf Sab/ ab/ b。代换后的Q不含有直接左递归,将其代入S, S的规则变为Sf Sabc/ abc/ bc/c。此时,S存在直接左递归。在消除了 S的直接左递归后,
5、得到整个文法为:SfabcS/bcS/ cSS f abcS/ &QfSab/ ab/ bRfSa/ a可以看到从文法开始符号 S出发,永远无法达到 Q和R,所以关于Q和R 的规则是多余的,将其删除并化简,最后得到文法 GS为:SfabcS/ bcS/cSS f abcS/ 当然如果对文法非终结符排序的不同,最后得到的文法在形式上可能不一 样,但它们都是等价的。例如,如果对上述非终结符排序选为 S、Q、R,那么最后得到的文法 GR为: Rf bcaR/ caR/ aRR fbcaR/ 容易证明上述两个文法是等价的。3.实验内容:消除左递归算法:(4)把文法G的所有非终结符按任一顺序排列,例如,
6、 A1, A2,An。(5)for (i = 1 ; i=n; i+)for (j= 1; j=i 1; j+)把形如AiAj 丫的产生式改写成 Aif Si Y & Y/ &丫 其中A s / & / &k是关于的Aj全部规则; 消除Ai规则中的直接左递归;( 6) 化简由( 2)所得到的文法,即去掉多余的规则。利用此算法可以将上述文法进行改写,来消除左递归。注意事项:指明是否存在左递归, 以及左递归的类型。 对于直接左递归, 可将其改为直 接右递归;对于间接左递归(也称文法左递归) ,则应按照算法给出非终结符不同排列的等价的消除左递归后的文法。(应该有n!种)4.代码实现( C 语言):#
7、include / 直接左递归函数/间接左递归函数/消除直接左递归函数/ 消除间接左递归函数#include #include #define N 20char PNN;char QN; char RNN;int r;/ 规则集/规则集,存放间接左递归消除后的部分规则/用来存放规则的初始值/实际输入的规则的个数int direct(char PNN);int indirect(char PNN); void directRemove(char PNN); void indirectRemove(char PNN);int direct(char PNN) /定义直接左递归函数int flag=
8、0;for(int i=0;i0)printf( 经判断该文法含有直接左递归 !n); return 1; / 属于直接接左递归elsereturn 0; / 不属于直接左递归int indirect(char PNN) / 定义间接左递归函数int flag=0;for(int i=0;ir;i+)for(int k=1;k0) break; if(flag0)printf( 经判断该文法含有间接左递归 !n);return 2; / 属于间接左递归elsereturn 0; / 不属于间接左递归void directRemove(char PNN) / 定义消除直接左递归的函数 int j
9、=4;for(int i=0;ir;i+) if(Pi3=Pi0) Pi3=Pi2;Pi2=Pi1;Pi1=; while(Pij!=0)j+;Pij=Pi0;Pij+1=;for(int k=0;k4;k+) / 包含空的一条规则 Prk=Pik;Prk=*;elsej=3;while(Pij!=0)j+;Pij=Pi0;Pij+1=;printf(n 消除直接左递归后的文法为 :n);printf(n);printf(* 代表& )n);printf(n);for(int t=0;tr+1;t+)printf(%sn,Pt);void indirectRemove(char PNN) /
10、定义消除间接左递归的函数int flag,flag1=0,copy=r;int e=0;Qe=Pe0; / 统计规则中不同的左部for(int i=1;ir;i+)flag=0;for(int k=0;k=e;k+)if(Pi0!=Qk) flag+;if(flag=(e+1)e+;Qe=Pi0;int g=0;for(int j=0;je;j+)int number=0;for(int z=0;z1) copy+;for(i=0;ir;i+)for(int k=1;kr;k+) if(Pi0=Pi+k3)&(flag1=0)for(int y=0;Pi+ky!=0;y+)Rgy=Pi+ky;
11、 / 把原值保留 flag1=1; int m=3;while(Pim!=0) / 统计替换字符的个数为 m-1-2 m+;int t=m-3;int n=4;while(Pi+kn!=0) / 统计被替换规则中非终结符的个数 for(int u=3;u=4;s-) Pi+ks+t-1=Pi+ks;for(int u=3;u=4;s-)Pcopy-1s+t-1=Pcopy-1s;Pcopy-1u=Piu;break;flag1=0;g+;printf( 首次消除间接左递归后的直接左递归文法为 :n); for(int t=0;tcopy;t+)printf(%sn,Pt);printf(n);
12、for(i=0;icopy;i+)if(Pi0=Qe)if(Pi3=Pi0)Pi3=Pi2;Pi2=Pi1;Pi1=;while(Pij!=0)j+;Pij=Pi0;Pij+1=;for(int k=0;k4;k+) / 包含空的一条规则Pcopyk=Pik;Pcopyk=*;elsej=3;while(Pij!=0)j+;Pij=Pi0;Pij+1=;printf( 再次消除直接左递归后的文法为 :n);printf(n);printf(* 代表& )n);printf(n);for(t=0;t连接,规则间用空格隔开 );printf(n);for(int k=0;kr;k+)scanf(%
13、s,Pk);printf(n);printf( 即输入的文法规则为 :n);for(k=0;kSa Sb即输入的文法规则为:S-SaS-经判断该立法含有亘叢左递归P除直接左递归后的文法为:S-bS-8 -”rrca an罗 hey to cant inuc消除文法间接左递归实例1如下:p F= lift锌原理養建浦除左SI归EuodigTiiDBbuxuodigiii_ ass请输入各棗规则h规则的左部跟右部用T连按,规则间用空格隔开 n-aB n-Eb H-Ac即输入的文法规则为:A-aBA-BbB-AcB-d星藉鮭噩薛養豊递口文祛力fl oDA EhB-&EcD-dB-Fhc甬腹泸睁言接左逋口肩的丈疔弋:A-aBA-EbB-aBcBB-dBfBJ-bcB*BJ-*Press any key to cantinue消除文法间接左递归实例2如下:
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1