【编译原理/C++】实验四 LR分析方法的设计与实现

一、实验目的

通过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#

写了有一段时间了,有的都忘了…踩过的坑注释里都有写,什么时候想起来再补充一下_(:з)∠)_

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值