实验四 利用预测分析表构造语法分析程序
1.实验目的: 熟悉语法分析阶段的要求,掌握LL(1)语法分析的原理,利用预测分析方式构造语法分析器。
2. 实验设备: 硬件:PC 机一台; 软件:Windows系统;高级语言集成开发环境。
3. 实验内容: 利用LL(1)预测分析法构造语法分析器。
4. 实验要求及步骤:
文法G(E):
E→TE’
E’→+TE’ | 空
T→FT’
T’→*FT’|空
F→(E) | i
- 证明上述文法是LL(1)文法;
- 文法不含左递归
- 对于文法中每一个非终结符A的各个产生式的候选首符集两两不相交。
- first集和follow集交集为空:
First(E)={(,i}
First(E’)={+,ε}
First(T)={(,i}
First(T’)={*,ε}
First(F)={(,i}
Follow(E)={),#}
Follow(E’)={),#}
Follow(T)={+,),#}
Follow(T’)={+,),#}
Follow(F)={*,+,),#}
- 构造预测分析表;
string table[5][6] = {
{"error","error","TM","error","TM","error" },
{"+TM","error","error","","error",""},
{"error","error","FN","error","FN","error"} ,
{"","*FN","error","","error",""} ,
{"error","error","(E)","error","i","error"} };
- 利用预测分析表实现以上文法的语法分析器;
见代码
- 自设10个输入语句(每个语句多加一个#作为结束标记),展示这10个语句经该语法分析器分析后的结果,如果正确输出“Right”,错误输出“ERROR”并输出判错时指针所指符号。
代码如下:
#include <stdio.h>
#include <string>
#include <stack>
#include <iostream>
using namespace std;
int a;//当前正在读的字符的下标
char VT[7] = { '+','*','(',')','i','#' };//终结符号
int length_vt = 6;//终结符号的个数
char VN[6] = { 'E','M','T','N','F' };//非终结符号用M代替了E' 用N代替了T’
int length_vn = 5;//非终结符号的个数
string equation[8] = { "TM","+TM","","FN","*FN","","(E)","i" };//产生式表
stack<char> sta;//分析栈
bool flag = false;//判断分析是否结束
string str;//存放用户输入的字符串
string used;//所使用的产生式
string table[5][6] = {
{"error","error","TM","error","TM","error" },
{"+TM","error","error","","error",""},
{"error","error","FN","error","FN","error"} ,
{"","*FN","error","","error",""} ,
{"error","error","(E)","error","i","error"} };//预测分析表
bool is_vn()//判断是否为非终结符
{
if ((sta.top() >= 'A') && (sta.top() <= 'Z'))
return true;
else
return false;
}
void init()//做初始化
{
sta.push('#');
sta.push('E');//将'#'和起始符号先入栈
str = str + '#';//将输入串最后加一个‘#’结束符。
a = 0;
}
void analyse()//对一个字符的分析情况
{
string s;//所使用的的产生式
if (is_vn() == false)//判断是否为非终结符
{
if (str[a] == '#' && (sta.top() == '#'))
{
cout << "分析成功..." << endl;
flag = true;
return;
}
else if (sta.top() == str[a])//如果栈顶元素和当前字符一致,则读入下一个字符,且栈顶元素出栈
{
s = s + str[a] + "匹配";
used = s;
// cout << "当前栈顶元素" << sta.top() << "当前字符" << str[a] << endl;
a++;
sta.pop();
return;
}
else
{
flag = true;//已经判断出了该句子不属于此文法,所以分析结束
cout << "该句子不属于该文法" << endl;
return;
}
}
else {
for (int i = 0; i < length_vn; i++)//查表判断
{
if (sta.top() == VN[i])
{
for (int j = 0; j < length_vt; j++)
{
if (VT[j] == str[a])
{
if (table[i][j] == "error")
{
cout << "预测分析表没有对应的产生式" << endl;
flag = true;//已经判断出了该句子不属于此文法,所以分析结束
return;
}
else if (table[i][j] == "")
{
s = s + VN[i];
s = s + "->空";
used = s;//将使用的产生式放入used
sta.pop();
return;
}
else//将当前栈顶出栈,将预测分析表对应的产生式右部进栈
{
sta.pop();
for (int z = table[i][j].length() - 1; z >= 0; z--)
{
sta.push(table[i][j][z]);
}
s = s + VN[i] + "->" + table[i][j];
used = s;
return;
}
}
}
cout << "error:这个输入串中的字符不属于该文法" << endl;
flag = true;
return;
}
}
cout << "error:该栈顶的符号不属于该文法" << endl;
flag = true;
return;
}
}
string printstack()//顺序输出栈中的符号
{
string s;//存放栈中的符号
string sf;//栈中的元素的反序
int num = sta.size();
for (int i = 0; i < num; i++)//把sta栈的内容给s
{
sf = sf + sta.top();
sta.pop();
}
for (int i = num - 1; i >= 0; i--)//反序
{
s = s + sf[i];
}
for (int i = 0; i < num; i++)//恢复sta
{
sta.push(s[i]);
}
return s;
}
string getstr()//返回输入串
{
string s;
for (int i = a; i < str.length(); i++)
{
s = s + str[i];
}
return s;
}
int main()
{
cout << "请输入一个字符串:" << endl;
cin >> str;
init();
int step = 0;
cout << " " << "步骤" << " " << "符号栈" << " " << "输入串" << " " << "所用产生式" << endl;
while (flag == false)
{
cout <<" " << step << " " << printstack() << " " << getstr() << " " << used << endl;
analyse();
step++;
}
return 0;
}