• 编译原理--语法分析之LR分析法的简单实现



    清晰记得本次实验在推了两次项目集规范簇之后,发现文档中给出的文法有错误,联系老师得到改正后,遂顺利完成。简单记录一下本次实验的经历,留作以后备用,若有错误之处,还请路过的博友不吝赐教。

    实验设计目标

    构造LR(1)分析程序,利用它进行语法分析,判断给出的符号串是否为该文法识别的句子。

    实验原理

    整体思路:在总控程序的控制下,从左到右扫描输入符号串,根据状态栈中的栈顶状态、符号栈中的栈顶字符和文法及当前输入符号,按分析表完成相应的分析工作。

    LR分析器由三个部分组成:

    • 总控程序,也可以称为驱动程序。对所有的LR分析器总控程序都是相同的。
    • 分析表或分析函数,不同的文法分析表将不同,同一个文法采用的LR分析器不同时,分析表将不同,分析表又可以分为动作表(ACTION)和状态转换(GOTO)表两个部分,它们都可用二维数组表示。
    • 分析栈,包括文法符号栈和相应的状态栈,它们均是先进后出栈。
      • 分析器的动作就是由栈顶状态和当前输入符号所决定。

        GOTO[i,X]=j表示,规定当栈顶状态为i,遇到当前文法符号为X时应转向状态j,X为非终结符。

        ACTION[i,a]规定了栈顶状态为i时,遇到输入符号a应执行的动作有四种可能:

      1.  移进:

        action[i,a]= Sj:状态 j 移入到状态栈,把 a 移入到文法符号栈,其中 i , j 表示状态号。

      2. 归约:

        action[i,a]=Rk:当在栈顶形成句柄时,则归约为相应的非终结符A,即文法中有A->B的产生式,若B的长度为R(即|B|=R),则从状态栈和文法符号栈中自顶向下去掉R个符号,即栈指针SP减去R,并把A移入文法符号栈内,j=GOTO[i,A]移进状态栈,其中i为修改指针后的栈顶状态。

      3. 接收Acc:

        当归约到文法符号栈中只剩文法的开始符号S时,并且输入符号串已结束即当前输入符是'#',则为分析成功。

      4. 报错:

        当遇到状态栈顶为某一状态下出现不该遇到的文法符号时,则报错,说明输入端不是该文法能接受的符号串。

    实验文法

     (0)S->E         

     (1)E->E+T

     (2)E->E-T        

     (3)E->T

     (4)T->F         

     (5)T->T*F

     (6)T->T/F      

     (7)F->(E)

     (8)F->i

    实验输入、输出

    1. 输入数据:

        case1: i+i*i#

        case2: i+i*#

    2. 输出结果:

    实验实现过程

    1. 首先就是秃头三次的项目集规范簇(一开始打算手写来着,画满一张A4纸之后, Visio好香啊……)

    这里我是采用类似DFS深度遍历的思想来画的,对于一个输入就按着他一个输入分支往下画,直到不能再往下扩展。便回溯将前边的分支填充,所以画出来的最后的图片就出现了这样一个特点,靠前的很多分支都是直接写编号就可以了。当然也可以采用像BFS遍历的思想来画,个人感觉效果应该是一样的。

      2. 那有了项目集规范簇,接下来就要构建相应的Action表和Goto表了,这里照着项目集规范簇来并不难,麻烦的是将其转换为代码中对应的表(建表时,眼都看花了……)

      • Action表

     

      • Goto表:

     

      3. 有了Action表和Goto表,剩下的就好办了,为了能更好的理清思路,我又画了LR(1)控制器的流程图。

    代码实现部分

    (待实验统计完毕之后,在统一上传一下XD)

    2020/6/29

    LR.h

    #include <iostream>
    #include <string>
    #include <vector>
    #include <iomanip>
    #include "LRTable.h"
    #ifndef _LR_H
    #define _LR_H
    
    using namespace std;
    
    class Analyser{
    private:
        string str; //被分析的字符串
        int step;   //步骤
        int idx;    //当前分析符号的下标
        vector<char> sign;  //符号栈
        vector<int> status; //状态栈
    
    public:
        Analyser();
        ~Analyser();
        bool startAnalyse(string str);
        string transformStackToStr(int opt);
    };
    
    Analyser::Analyser()
    {
        this->step = 1;
        this->idx = 0;
    }
    
    Analyser::~Analyser(){}
    
    string Analyser::transformStackToStr(int opt)
    {
        string str = "";
        //返回状态栈
        if(opt == 0)
        {
            vector<int>::iterator iter = status.begin();
            bool isfirst = true;
            for(;iter != status.end();iter++)
            {
                if(isfirst)
                {
                    isfirst = false;
                    str += to_string(*iter);
                }
                else
                {
                    str += "_"+to_string(*iter);
                }
            }
        }
        else//返回符号栈
        {
            vector<char>::iterator iter = sign.begin();
            for(; iter != sign.end(); iter++)
            {
                str += *iter;
            }
        }
        return str;
    }
    
    
    bool Analyser::startAnalyse(string nowStr)
    {
        this->str = nowStr;
        //将初始状态输入到栈中
        sign.push_back('#');
        status.push_back(0);
        LRAnalyseTable table;
    
        //当前的状态
        int nowStatus = 0;
    
        //初始说明
        cout<<setw(10)<<"步骤"<<setw(15)<<"状态栈"<<setw(10)<<"符号栈"<<setw(15)<<"当前符号"<<setw(15)<<"剩余字符串"<<setw(20)<<"动作说明"<<endl;
        
    
        while(table.getAction(nowStatus, str[idx]) != 0)
        {
            
            int result = table.getAction(nowStatus, str[idx]);
            //输出错误的情况信息
            if(result == -1)
            {
                printf("error! 在输入符号: %c 处出现错误,符号坐标为: %d
    ", str[idx], idx);
                return false;
            }
    
            if(result > 0)//移进操作
            {
                cout<<setw(10)<<step<<setw(15)<<transformStackToStr(0)<<setw(10)<<transformStackToStr(1)<<setw(15)<<str[idx]<<setw(15)<<str.substr(idx)<<setw(20)<<"Action["<<status.back()<<"]["<<str[idx]<<"]=S"<<result<<" 移进状态"<<endl;
                status.push_back(result);
                sign.push_back(str[idx]);
                idx++;
            }
            else if(result <= -10)//规约操作
            {
                //还原归约所用产生式的下标
                result += 10;
                result = -result;
                string rule = table.getGrammer(result);
    
                cout<<setw(10)<<step<<setw(15)<<transformStackToStr(0)<<setw(10)<<transformStackToStr(1)<<setw(15)<<str[idx]<<setw(15)<<str.substr(idx)<<setw(20)<<"R"<<result<<""+rule+"归约"<<endl;
                //弹出产生式右端的符号和状态
                step++;
                for(int i=rule.size()-1; rule[i]!='>' && i>=0; i--)
                {
                    status.pop_back();
                    sign.pop_back();
                }
    
                nowStatus = status.back();
                result = table.getGoto(nowStatus, rule[0]);
                cout<<setw(10)<<step<<setw(15)<<transformStackToStr(0)<<setw(10)<<transformStackToStr(1)<<setw(15)<<rule[0]<<setw(15)<<str.substr(idx)<<setw(20)<<"Goto["<<nowStatus<<"]["<<rule[0]<<"]="<<result<<" 状态转移"<<endl;
                status.push_back(result);
                sign.push_back(rule[0]);
            }
            //获取当前状态栈的状态
            nowStatus = status.back();
            step++;
        }
        cout<<setw(10)<<step<<setw(15)<<transformStackToStr(0)<<setw(10)<<transformStackToStr(1)<<setw(15)<<str[idx]<<setw(15)<<str.substr(idx)<<setw(20)<<" 分析完成"<<endl;
        return true;
    }
    
    #endif

    LRTable.h

    #include <string>
    #ifndef _LRTABLE_H
    #define _LRTABLE_H
    
    using namespace std;
    
    class LRAnalyseTable
    {
    private:
        //产生式
        string grammer[15] = {"S->E", "E->E+T", "E->E-T", "E->T", "T->F", "T->T*F", "T->T/F","F->(E)", "F->i"};
        //终结符
        char terminalChar[10] = {'+','-','*', '/', '(', ')','i','#'};
        //非终结符
        char nonTerminalChar[10] = {'E','F','T'};
        //终结符的个数
        int numTerminalChar = 8;
        //非终结符的个数
        int numNonTerminalChar = 3;
    
    
        //初始化LR(1)分析表
        //action表
        int Action[50][8] = {
            {-1, -1, -1, -1, 6, -1, 23, -1},{2, 28, -1, -1, -1, -1, -1, 0},// 0 1
            {-1, -1, -1, -1, 6, -1, 23, -1},{-11, -11, 4, 24, -1, -1, -1, -11},//2 3
            {-1, -1, -1, -1, 6, -1, 23, -1},{-15, -15, -15, -15, -1, -1, -1 ,-15},//4 5
            {-1, -1, -1, -1, 13, -1, 20, -1},{9, 16, -1, -1, -1, 8, -1, -1},//6 7
            {-17, -17, -17, -17, -1, -1, -1, 7},{-1, -1, -1, -1, 13, -1, 20, -1},//8 9
            {-11, -11, -11, 18, -1, 1 ,-1, -1},{-1, -1, -1, -1, 13, -1, 20, -1},//10 11
            {-15, -15, -15, -15, -1, -15, -1, -1},{-1, -1, -1, -1, 13, -1, 20, -1},//12 13
            {9, 16, -1, -1, -1, 15, -1, -1},{-17, -17, -17, -17, -1, -17, -1, -1},//14 15
            {-1, -1, -1, -1, 13, -1, 20, -1},{-12, -12, 11, 18, -1, -12, -1, -1},//16 17
            {-1, -1, -1, -1, 13, -1, 20,-1},{-16, -16, -16, -16, -1, -16, -1, -1},//18 19
            {-18, -18, -18, -18, -1, -18, -1, -1},{-14, -14, -14, -14, -1, -14, -1, -1},//20 21
            {-13, -13, 11, 18, -1, -13, -1, -1},{-18, -18, -18, -18, -1, -1, -1, -18},//22 23
            {-1, -1, -1, -1, 6, 23, -1, -1},{-16, -16, -16, -16, -1, -1, -1, -16},//24 25
            {-14, -14, -14, -14, -1, -1, -1, -14},{-13, -13, 4, 24, -1, -1, -1, -13},//26 27
            {-1, -1, -1, -1, 6, -1, 23, -1}//28
        };
        //goto表
        int Goto[50][4] = {
            {1, 26, 27},{-1, -1, -1},//0 1
            {-1, 26, 3},{-1, -1, -1},//2 3
            {-1, 5, -1},{-1, -1, -1},//4 5
            {7, 21, 22},{-1, -1, -1},//6 7
            {-1, -1, -1},{-1, 21, 10},//8 9
            {-1, -1, -1},{-1, 12, -1},//10 11
            {-1, -1, -1},{14, 21, 22},//12 13
            {-1, -1, -1},{-1, -1, -1},//14 15
            {-1, 21, 17},{-1, -1, -1},//16 17
            {-1, 19, -1},{-1, -1, -1},//18 19
            {-1, -1, -1},{-1, -1, -1},//20 21
            {-1, -1, -1},{-1, -1, -1},//22 23
            {-1, 5, -1},{-1, -1, -1},//24 25
            {-1, -1, -1},{-1, -1, -1},//26 27
            {-1, 26, 3}//28
        };
    
    
    public:
        LRAnalyseTable();
        ~LRAnalyseTable();
        int getTerminalIndex(char ch);
        int getNonTerminalIndex(char ch);
        int getAction(int status, char ch);
        int getGoto(int status, char ch);
        string getGrammer(int idx);
    };
    
    LRAnalyseTable::LRAnalyseTable(/* args */)
    {
    
    }
    
    LRAnalyseTable::~LRAnalyseTable()
    {
    
    }
    
    int LRAnalyseTable::getAction(int status, char ch)
    {
        return Action[status][getTerminalIndex(ch)];
    }
    
    int LRAnalyseTable::getGoto(int status, char ch)
    {
        return Goto[status][getNonTerminalIndex(ch)];
    }
    
    string LRAnalyseTable::getGrammer(int idx)
    {
        return grammer[idx];
    }
    
    //获取终结符的下标
    int LRAnalyseTable::getTerminalIndex(char ch){
        for(int i=0; i<numTerminalChar; i++)
        {
            if(ch == terminalChar[i])
            {
                return i;
            }    
        }
        return -1;
    }
    
    //获得非终结符的下标
    int LRAnalyseTable::getNonTerminalIndex(char ch){
        for(int i=0; i<numNonTerminalChar; i++)
        {
            if(ch == nonTerminalChar[i])
            {
                return i;
            }    
        }
        return -1;
    }
    
    
    #endif

    test.cpp

    #include <iostream>
    #include <string>
    #include <stack>
    #include <vector>
    #include <iomanip>
    #include "LR.h"
    
    using namespace std;
    
    int main(){
        freopen("in.txt","r", stdin);
        freopen("out.txt", "w", stdout);
        string str="";
        int cnt = 1;
        while(getline(cin, str))
        {
            str = str.substr(0, str.size()-1);
            cout<<"Case"<<cnt++<<": "<<str<<endl;
            Analyser analyse;
            if(analyse.startAnalyse(str)){
                cout<<"输入符号串"<<str<<"为合法符号串"<<endl;
            }else{
                cout<<"输入符号串"<<str<<"为非法符号串"<<endl;
            }
        }
        return 0;
    }
  • 相关阅读:
    F系列车牌识别设备
    金蝶云星空安装及卸载教程
    RG-RAC256高性能无线控制器
    关于IP网段划分
    Win10关闭自动更新的三种方法
    锐捷网络RG-S2528G-24P
    光纤信号的传输距离
    POE交换机
    光纤收发器
    大华工具管家 1.01.1官方版
  • 原文地址:https://www.cnblogs.com/sykline/p/13197470.html
Copyright © 2020-2023  润新知