笔记-编译原理-实验三-自下而上语法分析-SLR分析法

实验三. 自上而下语法分析

设计思想

根据对自下而上语法分析的理论知识的学习,可以知道自下而上语法分析的两种实现方法:算符优先分析法和LR分析法,本实验采用后者LR分析法

本实验对PL0文法的表达式文法进行设计自下而上语法分析,表达式巴斯克范式如下:

文法的初始化

< 表 达 式 > : : = [ + ∣ − ] < 项 > { < 加 法 运 算 符 > < 项 > } < 项 > : : = < 因 子 > { < 乘 法 运 算 符 > < 因 子 > } < 因 子 > : : = < 标 识 符 > ∣ < 无 符 号 整 数 > ∣ ′ ( ′ < 表 达 式 > ′ ) ′ < 加 法 运 算 符 > : : = + ∣ − < 乘 法 运 算 符 > : : = ∗ ∣ / \begin{aligned} & <表达式> ::= [+|-]<项>\{<加法运算符> <项>\} \\ & <项> ::= <因子>\{<乘法运算符> <因子>\} \\ & <因子> ::= <标识符>|<无符号整数>| '('<表达式>')' \\ & <加法运算符> ::= +|- \\ & <乘法运算符> ::= *|/ \end{aligned} <>::=[+]<>{<><>}<>::=<>{<><>}<>::=<><>(<>)<>::=+<>::=/

对以上文字描述的文法可以给出对应的英文表示,以及对应的非终结符的 F i r s t 集 合 First集合 First F o l l o w 集 合 Follow集合 Follow

< E x p r e s s i o n > : : = [ + ∣ − ] < T e r m > { < A d d o p > < T e r m > } < T e r m > : : = < F a c t o r > { < M u l o p > < F a c t o r > } < F a c t o r > : : = < I d e n t > ∣ < U n s i g n I n t > ∣ ( < E x p r e s s i o n > ) < A d d o p > : : = + ∣ − < M u l o p > : : = ∗ ∣ / \begin{aligned} & <Expression> ::= [+|-]<Term>\{<Addop> <Term>\} \\ & <Term> ::= <Factor>\{<Mulop> <Factor>\} \\ & <Factor> ::= <Ident> | <UnsignInt> | (<Expression>) \\ & <Addop> ::= + | - \\ & <Mulop> ::= * | / \\ \end{aligned} <Expression>::=[+]<Term>{<Addop><Term>}<Term>::=<Factor>{<Mulop><Factor>}<Factor>::=<Ident><UnsignInt>(<Expression>)<Addop>::=+<Mulop>::=/

该文法的非终结符结合以及终结符集合如下:
V T = { + , − , ∗ , / , ( , ) , I d e n t , U n s i g n I n t } V N = { E x p r e s s i o n , T e r m , A d d o p , F a c t o r , M u l o p } \begin{aligned} & V_T = \{+, -, *, /, (, ), Ident, UnsignInt\} \\ & V_N = \{Expression, Term, Addop, Factor, Mulop\} \\ \end{aligned} VT={+,,,/,(,),Ident,UnsignInt}VN={Expression,Term,Addop,Factor,Mulop}

F i r s t 集 合 First集合 First :

F i r s t ( E x p r e s s i o n ) = { + , − , I d e n t , U n s i g n I n t , ( } F i r s t ( T e r m ) = { I d e n t , U n s i g n I n t , ( } F i r s t ( F a c t o r ) = { I d e n t , U n s i g n I n t , ( } F i r s t ( A d d o p ) = { + , − } F i r s t ( M u l o p ) = { ∗ , / } \begin{aligned} & First(Expression) = \{+, -, Ident, UnsignInt, (\} \\ & First(Term) = \{Ident, UnsignInt, (\} \\ & First(Factor) = \{Ident, UnsignInt, (\} \\ & First(Addop) = \{+, -\} \\ & First(Mulop) = \{*, /\} \\ \end{aligned} First(Expression)={+,,Ident,UnsignInt,(}First(Term)={Ident,UnsignInt,(}First(Factor)={Ident,UnsignInt,(}First(Addop)={+,}First(Mulop)={,/}

F o l l o w 集 合 Follow集合 Follow :

F o l l o w ( S ′ ) = { # } F o l l o w ( E x p r e s s i o n ) = { # , + , − , ) } F o l l o w ( T e r m ) = { # , + , − , ∗ , / , ) } F o l l o w ( F a c t o r ) = { # , + , − , ∗ , / , ) } \begin{aligned} & Follow(S') = \{\#\} \\ & Follow(Expression) = \{\#, +, -, )\} \\ & Follow(Term) = \{\#, +, -, *, /, )\} \\ & Follow(Factor) = \{\#, +, -, *, /, )\} \\ \end{aligned} Follow(S)={#}Follow(Expression)={#,+,,)}Follow(Term)={#,+,,,/,)}Follow(Factor)={#,+,,,/,)}

将其简化一下文法:

E → T ∣ + T ∣ − T E → E + T ∣ E − T T → F T → T ∗ F ∣ T / F F → i ∣ u ∣ ( E ) \begin{aligned} E & \to T | +T | -T \\ E & \to E + T | E - T\\ T & \to F \\ T & \to T * F | T / F \\ F & \to i | u | (E) \\ \end{aligned} EETTFT+TTE+TETFTFT/Fiu(E)

对应的终结符和非终结符集合如下:

V T = { + , − , ∗ , / , ( , ) , i , u } V N = { S ′ , E , T , F } \begin{aligned} & V_T = \{+, -, *, /, (, ), i, u\} \\ & V_N = \{S', E, T, F\} \end{aligned} VT={+,,,/,(,),i,u}VN={S,E,T,F}

拓广文法

文法的拓广,将文法 G ( S ) G(S) G(S) 拓广为 G ′ ( S ′ ) G'(S') G(S) ,并规定每一个产生式的编号,以便后续的方便使用:

0 : S ′ → E 1 : E → T 2 : E → + T 3 : E → − T 4 : E → E + T 5 : E → E − T 6 : T → F 7 : T → T ∗ F 8 : T → T / F 9 : F → i 10 : F → u 11 : F → ( E ) \begin{aligned} & 0: & S &' \to E \\ & 1: & E & \to T \\ & 2: & E & \to +T \\ & 3: & E & \to -T \\ & 4: & E & \to E + T \\ & 5: & E & \to E - T \\ & 6: & T & \to F \\ & 7: & T & \to T * F \\ & 8: & T & \to T / F \\ & 9: & F & \to i \\ & 10: & F & \to u \\ & 11: & F & \to (E) \\ \end{aligned} 0:1:2:3:4:5:6:7:8:9:10:11:SEEEEETTTFFFET+TTE+TETFTFT/Fiu(E)

构造识别活前缀的DFA

由此DFA可以看出,某些状态存在“规约-移进”冲突,所以可以通过SLR分析法的方式来尝试构造分析表,构造出此时构造出的分析表显然没有冲突:

SLR分析表

+ − ∗ / ( ) i u # E T F 0 s 5 s 4 s 8 s 6 s 7 1 2 3 1 s 9 s 10 a c c 2 r 1 r 1 s 11 s 12 r 1 r 1 3 r 6 r 6 r 6 r 6 r 6 r 6 4 13 5 14 6 r 9 r 9 r 9 r 9 r 9 r 9 7 r 10 r 10 r 10 r 10 r 10 r 10 8 s 5 s 4 s 8 s 6 s 7 15 2 3 9 s 8 s 6 s 7 16 3 10 s 8 s 6 s 7 17 3 11 s 8 s 6 s 7 18 12 s 8 s 6 s 7 19 13 r 3 r 3 r 3 r 3 14 r 2 r 2 r 2 r 2 15 s 9 s 10 s 20 16 r 4 r 4 s 11 s 12 r 4 r 4 17 r 5 r 5 s 11 s 12 r 5 r 5 18 r 7 r 7 r 7 r 7 r 7 r 7 19 r 8 r 8 r 8 r 8 r 8 r 8 20 r 11 r 11 r 11 r 11 r 11 r 11 \begin{array}{c|c} \hline & + & - & * & / & ( & ) & i & u & \# & E & T & F \\ \hline 0 & s5 & s4 & & & s8 & & s6 & s7 & & 1 & 2 & 3 \\ \hline 1 & s9 & s10 & & & & & & & acc & & & \\ \hline 2 & r1 & r1 & s11 & s12 & & r1 & & & r1 & & & \\ \hline 3 & r6 & r6 & r6 & r6 & & r6 & & & r6 & & & \\ \hline 4 & & & & & & & & & & & 13 & \\ \hline 5 & & & & & & & & & & & 14 & \\ \hline 6 & r9 & r9 & r9 & r9 & & r9 & & & r9 & & & \\ \hline 7 & r10 & r10 & r10 & r10 & & r10 & & & r10 & & & \\ \hline 8 & s5 & s4 & & & s8 & & s6 & s7 & & 15 & 2 & 3 \\ \hline 9 & & & & & s8 & & s6 & s7 & & & 16 & 3 \\ \hline 10 & & & & & s8 & & s6 & s7 & & & 17 & 3 \\ \hline 11 & & & & & s8 & & s6 & s7 & & & & 18 \\ \hline 12 & & & & & s8 & & s6 & s7 & & & & 19 \\ \hline 13 & r3 & r3 & & & & r3 & & & r3 & & & \\ \hline 14 & r2 & r2 & & & & r2 & & & r2 & & & \\ \hline 15 & s9 & s10 & & & & s20 & & & & & & \\ \hline 16 & r4 & r4 & s11 & s12 & & r4 & & & r4 & & & \\ \hline 17 & r5 & r5 & s11 & s12 & & r5 & & & r5 & & & \\ \hline 18 & r7 & r7 & r7 & r7 & & r7 & & & r7 & & & \\ \hline 19 & r8 & r8 & r8 & r8 & & r8 & & & r8 & & & \\ \hline 20 & r11 & r11 & r11 & r11 & & r11 & & & r11 & & & \\ \hline \end{array} 01234567891011121314151617181920+s5s9r1r6r9r10s5r3r2s9r4r5r7r8r11s4s10r1r6r9r10s4r3r2s10r4r5r7r8r11s11r6r9r10s11s11r7r8r11/s12r6r9r10s12s12r7r8r11(s8s8s8s8s8s8)r1r6r9r10r3r2s20r4r5r7r8r11is6s6s6s6s6s6us7s7s7s7s7s7#accr1r6r9r10r3r2r4r5r7r8r11E115T2131421617F33331819

得到分析表后,就可以根据LR分析的程序框架完成总控程序等的编写,由上一次的 自上而下的SLR分析表法 的代码可以简单的修改一些代码,便可实现整个分析程序的编写。

算法流程

源程序

整个SLR分析程序是由上一实验的预测分析程序修改而来,根据SLR分析的所需,简单的修改了分析表的构成,即由ACTION和GOTO表组成,将原来的分析总控程序中的具体的执行流程根据LR分析法来修改,其他内容保持不变即可:

整个LR分析程序所设计到的类以及相互的关系如下:

项目地址

基础符号类

基础符号类作为一个符号类的基类,主要用途为使用基类指针来指引子类的终结符或非终结符,简化后续的操作。

// symbols.h
#ifndef symbols_h
#define symbols_h
#include<iostream>
/*
终结符和非终结符的一个共同的基类
这样可以通过基类来引用终结符和非终结符

*/
class symbols
{
private:
    /* data */
public:
    symbols(){};
    virtual ~symbols(){};
    virtual std::string getClassName(){
        return "symbols";
    }
    virtual void print(){};
};

#endif /*symbols_h*/

终结符类

终结符类继承至基础符号类,终结符由终结符的值和编码构成。

// symbolsVT.h
#ifndef symbolsVT_h
#define symbolsVT_h
#include<iostream>
#include"symbols.h"
/*
一个终结符
终结符由终结符的值和编码构成

*/
class symbolsVT : public symbols{
private:
    std::string word;   //终结符的值
    std::string code;   //词法分析后终结符的标识(编码)
public:
    symbolsVT(){}
    symbolsVT(std::string W, std::string C):word(W), code(C) {
        std::cerr<< "V_T: " << word << " " << code << " created..." << std::endl;
    }
    ~symbolsVT() {}
    std::string getClassName();
    std::string getWord();
    std::string getCode();
    void print();
};

#endif /*symbolsVT_h*/
// symbolsVT.cpp
#include<iostream>
#include"symbolsVT.h"

std::string symbolsVT::getClassName(){
    return "VT";
}
std::string symbolsVT::getWord(){
    return word;
}
std::string symbolsVT::getCode(){
    return code;
}
void symbolsVT::print(){
    std::cerr << "VT: " << word << " " << code << std::endl;
}

非终结符类

非终结符类与终结符类一样继承至基础符号类,非终结符由其左部的非终结符和有部一个一些产生式构成,产生式即为一些符号的排列,此处存储的是一些产生式的指针。

// symbolsVN.h
#ifndef symbolsVN_h
#define symbolsVN_h
#include<iostream>
#include"symbols.h"
#include"production.h"
const int maxnNum = 5;     // 一个终结符所有的产生式的数量
class production;
/*
非终结符
非终结符由其左部的非终结符和有部一个一些产生式构成
产生式即为一些符号的排列,此处存储的是一些产生式的指针
*/

class symbolsVN: public symbols{
private:
    std::string name;							// 非终结符左部名称X
    production *p[maxnNum];						// 产生式集合
    int num;
public:
    symbolsVN();
    symbolsVN(std::string);
    ~symbolsVN() {}
    std::string getClassName();
    std::string getName();
    void insertProduction(production *newp);	// 加入一个产生式
    production* getProductionIndexOf(int i);	// 获得第i个产生式
    production** getAllProduction();			// 获得所有的产生式
    void print();
};

#endif /*symbolsVN_h*/
// symbolsVN.cpp
#include<iostream>
#include"symbolsVN.h"

symbolsVN::symbolsVN(){
    num = 0;
}
symbolsVN::symbolsVN(std::string n):name(n){
    symbolsVN();
    std::cerr << "V_N: " << name << " created..." << std::endl;
}

std::string symbolsVN::getClassName(){
    return "VN";
}
std::string symbolsVN::getName(){
    return name;
}
void symbolsVN::insertProduction(production *newp){
    p[num++] = newp;
    return;
}
production* symbolsVN::getProductionIndexOf(int i){
    if(i >= num){
        std::cerr << "index overflow..." << std::endl;
        return NULL;
    }
    return p[i];
}
production** symbolsVN::getAllProduction(){
    return p;
}
void symbolsVN::print(){
    std::cerr << "VN: " << name << std::endl;
    std::cerr << "ALL production: " << std::endl;
    for(int i = 0; i < num; ++i){
        std::cerr << name << " \\to ";
        p[i]->print();
    }
    std::cerr << std::endl;
}

产生式类

一个产生式由一个左部的非终结符和一些右部的符号集合构成。

// production.h
#ifndef production_h
#define production_h
#include<iostream>
#include"symbols.h"
#include"symbolsVT.h"
#include"symbolsVN.h"
/*
产生式
一个产生式由一个左部的非终结符和一些右部的符号集合构成
*/

const int maxnLen = 10;        // 一个产生式的右部符号的数量
class symbolsVN;
class production
{
private:
    symbolsVN *vn;					// 产生式左部的非终结符
    symbols *pro[maxnLen];			// 产生式,由一些非终结符和终结符构成,故使用符号指针来指引
    int len;
public:
    production();
    production(symbolsVN *v);
    ~production(){}
    void push_back(symbols *a);		// 为产生式后部插入一个符号
    symbolsVN* getVN();				// 获得左部非终结符符号
    symbols** getProduction();		// 获得产生式指针数组
    int getLen();					// 获得产生式长度
    symbols* getProductionIndexOf(int i); // 获得产生式中第i个位置的符号
    void print();
};

#endif /*production_h*/
// production.cpp
#include<iostream>
#include"production.h"
#include"symbolsVT.h"
#include"symbolsVN.h"

production::production(){
    len = 0;
}
production::production(symbolsVN *v){
    vn = v;
    production();
    std::cerr << "A production of " << vn->getName() << " has created..." << std::endl;
}
void production::push_back(symbols *a){
    pro[len++] = a;
}
symbolsVN* production::getVN(){
    return vn;
}
symbols** production::getProduction(){
    return pro;
}
symbols* production::getProductionIndexOf(int i){
    if(i >= len){
        std::cerr << "index Overflow..." << std::endl;
        return NULL;
    }
    return pro[i];
}
int production::getLen(){
    return len;
}
void production::print(){
    std::cerr << vn->getName() << "->";
    for(int i = 0; i < len; ++i){
        if(pro[i]->getClassName() == "VT"){
            std::cerr << ((symbolsVT*)pro[i])->getWord();
        }
        else{
            std::cerr << ((symbolsVN*)pro[i])->getName();
        }
    }
    // std::cerr << std::endl;
}

分析表

分析表,由ACTION表和GOTO表构成,具体的状态内容由前期的DFA分析等得到:

// analysisTable.h
#ifndef analysisTable_h
#define analysisTable_h
#include<map>
#include"symbols.h"
#include"symbolsVN.h"
#include"symbolsVT.h"
#include"production.h"
const int NUMOFVT = 20;
const int NUMOFVN = 20;
const int NUMOFSTATE = 30;
const int NUMOFPRODUCTIONS = 30;
/*
分析表子程序
由前期的分析得到该文法的分析表,由ACTION表和GOTO表构成
*/
class ACTIONTable{
private:
    std::pair<char, int> ACTION[NUMOFSTATE][NUMOFVT];
    int numofstate;						// ACTION表状态的数量
    int numofsymbolsvt;					// ACTION表终结符的数量
    std::map<symbolsVT*, int> vtmap;    // 终结符对应在分析表中的位置
    int getVTMap(symbolsVT*);			// 获得终结符对应的编号
public:
    ACTIONTable();
    ACTIONTable(int);
    ~ACTIONTable(){}
    void setNumOfState(int);			// GOTO状态数量
    void insertVT(symbolsVT*);			// 插入一个终结符以及给一个对应的编号
    void insertSHIFT(int state, symbolsVT* vt, int numOfPro);       // 插入一个移进状态
    void insertREDUCE(int state, symbolsVT* vt, int numOfPro);      // 插入一个规约状态
    void insertACC(int state, symbolsVT* vt);                       // 插入一个acc状态
    std::pair<char, int> getACTION(int state, symbolsVT* vt);       // 获得一个ACTION信息
    void print();
};
class GOTOTable{
private:
    int GOTO[NUMOFSTATE][NUMOFVN];
    int numofstate;						// GOTO状态数量
    int numofsymbolsvn;
    std::map<symbolsVN*, int> vnmap;    // 非终结符对应在分析表中的位置
    int getVNMap(symbolsVN*);			// 获得非终结符对应的编号
public:
    GOTOTable();
    GOTOTable(int);
    ~GOTOTable(){}
    void setNumOfState(int);			// 设置GOTO表的状态数
    void insertVN(symbolsVN*);          // 插入一个非终结符
    void insert(int state, symbolsVN* vn, int numOfPro);    // 插入一个GOTO状态
    int get(int state, symbolsVN* vn);                      // 获得一个GOTO状态
    void print();
};
class analysisTable
{
private:
    ACTIONTable ACTION;                 // ACTION表
    GOTOTable GOTO;                     // GOTO表
    int numofstate;                     // 状态个数I_n
    int numofpro;                       // 产生式数量
    production* productions[NUMOFPRODUCTIONS];  // 产生式数组,下标即为编号
public:
    analysisTable(int ns);
    // analysisTable(int, int, int);
    ~analysisTable() {}
    void insertSymbols(symbols*);		// 插入一个符号
    void insertProduction(production* p);	// 插入一条产生式,自动编号
    production* getProduction(int i);	// 获得第i条产生式
    void insert(int state, symbols* s, char ch, int numOfPro);	// 插入一个状态
    std::pair<char, int> get(int state, symbols* s);	// 获得一个状态
    void print();
};

#endif /*analysisTable_h*/
// analysisTable.cpp
#include<iostream>
#include<algorithm>
#include<string.h>
#include"analysisTable.h"

ACTIONTable::ACTIONTable(){
    numofsymbolsvt = 0;
    vtmap.clear();
    std::pair<char, int> init = std::make_pair('e', -1);
    // fill(begin(ACTION), end(ACTION), std::make_pair('e', -1));
    for(int i = 0; i < NUMOFSTATE; ++i)
        for(int j = 0; j < NUMOFVT; ++j)
            ACTION[i][j] = init;
    std::cerr << "ACTIONTable has created..." << std::endl;
}
void ACTIONTable::setNumOfState(int ns){
    numofstate = ns;
}
int ACTIONTable::getVTMap(symbolsVT* vt){
    if(vtmap.find(vt) != vtmap.end())return vtmap[vt];
    return -1;
}
void ACTIONTable::insertVT(symbolsVT* vt){
    vtmap[vt] = numofsymbolsvt++;
}
void ACTIONTable::insertSHIFT(int state, symbolsVT* vt, int numOfPro){
    int nvt = getVTMap(vt);
    if(state < numofstate && ~nvt){
        ACTION[state][nvt] = std::make_pair('s', numOfPro);
    }
}
void ACTIONTable::insertREDUCE(int state, symbolsVT* vt, int numOfPro){
    int nvt = getVTMap(vt);
    if(state < numofstate && ~nvt){
        ACTION[state][nvt] = std::make_pair('r', numOfPro);
    }
}
void ACTIONTable::insertACC(int state, symbolsVT* vt){
    int nvt = getVTMap(vt);
    if(state < numofstate && ~nvt){
        ACTION[state][nvt] = std::make_pair('a', 0x3f3f3f3f);
    }
}
std::pair<char, int> ACTIONTable::getACTION(int state, symbolsVT* vt){
    int nvt = getVTMap(vt);
    if(state < numofstate && ~nvt){
        return ACTION[state][nvt];
    }
    return std::make_pair('e', -1);
}
void ACTIONTable::print(){
    std::cerr << "ACTION:" << std::endl;
    std::cerr << numofsymbolsvt << std::endl;
    std::cerr << "\t";
    // for(auto i: vtmap)std::cerr << i.first->getWord() << "\t";
    for(std::map<symbolsVT*, int>::iterator i = vtmap.begin(); i != vtmap.end(); ++i)std::cerr << i->first->getWord() << "\t";
    std::cerr << std::endl;
    for(int i = 0; i < numofstate; ++i){
        std::cerr << i << ": \t";
        for(int j = 0; j < numofsymbolsvt; ++j){
            if(~ACTION[i][j].second)
                std::cerr << ACTION[i][j].first << ACTION[i][j].second << " \t";
            else
                std::cerr << "   \t";
        }
        std::cerr << std::endl;
    }
    std::cerr << std::endl;
}


GOTOTable::GOTOTable(){
    numofsymbolsvn = 0;
    vnmap.clear();
    memset(GOTO, -1, sizeof GOTO);
    std::cerr << "GOTOTable has created..." << std::endl;
}
void GOTOTable::setNumOfState(int ns){
    numofstate = ns;
}
void GOTOTable::insertVN(symbolsVN* vn){
    vnmap[vn] = numofsymbolsvn++;
}
int GOTOTable::getVNMap(symbolsVN* vn){
    if(vnmap.find(vn) != vnmap.end())return vnmap[vn];
    return -1;
}
void GOTOTable::insert(int state, symbolsVN* vn, int numOfPro){
    int nvn = getVNMap(vn);
    if(state < numofstate && ~nvn){
        GOTO[state][nvn] = numOfPro;
    }
}
int GOTOTable::get(int state, symbolsVN* vn){
    int nvn = getVNMap(vn);
    if(state < numofstate && ~nvn){
        return GOTO[state][nvn];
    }
    return -1;
}
void GOTOTable::print(){
    std::cerr << "GOTO:" << std::endl;
    std::cerr << numofsymbolsvn << std::endl;
    std::cerr << "\t";
    // for(auto i: vnmap)std::cerr << i.first->getName() << "\t";
    for(std::map<symbolsVN*, int>::iterator i = vnmap.begin(); i != vnmap.end(); ++i)std::cerr << i->first->getName() << "\t";
    std::cerr << std::endl;
    for(int i = 0; i < numofstate; ++i){
        std::cerr << i << ": \t";
        for(int j = 0; j < numofsymbolsvn; ++j){
            if(~GOTO[i][j])
                std::cerr << GOTO[i][j] << "\t";
            else
                std::cerr << "   \t";
        }
        std::cerr << std::endl;
    }
    std::cerr << std::endl;
}


analysisTable::analysisTable(int ns):numofstate(ns){
    ACTION.setNumOfState(numofstate);
    GOTO.setNumOfState(numofstate);
    numofpro = 0;
    std::cerr << "An AnalysisTable has created..." << std::endl;
}
void analysisTable::insertSymbols(symbols* s){
    if(s->getClassName() == "VT"){
        ACTION.insertVT((symbolsVT*)(s));
    }
    else if(s->getClassName() == "VN"){
        GOTO.insertVN((symbolsVN*)(s));
    }
}
void analysisTable::insertProduction(production* p){
    productions[numofpro++] = p;
}
production* analysisTable::getProduction(int i){
    if(i < numofpro)return productions[i];
    // return nullptr;
    return NULL;
}
void analysisTable::insert(int state, symbols* s, char ch, int numOfPro){
    if(s->getClassName() == "VT"){
        if(ch == 'a'){
            ACTION.insertACC(state, (symbolsVT*)(s));
        }
        else if(ch == 's'){
            ACTION.insertSHIFT(state, (symbolsVT*)(s), numOfPro);
        }
        else if(ch == 'r'){
            ACTION.insertREDUCE(state, (symbolsVT*)(s), numOfPro);
        }
    }
    else if(s->getClassName() == "VN"){
        GOTO.insert(state, (symbolsVN*)(s), numOfPro);
    }
}
std::pair<char, int> analysisTable::get(int state, symbols* s){
    if(s->getClassName() == "VT"){
        return ACTION.getACTION(state, (symbolsVT*)(s));
    }
    else if(s->getClassName() == "VN"){
        return std::make_pair('g', GOTO.get(state, (symbolsVN*)(s)));
    }
    return std::make_pair('e', -1);
}
void analysisTable::print(){
    std::cerr << "analysisTable: " << std::endl;
    ACTION.print();
    GOTO.print();
    std::cerr << std::endl;
}

LR分析总控程序

根据LR分析程序编写的总控程序,包括初始化、读入、分析以及释放资源等:

// SLRAnalysis.cpp
#include<iostream>
#include<cstdio>
#include<string.h>
#include"symbols.h"
#include"symbolsVN.cpp"
#include"symbolsVT.cpp"
#include"production.cpp"
#include"analysisTable.cpp"
const int maxnAnalysisStack = 1e2 + 5;

// 定义出文法的所有终结符
symbolsVT* PLUS = new symbolsVT("+", "plus");
symbolsVT* MINUS = new symbolsVT("-", "minus");
symbolsVT* times = new symbolsVT("*", "times");
symbolsVT* slash = new symbolsVT("/", "slash");
symbolsVT* lparen = new symbolsVT("(", "lapren");
symbolsVT* rparen = new symbolsVT(")", "rparen");
symbolsVT* ident = new symbolsVT("i", "ident");
symbolsVT* unsignint = new symbolsVT("u", "unsignint");
symbolsVT* END = new symbolsVT("#", "end");
symbolsVT* epslion = new symbolsVT("e", "epslion");
// 定义出文法的所有非终结符
symbolsVN* Sdot = new symbolsVN("S'");
symbolsVN* E = new symbolsVN("E");
symbolsVN* T = new symbolsVN("T");
symbolsVN* F = new symbolsVN("F");

// 构造所有的产生式
production* Sdotproduction[1];
production* Eporduction[5];
production* Tproduction[3];
production* Fproduction[3];

// 定义出预测分析表
analysisTable AnalysisTable(21);

// 分析栈
std::pair<int, symbols*> analysisStack[maxnAnalysisStack];
int top;
void init(){
    // 初始化所有变量
	// 根据文法的不同,得到的分析表的结构也不同,此时初始化部分也不同

    // 定义出预测分析表
	// 为预测分析表插入终结符、非终结符
    AnalysisTable.insertSymbols(PLUS);
    AnalysisTable.insertSymbols(MINUS);
    AnalysisTable.insertSymbols(times);
    AnalysisTable.insertSymbols(slash);
    AnalysisTable.insertSymbols(lparen);
    AnalysisTable.insertSymbols(rparen);
    AnalysisTable.insertSymbols(ident);
    AnalysisTable.insertSymbols(unsignint);
    AnalysisTable.insertSymbols(END);

    AnalysisTable.insertSymbols(Sdot);
    AnalysisTable.insertSymbols(E);
    AnalysisTable.insertSymbols(T);
    AnalysisTable.insertSymbols(F);

    // 根据文法定义E的三条产生式,同理处理其他的产生式
    for(int i = 0; i < 1; ++i)Sdotproduction[i] = new production(Sdot);
    Sdotproduction[0]->push_back(E);
    Sdotproduction[0]->print();


    for(int i = 0; i < 5; ++i)Eporduction[i] = new production(E);

    Eporduction[0]->push_back(T);
    Eporduction[1]->push_back(PLUS); Eporduction[1]->push_back(T);
    Eporduction[2]->push_back(MINUS); Eporduction[2]->push_back(T);
    Eporduction[3]->push_back(E); Eporduction[3]->push_back(PLUS); Eporduction[3]->push_back(T);
    Eporduction[4]->push_back(E); Eporduction[4]->push_back(MINUS); Eporduction[4]->push_back(T);
    for(int i = 0; i < 5; ++i)E->insertProduction(Eporduction[i]);
    for(int i = 0; i < 5; ++i)Eporduction[i]->print();
    
    for(int i = 0; i < 3; ++i)Tproduction[i] = new production(T);
    Tproduction[0]->push_back(F);
    Tproduction[1]->push_back(T); Tproduction[1]->push_back(times); Tproduction[1]->push_back(F);
    Tproduction[2]->push_back(T); Tproduction[2]->push_back(slash); Tproduction[2]->push_back(F);
    for(int i = 0; i < 3; ++i)T->insertProduction(Tproduction[i]);
    for(int i = 0; i < 3; ++i)Tproduction[i]->print();

    
    for(int i = 0; i < 3; ++i)Fproduction[i] = new production(F);
    Fproduction[0]->push_back(ident);
    Fproduction[1]->push_back(unsignint);
    Fproduction[2]->push_back(lparen); Fproduction[2]->push_back(E); Fproduction[2]->push_back(rparen);
    for(int i = 0; i < 3; ++i)F->insertProduction(Fproduction[i]);
    for(int i = 0; i < 3; ++i)Fproduction[i]->print();   

    for(int i = 0; i < 1; ++i)AnalysisTable.insertProduction(Sdotproduction[i]);
    for(int i = 0; i < 5; ++i)AnalysisTable.insertProduction(Eporduction[i]);
    for(int i = 0; i < 3; ++i)AnalysisTable.insertProduction(Tproduction[i]);
    for(int i = 0; i < 3; ++i)AnalysisTable.insertProduction(Fproduction[i]);

    // 给出LR分析表
    AnalysisTable.insert(0, PLUS, 's', 5); AnalysisTable.insert(0, MINUS, 's', 4); AnalysisTable.insert(0, lparen, 's', 8); AnalysisTable.insert(0, ident, 's', 6); AnalysisTable.insert(0, unsignint, 's', 7); AnalysisTable.insert(0, E, ' ', 1); AnalysisTable.insert(0, T, ' ', 2); AnalysisTable.insert(0, F, ' ', 3);
    AnalysisTable.insert(1, PLUS, 's', 9); AnalysisTable.insert(1, MINUS, 's', 10); AnalysisTable.insert(1, END, 'a', -1);
    AnalysisTable.insert(2, PLUS, 'r', 1); AnalysisTable.insert(2, MINUS, 'r', 1); AnalysisTable.insert(2, times, 's', 11); AnalysisTable.insert(2, slash, 's', 12); AnalysisTable.insert(2, rparen, 'r', 1); AnalysisTable.insert(2, END, 'r', 1);
    AnalysisTable.insert(3, PLUS, 'r', 6); AnalysisTable.insert(3, MINUS, 'r', 6); AnalysisTable.insert(3, times, 'r', 6); AnalysisTable.insert(3, slash, 'r', 6); AnalysisTable.insert(3, rparen, 'r', 6); AnalysisTable.insert(3, END, 'r', 6);
    AnalysisTable.insert(4, T, ' ', 13);
    AnalysisTable.insert(5, T, ' ', 14);
    AnalysisTable.insert(6, PLUS, 'r', 9); AnalysisTable.insert(6, MINUS, 'r', 9); AnalysisTable.insert(6, times, 'r', 9); AnalysisTable.insert(6, slash, 'r', 9); AnalysisTable.insert(6, rparen, 'r', 9); AnalysisTable.insert(6, END, 'r', 9);
    AnalysisTable.insert(7, PLUS, 'r', 10); AnalysisTable.insert(7, MINUS, 'r', 10); AnalysisTable.insert(7, times, 'r', 10); AnalysisTable.insert(7, slash, 'r', 10); AnalysisTable.insert(7, rparen, 'r', 10); AnalysisTable.insert(7, END, 'r', 10);
    AnalysisTable.insert(8, PLUS, 's', 5); AnalysisTable.insert(8, MINUS, 's', 4); AnalysisTable.insert(8, lparen, 's', 8); AnalysisTable.insert(8, ident, 's', 6); AnalysisTable.insert(8, unsignint, 's', 7); AnalysisTable.insert(8, E, ' ', 15); AnalysisTable.insert(8, T, ' ', 2); AnalysisTable.insert(8, F, ' ', 3);
    AnalysisTable.insert(9, lparen, 's', 8); AnalysisTable.insert(9, ident, 's', 6); AnalysisTable.insert(9, unsignint, 's', 7); AnalysisTable.insert(9, T, ' ', 16); AnalysisTable.insert(9, F, ' ', 3);
    AnalysisTable.insert(10, lparen, 's', 8); AnalysisTable.insert(10, ident, 's', 6); AnalysisTable.insert(10, unsignint, 's', 7); AnalysisTable.insert(10, T, ' ', 17); AnalysisTable.insert(10, F, ' ', 3);
    AnalysisTable.insert(11, lparen, 's', 8); AnalysisTable.insert(11, ident, 's', 6); AnalysisTable.insert(11, unsignint, 's', 7); AnalysisTable.insert(11, F, ' ', 18);
    AnalysisTable.insert(12, lparen, 's', 8); AnalysisTable.insert(12, ident, 's', 6); AnalysisTable.insert(12, unsignint, 's', 7); AnalysisTable.insert(12, F, ' ', 19);
    AnalysisTable.insert(13, PLUS, 'r', 3); AnalysisTable.insert(13, MINUS, 'r', 3); AnalysisTable.insert(13, rparen, 'r', 3); AnalysisTable.insert(13, END, 'r', 3);
    AnalysisTable.insert(14, PLUS, 'r', 2); AnalysisTable.insert(14, MINUS, 'r', 2); AnalysisTable.insert(14, rparen, 'r', 2); AnalysisTable.insert(14, END, 'r', 2);
    AnalysisTable.insert(15, PLUS, 's', 9); AnalysisTable.insert(15, MINUS, 's', 10); AnalysisTable.insert(15, rparen, 's', 20);
    AnalysisTable.insert(16, PLUS, 'r', 4); AnalysisTable.insert(16, MINUS, 'r', 4); AnalysisTable.insert(16, times, 's', 11); AnalysisTable.insert(16, slash, 's', 12); AnalysisTable.insert(16, rparen, 'r', 4); AnalysisTable.insert(16, END, 'r', 4);
    AnalysisTable.insert(17, PLUS, 'r', 5); AnalysisTable.insert(17, MINUS, 'r', 5); AnalysisTable.insert(17, times, 's', 11); AnalysisTable.insert(17, slash, 's', 12); AnalysisTable.insert(17, rparen, 'r', 5); AnalysisTable.insert(17, END, 'r', 5);
    AnalysisTable.insert(18, PLUS, 'r', 7); AnalysisTable.insert(18, MINUS, 'r', 7); AnalysisTable.insert(18, times, 'r', 7); AnalysisTable.insert(18, slash, 'r', 7); AnalysisTable.insert(18, rparen, 'r', 7); AnalysisTable.insert(18, END, 'r', 7);
    AnalysisTable.insert(19, PLUS, 'r', 8); AnalysisTable.insert(19, MINUS, 'r', 8); AnalysisTable.insert(19, times, 'r', 8); AnalysisTable.insert(19, slash, 'r', 8); AnalysisTable.insert(19, rparen, 'r', 8); AnalysisTable.insert(19, END, 'r', 8);
    AnalysisTable.insert(20, PLUS, 'r', 11); AnalysisTable.insert(20, MINUS, 'r', 11); AnalysisTable.insert(20, times, 'r', 11); AnalysisTable.insert(20, slash, 'r', 11); AnalysisTable.insert(20, rparen, 'r', 11); AnalysisTable.insert(20, END, 'r', 11);
    AnalysisTable.print();
	
	// 初始化分析栈
    top = -1;
}
void release(){
	// 释放所有的动态申请的资源
    delete PLUS;
	delete MINUS;
	delete times;
	delete slash;
	delete lparen;
	delete rparen;
	delete ident;
	delete unsignint;
	delete END;
	delete epslion;
    delete E;
	delete T;
	delete F;
    for(int i = 0; i < 1; ++i)delete Sdotproduction[i];
    for(int i = 0; i < 5; ++i)delete Eporduction[i];
    for(int i = 0; i < 3; ++i)delete Tproduction[i];
    for(int i = 0; i < 3; ++i)delete Fproduction[i];
}
std::string word, code; 
// char word[10], code[10];
char ch;
symbolsVT* a;
void ADVANCE(){
	// 读入一个词法分析的结果项,同时给出对应的终结符a
    // if(scanf("(%s,%s)", code, word) != -1){
    std::cin >> ch;
    if(!std::cin.eof()){
    // if(scanf("%c", &ch) != -1){
        std::getline(std::cin, code, ',');
        std::getline(std::cin, word);
        word.resize(word.size() - 1);
        // std::cin >> ch;
        std::cerr << word << " " << code << std::endl;
        if(code == "plus")a = PLUS;
        else if(code == "minus") a = MINUS;
        else if(code == "times") a = times;
        else if(code == "slash") a = slash;
        else if(code == "lparen") a = lparen;
        else if(code == "rparen") a = rparen;
        else if(code == "ident") a = ident;
        else if(code == "number") a = unsignint;
    }
    else{ 
        a = END;
    // if(std::cin.eof() == EOF){
        std::cerr << "hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh" << std::endl;
    }
    std::cerr << word << "_____________" << code << std::endl;
}
bool SLRAnalysis(){
	// 预测分析程序的总控程序
    init();
    bool grammer = true;		// 表示句子是否符合一定的文法
    bool flag = true;			// 总控程序的运行标志
    analysisStack[++top] = std::make_pair(0, (symbols*)END);  // 初始化栈,将状态0和符号#压入
    std::pair<int, symbols*> X;					// 定义一个公共变量:状态和符号的指针
    production *p;				// 定义一个产生式的指针
    std::pair<char, int> state; // 从分析表中获得的状态信息
    ADVANCE();					// 读入一个词法分析的结果项
    while(flag){
		//************************************************************//
		// 调试信息:状态栈和符号栈的中内容
        std::cerr << std::endl << std::endl;
        std::cerr << "================" << std::endl;
        a->print();
        std::cerr << "stack: " << std::endl;;
        for(int i = 0; i <= top; ++i){
            std::cerr << analysisStack[i].first << " ";            
        }
        std::cerr << std::endl;
        for(int i = 0; i <= top; ++i){
            if(analysisStack[i].second->getClassName() == "VT")std::cerr << ((symbolsVT*)(analysisStack[i].second))->getWord() << " ";
            else std::cerr << ((symbolsVN*)analysisStack[i].second)->getName() << " ";
        }
        std::cerr << std::endl << "================" << std::endl;
        std::cerr << std::endl;
		//************************************************************//
		
        X = analysisStack[top];	// 得到分析栈的栈顶元素,pop操作
        state = AnalysisTable.get(X.first, a);	// 根据栈顶的状态以及分析表中的变化情况来获得下一转换的状态s_i, r_i, acc, i等等
        std::cerr << state.first << "  " << state.second << std::endl;
        if(state.first == 's'){		// 如果是移进状态
            analysisStack[++top] = std::make_pair(state.second, a);
            ADVANCE();
            std::cerr << "One SHIFT..." << std::endl << std::endl;;
        }
        else if(state.first == 'r'){	// 如果是规约状态
            p = AnalysisTable.getProduction(state.second);	// 获得第i个产生式
            p->print();
            int len = p->getLen();
            top -= len;					// 将栈顶的符号按照产生式来规约
            X = analysisStack[top];		// 获得此时的栈顶元素,据此来获得GOTO表的下一状态
            analysisStack[++top] = std::make_pair(AnalysisTable.get(X.first, p->getVN()).second, p->getVN());
            std::cerr << "One REDUCE..." << std::endl << std::endl;;
        }
        else if(state.first == 'a'){	// 如果是acc状态
            std::cerr << "ACC!!!" << std::endl << std::endl;
            flag = false;
        }
        else{							// 到达分析表的其他状态,错误
            grammer = false;
            flag = false;
        }
    }

    release();		// 释放资源
    return grammer;	// 返回结果,true表示句子符合一定的语法
}

程序入口

项目调用测试入口:

// main.cpp
#include<bits/stdc++.h>
#include"SLRAnalysis.cpp"
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int maxn = 1e2 + 5;
const int inf = 0x3f3f3f3f;


int main(int argc, char *argv[]){
    // freopen("in.in", "r", stdin);
    // freopen("out.out", "w", stdout);

    if(SLRAnalysis()) cout << "Yes,it is correct." << endl;
    else cout << "No,it is wrong." << endl;

    return 0;
}

调试数据

给出两组测试数据:

// in.in
(lparen,()
(ident,a)
(plus,+)
(number,15)
(rparen,))
(times,*)

// out.out
No,it is wrong.
// in.in
(ident,akldjsfkl)
(plus,+)
(lparen,()
(ident,alk)
(times,*)
(ident,askd)
(minus,-)
(ident,jfdkj)
(times,*)
(ident,ksfj)
(slash,/)
(ident,jsadlk)
(plus,+)
(lparen,()
(ident,a)
(slash,/)
(ident,v)
(minus,-)
(ident,d)
(plus,+)
(ident,b)
(rparen,))
(rparen,))
(slash,/)
(ident,jfj)
// out.out
Yes,it is correct.

实验体会

本次实验是完成 LR分析法 的自下而上分析,相比较上一次实验的预测分析法,LR分析法主要的差别是分析表的构造上,通过活前缀DFA的构造,以及由此分析得到SLR分析表,将图的转换变为表内各状态的转换。实验中,自我认为最难的并不是程序的编写,而是构造活前缀DFA以及得到分析表的步骤,这一步中画图花费了很多的时间,同时也再一次的复习了相关的理论知识内容,当这一切准备工作完成后,只需根据此编写相关的代码即可,以为上个实验已经完成了最基础的诸如符号、产生式等类的编写,所以这次只需考虑分析表以及分析程序的编写,这次实验的简化也一定程度上达到了上一次实验中 代码重复使用 的目的。实验整体难度不大,是进一步的对理论知识的复习过程。

HTML

  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值