LL(1)文法实现(C系语言版)实现

原创作品,出自 “晓风残月xj” 博客,欢迎转载,转载时请务必注明出处(http://blog.csdn.net/xiaofengcanyuexj)。

由于各种原因,可能存在诸多不足,欢迎斧正!

一、实验目标

    1.学习消除文法左递归算法。

    2.掌握预测分析法实现语法分析。

    3.自动求得“FIRST”“FOLLOW”集构造预测分析表。

   4.能够使用自己编写的分析程序对简单的程序段进行语法翻译。

二、设计思想

       1、需求分析

  本题要求用LL(1)实现对语句的分析。主要工作有以下几点:

     (1)、对于某些非LL(1)文法,可以通过消除左递归转换为LL(1)文法;

     (2)、求得FIRST集、FOLLOW集,构造SELECT集;

     (3)、构造预测分析表

     (4)、预测分析程序

2、设计思想

       在此说明,我们的程序中的文法的大写字母‘A’—‘Z’,非终结符为除‘A’—‘Z’外的所能用ASCII码表示的所有字符。

       对于空串‘ε’,由于8ASCII直接表示,输入时自动缺省(符合本身含义),如文法A->ε只输A->,但在输出时显示A->ε。

       由于我们选用的是上下文无关文法,即2型文法。其右部只含有一个非终结符V[N],体现在我们的算法中即可用hash的思想。

     Bool UsedUpLetter[26];表示非终结符的使用情况

     UsedUpLetter[i]=0表示字符char(‘A+i)没有使用;否则使用了。

     文法的存储可以用C++中的顺序容器vector.

     vector<string>MyProduction[26]存储所有的产生式

     MyProduction[i]vector<string>容器,存储以字符char(‘A+i)为右部的所有产生式。插入、更新、删除、查找等都很方便,而且效率不低。

消除左递归

解决了储存问题后,就是面临消除左递归的操作了。

   (1)将非终结符合理排序:A1A2...An;

       

      (2)

   for  i:=1 to N Do

        Begin

        for j:=1 to i-1 Do

               Begin

                用Aj→δ1|δ2|...|δk的右部

                替换每个形如Ai→Ajγ产生式中的Aj,

                得到新产生式:Ai→δ1γ|δ2γ|...|δkγ;

               End 

        消除Ai产生式中的直接左递归;

     End  

  

    (3)去掉无用产生式。


 

考虑到判断文法是否左递归的时间复杂度较高,资源消耗较大,我们的所有文法都将进行消除左递归操作。

若该文法含有左递归,则消除之;若不含左递归,由于操作下面操作的存在,也可以简化文法。

       用Aj→δ1|δ2|...|δk的右部

    替换每个形如Ai→Ajγ产生式中的Aj,

    得到新产生式:Ai→δ1γ|δ2γ|...|δkγ;

下面是我们A004的计算中间过程,

       

</pre><p></p><p></p><p>    </p><p>     我们知道上面的文法不含左递归,但在进行消除左递归的操作后有些文法<span style="font-family:Times New Roman">F</span><span style="font-family:宋体">,</span><span style="font-family:Times New Roman">P</span><span style="font-family:宋体">变得不可达,可以删除,且其语法功能完整的保存下来了。即</span><span style="color:rgb(0,0,255)">前后两组文法所标示的语言等价。</span></p><p>下面是我们的消除左递归主要过程:</p><p></p><p>void RemoveAllLeftRecursion()</p><p>消除左递归的主调函数,主要完成上面的算法框架。</p><p></p><p>IsDirectLeftRecursion(int bel,int id)</p><p>判断MyProduction[bel][id]<span style="font-family:宋体">文法是否含有</span>直接左递归</p><p></p><p>bool RemoveDirectLeftRecursion(int bel,int id)</p><p>消除<span style="font-family:Times New Roman">MyProduction</span>[bel][id]<span style="font-family:宋体">文法的</span>直接左递归</p><p></p><p>void BFS(char start)</p><p>Satrt=<span style="font-family:宋体">文法开始符号,</span>宽度优先搜索可达状态</p><p></p><p>void DeleteUselessProduction(char start)</p><p>删除无用的产生式(主要指消除左递归后变成不可达的)</p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p>计算<span style="font-family:Times New Roman">FIRST</span><span style="font-family:宋体">集</span></p><p>     设<span style="font-family:Verdana">G=(VT,VN,P</span><span style="font-family:宋体">,</span><span style="font-family:Verdana">S)</span><span style="font-family:宋体">是上下文无关文法</span></p><p>         FIRST<span style="font-family:宋体">(</span>α)<span style="font-family:Verdana">={a|</span>α =>* aβ,a∈VT, α, β∈V*}</p><p>     若α =>* ε<span style="font-family:宋体">则规定</span><span style="font-family:Verdana">ε∈FRIST</span><span style="font-family:宋体">(</span>α)</p><p></p><p>       </p><p></p><p>我们计算<span style="font-family:Times New Roman">FIRST</span><span style="font-family:宋体">集就是依定义求的,下面是我们的计算</span><span style="font-family:Times New Roman">FIRST</span><span style="font-family:宋体">集主要过程:</span></p><p> </p><p>对于非终结符<span style="font-family:Times New Roman">ch,</span><span style="font-family:宋体">它的</span><span style="font-family:Times New Roman">FIRST</span><span style="font-family:宋体">集为</span>MySingleNFirstSet[ch-’A’]</p><p></p><p></p><p></p><p>/***********************************************</p><p>*<span style="font-family:宋体">参数</span><span style="font-family:Times New Roman">:str</span><span style="font-family:宋体">表示表示待处理的产生式</span></p><p>*<span style="font-family:宋体">功能</span><span style="font-family:Times New Roman">:</span><span style="font-family:宋体">深度优先搜索所有的非终结符的</span><span style="font-family:Times New Roman">FirstSet</span></p><p>***********************************************/</p><p>string DFS(string &str)</p><p>{</p><p>If(str<span style="font-family:宋体">的右部是空串</span><span style="font-family:Times New Roman">)</span></p><p>        Return <span style="font-family:宋体">空串;  </span></p><p>else </p><p>{</p><p>if(!(str[3]>='A'&&str[3]<='Z'))//<span style="font-family:宋体">此时表示</span>最右边是终结符</p><p>Return str[3];</p><p>else //str<span style="font-family:宋体">形如</span><span style="font-family:Times New Roman">str:  X->X[0]X[1]</span>…X[n]</p><p>{</p><p>            for(i=0-------n)</p><p>            {</p><p>                 FIRST(X[i])=DFS(<span style="font-family:宋体">以</span><span style="font-family:Times New Roman">X[i]</span><span style="font-family:宋体">开头的产生式</span><span style="font-family:Times New Roman">)</span><span style="font-family:宋体">;</span></p><p>                 Ret+=FIRST(X[i])-{ε}</p><p>                 如果<span style="font-family:Times New Roman">FIRST(X[i])</span><span style="font-family:宋体">不含</span>ε,退出for<span style="font-family:宋体">循环</span></p><p>            } </p><p>            Return ret;</p><p>        }</p><p>     } </p><p>}</p><p></p><p></p><p></p><p>/***********************************************</p><p>*<span style="font-family:宋体">参数</span><span style="font-family:Times New Roman">:</span><span style="font-family:宋体">无参数</span></p><p>*<span style="font-family:宋体">功能</span><span style="font-family:Times New Roman">:</span><span style="font-family:宋体">计算所有单个非终结符的</span><span style="font-family:Times New Roman">FIRST</span><span style="font-family:宋体">集</span></p><p>***********************************************/</p><p>void GetSingleNFirstSet()</p><p>{</p><p>      调用<span style="font-family:Times New Roman">DFS</span><span style="font-family:宋体">依次处理每个未处理产生式。</span></p><p></p><p>      由于上面求得的FIRST<span style="font-family:宋体">集</span>可能有重复,需去重 。</p><p>}</p><p></p><p>上面已经求出了单个字符的<span style="font-family:Times New Roman">FIRST</span><span style="font-family:宋体">集,下面进一步求符号串的</span><span style="font-family:Times New Roman">FIRST</span><span style="font-family:宋体">集,还是依定义。</span></p><p></p><p>单个字符<span style="font-family:Times New Roman">ch</span><span style="font-family:宋体">的</span><span style="font-family:Times New Roman">FIRST</span><span style="font-family:宋体">集</span>可表示为MySingleNFirstSet[ch-’A’],即string<span style="font-family:宋体">型数组;</span></p><p>     string MySingleNFirstSet[26];//<span style="font-family:宋体">存储所有单个非终结符的</span><span style="font-family:Times New Roman">FISRT</span><span style="font-family:宋体">集</span></p><p></p><p>符号串的<span style="font-family:Times New Roman">FIRST</span><span style="font-family:宋体">集</span>则不能用数组<span style="font-family:Times New Roman">int</span><span style="font-family:宋体">型下标直接索引,我们用关联容器</span><span style="font-family:Times New Roman">map.</span></p><p>   map<string,string>MyPRightFirstSet;//<span style="font-family:宋体">存储所有产生式右部的</span><span style="font-family:Times New Roman">FIRST</span><span style="font-family:宋体">集</span></p><p>为了提高效率可以不用map自己写个字典树关联,<span style="font-family:宋体">为了方便此处就用</span><span style="font-family:Times New Roman">map.</span></p><p></p><p></p><p>/***********************************************</p><p>*<span style="font-family:宋体">参数</span><span style="font-family:Times New Roman">:str</span><span style="font-family:宋体">表示待求</span><span style="font-family:Times New Roman">FIRST</span><span style="font-family:宋体">集的文法串</span></p><p>*<span style="font-family:宋体">功能</span><span style="font-family:Times New Roman">:</span><span style="font-family:宋体">计算单个产生式右部</span><span style="font-family:Times New Roman">str</span><span style="font-family:宋体">的</span><span style="font-family:Times New Roman">FIRST</span><span style="font-family:宋体">集</span></p><p>***********************************************/</p><p>string GetOnePRightFirstSet(string str)</p><p>{</p><p>if(str.表示的右部为空)</p><p>        R eturn <span style="font-family:宋体">空串;</span></p><p>for(i=0;i<str.size();i++)</p><p>{</p><p>if(str[i]为终结符)</p><p>        {</p><p>           将<span style="font-family:Times New Roman">str[i]</span><span style="font-family:宋体">加入</span><span style="font-family:Times New Roman">FIRST{str}</span><span style="font-family:宋体">;</span><span style="font-family:Times New Roman">return ;</span></p><p>        }</p><p>else if(如果str[i]<span style="font-family:宋体">为非终结符且</span>ε∈FIRST{str[i]})</p><p>           将<span style="font-family:Times New Roman">FIRST{str[i]}-{</span>ε}<span style="font-family:宋体">加入</span><span style="font-family:Times New Roman">FIRST{str}</span><span style="font-family:宋体">;</span></p><p>else if(如果str[i]<span style="font-family:宋体">为非终结符且</span>ε¢FIRST{str[i]})</p><p>{</p><p>   将<span style="font-family:Times New Roman">str[i]</span><span style="font-family:宋体">加入</span><span style="font-family:Times New Roman">FIRST{str}</span><span style="font-family:宋体">;</span><span style="font-family:Times New Roman">return ;</span></p><p>}</p><p>}</p><p>如果str<span style="font-family:宋体">中的每个符号的</span>FIRST<span style="font-family:宋体">集</span>都含有ε,将ε加入str<span style="font-family:宋体">的</span><span style="font-family:Times New Roman">FIRST</span><span style="font-family:宋体">;</span></p><p>}</p><p></p><p></p><p>/***********************************************</p><p>*<span style="font-family:宋体">参数</span><span style="font-family:Times New Roman">:</span><span style="font-family:宋体">无参数</span></p><p>*<span style="font-family:宋体">功能</span><span style="font-family:Times New Roman">:</span><span style="font-family:宋体">计算所有所有产生式右部的</span><span style="font-family:Times New Roman">FIRST</span><span style="font-family:宋体">集</span></p><p>***********************************************/</p><p>void GetPRightFirstSet()</p><p>{</p><p>      调用GetOnePRightFirstSet计算每个产生式右部的FIRST<span style="font-family:宋体">集;</span></p><p>      FIRST<span style="font-family:宋体">集去重</span></p><p>}</p><p></p><p></p><p></p><p></p><p></p><p></p><p>计算FOLLOW集</p><p>  下面是<span style="font-family:Times New Roman">FOLLOW</span><span style="font-family:宋体">集定义:</span></p><p></p><p></p><p></p><p>由于只需计算非终结符的<span style="font-family:Times New Roman">FOLLOW</span><span style="font-family:宋体">集,单个字符,可以开下面数组存储</span><span style="font-family:Times New Roman">FOLLOW</span><span style="font-family:宋体">集</span></p><p></p><p>     string MySingleNFollowSet[26];//<span style="font-family:宋体">存储所有单个非终结符的</span><span style="font-family:Times New Roman">FOLLOW</span><span style="font-family:宋体">集</span></p><p> 其中单个非终结符ch<span style="font-family:宋体">的</span>FOLLOW<span style="font-family:宋体">集</span>为MySingleNFollowSet[ch-’A’];</p><p></p><p></p><p></p><p></p><p></p><p></p><p>下面是依定义求<span style="font-family:Times New Roman">FOLLOW</span><span style="font-family:宋体">集的过程</span></p><p></p><p>/***********************************************</p><p>*<span style="font-family:宋体">参数</span><span style="font-family:Times New Roman">:str</span><span style="font-family:宋体">为一个待求</span><span style="font-family:Times New Roman">FOLLOW</span><span style="font-family:宋体">集的产生式</span></p><p>*<span style="font-family:宋体">功能</span><span style="font-family:Times New Roman">:</span><span style="font-family:宋体">计算</span><span style="font-family:Times New Roman">str</span><span style="font-family:宋体">中右部非终结符的</span><span style="font-family:Times New Roman">FOLLOW</span><span style="font-family:宋体">集</span></p><p>***********************************************/</p><p>void GetOneNFollowSet(string str)</p><p>上面函数是已定义计算一个的FOLLOW<span style="font-family:宋体">集,如</span></p><p>X=X[0]X[1]…X[n]<span style="font-family:宋体">,知道</span><span style="font-family:Times New Roman">X</span><span style="font-family:宋体">以及</span><span style="font-family:Times New Roman">X[0-n]</span><span style="font-family:宋体">的</span><span style="font-family:Times New Roman">FIRST</span><span style="font-family:宋体">集,就可以倒着退出</span><span style="font-family:Times New Roman">X[0-n]</span><span style="font-family:宋体">的</span><span style="font-family:Times New Roman">FOLLOW</span><span style="font-family:宋体">集,完全依定义。</span></p><p></p><p></p><p>/***********************************************</p><p>*<span style="font-family:宋体">参数</span><span style="font-family:Times New Roman">:id</span><span style="font-family:宋体">为开始文法符号的下标</span></p><p>*<span style="font-family:宋体">功能</span><span style="font-family:Times New Roman">:</span><span style="font-family:宋体">宽度优先搜索计算非终结符的</span><span style="font-family:Times New Roman">FOLLOW</span><span style="font-family:宋体">集</span></p><p>***********************************************/</p><p>void FollowSetBFS(int id)</p><p>{</p><p>    计算<span style="font-family:Times New Roman">FOLLOW</span><span style="font-family:宋体">集的求解顺序,如</span><span style="font-family:Times New Roman">X=X[0]X[1]</span>…X[n]<span style="font-family:宋体">;</span></p><p>    X<span style="font-family:宋体">入队列;</span></p><p>    While(<span style="font-family:宋体">队列不为空</span><span style="font-family:Times New Roman">)</span></p><p>   {</p><p>     tmp<span style="font-family:宋体">出队列;</span><span style="font-family:Times New Roman">//</span><span style="font-family:宋体">有产生式</span><span style="font-family:Times New Roman">tmp->tmp[0]tmp[1]</span>…tmp[n]</p><p>    知道<span style="font-family:Times New Roman">tmp</span><span style="font-family:宋体">,调用上面的</span>GetOneNFollowSet函数可以求得tmp[0]<span style="font-family:宋体">、</span><span style="font-family:Times New Roman">tmp[1]</span><span style="font-family:宋体">、</span>…tmp[n]<span style="font-family:宋体">的  </span><span style="font-family:Times New Roman">FOLLOW</span><span style="font-family:宋体">集(可能不全);</span></p><p>    tmp[0]<span style="font-family:宋体">、</span><span style="font-family:Times New Roman">tmp[1]</span><span style="font-family:宋体">、</span>…tmp[n]<span style="font-family:宋体">入队列;</span></p><p>   }</p><p>}</p><p></p><p></p><p></p><p>/***********************************************</p><p>*<span style="font-family:宋体">参数</span><span style="font-family:Times New Roman">:start</span><span style="font-family:宋体">文法开始符号</span></p><p>*<span style="font-family:宋体">功能</span><span style="font-family:Times New Roman">:</span><span style="font-family:宋体">计算所有单个非终结符的</span><span style="font-family:Times New Roman">FOLLOW</span><span style="font-family:宋体">集</span></p><p>***********************************************/</p><p>void GetSingleNFollowSet(char start)</p><p>{</p><p>将#加入FOLLOW(S)</p><p>FollowSetBFS(S);</p><p>    While(true)</p><p>    {</p><p>       FollowSetBFS(S);</p><p>        若前后两次一样,退出;</p><p>    }</p><p>    去重<span style="font-family:Times New Roman">FOLLOW</span><span style="font-family:宋体">集;</span></p><p>}</p><p><span style="color:rgb(0,0,255)">    </span></p><p></p><p></p><p>计算SELECT集 </p><p>   </p><p>   下面是<span style="font-family:Times New Roman">SELECT</span><span style="font-family:宋体">集的定义。</span></p><p></p><p></p><p>   有了<span style="font-family:Times New Roman">FIRST</span><span style="font-family:宋体">集,</span><span style="font-family:Times New Roman">FOLLOW</span><span style="font-family:宋体">集,就可以构造</span><span style="font-family:Times New Roman">SELECT</span><span style="font-family:宋体">集了。</span></p><p>   SELECT<span style="font-family:宋体">集是产生式与符号串的映射,也可以用关联容器</span><span style="font-family:Times New Roman">map</span><span style="font-family:宋体">。</span></p><p>        map<string,string>MySelectSet;//<span style="font-family:宋体">存储所有产生式的</span><span style="font-family:Times New Roman">SELECT</span><span style="font-family:宋体">集</span></p><p></p><p>/***********************************************</p><p>*<span style="font-family:宋体">参数</span><span style="font-family:Times New Roman">:</span><span style="font-family:宋体">无参数</span></p><p>*<span style="font-family:宋体">功能</span><span style="font-family:Times New Roman">:</span><span style="font-family:宋体">计算所有产生式的</span><span style="font-family:Times New Roman">FSELECT</span><span style="font-family:宋体">集</span></p><p>***********************************************/</p><p>void GetProductionSelectSet()</p><p>{</p><p>For(i=0;i<26;i++)</p><p>{</p><p>   If(char(‘A’+i)<span style="font-family:宋体">是用到的产生式的右部</span><span style="font-family:Times New Roman">)</span></p><p>   {</p><p>      For(<span style="font-family:宋体">对以</span><span style="font-family:Times New Roman">char(</span>‘A’+i)<span style="font-family:宋体">为右部的每个产生式</span><span style="font-family:Times New Roman">)//</span>A-><span style="font-family:宋体">α</span></p><p>      {</p><p>         If(<span style="font-family:宋体">右部可以退出空串</span><span style="font-family:Times New Roman">)</span></p><p>            SELECT(A-><span style="font-family:宋体">α</span><span style="font-family:Times New Roman">)={FIRST(</span><span style="font-family:宋体">α</span><span style="font-family:Times New Roman">)-{</span><span style="font-family:宋体">ε</span><span style="font-family:Times New Roman">}}</span><span style="font-family:宋体">∪</span><span style="font-family:Times New Roman">FOLLOW(A)</span></p><p>         Else if(<span style="font-family:宋体">右部不能退出空串</span><span style="font-family:Times New Roman">)</span></p><p>            SELECT(A-><span style="font-family:宋体">α</span><span style="font-family:Times New Roman">)=FIRST(</span><span style="font-family:宋体">α</span><span style="font-family:Times New Roman">)</span></p><p>      }</p><p>   }</p><p>} </p><p>}</p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p>判断<span style="font-family:Times New Roman">LL(1)</span><span style="font-family:宋体">文法</span></p><p>     在求得<span style="font-family:Times New Roman">SELECT</span><span style="font-family:宋体">集后,就可以判断所给文法是否是</span><span style="font-family:Times New Roman">LL</span><span style="font-family:宋体">(</span><span style="font-family:Times New Roman">1</span><span style="font-family:宋体">)文法。</span></p><p>     首先得计算相同左部产生式的<span style="font-family:Times New Roman">SELECT</span><span style="font-family:宋体">交集。</span></p><p>     基于<span style="font-family:Times New Roman">SELECT</span><span style="font-family:宋体">集的元素是单个字符,判断交集可以用</span><span style="font-family:Times New Roman">hash</span><span style="font-family:宋体">的思想。假设当前需判断</span></p><p>产生式SELECT(A-><span style="font-family:宋体">α</span><span style="font-family:Times New Roman">)</span>与SELECT(A-><span style="font-family:宋体">β</span><span style="font-family:Times New Roman">)</span>的交集。可以先开数组</p><p>          bool visited[128];</p><p>          Memset(visited,false,sizeof(visited));//visited[]<span style="font-family:宋体">都置</span><span style="font-family:Times New Roman">false</span></p><p>     首先处理SELECT(A-><span style="font-family:宋体">α</span><span style="font-family:Times New Roman">)</span></p><p>          For(i=0;i<MySelectSet[A-><span style="font-family:宋体">α</span>].size();i++)</p><p>              Visited[MySelectSet[A-><span style="font-family:宋体">α</span>][i]]=true;</p><p>     然后处理SELECT(A-><span style="font-family:宋体">β</span><span style="font-family:Times New Roman">)</span></p><p>          For(i=0;i<MySelectSet[A-><span style="font-family:宋体">β</span>].size();i++)</p><p>              If(Visited[MySelectSet[A-><span style="font-family:宋体">β</span>][i]]==true)</p><p>                 则存在交集,不是<span style="font-family:Times New Roman">LL(1)</span><span style="font-family:宋体">文法。</span></p><p>     </p><p>若所有相同左部产生式的<span style="font-family:Times New Roman">SELECT</span><span style="font-family:宋体">交集都为空集,则为</span><span style="font-family:Times New Roman">LL</span><span style="font-family:宋体">(</span><span style="font-family:Times New Roman">1</span><span style="font-family:宋体">)文法。</span></p><p></p><p></p><p></p><p></p><p></p><p>构造预测分析表</p><p>     不同文法的预测分析表一般是不同的。每个文法的预测分析表可以通过<span style="font-family:Verdana">SELECT</span><span style="font-family:宋体">集求得。</span></p><p>     预测分析表ForecastTable[Up][Low]<span style="font-family:宋体">表示的是当非终结符</span><span style="font-family:Times New Roman">Up</span><span style="font-family:宋体">遇到终结符</span><span style="font-family:Times New Roman">Low</span><span style="font-family:宋体">时转到下一个状态需用的产生式。</span></p><p>     预测分析表可以开个二维数组,也可以用关联容器<span style="font-family:Verdana">map</span><span style="font-family:宋体">或写棵字典树,此处由于在分析过程中要经常用到且终结符与非终结符都不是多,为了简化,直接开个二维数组</span></p><p>          node  ForecastTable[26][128];其中ForecastTable[][]只存储产生式的右部,左部可以通过第一维的下表获得,节省了空间。</p><p></p><p>此过程比较简单,直接贴代码。</p><p>/***********************************************</p><p>*<span style="font-family:宋体">参数</span><span style="font-family:Times New Roman">:</span><span style="font-family:宋体">无参数</span></p><p>*<span style="font-family:宋体">功能</span><span style="font-family:Times New Roman">:</span><span style="font-family:宋体">计算预测分析表</span><span style="font-family:Times New Roman">ForecastTable[][]</span></p><p>***********************************************/</p><p>void GetForecastTable()</p><p>{</p><p>int i;</p><p>for(map<string,string>::iterator iter=MySelectSet.begin();iter!=MySelectSet.end();iter++)</p><p>{</p><p>string tmp=iter->first;//<span style="font-family:宋体">整个产生式</span></p><p>tmp.erase(tmp.begin(),tmp.begin()+3);//<span style="font-family:宋体">获得产生式的右部</span></p><p>int row=(iter->first)[0]-'A';//<span style="font-family:宋体">产生式的开始符</span></p><p>for(i=0;i<(iter->second).size();i++)//<span style="font-family:宋体">遍历</span>SELECT<span style="font-family:宋体">集(</span>iter->first]<span style="font-family:宋体">)</span></p><p>        {</p><p>Terminate[(iter->second)[i]]=true;</p><p>ForecastTable[row][(iter->second)[i]].Pro=tmp;</p><p>ForecastTable[row][(iter->second)[i]].tag=true;</p><p>}</p><p>}</p><p>}</p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p>模拟分析过程</p><p>     下面就是模拟分析过程了。大致框架如下:</p><p>    <img src="https://img-blog.csdn.net/20131217180736687?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveGoyNDE5MTc0NTU0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="" /></p><p>    </p><p>     在此有个小优化,就是不用栈,直接用<span style="font-family:Times New Roman">string</span><span style="font-family:宋体">类型变量模拟栈的功能,减少资源开销。</span></p><p><span style="font-family:宋体"></span></p><p><span style="font-family:宋体"></span></p><pre code_snippet_id="116372" snippet_file_name="blog_20131217_1_8102878" name="code" class="cpp">#include<iostream>
#include<iomanip>
#include<cstring>
#include<string>
#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
#include<queue>
#include<numeric>
#include<map>
#include<stack>
#include<cstdlib>
using namespace std;

int UsedUpLetter[26];//表示非终结符的使用情况
bool IsReached[26];//表示非终结符是否可达
bool IsGetFirstSet[26];//表示是否计算过First集
bool IsGetFollowSet[26];//表示是否计算过Follow集
bool Terminate[128];//存储终结符的ASCII码
vector<string>MyProduction[26];//存储所有的产生式
string MySingleNFirstSet[26];//存储所有单个非终结符的FISRT集
string MySingleNFollowSet[26];//存储所有单个非终结符的FOLLOW集
map<string,string>MyPRightFirstSet;//存储所有产生式右部的FIRST集
map<string,string>MySelectSet;//存储所有产生式的SELECT集
string MyNProStr;//待识别句子
string StartChar;//开始文法符号

struct node
{
	string Pro;
	bool tag;
}ForecastTable[26][128];//预测分析表

/***********************************************/
//*参数:无参数
//*功能:初始化函数
/***********************************************/
void init()
{
	memset(UsedUpLetter,0,sizeof(UsedUpLetter));
	memset(IsReached,false,sizeof(IsReached));
	memset(IsGetFirstSet,false,sizeof(IsGetFirstSet));
	memset(IsGetFollowSet,false,sizeof(IsGetFollowSet));
	memset(Terminate,false,sizeof(Terminate));
	
	MyPRightFirstSet.clear();
	MySelectSet.clear();
	
	StartChar.erase(StartChar.begin(),StartChar.end());
	MyNProStr.erase(MyNProStr.begin(),MyNProStr.end());
	
	for(int i=0;i<26;i++)
	{
		MyProduction[i].clear();
		MySingleNFirstSet[i].erase(MySingleNFirstSet[i].begin(),MySingleNFirstSet[i].end());
		MySingleNFollowSet[i].erase(MySingleNFollowSet[i].begin(),MySingleNFollowSet[i].end());
		for(int j=0;j<128;j++)
		{
			ForecastTable[i][j].Pro.erase(ForecastTable[i][j].Pro.begin(),ForecastTable[i][j].Pro.end());
			ForecastTable[i][j].tag=false;
		}
	}
}

bool CharCmp(char a,char b)
{
	return a<b;
}

/***********************************************
*参数:无参数
*功能:打印所有的产生式
***********************************************/
void PrintMyProduction()
{
	int i;
	cout<<setiosflags(ios::left);
	for(i=0;i<26;i++)
	{
		for(vector<string>::iterator iter=MyProduction[i].begin();iter!=MyProduction[i].end();iter++)
		{
			//cout.width(8);
			cout<<(*iter);
			if((*iter).size()==3)
				cout<<"ε";
			cout<<endl;
		}
	}
	cout<<resetiosflags(ios::left);
	cout<<"********************************************"<<endl<<endl;
}

/********************************************消除左递归******************************************************/
/***********************************************
*参数:判断MyProduction[bel][id]中是否含有直接左递归的产生式的下标
*功能:判断是否含有直接左递归
***********************************************/
bool IsDirectLeftRecursion(int bel,int id)
{
	//A->Aγ,且γ不为空
	if(MyProduction[bel][id][0]==MyProduction[bel][id][3]&&MyProduction[bel][id].size()>4)
		return true;
	return false;
}

/***********************************************
*参数:start表示开始的非终结符
*功能:宽度优先搜索可达状态
***********************************************/
void BFS(char start)
{
	int i,j;
	queue<int>MyQueue;
	IsReached[start-'A']=true;
	MyQueue.push(start-'A');
	while(!MyQueue.empty())
	{
		int now=MyQueue.front();
		//cout<<char('A'+now)<<endl;
		MyQueue.pop();
		for(i=0;i<MyProduction[now].size();i++)//MyProduction[now][i]单个产生式
		{
			for(j=3;j<MyProduction[now][i].size();j++)//每个产生式的右部搜非终结符
			{
				char ch=MyProduction[now][i][j];
				if(ch>='A'&&ch<='Z'&&!IsReached[ch-'A'])//是终结符且未处理
				{
					IsReached[ch-'A']=true;
					MyQueue.push(ch-'A');
				}
			}
		}
	}
}

/***********************************************
*参数:start表示开始的非终结符
*功能:删除无用的产生式
***********************************************/
void DeleteUselessProduction(char start)
{
	int i;
	BFS(start);
	for(i=0;i<26;i++)
	{
		//删除不可达的产生式
		if(!IsReached[i])
			MyProduction[i].clear();
	}
}

/***********************************************
*参数:id表示当前需消除左递归的产生式的下标
*功能:消除当前的直接左递归递归
***********************************************/
bool RemoveDirectLeftRecursion(int bel,int id)
{
	int i;
	if(IsDirectLeftRecursion(bel,id))//判断含有直接左递归
	{
		for(i=0;i<26;i++)//找到一个未使用的大写字符充当非终结符
		{
			if(0==UsedUpLetter[i])
			{
				break;
			}
		}
		//将A->Aγ变成X->γX,X->ε
		UsedUpLetter[i]=-1;
		string tmp1=MyProduction[bel][id];
		char ch=MyProduction[bel][id][0];
		tmp1.erase(0,4);
		MyProduction[bel].erase(MyProduction[bel].begin()+id);
		string tmp2;
		tmp2.insert(0,'A'+i);
		tmp2+="->";
		MyProduction[i].push_back(tmp2);
		
		tmp2+=tmp1;
		tmp2+='A'+i;
		MyProduction[i].push_back(tmp2);
		
		//将A->γβ,其中γ不以A
		for(int k=0;k<MyProduction[bel].size();k++)
		{
			if(MyProduction[bel][k][0]==ch)
			{
				MyProduction[bel][k]+='A'+i;
			}
		}
		return true;
	}
	return false;
}

/***********************************************
*参数:无参数
*功能:消除所有的左递归
***********************************************/
void RemoveAllLeftRecursion()
{
	int i,j,k,t;
	for(i=0;i<26;i++)
	{
		if(1==UsedUpLetter[i])
		{
			for(j=0;j<i;j++)
			{
				if(1==UsedUpLetter[j])
				{
					//把左部为A[j]的所有规则的右部替换左部为A[i]开头的右部以A[j]开始的产生式中的A[j]
					//A[j]->α|β,A[i]->A[j]γ变成A[i]->αγ,A[i]->βγ
					vector<string>TempVec;
					TempVec.clear();
					for(k=0;k<MyProduction[i].size();k++)
					{
						bool flag=false;
						string tmp=MyProduction[i][k];
						tmp.erase(tmp.begin()+3);//删除中的A[j]
						string tmptmp=tmp;
						for(t=0;t<MyProduction[j].size();t++)
						{
							string right=MyProduction[j][t];//得到A[j]->γ中的γ
							right.erase(0,3);
							if(MyProduction[i][k].size()>3&&MyProduction[i][k][3]=='A'+j)
							{
								tmp.insert(3,right);
								TempVec.push_back(tmp);//此处用TempVec而不是直接加到MyProduction[i]是为了防止不必要的处理
								//	cout<<"tmp="<<tmp<<endl;
								flag=true;
							}
							tmp=tmptmp;
						}
						if(flag)//有产生式被替换
						{
							MyProduction[i].erase(MyProduction[i].begin()+k);
							k=k-1;//退到下一个待处理的位置
						}
					}	
					for(k=0;k<TempVec.size();k++)
						MyProduction[i].push_back(TempVec[k]);
				}
			}
			//删除A[i]->A[i]γ的直接左递归
			for(j=0;j<MyProduction[i].size();j++)
			{
				if(RemoveDirectLeftRecursion(i,j))j=j-1;//消除直接左递归成功,删除原产生式,故左移一个
			}
		}
	}
	cout<<endl<<"消除左递归但未删除无用状态的文法G["<<StartChar<<"]:"<<endl;
	PrintMyProduction();
	
	DeleteUselessProduction(StartChar[0]);
	
	//出现在产生式中但消除左递归后不可达非终结符
	int numNotUsed=0;
	bool NotUsed[26];
	memset(NotUsed,false,sizeof(NotUsed));
	for(i=0;i<26;i++)
	{
		if(UsedUpLetter[i]&&!IsReached[i])
		{
			numNotUsed++;
			NotUsed[i]=true;
			UsedUpLetter[i]=0;
		}
	}
	cout<<endl<<"消除左递归后不可达的非终结符有"<<numNotUsed<<"个!"<<endl;
	if(numNotUsed)
	{
		cout<<"它(们)是:";
		for(i=0;i<26;i++)
		{
			if(NotUsed[i])
				cout<<char('A'+i)<<" ";
		}
		cout<<"除掉包含它(们)的产生式!"<<endl;
	}
	cout<<"********************************************"<<endl<<endl;
	
	
	cout<<endl<<"消除左递归且删除无用状态的文法G["<<StartChar<<"]:"<<endl;
	PrintMyProduction();
}

/********************************************计算FIRST集******************************************************/

/***********************************************
*参数:无参数
*功能:打印所有单个非终结符的FirstSet
***********************************************/
void PrintMySingleNFirstSet()
{
	int i,j;
	cout<<endl<<"单个非终结符的FIRST集:"<<endl;
	cout<<setiosflags(ios::left);
	for(i=0;i<26;i++)
	{
		if(UsedUpLetter[i])
		{
			cout<<char('A'+i);
			cout<<"的FIRST集:";
			//cout.width(8);
			//	cout<<MySingleNFirstSet[i]<<endl;
			for(j=0;j<MySingleNFirstSet[i].size();j++)
			{
				if(MySingleNFirstSet[i][j]=='@')
					cout<<"ε";
				else cout<<MySingleNFirstSet[i][j];
				if(j!=MySingleNFirstSet[i].size()-1)
					cout<<",";
			}
			cout<<endl;
		}
	}
	cout<<resetiosflags(ios::left);
	cout<<"********************************************"<<endl<<endl;
}

/***********************************************
*参数:str表示表示待处理的产生式
*功能:深度优先搜索所有的非终结符的FirstSet
***********************************************/
string DFS(string &str)
{
	int i;
	string ret;
	if(str.size()==3)
	{
		ret+='@';//表示@表示空串
	}
	else if(str.size()>3)
	{
		if(!(str[3]>='A'&&str[3]<='Z'))//此时表示终结符
			ret+=str[3];
		else 
		{
			int st=3;
			string tmp;
			while(st==3||tmp.find('@',0)!=string::npos)//A->BC中存在@表示的空串
			{
				if(ret.find('@',0)!=string::npos&&st<str.size())
				{
					ret.erase(ret.begin()+ret.find('@',0));
				}
				tmp.erase(tmp.begin(),tmp.end());
				int id=str[st++]-'A';
				if(!IsGetFirstSet[id])
				{
					for(i=0;i<MyProduction[id].size();i++)//MyProduction[id][i]表示单个产生式
					{
						tmp+=DFS(MyProduction[id][i]);
						MySingleNFirstSet[MyProduction[id][i][0]-'A']+=tmp;
					}
					IsGetFirstSet[id]=true;
				}
				else tmp+=MySingleNFirstSet[id];
				ret+=tmp;
			}
		}
	}
	return ret;
}

/***********************************************
*参数:无参数
*功能:计算所有单个非终结符的FIRST集
***********************************************/
void GetSingleNFirstSet()
{
	int i,j;
	for(i=0;i<26;i++)
	{
		if(UsedUpLetter[i]&&!IsGetFirstSet[i])
		{
			for(j=0;j<MyProduction[i].size();j++)
			{
				MySingleNFirstSet[i]+=DFS(MyProduction[i][j]);
			}
			IsGetFirstSet[i]=true;
		}
	}
	//去掉重复的
	for(i=0;i<26;i++)
	{
		if(UsedUpLetter[i])
		{
			sort(MySingleNFirstSet[i].begin(),MySingleNFirstSet[i].end(),CharCmp);
			int DifNum=unique(MySingleNFirstSet[i].begin(),MySingleNFirstSet[i].end())-MySingleNFirstSet[i].begin();
			MySingleNFirstSet[i].erase(MySingleNFirstSet[i].begin()+DifNum,MySingleNFirstSet[i].end());
		}
	}
	PrintMySingleNFirstSet();
}

/***********************************************
*参数:无参数
*功能:打印所有产生式右部的FirstSet
***********************************************/
void PrintPRightFirstSet()
{
	cout<<endl<<"产生式右部符号串的FIRST集"<<endl;
	cout<<setiosflags(ios::left);
	for(map<string,string>::iterator iter=MyPRightFirstSet.begin();iter!=MyPRightFirstSet.end();iter++)
	{
		cout.width(8);
		if((iter->first).size()==0)
			cout<<"ε";
		else cout<<iter->first;
		cout<<"的FIRST集:";
		//	cout.width(8);
		//cout<<iter->second<<endl;
		for(int i=0;i<(iter->second).size();i++)
		{
			if((iter->second)[i]=='@')
				cout<<"ε";
			else cout<<(iter->second)[i];
			if(i!=(iter->second).size()-1)
				cout<<",";
		}
		cout<<endl;
	}
	cout<<resetiosflags(ios::left);
	cout<<"********************************************"<<endl<<endl;
}


/***********************************************
*参数:str表示待求FIRST集的文法串
*功能:计算单个产生式右部str的FIRST集
***********************************************/
string GetOnePRightFirstSet(string str)
{
	int i,cnt=0;
	string ret;
	if(str.size()==0)
	{
		ret+="@";
		return ret;
	}
	for(i=0;i<str.size();i++)
	{
		if(!(str[i]>='A'&&str[i]<='Z'))//为终结符
		{
			ret+=str[i];
			break;
		}
		else if(MySingleNFirstSet[str[i]-'A'].find('@',0)!=string::npos)//A->CB,C中含有@
		{
			cnt++;
			string tmp;
			tmp=MySingleNFirstSet[str[i]-'A'];
			int tid=tmp.find('@',0);
			tmp.erase(tmp.begin()+tid);
			ret+=tmp;
		}
		else 
		{
			ret+=MySingleNFirstSet[str[i]-'A'];
			break;
		}
	}
	if(cnt==str.size())//所有的A->CB右部都含@,
		ret+="@";
	return ret;
}

/***********************************************
*参数:无参数
*功能:计算所有所有产生式右部的FIRST集
***********************************************/
void GetPRightFirstSet()
{
	int i,j;
	for(i=0;i<26;i++)
	{
		if(UsedUpLetter[i])
		{
			for(j=0;j<MyProduction[i].size();j++)
			{
				string tmp;//tmp为MyProduction[i][j]的右部
				tmp.append(MyProduction[i][j].begin()+3,MyProduction[i][j].end());
				MyPRightFirstSet[tmp]+=GetOnePRightFirstSet(tmp);
			}
		}
	}
	for(map<string,string>::iterator iter=MyPRightFirstSet.begin();iter!=MyPRightFirstSet.end();iter++)
	{
		sort((iter->second).begin(),(iter->second).end(),CharCmp);
		int DifNum=unique((iter->second).begin(),(iter->second).end())-(iter->second).begin();
		(iter->second).erase((iter->second).begin()+DifNum,(iter->second).end());
	}
}

/********************************************计算FOLLOW集******************************************************/

/***********************************************
*参数:无参数
*功能:打印所有非终结符的FOLLOW集
***********************************************/
void PrintMySingleNFollowSet()
{
	int i,j;
	cout<<endl<<"单个非终结符的FOLLOW集:"<<endl;
	cout<<setiosflags(ios::left);
	for(i=0;i<26;i++)
	{
		if(UsedUpLetter[i])
		{
			cout<<char('A'+i);
			cout<<"的FOLLOW集:";
			//cout.width(8);
			//	cout<<MySingleNFollowSet[i]<<endl;
			for(j=0;j<MySingleNFollowSet[i].size();j++)
			{
				if(MySingleNFollowSet[i][j]=='@')
					cout<<"ε";
				else cout<<MySingleNFollowSet[i][j];
				if(j!=MySingleNFollowSet[i].size()-1)
					cout<<",";
			}
			cout<<endl;
		}
	}
	cout<<resetiosflags(ios::left);
	cout<<"********************************************"<<endl<<endl;
}

/***********************************************
*参数:str为一个待求FOLLOW集的产生式
*功能:计算str中右部非终结符的FOLLOW集
***********************************************/
void GetOneNFollowSet(string str)
{
	int i;
	bool flag=true;
	for(i=str.size()-1;i>=3;i--)
	{
		//	cout<<"i="<<i<<endl;
		if(i!=3)//i的右边有符号A->αBβ
		{
			if(!(str[i]>='A'&&str[i]<='Z')&&str[i-1]>='A'&&str[i-1]<='Z')//β是终结符
			{
				flag=false;
				MySingleNFollowSet[str[i-1]-'A']+=str[i];//β∈FOLLOW(B)
			}
			else if(str[i-1]>='A'&&str[i-1]<='Z')//β是非终结符
			{
				int tid;
				string tmp=MySingleNFirstSet[str[i]-'A'];		
				if((tid=tmp.find('@',0))!=string::npos)//去掉First(β)集中的空串ε
				{
					tmp.erase(tmp.begin()+tid);
				}
				else flag=false;
				if(flag)
				{
					MySingleNFollowSet[str[i-1]-'A']+=MySingleNFollowSet[str[0]-'A'];//β—>ε(可能多次推导),FOLLOW(A)∈FOLLOW(B)
				}
				MySingleNFollowSet[str[i-1]-'A']+=tmp;//FIRST(β)-{ε}∈FOLLOW(B)	   
			}
		}
	}
	if(str[str.size()-1]>='A'&&str[str.size()-1]<='Z')//A->βB
	{
		MySingleNFollowSet[str[str.size()-1]-'A']+=MySingleNFollowSet[str[0]-'A'];
	}
}

/***********************************************
*参数:id为开始文法符号的下标
*功能:宽度优先搜索计算非终结符的FOLLOW集
***********************************************/
void FollowSetBFS(int id)
{
	int i,j,now;
	queue<int>MyQueue;
	MyQueue.push(id);
	IsGetFollowSet[id]=true;
	while(!MyQueue.empty())
	{
		now=MyQueue.front();
		//cout<<"now="<<char('A'+now)<<endl;
		MyQueue.pop();
		for(i=0;i<MyProduction[now].size();i++)//第i个产生式
		{
			GetOneNFollowSet(MyProduction[now][i]);
			for(j=0;j<MyProduction[now][i].size();j++)//第j个字符
			{
				if(MyProduction[now][i][j]>='A'&&MyProduction[now][i][j]<='Z')
				{
					if(!IsGetFollowSet[MyProduction[now][i][j]-'A'])
					{
						IsGetFollowSet[MyProduction[now][i][j]-'A']=true;
						MyQueue.push(MyProduction[now][i][j]-'A');
					}
				}
			}
		}
	}
}

/***********************************************
*参数:start文法开始符号
*功能:计算所有单个非终结符的FOLLOW集
***********************************************/
void GetSingleNFollowSet(char start)
{
	int i,j;
	MySingleNFollowSet[start-'A']="#";//#∈FOLLOW(S)
	IsGetFollowSet[start-'A']=true;
	FollowSetBFS(start-'A');
	for(i=0;i<26;i++)
	{
		if(UsedUpLetter[i])
		{
			sort(MySingleNFollowSet[i].begin(),MySingleNFollowSet[i].end(),CharCmp);
			int DifNum=unique(MySingleNFollowSet[i].begin(),MySingleNFollowSet[i].end())-MySingleNFollowSet[i].begin();
			MySingleNFollowSet[i].erase(MySingleNFollowSet[i].begin()+DifNum,MySingleNFollowSet[i].end());
		}
	}
	string tmpFollowSet[26];//临时存储所有单个非终结符的FOLLOW集
	for(i=0;i<26;i++)
	{
		if(UsedUpLetter[i])
		{
			tmpFollowSet[i]=MySingleNFollowSet[i];
		}
	}
	bool IsExit=false;
	while(true)
	{
		IsExit=false;
		memset(IsGetFollowSet,false,sizeof(IsGetFollowSet));
		IsGetFollowSet[start-'A']=true;
		FollowSetBFS(start-'A');
		for(i=0;i<26;i++)
		{
			if(UsedUpLetter[i])
			{
				sort(MySingleNFollowSet[i].begin(),MySingleNFollowSet[i].end(),CharCmp);
				int DifNum=unique(MySingleNFollowSet[i].begin(),MySingleNFollowSet[i].end())-MySingleNFollowSet[i].begin();
				MySingleNFollowSet[i].erase(MySingleNFollowSet[i].begin()+DifNum,MySingleNFollowSet[i].end());
				if(tmpFollowSet[i]!=MySingleNFollowSet[i])//有一个不相等则继续判断
				{
					tmpFollowSet[i]=MySingleNFollowSet[i];
					IsExit=true;
				}
			}
		}
		if(!IsExit)
			break;
	}
}

/********************************************计算SELECT集******************************************************/

/***********************************************
*参数:无参数
*功能:打印所有产生式的SelsectSet
***********************************************/
void PrintProductionSelectSet()
{
	cout<<endl<<"所有产生式的SELECT SET:"<<endl;
	cout<<setiosflags(ios::left);
	for(map<string,string>::iterator iter=MySelectSet.begin();iter!=MySelectSet.end();iter++)
	{
		cout.width(8);
		string tmp;
		tmp=iter->first;
		if((iter->first).size()==3)
			tmp+="ε";
		cout<<tmp;
		
		cout<<"的SELECT集:";
		//cout.width(8);
		//cout<<iter->second<<endl;
		for(int i=0;i<(iter->second).size();i++)
		{
			if((iter->second)[i]=='@')
				cout<<"ε";
			else cout<<(iter->second)[i];
			if(i!=(iter->second).size()-1)
				cout<<",";
		}
		cout<<endl;
		
	}
	cout<<resetiosflags(ios::left);
	cout<<"********************************************"<<endl<<endl;
}


/***********************************************
*参数:无参数
*功能:计算所有产生式的FSELECT集
***********************************************/
void GetProductionSelectSet()
{
	int i,j;
	for(i=0;i<26;i++)
	{
		if(UsedUpLetter[i])
		{
			for(j=0;j<MyProduction[i].size();j++)//MyProduction[i][j]表示单个产生式,A->α
			{
				string tmp;
				int tid;
				tmp.append(MyProduction[i][j].begin()+3,MyProduction[i][j].size()-3);//tmp为右部
				//	cout<<"tmp="<<tmp<<"   MyPRightFirstSet[tmp]="<<MyPRightFirstSet[tmp]<<endl;
				if(!tmp.size())//产生式右部为空
				{
					MySelectSet[MyProduction[i][j]]=MySingleNFollowSet[MyProduction[i][j][0]-'A'];//SELECT(A->ε)=FOLLOW(A)
				}
				else if(!((tid=MyPRightFirstSet[tmp].find('@',0))!=string::npos))//α不能推导出ε,SELECT(A->α)=FIRST(α)
				{
					MySelectSet[MyProduction[i][j]]=MyPRightFirstSet[tmp];
				}
				else //α推导出ε,SELECT(A->α)={FIRST(α)-{ε}}∪FOLLOW(A)
				{
					string ttmp=MyPRightFirstSet[tmp].erase(MyPRightFirstSet[tmp].begin()+tid);
					MySelectSet[MyProduction[i][j]]+=ttmp;//SELECT(A->α)+={FIRST(α)-{ε}}
					MySelectSet[MyProduction[i][j]]+=MySingleNFollowSet[MyProduction[i][j][0]-'A'];//SELECT(A->α)+=FOLLOW(A)
					
					sort(MySelectSet[MyProduction[i][j]].begin(),MySelectSet[MyProduction[i][j]].end(),CharCmp);
					int DifNum=unique(MySelectSet[MyProduction[i][j]].begin(),MySelectSet[MyProduction[i][j]].end())-MySelectSet[MyProduction[i][j]].begin();
					MySelectSet[MyProduction[i][j]].erase(MySelectSet[MyProduction[i][j]].begin()+DifNum,MySelectSet[MyProduction[i][j]].end());
				}
				//cout<<MyProduction[i][j]<<" SELECT :"<<MySelectSet[MyProduction[i][j]]<<endl;
			}
		}
	}
}


/********************************************判断是否是LL(1)文法******************************************************/

/***********************************************
*参数:无参数
*功能:判断所给文法是否是LL(1)文法
***********************************************/
bool IsLL1()
{
	bool visited[128];//对应128个ASCII码
	int i;
	for(map<string,string>::iterator iter=MySelectSet.begin();iter!=MySelectSet.end();iter++)
	{
		memset(visited,false,sizeof(visited));
		for(i=0;i<(iter->second).size();i++)//前一个的SELECT集
		{
			visited[(iter->second)[i]]=true;
		}
		map<string,string>::iterator tmp=iter;
		for(tmp++;tmp!=MySelectSet.end();tmp++)
		{
			if((iter->first)[0]==(tmp->first)[0])//两产生式右部相等
			{
				for(i=0;i<(tmp->second).size();i++)//后一个的SELECT集
				{
					if(visited[(tmp->second)[i]])
					{
						cout<<setiosflags(ios::left);
						cout.width(8);	cout<<iter->first;
						cout<<"的SELECTE Set :";
						cout.width(8);cout<<iter->second;
						cout<<endl;
						
						cout.width(8);cout<<tmp->first;
						cout<<"的SELECTE Set :";
						cout.width(8);cout<<tmp->second;
						cout<<endl;
						cout<<"以上二者包含相同元素:";
						cout.width(3);cout<<(tmp->second)[i]<<endl;
						cout<<"所输入的文法G["<<StartChar<<"]不是LL(1)文法!"<<endl<<endl;
						cout<<resetiosflags(ios::left);
						return false;
					}
				}
			}
		}
	}
	cout<<endl<<"所输入的文法G["<<StartChar<<"]是LL(1)文法!"<<endl<<endl;
	return true;
}

/********************************************计算预测分析表******************************************************/

/***********************************************
*参数:无参数
*功能:打印预测分析表
***********************************************/
void PrintForecastTable()
{
	int i,j;
	cout<<"预测分析表:"<<endl;
	//cout<<"     ";
	for(i=0;i<128;i++)
	{
		if(Terminate[i])
		{
			cout.width(10);
			cout<<char(i);
		}
	}
	cout<<endl;
	string ch="ε";
	cout<<setiosflags(ios::left);//
	for(i=0;i<26;i++)
	{
		if(UsedUpLetter[i])
		{
			cout.width(8);cout<<char('A'+i);
			for(j=0;j<128;j++)
			{
				if(Terminate[j])
				{
					string tmp;
					tmp+="->";
					if(ForecastTable[i][j].Pro.size())
					{
						tmp+=ForecastTable[i][j].Pro;
					}
					else if(ForecastTable[i][j].tag)
					{
						tmp+=ch;
					}
					cout.width(10);
					if(tmp!="->")
						cout<<tmp;
					else cout<<"NULL";
				}
			}
			cout<<endl;
		}
	}
	cout<<resetiosflags(ios::left);//
	cout<<"********************************************"<<endl<<endl;
}

/***********************************************
*参数:无参数
*功能:计算预测分析表ForecastTable[][]
***********************************************/
void GetForecastTable()
{
	int i;
	for(map<string,string>::iterator iter=MySelectSet.begin();iter!=MySelectSet.end();iter++)
	{
		string tmp=iter->first;
		tmp.erase(tmp.begin(),tmp.begin()+3);
		int row=(iter->first)[0]-'A';
		//	cout<<"tmp="<<tmp<<"  "<<iter->second<<endl;
		for(i=0;i<(iter->second).size();i++)
		{
			Terminate[(iter->second)[i]]=true;
			ForecastTable[row][(iter->second)[i]].Pro=tmp;
			ForecastTable[row][(iter->second)[i]].tag=true;
		}
	}
}

/********************************************模拟分析过程******************************************************/

/***********************************************
*参数:无参数
*功能:显示分析过程
***********************************************/
void Process()
{
	string MyStack;
	MyStack+="#";
	MyStack+=StartChar;
	cout<<"我的需识别的句子:"<<MyNProStr<<endl<<endl;
	string str=MyNProStr;
	
	cout<<setiosflags(ios::left);
	cout<<"步骤    ";
	cout<<"分析栈           ";
	cout<<"                剩余输入串";
	cout<<"          推导用产生式或匹配"<<endl;
	cout<<resetiosflags(ios::left);
	
	int count=0;
	while(MyStack.size()&&str.size())
	{
		string X;
		X.append(MyStack.end()-1,1);
		count++;
		
		cout<<setiosflags(ios::left);
		cout.width(8);cout<<count;
		cout.width(15);cout<<MyStack;
		cout<<resetiosflags(ios::left);
		cout.width(30);cout<<str;
		
		MyStack.erase(MyStack.end()-1,MyStack.end());	
		string Left;
		Left.append(str.begin(),1);//MyNProStr;
		if(!(X[0]>='A'&&X[0]<='Z')&&X[0]!='#')//X是终结符
		{
			if(X[0]==Left[0])
			{
				cout.width(8);
				cout<<Left[0]<<"匹配"<<endl;
				str.erase(str.begin(),str.begin()+1);
			}
			else 
			{
				cout.width(8);
				cout<<Left[0]<<"不匹配,出错"<<endl;
				cout<<MyNProStr<<"识别失败???"<<endl;
				return ;
			}
		}
		else 
		{
			if('#'==X[0])
			{
				if(X[0]==Left[0])
				{
					cout.width(11);
					cout<<"接受"<<endl;
					cout<<MyNProStr<<"识别成功!!!"<<endl;
					return ;
				}
				else 
				{
					cout.width(8);
					cout<<Left[0]<<"不匹配,出错"<<endl;
					cout<<MyNProStr<<"识别失败???"<<endl;
					return ;
				}
			}
			else 
			{
				if(ForecastTable[X[0]-'A'][Left[0]].tag)
				{
					for(int j=ForecastTable[X[0]-'A'][Left[0]].Pro.size()-1;j>=0;j--)
					{
						string tmp;
						tmp.append(ForecastTable[X[0]-'A'][Left[0]].Pro.begin()+j,1);
						MyStack+=tmp;
					}
					cout.width(8);
					cout<<X<<"->";
					if(ForecastTable[X[0]-'A'][Left[0]].Pro.size())
						cout<<ForecastTable[X[0]-'A'][Left[0]].Pro<<endl;
					else cout<<"ε"<<endl;
				}
				else 
				{
					cout.width(8);
					cout<<Left[0]<<"不匹配,出错"<<endl;
					cout<<MyNProStr<<"识别失败???"<<endl;
					return ;
				}
			}
		}
	}
}

/********************************************菜单+读入文件******************************************************/

/***********************************************
*参数:无参数
*功能:读入文法,"END"结尾
***********************************************/
void InPutProduction()
{
	string str;
	int i;
	while(cin>>str)
	{
		if(str=="END")break;
		for(i=0;i<str.size();i++)
		{
			if(str[i]>='A'&&str[i]<='Z')//判断是否为非终结符
			{
				if(!UsedUpLetter[str[i]-'A'])//没被使用,标记为使用过
					UsedUpLetter[str[i]-'A']=1;
			}
		}
		MyProduction[str[0]-'A'].push_back(str);
	}
}

/***********************************************
*参数:无参数
*功能:显示人机互动界面
***********************************************/
void MyMenu()
{
	int choice;
	bool flag=true;
	char FileNameIn[100];
	char FileNameOut[100];
	do
	{
		if(flag)
		{
			cout<<"*********************菜单************************"<<endl;
			cout<<"        1 .A001文法"<<endl;
			cout<<"        2 .A002文法"<<endl;
			cout<<"        3 .A003文法"<<endl;
			cout<<"        4 .A004(我们组所选文法)文法"<<endl;
			cout<<"        5 .A005文法"<<endl;
			cout<<"        6 .A006文法"<<endl;
			cout<<"        7 .课本93页文法"<<endl;
			cout<<"        8 .课本96页例题1文法"<<endl;
			cout<<"        9 .课本99页练习1文法"<<endl;
			cout<<"        10.手动输入自己的文法"<<endl;
			cout<<"        11.退出"<<endl;
			flag=false;
		}
		else cout<<"您的选项错误!请重新选择!"<<endl;
		cout<<"请输入您的选项[  ]\b\b\b";
		cin>>choice;
	}while(!(choice>=1&&choice<=11));
	cout<<"*************************************************"<<endl;
	if(1==choice)
	{
		strcpy(FileNameIn,"A001文法读入文件.txt");
		strcpy(FileNameOut,"A001文法写出文件.txt");
	}
	else if(2==choice)
	{
		strcpy(FileNameIn,"A002文法读入文件.txt");
		strcpy(FileNameOut,"A002文法写出文件.txt");
	}
	else if(3==choice)
	{
		strcpy(FileNameIn,"A003文法读入文件.txt");
		strcpy(FileNameOut,"A003文法写出文件.txt");
	}
	else if(4==choice)
	{
		strcpy(FileNameIn,"A004(我们组所选文法)文法读入文件.txt");
		strcpy(FileNameOut,"A004(我们组所选文法)文法写出文件.txt");
	}
	else if(5==choice)
	{
		strcpy(FileNameIn,"A005文法读入文件.txt");
		strcpy(FileNameOut,"A005文法写出文件.txt");
	}
	else if(6==choice)
	{
		strcpy(FileNameIn,"A006文法读入文件.txt");
		strcpy(FileNameOut,"A006文法写出文件.txt");
	}
	else if(7==choice)
	{
		strcpy(FileNameIn,"课本93页文法读入文件.txt");
		strcpy(FileNameOut,"课本93页文法写出文件.txt");
	}
	else if(8==choice)
	{
		strcpy(FileNameIn,"课本96页例题1文法读入文件.txt");
		strcpy(FileNameOut,"课本96页例题1文法写出文件.txt");
	}
	else if(9==choice)
	{
		strcpy(FileNameIn,"课本99页练习1文法读入文件.txt");
		strcpy(FileNameOut,"课本99页练习1文法写出文件.txt");
	}
	if(11==choice)
	{
		cout<<"接受处理文法,成功退出!"<<endl<<endl;
		exit(0);
	}
	if(choice>=1&&choice<=9)
	{
		freopen(FileNameIn,"r",stdin);
	}
	else if(10==choice)
	{
		cout<<endl<<"请手动输入自己的文法:"<<endl;
	}
	InPutProduction();
	if(10==choice)
		cout<<"输入自己的开始符:";
	cin>>StartChar;
	if(10==choice)
		cout<<"输入自己的待识别句子:";
	cin>>MyNProStr;
	if(10==choice)
		strcpy(FileNameOut,"手动输入自己的文法写出文件.txt");
	freopen(FileNameOut,"w",stdout);//不屏蔽此语句则输出到相应文件
}

/***********************************************
*参数:无参数
*功能:主框架处理函数,完成一系列功能函数调用
***********************************************/
void MyMainAnalyse()
{
	cout<<"下面是我们的原始文法G["<<StartChar<<"]:"<<endl;
	PrintMyProduction();
	
	RemoveAllLeftRecursion();
	
	GetSingleNFirstSet();
	GetPRightFirstSet();
	PrintPRightFirstSet();
	
	GetSingleNFollowSet(StartChar[0]);//注意此处修改的开始文法符号
	PrintMySingleNFollowSet();
	
	GetProductionSelectSet();
	PrintProductionSelectSet();
	
	if(IsLL1())
	{
		GetForecastTable();
		PrintForecastTable();
		Process();
	}
	cout<<"********************************************"<<endl<<endl;
	cout<<"本轮处理完毕!"<<endl<<endl;
}

int main()
{
	init();
	MyMenu();
	MyMainAnalyse();
	return 0;
}


源程序清单见http://download.csdn.net/detail/xj2419174554/6637325

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值