c++簡單實現SLR1文法分析器(自動求項目集、建表、分析)

 

 

 

 

 

 

 

 

 

  1. 規定終結符用小寫字母開頭和後面接若干“`”表示例如a,b,i,i`,i``表示不同的終結符。非終結符用大寫字母和後面接若干“`”表示非終結符例如A,B,T`,T``表示不同的非終結符。用“&”代表空串。連續輸入的“-”“>”代表推導,分割產生式左右部。輸入的文法的第一個產生式爲文法開始符的產生式。
  2. 設置變量SIZE,代表非終結符的最大的數量。對終結符和非終結符進行編號,規定數值0爲空串(&)。用1~SIZE的正整數對終結符和非終結符分別進行編號。爲了在候選式中不發生衝突,候選式的終結符使用終結符的相反數。例如:編號A:1, B:2, a:1, b:2 。則二維數組{{1,2},{-1,2},{0} } 代表候選式 AB | aB | & 。FIRST和FOLLOW集合存儲的是非終結符的編號和終結符的編號的相反數。
  3. 將候選式分開存儲進pro結構體中,屬性Vn表示產生式左部,candy數組表示產生式右部。都是存儲符號的編號。每個pro的下標代表產生式的編號。項目集結構體中屬性pro集合代表一對序偶一個代表產生式的編號,一個表示‘.’號的位置。集合v代表項目集的邊。go集合也是一對序偶,第一個數表示邊代表的字符編號,第二個數代表指向的項目集。

 

 

#include <bits/stdc++.h>


using namespace std;

#include "definition.h"
#include "Check.h"
#include "Init.h"
#include "getFirst.h"
#include "getFollow.h"
#include "Display.h"
#include "getI.h"
#include "getTable.h"
#include "analyse.h"

int main()
{

    ifstream file;
    file.open("test/input3.txt");
    string str;
    while(getline(file, str)){  //輸入一行,即一個非終結符的候選式
        cout<<str<<endl;
        init(str);  //初始化,將終結符和非終結符等進行編號等
    }

    getFIRST(); //獲取FIRST集
    getFollow();    //獲取FOLLOW集

    dispalyFirst(); //輸出FIRST集
    dispalyFollow();    //輸出FOLLOW集

    //displayPro2();
    displayPro();   //輸出產生式

    getI(); //獲取項目集(I)

    getActionGotoTable();   //獲取Action和GOTO表

    ifstream in;
    in.open("test/inputa3.txt");    //輸入串
    string inStr;
    while(getline(in,inStr)){
        getAns(inStr);
    }

    return 0;
}

 

#ifndef DEFINITION_H_INCLUDED
#define DEFINITION_H_INCLUDED

#define SIZE 100

int idVt = 0;   //終結符編號
int idVn = 1;   //非終結符編號,0號爲擴展文法開始符
int idPro = 1;   //產生式編號,0號爲擴展文法開始符

int JING;   //# 號
int EMPTY = 5*SIZE;  //空串
int startVt = -1;   //判斷是否處理了開始符,只處理一次
int ERROR = 4*SIZE; //出錯標誌
int ACC = 5*SIZE;   //成功標誌

map<string,int>mpVn,mpVt;   //編號(字符,編號)
map<int,string>rmpVn,rmpVt; //雙向映射(編號,字符)

//存儲分開編號的產生式,下標爲編號
struct Pro {
    int Vn; //產生式左部 1 <=> A
    vector<int>candy;   //產生式右部{1,2,-1} 代表 A -> ABa
    Pro(){
        Vn =0 ;
        candy.clear();
    }
}pro[SIZE];

//項目集I
struct Ix{
    set<pair<int,int> >pro;  //記錄項目集擁有的產生式編號以及對應的‘.’ 號的位置  {idPro,dot} 例如: {  {0,0} , {1,1}   }  <=> { S`->.XX, E -> X.XX  }
    set<int>v;  //記錄項目集的邊的符號的編號如:a編號1。GOTO(a,I)、GOTO(b,I) 的a, b
    set<pair<int,int> >go;  //(idVt/idVn, numI)    對應的邊以及其GOTO到的項目集
    void Clear(){
        pro.clear();
        v.clear();
        go.clear();
    }
}I[SIZE];

//每個非終結符對應一個結構體
struct NoTml
{
    vector<vector<int> > pro;   //候選式:例如 {{1,2},{-1,2},{0} } => AB | aB | &
    set<int> FIRST, FOLLOW; //FIRST集,FOLLOW集
    int proNum; //處理FIRST集時使用,判斷以及完成的候選式
    bool FirstFinish;   //處理FIRST集時使用,判斷是否全部候選式都完成
    NoTml(){
        FirstFinish = false;
        int proNum = 0 ;
        FIRST.clear();
        FOLLOW.clear();
        pro.clear();
    }
}notml[SIZE];   //每個下標對應一個非終結符


#endif // DEFINITION_H_INCLUDED
#ifndef INIT_H_INCLUDED
#define INIT_H_INCLUDED

void init(string str){
    int len = str.length();
    int pos = 0;
    int idLeft = 0;
    string word="";
    vector<int>vec;

    //獲取產生式左部
    while(pos<len){
        if(str[pos]==' '){  //過濾空格
            pos++;
        }
        else if(str[pos]>='A'&&str[pos]<='Z'){ //判斷是否爲大寫字母開始,即是否爲非終結符
            word="";
            word+=str[pos];
            pos++;
            while(pos<len&&str[pos]=='`') word+=str[pos],pos++;
            if(mpVn.count(word)==0){
                mpVn[word]=idVn++;  //雙向映射(編號,字符),(字符,編號)
                rmpVn[idVn-1]=word;
            }
        }
        else if(str[pos]=='-'&&str[pos+1]=='>') {
            idLeft = mpVn[word];
            pos+=2;
            break;
        }
        else {
            errorG();   //文法輸入錯誤
            return ;
        }
    }

    //擴展文法開始符
    if(startVt == -1){
        rmpVt[EMPTY]="&"; //& 代表空串
        mpVt["&"] = EMPTY;

        JING = idVt++;    //對 # 號進行編號
        rmpVt[JING]="#";
        mpVt["#"] = JING;

        ERROR = SIZE+1;

        startVt = idLeft;
        mpVn["S`"] = 0;
        rmpVn[0] = "S`";
        pro[0].candy.push_back(idLeft);
        pro[0].Vn = 0;

        notml[0].pro.push_back({idLeft});


    }

    //獲取產生式右部
    while(pos<len){
        if(str[pos]==' '){
            pos++;
        }
        else if(str[pos]=='&'){ //空串
            vec.push_back(EMPTY);
            pos++;
        }
        else if(str[pos]=='|'){ //得到了一個候選式,
            if(!vec.empty()) {
                pro[idPro].candy.assign(vec.begin(),vec.end());
                pro[idPro++].Vn=idLeft;

                notml[idLeft].pro.push_back(vec);

            }
            vec.clear();
            pos++;
        }
        else if(str[pos]>='A'&&str[pos]<='Z') {    //對非終結符編號
            word="";
            word+=str[pos];
            pos++;
            while(pos<len&&str[pos]=='`') word+=str[pos],pos++;
            if(mpVn.count(word)==0){
                mpVn[word]=idVn++;
                rmpVn[idVn-1]=word;
            }
            vec.push_back(mpVn[word]);
        }
        else if(!(str[pos]>='A'&&str[pos]<='Z')){    //對終結符編號
            word="";
            word+=str[pos];
            pos++;
            while(pos<len&&str[pos]=='`') word+=str[pos],pos++;
            if(mpVt.count(word)==0){
                mpVt[word]=idVt++;
                rmpVt[idVt-1]=word;
            }
            vec.push_back(-mpVt[word]);  //終結符在候選式內使用負數,防止和非終結符衝突
        }
        else {
            errorG();
        }
    }
    if(!vec.empty()) {
        pro[idPro].candy.assign(vec.begin(),vec.end());  //處理最後的候選式
        pro[idPro++].Vn = idLeft;

        notml[idLeft].pro.push_back(vec);  //處理最後的候選式
    }
    vec.clear();

    if(idVt>=SIZE||idVn>=SIZE) { //終結符或,非終結符超出範圍,錯誤
        errorG();
        return ;
    }

}

#endif // INIT_H_INCLUDED

 

#ifndef GETFIRST_H_INCLUDED
#define GETFIRST_H_INCLUDED

//輸出FIRST集合
void dispalyFirst(){
    cout<<"---------------FIRST start---------------------"<<endl;
    for(int i=0;i<idVn;i++){
        cout<<rmpVn[i]<<":  ";
        for(set<int>::iterator it=notml[i].FIRST.begin();it!=notml[i].FIRST.end();it++){
            cout<<rmpVt[abs(*it)]<<" ";
        }
        cout<<endl;
    }

    cout<<"---------------FIRST end---------------------"<<endl;
}

//獲取FIRST集,和實驗二LL分析器一樣
void getFIRST(){

    //規則(1) 即將候選式的首字符是非終結符的加入FIRST集合
    for(int i=0;i<idVn;i++){
        for(int j=0;j< notml[i].pro.size();j++){
            if(notml[i].pro[j][0]<=0){
                notml[i].FIRST.insert(notml[i].pro[j][0]);
                notml[i].proNum++;
            }
            //判斷是否全部候選式都處理完
            if(notml[i].proNum == notml[i].pro.size()) notml[i].FirstFinish = true;
        }
    }

    //規則(2)的第一步,將X -> Y...的FIRST(Y)/{&}加入到FIRST(X)
    for(int i=0;i<idVn;i++){
        for(int j=0;j< notml[i].pro.size();j++){
            if(notml[i].pro[j][0]>0){   //判斷首字符是否爲非終結符
                set<int>tmp;
                int idk=notml[i].pro[j][0]; //獲取首字符的編號
                tmp.insert(notml[idk].FIRST.begin(),notml[idk].FIRST.end());
                if(tmp.count(EMPTY)) tmp.erase(EMPTY);
                notml[i].FIRST.insert(tmp.begin(),tmp.end());
            }
        }
    }

    //規則(2)第二步,每次有變化都要進行更新
    bool hasChange = true;
    int Empty=0;
    while(hasChange){
        hasChange = false;
        for(int i=0;i<idVn;i++){    //遍歷非終結符,對還有候選式沒有處理的進行處理
            if(!notml[i].FirstFinish){
                for(int j=0;j<notml[i].pro.size();j++){ //遍歷每個候選式
                    Empty=0;    //記錄空串,判斷是否整個字符串都有空串
                    bool ok = true;
                    for(int k=0;k<notml[i].pro[j].size();k++){  //遍歷每個候選的每個字符
                        int id = notml[i].pro[j][k];
                        if(id>0&&!notml[id].FirstFinish){   //必須是已經處理完成的非終結符才能更新現在的非終結符
                            ok=false;
                            break;
                        }
                    }
                    if(ok){ //對非終結符進行更新
                        for(int k=0;k<notml[i].pro[j].size();k++){
                            int id = notml[i].pro[j][k];
                            if(id>0&&notml[id].FirstFinish){
                                set<int> tmp;
                                tmp.insert(notml[id].FIRST.begin(),notml[id].FIRST.end());  //將FIRST(Y)加入到FIRST(X)
                                if(notml[id].FIRST.count(EMPTY)){   //判斷空串
                                    Empty++;
                                    tmp.erase(EMPTY);
                                    notml[i].FIRST.insert(tmp.begin(),tmp.end());
                                    hasChange = true;
                                }
                                else {
                                    notml[i].FIRST.insert(tmp.begin(),tmp.end());
                                    hasChange = true;
                                    break;  //沒有空串則停止
                                }
                            }
                        }
                        if(Empty == notml[i].pro[j].size()){    //如果全部字符都有空串,則加入空串到FIRST(X)
                            notml[i].FIRST.insert(EMPTY);
                        }
                        notml[i].proNum++;  //記錄已經處理候選式
                        if(notml[i].proNum == notml[i].pro.size()) notml[i].FirstFinish = true; //全部候選式處理完則該非終結符處理完
                    }
                }
            }
        }
    }
}


#endif // GETFIRST_H_INCLUDED

 

#ifndef GETFOLLOW_H_INCLUDED
#define GETFOLLOW_H_INCLUDED

//輸出FOLLOW集合
void dispalyFollow(){
    cout<<"---------------FOLLOW start---------------------"<<endl;
    for(int i=0;i<idVn;i++){
        cout<<rmpVn[i]<<":  ";
        for(set<int>::iterator it=notml[i].FOLLOW.begin();it!=notml[i].FOLLOW.end();it++){
            cout<<rmpVt[abs(*it)]<<" ";
        }
        cout<<endl;
    }

    cout<<"---------------FOLLOW end---------------------"<<endl;
}

//獲取FOLLOW集,和實驗二LL分析器一樣
void getFollow(){
    //規則(1)將 # 加入到文法開始符的FOLLOW集合
    notml[0].FOLLOW.insert(JING);

    //規則(2)A -> aBP 將FIRST(P)/{&} 加入到FOLLOW(B)
    for(int id=0;id<idVn;id++){ //遍歷每個非終結符,獲取位置進行處理
        for(int i=0;i<idVn;i++){    //三個for遍歷每個非終結符的每個候選式的每個字符
            for(int j=0;j<notml[i].pro.size();j++){
                for(int k=0;k<notml[i].pro[j].size();k++){
                    if((notml[i].pro[j][k]==id)&&(k+1<notml[i].pro[j].size())&&(notml[i].pro[j][k+1]<0)){
                        notml[id].FOLLOW.insert(notml[i].pro[j][k+1]);  //P不是終結符,終結符的FIRST集合是它本身,直接加入
                    }
                    else if((notml[i].pro[j][k]==id)&&(k+1<notml[i].pro[j].size())&&(notml[i].pro[j][k+1]>0)){
                        set<int>tmp;
                        int idk = notml[i].pro[j][k+1];
                        tmp.insert(notml[idk].FIRST.begin(),notml[idk].FIRST.end());
                        if(tmp.count(EMPTY))
                            tmp.erase(EMPTY);
                        notml[id].FOLLOW.insert(tmp.begin(),tmp.end()); //FIRST(P)/{&}加入FOLLOW(A)
                    }
                }
            }
        }
    }

    //規則(3)A -> aB  或  A-> aBP
    queue<int>que;  //記錄需要進行處理的非終結符
    for(int i=1;i<idVn;i++){
        que.push(i);
    }
    int id;
    while(!que.empty()){
        id=que.front(); //處理B
        que.pop();
        for(int i=0;i<idVn;i++){    //遍歷A
            for(int j=0;j<notml[i].pro.size();j++){
                for(int k=0;k<notml[i].pro[j].size();k++){
                    if((notml[i].pro[j][k]==id)&&(k+1==notml[i].pro[j].size())){    //候選式爲 A -> aB
                        if(notml[i].FOLLOW.size()==0) que.push(id);
                        else notml[id].FOLLOW.insert(notml[i].FOLLOW.begin(),notml[i].FOLLOW.end());
                    }
                    else if((notml[i].pro[j][k]==id)&&(k+1<notml[i].pro[j].size())&&(notml[i].pro[j][k+1]>0)&&(notml[notml[i].pro[j][k+1]].FIRST.count(0)>0)){
                        //候選式爲  A -> aBP
                        if(notml[i].FOLLOW.size()==0) que.push(id);
                        else notml[id].FOLLOW.insert(notml[i].FOLLOW.begin(),notml[i].FOLLOW.end());
                    }
                }
            }
        }
    }
}


#endif // GETFOLLOW_H_INCLUDED

 

#ifndef GETI_H_INCLUDED
#define GETI_H_INCLUDED

//處理項目集

stack<int>st;   //記錄需要增長的項目集
bool vis[SIZE]; //標誌每次擴展一個項目集的產生式,判斷是否重複

int numI = 0;   //項目集的數量
Ix tmpI;    //項目集的臨時變量

//顯示每個項目集
void displayByIdI(int id){
    cout<<"-----------------start---------------------"<<endl;
    bool flag = false;
    cout<<"I["<<id<<"]:"<<endl;
    //cout<<id<<":"<<I[id].pro.size()<<endl;
    for(pair<int,int> x : I[id].pro){
        int idV = x.first;
        int dot = x.second;
        int idV2 = pro[idV].Vn;
        flag = false;
        cout<<rmpVn[idV2]<<"->";
        for(int j=0;j<pro[idV].candy.size();j++){
            if(j==dot){
                flag = true;
                cout<<".";
            }
            int value = pro[idV].candy[j];
            if(value>0){
                cout<<rmpVn[value];
            }else {
                cout<<rmpVt[-value];
            }
        }
        if(!flag) cout<<".";
        cout<<endl;
    }

    for(pair<int,int> x:I[id].go){
        cout<<"GOTO(";
        if(x.first>0){
            cout<<rmpVn[x.first];
        }else {
            cout<<rmpVt[-x.first];
        }
        cout<<", I["<<x.second<<"] )\n";
    }
    cout<<"-----------------end---------------------"<<endl;
}

//void displayI(){
//    cout<<"--------------------I start-----------------------"<<endl;
//    for(int i=0;i<=numI;i++){
//        cout<<"------------"<<i<<"--------------"<<endl;
//        cout<<"pro:"<<endl;
//        for(pair<int,int> p:I[i].pro){
//            cout<<p.first<<":"<<p.second<<endl;
//        }
//        cout<<"go"<<endl;
//        for(pair<int,int> p:I[i].go){
//            cout<<p.first<<":"<<p.second<<endl;
//        }
//        cout<<"------------"<<i<<"--------------"<<endl;
//    }
//    cout<<"--------------------I end-----------------------"<<endl;
//}

//DFS求項目集的閉包
void Closure(int idV){
    for(int i=0;i<idPro;i++){
        if(vis[i]) continue;    //已經有的產生式跳過
        if(pro[i].Vn == idV){   //判斷是否是相同的產生式左部
            vis[i] = true;         //標誌該產生式
            tmpI.pro.insert({i,0});     //存儲產生式
            tmpI.v.insert(pro[i].candy[0]);     //存儲產生式右部第一個字符,作爲一條邊
            if(pro[i].candy[0]>0){
                Closure(pro[i].candy[0]);   //根據第一個字符繼續搜索
            }
        }
    }

}

//求項目集
void GOTO(int idV,int dot){
    memset(vis, false, sizeof(vis));    //每次處理一個項目集要將產生式標誌清零
    tmpI.pro.insert({idV, dot+1});      //存儲產生式以及它的點‘.’位置
    if(dot+1<pro[idV].candy.size()){
        int idV2 = pro[idV].candy[dot+1];       //獲取一條邊
        tmpI.v.insert(idV2);
        Closure(idV2);      //求閉包
    }
}

//判斷求得的項目集是否出現過,沒則創建新的
int getNext(){
    for(int i=0;i<=numI;i++){
        if(I[i].pro==tmpI.pro){
            return i;
        }
    }
    ++numI;
    I[numI].pro=tmpI.pro;
    I[numI].v=tmpI.v;
    I[numI].go=tmpI.go;
    st.push(numI);
    return numI;
}

//求項目集
void getI(){

    memset(vis, false, sizeof(vis));
    tmpI.Clear();
    tmpI.pro.insert({0,0});
    Closure(1);                 //求初始項目集
    I[0].pro=tmpI.pro;
    I[0].v=tmpI.v;
    I[0].go=tmpI.go;

    //求初始項目集的邊
    for(pair<int,int> x:I[0].pro){
        int idV = x.first;
        int dot = x.second;
        int Vn = pro[idV].candy[dot];
        I[0].v.insert(Vn);
    }

    //使用棧存儲需要增長的項目集,從0號項目集開始
    st.push(0);
    while(!st.empty()){
        int idI = st.top();     //獲取項目集編號
        st.pop();
        for(int x:I[idI].v){    //遍歷項目集的出度邊
            tmpI.Clear();       //初始化臨時遍歷,用來指定下一個擴展的節點
            for(pair<int,int> p:I[idI].pro){    //遍歷項目集的產生式
                int idV = p.first;
                int dot = p.second;
                int v = pro[idV].candy[dot];
                if(x == v){                 //產生式的點‘.’後面的字符是出度的邊的字符則邊指向另一個項目集
                    GOTO(idV, dot);
                }
            }
            I[idI].go.insert({x,getNext()});    //增加一條邊
        }
    }

    //輸出項目集
    for(int i=0;i<=numI;i++){
        displayByIdI(i);
        cout<<endl;
    }

    //displayI();




}

#endif // GETI_H_INCLUDED

 

#ifndef GETACTION_H_INCLUDED
#define GETACTION_H_INCLUDED

//求ACTION和GOTO表

int Action[SIZE][SIZE];     //第一維表示項目集編號,第二維表示終結符或非終結符
int Goto[SIZE][SIZE];

//顯示錶內容
void displayTable(){

    cout<<"------------------------------LR Table-----------------------------"<<endl;
    cout<<"\t";
    for(int i=0;i<idVt;i++){
        cout<<rmpVt[i]<<"\t";
    }
    for(int i=0;i<idVn;i++){
        cout<<rmpVn[i]<<"\t";
    }
    cout<<endl;

    for(int i=0;i<=numI;i++){
        cout<<i<<"\t";
        for(int j=0;j<idVt;j++){
            if(Action[i][j] == ERROR){
                cout<<"error\t";
            }else {
                //cout<<Action[i][j]<<"\t";
                if(Action[i][j]==ACC){
                    cout<<"acc\t";
                }else if(Action[i][j]>=2*SIZE){
                    cout<<"r"<<Action[i][j]-2*SIZE<<"\t";
                }else {
                    cout<<"S"<<Action[i][j]<<"\t";
                }
            }
        }
        for(int j=0;j<idVn;j++){
            if(Goto[i][j] == ERROR){
                cout<<"error\t";
            }else {
                cout<<Goto[i][j]<<"\t";
            }
        }
        cout<<endl;
    }

    cout<<"------------------------------LR Table-----------------------------"<<endl<<endl;
}

//求ACTION和GOTO表
void getActionGotoTable(){

    //初始化
    for(int i=0;i<SIZE;i++){
        for(int j=0;j<SIZE;j++){
            Action[i][j]= ERROR;
            Goto[i][j] = ERROR;
        }
    }

    for(int i=0;i<=numI;i++){       //遍歷全部項目集
        int idP, dot;
        for(pair<int,int>p:I[i].pro){   //遍歷其全部產生式
            idP = p.first;
            dot = p.second;

            if(pro[idP].candy.size()==dot&&idP==0){   //規則(3) 處理文法開始符,如S` -> S
                Action[i][JING]=ACC;
            }
            else if(pro[idP].candy.size()==dot){    //規則(2) 處理點‘.’在產生式最右邊  如A -> a .
                for(int j=0;j<idVt;j++){//非終結符 a
                    int idV = pro[idP].Vn;  //產生式左部 A
                    if(notml[idV].FOLLOW.count(-j)){   //歸約
                        Action[i][j] = idP+2*SIZE;      //產生式編號加兩倍SIZE,和移進操作區分
                    }
                }
            }else { //規則(1)(4)
                for(pair<int,int> x:I[i].go){   //遍歷每條邊
                    int idt = x.first;  //邊的字符 a
                    int idI = x.second; //邊的指向項目集 I
                    if(idt>0){  //點‘.’後面是非終結符 如A -> a . Bp
                        Goto[i][idt] = idI;
                    }
                    else if(pro[idP].candy.size()>dot&&(pro[idP].candy[dot]==idt)){    //點‘.’後面是終結符  如A -> c . ap
                        Action[i][-idt] = idI;
                    }
                }
            }

        }


    }
    displayTable();
}

#endif // GETACTION_H_INCLUDED

 

#ifndef ANALYSE_H_INCLUDED
#define ANALYSE_H_INCLUDED

//輸出ACTION動作
void displayS(int inNum,int stzNum,int stfNum,int tableNum){
    cout<<"ACTION["<<stzNum<<","<<rmpVt[-inNum]<<"]=S"<<tableNum<<":";
    cout<<"將狀態"<<tableNum<<"入棧"<<endl;
}

//輸出歸約動作
void displayR(int stzT,int tableNum,int idP,int stznew){
    cout<<"r"<<tableNum-2*SIZE<<":"<<"用";
    cout<<rmpVn[pro[idP].Vn]<<"->";
    for(int i=0;i<pro[idP].candy.size();i++){
        int x=pro[idP].candy[i];
        if(x>0) cout<<rmpVn[x];
        else cout<<rmpVt[-x];
    }
    cout<<"歸約且GOTO(";
    cout<<stzT<<","<<rmpVn[pro[idP].Vn]<<")=";
    cout<<stznew<<"入棧"<<endl;
}

//輸出分析成功
void displaySuccess(){
    cout<<"Acc:分析成功"<<endl;
}

//輸出狀態棧情況
void displayStz(stack<int>st){
    vector<int>vec;
    while(!st.empty()){
        vec.push_back(st.top());
        st.pop();
    }
    for(int i=vec.size()-1;i>=0;i--){
        if(i==0) cout.width(20-2*vec.size());
        cout<<vec[i]<<" ";
    }
}

//輸出符號棧情況
void displayStf(stack<int>st){
    vector<int>vec;
    while(!st.empty()){
        vec.push_back(st.top());
        st.pop();
    }
    for(int i=vec.size()-1;i>=0;i--){
        if(i==0) cout.width(20-2*vec.size());
        if(vec[i]>0) cout<<rmpVn[vec[i]]<<" ";
        else cout<<rmpVt[-vec[i]]<<" ";
    }
}

//輸出輸入串情況
void displayInput(int pos,vector<int> vec){
    for(int i=pos;i<vec.size();i++){
        if(i==vec.size()-1) cout.width(20-2*(vec.size()-pos));
        if(vec[i]>0) cout<<rmpVn[vec[i]]<<" ";
        else cout<<rmpVt[-vec[i]]<<" ";
    }
}

//分析輸入串
void getAns(string str){

    cout.setf(std::ios::left);

    cout<<"輸入串:"<<str<<endl;
    cout<<"------------------------analyse start-----------------------"<<endl;
    cout<<"步驟\t狀態棧\t\t符號棧\t\t\t輸入串\t\t動作說明\n";
    int len = str.length();
    vector<int>input;
    for(int i=0;i<len;i++){ //將輸入串轉換成編號
        string tmp="";
        tmp+=str[i];
        input.push_back(-mpVt[tmp]);
    }
    input.push_back(-JING); //增加‘#’號

    stack<int>stz, stf; //狀態棧和符號棧

    stz.push(0);
    stf.push(-JING);

    int pos = 0;

    int step = 1;
    while(1){
        cout.width(8);
        cout<<step++;   //輸出第幾步
        displayStz(stz);    //輸出狀態棧
        displayStf(stf);    //輸出符號棧
        displayInput(pos,input);    //輸出輸入串
        int inNum = input[pos];
        if(stf.size()==0||stz.size()==0){   //狀態棧或符號棧爲空分析失敗
            errorA();
            return ;
        }
        int stzNum = stz.top();
        int stfNum = stf.top();
        int tableNum;
        tableNum = Action[stzNum][-inNum];  //取Action表對應值
        //cout<<stzNum<<":"<<inNum<<":"<<tableNum<<":"<<stfNum<<endl;
        if(tableNum == ACC) break;
        if(tableNum == ERROR){
            errorA();
            return ;
        }
        if(tableNum>=2*SIZE){   //歸約
            int idP = tableNum - 2*SIZE;
            for(int i=pro[idP].candy.size()-1;i>=0;i--){    //根據產生式右部進行出棧
                if(pro[idP].candy[i]!=stf.top()) errorA();
                if(stf.size()==0||stz.size()==0){
                    errorA();
                    return ;
                }
                stf.pop();
                stz.pop();

            }
            stf.push(pro[idP].Vn);  //將產生式左部加進符號棧
            if(stf.size()==0||stz.size()==0){
                errorA();
                return ;
            }
            int stzT = stz.top();
            int stznew = Goto[stzT][pro[idP].Vn];   //取得對應的GOTO表值
            stz.push(stznew);   //將GOTO表的值加入狀態棧
            displayR(stzT,tableNum,idP,stznew); //輸出歸約動作
        }else{     //移進
            stz.push(tableNum);
            stf.push(inNum);
            pos++;
            displayS(inNum,stzNum,stfNum,tableNum);
        }
        cout<<endl;
    }
    displaySuccess();


    cout<<"------------------------analyse end-----------------------"<<endl;

}

#endif // ANALYSE_H_INCLUDED

 

#ifndef CHECK_H_INCLUDED
#define CHECK_H_INCLUDED

void errorG()
{
    cout<<"輸入的文法有誤"<<endl;
    exit(0);
}

void errorA()
{
    cout<<"分析錯誤"<<endl;
    cout<<"------------------------error start-----------------------"<<endl;
}

#endif // CHECK_H_INCLUDED

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章