这是一次编译原理的实验,总结输出一下:
原理:
对每一个非终结符(分别代表一个语法单位)按其产生方式结构构造相应的语法子程序,以完成非终结符号所对应的语法单位的分析和识别任务。其中终结符号产生匹配命令,而非终结符号则产生过程调用命令。因为文法可以递归,相应子程序也是递归的。
1)示范,示例LL(1)文法如下:
G[A]:
(1)S::=pA
(2)S::=qB
(3)A::=cAd
(4)A::=a
(5)B::=dB
(6)B::=b
对应每条规则的选择集如下:
(1){p}
(2){q}
(3){c}
(4){a}
(5){d}
(6){b}
上述LL(1)递归下降子程序示例代码:
#include <stdio.h> #include <stdlib.h> #include <string.h> #define SourceMaxLength 10000 //声明函数 void A(); void B(); //结构体存放待比较字符串 struct sourceStr{ char source[SourceMaxLength];//缓存字符串 int pointer;//字符串下表指针 }; struct sourceStr sour; char token;//存放当前比较的字符 int flag=1;//编译成功标记 char getToken()//获取当前字符 { token=sour.source[sour.pointer]; sour.pointer++; return token; } void getSource(FILE *fp)//用于从文件中获取字符串 { } void error()//错误输出操作 { flag=0; printf("error;"); } void S()//开始判断函数 { token=getToken(); if(token != 'p' && token!='q')//如果下一个当前取得的字符不为p\q,则字符串错误 error(); else { if(token == 'p')//如果当前字符为p { A();//执行非终结符A的判断 } else//否则执行非终结符B的判断 { B(); } } } void A()//执行非终结符A的判断 { token=getToken(); if(token!='c'&&token!='a')//如果当前字符不符合,输出错误 error(); else{ if(token=='c')//如果为c,则执行A判断 { A(); //判断下一个字符是否为d token=getToken(); if(token!='d') error(); } else{ ; } } } void B()//执行非终结符A的判断 { token=getToken(); if(token!='d'&&token!='b')//如果当前字符不符合,输出错误 error(); else{ if(token=='d')//如果为d,执行B函数 { B(); } } } int main() { sour.pointer=0; strcpy(sour.source,"pccaadd");//将字符串复制给sour.source //首先执行初始非终结符 S(); if(flag==1) { printf("success!"); } else { printf("error"); } return 0; }
2)下面是简化的四则运算的语法规则,递归下降子程序法不能直接用这组规则进行语法分析
G[E]:
E::=E+T
E::=T
T::=T*F
T::=F
F::=(E)
F::=i
但是我们可以通过改造文法后,构建一等价文法,可以利用递归下降子程序发进行语法分析,该等价文法如下:
1. E::=TA
2. A::=+TA
3. A::=
4. T::=FB
5. B::=*FB
6. B::=
7. F::=(E)
8. F::=i
对应规则的选择集如下:
1. {(,i}
2. {+}
3. {),#}
4. {(,i}
5. {*}
6. {+,),#}
7. {(}
8. {i}
代码如下:
#include <stdio.h> #include <stdlib.h> #include <string.h> #define SourceMaxLength 10000 //声明函数 void A(); void B(); void F(); void T(); //字符串结构体 struct sourceStr{ char source[SourceMaxLength];//缓存字符串 int pointer;//字符串下表指针 }; struct sourceStr sour; char token;//存放当前比较的字符 int flag=1;//编译成功标记 char getToken()//获取当前字符 { token=sour.source[sour.pointer]; sour.pointer++; return token; } void getSource(FILE *fp)//用于从文件中获取字符串 { } void error()//错误输出操作 { flag=0; printf("error;"); } void E()//开始判断函数 { token=getToken(); if(token != '(' && token!='i')//如果下一个当前取得的字符不为(、i,则字符串错误 error(); else{ if(token=='('){//如果为(,执行(),并取下一个字符 E(); token=getToken(); if(token!=')') error(); } B(); A(); } } void T()//非终结符T判断 { token=getToken(); if(token != '(' && token!='i')//如果下一个当前取得的字符不为(、i,则字符串错误 error(); else { if(token=='('){ E(); token=getToken(); if(token!=')') error(); } B(); } } void F()//非终结符F判断 { token=getToken(); if(token != '(' && token!='i') error(); else { if(token=='('){ E(); token=getToken(); if(token!='(') error(); } else{ ; } } } void A()//非终结符A判断 { token=getToken(); if(token!='+'&&token!=')'&&token!='#')//如果当前字符不符合,输出错误 error(); else{ if(token=='+') { T(); A(); }else{//如果A终结符为空,字符串指针回溯一个 sour.pointer--; } } } void B() { token=getToken(); if(token!='*'&&token!='+'&&token!=')'&&token!='#')//如果当前字符不符合,输出错误 error(); else{ if(token=='*') { F(); B(); }else{//如果B终结符为空,字符串指针回溯一个 sour.pointer--; } } } int main() { sour.pointer=0; strcpy(sour.source,"(i+i*i)+i*i#");//将字符串复制给sour.source //首先执行初始非终结符 E(); if(flag==1) { printf("success!"); } else { printf("error"); } return 0; }