【编译技术实验】LL(1)预测分析(C++实现)

本文介绍了一次通过(LL(1))预测分析的原理,并提供了使用C++实现的清晰代码示例,无需额外注释即可理解。

代码易懂,无需注释就能看懂。

#include<iostream>
#include<unordered_map>
#include<vector>
#include<fstream>
#include<sstream>
#include<unordered_set>
#include<map>
#include<iomanip>

using namespace std;

class OutPut{
public:
    OutPut(string step,string symbolStack,string inputString,string production,string action):
        step(std::move(step)),symbolStack(std::move(symbolStack)),inputString(std::move(inputString)),
        production(std::move(production)),action(std::move(action)){};
    void run(){
        cout << setiosflags(ios::left) << setw(14) << step << setiosflags(ios::left) << setw(14) << symbolStack
                << setiosflags(ios::left) << setw(14) << inputString<< setiosflags(ios::left) << setw(14) << production
                << setiosflags(ios::left) << setw(14) << action<<endl;
    }
private:
    string step,symbolStack,inputString,production,action;
};

class LL1Analyzer{
public:
    explicit LL1Analyzer(const string& path){
        startchar='$';
        ifstream readFile(path);
        string grammar;
        while(!readFile.eof()){
            getline(readFile,grammar,'\n');
            stringstream ss(grammar);
            string left,right;
            getline(ss,left,'>');
            if(startchar=='$') startchar=left[0];
            while(getline(ss,right,'|')){
                production[left[0]].emplace_back(right);
                for(char & ch:right)
                    if(!isupper(ch) && ch != '$') vt.insert(ch);
            }
        }
        generateFirstSet();
        generateFollowSet();
        generateM();
    }

    void solve(const string& input){
        vector<OutPut> outPutVec={OutPut("步骤","符号栈","输入串","所用产生式","动作")};
        int step=0;
        string inputstring=input+"#",symbolStack="#"+string(1,startchar),aproduciton,action="初始化";
        outPutVec.emplace_back(OutPut(to_string(step),symbolStack,input,aproduciton,action));
        int i=0;
        while(i<inputstring.size()-1){
            if(symbolStack.back()==inputstring[i]){
                symbolStack.pop_back();
                aproduciton="";
                action="GETNEXT("+string(1,inputstring[i++])+")";
            }else if(M.find({symbolStack.back(),inputstring[i]})==M.end()) break;
            else{
                aproduciton=M[{symbolStack.back(),inputstring[i]}];
                action="pop";
                symbolStack.pop_back();
                if(aproduciton.back()!='$'){
                    int point=aproduciton.find('>')+1;
                    action+=",push("+aproduciton.substr(point)+")";
                    for(int j=aproduciton.size()-1;j>=point;--j) symbolStack.push_back(aproduciton[j]);
                }
            }
            outPutVec.emplace_back(OutPut(to_string(++step),symbolStack,inputstring.substr(i),aproduciton,action));
        }
        for(OutPut aOutPut:outPutVec) aOutPut.run();
        if(inputstring[i]!='#') cout<<"出错"<<endl;
    }

private:
    void generateFirstSet(){
        int lastnum=-1,curnum=0;
        while(lastnum!=curnum){
            for(const pair<const char, vector<string>>& aProduction : production){
                for(const string& candidate:aProduction.second){
                    for(char ch : candidate) if(!isupper(ch)) first[ch].insert(ch);
                    unordered_set<char> candidateFirst= FIRST(candidate);
                    for(char item:candidateFirst)
                        if(candidate=="$"||item!='$') first[aProduction.first].insert(item);
                }
            }
            lastnum=curnum;
            curnum= tableSize(first);
        }
    }
    
    void generateFollowSet(){
        follow[startchar]={'#'};
        int lastnum=-1,curnum=0;
        while(lastnum!=curnum){
            for(const pair<const char, vector<string>>& aProduction : production){
                for(const string& candidate:aProduction.second){
                    for(int i=0;i<candidate.size();++i){
                        unordered_set<char> tempFirst= FIRST(candidate.substr(i+1));
                        for(char item:tempFirst)   follow[candidate[i]].insert(item);
                        if(tempFirst.find('$')!=tempFirst.end()||i==candidate.size()-1)
                            for(char item:follow[aProduction.first])
                                if(item!='$') follow[candidate[i]].insert(item);
                    }
                }
            }
            lastnum=curnum;
            curnum= tableSize(follow);
        }
    }

    void generateM(){
        for(const pair<const char, vector<string>>& aProduction : production){
            for(const string& candidate:aProduction.second) {
                string formula=string(1,aProduction.first)+"->"+candidate;
                unordered_set<char> candidateFirst= FIRST(candidate);
                for(char ftitem:candidateFirst)
                    if(ftitem != '$') M[{aProduction.first,ftitem}]=formula;
                    else for(char fwitem:follow[aProduction.first]) M[{aProduction.first, fwitem}]=formula;
            }
        }
    }

    unordered_set<char> FIRST(const string& txt){
       unordered_set<char> res;
        for(char ch : txt){
            unordered_set<char> cur = first[ch];
            for(char item : cur) res.insert(item);
            if(cur.find('$')==cur.end()) return res;
        }
        return res;
    }

    static int tableSize(unordered_map<char,unordered_set<char>> & table){
        int res=0;
        for(const pair<const char, unordered_set<char>>& map:table) res+=map.second.size();
        return res;
    }

    char startchar;
    unordered_map<char,unordered_set<char>> first,follow;
    unordered_map<char,vector<string>> production;
    unordered_set<char> vt;
    map<pair<char,char>,string> M; //pair不能作为无序表的key
};

int main(){
    LL1Analyzer ll1Analyzer("D://2019215055LL(1)//grammar.txt");
    ll1Analyzer.solve("i*i+i");
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值