LR(1)文法分析器 //c++ 实现

1、先读入终结符,非终结符,和全部产生式。

2、预处理:初始化;getpp()获得每一个非终结符在产生式左边时的产生式编号,

记录在 string getp[]中(能够多个)。

3.获得全部的符号的first集:dfs法,从S開始DFS,遇到终结符则是递归出口,回溯时候沿路保存记录全部路径上VN的first,(遇到有左递归的,continue,左递归的产生式不用不影响求fisrt集)

4:获得项目集族:一个lr(1)项目用一个结构体记录,get_close(项目 t):bfs来完毕对t的闭包。getxmjizu():bfs,并用链式前向星记录图。

5.获得分析表table[][]:遍历对于图的全部边,状态i->j有权为w的边,置action(i,w)=j;go,本质是一样的.其次扫描全部项目,对于归约项目,置归约

6总控程序:俩个栈:状态栈和符号栈,无非移进、归约,接受保存。

測试:

a b

H S B

H->S

B->aB

S->BB

B->b

end

i * ( ) +

E T F

E->E+T

E->T

T->T*F

T->F

F->(E)

F->i

end

a b c d

S A B

S->A

A->B|cAd

B->aBb|ab

end

#include<iostream>
#include<string>
#include<map>
#include<vector>
#include<stack>
#include<set>
#include<cstring>
#include<queue>
using namespace std;
map<char,int>getnum;
char getchar[100];          //获得相应字符
vector<string>proce;        //产生式
int table[30][30];         //预測分析表 -1
int tb_s_r[30][30];        //是移进项还是规约项,-1,-2.
int num=0;int numvt=0;   //numvt是终结符集合,0是‘#’,numvt表空字
void readin()                        //读入vt,vn,编号1-num,读入全部产生式
{
    memset(table,-1,sizeof(table));
    getnum[‘#‘]=0;
    getchar[0]=‘#‘;
    cout<<"请输入终结符集:"<<endl;
    char x;
    do
    {
      cin>>x;
      getnum[x]=++num;
      getchar[num]=x;
    }while(cin.peek()!=‘\n‘);
     numvt=++num;
     getnum[‘@‘]=numvt;        //kong zi
     getchar[num]=(‘@‘);
    cout<<"请输入非终结符集:"<<endl;
    do
    {
      cin>>x;
      getnum[x]=++num;
      getchar[num]=x;
    }while(cin.peek()!=‘\n‘);
    cout<<"输入全部产生式(空字用‘@’表示),以‘end’结束:"<<endl;
    string pro;
     while(cin>>pro&&pro!="end")
     {
         string ss;
         ss+=pro[0];
         for(int i=3;i<pro.size();i++)
         {
             if(pro[i]==‘|‘)
             {
                  proce.push_back(ss);
                  ss.clear();ss+=pro[0];
             }
             else
             {
                 ss+=pro[i];
             }
         }
          proce.push_back(ss);
    }
}
struct xiangmu         //一个项目
{
    int nump;       //产生式编号
    int id;        //.的位置
    string fst;   //集合
};
string getp[100];   //获得某终结符在左边的产生式集合
void getpp()
{
    for(int i=0;i<proce.size();i++)
    {
        int temp=getnum[proce[i][0]];
        getp[temp]+=char(‘0‘+i);
    }
}
string first[100];   //每一个符号的first集
bool gotfirst[100]; //是否已经完毕FIRST集合
void dfsgetfirst(int nv,int nump)  //当前的符号,和相应产生式编号
{
   int temp=getnum[proce[nump][1]];  //产生式推出来的首符
    gotfirst[nump]=1;               //标记
    if(temp<=numvt)first[nv]+=char(‘0‘+temp);  //是终结符
    else
    {
        for(int i=0;i<getp[temp].size();i++)    //全部temp能够推出来的符号相应的产生式
          {
              if(proce[nump][0]==proce[nump][1])continue; //左递归的产生式不用不影响求fisrt集
              dfsgetfirst(temp,getp[temp][i]-‘0‘);
          }

        first[nv]+=first[temp];                  //回溯时候沿途保存
    }
}
void get_first()
{
    for(int i=1;i<=numvt;i++)             //    终结符first集合是它自己.
    {
        first[i]=char(‘0‘+i);
    }
     for(int i=0;i<proce.size();i++)
    {
        if(proce[i][0]==proce[i][1])continue; //左递归的产生式不用不影响求fisrt集
        if(gotfirst[i])continue;              //已经生成。

int temp=getnum[proce[i][0]];
          dfsgetfirst(temp,i);
    }
}
vector<vector<xiangmu> >v;             //项目集族
int e[100][3]; int head[100];int nume=0;    //链式前向星项目集族图
void addegde(int from,int to,int w)         //加入边
{
    e[nume][0]=to;e[nume][1]=head[from];head[from]=nume;
    e[nume++][2]=w;
}
void clear()                 //初始化函数
{
    for(int i=0;i<100;i++)
       head[i]=-1;
     for(int i=0;i<30;i++)
       for(int j=0;j<30;j++)
         tb_s_r[i][j]=table[i][j]=-1;
    nume=0;
}
inline bool xmeq(xiangmu a,xiangmu b)
{
    if(a.fst==b.fst&&a.id==b.id&&a.nump==b.nump)return 1;
    return 0;
}
bool isin(xiangmu a,vector<xiangmu> b)      //xm a is in xmji b
{
    for(int i=0;i<b.size();i++)
    {
        if(xmeq(a,b[i]))return 1;
    }
    return 0;
}
vector<xiangmu>  hebing(vector<xiangmu>a ,vector<xiangmu>b)  //合并项目集 a,b 复给 a
{
    for(int i=0;i<b.size();i++)
    {
        if(isin(b[i],a))continue;
        else
         a.push_back(b[i]);
    }
    return a;
}
bool xmjieq(vector<xiangmu> a,vector<xiangmu> b)  //两个项目集是否相等
{
    if(a.size()!=b.size())return 0;
     for(int i=0;i<a.size();i++)
     {
        if(!isin(a[i],b))return 0;
     }
     return 1;
}
int xmji_isin_xmjizu(vector<xiangmu>a,vector<vector<xiangmu> >b)  //查找项目集,若有,则返回编号,一举俩得
{
    for(int i=0;i<b.size();i++)
    {
        if(xmjieq(a,b[i]))return i;
    }
    return -1;
}
vector<xiangmu> get_close(xiangmu t)           //对项目 T作闭包
{
   vector<xiangmu> temp;
   temp.push_back(t);
    queue<xiangmu> q;                         //bfs完毕闭包
    q.push(t);
    while(!q.empty())
    {
      xiangmu cur=q.front();
      q.pop();
      if(cur.id==proce[cur.nump].size())          //归约项舍去
          continue;
     int tt=getnum[proce[cur.nump][cur.id]];       //tt is thm num of ‘.‘zhihoudefuhao
      if(tt<=numvt)   continue ;                  //若是终结符,则不必找了
      for(int i=0;i<getp[tt].size();i++)         //相应产生式的编号
       {
          xiangmu c;
         c.id=1;                               //
         c.nump=getp[tt][i]-‘0‘;             //
        if(proce[cur.nump].size()-cur.id==1)   // the last : A->BC.D,a/b
          c.fst+=cur.fst;
         else                           //not the last  :A->B.CFb,a/b
        {
          int tttnum=getnum[proce[cur.nump][cur.id+1]];
          c.fst+=first[tttnum];
        }
         if(!isin(c,temp))           //排重,新的项目就加入。
         {
             q.push(c);
             temp.push_back(c);
         }
        }
      }
      return temp;
}
void get_xiangmujizu()             //获得项目集族
{
    vector<xiangmu>temp;
    xiangmu t;
    t.nump=0;t.id=1;t.fst+=‘0‘;    //初始的项目集:0
    temp=get_close(t);
    queue<vector<xiangmu> >q;        //bfs法获得
    q.push(temp);
    v.push_back(temp);             //第一个入
    while(!q.empty())
    {
         vector<xiangmu> cur=q.front();
         q.pop();
         for(int i=1;i<=num;i++)     //全部符号
         {
             if(i==numvt)continue;      //‘#‘
             vector<xiangmu> temp;
              for(int j=0;j<cur.size();j++)     //该项目集中的全部项目
              {
                 if(cur[j].id==proce[cur[j].nump].size())continue;  //是规约项目。无法再读入了
                 int tt=getnum[proce[cur[j].nump][cur[j].id]];
                if(tt==i)                                          //can read in 符号i
                {
                    xiangmu tempt;
                    tempt.fst=cur[j].fst;
                    tempt.id=cur[j].id+1;
                    tempt.nump=cur[j].nump;
                    temp=hebing(temp,get_close(tempt));
                }
              }
              if(temp.size()==0)continue;             //该符号无法读入。
                int numcur=xmji_isin_xmjizu(cur,v);   //当前节点标号
                int tttnum=xmji_isin_xmjizu(temp,v);  //新目标标号
                   if(tttnum==-1)                    //新的项目集
                   {
                    v.push_back(temp);
                    q.push(temp);
                    addegde(numcur,v.size()-1,i) ;   //加入边,权为读入的符号
                  }
                   else                             //老的项目集
                   {
                    addegde(numcur,tttnum,i);
                   }
         }
    }
}
void print_xmjizu()              //打印项目集族
{
    for(int i=0;i<v.size();i++)
    {
        cout<<"项目集"<<i<<":"<<endl;
      for(int j=0;j<v[i].size();j++)
        {
          cout<<proce[v[i][j].nump]<<" "<<v[i][j].id<<" "<<v[i][j].fst<<endl;
        }
      cout<<endl;
    }
    for(int i=0;i<v.size();i++)
    {
        for(int j=head[i];j!=-1;j=e[j][1])
        {
            cout<<"  "<<getchar[e[j][2]]<<endl;
            cout<<i<<"--->"<<e[j][0]<<endl;
        }
    }
}
bool get_table()            //获得分析表table[i][j]=w:状态i-->j,读入符号W。

{
    for(int i=0;i<v.size();i++)          //遍历图
    {
        for(int j=head[i];j!=-1;j=e[j][1])
        {
            if(table[i][e[j][2]]!=-1)return 0;           //多重入口。报错.
             table[i][e[j][2]]=e[j][0];
            tb_s_r[i][e[j][2]]=-1;             //移近项-1。

}
    }
    for(int i=0;i<v.size();i++)             //遍历全部项目
    {
      for(int j=0;j<v[i].size();j++)
        {
            if(v[i][j].id==proce[v[i][j].nump].size())  //归约项
            {
                for(int k=0;k<v[i][j].fst.size();k++)
                   {
                      if(table[i][(v[i][j].fst)[k]-‘0‘]!=-1)return 0;           //多重入口,报错.
                     if(  (v[i][j].fst)[k]==‘0‘&&v[i][j].nump==0)
                        table[i][(v[i][j].fst)[k]-‘0‘]=-3 ;           //接受态。
                     else
                     {
                        table[i][(v[i][j].fst)[k]-‘0‘]=v[i][j].nump;
                        tb_s_r[i][(v[i][j].fst)[k]-‘0‘]=-2;            //归约态
                     }
                   }
            }
         }
     }
     return 1;
}
void print_table()
{
    cout<<"LR(1)分析表:"<<endl;
    cout<<"状态   "<<"         actoin     "<<endl;
     for(int j=0;j<=num;j++)
        {
            if(j==numvt)continue;
            cout<<"    "<<getchar[j];
        }
       cout<<endl;
    for(int i=0;i<v.size();i++)
    {
        cout<<i<<"   ";
        for(int j=0;j<=num;j++)
        {
            if(j==numvt)continue;
            if(table[i][j]==-3)  cout<<"acc"<<"  ";       //接受
            else if(table[i][j]==-1)cout<<"     ";        //空
            else if(tb_s_r[i][j]==-1)cout<<"s"<<table[i][j]<<"   ";  //移近
            else if(tb_s_r[i][j]==-2)cout<<"r"<<table[i][j]<<"   ";  //归约
        }
        cout<<endl;
    }
}
string word;
void  print_now_state(int count,stack<int>state,stack<int>wd,int i)
{
    cout<<count<<‘\t‘<<‘\t‘;
    stack<int>temp;
    while(!state.empty())
    {
        temp.push(state.top());
        state.pop();
    }
    while(!temp.empty())
    {
        cout<<temp.top();
        temp.pop();
    }
    cout<<‘\t‘<<‘\t‘;
     while(!wd.empty())
    {
        temp.push(wd.top());
        wd.pop();
    }
    while(!temp.empty())
    {
        cout<<getchar[temp.top()];
        temp.pop();
    }
    cout<<‘\t‘<<‘\t‘;
    for(int j=i;j<word.size();j++)
        cout<<word[j];
    cout<<‘\t‘<<‘\t‘;
}
bool analyze()
{
    cout<<"       "<<word<<"的分析过程:"<<endl;
    cout<<"步骤\t\t"<<"状态栈\t\t"<<"符号栈\t\t"<<"输入串\t\t"<<"动作说明"<<endl;
      stack<int>state;   //俩个栈:状态栈和符号栈
      stack<int>wd;
      int count=0;
      state.push(0);     //初始化
      wd.push(0);        //‘#‘
    for(int i=0;;)       //i,读入文本的
    {
        int cur=state.top();
        if(table[cur][getnum[word[i]]]==-1)    // 空白,报错误
             return 0;
        if(table[cur][getnum[word[i]]]==-3)  //接受态
            {
                print_now_state(count++,state,wd,i);
                cout<<"      恭喜。acc!"<<endl;
                return 1;
            }
        if(tb_s_r[cur][getnum[word[i]]]==-1)       //移进项
        {
            print_now_state(count++,state,wd,i);
           int newstate=table[cur][getnum[word[i]]];
            cout<<"action["<<cur<<","<<getnum[word[i]]<<"]="<<newstate;
            cout<<",状态"<<newstate<<"入栈"<<endl;
            wd.push(getnum[word[i]]);
            state.push(newstate);
            i++;
        }
        else if(tb_s_r[cur][getnum[word[i]]]==-2)         //归约
        {
            print_now_state(count++,state,wd,i);

             int numpro=table[cur][getnum[word[i]]];   //用该产生式归约
            int len=proce[numpro].size()-1;
            for(int ii=0;ii<len;ii++)                 //弹栈
             {
                 wd.pop();
                 state.pop();
             }
             wd.push(getnum[proce[numpro][0]]);    //新入
             int cur=state.top();
            cout<<"用"<<proce[numpro][0]<<"->";
             for(int ii=1;ii<=len;ii++)
                 cout<<proce[numpro][ii];
            cout<<"进行归约,"<<"goto["<<cur<<","<<getnum[word[i]]<<"]="<<table[cur][getnum[proce[numpro][0]]];
            cout<<"入栈"<<endl;
             state.push(table[cur][getnum[proce[numpro][0]]]);
        }
    }
    return 1;
}
int main()
{
    clear();
    readin();
    getpp();
    get_first();
    get_xiangmujizu();
    if(!get_table())
    {
        cout<<"此文法在生成分析表时候有多重入口,非LR(1)文法!

"<<endl;
        return 0;
    }
  // print_xmjizu();
   print_table();
   cout<<"请输入字:"<<endl;
   cin>>word;
   word+=‘#‘;
   if(!analyze())
       cout<<"error!"<<endl;
   else;
    return 0;
}
时间: 2024-08-27 06:05:13

LR(1)文法分析器 //c++ 实现的相关文章

LR(1)文法智能分析

LR1文法全智能分析 // by hfut yzk #include "stdafx.h" #include<fstream> #include<string> #include<map> #include<vector> #include<stack> #include<set> #include<cstring> #include<queue> using namespace std;

LR(1)语法分析器生成器(生成Action表和Goto表)java实现(二)

本来这次想好好写一下博客的...结果耐心有限,又想着烂尾总比断更好些.于是还是把后续代码贴上.不过后续代码是继续贴在BNF容器里面的...可能会显得有些臃肿.但目前管不了那么多了.先贴上来吧hhh.说不定哪天觉得羞耻又改了呢.参考资料建议参考<编译器设计>一书. 目前完成进度 : 目前已经完成了表驱动,通过函数输出这个Action 和 Goto表.然后使用者就可以根据两个表来进行LR(1)语法分析.且经过比对,发现和书上的例子(括号语法)是完全吻合的. 1 package cn.vizdl.L

LR(0)文法项目集规范族、DFA和分析表的构建实例

最近在复习编译原理,考试之前以为自己懂了,眼高手低就没去实践.结果一考试出问题了.... 学习就要脚踏实地,容不得半点模糊.凭着侥幸心理很危险的.以后要引以为戒啊. 特别写出这篇文章 :一来总结一下这几天的收获.二来与君共勉. 一.概念 1.概念解释 1.活前缀:不包含句柄右侧任一符号的规范句型的前缀称为该句型的活前缀. 例如:Bab是下面那个文法的一个句型,其中b是句柄. 那么针对这个句型的活前缀有:ε.B.Ba 和Bab (其实,LR分析器的工作过程实际上就是逐步产生规范句型的活前缀. 如果

求LR(0)文法的规范族集和ACTION表、GOTO表的构造算法

原理 数据结构 1 // GO 2 private static Map<Map<Integer,String>,Integer> GO 3 = new HashMap<Map<Integer,String>,Integer>(); 4 5 // 规范族集 C 6 private static Map<Integer,Map<String,List<String>>> C 7 = new HashMap<Intege

构造可配置词法语法分析器生成器(中)

本文为笔者原创,转载请注明出处 http://blog.csdn.net/xinghongduo   语法分析器 语法分析器(grammar parser)是编译器的核心部分之一,它的作用是检测词法分析器返回的token序列是否符合文法定义的规则.一个完整的语法分析器除了检测语法正确性外还要包含对出错的处理以及错误恢复等功能. 文法和文法类型 文法是定义一个语言的所有规则的集合,形式上定义为四元组G={VT,VN,S,P},其中: VT是非空有限符号集合,它的每个符号称为终结符,文法产生的语言由

编译系统中的LR与LL理解

编译原理:LL(1),LR(0),SLR(1),LALR(1),LR(1)对比 LL(1)定义:一个文法G是LL(1)的,当且仅当对于G的每一个非终结符A的任何两个不同产生式 A→α|β,下面的条件成立:SELECT( A→α)∩SELECT( A→β)=dd,其中, α|β不能同时 ε. 解释:LL(1)的意思是,第一个L,指的是从左往右处理输入,第二个L,指的是它为输入生成一个最左推导.1指的是向前展望1个符号. LL(1)文法是上下文无关文法的一个子集.它用的方法是自顶向下的(递归式的处理

编译原理——算符优先分析文法(附源代码)

算符优先分析文法 一.写在前面 算符优先分析文法是一种工具,在编译的过程中,隶属于语法分析环节,却又与中间代码的生成息息相关,编译可以分为五个阶段:词法分析.语法分析.语义分析(中间代码的生成).代码优化.目标代码生成.语法分析是指:在词法分析基础上,将单词符号串转化为语法单位(语法范畴)(短语.子句.句子.程序段.程序),并确定整个输入串是否构成语法上正确的程序.也就是说语法分析是检验输入串的语法是否正确,注意这里的语法正确,只是简单地符合自己定义的规范,而不能检测出运行时错误,比如"X/0&

SQLite3源程序分析之Lemon分析器生成工具

1.概述 Lemon是一个LALR(1)文法分析器生成工具.虽然它是SQLite作者针对SQLite写的一个分析器生成工具,但是它与bison和yacc类似,是一个可以独立于SQLite使用的开源的分析器生成工具.而且它使用与yacc(bison)不同的语法规则,可以减少编程时出现错误的机会.Lemon比yacc和bison更精致.更快,而且是可重入的,也是线程安全的——这对于支持多线程的程序是非常重要的. Lemon的主要功能就是根据上下文无关文法(CFG),生成支持该文法的分析器.程序的输入

LL(1),LR(0),SLR(1),LALR(1),LR(1)对比与分析

前言:考虑到这几种文法如果把具体内容讲下来肯定篇幅太长,而且繁多的符号对初学者肯定是极不友好的,而且我相信看这篇博客的人已经对这几个文法已经有所了解了,本篇博客的内容只是对 这几个文法做一下对比,加深大家对这几个文法的理解.更详细的细节,初学者可以看看这个课件https://files-cdn.cnblogs.com/files/henuliulei/%E7%AC%AC5%E7%AB%A0.ppt,或者其他相关的博客. 一:五种文法的演变 1.1 LL(1)文法 LL(1)文法是自上而下的分析方