原创作品,出自 “晓风残月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码表示的所有字符。
对于空串‘ε’,由于8位ASCII直接表示,输入时自动缺省(符合本身含义),如文法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)将非终结符合理排序:A1,A2,...,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