一、实验要求
实验二 基于预测方法的语法分析程序的设计
一、实验目的
了解预测分析器的基本构成及用自顶向下的预测法对表达式进行语法分析的方法,掌握预测语法分析程序的手工构造方法。
二、实验内容
1、了解编译程序的基于预测方法的语法分析过程。
2、根据预测分析原理设计一个基于预测方法的语法分析程序。
三、实验要求
对给定文法G[S]:
S->AT A->BU T->+AT|$ U->*BU|$ B->(S)|m
其中,$表示空串。
1、判断上述文法G[S]是否LL(1)文法,若不是,将其转变为LL(1)文法;
2、对转变后的LL(1)文法建立预测分析表;
3、根据清华大学出版编译原理教材教材第五章P94的图5.11手工构造预测分析程序;
4、用预测分析程序对任意给定的键盘输入串m+m*m#进行语法分析,并根据栈的变化状态输出给定串的具体分析过程。
四、运行结果
从任意给定的键盘输入串:
m+m*m#;
输出:
用预测分析法分析符号串m+m*m#的过程
Step | Stack | String | Rule | Step | Stack | String | Rule |
1 | #S | m+m*m# | S->AT | 10 | #TUm | m*m# | M匹配 |
2 | #TA | m+m*m# | A->BU | 11 | #TU | *m# | U->*BU |
3 | #TUB | m+m*m# | B->m | 12 | #TUB* | *m# | *匹配 |
4 | #TUm | m+m*m# | M匹配 | 13 | #TUB | m# | B->m |
5 | #TU | +m*m# | U->$ | 14 | #TUm | m# | M匹配 |
6 | #T | +m*m# | T->+AT | 15 | #TU | # | U->$ |
7 | #TA+ | +m*m# | +匹配 | 16 | #T | # | T->$ |
8 | #TA | m*m# | A->BU | 17 | # | # | 接受 |
9 | #TUB | m*m# | B->m |
|
|
|
|
五、提示
本实验重点有两个:一是如何用适当的数据结构实现预测分析表存储和使用;二是如何实现各规则右部串的逆序入栈处理。
建议:使用结构体数组。
六、分析与讨论
1、若输入串不是指定文法的句子,会出现什么情况?
2、总结预测语法分析程序的设计和实现的一般方法。
二、通过代码
#include<stdio.h>
#include<iostream>
#include<cstring>
#include<string>
#include<stack>
#include<map>
#include<vector>
using namespace std;
string fir[5][6]={"","","AT","","AT","",
"","","BU","","BU","",
"+AT","","","$","","$",
"$","*BU","","$","","$",
"","","(S)","","m",""}; //first值表
map<char,int> vn; //first表索引[非终结符]
map<char,int> vt; //first表索引[终结符]
stack<char> Stack; //分析栈
stack<char> String; //剩余输入串栈
string s; //语句存放
void inital(){
vn['S']=1;//初始化first变索引
vn['A']=2;
vn['T']=3;
vn['U']=4;
vn['B']=5;
vt['+']=1;
vt['*']=2;
vt['(']=3;
vt[')']=4;
vt['m']=5;
vt['#']=6;
}
void output_stackt(){//每一步分析都得输出stack和String的值
int n;
s.clear();
while(!Stack.empty()){
s+=Stack.top();
Stack.pop();
}
n=0;
for(n=s.length()-1;n>=0;n--){
Stack.push(s[n]);
cout<<s[n];
}
cout<<"\t\t";
s.clear();
while(!String.empty()){
s+=String.top();
String.pop();
}
cout<<s<<"\t\t";
n=0;
for(n=s.length()-1;n>=0;n--)
String.push(s[n]);
}
void ann()//程序核心程序,语法分析函数
{
int len=0,count=0;
char Stack_top,String_top; //分析栈与余串栈栈顶元素
Stack.push('#'); //#s进分析栈
Stack.push('S');
for(len =s.length()-1;len>=0;len--) //输入串进剩余输出栈
String.push(s[len]);
while(++count){ //ann 一直分析,直到接受或报错
cout<<count<<"\t";
output_stackt();
if(Stack.empty()){//缺“#”【基本不会出现】
cout<<"报错\nerror---the stack is empty\n";
break;
}
if(String.empty()){//输入的串中没有“#”
cout<<"报错\nerror---the sting is empty\n";
break;
}
Stack_top=Stack.top();//取分析栈栈顶元素
Stack.pop(); //栈顶已经要处理了,现在弹出
String_top=String.top();//取待分析串栈顶元素
if(vt[Stack_top]!=0&&Stack_top!='#')//没有分析道栈底
{
if(Stack_top==String_top){//能匹配字符
cout<<"'"<<Stack_top<<"'匹配\n";
String.pop();
continue;
}
else{
cout<<"报错\nerror---Stack_top!=String_top\n";
break;
}
}
if(Stack_top=='#')//分析到栈底了
{
if(Stack_top==String_top) //栈底是#,接受
{
cout<<"接受\n";
break;
}
else{
cout<<"报错\nerror---Stack_top=='#',but Stack_top!=String_top\n";
break;
}
}
else
{
if(vn[Stack_top]!=0&&vt[String_top]!=0){
s=fir[vn[Stack_top]-1][vt[String_top]-1];
if(s!="")
{
if(s!="$")
for(len =s.length()-1;len>=0;len--) //公式进分析栈
Stack.push(s[len]);
cout<<Stack_top<<"->"<<s<<endl;
}
else
{
cout<<"报错\nerror---fir[vn[Stack_top]-1][vt[String_top]-1] is null!\n";
break;
}
}
else
{
cout<<"报错\nerror---vn[Stack_top]==0||vt[String_top]==0\n";
break;
}
}
}
}
void start()
{
while(!Stack.empty())Stack.pop();
while(!String.empty())String.pop();
cout<<"please input the annli string:";
cin>>s;
cout<<"step\tstack\t\tstring\t\trule\n";
ann();
cout<<"\n\nthe annli is finish!\n";
}
int main(){//主函数,运行入口
while(true){
inital(); //初始化变量
start(); //开始分析,并且输出分析情况
}
return 0;
}
三、运行结果