LL(1)分析法(C++实现)

  • LL(1)分析法实验设计思想及算法

本程序只是针对LL(1)文法,对于左递归和含有回溯的文法没有进行处理。本程序主要包括以下功能:

  1. 对输入的文法进行读取,并保存在相应的数据结构中。
  2. 计算每一个非终结符的FIRST集合。
  3. 计算每一个非终结符的FOLLOW集合。
  4. 根据FIRST集和FOLLOW集构建预测分析表。
  5. 根据分析表对输入的字符串进行分析(总控程序)。
  6. 分析过程中能对相应的错误进行处理。
  • 主程序设计基本思路

对于读取的文法存在文法类(grammar)中,具体结构见下:

//定义文法类,保存文法个数和记录所有文法
class Grammar{
public:
    //保存所有文法
    list<char> grammarTable[N][N];
    //保存终结字符
    char terminalChar[N];
    //保存终结字符的个数
    int terNum;
    //保存每行的产生式的个数
    int countEachRow[N];
    //定义文法数量
    int count;
    Grammar(){
        terNum = 0;
    }
};
  • 对于FIRST集的计算要遵守以下规则:

对每一文法符号X∈VT∪VN构造FIRST(X)连续使用下面的规则,直至每个集合FIRST

不再增大为止:

1. 若X∈VT,则FIRST(X)={X}。

2. 若X∈VN,且有产生式X→a…,则把a加入到FIRST(X)中;若X→e也是一条产生式,

则把e也加到FIRST(X)中。

3.若X→Y…是一个产生式且Y∈VN,则把FIRST(Y)中的所有非e-元素都加到FIRST(X)中;

4.若X→Y1Y2…Yk是一个产生式,Y1,…,Yi-1都是非终结符,而且,对于任何j,1≤j≤i-1,FIRST(Yj)都含有e(即Y1…Yi-1e), 则把FIRST(Yi)中的所有非e-元素都加到FIRST(X)中;特别是,若所有的FIRST(Yj)均含有e,j=1,2,…,k,则把e加到FIRST(X)中。

具体实现算法如下:

  • 对每个产生式进行扫描,如果能计算FIRST集则计算并标志已经计算
  • 对于没有计算FIRST的非终结字符,如果能计算FIRST集则计算并标志已经计算。
  • 重复执行步骤②,直至所有的终结符的FIRST集计算完成。

具体代码实现如下:

//保存每个非终结符的FIRST集合
class FIRST{
public:
    //保存每个非终结符的FIRST集合
    set<char> First[N];
    //保存非终结符
    char nonTerminal[N];
    //保存是否计算出相应的FIRST集
    bool flag[N] ={0};
    //保存已计算FIRST集的个数
    int calCount ;

    FIRST(){
        calCount =0;
    }
};
//计算FIRST集
void calFIRSTSet(){
while(reloadCalCount() != grammar.count){
    //扫描每一个产生式
        for(int i=0;i<grammar.count;i++){
            //如果没有计算FIRST集
            if(!first.flag[i]){
                for(int j =0;j<grammar.countEachRow[i];j++){
              list<char>::iterator it = grammar.grammarTable[i][j].begin();
                    //获取产生式的首字符
                    it++;
  //如果it没有到边界并且是非终结字符并且并且已经计算FIRST集并且FIRST含有空字
 while(it != grammar.grammarTable[i][j].end() && isNonTerminal(*it) && 
first.flag[getNonTerminalIndex(*it)] && hasEmpty(getNonTerminalIndex(*it))){

                    first.nonTerminal[i] = grammar.grammarTable[i][0].front();
                        calSetUnion(i,getNonTerminalIndex(*it));
                        it++;
                    }
      //如果it到边界,说明每个非终结符的FIRST集都已经计算出来,并且都含有空字
                    if(it == grammar.grammarTable[i][j].end()){
                        //把空字加入
                        first.First[i].insert('@');
                        first.flag[i] = true;
                        continue;
                    }
                    //否则,it没有到边界
                    else{
                        //如果*it为终结符
                        if(isTerminal(*it)){
                    first.nonTerminal[i] = grammar.grammarTable[i][0].front();
                            first.flag[i] = true;
                            //把终结字符保存到FIRST集
                            first.First[i].insert(*it);
                        }
                        //如果是非终结符
                        else if(isNonTerminal(*it)){
                            //如果已经计算过FIRST集,则把FIrst集加入
                            if(first.flag[getNonTerminalIndex(*it)]){
                     first.nonTerminal[i] = grammar.grammarTable[i][0].front();
                                first.flag[i] = true;
                                calSetUnion(i,getNonTerminalIndex(*it));
                            }
                            //没有计算过
                            else{
                                first.flag[i] = false;
                            }
                        }
                        //如果是空字
                        else{
                     first.nonTerminal[i] = grammar.grammarTable[i][0].front();
                            first.flag[i] = true;
                            //把终结字符保存到FIRST集
                            first.First[i].insert(*it);
                        }
                    }
                }
            }
            //如果计算FIRST集
            else{
                continue;
            }
        }
    }
}
  • 对于FOLLOW集的计算要遵守以下规则:

对于文法G的每个非终结符A构造FOLLOW(A)的办法是,连续使用下面的规则,直至每个FOLLOW不再增大为止:

1. 对于文法的开始符号S,置#于FOLLOW(S)中;

2. 若A→aBb是一个产生式,则把FIRST(b)\{e}加至FOLLOW(B)中;

3. 若A→aB是一个产生式,或A→a是一个产生式,而b *推导出e (e∈FIRST(b)),则把FOLLOW(A)加至FOLLOW(B)中。

具体实现算法如下:

  • 对每个产生式进行扫描,如果能计算FOLLOW集则计算并标志已经计算
  • 对于没有计算FOLLOW的非终结字符,如果能计算FOLLOW集则计算并标志已经计算。
  • 重复执行步骤②,直至所有的终结符的FOLLOW集计算完成。

具体代码实现如下:

//保存每个非终结符的FOLLOW集合
class FOLLOW{
public:
    //保存每个非终结符的FOLLOW集合
    set<char> Follow[N];
    //保存非终结符
    char nonTerminal[N];
    //保存是否计算出相应的FOLLOW集
    bool flag[N] ={0};
    //保存已计算Follow集的个数
    int calCount ;
    //保存产生式的索引
    vector<Position> position[N];

    FOLLOW(){
        calCount =0;
    }
};
//计算FOLLOW集
void calFOLLOWSet(){
    //对于开始符号S,需将"#"加入其FOLLOW集
    follow.Follow[0].insert('#');
while(reloadFOLLOWCalCount()!= grammar.count){
	//扫描每个产生式
        for(int i=0;i<grammar.count;i++){
            //如果没有计算FOLLOW集,则计算
            if(!follow.flag[i]){
                vector<Position>::iterator it = follow.position[i].begin();
                for(it ;it!= follow.position[i].end();it++){
                    int m = (*it).x;
                    int n = (*it).y ;
             list<char>::iterator  itp = grammar.grammarTable[m][n].begin();
                    //使其指向首字符
                    itp++;
                    for(itp;itp!=grammar.grammarTable[m][n].end();itp++){
                if((int)(*itp) == (int)grammar.grammarTable[i][0].front()){
                            itp++;
                            break;
                        }
                    }
              //itp不指向结尾,并且是非终结符并FIRST集含有空字,则继续检测while(itp != grammar.grammarTable[m][n].end() && isNonTerminal(*itp) && hasEmpty(getNonTerminalIndex(*itp))){
                        int index = getNonTerminalIndex(*itp);
                 follow.nonTerminal[i] = grammar.grammarTable[i][0].front();
                        //将非终结符去空字的FIRST集加入FOLLOW集
                        calFollowAndFirstUnion(i,index);
                        itp++;
                    }
         //如果itp没有指向end指针,说明该字符为终结字符或非终结字符或空字
                    if(itp != grammar.grammarTable[m][n].end()){
                        if(isTerminal(*itp)){
                 follow.nonTerminal[i] = grammar.grammarTable[i][0].front();
                            //将非终结字符加入FOLLOW集
                            follow.Follow[i].insert(*itp);
                            //标记已经计算该非终结符的FOLLOW集
                            follow.flag[i] = true;
                        }
                        else if(isNonTerminal(*itp)){
                            int index = getNonTerminalIndex(*itp);
                 follow.nonTerminal[i] = grammar.grammarTable[i][0].front();
                            //将非终结符去空字的FIRST集加入FOLLOW集
                            calFollowAndFirstUnion(i,index);
                            //标记已经计算该非终结符的FOLLOW集
                            follow.flag[i] = true;
                        }
                        //空字什么也不做
                        else{

                        }
                    }
                    //itp指向end指针
                    else{
                        if(!follow.flag[m]){
                            //如果没有计算则标记false
                            follow.flag[i] = false;
                        }
                        else{
                 follow.nonTerminal[i] = grammar.grammarTable[i][0].front();
                            calFollowAndFollowUnion(i,m);
                            //标记已经计算该非终结符的FOLLOW集
                            follow.flag[i] = true;
                        }
                    }
                }
            }
        }
    }
}
  • 对于预测分析表的构造的算法思想:

①对文法G的每个产生式A→a执行第2步和第3步。

② 对每个终结符a∈FIRST(a),把A→a加至M[A,a]。

③​​​​​​​若e∈FIRST(a),则对任何b∈FOLLOW(A)把A→a加至M[A,b]中,若e FIRST(a),则对任何b∈FOLLOW(A)把” synch”加至M[A,b]中,以便出错处理;

具体实现代码如下:

//构建预测分析表
void bulidAnalyseTable(){
    bool flag = false;
    //遍历每个非终结符
    for(int i=0;i<grammar.count;i++){
        //遍历每个非终结字符的产生式
        for(int j=0;j<grammar.countEachRow[i];j++){
            flag = false;
            set<char> firstSet = buildFirstForOne(i,j);
            set<char>::iterator it = firstSet.begin();
            for(it;it != firstSet.end();it++){
                //如果FIRST集存在空字,记上标记
                if(isEmpty(*it)){
                    flag = true;
                }
                //否则将相应的产生式加入预测分析表
                else{
                    //将文法字符转为字符串
                    string str =charToString(i,j);
                    analyseTable[i][getTerminalIndex(*it)] = str;
                }
            }
            //产生式的FIRST集中含有空字
            if(flag){
                //获取i为索引的非终结字符的FOLLOW集
                set<char>::iterator it = follow.Follow[i].begin();
                for(it;it != follow.Follow[i].end();it++){
                    if(isTerminal(*it)){
                        analyseTable[i][getTerminalIndex(*it)] = (string)"@";
                    }
                }
            }
            //产生式的FIRST集中不含有空字
            else{
                //获取i为索引的非终结字符的FOLLOW集
                set<char>::iterator it = follow.Follow[i].begin();
                for(it;it != follow.Follow[i].end();it++){
                    analyseTable[i][getTerminalIndex(*it)]=(string)"synch";
                }
            }
        }
    }
}
  • 总控算法思想:

BEGIN 

    首先把’#’然后把文法开始符号推进STACK栈;

    把第一个输入符号读进a;

    FLAG := TRUE;

    WHILE FLAG DO

       BEGIN

           把STACK栈顶符号上托出去并放在X中;

           IF X∈VT THEN

              IF X =a THEN 把下个输入符号读进a;

              ELSE ERROR

           ELSE IF X = ‘#’ THEN

              IF X = a THEN  FLAG:= FALSE;

              ELSE ERROR;

           ELSE IF M[A,a] ={X->X1X2…XK} THEN

              把XK,XK-1,…,X1一一推进STACK栈

              /* 若X1X2…XK = e */

           ELSE ERROR;

       END OF WHILE

    STOP

END

由于篇幅有限代码不在贴出。

  • 错误处理

分析时,若发现M[A,a]为空则跳过输入符号a;若该项为“synch”,则弹出栈顶非终结符(开始符号除外);若栈顶的终结符号不匹配输入符号,则弹出栈顶的终结符。

  • 具体函数逻辑:

  1. bool isNonTerminal(char var):检测一个字符是否为非终结字符
  2. bool isEmpty(char var):检测一个字符是否为空字
  3. bool isTerminal(char var):检测一个字符是否为终结字符
  4. void readGrammar():从控制台读取文法并保存
  5. bool canCalFIRST(int i):判断一个产生式是否能求出FIRST集,能返回true,否则false
  6. void calFIRST():计算能够计算FIRST集的产生式
  7. int getNonTerminalIndex(char var):获取其非终结字符所在的索引
  8. bool hasEmpty(int i):检测第i个FIRST集是否有空字
  9. bool adjustFIRST(int i):判断是否能计算FIRST集(首字符含非终结符)
  10. void calSetUnion(int i,int j):计算两个集合的并集,即set(i) = set(i) ∪ set(j)
  11. int reloadCalCount():更新calCount
  12. void calFIRSTSet():计算FIRST集
  13. void printFIRST():输出first集
  14. void getPosition():获取索引(每一个非终结符在产生式的索引,索引保存在容器中)
  15. void calFollowAndFirstUnion(int i,int j):将FIRST集去空加入FOLLOW集,i代表FOLLOW,i代表FIRST集
  16. void calFollowAndFollowUnion(int i,int j):计算两个FOLLOW集的并集,即set(i) = set(i) ∪ set(j)
  17. int reloadFOLLOWCalCount():更新FOLLOW集的calCount
  18. void calFOLLOWSet():计算FOLLOW集
  19. void getFollowSet():获取每一个非终结符的FOLLOW集
  20. void printFOLLOW():打印FOLLOW集
  21. int getTerminalIndex(char var):获取终结符在Grammar.terminal[]中的索引
  22. set<char> buildFirstForOne(int i,int j):构建单个产生式的First集,i,j为相应产生式的索引
  23. string charToString(int i,int j):将产生式字符转为字符串,i,j为相应产生式的索引
  24. void bulidAnalyseTable():构建预测分析表
  25. void printAnalyseTable():打印预测分析表
  26. string veToString(vector<char> &vec):将vector中的字符转化为字符串
  27. string toString(char buf[],int start,int end):将字符数组有选择的转化为字符串
  28. void analyseGrammar():核心函数,对语法进行分析(总控)
  • 代码实现:

#ifndef _grammar_
#define _grammar_

#include <list>
#include <set>
#include <vector>
#define N 50

using namespace std;

//定义文法类,保存文法个数和记录所有文法
class Grammar{
public:
    //保存所有文法
    list<char> grammarTable[N][N];
    //保存终结字符
    char terminalChar[N];
    //保存终结字符的个数
    int terNum;
    //保存每行的产生式的个数
    int countEachRow[N];
    //定义文法数量
    int count;

    Grammar(){
        terNum = 0;
    }
};
//保存每个非终结符的FIRST集合
class FIRST{
public:
    //保存每个非终结符的FIRST集合
    set<char> First[N];
    //保存非终结符
    char nonTerminal[N];
    //保存是否计算出相应的FIRST集
    bool flag[N] ={0};
    //保存已计算FIRST集的个数
    int calCount ;

    FIRST(){
        calCount =0;
    }

};
class Position{
public:
    int x;
    int y;
    Position(){
        x=-1;
        y=-1;
    }
};
//保存每个非终结符的FOLLOW集合
class FOLLOW{
public:
    //保存每个非终结符的FOLLOW集合
    set<char> Follow[N];
    //保存非终结符
    char nonTerminal[N];
    //保存是否计算出相应的FOLLOW集
    bool flag[N] ={0};
    //保存已计算Follow集的个数
    int calCount ;
    //保存产生式的索引
    vector<Position> position[N];

    FOLLOW(){
        calCount =0;
    }
};

#endif // _grammar_
#include <iostream>
#include <Cstring>
#include <algorithm>
#include <string>
#include <set>
#include <iomanip>
#include <stack>
#include "grammar.h"

using namespace std;

//定义一个文法类对象
Grammar grammar;
//定义FIRST集
FIRST first;
//定义·FOLLOW集
FOLLOW follow;
//定义预测分析表
string analyseTable[N][N] ;
//检测一个字符是否为非终结字符
bool isNonTerminal(char var);
//检测一个字符是否为空字
bool isEmpty(char var);
//检测一个字符是否为终结字符
bool isTerminal(char var);
//从控制台读取文法并保存
void readGrammar();
//判断一个产生式是否能求出FIRST集,能返回true,否则false
bool canCalFIRST(int i);
//计算能够计算FIRST集的产生式
void calFIRST();
//获取其非终结字符所在的索引
int getNonTerminalIndex(char var);
//检测第i个FIRST集是否有空字
bool hasEmpty(int i);
//判断是否能计算FIRST集(首字符含非终结符)
bool adjustFIRST(int i);
//计算两个集合的并集,即set(i) = set(i) ∪ set(j)
void calSetUnion(int i,int j);
//更新calCount
int reloadCalCount();
//计算FIRST集
void calFIRSTSet();
//输出first集
void printFIRST();
//获取索引(每一个非终结符在产生式的索引,索引保存在容器中)
void getPosition();
//将FIRST集去空加入FOLLOW集,i代表FOLLOW,i代表FIRST集
void calFollowAndFirstUnion(int i,int j);
//计算两个FOLLOW集的并集,即set(i) = set(i) ∪ set(j)
void calFollowAndFollowUnion(int i,int j);
//更新FOLLOW集的calCount
int reloadFOLLOWCalCount();
//计算FOLLOW集
void calFOLLOWSet();
//获取每一个非终结符的FOLLOW集
void getFollowSet();
//打印FOLLOW集
void printFOLLOW();
//获取终结符在Grammar.terminal[]中的索引
int getTerminalIndex(char var);
//构建单个产生式的First集,i,j为相应产生式的索引
set<char> buildFirstForOne(int i,int j);
//将产生式字符转为字符串,i,j为相应产生式的索引
string charToString(int i,int j);
//构建预测分析表
void bulidAnalyseTable();
//打印预测分析表
void printAnalyseTable();
//将vector中的字符转化为字符串
string veToString(vector<char> &vec);
//将字符数组有选择的转化为字符串
string toString(char buf[],int start,int end);
//核心函数,对语法进行分析
void analyseGrammar();


/*
E->TG
G->+TG|@
T->FH
H->*FH|@
F->(E)|i
*/
/*
E->TG
G->+TG|-TG|@
T->FSj
S->*FS|/FS|@
F->(E)|i|@
*/
int main()
{
    readGrammar();
    calFIRSTSet();
    printFIRST();

    getFollowSet();
    printFOLLOW();
    bulidAnalyseTable();
    printAnalyseTable();
    analyseGrammar();
    return 0;
}
//从控制台读取文法并保存
void readGrammar(){
    //保存输入的第i行文法
    string str;
    //把第i行文法转换为字符数组
    char buf[100] ={0};
    int i=0;
    int index = 0;
    int count=0;
    //临时保存非终结字符
    set<char> ter;
    cout << "请输入文法(单行输入#回车结束,空字用@代替):" << endl;
    cin>>str;
    strcpy(buf,str.c_str());
    while(str != "#"){
        i=0;
        count = 0;
        grammar.grammarTable[index][count].push_back(buf[i]);
        //略去"->"
        i+=3;
        //检测是否到边界
        while((int)buf[i] != 0){
            //如果检测到"|"
            if((int)buf[i] == 124){
                count++;
                i++;
                //保存起始字符
                grammar.grammarTable[index][count].push_back(buf[0]);
                //保存产生式的每个字符
                grammar.grammarTable[index][count].push_back(buf[i]);
                //如果是终结字符则保存
                if(isTerminal(buf[i])){
                    ter.insert(buf[i]);
                }
                i++;
            }
            else{
                //保存产生式的每个字符
                grammar.grammarTable[index][count].push_back(buf[i]);
                //如果是终结字符则保存
                if(isTerminal(buf[i])){
                    ter.insert(buf[i]);
                }
                i++;
            }
        }
        grammar.countEachRow[index] = count+1;
        index++;
        cin>>str;
        strcpy(buf,str.c_str());
    }
    //保留文法个数
    grammar.count = index ;
    //保存终结字符
    set<char>::iterator it = ter.begin();
    for(it;it != ter.end();it++){
        grammar.terminalChar[grammar.terNum] = *it;
        grammar.terNum++;
    }
    //注意需要把特殊符号"#",加入
    grammar.terminalChar[grammar.terNum] = '#';
    grammar.terNum++;
}
//检测一个字符是否为终结字符,注意空字@也不算终结字符
bool isTerminal(char var){
    if((!isNonTerminal(var))&&(!isEmpty(var))){
        return true;
    }
    else{
        return false;
    }
}
//检测一个字符是否为非终结字符
bool isNonTerminal(char var){
    if(((int)var > 64)&&((int)var < 91)){
        return true;
    }
    else{
        return false;
    }
}
//检测一个字符是否为空字
bool isEmpty(char var){
    if((int)var == 64){
        return true;
    }
    else{
        return false;
    }
}
//获取其非终结字符所在的索引
int getNonTerminalIndex(char var){
    int index=0;
    //获取其终结字符所在的索引
    for(index;index<grammar.count;index++){
        if((int) var == (int) grammar.grammarTable[index][0].front()){
            break;
        }
    }
    return index;

}
//检测第i个FIRST集是否有空字
bool hasEmpty(int i){
    set<char>::iterator it = first.First[i].begin();
    for(it;it!=first.First[i].end();it++){
        if((int) *it == 64){
            return true;
        }
    }
    return false;
}
//计算两个集合的并集,即set(i) = set(i) ∪ set(j),其中set(j)中去除空字
void calSetUnion(int i,int j){
    set<char>::iterator it = first.First[j].begin();
    //如果有空字,则去空字
    if(hasEmpty(j)){
        for(it;it!=first.First[j].end();it++){
            if(!isEmpty(*it)){
                first.First[i].insert(*it);
            }
        }
    }
    else{
        for(it;it!=first.First[j].end();it++){
            first.First[i].insert(*it);
        }
    }
}
//更新calCount
int reloadCalCount(){
    int count =0;
    for(int i=0;i<grammar.count;i++){
        if(first.flag[i] == true){
            count++;
        }
    }
    first.calCount = count;
    return count;
}
//计算FIRST集
void calFIRSTSet(){
    while(reloadCalCount() != grammar.count){
        //扫描每一个产生式
        for(int i=0;i<grammar.count;i++){
            //如果没有计算FIRST集
            if(!first.flag[i]){
                for(int j =0;j<grammar.countEachRow[i];j++){
                    list<char>::iterator it = grammar.grammarTable[i][j].begin();
                    //获取产生式的首字符
                    it++;
                    //如果it没有到边界并且是非终结字符并且并且已经计算FIRST集并且FIRST含有空字
                    while(it != grammar.grammarTable[i][j].end() && isNonTerminal(*it) && first.flag[getNonTerminalIndex(*it)] && hasEmpty(getNonTerminalIndex(*it))){
                        first.nonTerminal[i] = grammar.grammarTable[i][0].front();
                       // first.flag[i] = true;
                        calSetUnion(i,getNonTerminalIndex(*it));
                        it++;
                    }
                    //如果it到边界,说明每个非终结符的FIRST集都已经计算出来,并且都含有空字
                    if(it == grammar.grammarTable[i][j].end()){
                        //把空字加入
                        first.First[i].insert('@');
                        first.flag[i] = true;
                        continue;
                    }
                    //否则,it没有到边界
                    else{
                        //如果*it为终结符
                        if(isTerminal(*it)){
                            first.nonTerminal[i] = grammar.grammarTable[i][0].front();
                            first.flag[i] = true;
                            //把终结字符保存到FIRST集
                            first.First[i].insert(*it);
                        }
                        //如果是非终结符
                        else if(isNonTerminal(*it)){
                            //如果已经计算过FIRST集,则把FIrst集加入
                            if(first.flag[getNonTerminalIndex(*it)]){
                                first.nonTerminal[i] = grammar.grammarTable[i][0].front();
                                first.flag[i] = true;
                                calSetUnion(i,getNonTerminalIndex(*it));
                            }
                            //没有计算过
                            else{
                                first.flag[i] = false;
                            }
                        }
                        //如果是空字
                        else{
                            first.nonTerminal[i] = grammar.grammarTable[i][0].front();
                            first.flag[i] = true;
                            //把终结字符保存到FIRST集
                            first.First[i].insert(*it);
                        }
                    }
                }
            }
            //如果计算FIRST集
            else{
                continue;
            }
        }
    }
}
//输出first集
void printFIRST(){
    cout<<"FIRST集如下:"<<endl;
    for(int i=0;i<grammar.count;i++){
        cout<<"FIRST"<<"("<<first.nonTerminal[i]<<")"<<"=";
        set<char>::iterator it;
        for(it = first.First[i].begin();it!=first.First[i].end();it++){
            cout<<*it<<" ";
        }
        cout<<endl;
    }
    cout<<endl;
}
//获取索引(每一个非终结符在产生式的索引,索引保存在容器中)
void getPosition(){
    for(int i=0;i<grammar.count;i++){
        list<char>::iterator it = grammar.grammarTable[i][0].begin();
        for(int j=0;j<grammar.count;j++){
            for(int k=0;k<grammar.countEachRow[j];k++){
                list<char>::iterator itp = grammar.grammarTable[j][k].begin();
                itp++;
                for(itp;itp!=grammar.grammarTable[j][k].end();itp++){
                    if((int)*it == (int) *itp){
                        Position pos;
                        pos.x = j;
                        pos.y = k;
                        //记下其位置
                        follow.position[i].push_back(pos);
                    }
                }
            }
        }
    }
    //test
//    for(int i=0;i<grammar.count;i++){
//        vector<Position>::iterator it = follow.position[i].begin();
//        for(it;it!=follow.position[i].end();it++){
//            cout<<"("<<(*it).x<<","<<(*it).y<<")";
//        }
//        cout<<endl;
//    }
}
//将FIRST集去空加入FOLLOW集,i代表FOLLOW,i代表FIRST集
void calFollowAndFirstUnion(int i,int j){
    set<char>::iterator it = first.First[j].begin();
    //如果有空字,则去空字
    if(hasEmpty(j)){
        for(it;it!=first.First[j].end();it++){
            if(!isEmpty(*it)){
                follow.Follow[i].insert(*it);
            }
        }
    }
    else{
        for(it;it!=first.First[j].end();it++){
            follow.Follow[i].insert(*it);
        }
    }
}
//更新FOLLOW集的calCount
int reloadFOLLOWCalCount(){
    int count =0;
    for(int i=0;i<grammar.count;i++){
        if(follow.flag[i] == true){
            count++;
        }
    }
    follow.calCount = count;
    return count;
}
//计算两个FOLLOW集的并集,即set(i) = set(i) ∪ set(j)
void calFollowAndFollowUnion(int i,int j){
    set<char>::iterator it = follow.Follow[j].begin();
    for(it;it!=follow.Follow[j].end();it++){
        follow.Follow[i].insert(*it);
    }
}
//计算FOLLOW集
void calFOLLOWSet(){
    //对于开始符号S,需将"#"加入其FOLLOW集
    follow.Follow[0].insert('#');
    while(reloadFOLLOWCalCount()!= grammar.count){
        for(int i=0;i<grammar.count;i++){
            //如果没有计算FOLLOW集,则计算
            if(!follow.flag[i]){
                vector<Position>::iterator it = follow.position[i].begin();
                for(it ;it!= follow.position[i].end();it++){
                    int m = (*it).x;
                    int n = (*it).y ;
                    list<char>::iterator  itp = grammar.grammarTable[m][n].begin();
                    //使其指向首字符
                    itp++;
                    for(itp;itp!=grammar.grammarTable[m][n].end();itp++){
                        if((int)(*itp) == (int)grammar.grammarTable[i][0].front()){
                            itp++;
                            break;
                        }
                    }
                    //itp不指向结尾,并且是非终结符并FIRST集含有空字,则继续检测
                    while(itp != grammar.grammarTable[m][n].end() && isNonTerminal(*itp) && hasEmpty(getNonTerminalIndex(*itp))){
                        int index = getNonTerminalIndex(*itp);
                        follow.nonTerminal[i] = grammar.grammarTable[i][0].front();
                        //将非终结符去空字的FIRST集加入FOLLOW集
                        calFollowAndFirstUnion(i,index);
                        itp++;
                    }
                    //如果itp没有指向end指针,说明该字符为终结字符或非终结字符或空字
                    if(itp != grammar.grammarTable[m][n].end()){
                        if(isTerminal(*itp)){
                            follow.nonTerminal[i] = grammar.grammarTable[i][0].front();
                            //将非终结字符加入FOLLOW集
                            follow.Follow[i].insert(*itp);
                            //标记已经计算该非终结符的FOLLOW集
                            follow.flag[i] = true;
                        }
                        else if(isNonTerminal(*itp)){
                            int index = getNonTerminalIndex(*itp);
                            follow.nonTerminal[i] = grammar.grammarTable[i][0].front();
                            //将非终结符去空字的FIRST集加入FOLLOW集
                            calFollowAndFirstUnion(i,index);
                            //标记已经计算该非终结符的FOLLOW集
                            follow.flag[i] = true;
                        }
                        //空字什么也不做
                        else{

                        }
                    }
                    //itp指向end指针
                    else{
                        if(!follow.flag[m]){
                            //如果没有计算则标记false
                            follow.flag[i] = false;
                        }
                        else{
                            follow.nonTerminal[i] = grammar.grammarTable[i][0].front();
                            calFollowAndFollowUnion(i,m);
                            //标记已经计算该非终结符的FOLLOW集
                            follow.flag[i] = true;
                        }
                    }
                }
            }
        }
    }
}
//获取每一个非终结符的FOLLOW集
void getFollowSet(){
    getPosition();
    calFOLLOWSet();
}
//打印FOLLOW集
void printFOLLOW(){
    cout<<"FOLLOW集如下:"<<endl;
    for(int i=0;i<grammar.count;i++){
        cout<<"FOLLOW"<<"("<<follow.nonTerminal[i]<<")"<<"=";
        set<char>::iterator it;
        for(it = follow.Follow[i].begin();it!=follow.Follow[i].end();it++){
            cout<<*it<<" ";
        }
        cout<<endl;
    }
    cout<<endl;
}
//获取终结符在Grammar.terminal[]中的索引
int getTerminalIndex(char var)
{
    for(int i=0;i<grammar.terNum;i++){
        if((int)grammar.terminalChar[i] == (int) var){
            return i;
        }
    }
    //不存在返回-1
    return -1;
}
//构建单个产生式的First集,i,j为相应产生式的索引
set<char> buildFirstForOne(int i,int j){
    //定义集合
    set<char> temp;
    list<char>::iterator it = grammar.grammarTable[i][j].begin();
    it++;
    for(it;it != grammar.grammarTable[i][j].end();it++){
        //如果没有出界,并且是非终结字符,并且FIRST集含有空字
        while(it != grammar.grammarTable[i][j].end() && isNonTerminal(*it) && hasEmpty(getNonTerminalIndex(*it))){
            int index = getNonTerminalIndex(*it);
            set<char>::iterator itp = first.First[index].begin();
            for(itp;itp!=first.First[index].end();itp++){
                //如果不是空字则添加temp集合
                if(!isEmpty(*itp)){
                    temp.insert(*itp);
                }
            }
            it++;
        }
        //没有出界
        if(it != grammar.grammarTable[i][j].end()){
             //如果是终结字符或空字,则把终结字符填到FIRST集
            if(isTerminal(*it) || isEmpty(*it)){
                temp.insert(*it);
                return temp;
            }
            //否则为非终结符
            else {
                int index = getNonTerminalIndex(*it);
                set<char>::iterator itpt = first.First[index].begin();
                for(itpt;itpt!=first.First[index].end();itpt++){
                    temp.insert(*itpt);
                }
                return temp;
            }
        }
         //如果出界,则退出
        else{
            //说明都是非终结字符,且都含有空字
            temp.insert('@');
            return temp;
        }
    }
}
//将产生式字符转为字符串,i,j为相应产生式的索引
string charToString(int i,int j){
    char buf[100] ={0};
    int count = 0;
    list<char>::iterator it = grammar.grammarTable[i][j].begin();
    it++;
    for(it;it!=grammar.grammarTable[i][j].end();it++){
        buf[count] =*it;
        count++;
    }
    buf[count] = '\0';
    string str(buf);
    return str;
}
//构建预测分析表
void bulidAnalyseTable(){
    bool flag = false;
    //遍历每个非终结符
    for(int i=0;i<grammar.count;i++){
        //遍历每个非终结字符的产生式
        for(int j=0;j<grammar.countEachRow[i];j++){
            flag = false;
            set<char> firstSet = buildFirstForOne(i,j);
            set<char>::iterator it = firstSet.begin();
            for(it;it != firstSet.end();it++){
                //如果FIRST集存在空字,记上标记
                if(isEmpty(*it)){
                    flag = true;
                }
                //否则将相应的产生式加入预测分析表
                else{
                    //将文法字符转为字符串
                    string str =charToString(i,j);
                    analyseTable[i][getTerminalIndex(*it)] = str;
                }
            }
            //产生式的FIRST集中含有空字
            if(flag){
                //获取i为索引的非终结字符的FOLLOW集
                set<char>::iterator it = follow.Follow[i].begin();
                for(it;it != follow.Follow[i].end();it++){
                    if(isTerminal(*it)){
                        analyseTable[i][getTerminalIndex(*it)] = (string)"@";
                    }
                }
            }
            //产生式的FIRST集中不含有空字
            else{
                //获取i为索引的非终结字符的FOLLOW集
                set<char>::iterator it = follow.Follow[i].begin();
                for(it;it != follow.Follow[i].end();it++){
                    analyseTable[i][getTerminalIndex(*it)]=(string)"synch";
                }
            }
        }
    }
}
//打印预测分析表
void printAnalyseTable(){
    cout<<"预测分析表如下:"<<endl;
    //占位符
    cout<<setw(10)<<" ";
    //循环输出每位终结符
    for(int i =0;i<grammar.terNum;i++){
        cout<<setw(10)<<grammar.terminalChar[i];
    }
    cout<<endl;
    //输出每行
    for(int i=0;i<grammar.count;i++){
        //输出非终结字符
        cout<<setw(10)<<grammar.grammarTable[i][0].front();
        //输出相应的产生式
        for(int j =0;j<grammar.terNum;j++){
            cout<<setw(10)<<analyseTable[i][j];
        }
        cout<<endl;
    }
    cout<<endl;
}
//将vector中的字符转化为字符串
string veToString(vector<char> &vec){
    char buf[N] ={0};
    int index = 0;
    vector<char>::iterator it = vec.begin();
    for(it;it!=vec.end();it++){
        buf[index] = *it;
        index++;
    }
    buf[index] ='\0';
    string str(buf);
    return str;
}
//将字符数组有选择的转化为字符串
string toString(char buf[],int start,int end){
    char temp[N];
    int index = 0;
    for(start;start <= end;start++){
        temp[index] = buf[start];
        index++;
    }
    temp[index] = '\0';
    string str(temp);
    return str;
}
//核心函数,对语法进行分析
void analyseGrammar(){
    cout<<"请输入待分析的字符串:";
    string str;
    cin>>str;
    //将输入的字符串转化为字符数组
    char buf[N] ={0};
    strcpy(buf,str.c_str());
    //计算字符的数目
    int count =0;
    for(int i=0;buf[i]!=0;i++){
        count++;
    }
    buf[count++] = '#';
    cout<<setw(15)<<"步骤"<<setw(15)<<"符号栈"<<setw(15)<<"输入串"<<setw(15)<<"所用产生式"<<setw(15)<<"动作"<<setw(15)<<"附注"<<endl;
    //定义一个分析栈
    stack<char> analyseStack;
    //把'#'和文法开始符号入栈
    analyseStack.push('#');
    analyseStack.push(grammar.grammarTable[0][0].front());
    vector<char> vec;
    vec.push_back('#');
    vec.push_back(grammar.grammarTable[0][0].front());
    //把第一个字符读入a中
    char a = buf[0];
    //记录步骤
    int step = 0;
    cout<<setw(15)<<step<<setw(15)<<veToString(vec)<<setw(15)<<toString(buf,0,count-1)<<setw(15)<<" "<<setw(15)<<"初始化"<<setw(15)<<" "<<endl;
    //buf[]的索引
    int index = 0;
    bool flag = true;
    while(flag){
        char ch;
        if(!analyseStack.empty()){
            ch = analyseStack.top();
            analyseStack.pop();
            vec.pop_back();
        }
        if(isTerminal(ch) && ch != '#'){
            if(ch == a){

                index++;
                a = buf[index];
                step++;
                cout<<setw(15)<<step<<setw(15)<<veToString(vec)<<setw(15)<<toString(buf,index,count-1)<<setw(15)<<" "<<setw(15)<<(string)"GETNEXT("+ch+(string)")"<<setw(15)<<" "<<endl;

            }
            else{
                //出错
                step++;
                cout<<setw(15)<<step<<setw(15)<<veToString(vec)<<setw(15)<<toString(buf,index,count-1)<<setw(15)<<" "<<setw(15)<<(string)"pop"<<setw(15)<<"错误,栈顶终结符与输入符号不匹配 "<<endl;
            }
        }
        else if(ch =='#'){
            if(ch == a){
                flag = false;
            }
            else{
                //出错
                cout<<"出错";
                return;
            }
        }
        else if(isNonTerminal(ch)){
            string str = analyseTable[getNonTerminalIndex(ch)][getTerminalIndex(a)];
            //如果产生式不为空,且不为空字
            if(str != "@" && !str.empty()&& str != "synch"){

                int strSize = str.size();
                char temp[N];
                strcpy(temp,str.c_str());
                for(int i= strSize-1;i>=0;i--){
                    analyseStack.push(temp[i]);
                    vec.push_back(temp[i]);
                }
                step++;
                cout<<setw(15)<<step<<setw(15)<<veToString(vec)<<setw(15)<<toString(buf,index,count-1)<<setw(15)<<str<<setw(15)<<(string)"pop,push("+str+(string)")"<<setw(15)<<" "<<endl;
            }
            //如果[M,a]为空,则跳过输入符号a
            else if(str.empty()){
                //出错
                index++;
                a = buf[index];
                step++;
                cout<<setw(15)<<step<<setw(15)<<veToString(vec)<<setw(15)<<toString(buf,index,count-1)<<setw(15)<<" "<<setw(15)<<" "<<setw(15)<<"错,跳过"<<endl;
            }
            else if(str == "synch"){
                //如果栈顶为文法开始符号,跳过输入符号
                if(ch == grammar.grammarTable[0][0].front()){
                    index++;
                    a = buf[index];
                    //文法开始符号入栈
                    analyseStack.push(ch);
                    vec.push_back(ch);
                    step++;
                    cout<<setw(15)<<step<<setw(15)<<veToString(vec)<<setw(15)<<toString(buf,index,count-1)<<setw(15)<<" "<<setw(15)<<" "<<setw(15)<<"错,跳过"<<endl;
                }
                else{
                    step++;
                    cout<<setw(15)<<step<<setw(15)<<veToString(vec)<<setw(15)<<toString(buf,index,count-1)<<setw(15)<<" "<<setw(15)<<" "<<setw(15)<<(string)"错,M["+ch+(string)","+a+(string)"]=synch"+","+ch+(string)"已弹出栈"<<endl;
                }
            }
            //若为空字,什么也不做
            else{
                step++;
                cout<<setw(15)<<step<<setw(15)<<veToString(vec)<<setw(15)<<toString(buf,index,count-1)<<setw(15)<<ch+(string)"->"+(string)"@"<<setw(15)<<" "<<setw(15)<<""<<endl;
            }
        }
        else{
            //出错
            cout<<"出错";
            return;
        }
    }
}
  • 运行结果

测试文法为:E->TG

                     G->+TG|@

                     T->FH

                     H->*FH|@

                     F->(E)|i

注:’@’代表空字。

运行结果如下:

对不正确的输入串处理的截图如下:

发布了46 篇原创文章 · 获赞 48 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qq_39559641/article/details/84068321
今日推荐