【编译原理】LR(1)分析方法(c++实现)

2023-11-17

前文回顾

【编译原理】LR(0)分析方法(c++实现)
【编译原理】SLR(1)分析方法(c++实现)
 

算法

来自龙书第二版
在这里插入图片描述
在这里插入图片描述

代码

和SLR的区别其实只是DFA中多了一个搜索符,构建分析表的时候规约项的列是相应的搜索符而已

代码基本上就在SLR的代码上修修补补,但是写的有点乱,以后有时间再整理一下吧

Item类

#include <iostream>
#include <fstream>
#include <string.h>
#include <string>
#include <cstring>
#include <algorithm>
#include <set>
#include <map>
#include <stack>
#include <utility>
#include <iomanip>
using namespace std;

//返回s的第一个词
string firstWord(string s)
{
    s+=" ";
    string first=s.substr(0,s.find(" "));
    return first;
}

//将字符串划分为一个个词
vector<string> split(string s,string separator)
{
    vector<string>v;

    string::size_type pos1, pos2;
    pos2 = s.find(separator);
    pos1 = 0;

    while(string::npos != pos2)
    {
        v.push_back(s.substr(pos1, pos2-pos1));

        pos1 = pos2 + separator.size();
        pos2 = s.find(separator, pos1);
    }
    if(pos1 != s.length())
        v.push_back(s.substr(pos1));

    return v;
}

class Item
{
private:
    string item;//项目
    string left;//项目左部
    string right;//项目右部
    string symbol;//向前搜索符号
    static int count;

public:
    int id;

    //参数是产生式
    Item(string i)
    {
        id=count++;
        left=i.substr(0,i.find("->"));
        right=i.substr(i.find("->")+2);
        item=left+"->"+right;
        symbol="$";//初始向前搜索符为"$"

        if(right.find(".")==string::npos)
            addDot(0);
    }

    //参数是左部和右部
    Item(string l,string r)
    {
        id=count++;
        left=l;
        right=r;
        symbol="$";
        item=left+"->"+right;

        if(right.find(".")==string::npos)
            addDot(0);
    }

    //参数是左部和右部和向前搜索符号
    Item(string l,string r,string s)
    {
        id=count++;
        left=l;
        right=r;
        symbol=s;
        item=left+"->"+right;

        if(right.find(".")==string::npos)
            addDot(0);
    }

    string getLeft()
    {
        return left;
    }

    string getRight()
    {
        return right;
    }

    string getItem()
    {
        item=left+"->"+right;
        return item;
    }

    string getSymbol()
    {
        return symbol;
    }

    //找点的位置
    int getDot(string item)
    {
        return item.find(".");
    }
    //设置向前搜索符号
    void setSymbol(string new_symbol)
    {
        symbol=new_symbol;
    }
    //给文法加点
    void addDot(int pos)
    {
        if(right[pos]=='@')
            right=".";
        else if(pos==0)
            right.insert(pos,". ");
        else if(pos==right.size())
            right.insert(pos," .");
        else
            right.insert(pos," . ");
    }

    //判断一个项目进度是否到结尾
    int hasNextDot()
    {
        vector<string>buffer=split(right,".");
        if(buffer.size()>1)
            return 1;
        else
            return 0;
    }

    //得到"."后面的一个文法符号
    string getPath()
    {
        vector<string>buffer=split(item,".");
        buffer[1].erase(0,1);
        string first=firstWord(buffer[1]);
        return first;
    }

    //返回下一个点的串
    string nextDot()
    {
        int dotPos=right.find(".");
        vector<string>buffer=split(item,".");
        buffer[1].erase(0,1);
        string first=firstWord(buffer[1]);
        int nextPos=dotPos+first.size();
        right.erase(right.find("."),2);
        right.insert(nextPos," .");
        return right;
    }

    bool operator ==(Item &x)
    {
        return getItem()==x.getItem();
    }
};
int Item::count=0;

LR(1)分析方法

#include <iostream>
#include <fstream>
#include <string.h>
#include <string>
#include <cstring>
#include <algorithm>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <utility>
#include <iomanip>
#include "Item.h"

using namespace std;

//DFA的边
struct GOTO
{
    int from;
    int to;
    string path;

    GOTO(int s,string p,int t)
    {
        from=s;
        path=p;
        to=t;
    }
};

//DFA中状态
struct State
{
    int id;//状态编号
    set<Item>items;//项目集
};

/*一些操作符的重载*/
bool operator <(const State &x,const State &y)
{

    return x.id<y.id;
}

bool operator <(const Item &x,const Item &y)
{

    return x.id<y.id;
}

bool operator <(const GOTO &x,const GOTO &y)
{

    return x.from<y.from;
}

bool operator ==(const GOTO &x,const GOTO &y)
{
    return x.from==y.from && x.path==y.path && x.to==y.to;
}

bool operator ==(const set<Item> &x,const set<Item> &y)
{
    auto it1=x.begin();
    auto it2=y.begin();

    for(; it1!=x.end(),it2!=y.end(); it1++,it2++)
    {
        Item a=*it1;
        Item b=*it2;
        if(a==b&&a.getSymbol()==b.getSymbol())
            continue;

        //有一个项目不相等,两项目集一定不相等
        else
            return false;
    }
    return true;
}

class LR1
{
private:
    int number=0;
    vector<string>T;//终结符号集合
    vector<string>NT;//非终结符号集合
    string S;//开始符号
    map<string,vector<string>>production;//产生式
    map<string,int>numPro;//编号的产生式集合,用于规约
    set<State>States;//状态集合
    vector<GOTO>GO;//转换函数
    map<string,set<string>>FIRST;//FIRST集
    map<string,set<string>>FOLLOW;//FOLLOW集
    map<pair<int,string>,string>actionTable;//action表
    map<pair<int,string>,int>gotoTable;//goto表

    //读取文法规则
    void readGrammar(string fileName)
    {
        ifstream input(fileName);
        if(!input)
        {
            cout<<fileName<<" Failed"<<endl;
        }

        //读取文法规则
        string line;//读入的每一行
        while(getline(input,line))
        {
            int i;

            //读取左部
            string left="";
            for(i=0; line[i]!='-'&&i<line.size(); i++)
            {
                left+=line[i];
            }

            NT.push_back(left);//左部加入非终结符号集

            //读取右部
            string right=line.substr(i+2,line.size()-i);//获取产生式右部
            addP(left,right);//添加产生式
        }
        addT();//添加终极符
        S=*NT.begin();
        input.close();
    }

    //填产生式
    void addP(string left,string right)
    {
        right+="#";//'#'作为每句文法结尾标志
        string pRight="";
        for(int i=0; i<right.size(); i++)
        {
            if(right[i]=='|'||right[i]=='#')
            {
                production[left].push_back(pRight);
                pRight="";
            }
            else
            {
                pRight+=right[i];
            }
        }
    }

    //带标号的产生式集
    void addNumP()
    {
        int i=0;
        for(string left:NT)
        {
            for(string right:production[left])
            {
                numPro[left+"->"+right]=i;
                i++;
            }
        }

//        for(auto it=numPro.begin();it!=numPro.end();it++)
//            cout<<it->first<<"\t"<<it->second<<endl;
    }

    //填终结符
    void addT()
    {
        string temp="";
        for(string left:NT)
        {
            for(string right:production[left])
            {
                right+="#";
                for(int i=0; i<right.size(); i++)
                {
                    if(right[i]=='|'||right[i]==' '||right[i]=='#')
                    {
                        //不是非终结,且不是空,则加入终结符号
                        if((find(NT.begin(),NT.end(),temp)==NT.end())&&temp!="@")
                        {
                            T.push_back(temp);
                        }
                        temp="";
                    }
                    else
                    {
                        temp+=right[i];
                    }
                }
            }
        }//end left

        //终结符去重
        sort(T.begin(),T.end());
        T.erase(unique(T.begin(), T.end()), T.end());
    }
    //判断是否是非终极符号
    bool isNT(string token)
    {
        if(find(NT.begin(),NT.end(),token)!=NT.end())
            return true;
        return false;
    }
    //判断temp在不在集合c中
    bool isIn(Item temp,set<Item>c)
    {
        for(Item i:c)
        {
            if(i.getItem()==temp.getItem()&&i.getSymbol()==temp.getSymbol())
                return true;
        }
        return false;
    }
    //判断是否应该规约
    string tableReduce(int num)
    {
        for(State s:States)
        {
            //目标状态
            if(s.id==num)
            {
                //遍历项目集
                for(Item i:s.items)
                {
                    //还有下一个点,肯定不是规约项目
                    if(i.hasNextDot())
                        return "";
                    //是规约项目
                    else
                        return i.getLeft();//返回左部NT
                }
            }
        }
        return "";
    }

    //找到item规约到的产生式,返回其编号
    int findReduce(int num)
    {
        for(State s:States)
        {
            if(s.id==num)
            {
                for(Item i:s.items)
                {
                    string temp=i.getItem();
                    temp.erase(temp.find("."));
                    temp.pop_back();
                    return numPro.find(temp)->second;
                }
            }
        }
        return -1;
    }
    //根据项目找规约的产生式编号
    int findReduce(Item item)
    {
        string temp=item.getItem();
        temp.erase(temp.find("."));
        temp.pop_back();
        if(numPro.find(temp)!=numPro.end())
            return numPro.find(temp)->second;
        return -1;
    }
    //找到产生式序号为pro的产生式右部数量
    int rightCount(string &left,int pro)
    {
        for(auto it=numPro.begin(); it!=numPro.end(); it++)
        {
            if(it->second==pro)
            {
                cout<<it->first<<endl;
                string target=it->first;
                left=target.substr(0,target.find("->"));
                string right=target.substr(target.find("->")+2);
                vector<string>temp=split(right," ");
                return temp.size();
            }
        }
        return 0;
    }
public:
    //构造函数,读入所需的四元组
    LR1(string fileName)
    {
        readGrammar(fileName);
        Extension();//拓广文法
    }

    //拓广文法
    void Extension()
    {
        string newS=S;
        newS+="'";
        NT.insert(NT.begin(),newS);
        production[newS].push_back(S);
        S=newS;
    }

    //状态集是否已经包含该状态
    int hasState(set<Item>J)
    {
        for(State s:States)
        {
            if(s.items.size()!=J.size())
                continue;

            if(s.items==J)
                return s.id;
            else
                continue;

        }
        return -1;
    }
    //获得FIRST集合
    void getFirst()
    {
        FIRST.clear();

        //终结符号或@
        FIRST["@"].insert("@");
        for(string X:T)
        {
            FIRST[X].insert(X);
        }

        //非终结符号
        int j=0;
        while(j<4)
        {
            for(int i=0; i<NT.size(); i++)
            {
                string A=NT[i];

                //遍历A的每个产生式
                for(int k=0; k<production[A].size(); k++)
                {
                    int Continue=1;//是否添加@
                    string right=production[A][k];

                    //X是每条产生式第一个token
                    string X;
                    if(right.find(" ")==string::npos)
                        X=right;
                    else
                        X=right.substr(0,right.find(" "));
                    //cout<<A<<"\t"<<X<<endl;

                    //FIRST[A]=FIRST[X]-@
                    if(!FIRST[X].empty())
                    {
                        for(string firstX:FIRST[X])
                        {
                            if(firstX=="@")
                                continue;
                            else
                            {
                                FIRST[A].insert(firstX);
                                Continue=0;
                            }
                        }
                        if(Continue)
                            FIRST[A].insert("@");
                    }
                }

            }
            j++;
        }
    }

    //获得FOLLOW集合
    void getFollow()
    {
        getFirst();

        //将界符加入开始符号的follow集
        FOLLOW[S].insert("$");

        int j=0;
        while(j<4)
        {
            //遍历非终结符号
            for(string A:NT)
            {
                for(string right:production[A])
                {
                    for(string B:NT)
                    {
                        //A->Bb
                        if(right.find(B)!=string::npos)
                        {
                            /*找B后的字符b*/
                            string b;
                            int flag=0;
                            //识别到E'
                            if(right[right.find(B)+B.size()]!=' '&&right[right.find(B)+B.size()]!='\0')
                            {
                                string s=right.substr(right.find(B));//E'b
                                string temp=right.substr(right.find(B)+B.size());//' b

                                //A->E'
                                if(temp.find(" ")==string::npos)
                                {
                                    B=s;//B:E->E'
                                    FOLLOW[B].insert(FOLLOW[A].begin(),FOLLOW[A].end());//左部的FOLLOW赋给B
                                    flag=1;
                                }
                                //A->E'b
                                else
                                {
                                    B=s.substr(0,s.find(" "));
                                    temp=temp.substr(temp.find(" ")+1);//b

                                    //b后无字符
                                    if(temp.find(" ")==string::npos)
                                        b=temp;
                                    //b后有字符
                                    else
                                        b=temp.substr(0,temp.find(" "));
                                }
                            }

                            //A->aEb
                            else if(right[right.find(B)+B.size()]==' ')
                            {
                                string temp=right.substr(right.find(B)+B.size()+1);//B后的子串

                                //b后无字符
                                if(temp.find(" ")==string::npos)
                                    b=temp;
                                //b后有字符
                                else
                                    b=temp.substr(0,temp.find(" "));
                            }
                            //A->aE
                            else
                            {
                                FOLLOW[B].insert(FOLLOW[A].begin(),FOLLOW[A].end());
                                flag=1;
                            }

                            //FOLLOW[B]还没求到
                            if(flag==0)
                            {
                                //FIRST[b]中不包含@
                                if(FIRST[b].find("@")==FIRST[b].end())
                                {
                                    FOLLOW[B].insert(FIRST[b].begin(),FIRST[b].end());
                                }
                                else
                                {
                                    for(string follow:FIRST[b])
                                    {
                                        if(follow=="@")
                                            continue;
                                        else
                                            FOLLOW[B].insert(follow);
                                    }
                                    FOLLOW[B].insert(FOLLOW[A].begin(),FOLLOW[A].end());
                                }
                            }
                        }
                    }
                }
            }
            j++;
        }
        printFIRST();
        printFOLLOW();
    }

    //项目闭包
    set<Item> closure(Item item)
    {
        set<Item>C;//项目闭包
        C.insert(item);

        queue<Item>bfs;//bfs求所有闭包项
        bfs.push(item);
        //cout<<item.getItem()<<endl;

        while(!bfs.empty())
        {
            Item now=bfs.front();
            bfs.pop();
            //cout<<now.getItem()<<endl;

            vector<string>buffer=split(now.getRight(),".");

            if(buffer.size()>1)
            {
                string first=firstWord(buffer[1].erase(0,1));

                set<string>fst;
                vector<string>candidate=split(now.getRight(),first);
                //如果first后面有符号,则first后面符号的FIRST作为新的向前搜索符号
                if(candidate.size()>1)
                {
                    candidate[1].erase(0,1);
                    for(string f:FIRST[firstWord(candidate[1])])
                        fst.insert(f);
                }
                //如果first后面没有符号,则向前搜索符号为新的向前搜索符号
                else
                    fst.insert(now.getSymbol());

                if(isNT(first))//如果"."后面第一个字符是NT
                {
                    for(auto it2=production[first].begin(); it2!=production[first].end(); it2++)
                    {
                        Item temp(first,*it2);

                        if(!isIn(temp,C))
                        {
                            for(string f:fst)
                            {
                                temp.setSymbol(f);
                                C.insert(temp);
                                bfs.push(temp);
                            }
                        }
                    }
                }
            }
        }
        return C;
    }

    //构造DFA
    void dfa()
    {
        State s0;//初始项目集
        s0.id=number++;//状态序号

        //初始项目集
        string firstRight=*(production[S].begin());
        Item start(S,firstRight);
        s0.items=closure(start);//加到状态中
        States.insert(s0);

        //构建DFA
        State temp;
        for(State s:States)
        {
            map<string,int>Paths;//路径
            for(Item now:s.items)
            {
                now.getItem();
                if(now.hasNextDot())
                {
                    string path=now.getPath();//path
                    Item nextD(now.getLeft(),now.nextDot(),now.getSymbol());//新状态核心项,向前搜索符继承
                    set<Item>next=closure(nextD);//to

                    //该状态已经有这条路径了,则将新产生的闭包添加到原有目的状态中
                    int oldDes;
                    if(Paths.find(path)!=Paths.end())
                    {
                        oldDes=Paths.find(path)->second;
//                        cout<<oldDes<<endl;
                        for(State dest:States)
                        {
                            if(dest.id==oldDes)
                            {
                                dest.items.insert(next.begin(),next.end());
                                next=dest.items;

                                //更新状态集中状态
                                //set不允许重复插入,因此只能删除再插
                                States.erase(dest);
                                States.insert(dest);


                                int tID=hasState(next);
                                if(tID!=-1)
                                {
                                    //temp=dest;
                                    for(int i=0; i<GO.size(); i++)
                                    {
                                        if(GO[i].to==oldDes)
                                        {
                                            GO[i].to=tID;
//                                            cout<<tID<<endl;
                                        }
                                    }
                                }
                            }

                        }
                    }

                    //如果该目的状态在状态集里没有出现过,就加入状态集
                    int tID=hasState(next);
                    if(tID==-1)
                    {
                        State t;
                        t.id=number++;
                        t.items=next;
                        States.insert(t);
                        Paths.insert(pair<string,int>(path,t.id));
                        GO.push_back(GOTO(s.id,path,t.id));
                    }
                    //该目的状态已经在状态集中了
                    else
                    {
                        Paths.insert(pair<string,int>(path,tID));
                        GO.push_back(GOTO(s.id,path,tID));
                    }
                }
            }
        }
        //删除重复GOTO
        sort(GO.begin(),GO.end());
        GO.erase(unique(GO.begin(), GO.end()), GO.end());

        //处理重复状态
        for(State s1:States)
        {
            for(State s2:States)
            {
                //发现重复状态集
                if(s2.id>s1.id&&s1.items==s2.items)
                {
                    int erase_id=s2.id;
                    States.erase(s2);

                    //重复状态后面的所有状态序号-1
                    for(State s:States)
                    {
                        if(s.id>erase_id)
                        {
                            //原地修改set!
                            State &newS=const_cast<State&>(*States.find(s));
                            newS.id--;
                        }
                    }
                    //状态转移函数
                    for(int i=0; i<GO.size(); i++)
                    {
                        if(GO[i].from==erase_id||GO[i].to==erase_id)
                            GO.erase(find(GO.begin(),GO.end(),GO[i]));
                        if(GO[i].from>erase_id)
                            GO[i].from--;
                        if(GO[i].to>erase_id)
                            GO[i].to--;
                    }
                }
            }
        }
        printS();
        printGO();
    }
    //构造LR(1)分析表
    void getTable()
    {
        addNumP();
        string s=S;
        s=s.erase(s.find("'"));

        pair<int,string>title(1,"$");
        actionTable[title]="acc";

        for(GOTO go:GO)
        {
            //目的地是NT
            if(isNT(go.path))
            {
                pair<int,string>title(go.from,go.path);
                gotoTable[title]=go.to;

            }
            //加入action表
            else
            {
                //shift
                pair<int,string>title(go.from,go.path);
                actionTable[title]="s"+to_string(go.to);
            }
            //reduce,行为状态号,列为向前搜索符
            string rNT=tableReduce(go.to);
            if(rNT!="")
            {
                if(go.path!=s)
                {
                    //找该状态的项目集
                    State temp;
                    temp.id=go.to;
                    temp=*(States.find(temp));
                    set<Item>itm(temp.items.begin(),temp.items.end());
                    //向前搜索符下的规约项规约到对应产生式
                    for(Item i:itm)
                    {
                        pair<int,string>title(go.to,i.getSymbol());
                        int nReduce=findReduce(i);
                        if(nReduce!=-1)
                            actionTable[title]="r"+to_string(nReduce);
                        else
                            actionTable[title]="error";
                    }
                }
            }
        }
        printTable();
    }
    //语法分析过程
    int parsing(string input)
    {
        stack<string>Analysis;
        input+=" $";

        //0状态入栈
        Analysis.push("$");
        Analysis.push("0");

        vector<string>w=split(input," ");//将输入串分成一个个词
        int ip=0;//输入串的指针

        while(true)
        {
            pair<int,string>title(stoi(Analysis.top()),w[ip]);//stoi函数用于string to int
            string res=actionTable[title];
            cout<<"栈顶:s"<<setw(10)<<Analysis.top()<<"当前输入字符:"<<setw(8)<<w[ip];

            //shift
            if(res[0]=='s')
            {
                cout<<"动作:shift"<<endl;
                int state=stoi(res.substr(1));
                Analysis.push(w[ip]);
                Analysis.push(to_string(state));
                ip++;
            }
            //reduce
            else if(res[0]=='r')
            {
                cout<<"动作:reduce ";
                int pro=stoi(res.substr(1));
                string left;//产生式左部
                int b=2*rightCount(left,pro);//2倍的产生式右部符号数量

                while(b>0)
                {
                    Analysis.pop();
                    b--;
                }

                int s1=stoi(Analysis.top());
                Analysis.push(left);

                pair<int,string>t(s1,left);
                Analysis.push(to_string(gotoTable[t]));
            }
            else if(res[0]=='a')
            {
                cout<<"动作:接受"<<endl;
                return 1;
            }

            else
            {
                cout<<"文法错误"<<endl;
                return 0;
            }
        }
    }

    void parser(string fileName)
    {
        ifstream input(fileName);
        if(!input)
        {
            cout<<fileName<<" Failed"<<endl;
            return;
        }

        getFollow();
        dfa();
        getTable();

        //读取token
        char c;
        string program="";
        int line=1;
        cout<<"源程序的token序列为"<<endl;
        cout<<line<<"  ";
        while((c=input.get())!=EOF)
        {
            cout<<c;
            if(c=='\n')
            {
                cout<<++line<<"  ";
                program+=" ";
            }
            else
                program+=c;
        }
        cout<<endl;


        cout<<"分析结果:"<<endl;

        if(parsing(program))
            cout<<endl<<"*********************输入串属于该文法*********************"<<endl;
        else
            cout<<endl<<"********************输入串不属于该文法********************"<<endl;;

    }
    /*=====================打印===========================*/
    //打印NT和T
    void printV()
    {
        cout<<"非终结符号集合:"<<endl;
        for(int i=0; i<NT.size(); i++)
        {
            cout<<NT[i]<<" ";
        }
        cout<<endl;
        cout<<"终结符号集合:"<<endl;
        for(int i=0; i<T.size(); i++)
        {
            cout<<T[i]<<" ";
        }
        cout<<endl;
    }

    //打印FIRST集
    void printFIRST()
    {
        cout<<"FIRST集合为"<<endl;
        cout.setf(ios::left);
        for(string non_terminal:NT)
        {
            cout<<setw(20)<<non_terminal;
            for(string first:FIRST[non_terminal])
                cout<<first<<" ";
            cout<<endl;
        }
        cout<<endl;
    }

    //打印FOLLOW集
    void printFOLLOW()
    {
        cout<<"FOLLOW集合为"<<endl;
        cout.setf(ios::left);
        for(string non_terminal:NT)
        {
            cout<<setw(20)<<non_terminal;
            for(string follow:FOLLOW[non_terminal])
                cout<<follow<<" ";
            cout<<endl;
        }
        cout<<endl;
    }

    //打印分析表
    void printTable()
    {
        cout<<"LR分析表:"<<endl;

        vector<string>x=T;//含界符的终结符号集合
        x.push_back("$");

        //输出表格横轴
        cout<<"****************action****************"<<endl;
        cout.setf(ios::left);
        for (auto it1 = x.begin(); it1 != x.end(); it1++)
        {
            if (it1==x.begin())
                cout<<setw(10)<<" ";
            cout<<setw(8)<<*it1;
        }
        cout<<endl;

        for(int i=0; i<States.size(); i++)
        {
            cout<<setw(10)<<i;

            for(string t:x)
            {
                //cout<<i<<"ttt"<<endl;

                if(!actionTable.empty())
                {
                    pair<int,string>title(i,t);
                    cout<<setw(8)<<actionTable[title];
                }

                else
                    cout<<setw(8);
            }
            cout<<endl;
        }
        cout<<endl;

        /*打印GOTO表*/
        vector<string>y=NT;//不含S’的非终结符号集合
        y.erase(y.begin());

        cout<<"****************goto******************"<<endl;
        cout.setf(ios::left);

        for (auto it1 = y.begin(); it1 != y.end(); it1++)
        {
            if(it1==y.begin())
                cout<<setw(10)<<"";

            cout<<setw(8)<<*it1;
        }
        cout<<endl;

        for(int i=0; i<States.size(); i++)
        {
            cout<<setw(10)<<i;

            for(string t:y)
            {
                pair<int,string>title(i,t);

                if(gotoTable[title]!=0)
                {
                    cout<<setw(8)<<gotoTable[title];
                }
                else
                    cout<<setw(8)<<"";
            }
            cout<<endl;
        }

        cout<<endl<<"LR分析表构建完成"<<endl<<endl;
    }


    //打印产生式
    void printP()
    {
        cout<<"语法的产生式为"<<endl;
        for(string left:NT)
        {
            cout<<left<<"->";
            for(auto it=production[left].begin(); it!=production[left].end(); it++)
            {
                if(it!=production[left].end()-1)
                    cout<<*it<<"|";
                else
                    cout<<*it<<endl;
            }
        }
        cout<<endl;
    }

    //打印状态表
    void printS()
    {
        cout<<"**********状态集合为**********"<<endl;
        for(State s:States)
        {
            cout<<"状态编号:"<<s.id<<endl;
            printI(s.items);
        }
        cout<<endl;
    }

    //打印状态转移函数
    void printGO()
    {
        cout<<"**********状态转移函数为**********"<<endl;
        for(GOTO go:GO)
        {
            cout<<go.from<<"---"<<go.path<<"-->"<<go.to<<endl;
        }
        cout<<endl;
    }

    //打印项目集
    void printI(set<Item>I)
    {
        cout<<"LR的项目集为"<<endl;
        for(Item i:I)
        {
            cout<<i.getItem()<<","<<i.getSymbol()<<endl;
        }
        cout<<endl;
    }
};
int main()
{
    string filename="grammar-input.txt";
    LR1 grammar(filename);
    grammar.printP();//输出产生式
    grammar.parser("Tokens.txt");

    return 0;
}
/*
测试文法:
S->id|V := E
V->id
E->V|n
*/

测试结果

在这里插入图片描述
在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【编译原理】LR(1)分析方法(c++实现) 的相关文章

  • 电子科技大学编译原理复习笔记(八):语义分析

  • 控制流分析之循环

    最近做科研碰到了如何识别程序热对象的问题 解决这个问题的一般思路是做静态分析 主要是分支概率和基本块频率的分析 目前 LLVM 里已经添加了这两种分析 然而 直接看相关的代码效率很低 主要原因是缺乏控制流分析方面的基础 导致代码中出现的许多
  • 合肥工业大学编译原理实验二 LL1分析

    写在开头 当老师说这个实验最好写成图形界面时 我笑了 滑稽 心想终于可以用到python了 python真香 用python的数据结构可以很方便的表示LL1的某些东西 当然有利也有弊 方便的同时也会有一些坑 当然Java也牛逼 Java的图
  • 编译原理 课程设计 LR(1)分析法

    作业目的 构造LR 1 分析程序 利用它进行语法分析 判断给出的符号串是否为该文法识别的句子 了解LR K 分析方法是严格的从左向右扫描 和自底向上的语法分析方法 作业题目 1 对下列文法 用LR 1 分析法对任意输入的符号串进行分析 0
  • C++实现的利用LR(1)分析表对赋值表达式进行语法制导翻译生成四元式及汇编代码

    赋值语句的语法制导翻译 后续已完善算术运算文法 赋值文法 布尔运算文法 if while do while和复合语句文法 编译器项目已上传GitHub https github com sleep jyx compiler 一 需要的语义过
  • 将NFA变成最小化DFA的方法

    学习的时候总感觉这个遇到新的题目不会做 这里总结一下 整个流程是这样的 我们直接来看一个例子 使用上面的算法来实现我们最后的目标 a b ba ab 我们先来画NFA 明确 开始状态和接受状态 终结状态要画两个圈 值得注意的是 由于 也可以
  • FLEX & BISON 联合使用

    flex是词法分析器 bison是语法分析器 基本原理就是flex解析出token后 让bison来使用 实际上 一般是先编写bison脚本 里面的token就是一个定义 没有实现 里面的yylex也是没有实现 只有定义 为什么先做biso
  • cucu: a compiler u can understand (part 2)

    原文地址 http blog csdn net roger wong article details 8502477 原文地址 http zserge com blog cucu part2 html 到目前为止 我们已经定义了我们语言的语
  • LLVM IR / LLVM指令集入门

    本文基于LLVM 12官方文档的LLVM Language Reference Manual 以学习笔记为主 所以本文会摘录一些常见 常用的指令 对于一些更加深层次的指令属性 特性 待我对LLVM有更深的理解再单独写文章记录 1 LLVM
  • 【编译原理】LALR(1)语法分析方法(c++实现)

    前文回顾 编译原理 LR 0 分析方法 c 实现 编译原理 SLR 1 分析方法 c 实现 编译原理 LR 1 分析方法 c 实现 这几个程序的代码大部分是一样的 根据不同算法特点做了部分修改而已 代码 LALR 1 的代码就是在LR 1
  • GDB 程序调试常用命令

    调试之前 若要在GDB中调试程序在编译时需要加上调试信息 在GCC中添加的方法 GCC g a c o a exe 或下面提供更符合GDB的调试信息 GCC ggdb a c o a exe 运行流程 命令 作用 start 开始执行程序
  • PL0语言出错编号表

    Notes 编译原理第 3 版的书貌似没有这个表 做实验和写课设的时候很不方便 把别人拍的第 2 版书上的这个表在这备份一份 Error Code Table 出错编号 出错原因 1 常数说明中的 写成 2 常数说明中的 后应是数字 3 常
  • LLVM SSA 介绍

    最近做研究碰到了一个难题 需要对程序变量按生命期进行重命名 考虑到 SSA 中一个变量在不同的程序分支中赋值时会进行重命名 因此打算以此作为参考 看看能否采取同样的方法达到目的 由于之前看到的文档中都说 LLVM IR 是 SSA 形式的
  • 编译原理 CS-143(更新至week4)

    编译原理 CS 143 Pre Course Survey Navigation Your Course 01 01 Introduction 8m20s 01 02 Structure of a Compiler 13m53s 编译器结构
  • The Backus-Naur Form (BNF) & The Extended Backus-Naur Form (EBNF)

    The Backus Naur Form BNF The Backus Naur Form BNF is a notation used for formal description of the syntax of programming
  • 编译原理实验二:Bison

    编译原理实验二 Bison 实验要求 1 了解Bision基础知识 如何将文法产生式转换为Bison语句 2 阅读 src common SyntaxTree c 对应头文件 include SyntaxTree h 理解分析树生成的过程
  • 编译原理绪论

    1 美图 5 编译过程一语法分析 任务 在词法分析的基础上 根据语言的语法规则把单词符号串分解成各类语法单位 语法范畴 依循的原则 语法规则 描述工具 上下文无关文法 6 编译过程一中间代码产生 任务 对各类不同语法范畴按语言的语义进行初步
  • OCaml 安装以及简单的加减乘除Demo(以Ubuntu16.04为例)

    安装nix 参考 https mirrors tuna tsinghua edu cn help nix 安装nix sh lt curl https mirrors tuna tsinghua edu cn nix latest inst
  • 【编译原理】LR(1)分析方法(c++实现)

    前文回顾 编译原理 LR 0 分析方法 c 实现 编译原理 SLR 1 分析方法 c 实现 算法 来自龙书第二版 代码 和SLR的区别其实只是DFA中多了一个搜索符 构建分析表的时候规约项的列是相应的搜索符而已 代码基本上就在SLR的代码上
  • linux下几种目标文件的分析

    本文中用到的命令 gcc c addvec c 生成可重定位目标文件addvec o readelf addvec o a 读取可重定位目标文件addvec o gcc O2 c main c 生成可重定位目标文件main o gcc st

随机推荐

  • QT开发遇到的问题(1)——程序循环执行的问题

    我之前一直直接用C 开发工程 有需求需要跨平台开发 前期使用时候感觉还可以 转到工程应用时候 就遇到好多坑 今天就遇到个大坑 在开发时候需要不断循环一块代码来实现某种功能 QT不像C 那种 这个更加专业 下面我对这个问题进行详细说明分析 问
  • ResultSet详解

    结果集 ResultSet 是数据中查询结果返回的一种对象 可以说结果集是一个存储查询结果的对象 但是结果集并不仅仅具有存储的功能 他同时还具有操纵数据的功能 可能完成对数据的更新等 结果集读取数据的方法主要是getXXX 他的参数可以是整
  • docker 入门指南

    docker Docker is an open platform for developing shipping and running applications Docker enables you to separate your a
  • Matlab零基础入门

    前言 本篇是随笔 一段时间没用Matlab 简单复习了下 都是入门知识 零基础可读 文章目录 1 初步认识界面和命名 2 数据类型和矩阵 3 元胞数组和结构体 3 1 元胞数组 3 2 eye 3 3 3 magic 3 4 结构体 4 矩
  • RNA-seq——学习路线、学习经验、实战项目、学习总结

    1 参考课程和博客 B站 RNA seq转录组数据分析入门实战 生信技能树 转录组测序数据分析 简书 RNA seq 1 用conda安装RNA seq所需要的工具 简书 RNA seq 2 1 原始数据下载的几种方法 简书 RNA seq
  • python接口自动化(三)--如何设计接口测试用例(详解)

    简介 上篇我们已经介绍了什么是接口测试和接口测试的意义 在开始接口测试之前 我们来想一下 如何进行接口测试的准备工作 或者说 接口测试的流程是什么 有些人就很好奇 接口测试要流程干嘛 不就是拿着接口文档直接利用接口 测试工具测试嘛 其实 如
  • 开发EduSoho v8.7.10 本地播放视频超时或者快进后网络错误导致视频下载中途失败。鉴权播放次数问题

    EduSoho v8 7 10 本地播放视频超时或者快进后网络错误导致视频下载中途失败 鉴权播放次数问题 文件路径 src AppBundle Twig WebExtension php protected function makeTok
  • CFileDialog 多文件选择注意事项

    当选择文件数量比较多的时候 发现CFileDialog返回文件名并不完整 翻阅MSDN发现文件名长度是有限制的 解决思路 CFileDialog dlgOpen TRUE T txt NULL OFN HIDEREADONLY OFN RE
  • 【转】游戏汉化之Tile全格式解读 by 阿一

    最近在破解一些图片的格式 并想导出PNG 不过老是记不住bpp的格式 转载之 方便查看 做些锚记 标准1BPP NDS 1BPP 标准2BPP VB 2BPP NGP 2BPP NES 2BPP 1BPP 1BPP GB 2BPP 1BPP
  • SpringCloud2架构图

    先来个简洁版 1 外部或者内部的非Spring Cloud项目都统一通过API网关 Zuul 来访问内部服务 zuul是对外暴露的唯一接口相当于路由的是controller的请求 2 网关接收到请求后 从注册中心 Eureka 获取可用服务
  • Unity泛光效果消失问题

    关于Unity泛光效果消失问题解决过程 问题描述 第一次尝试解决 第二次尝试解决 第三次尝试解决 问题描述 之前一直在做的一个项目 在一次想要添加UI泛光效果失败后 发现项目中已有的泛光效果也消失了 第一次尝试解决 因为问题是在添加插件Po
  • linux服务器编译报错:DSO missing from command line原因及解决办法

    报错信息提示包含以下两行 undefined reference to symbol libfastrtps so 1 error adding symbols DSO missing from command line 原因 提示说符号没
  • SpringMVC异常处理

    为了统一处理代码运行过程中出现的异常 给用户一个更友好的异常界面 需要引入springMVC的异常处理功能 为了演示这个功能 本文实现一个比较常用的需求 将所有的异常归为两类 一类是程序员自己创建的异常类 另一类是系统或框架定义的异常类 程
  • junit如何测试没有返回值的方法

    方法里总有些操作 只要测试结果对就可以了 没有必要说非要有返回值 马士兵
  • 深入理解 SQL 中的 Grouping Sets 语句

    前言 SQL 中 Group By 语句大家都很熟悉 根据指定的规则对数据进行分组 常常和聚合函数一起使用 比如 考虑有表 dealer 表中数据如下 id Int city String car model String quantity
  • Linux系统下ping命令报错 name or service not know

    问题描述 CentOS 但是当执行ping命令的时候 提示name or service not known 解决方法 1 添加DNS服务器 1 vi etc resolv conf 进入编辑模式 增加如下两行内容 分别是首选DNS服务器和
  • logback--进阶--05--自定义Appenders

    logback 进阶 05 自定义Appenders 代码位置 https gitee com DanShenGuiZu learnDemo tree master logback learn 1 介绍 1 1 继承关系图 可以看到Appe
  • C++ 多态和虚函数

    一 先搞清override overload overwrite的区别 1 overload 重载 不是多态 在C 程序中 可以将语义 功能相似的几个函数用同一个名字表示 但参数不同 包括类型 顺序不同 即函数重载 1 相同的范围 在同一个
  • 药明康德成都研发中心投入运营;中国白酒行业净利润将迎来七年来首次下滑

    今日看点 药明康德成都研发中心正式投入运营 该研发中心将成为药明康德上海研发总部以外 又一个覆盖化学及生物学的新药发现整体研发平台 将为客户提供从小分子药物设计 合成 分析 体内体外生物学 肿瘤免疫学等全方位 一体化的新药研发服务 该研发中
  • 【编译原理】LR(1)分析方法(c++实现)

    前文回顾 编译原理 LR 0 分析方法 c 实现 编译原理 SLR 1 分析方法 c 实现 算法 来自龙书第二版 代码 和SLR的区别其实只是DFA中多了一个搜索符 构建分析表的时候规约项的列是相应的搜索符而已 代码基本上就在SLR的代码上