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

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

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

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

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

//定义文法类,保存文法个数和记录所有文法
class Grammar{
public:
    //保存所有文法
    list 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 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::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 Follow[N];
    //保存非终结符
    char nonTerminal[N];
    //保存是否计算出相应的FOLLOW集
    bool flag[N] ={0};
    //保存已计算Follow集的个数
    int calCount ;
    //保存产生式的索引
    vector position[N];

    FOLLOW(){
        calCount =0;
    }
};
//计算FOLLOW集
void calFOLLOWSet(){
    //对于开始符号S,需将"#"加入其FOLLOW集
    follow.Follow[0].insert('#');
while(reloadFOLLOWCalCount()!= grammar.count){
	//扫描每个产生式
        for(int i=0;i::iterator it = follow.position[i].begin();
                for(it ;it!= follow.position[i].end();it++){
                    int m = (*it).x;
                    int n = (*it).y ;
             list::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 firstSet = buildFirstForOne(i,j);
            set::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::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::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 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 &vec):将vector中的字符转化为字符串
  27. string toString(char buf[],int start,int end):将字符数组有选择的转化为字符串
  28. void analyseGrammar():核心函数,对语法进行分析(总控)
  • 代码实现:

#ifndef _grammar_
#define _grammar_

#include 
#include 
#include 
#define N 50

using namespace std;

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

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

    FOLLOW(){
        calCount =0;
    }
};

#endif // _grammar_
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#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 buildFirstForOne(int i,int j);
//将产生式字符转为字符串,i,j为相应产生式的索引
string charToString(int i,int j);
//构建预测分析表
void bulidAnalyseTable();
//打印预测分析表
void printAnalyseTable();
//将vector中的字符转化为字符串
string veToString(vector &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 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::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::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::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::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集如下:"<::iterator it = grammar.grammarTable[i][0].begin();
        for(int j=0;j::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::iterator it = follow.position[i].begin();
//        for(it;it!=follow.position[i].end();it++){
//            cout<<"("<<(*it).x<<","<<(*it).y<<")";
//        }
//        cout<::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::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::iterator it = follow.position[i].begin();
                for(it ;it!= follow.position[i].end();it++){
                    int m = (*it).x;
                    int n = (*it).y ;
                    list::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集如下:"< buildFirstForOne(int i,int j){
    //定义集合
    set temp;
    list::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::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::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::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 firstSet = buildFirstForOne(i,j);
            set::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::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::iterator it = follow.Follow[i].begin();
                for(it;it != follow.Follow[i].end();it++){
                    analyseTable[i][getTerminalIndex(*it)]=(string)"synch";
                }
            }
        }
    }
}
//打印预测分析表
void printAnalyseTable(){
    cout<<"预测分析表如下:"< &vec){
    char buf[N] ={0};
    int index = 0;
    vector::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< analyseStack;
    //把'#'和文法开始符号入栈
    analyseStack.push('#');
    analyseStack.push(grammar.grammarTable[0][0].front());
    vector vec;
    vec.push_back('#');
    vec.push_back(grammar.grammarTable[0][0].front());
    //把第一个字符读入a中
    char a = buf[0];
    //记录步骤
    int step = 0;
    cout<=0;i--){
                    analyseStack.push(temp[i]);
                    vec.push_back(temp[i]);
                }
                step++;
                cout<"+(string)"@"<
  • 运行结果

测试文法为:E->TG

                     G->+TG|@

                     T->FH

                     H->*FH|@

                     F->(E)|i

注:’@’代表空字。

运行结果如下:

LL(1)分析法(C++实现)_第1张图片

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

LL(1)分析法(C++实现)_第2张图片

你可能感兴趣的:(编译原理)