一、实验目的
通过LR分析方法的实现,加深对自下而上语法分析方法及语法分析程序自动生成过程的理解。
二、实验要求
输入上下文无关文法,对给定的输入串,给出其LR分析过程及正确与否的判断。
三、实验步骤
1.参考数据结构
typedef struct{/*文法*/
char head;//产生式左部符号
char b[20];//用于存放产生式
int point;
int lg;//产生式的长度
}regular;
typedef struct{
int l; //文法数量
int m; //vn 数量
int n; //vt 数量
regular re[20];
nfinal vn[20];//非终结符
final vt[20];//终结符
}condition;
condition cd[20];//项目
regular first[20];//产生式
(我沿用的是之前实验的数据结构)
2. 使用闭包函数(CLOSURE)和转换函数(GO(I,X))构造文法G’的LR(0)的项目集规范族。
计算LR(0)项目集规范族C={I0,I1,...,In}
算法描述如下:
Procedure itemsets(G’);
Begin C = { CLOSURE ({S’ →.S})}
Repeat
For C 中每一项目集I和每一文法符号X
Do if GO(I,X) 非空且不属于C
Then 把 GO(I,X) 放入C中
Until C 不再增大
End;
定义转换函数如下:
GO(I,X)= CLOSURE(J)
其中:I为包含某一项目集的状态,X为一文法符号,J={A→aX.b|A→a.X b∈I}。
3. 构造LR(0)分析表
对于LR(0)文法,我们可以直接从它的项目集规范族C和活前缀识别自动机的状态转换函数GO构造出LR分析表。
算法描述如下:
begin
if A→α•aβ (属于) Ik and GO(Ik,a) = Ij (a(属于)VT) then
置ACTION[k,a] = sj;
If A→α•(属于) Ik then
对任意终结符a(包括#)置ACTION[k,a] = rj;
If S’ →S•(属于) Ik then
置ACTION[k,#] = acc;
If GO(Ik,A) = Ij (A(属于)VN) then
置 GOTO(k,A) = j;
else ERROR //出错
4. LR分析算法描述
对给定的输入串,给出其分析过程及正确与否的判断
将S0移进状态栈,#移进符号栈,S为状态栈栈顶状态
begin
a=getsym() //读入第一个符号给a
while(ACTION[S,a]!=acc)
If ACTION[S,a]=si then
PUSH i,a(分别进栈);输出进栈信息
a=getsym();//读入下一个符号给a
else if ACTION[S,a] = rj (第j条产生式为A→β) then
输出归约信息
将状态栈和符号栈分别弹出|β|项; push(A);
将GOTO[S’,A]移进状态栈(S’为当前栈顶状态);
else error;
输出分析结果,接受或出错
End
5、对给定输入串输出其准确与否的分析过程。
四、代码实现
源码
#include<iostream>
#include<string>
#include<list>
#include<stack>
using namespace std;
typedef struct{
string formula;//产生式增广文法
int p;
}grammarElement;
grammarElement gramOldSet[20][10];
bool flag[20][10]={true}; //如果已经添加到闭包内,置true
int n=0;
typedef struct{
list<grammarElement> fm;
}lrCondition; //LR(0)项目规范集族
lrCondition clos[20];
string terSymbol;//终结符号
string non_ter;//非终结符号
string allSymbol;//所有符号
typedef struct{
char ac;
int num;
}Table;
Table table[20][20];
int m=0;
int Closure();
void toTable();
void Control();
void print_i(stack<int> s);
void print_c(stack<char> s);
int main(){
cout << "non_ter: ";
cin >> non_ter;
cout << "ter: ";
cin >> terSymbol;
terSymbol.push_back('#');
allSymbol = terSymbol + non_ter;
cout<<"num: ";
cin>> n;
for(int i=1;i<=n;i++){
cin>>gramOldSet[i][0].formula;
gramOldSet[i][0].p = 3;
flag[i][0]=false;
//写入增广文法
for(int j=1;j<=gramOldSet[i][0].formula.size()-3;j++){
gramOldSet[i][j].formula = gramOldSet[i][0].formula;
gramOldSet[i][j].p = j+3;
flag[i][j]=false;
}
}
gramOldSet[0][0].formula="S->";
gramOldSet[0][0].formula.push_back(gramOldSet[1][0].formula[0]);
gramOldSet[0][0].p=3;
gramOldSet[0][1].formula = gramOldSet[0][0].formula;
gramOldSet[0][1].p=4;
flag[0][0] = false;
flag[0][1] = false;
//
m = Closure();
for(int i=0;i<m;i++){
cout<<"I"<<i<<endl;
for(list<grammarElement>::iterator s = clos[i].fm.begin(); s!=clos[i].fm.end(); s++){
cout<<(*s).formula<<" "<<(*s).p<<endl;
}
}
toTable();
for(int i=0;i<m;i++){
cout<<"I";
cout.width(4);
cout<<left<<i;
for(int j=0;j<allSymbol.size();j++){
if(table[i][j].ac == 0) cout<<" ";
cout.width(2);
cout<<right<<table[i][j].ac;
cout.width(2);
cout<<left<<table[i][j].num;
}
cout<<endl;
}
Control();
return 0;
}
int Closure(){
// clos[0].fm.push_back(gramOldSet[0][0]);
//构造I1~In
for(int i=0;i<15;i++){
//向该闭包中添加第一个增广项目
for(int p=0;p<=n;p++){
for(int q=0;q<10;q++){
if(gramOldSet[p][q].formula[0]==0) break;
if(flag[p][q]==false && gramOldSet[p][q].formula[0]!=0){
clos[i].fm.push_back(gramOldSet[p][q]);
flag[p][q] = true;
break;
}
}
if(!clos[i].fm.empty()) break;
}
list<grammarElement>::iterator s = clos[i].fm.begin(); //该闭包中第一个项目
//遍历构造闭包
for( ; s!=clos[i].fm.end(); s++){
char c = (*s).formula[(*s).p]; //.后的符号
if(c!=0 && non_ter.find(c)!=-1){
//寻找c的项目且.在开头
for(int k=0;k<=n;k++){
if(gramOldSet[k][0].formula[0] == c){
clos[i].fm.push_back(gramOldSet[k][0]);
flag[k][0]=true;
}
}
}
}
if(clos[i].fm.empty()) return i;
}
return -1;
}
void toTable(){
//遍历每个闭包
for(int i=0;i<m;i++){
list<grammarElement>::iterator r = clos[i].fm.begin();
//看是否为归约
if(clos[i].fm.size()==1 && (*r).formula.size()==(*r).p){
//归约时action每个都填
for(int j=0;j<terSymbol.size();j++){
//查找归约用到第几个产生式
int k=0;
for( k=0;k<=n;k++){
if(gramOldSet[k][0].formula == (*r).formula){
table[i][0].num=k;
break;
}
}
//如果是形如S->..的归约项目说明结束
if(k==0){
table[i][terSymbol.size()-1].ac = 'a';
break;
}
table[i][j].ac = 'r';
table[i][j]=table[i][0];
}
continue;
}
while(r!=clos[i].fm.end()){
//遍历I0-In看它接受后跳到哪里
for(int j=0;j<m;j++){
list<grammarElement>::iterator s = clos[j].fm.begin();
while(s!=clos[j].fm.end()){
if((*r).formula==(*s).formula && (*r).p+1 == (*s).p){
char c = (*r).formula[(*r).p];
table[i][allSymbol.find(c)].num = j;
//action移进填s
if(terSymbol.find(c)!=-1){
table[i][allSymbol.find(c)].ac = 's';
}
}
s++;
}
}
r++;
}
}
}
void Control(){
stack<int> state; //状态栈
state.push(0);
stack<char> symbol; //符号栈
symbol.push('#');
string str; //输入串
cin>>str;
bool fl=true;
int a=1;
while(fl){
Table t = table[state.top()][allSymbol.find(str[0])];
//移进
if(t.ac == 's'){
state.push(t.num);
symbol.push(str[0]);
str.erase(0,1);
}
//归约
else if(t.ac == 'r'){
for(int i=0;i<gramOldSet[t.num][0].formula.size()-3;i++){
symbol.pop();
}
symbol.push(gramOldSet[t.num][0].formula[0]);
state.pop();
//GOTO[ , ]
//当前状态出栈,再看栈顶GOTO()
int st = table[state.top()][allSymbol.find(symbol.top())].num;
state.pop();
state.push(st);
}
else if(t.ac == 0 && t.num == 0){
fl = false;
cout<<"error!";
return;
}
//判断完成当前步骤后是否acc,不能用t,那是本次操作之前的
if(table[state.top()][allSymbol.find(str[0])].ac == 'a'){
fl=false;
}
cout.width(4);
cout<<left<<a;
a++;
print_i(state);
print_c(symbol);
cout.width(12);
cout<<right<<str<<endl;
}
}
void print_i(stack<int> s){
string r;
while(!s.empty()){
r.insert(0,1,s.top()+'0');
s.pop();
}
cout.width(12);
cout<<left<<r;
}
void print_c(stack<char> s){
string r;
while(!s.empty()){
r.insert(0,1,s.top());
s.pop();
}
cout.width(12);
cout<<left<<r;
}
测试数据:
EAB
abcd
6
E->aA
E->bB
A->cA
A->d
B->cB
B->d
acccd#
写了有一段时间了,有的都忘了…踩过的坑注释里都有写,什么时候想起来再补充一下_(:з)∠)_