下面代码仅为实现实验作业所写。有很多不足之处,并且只能正确判断只包含下列字符的文法,并没有做任何的其他非法语言检测。
一、实验目的
设计、编制并调试一个词法分析程序,加深对算符优先分析法的理解。
- 实验内容
编写程序,实现算符优先分析算法。
表达式文法G(E)如下:
- E->E+T|T
- T->T*F|F
- F->(E)|i
该方法的优先关系矩阵如下:
+ | * | i | ( | ) | # | |
+ | > | < | < | < | > | > |
* | > | > | < | < | > | > |
i | > | > | > | > | ||
( | < | < | < | < | = | |
) | > | > | > | > | ||
# | < | < | < | < | = |
#include<iostream>
#include<cstdio>
#include<stack>
#include<unordered_map>
using namespace std;
//用一个hashmap储存字符转换为对应的数字
unordered_map<string,int> charTransion={{"+",0},{"*",1},{"i",2},{"(",3},{")",4},{"#",5}};
//设置算符优先矩阵(用数字的储存方式) >,=,<优先级依次为2,1,0;没有的置为-1
/*
+ * i ( ) #
+ 2 0 0 0 2 2
* 2 2 0 0 2 2
i 2 2 -1 -1 2 2
( 0 0 0 0 1 -1
) 2 2 -1 -1 2 2
# 0 0 0 0 -1 1
*/
int prior[6][6]={{2,0,0,0,2,2},
{2,2,0,0,2,2},
{2,2,-1,-1,2,2},
{0,0,0,0,1,-1},
{2,2,-1,-1,2,2},
{0,0,0,0,-1,1}};
//把栈中的符号,转换成字符串的形式
string showStack(stack<string> symbol)
{
string tmp;
string str;
while(symbol.size())
{
tmp+=symbol.top();
symbol.pop();
}
for(int i=tmp.size()-1;i>=0;i--)
str+=tmp[i];
return str;
}
//显示在控制台
void show(int i,stack<string> symbol,string tmp)
{
if(tmp.size()>1) //判断剩余输入串的长度如果不为1则,照常输出,如果为1那么就只剩下一个#号
cout<<i<<'\t'<<showStack(symbol)<<'\t'<<tmp[0]<<'\t'<<'\t'<<tmp.substr(1)<<endl;
else
cout<<i<<'\t'<<showStack(symbol)<<'\t'<<tmp[0]<<endl;
}
string findVT(stack<string> symbol)//找栈中第一个非终结符
{
string str;
while(symbol.size())
{
string s=symbol.top();
if(s[0]=='+' || s[0]=='*' || s[0]=='i' || s[0]=='(' || s[0]==')' || s[0]=='#')
{
str+=s[0];
return str;
}
symbol.pop();
}
}
//判断用哪个规约式子
string judge(string str)
{
string tmp;
if(str.size()==1)
{
if(str[0]=='T')
tmp="E";//匹配E -> T
else if(str[0]=='F')
tmp="T";//匹配T -> F
else
tmp="F";//匹配F -> i
}
else if(str.size()==3)
{
if(str[0]=='(')
tmp="F";//匹配F -> (E)
else if(str[1]=='*')
tmp="T";//匹配T -> T*F
else
tmp="E";//匹配E -> E+T
}
return tmp;
}
stack<string> reduction(stack<string> symbol,int indexY)//规约操作
{
//
stack<string> red;
string str;
string tmp;//需要规约的字符
tmp+=symbol.top();
symbol.pop();
//下面进行规约操作
while(symbol.size()>=1)//因为最后一个是'#'号所以长度需要大于1
{
//取出栈顶元素
string s=symbol.top();
if(!isupper(s[0]))//不是大写字母
{
string ss;
ss+=s[0];
int indexX=charTransion[ss];//把栈顶元素转换成数字
int index=prior[indexX][indexY];//查找相对应的优先级
if(index==0)//优先级为<则进行规约
{
for(int i=tmp.size()-1;i>=0;i--)str+=tmp[i];//颠倒字符串
str=judge(str);//寻找使用哪个规约式子
if(str=="")//没有找的匹配的规约式子 ,退出程序
{
cout<<"程序有错"<<endl;
exit(0);
}
break;
}
else//继续往栈下面查找
{
indexY=indexX;
tmp+=ss;
}
}
else//是大写字母
{
tmp+=s;
}
symbol.pop();
}
red=symbol;
red.push(str);
return red;
}
//(i+i)*i#
int main()
{
string tt;//用来输入句子
string str;
stack<string> symbol;//状态栈
cout<<"请输入待规约句子,并以#号结尾"<<endl;
while(cin>>tt,str+=tt,tt[tt.size()-1]!='#');//只有以'#'号结尾才能退出输入
int i=1;
while(symbol.size())
{
cout<<symbol.top()<<endl;
symbol.pop();
}
printf("步骤\t栈\t当前符号\t剩余输入串\n\n");
string tmp=str;
symbol.push("#");
while(1)
{
show(i,symbol,tmp);//输出
//tmp储存输入串
//tmp[0]是代表当前符号
//tmp.substr(1)//代表剩余输入串;
string stackTopVT=findVT(symbol);//栈的第一个终结符
string nowChar;
nowChar+=tmp[0];
//判断是否满足成功退出条件
if(stackTopVT=="#" && nowChar=="#")
{
cout<<"分析成功"<<endl;
break;
}
int indexX=charTransion[stackTopVT],indexY=charTransion[nowChar];
int charIndex=prior[indexX][indexY];
//按照查找出来的优先级来进行下一步的操作
if(charIndex==-1)
{
cout<<"程序有错"<<endl;
break;
}
else if(charIndex==2)//进行规约操作
{
symbol=reduction(symbol,indexX);
}
else if((charIndex==1 || charIndex==0) && tmp.size()>=2)//移进操作
{
string s;
s+=tmp[0];
symbol.push(s);
tmp=tmp.substr(1);
}
i++;
}
return 0;
}
运行截图: