编译原理实验2——语法分析器

1  语法分析程序设计与实现 

任选一种有代表性的语法分析方法,如算符优先法、递归下降法、LL(1)SLR(1)LR(1)等,通过设计、编制、调试实现一个典型的语法分析程序,对 实验一所得扫描器提供的单词序列进行语法检查和结构分析,实现并进一步 掌握常用的语法分析方法。 

选择对各种常见高级程序设计语言都较为通用的语法结构——算术表达式的一个简化子集——作为分析对象,根据如下描述其语法结构的 BNF 定义 G2[<算术表达式>],任选一种学过的语法分析方法,针对运算对象为无符号 常数和变量的四则运算,设计并实现一个语法分析程序。

2  语法结构范围及文法定义 

G2[算术表达式>] <算术表达式> → <> |

<算术表达式>+<> |

<算术表达式>-<> <> → <因式> |

<>*<因式> |

<>/<因式> <因式> → <运算对象> |

(<算术表达式>)

若将语法范畴<算术表达式><><因式><运算对象>分别用 ETF i 代表,则 G2 可写成: 

G2[E]E → T | E+T | E-T

T → F | T*F | T/F

F → i | (E)

输入:由实验一输出的单词串,例如:UCON,PL,UCON,MU,ID ...

输出:若输入源程序中的符号串是给定文法的句子,则输出“RIGHT”, 并且给出每一步分析过程;若不是句子,即输入串有错误,则输出“ERROR”, 并且显示分析至此所得的中间结果,如分析栈、符号栈中的信息等,以及必 要的出错说明信息。

3  语法分析器设计

3.1  SLR(1)分析表

首先,我没有采用传统的二维数组的形势去构造分析表,原因如下:

二维数组去构造的话,数据类型不好选择

假定数据类型,例如:整型、字符型等,之后在语法分析过程中,新字符与文法中的字符对应起来较困难

所以,这次的建表过程,我采取了一种全新的图结构map,首先构建一个枚举类型的四种动作以及包括该动作序号的结构体

enum action{S,r,acc,error};//枚举四种动作,移进、规约、接受、拒绝
struct actionGo {
    action action;
    int s;//移进动作的编号
    int r;//规约动作的编号
};

其次,建表过程中我采用了map<pair<int,char>,actionGo>类型的图结构,意在将表的结构联系紧密且容易分析。

class SLR {
public:
    map<pair<int,char>,actionGo> actiontable;//action子表
    map<pair<int,char>,int> gototable;//goto子表
    vector<char> txttoken;//余留符号串
    stack<int> now_num;//状态栈
    stack<char> now_id;//符号
};

优点:

①:数据类型明确、直观,不需要为数据类型的对应匹配而花费精力

②:表中的表头以及各项都与文法中的符号一模一样,不需要额外去对应,节省了一部分空间

3.2  分析过程

首先,0状态入栈,#入栈,作为初始状态,开始移进第一个文本符号,移进之后首先判断是否是合法输入,若不是合法输入直接结束分析,若是合法输入则继续分析。通过当前符号和状态的联系,得出actionGo的一个实例ag,通过分析ag的动作(S,r,acc,error)继而执行下面的过程

移进动作(s):

当前状态入栈、当前符号入栈、将指针指向下一个文本信息

规约动作(r):

统计对应产生式右部的符号个数,按照统计的个数对应符号栈弹栈、状态栈弹栈,之后产生式左部入栈,通过栈顶状态和栈顶符号匹配新的GOTO状态,将GOTO状态入栈

接受动作(acc):

将分析结果flag=1,表示分析成功

拒绝动作(error):

将分析结果flag=0,表示分析失败

4  语法分析器程序设计

4.1  数据结构分析

本程序的数据结构有:

一个枚举类型的移进规约动作集合

enum action{S,r,acc,error};//枚举四种动作,移进、规约、接受、拒绝
struct actionGo {
    action action;
    int s;//移进动作的编号
    int r;//规约动作的编号
};

产生式结构体(为了方便规约动作的操作):

struct V {//产生式的结构体
    char left;
    vector<char> right;
}v[ALL_V];

SLR的分析表:

class SLR {
public:
    map<pair<int,char>,actionGo> actiontable;//action子表
    map<pair<int,char>,int> gototable;//goto子表
    vector<char> txttoken;//余留符号串
    stack<int> now_num;//状态栈
    stack<char> now_id;//符号
};

4.2  函数分析

产生式初始化函数:

void Init_V() {//初始化产生式
    v[0].left = 'S',v[0].right.resize(1),v[0].right[0] = 'E';
    v[1].left = 'E',v[1].right.resize(3),v[1].right[0]='E',v[1].right[1]='+',v[1].right[2]='T';
    v[2].left = 'E',v[2].right.resize(3),v[2].right[0] = 'E',v[2].right[1]='-',v[2].right[2]='T';
    v[3].left = 'E',v[3].right.resize(1),v[3].right[0] = 'T';
    v[4].left = 'T',v[4].right.resize(3),v[4].right[0] = 'T',v[4].right[1] = '*',v[4].right[2] = 'F';
    v[5].left = 'T',v[5].right.resize(3),v[5].right[0] = 'T',v[5].right[1] = '/',v[5].right[2] = 'F';
    v[6].left = 'T',v[6].right.resize(1),v[6].right[0] = 'F';
    v[7].left = 'F',v[7].right.resize(3),v[7].right[0] = '(',v[7].right[1] = 'E',v[7].right[2] = ')';
    v[8].left = 'F',v[8].right.resize(1),v[8].right[0] = 'i';
}

填表函数(SLR1):

void fixtable(SLR &slr,actionGo &actiongo) {
    slr.actiontable[make_pair(0,')')] = {error,0,0};
    slr.actiontable[make_pair(0,'+')] = {error,0,0};
    slr.actiontable[make_pair(0,'-')] = {error,0,0};
    slr.actiontable[make_pair(0,'*')] = {error,0,0};
    slr.actiontable[make_pair(0,'/')] = {error,0,0};
    slr.actiontable[make_pair(0,'(')] = {S,4,-1};
    slr.actiontable[make_pair(0,'#')] = {error,0,0};
    slr.actiontable[make_pair(0,'i')] = {S,5,-1};


    slr.actiontable[make_pair(1,'+')] = {S,6,-1};
    slr.actiontable[make_pair(1,'-')] = {S,7,-1};
    slr.actiontable[make_pair(1,'#')] = {acc,-1,-1};
    slr.actiontable[make_pair(1,'(')] = {error,0,0};
    slr.actiontable[make_pair(1,')')] = {error,0,0};
    slr.actiontable[make_pair(1,'i')] = {error,0,0};
    slr.actiontable[make_pair(1,'*')] = {error,0,0};
    slr.actiontable[make_pair(1,'/')] = {error,0,0};


    slr.actiontable[make_pair(2,')')] = {r,-1,3};
    slr.actiontable[make_pair(2,'+')] = {r,-1,3};
    slr.actiontable[make_pair(2,'-')] = {r,-1,3};
    slr.actiontable[make_pair(2,'*')] = {S,8,-1};
    slr.actiontable[make_pair(2,'/')] = {S,9,-1};
    slr.actiontable[make_pair(2,'#')] = {r,-1,3};
    slr.actiontable[make_pair(2,'(')] = {error,0,0};
    slr.actiontable[make_pair(2,'i')] = {error,0,0};


    slr.actiontable[make_pair(3,')')] = {r,-1,6};
    slr.actiontable[make_pair(3,'+')] = {r,-1,6};
    slr.actiontable[make_pair(3,'-')] = {r,-1,6};
    slr.actiontable[make_pair(3,'*')] = {r,-1,6};
    slr.actiontable[make_pair(3,'/')] = {r,-1,6};
    slr.actiontable[make_pair(3,'#')] = {r,-1,6};
    slr.actiontable[make_pair(3,'(')] = {error,0,0};
    slr.actiontable[make_pair(3,'i')] = {error,0,0};


    slr.actiontable[make_pair(4,')')] = {error,0,0};
    slr.actiontable[make_pair(4,'+')] = {error,0,0};
    slr.actiontable[make_pair(4,'-')] = {error,0,0};
    slr.actiontable[make_pair(4,'*')] = {error,0,0};
    slr.actiontable[make_pair(4,'/')] = {error,0,0};
    slr.actiontable[make_pair(4,'#')] = {error,0,0};
    slr.actiontable[make_pair(4,'(')] = {S,4,-1};
    slr.actiontable[make_pair(4,'i')] = {S,5,-1};


    slr.actiontable[make_pair(5,'(')] = {error,0,0};
    slr.actiontable[make_pair(5,'i')] = {error,0,0};
    slr.actiontable[make_pair(5,')')] = {r,-1,8};
    slr.actiontable[make_pair(5,'+')] = {r,-1,8};
    slr.actiontable[make_pair(5,'-')] = {r,-1,8};
    slr.actiontable[make_pair(5,'*')] = {r,-1,8};
    slr.actiontable[make_pair(5,'/')] = {r,-1,8};
    slr.actiontable[make_pair(5,'#')] = {r,-1,8};


    slr.actiontable[make_pair(6,')')] = {error,0,0};
    slr.actiontable[make_pair(6,'+')] = {error,0,0};
    slr.actiontable[make_pair(6,'-')] = {error,0,0};
    slr.actiontable[make_pair(6,'*')] = {error,0,0};
    slr.actiontable[make_pair(6,'/')] = {error,0,0};
    slr.actiontable[make_pair(6,'#')] = {error,0,0};
    slr.actiontable[make_pair(6,'(')] = {S,4,-1};
    slr.actiontable[make_pair(6,'i')] = {S,5,-1};


    slr.actiontable[make_pair(7,')')] = {error,0,0};
    slr.actiontable[make_pair(7,'+')] = {error,0,0};
    slr.actiontable[make_pair(7,'-')] = {error,0,0};
    slr.actiontable[make_pair(7,'*')] = {error,0,0};
    slr.actiontable[make_pair(7,'/')] = {error,0,0};
    slr.actiontable[make_pair(7,'#')] = {error,0,0};
    slr.actiontable[make_pair(7,'(')] = {S,4,-1};
    slr.actiontable[make_pair(7,'i')] = {S,5,-1};


    slr.actiontable[make_pair(8,')')] = {error,0,0};
    slr.actiontable[make_pair(8,'+')] = {error,0,0};
    slr.actiontable[make_pair(8,'-')] = {error,0,0};
    slr.actiontable[make_pair(8,'*')] = {error,0,0};
    slr.actiontable[make_pair(8,'/')] = {error,0,0};
    slr.actiontable[make_pair(8,'#')] = {error,0,0};
    slr.actiontable[make_pair(8,'(')] = {S,4,-1};
    slr.actiontable[make_pair(8,'i')] = {S,5,-1};



    slr.actiontable[make_pair(9,')')] = {error,0,0};
    slr.actiontable[make_pair(9,'+')] = {error,0,0};
    slr.actiontable[make_pair(9,'-')] = {error,0,0};
    slr.actiontable[make_pair(9,'*')] = {error,0,0};
    slr.actiontable[make_pair(9,'/')] = {error,0,0};
    slr.actiontable[make_pair(9,'#')] = {error,0,0};
    slr.actiontable[make_pair(9,'(')] = {S,4,-1};
    slr.actiontable[make_pair(9,'i')] = {S,5,-1};


    slr.actiontable[make_pair(10,'#')] = {error,0,0};
    slr.actiontable[make_pair(10,'i')] = {error,0,0};
    slr.actiontable[make_pair(10,'/')] = {error,0,0};
    slr.actiontable[make_pair(10,'*')] = {error,0,0};
    slr.actiontable[make_pair(10,'(')] = {error,0,0};
    slr.actiontable[make_pair(10,')')] = {S,15,-1};
    slr.actiontable[make_pair(10,'+')] = {S,6,-1};
    slr.actiontable[make_pair(10,'-')] = {S,7,-1};


    slr.actiontable[make_pair(11,'(')] = {error,0,0};
    slr.actiontable[make_pair(11,'i')] = {error,0,0};
    slr.actiontable[make_pair(11,')')] = {r,-1,1};
    slr.actiontable[make_pair(11,'+')] = {r,-1,1};
    slr.actiontable[make_pair(11,'-')] = {r,-1,1};
    slr.actiontable[make_pair(11,'*')] = {S,8,-1};
    slr.actiontable[make_pair(11,'/')] = {S,8,-1};
    slr.actiontable[make_pair(11,'#')] = {r,-1,1};


    slr.actiontable[make_pair(12,'(')] = {error,0,0};
    slr.actiontable[make_pair(12,'i')] = {error,0,0};
    slr.actiontable[make_pair(12,')')] = {r,-1,2};
    slr.actiontable[make_pair(12,'+')] = {r,-1,2};
    slr.actiontable[make_pair(12,'-')] = {r,-1,2};
    slr.actiontable[make_pair(12,'*')] = {S,8,-1};
    slr.actiontable[make_pair(12,'/')] = {S,9,-1};
    slr.actiontable[make_pair(12,'#')] = {r,-1,2};


    slr.actiontable[make_pair(13,'(')] = {error,0,0};
    slr.actiontable[make_pair(13,'i')] = {error,0,0};
    slr.actiontable[make_pair(13,')')] = {r,-1,4};
    slr.actiontable[make_pair(13,'+')] = {r,-1,4};
    slr.actiontable[make_pair(13,'-')] = {r,-1,4};
    slr.actiontable[make_pair(13,'*')] = {r,-1,4};
    slr.actiontable[make_pair(13,'/')] = {r,-1,4};
    slr.actiontable[make_pair(13,'#')] = {r,-1,4};


    slr.actiontable[make_pair(14,'(')] = {error,0,0};
    slr.actiontable[make_pair(14,'i')] = {error,0,0};
    slr.actiontable[make_pair(14,')')] = {r,-1,5};
    slr.actiontable[make_pair(14,'+')] = {r,-1,5};
    slr.actiontable[make_pair(14,'-')] = {r,-1,5};
    slr.actiontable[make_pair(14,'*')] = {r,-1,5};
    slr.actiontable[make_pair(14,'/')] = {r,-1,5};
    slr.actiontable[make_pair(14,'#')] = {r,-1,5};


    slr.actiontable[make_pair(15,'(')] = {error,0,0};
    slr.actiontable[make_pair(15,'i')] = {error,0,0};
    slr.actiontable[make_pair(15,')')] = {r,-1,7};
    slr.actiontable[make_pair(15,'+')] = {r,-1,7};
    slr.actiontable[make_pair(15,'-')] = {r,-1,7};
    slr.actiontable[make_pair(15,'*')] = {r,-1,7};
    slr.actiontable[make_pair(15,'/')] = {r,-1,7};
    slr.actiontable[make_pair(15,'#')] = {r,-1,7};
    slr.gototable[make_pair(0,'E')] = 1;
    slr.gototable[make_pair(0,'T')] = 2;
    slr.gototable[make_pair(0,'F')] = 3;
    slr.gototable[make_pair(4,'E')] = 10;
    slr.gototable[make_pair(4,'T')] = 2;
    slr.gototable[make_pair(4,'F')] = 3;
    slr.gototable[make_pair(6,'T')] = 11;
    slr.gototable[make_pair(6,'F')] = 3;
    slr.gototable[make_pair(7,'T')] = 12;
    slr.gototable[make_pair(7,'F')] = 3;
    slr.gototable[make_pair(8,'F')] = 13;
    slr.gototable[make_pair(9,'F')] = 14;
}

SLR1分析过程函数:

void doSLR(SLR &slr) {
    //设置初始状态和最终的acc的#号
    slr.now_num.push(0);//状态栈->0
    slr.now_id.push('#');//符号栈->#
    int i = 0;
    int r_length = -1;//规约时代表产生式右部的符号数量
    char l_char;//规约时代表产生式左部的符号
    while (true) {//开始循环分析
        int now_state = slr.now_num.top();//当前的状态符号 = 符号栈栈顶符号
        char now_id = NULL;
        if(txt[i] != NULL) {
            now_id = txt[i];//当前匹配的符号
        }
        if(now_id != 'i' && now_id != '+' && now_id != '-' && now_id != '*'&&now_id != '/'&&now_id != '('&&now_id != ')'&&now_id != '#' && now_id != NULL) {
            cout<<"有不合法的输入,分析终止!"<<endl;
            break;
        }
        actionGo ag = slr.actiontable[make_pair(now_state,now_id)];//匹配当前的状态与符号,找动作
        if(ag.action == S) {
            //根据不同的动作开始分析
            slr.now_num.push(ag.s);//状态进栈
            slr.now_id.push(now_id);//当前符号进符号栈
            i++;//指向下一个待匹配的符号
        }else if(ag.action == r) {
            r_length = v[ag.r].right.size();//统计产生式右部的符号个数
            for(int j = 0;j<r_length;++j) {
                slr.now_num.pop();//状态栈弹栈
                slr.now_id.pop();//符号栈弹栈
            }
            l_char = v[ag.r].left;//产生式左部的符号
            slr.now_id.push(l_char);//左部符号入栈
            int go_to = slr.gototable[make_pair(slr.now_num.top(),l_char)];//找goto的状态
            slr.now_num.push(go_to);//新状态入栈
        }else if(ag.action == acc) {
            flag = 1;
            cout<<"分析成功!"<<endl;
            break;
        }else{
            cout<<"分析失败!"<<endl;
            break;
        }
    }
}

文本转换函数(将BEGIN\EDN等字符转换为该文法的字符):

void txt_cin(ifstream &fin) {//输入文本,并转换为该文法
    fin.open("D:/Class_Code/bianyiyuanli_Code/shiyan1_to_2.txt");
    string s;
    int i = 0;
    txt.resize(50);
    while (getline(fin,s)) {
        if(s == "ID" || s == "DATA_INT" || s == "DATA_FLOAT") {
            txt[i++] = 'i';
        }else if(s == "PL") {
            txt[i++] = '+';
        }else if(s == "MI") {
            txt[i++] = '-';
        }else if(s == "MU") {
            txt[i++] = '*';
        }else if(s == "DI") {
            txt[i++] = '/';
        }else if(s == "IS") {
            txt[i++] = '=';
        }else if(s == "LEFT") {
            txt[i++] = '(';
        }else if(s == "RIGHT") {
            txt[i++] = ')';
        }
    }
    txt[i] = '#';
    fin.close();
}

打印函数(打印最终结果):

void print(string s) {//输出结果
    if(flag == 1) {
        cout<<s<<endl;
        cout<<"该句子是该文法的句型!";
    }else {
        cout<<s<<endl;
        cout<<"该句子不是该文法的句型!";
    }
}

主函数:

void test() {
    ifstream fin;
    txt_cin(fin);//从文件中获取单词
    string s = get_s();//将单词->句子
    Init_V();//初始化产生式
    SLR slr;//创建一张SLR分析表
    actionGo actiongo;//创建一个动作表
    fixtable(slr,actiongo);//填表
    doSLR(slr);//做SLR分析
    print(s);//打印最终结果
}

4.3  程序结构

4.4  程序源码

#include<iostream>
#include<fstream>
#include<vector>
#include<map>
#include <stack>
#include<string>
#define ALL_V 9//产生式的个数,为了r操作
using namespace std;
int flag = 0;//分析成功与否0->失败,1->成功
vector<char> txt;

enum action{S,r,acc,error};//枚举四种动作,移进、规约、接受、拒绝
struct actionGo {
    action action;
    int s;//移进动作的编号
    int r;//规约动作的编号
};

struct V {//产生式的结构体
    char left;
    vector<char> right;
}v[ALL_V];

class SLR {
public:
    map<pair<int,char>,actionGo> actiontable;//action子表
    map<pair<int,char>,int> gototable;//goto子表
    vector<char> txttoken;//余留符号串
    stack<int> now_num;//状态栈
    stack<char> now_id;//符号
};
class LL1 {//这是LL1分析法的实现,将在扩展实验中展示

};

void Init_V() {//初始化产生式
    v[0].left = 'S',v[0].right.resize(1),v[0].right[0] = 'E';
    v[1].left = 'E',v[1].right.resize(3),v[1].right[0]='E',v[1].right[1]='+',v[1].right[2]='T';
    v[2].left = 'E',v[2].right.resize(3),v[2].right[0] = 'E',v[2].right[1]='-',v[2].right[2]='T';
    v[3].left = 'E',v[3].right.resize(1),v[3].right[0] = 'T';
    v[4].left = 'T',v[4].right.resize(3),v[4].right[0] = 'T',v[4].right[1] = '*',v[4].right[2] = 'F';
    v[5].left = 'T',v[5].right.resize(3),v[5].right[0] = 'T',v[5].right[1] = '/',v[5].right[2] = 'F';
    v[6].left = 'T',v[6].right.resize(1),v[6].right[0] = 'F';
    v[7].left = 'F',v[7].right.resize(3),v[7].right[0] = '(',v[7].right[1] = 'E',v[7].right[2] = ')';
    v[8].left = 'F',v[8].right.resize(1),v[8].right[0] = 'i';
}

void fixtable(SLR &slr,actionGo &actiongo) {
    slr.actiontable[make_pair(0,')')] = {error,0,0};
    slr.actiontable[make_pair(0,'+')] = {error,0,0};
    slr.actiontable[make_pair(0,'-')] = {error,0,0};
    slr.actiontable[make_pair(0,'*')] = {error,0,0};
    slr.actiontable[make_pair(0,'/')] = {error,0,0};
    slr.actiontable[make_pair(0,'(')] = {S,4,-1};
    slr.actiontable[make_pair(0,'#')] = {error,0,0};
    slr.actiontable[make_pair(0,'i')] = {S,5,-1};


    slr.actiontable[make_pair(1,'+')] = {S,6,-1};
    slr.actiontable[make_pair(1,'-')] = {S,7,-1};
    slr.actiontable[make_pair(1,'#')] = {acc,-1,-1};
    slr.actiontable[make_pair(1,'(')] = {error,0,0};
    slr.actiontable[make_pair(1,')')] = {error,0,0};
    slr.actiontable[make_pair(1,'i')] = {error,0,0};
    slr.actiontable[make_pair(1,'*')] = {error,0,0};
    slr.actiontable[make_pair(1,'/')] = {error,0,0};


    slr.actiontable[make_pair(2,')')] = {r,-1,3};
    slr.actiontable[make_pair(2,'+')] = {r,-1,3};
    slr.actiontable[make_pair(2,'-')] = {r,-1,3};
    slr.actiontable[make_pair(2,'*')] = {S,8,-1};
    slr.actiontable[make_pair(2,'/')] = {S,9,-1};
    slr.actiontable[make_pair(2,'#')] = {r,-1,3};
    slr.actiontable[make_pair(2,'(')] = {error,0,0};
    slr.actiontable[make_pair(2,'i')] = {error,0,0};


    slr.actiontable[make_pair(3,')')] = {r,-1,6};
    slr.actiontable[make_pair(3,'+')] = {r,-1,6};
    slr.actiontable[make_pair(3,'-')] = {r,-1,6};
    slr.actiontable[make_pair(3,'*')] = {r,-1,6};
    slr.actiontable[make_pair(3,'/')] = {r,-1,6};
    slr.actiontable[make_pair(3,'#')] = {r,-1,6};
    slr.actiontable[make_pair(3,'(')] = {error,0,0};
    slr.actiontable[make_pair(3,'i')] = {error,0,0};


    slr.actiontable[make_pair(4,')')] = {error,0,0};
    slr.actiontable[make_pair(4,'+')] = {error,0,0};
    slr.actiontable[make_pair(4,'-')] = {error,0,0};
    slr.actiontable[make_pair(4,'*')] = {error,0,0};
    slr.actiontable[make_pair(4,'/')] = {error,0,0};
    slr.actiontable[make_pair(4,'#')] = {error,0,0};
    slr.actiontable[make_pair(4,'(')] = {S,4,-1};
    slr.actiontable[make_pair(4,'i')] = {S,5,-1};


    slr.actiontable[make_pair(5,'(')] = {error,0,0};
    slr.actiontable[make_pair(5,'i')] = {error,0,0};
    slr.actiontable[make_pair(5,')')] = {r,-1,8};
    slr.actiontable[make_pair(5,'+')] = {r,-1,8};
    slr.actiontable[make_pair(5,'-')] = {r,-1,8};
    slr.actiontable[make_pair(5,'*')] = {r,-1,8};
    slr.actiontable[make_pair(5,'/')] = {r,-1,8};
    slr.actiontable[make_pair(5,'#')] = {r,-1,8};


    slr.actiontable[make_pair(6,')')] = {error,0,0};
    slr.actiontable[make_pair(6,'+')] = {error,0,0};
    slr.actiontable[make_pair(6,'-')] = {error,0,0};
    slr.actiontable[make_pair(6,'*')] = {error,0,0};
    slr.actiontable[make_pair(6,'/')] = {error,0,0};
    slr.actiontable[make_pair(6,'#')] = {error,0,0};
    slr.actiontable[make_pair(6,'(')] = {S,4,-1};
    slr.actiontable[make_pair(6,'i')] = {S,5,-1};


    slr.actiontable[make_pair(7,')')] = {error,0,0};
    slr.actiontable[make_pair(7,'+')] = {error,0,0};
    slr.actiontable[make_pair(7,'-')] = {error,0,0};
    slr.actiontable[make_pair(7,'*')] = {error,0,0};
    slr.actiontable[make_pair(7,'/')] = {error,0,0};
    slr.actiontable[make_pair(7,'#')] = {error,0,0};
    slr.actiontable[make_pair(7,'(')] = {S,4,-1};
    slr.actiontable[make_pair(7,'i')] = {S,5,-1};


    slr.actiontable[make_pair(8,')')] = {error,0,0};
    slr.actiontable[make_pair(8,'+')] = {error,0,0};
    slr.actiontable[make_pair(8,'-')] = {error,0,0};
    slr.actiontable[make_pair(8,'*')] = {error,0,0};
    slr.actiontable[make_pair(8,'/')] = {error,0,0};
    slr.actiontable[make_pair(8,'#')] = {error,0,0};
    slr.actiontable[make_pair(8,'(')] = {S,4,-1};
    slr.actiontable[make_pair(8,'i')] = {S,5,-1};



    slr.actiontable[make_pair(9,')')] = {error,0,0};
    slr.actiontable[make_pair(9,'+')] = {error,0,0};
    slr.actiontable[make_pair(9,'-')] = {error,0,0};
    slr.actiontable[make_pair(9,'*')] = {error,0,0};
    slr.actiontable[make_pair(9,'/')] = {error,0,0};
    slr.actiontable[make_pair(9,'#')] = {error,0,0};
    slr.actiontable[make_pair(9,'(')] = {S,4,-1};
    slr.actiontable[make_pair(9,'i')] = {S,5,-1};


    slr.actiontable[make_pair(10,'#')] = {error,0,0};
    slr.actiontable[make_pair(10,'i')] = {error,0,0};
    slr.actiontable[make_pair(10,'/')] = {error,0,0};
    slr.actiontable[make_pair(10,'*')] = {error,0,0};
    slr.actiontable[make_pair(10,'(')] = {error,0,0};
    slr.actiontable[make_pair(10,')')] = {S,15,-1};
    slr.actiontable[make_pair(10,'+')] = {S,6,-1};
    slr.actiontable[make_pair(10,'-')] = {S,7,-1};


    slr.actiontable[make_pair(11,'(')] = {error,0,0};
    slr.actiontable[make_pair(11,'i')] = {error,0,0};
    slr.actiontable[make_pair(11,')')] = {r,-1,1};
    slr.actiontable[make_pair(11,'+')] = {r,-1,1};
    slr.actiontable[make_pair(11,'-')] = {r,-1,1};
    slr.actiontable[make_pair(11,'*')] = {S,8,-1};
    slr.actiontable[make_pair(11,'/')] = {S,8,-1};
    slr.actiontable[make_pair(11,'#')] = {r,-1,1};


    slr.actiontable[make_pair(12,'(')] = {error,0,0};
    slr.actiontable[make_pair(12,'i')] = {error,0,0};
    slr.actiontable[make_pair(12,')')] = {r,-1,2};
    slr.actiontable[make_pair(12,'+')] = {r,-1,2};
    slr.actiontable[make_pair(12,'-')] = {r,-1,2};
    slr.actiontable[make_pair(12,'*')] = {S,8,-1};
    slr.actiontable[make_pair(12,'/')] = {S,9,-1};
    slr.actiontable[make_pair(12,'#')] = {r,-1,2};


    slr.actiontable[make_pair(13,'(')] = {error,0,0};
    slr.actiontable[make_pair(13,'i')] = {error,0,0};
    slr.actiontable[make_pair(13,')')] = {r,-1,4};
    slr.actiontable[make_pair(13,'+')] = {r,-1,4};
    slr.actiontable[make_pair(13,'-')] = {r,-1,4};
    slr.actiontable[make_pair(13,'*')] = {r,-1,4};
    slr.actiontable[make_pair(13,'/')] = {r,-1,4};
    slr.actiontable[make_pair(13,'#')] = {r,-1,4};


    slr.actiontable[make_pair(14,'(')] = {error,0,0};
    slr.actiontable[make_pair(14,'i')] = {error,0,0};
    slr.actiontable[make_pair(14,')')] = {r,-1,5};
    slr.actiontable[make_pair(14,'+')] = {r,-1,5};
    slr.actiontable[make_pair(14,'-')] = {r,-1,5};
    slr.actiontable[make_pair(14,'*')] = {r,-1,5};
    slr.actiontable[make_pair(14,'/')] = {r,-1,5};
    slr.actiontable[make_pair(14,'#')] = {r,-1,5};


    slr.actiontable[make_pair(15,'(')] = {error,0,0};
    slr.actiontable[make_pair(15,'i')] = {error,0,0};
    slr.actiontable[make_pair(15,')')] = {r,-1,7};
    slr.actiontable[make_pair(15,'+')] = {r,-1,7};
    slr.actiontable[make_pair(15,'-')] = {r,-1,7};
    slr.actiontable[make_pair(15,'*')] = {r,-1,7};
    slr.actiontable[make_pair(15,'/')] = {r,-1,7};
    slr.actiontable[make_pair(15,'#')] = {r,-1,7};
    slr.gototable[make_pair(0,'E')] = 1;
    slr.gototable[make_pair(0,'T')] = 2;
    slr.gototable[make_pair(0,'F')] = 3;
    slr.gototable[make_pair(4,'E')] = 10;
    slr.gototable[make_pair(4,'T')] = 2;
    slr.gototable[make_pair(4,'F')] = 3;
    slr.gototable[make_pair(6,'T')] = 11;
    slr.gototable[make_pair(6,'F')] = 3;
    slr.gototable[make_pair(7,'T')] = 12;
    slr.gototable[make_pair(7,'F')] = 3;
    slr.gototable[make_pair(8,'F')] = 13;
    slr.gototable[make_pair(9,'F')] = 14;
}

void doSLR(SLR &slr) {
    //设置初始状态和最终的acc的#号
    slr.now_num.push(0);//状态栈->0
    slr.now_id.push('#');//符号栈->#
    int i = 0;
    int r_length = -1;//规约时代表产生式右部的符号数量
    char l_char;//规约时代表产生式左部的符号
    while (true) {//开始循环分析
        int now_state = slr.now_num.top();//当前的状态符号 = 符号栈栈顶符号
        char now_id = NULL;
        if(txt[i] != NULL) {
            now_id = txt[i];//当前匹配的符号
        }
        if(now_id != 'i' && now_id != '+' && now_id != '-' && now_id != '*'&&now_id != '/'&&now_id != '('&&now_id != ')'&&now_id != '#' && now_id != NULL) {
            cout<<"有不合法的输入,分析终止!"<<endl;
            break;
        }
        actionGo ag = slr.actiontable[make_pair(now_state,now_id)];//匹配当前的状态与符号,找动作
        if(ag.action == S) {
            //根据不同的动作开始分析
            slr.now_num.push(ag.s);//状态进栈
            slr.now_id.push(now_id);//当前符号进符号栈
            i++;//指向下一个待匹配的符号
        }else if(ag.action == r) {
            r_length = v[ag.r].right.size();//统计产生式右部的符号个数
            for(int j = 0;j<r_length;++j) {
                slr.now_num.pop();//状态栈弹栈
                slr.now_id.pop();//符号栈弹栈
            }
            l_char = v[ag.r].left;//产生式左部的符号
            slr.now_id.push(l_char);//左部符号入栈
            int go_to = slr.gototable[make_pair(slr.now_num.top(),l_char)];//找goto的状态
            slr.now_num.push(go_to);//新状态入栈
        }else if(ag.action == acc) {
            flag = 1;
            cout<<"分析成功!"<<endl;
            break;
        }else{
            cout<<"分析失败!"<<endl;
            break;
        }
    }
}

void txt_cin(ifstream &fin) {//输入文本,并转换为该文法
    fin.open("D:/Class_Code/bianyiyuanli_Code/shiyan1_to_2.txt");
    string s;
    int i = 0;
    txt.resize(50);
    while (getline(fin,s)) {
        if(s == "ID" || s == "DATA_INT" || s == "DATA_FLOAT") {
            txt[i++] = 'i';
        }else if(s == "PL") {
            txt[i++] = '+';
        }else if(s == "MI") {
            txt[i++] = '-';
        }else if(s == "MU") {
            txt[i++] = '*';
        }else if(s == "DI") {
            txt[i++] = '/';
        }else if(s == "IS") {
            txt[i++] = '=';
        }else if(s == "LEFT") {
            txt[i++] = '(';
        }else if(s == "RIGHT") {
            txt[i++] = ')';
        }
    }
    txt[i] = '#';
    fin.close();
}
string get_s() {//组成句子
    string s;
    for(int i = 0;i<txt.size();i++) {
        if(txt[i] != NULL && txt[i]!='#') {
            s = s+txt[i];
        }
    }
    return s;
}
void print(string s) {//输出结果
    if(flag == 1) {
        cout<<s<<endl;
        cout<<"该句子是该文法的句型!";
    }else {
        cout<<s<<endl;
        cout<<"该句子不是该文法的句型!";
    }
}
void test() {
    ifstream fin;
    txt_cin(fin);//从文件中获取单词
    string s = get_s();//将单词->句子
    Init_V();//初始化产生式
    SLR slr;//创建一张SLR分析表
    actionGo actiongo;//创建一个动作表
    fixtable(slr,actiongo);//填表
    doSLR(slr);//做SLR分析
    print(s);//打印最终结果
}

int main(void) {
    test();
    return 0;
}

5  扩展实验(LL1分析法实现语法分析器)

5.1  扩展分析

5.1.1  消除左递归

E->TE’   

E’-> +TE’ | -TE’ | ɜ

T->FT’   

T’->*FT’ | /FT’ | ɜ

F->(E)   F->i

5.1.2  求FIRST集与FOLLOW集

5.1.3  建立LL1分析表

5.2  扩展程序分析

新增数据结构:

LL1分析类:

其中包含各个非终结符号的FIRST集合与FOLLOW集合、一个图类型的LL1分析表、一个stack类型的符号栈、一个初始化LL1分析表的方法、一个开始分析的方法

class LL1 {
public:
    char FIRST_E[2] = {'(','i'};
    char FIRST_e[3] = {'+','-','!'};//'!' -> ?
    char FIRST_T[2] = {'(','i'};
    char FIRST_F[2] = {'(','i'};
    char FIRST_t[3]={'*','/','!'};
    char FOLLOW_E[2] = {'#',')'};
    char FOLLOW_e[2] = {'#',')'};
    char FOLLOW_t[4] = {'+','-','#',')'};
    char FOLLOW_F[6] = {'+','-','*','/','#',')'};
    char FOLLOW_T[4] = {'+','-','#',')'};
    map<pair<char,char>,int> LL1_table;
    stack<char> simple;
    void init_LL1(LL1 &LL1);//填表
    void doLL1(LL1 &LL1);//开始分析
};

新增函数:

LL1分析表初始化函数,器内容与SLR分析表的填表过程类似(-1表示分析失败的情况):

void LL1::init_LL1(LL1 &LL1) {

    LL1.LL1_table[make_pair('E','i')] = 1;
    LL1.LL1_table[make_pair('E','(')] = 1;
    LL1.LL1_table[make_pair('E','+')] = -1;
    LL1.LL1_table[make_pair('E','-')] = -1;
    LL1.LL1_table[make_pair('E','*')] = -1;
    LL1.LL1_table[make_pair('E','/')] = -1;
    LL1.LL1_table[make_pair('E',')')] = -1;
    LL1.LL1_table[make_pair('E','#')] = -1;

    LL1.LL1_table[make_pair('e','+')] = 2;
    LL1.LL1_table[make_pair('e','-')] = 3;
    LL1.LL1_table[make_pair('e',')')] = 4;
    LL1.LL1_table[make_pair('e','#')] = 4;
    LL1.LL1_table[make_pair('e','i')] = -1;
    LL1.LL1_table[make_pair('e','*')] = -1;
    LL1.LL1_table[make_pair('e','/')] = -1;
    LL1.LL1_table[make_pair('e','(')] = -1;

    LL1.LL1_table[make_pair('T','i')] = 5;
    LL1.LL1_table[make_pair('T','(')] = 5;
    LL1.LL1_table[make_pair('T','+')] = -1;
    LL1.LL1_table[make_pair('T','-')] = -1;
    LL1.LL1_table[make_pair('T','*')] = -1;
    LL1.LL1_table[make_pair('T','/')] = -1;
    LL1.LL1_table[make_pair('T',')')] = -1;
    LL1.LL1_table[make_pair('T','#')] = -1;

    LL1.LL1_table[make_pair('t','+')] = 8;
    LL1.LL1_table[make_pair('t','-')] = 8;
    LL1.LL1_table[make_pair('t','*')] = 6;
    LL1.LL1_table[make_pair('t','/')] = 7;
    LL1.LL1_table[make_pair('t',')')] = 8;
    LL1.LL1_table[make_pair('t','#')] = 8;
    LL1.LL1_table[make_pair('t','i')] = -1;
    LL1.LL1_table[make_pair('t','(')] = -1;

    LL1.LL1_table[make_pair('F','i')] = 10;
    LL1.LL1_table[make_pair('F','(')] = 9;
    LL1.LL1_table[make_pair('F','#')] = -1;
    LL1.LL1_table[make_pair('F','+')] = -1;
    LL1.LL1_table[make_pair('F','-')] = -1;
    LL1.LL1_table[make_pair('F','*')] = -1;
    LL1.LL1_table[make_pair('F','/')] = -1;
    LL1.LL1_table[make_pair('F',')')] = -1;
}

新增doLL1函数,该函数为LL1分析法的总控程序,首先先将初始符号’#’与’E’压栈,之后根据LL1类中的LL1分析表进行栈顶元素与输入文本的首字符进行匹配,找到相应的产生式,进而再对符号栈simple进行操作:

void LL1::doLL1(LL1 &LL1) {
    int index = 0;//用于指向txt的下一个符号
    /*开始匹配*/
    int now_state;
    /*先压栈开始符# 与初始状态E*/
    LL1.simple.push('#');
    LL1.simple.push('E');
    while (true){
        if(simple.top() == txt[index]) {//栈顶元素与当前符号匹配,直接消除
            if(simple.top() == '#') {//分析成功的情况
                cout<<"分析成功!"<<endl;
                flag = 1;
                break;
            }else {
                simple.pop();
                index++;
            }
        }
        now_state = LL1.LL1_table[make_pair(LL1.simple.top(),txt[index])];
        if(now_state == -1) {
            cout<<"分析失败"<<endl;
            flag = 0;
            break;
        }else {
            switch (now_state) {
                case 1:
                    simple.pop();//当前符号弹栈
                /*反向压栈*/
                simple.push('e');
                simple.push('T');
                break;
                case 2:
                    simple.pop();
                simple.push('e');
                simple.push('T');
                simple.push('+');
                break;
                case 3:
                    simple.pop();
                simple.push('e');
                simple.push('T');
                simple.push('+');
                break;
                case 4:
                    simple.pop();
                break;
                case 5:
                    simple.pop();
                simple.push('t');
                simple.push('F');
                break;
                case 6:
                    simple.pop();
                simple.push('t');
                simple.push('F');
                simple.push('*');
                break;
                case 7:
                    simple.pop();
                simple.push('t');
                simple.push('F');
                simple.push('/');
                break;
                case 8:
                    simple.pop();
                break;
                case 9:
                    simple.pop();
                simple.push(')');
                simple.push('E');
                simple.push('(');
                break;
                case 10:
                    simple.pop();
                simple.push('i');
            }
        }
    }
}

6  整体源码

#include<iostream>
#include<fstream>
#include<vector>
#include<map>
#include <stack>
#include<string>
#define ALL_V 9//产生式的个数,为了r操作
using namespace std;
int flag = 0;//分析成功与否0->失败,1->成功
vector<char> txt;

enum action{S,r,acc,error};//枚举四种动作,移进、规约、接受、拒绝
struct actionGo {
    action action;
    int s;//移进动作的编号
    int r;//规约动作的编号
};

struct V {//产生式的结构体
    char left;
    vector<char> right;
}v[ALL_V];

class SLR {
public:
    map<pair<int,char>,actionGo> actiontable;//action子表
    map<pair<int,char>,int> gototable;//goto子表
    vector<char> txttoken;//余留符号串
    stack<int> now_num;//状态栈
    stack<char> now_id;//符号
};
class LL1 {
public:
    char FIRST_E[2] = {'(','i'};
    char FIRST_e[3] = {'+','-','!'};//'!' -> ?
    char FIRST_T[2] = {'(','i'};
    char FIRST_F[2] = {'(','i'};
    char FIRST_t[3]={'*','/','!'};
    char FOLLOW_E[2] = {'#',')'};
    char FOLLOW_e[2] = {'#',')'};
    char FOLLOW_t[4] = {'+','-','#',')'};
    char FOLLOW_F[6] = {'+','-','*','/','#',')'};
    char FOLLOW_T[4] = {'+','-','#',')'};
    map<pair<char,char>,int> LL1_table;
    stack<char> simple;
    void init_LL1(LL1 &LL1);//填表
    void doLL1(LL1 &LL1);//开始分析
};

void Init_V() {//初始化产生式
    v[0].left = 'S',v[0].right.resize(1),v[0].right[0] = 'E';
    v[1].left = 'E',v[1].right.resize(3),v[1].right[0]='E',v[1].right[1]='+',v[1].right[2]='T';
    v[2].left = 'E',v[2].right.resize(3),v[2].right[0] = 'E',v[2].right[1]='-',v[2].right[2]='T';
    v[3].left = 'E',v[3].right.resize(1),v[3].right[0] = 'T';
    v[4].left = 'T',v[4].right.resize(3),v[4].right[0] = 'T',v[4].right[1] = '*',v[4].right[2] = 'F';
    v[5].left = 'T',v[5].right.resize(3),v[5].right[0] = 'T',v[5].right[1] = '/',v[5].right[2] = 'F';
    v[6].left = 'T',v[6].right.resize(1),v[6].right[0] = 'F';
    v[7].left = 'F',v[7].right.resize(3),v[7].right[0] = '(',v[7].right[1] = 'E',v[7].right[2] = ')';
    v[8].left = 'F',v[8].right.resize(1),v[8].right[0] = 'i';
}

void fixtable(SLR &slr,actionGo &actiongo) {
    slr.actiontable[make_pair(0,')')] = {error,0,0};
    slr.actiontable[make_pair(0,'+')] = {error,0,0};
    slr.actiontable[make_pair(0,'-')] = {error,0,0};
    slr.actiontable[make_pair(0,'*')] = {error,0,0};
    slr.actiontable[make_pair(0,'/')] = {error,0,0};
    slr.actiontable[make_pair(0,'(')] = {S,4,-1};
    slr.actiontable[make_pair(0,'#')] = {error,0,0};
    slr.actiontable[make_pair(0,'i')] = {S,5,-1};


    slr.actiontable[make_pair(1,'+')] = {S,6,-1};
    slr.actiontable[make_pair(1,'-')] = {S,7,-1};
    slr.actiontable[make_pair(1,'#')] = {acc,-1,-1};
    slr.actiontable[make_pair(1,'(')] = {error,0,0};
    slr.actiontable[make_pair(1,')')] = {error,0,0};
    slr.actiontable[make_pair(1,'i')] = {error,0,0};
    slr.actiontable[make_pair(1,'*')] = {error,0,0};
    slr.actiontable[make_pair(1,'/')] = {error,0,0};


    slr.actiontable[make_pair(2,')')] = {r,-1,3};
    slr.actiontable[make_pair(2,'+')] = {r,-1,3};
    slr.actiontable[make_pair(2,'-')] = {r,-1,3};
    slr.actiontable[make_pair(2,'*')] = {S,8,-1};
    slr.actiontable[make_pair(2,'/')] = {S,9,-1};
    slr.actiontable[make_pair(2,'#')] = {r,-1,3};
    slr.actiontable[make_pair(2,'(')] = {error,0,0};
    slr.actiontable[make_pair(2,'i')] = {error,0,0};


    slr.actiontable[make_pair(3,')')] = {r,-1,6};
    slr.actiontable[make_pair(3,'+')] = {r,-1,6};
    slr.actiontable[make_pair(3,'-')] = {r,-1,6};
    slr.actiontable[make_pair(3,'*')] = {r,-1,6};
    slr.actiontable[make_pair(3,'/')] = {r,-1,6};
    slr.actiontable[make_pair(3,'#')] = {r,-1,6};
    slr.actiontable[make_pair(3,'(')] = {error,0,0};
    slr.actiontable[make_pair(3,'i')] = {error,0,0};


    slr.actiontable[make_pair(4,')')] = {error,0,0};
    slr.actiontable[make_pair(4,'+')] = {error,0,0};
    slr.actiontable[make_pair(4,'-')] = {error,0,0};
    slr.actiontable[make_pair(4,'*')] = {error,0,0};
    slr.actiontable[make_pair(4,'/')] = {error,0,0};
    slr.actiontable[make_pair(4,'#')] = {error,0,0};
    slr.actiontable[make_pair(4,'(')] = {S,4,-1};
    slr.actiontable[make_pair(4,'i')] = {S,5,-1};


    slr.actiontable[make_pair(5,'(')] = {error,0,0};
    slr.actiontable[make_pair(5,'i')] = {error,0,0};
    slr.actiontable[make_pair(5,')')] = {r,-1,8};
    slr.actiontable[make_pair(5,'+')] = {r,-1,8};
    slr.actiontable[make_pair(5,'-')] = {r,-1,8};
    slr.actiontable[make_pair(5,'*')] = {r,-1,8};
    slr.actiontable[make_pair(5,'/')] = {r,-1,8};
    slr.actiontable[make_pair(5,'#')] = {r,-1,8};


    slr.actiontable[make_pair(6,')')] = {error,0,0};
    slr.actiontable[make_pair(6,'+')] = {error,0,0};
    slr.actiontable[make_pair(6,'-')] = {error,0,0};
    slr.actiontable[make_pair(6,'*')] = {error,0,0};
    slr.actiontable[make_pair(6,'/')] = {error,0,0};
    slr.actiontable[make_pair(6,'#')] = {error,0,0};
    slr.actiontable[make_pair(6,'(')] = {S,4,-1};
    slr.actiontable[make_pair(6,'i')] = {S,5,-1};


    slr.actiontable[make_pair(7,')')] = {error,0,0};
    slr.actiontable[make_pair(7,'+')] = {error,0,0};
    slr.actiontable[make_pair(7,'-')] = {error,0,0};
    slr.actiontable[make_pair(7,'*')] = {error,0,0};
    slr.actiontable[make_pair(7,'/')] = {error,0,0};
    slr.actiontable[make_pair(7,'#')] = {error,0,0};
    slr.actiontable[make_pair(7,'(')] = {S,4,-1};
    slr.actiontable[make_pair(7,'i')] = {S,5,-1};


    slr.actiontable[make_pair(8,')')] = {error,0,0};
    slr.actiontable[make_pair(8,'+')] = {error,0,0};
    slr.actiontable[make_pair(8,'-')] = {error,0,0};
    slr.actiontable[make_pair(8,'*')] = {error,0,0};
    slr.actiontable[make_pair(8,'/')] = {error,0,0};
    slr.actiontable[make_pair(8,'#')] = {error,0,0};
    slr.actiontable[make_pair(8,'(')] = {S,4,-1};
    slr.actiontable[make_pair(8,'i')] = {S,5,-1};



    slr.actiontable[make_pair(9,')')] = {error,0,0};
    slr.actiontable[make_pair(9,'+')] = {error,0,0};
    slr.actiontable[make_pair(9,'-')] = {error,0,0};
    slr.actiontable[make_pair(9,'*')] = {error,0,0};
    slr.actiontable[make_pair(9,'/')] = {error,0,0};
    slr.actiontable[make_pair(9,'#')] = {error,0,0};
    slr.actiontable[make_pair(9,'(')] = {S,4,-1};
    slr.actiontable[make_pair(9,'i')] = {S,5,-1};


    slr.actiontable[make_pair(10,'#')] = {error,0,0};
    slr.actiontable[make_pair(10,'i')] = {error,0,0};
    slr.actiontable[make_pair(10,'/')] = {error,0,0};
    slr.actiontable[make_pair(10,'*')] = {error,0,0};
    slr.actiontable[make_pair(10,'(')] = {error,0,0};
    slr.actiontable[make_pair(10,')')] = {S,15,-1};
    slr.actiontable[make_pair(10,'+')] = {S,6,-1};
    slr.actiontable[make_pair(10,'-')] = {S,7,-1};


    slr.actiontable[make_pair(11,'(')] = {error,0,0};
    slr.actiontable[make_pair(11,'i')] = {error,0,0};
    slr.actiontable[make_pair(11,')')] = {r,-1,1};
    slr.actiontable[make_pair(11,'+')] = {r,-1,1};
    slr.actiontable[make_pair(11,'-')] = {r,-1,1};
    slr.actiontable[make_pair(11,'*')] = {S,8,-1};
    slr.actiontable[make_pair(11,'/')] = {S,8,-1};
    slr.actiontable[make_pair(11,'#')] = {r,-1,1};


    slr.actiontable[make_pair(12,'(')] = {error,0,0};
    slr.actiontable[make_pair(12,'i')] = {error,0,0};
    slr.actiontable[make_pair(12,')')] = {r,-1,2};
    slr.actiontable[make_pair(12,'+')] = {r,-1,2};
    slr.actiontable[make_pair(12,'-')] = {r,-1,2};
    slr.actiontable[make_pair(12,'*')] = {S,8,-1};
    slr.actiontable[make_pair(12,'/')] = {S,9,-1};
    slr.actiontable[make_pair(12,'#')] = {r,-1,2};


    slr.actiontable[make_pair(13,'(')] = {error,0,0};
    slr.actiontable[make_pair(13,'i')] = {error,0,0};
    slr.actiontable[make_pair(13,')')] = {r,-1,4};
    slr.actiontable[make_pair(13,'+')] = {r,-1,4};
    slr.actiontable[make_pair(13,'-')] = {r,-1,4};
    slr.actiontable[make_pair(13,'*')] = {r,-1,4};
    slr.actiontable[make_pair(13,'/')] = {r,-1,4};
    slr.actiontable[make_pair(13,'#')] = {r,-1,4};


    slr.actiontable[make_pair(14,'(')] = {error,0,0};
    slr.actiontable[make_pair(14,'i')] = {error,0,0};
    slr.actiontable[make_pair(14,')')] = {r,-1,5};
    slr.actiontable[make_pair(14,'+')] = {r,-1,5};
    slr.actiontable[make_pair(14,'-')] = {r,-1,5};
    slr.actiontable[make_pair(14,'*')] = {r,-1,5};
    slr.actiontable[make_pair(14,'/')] = {r,-1,5};
    slr.actiontable[make_pair(14,'#')] = {r,-1,5};


    slr.actiontable[make_pair(15,'(')] = {error,0,0};
    slr.actiontable[make_pair(15,'i')] = {error,0,0};
    slr.actiontable[make_pair(15,')')] = {r,-1,7};
    slr.actiontable[make_pair(15,'+')] = {r,-1,7};
    slr.actiontable[make_pair(15,'-')] = {r,-1,7};
    slr.actiontable[make_pair(15,'*')] = {r,-1,7};
    slr.actiontable[make_pair(15,'/')] = {r,-1,7};
    slr.actiontable[make_pair(15,'#')] = {r,-1,7};
    slr.gototable[make_pair(0,'E')] = 1;
    slr.gototable[make_pair(0,'T')] = 2;
    slr.gototable[make_pair(0,'F')] = 3;
    slr.gototable[make_pair(4,'E')] = 10;
    slr.gototable[make_pair(4,'T')] = 2;
    slr.gototable[make_pair(4,'F')] = 3;
    slr.gototable[make_pair(6,'T')] = 11;
    slr.gototable[make_pair(6,'F')] = 3;
    slr.gototable[make_pair(7,'T')] = 12;
    slr.gototable[make_pair(7,'F')] = 3;
    slr.gototable[make_pair(8,'F')] = 13;
    slr.gototable[make_pair(9,'F')] = 14;
}

void doSLR(SLR &slr) {
    //设置初始状态和最终的acc的#号
    slr.now_num.push(0);//状态栈->0
    slr.now_id.push('#');//符号栈->#
    int i = 0;
    int r_length = -1;//规约时代表产生式右部的符号数量
    char l_char;//规约时代表产生式左部的符号
    while (true) {//开始循环分析
        int now_state = slr.now_num.top();//当前的状态符号 = 符号栈栈顶符号
        char now_id = NULL;
        if(txt[i] != NULL) {
            now_id = txt[i];//当前匹配的符号
        }
        if(now_id != 'i' && now_id != '+' && now_id != '-' && now_id != '*'&&now_id != '/'&&now_id != '('&&now_id != ')'&&now_id != '#' && now_id != NULL) {
            cout<<"有不合法的输入,分析终止!"<<endl;
            break;
        }
        actionGo ag = slr.actiontable[make_pair(now_state,now_id)];//匹配当前的状态与符号,找动作
        if(ag.action == S) {
            //根据不同的动作开始分析
            slr.now_num.push(ag.s);//状态进栈
            slr.now_id.push(now_id);//当前符号进符号栈
            i++;//指向下一个待匹配的符号
        }else if(ag.action == r) {
            r_length = v[ag.r].right.size();//统计产生式右部的符号个数
            for(int j = 0;j<r_length;++j) {
                slr.now_num.pop();//状态栈弹栈
                slr.now_id.pop();//符号栈弹栈
            }
            l_char = v[ag.r].left;//产生式左部的符号
            slr.now_id.push(l_char);//左部符号入栈
            int go_to = slr.gototable[make_pair(slr.now_num.top(),l_char)];//找goto的状态
            slr.now_num.push(go_to);//新状态入栈
        }else if(ag.action == acc) {
            flag = 1;
            cout<<"分析成功!"<<endl;
            break;
        }else{
            cout<<"分析失败!"<<endl;
            break;
        }
    }
}

void LL1::init_LL1(LL1 &LL1) {

    LL1.LL1_table[make_pair('E','i')] = 1;
    LL1.LL1_table[make_pair('E','(')] = 1;
    LL1.LL1_table[make_pair('E','+')] = -1;
    LL1.LL1_table[make_pair('E','-')] = -1;
    LL1.LL1_table[make_pair('E','*')] = -1;
    LL1.LL1_table[make_pair('E','/')] = -1;
    LL1.LL1_table[make_pair('E',')')] = -1;
    LL1.LL1_table[make_pair('E','#')] = -1;

    LL1.LL1_table[make_pair('e','+')] = 2;
    LL1.LL1_table[make_pair('e','-')] = 3;
    LL1.LL1_table[make_pair('e',')')] = 4;
    LL1.LL1_table[make_pair('e','#')] = 4;
    LL1.LL1_table[make_pair('e','i')] = -1;
    LL1.LL1_table[make_pair('e','*')] = -1;
    LL1.LL1_table[make_pair('e','/')] = -1;
    LL1.LL1_table[make_pair('e','(')] = -1;

    LL1.LL1_table[make_pair('T','i')] = 5;
    LL1.LL1_table[make_pair('T','(')] = 5;
    LL1.LL1_table[make_pair('T','+')] = -1;
    LL1.LL1_table[make_pair('T','-')] = -1;
    LL1.LL1_table[make_pair('T','*')] = -1;
    LL1.LL1_table[make_pair('T','/')] = -1;
    LL1.LL1_table[make_pair('T',')')] = -1;
    LL1.LL1_table[make_pair('T','#')] = -1;

    LL1.LL1_table[make_pair('t','+')] = 8;
    LL1.LL1_table[make_pair('t','-')] = 8;
    LL1.LL1_table[make_pair('t','*')] = 6;
    LL1.LL1_table[make_pair('t','/')] = 7;
    LL1.LL1_table[make_pair('t',')')] = 8;
    LL1.LL1_table[make_pair('t','#')] = 8;
    LL1.LL1_table[make_pair('t','i')] = -1;
    LL1.LL1_table[make_pair('t','(')] = -1;

    LL1.LL1_table[make_pair('F','i')] = 10;
    LL1.LL1_table[make_pair('F','(')] = 9;
    LL1.LL1_table[make_pair('F','#')] = -1;
    LL1.LL1_table[make_pair('F','+')] = -1;
    LL1.LL1_table[make_pair('F','-')] = -1;
    LL1.LL1_table[make_pair('F','*')] = -1;
    LL1.LL1_table[make_pair('F','/')] = -1;
    LL1.LL1_table[make_pair('F',')')] = -1;

}

void LL1::doLL1(LL1 &LL1) {
    int index = 0;//用于指向txt的下一个符号
    /*开始匹配*/
    int now_state;
    /*先压栈开始符# 与初始状态E*/
    LL1.simple.push('#');
    LL1.simple.push('E');
    while (true){
        if(simple.top() == txt[index]) {//栈顶元素与当前符号匹配,直接消除
            if(simple.top() == '#') {//分析成功的情况
                cout<<"分析成功!"<<endl;
                flag = 1;
                break;
            }else {
                simple.pop();
                index++;
            }
        }
        now_state = LL1.LL1_table[make_pair(LL1.simple.top(),txt[index])];
        if(now_state == -1) {
            cout<<"分析失败"<<endl;
            flag = 0;
            break;
        }else {
            switch (now_state) {
                case 1:
                    simple.pop();//当前符号弹栈
                /*反向压栈*/
                simple.push('e');
                simple.push('T');
                break;
                case 2:
                    simple.pop();
                simple.push('e');
                simple.push('T');
                simple.push('+');
                break;
                case 3:
                    simple.pop();
                simple.push('e');
                simple.push('T');
                simple.push('+');
                break;
                case 4:
                    simple.pop();
                break;
                case 5:
                    simple.pop();
                simple.push('t');
                simple.push('F');
                break;
                case 6:
                    simple.pop();
                simple.push('t');
                simple.push('F');
                simple.push('*');
                break;
                case 7:
                    simple.pop();
                simple.push('t');
                simple.push('F');
                simple.push('/');
                break;
                case 8:
                    simple.pop();
                break;
                case 9:
                    simple.pop();
                simple.push(')');
                simple.push('E');
                simple.push('(');
                break;
                case 10:
                    simple.pop();
                simple.push('i');
            }
        }
    }
}


void txt_cin(ifstream &fin) {//输入文本,并转换为该文法
    fin.open("D:/Class_Code/bianyiyuanli_Code/shiyan1_to_2.txt");
    string s;
    int i = 0;
    txt.resize(50);
    while (getline(fin,s)) {
        if(s == "ID" || s == "DATA_INT" || s == "DATA_FLOAT") {
            txt[i++] = 'i';
        }else if(s == "PL") {
            txt[i++] = '+';
        }else if(s == "MI") {
            txt[i++] = '-';
        }else if(s == "MU") {
            txt[i++] = '*';
        }else if(s == "DI") {
            txt[i++] = '/';
        }else if(s == "IS") {
            txt[i++] = '=';
        }else if(s == "LEFT") {
            txt[i++] = '(';
        }else if(s == "RIGHT") {
            txt[i++] = ')';
        }
    }
    txt[i] = '#';
    fin.close();
}
string get_s() {//组成句子
    string s;
    for(int i = 0;i<txt.size();i++) {
        if(txt[i] != NULL && txt[i]!='#') {
            s = s+txt[i];
        }
    }
    return s;
}
void print(string s) {//输出结果
    if(flag == 1) {
        cout<<s<<endl;
        cout<<"该句子是该文法的句型!";
    }else {
        cout<<s<<endl;
        cout<<"该句子不是该文法的句型!";
    }
}
void test() {
    ifstream fin;
    txt_cin(fin);//从文件中获取单词
    string s = get_s();//将单词->句子
    Init_V();//初始化产生式
    SLR slr;//创建一张SLR分析表
    actionGo actiongo;//创建一个动作表
    fixtable(slr,actiongo);//填表
    doSLR(slr);//做SLR分析
    print(s);//打印最终结果
}
void test2() {
    ifstream fin;
    txt_cin(fin);//从文件中获取单词
    string s = get_s();//将单词->句子
    LL1 LL1;//创建LL1对象
    LL1.init_LL1(LL1);//初始化LL1
    LL1.doLL1(LL1);
    print(s);//打印最终结果
}

int main(void) {
    //test();
    test2();
    return 0;
}

附录c 编译程序实验 实验目的:用c语言对一个简单语言的子集编制一个一遍扫描的编译程序,以加深对编译原理的理解,掌握编译程序的实现方法和技术。 语法分析 C2.1 实验目的 编制一个递归下降分析程序,实现对词法分析程序所提供的单词序列的语法检查和结构分析. C2.2 实验要求 利用C语言编制递归下降分析程序,并对简单语言进行语法分析. C2.2.1待分析的简单语言的语法 实验目的 通过上机实习,加深对语法制导翻译原理的理解,掌握将语法分析所识别的语法成分变换为中间代码的语义翻译方法. 实验要求 采用递归下降语法制导翻译法,对算术表达式、赋值语句进行语义分析并生成四元式序列。 实验的输入和输出 输入是语法分析提供的正确的单词串,输出为三地址指令形式的四元式序列。 例如:对于语句串 begin a:=2+3*4;x:=(a+b)/c end# 输出的三地址指令如下: (1) t1=3*4 (2) t2=2+t1 (3) a=t2 (4) t3=a+b (5) t4=t3/c (6) x=t4 算法思想 1设置语义过程 (1) emit(char *result,char *arg1,char *op,char *ag2) 该函数功能是生成一个三地址语句送到四元式表中。 四元式表的结构如下: struct {char result[8]; char ag1[8]; char op[8]; char ag2[8]; }quad[20]; (2)char *newtemp() 该函数回送一个新的临时变量名,临时变量名产生的顺序为T1,T2,…. Char *newtemp(void) { char *p; char m[8]; p=(char *)malloc(8); k++; itoa(k,m,10); strcpy(p+1,m); p[0]=’t’; return(p); } (2)主程序示意图如图c.10所示。 (2) 函数lrparser在原来语法分析的基础上插入相应的语义动作:将输入串翻译成四元式序列。在实验中我们只对表达式、赋值语句进行翻译。 语义分析程序的C语言程序框架 int lrparser() { int schain=0; kk=0; if(syn=1) { 读下一个单词符号; schain=yucu; /调用语句串分析函数进行分析/ if(syn=6) { 读下一个单词符号; if(syn=0 && (kk==0)) 输出(“success”); } else { if(kk!=1 ) 输出 ‘缺end’ 错误;kk=1;} else{输出’begin’错误;kk=1;} } return(schain); int yucu() { int schain=0; schain=statement();/调用语句分析函数进行分析/ while(syn=26) {读下一个单词符号; schain=statement(); /调用语句分析函数进行分析/ } return(schain); } int statement() { char tt[8],eplace[8]; int schain=0; {switch(syn) {case 10: strcpy(tt,token); scanner(); if(syn=18) {读下一个单词符号; strcpy(eplace,expression()); emit(tt,eplace,””,””); schain=0; } else {输出’缺少赋值号’的错误;kk=1; } return(schain); break; } } char *expression(void) {char *tp,*ep2,*eplace,*tt; tp=(char *)malloc(12);/分配空间/ ep2=(char *)malloc(12); eplace=(char *)malloc(12); tt =(char )malloc(12); strcpy(eplace,term ());/调用term分析产生表达式计算的第一项eplace/ while(syn=13 or 14) { 操作符 tt= ‘+’或者‘—’; 读下一个单词符号; strcpy(ep2,term());/调用term分析产生表达式计算的第项ep2/ strcpy(tp,newtemp());/调用newtemp产生临时变量tp存储计算结果/ emit(tp,eplace,tt,ep2);/生成四元式送入四元式表/ strcpy(eplace,tp); } return(eplace); } char *term(void)/仿照函数expression编写/ char *factor(void) {char *fplace; fplace=(char *)malloc(12); strcpy(fplace, “ ”); if(syn=10) {strcpy(fplace,,token);/将标识符token的值赋给fplace/ 读下一个单词符号; } else if(syn=11) {itoa(sum,fplace,10); 读下一个单词符号; } else if (syn=27) {读下一个单词符号; fplace=expression();/调用expression分析返回表达式的值/ if(syn=28) 读下一个单词符号; else{输出‘}’错误;kk=1; } } else{输出‘(’错误;kk=1; } return(fplace); }
这个里面的都是测试数据,总共得分5分。从控制台输入,不能从文件中读取。实现了基本功能,加分项目都没有去实现,没有函数数组这些的实现。这是用C++语言写的,新建parser类别要选C++,其他对于VS的配置和C语言一样。for语句用的是枚举所有情况,你可以自行修改。 对预备工作中自然语言描述的简化C编译器的语言特性的语法,设计上下文无关文法进行描述 借助Yacc工具实现语法分析器 考虑语法树的构造: 1.语法树数据结构的设计:节点类型的设定,不同类型节点应保存哪些信息,多叉树的实现方式 2.实现辅助函数,完成节点创建、树创建等功能 3.利用辅助函数,修改上下文无关文法,设计翻译模式 4.修改Yacc程序,实现能构造语法树的分析器 考虑符号表处理的扩充 1.完成语法分析后,符号表项应增加哪些标识符的属性,保存语法分析的结果 2.如何扩充符号表数据结构,Yacc程序如何与Lex程序交互,正确填写符号表项 以一个简单的C源程序验证你的语法分析器,可以文本方式输出语法树结构,以节点编号输出父子关系,来验证分析器的正确性,如下例: main() { int a, b; if (a == 0) a = b + 1; } 可能的输出为: 0 : Type Specifier, integer, Children: 1 : ID Declaration, symbol: a Children: 2 : ID Declaration, symbol: b Children: 3 : Var Declaration, Children: 0 1 2 4 : ID Declaration, symbol: a Children: 5 : Const Declaration, value:0, Children: 6 : Expr, op: ==, Children: 4 5 7 : ID Declaration, symbol: a Children: 8 : ID Declaration, symbol: b Children: 9 : Const Declaration, value:1, Children: 10: Expr, op: +, Children: 8 9 11: Expr, op: =, Children: 7 10 12: if statement, Children: 6 11 13: compound statement, Children: 3 12
语法分析编译原理中的重要部分,它的作用是将词法分析阶段得到的词法单元序列转换成抽象语法树(AST)或语法分析树(Parse Tree),以便于后续的语义分析、中间代码生成和目标代码生成等环节的进行。在本次实验中,我们将使用Java语言实现一个简单的语法分析器。 实验要求: 1. 实现自顶向下的递归下降分析器2. 支持的文法如下: ``` <program> ::= <stmts_list> <stmts_list> ::= <stmt> | <stmts_list> <stmt> <stmt> ::= <if_stmt> | <while_stmt> | <assign_stmt> <if_stmt> ::= if <condition> then <stmts_list> end <while_stmt> ::= while <condition> do <stmts_list> end <assign_stmt> ::= <id> = <expr> <condition> ::= <expr> <relop> <expr> <expr> ::= <term> | <expr> <addop> <term> <term> ::= <factor> | <term> <mulop> <factor> <factor> ::= <id> | <number> | '(' <expr> ')' <relop> ::= '<' | '>' | '=' | '<=' | '>=' | '<>' <addop> ::= '+' | '-' <mulop> ::= '*' | '/' <id> ::= <letter> | <id> <letter> | <id> <digit> <number> ::= <digit> | <number> <digit> <letter> ::= A | B | ... | Z | a | b | ... | z <digit> ::= 0 | 1 | ... | 9 ``` 注意:文法中的关键字 if、then、end、while、do、and 等均为保留字。 3. 实现的语法分析器应具备以下功能: - 能够识别出语法正确的程序,并输出相应的语法分析树或抽象语法树。 - 能够识别出语法错误的程序,并给出相应的错误提示信息。 - 能够处理注释和空格等无意义的字符。 4. 实验提交要求: - 实验报告,包括程序设计和实验结果分析。 - 程序源代码。 实验设计思路: 1. 根据给定的文法,设计语法分析器的语法规则和对应的产生式。 2. 编写相应的Java代码,将文法转换为递归下降分析器所需要的形式。 3. 实现从输入的源代码中读取词法单元序列的功能。 4. 实现递归下降分析器的核心算法,对输入的词法单元序列进行语法分析,并构建相应的语法分析树或抽象语法树。 5. 在语法分析过程中,需要处理注释和空格等无意义的字符,以便于正确识别语法错误。 6. 在语法分析过程中,需要对输入的源代码进行错误检查,并给出相应的错误提示信息。 7. 输出语法分析树或抽象语法树,以便于后续的语义分析、中间代码生成和目标代码生成等环节的进行。 实验结果分析: 经过实验测试,我们的语法分析器能够正确地识别出合法的程序,并输出相应的语法分析树或抽象语法树。同时,它也能够正确地识别出语法错误的程序,并给出相应的错误提示信息。总的来说,本次实验取得了较好的实验效果。 实验源代码: 见下方代码框:
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值