这是一次编译原理的实验,总结输出一下:
原理:
对每一个非终结符(分别代表一个语法单位)按其产生方式结构构造相应的语法子程序,以完成非终结符号所对应的语法单位的分析和识别任务。其中终结符号产生匹配命令,而非终结符号则产生过程调用命令。因为文法可以递归,相应子程序也是递归的。
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;
}