语法分析程序
实验目的和内容
理解语法分析的功能和实现机制。掌握递归向下的语法分析方法。
实验要求
1. 完成实验的要求
附录是一个简单的算法表达式文法,如a+b*c-b/d就是一个该文法所表示的合法的表达式。请你为该文法编写一个递归向下的语法分析程序。
输入:字符串或者文本文件
输出:“合法表达式”或者“非法表达式”
例如:输入a+b*c-b/d则显示或者输出“合法表达式”,输入aa++–c*则显示或者输出“非法表达式”
提示:先消除文法的左递归
附录:
一个简单的算法表达式文法
〈算术表达式〉∷=〈项〉│〈算术表达式〉+〈项〉│〈算术表达式〉-〈项〉
〈项〉∷=〈因式〉│〈项〉*〈因式〉│〈项〉/〈因式〉
〈因式〉∷=〈变量〉│(〈算术表达式〉)
〈变量〉∷=a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z
说明:为了简化变量,即简化词法分析程序,此文法中变量的定义就是一个字母。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
/*
消除左递归后的文法:
S->BI
I->+BI|-BI|ξ //使用I消除左递归
B->CJ
J->*BI|/BI|ξ
C->V|(S)
V->a|…|z
First(S)={a,…,z,(}
First(I)={+,-, ξ}
First(B)={a,…,z,(}
First(J)={*,/, ξ}
First(C)={a,…,z,(}
First(V)={a,…,z}
Follow(S)={#,)}
Follow(B)={+,-,),#}
Follow(I)={#,)}
Follow(J)={+,-,),#}
Follow(C)={*,/,+,-,),#}
Follow(V)={*,/,+,-,),#}
*/
/* 符号 */
enum symbol //枚举类型
{
nul, end, ident, plus, times, lparen, divide, rparen, sub,
};
/*enum symbol sym;
#define nul 0
#define ident 1
#define plus 2
#define times 3
#define lparen 4
#define rparen 5
#define divide 6
#define sub 7*/
#define al 10 //标识符的最大长度
enum symbol sym; //当前的符号
char ch; //获取当前字符,getch 使用
char a[al+1]; //当前标识符ident
FILE* fin; //用于指向输入文件的指针
void getsym(); //读单词,将单词类别放入sym中
void S();
void I();
void B();
void J();
void C();
void V();
int main()
{
char filename[20]; //文件名数组
printf("请输入分析的文件名:");
gets(filename);
//scanf("%s",filename);
do
{
if((fin=fopen(filename,"r"))==NULL) //以只读方式打开文件,并判断输入文件名是否正确
{
printf("不能打开文件.\n");
return 0;
}
getsym(); //读第一个单词,将单词类别放入sym中
S(); //开始按S->BI 分析
if (sym==end) //程序递归中途没有exit(0)则是语法正确
{
printf("语法正确\n");
}
else
{
printf("语法错\n");
}
fclose(fin); //关闭文件
printf("继续分析则输入文件名,否则回车");
//scanf("%s",filename);
gets(filename);
}
while (strlen(filename)>0); //判断文件名字符串是否大于0
}
/*词法分析,获取一个符号*/
void getsym()
{
ch=fgetc(fin);
while (ch==' ' || ch==10 || ch==13 || ch==9) /* 忽略空格、换行、回车和TAB */
ch=fgetc(fin);
if (ch==EOF) sym=end; //如果到了文件末尾,则赋值为end
else if (ch>='a' && ch<='z')
sym = ident;
else if(ch == '+')
sym = plus;
else if (ch == '*')
sym = times;
else if (ch == '/')
sym = divide;
else if (ch == '-')
sym = sub;
else if (ch == '(')
sym = lparen;
else if (ch == ')')
sym = rparen;
else
{
sym = nul;
printf("--词法错\n"); //不是上面的first集中的元素
exit(0);
}
return;
}
//递归下降分析 分析产生式S->BI
void S()
{
if (sym==ident ||sym==lparen) //如果类型是标识符(变量)或者左括号
{
B(); //先按B推导,执行B
I(); //再按I推导,执行I
}
else
{
printf("语法错: 缺变量或者左括号\n");
exit(0);
}
}
//first集为+或-的时候
void I()
{
if(sym==plus||sym==sub) //如果类型是加或者减
{
getsym(); //读下一个单词
B(); //调用执行B
I(); //调用执行I
}
else if(sym==rparen || sym==end)//右括号或者文件结束则为正确
{
return;
}
else
{
if(sym==nul)
{
printf("错误4_1:非法操作符\n");
exit(0);//无条件的退出程序
}
else
{
printf("错误5:缺少操作符+或者缺少操作符-");
exit(0);
}
}
}
void B()
{
C(); //调用执行C
J(); //调用执行J
}
void J()
{
if(sym==times||sym==divide) //如果类型是*或者除法
{
getsym(); //读取下一个单词
C(); //调用执行C
J(); //调用执行J
}
else if(sym==plus || sym==sub || sym==rparen || sym==end)//+——)或者结束
{
return;
}
else
{
if(sym==nul)
{
printf("错误4_2:非法操作符\n");
exit(0);
}
else
{
printf("错误6:缺少操作符×或者÷\n");
exit(0);
}
}
}
void C()
{
if(sym==lparen) //如果类型是左括号
{
getsym(); //读取下一个单词
S(); //调用执行S
if(sym==rparen) //如果类型是右括号
{
getsym(); //读取下一个单词
return;
}
else
{
printf("语法错9: 缺变量或符号\n ");
exit(0);
}
}
else
{
V(); //否则调用执行V
}
}
void V()
{
if (sym==ident) //当前单词为indent(标识符)类型
getsym(); //读下一个符号
else
{
printf("语法错8: 缺变量\n ");
exit(0);
}
}