一、实验要求
实验二 基于预測方法的语法分析程序的设计
一、实验目的
了解预測分析器的基本构成及用自顶向下的预測法对表达式进行语法分析的方法,掌握预測语法分析程序的手工构造方法。
二、实验内容
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; }
三、执行结果