【编译原理实验】词法分析(Thompson)


实验使用 Code::Blocks C++编写

【实验目标】

  1. 编写一个词法分析程序,要求能够根据用户给定的任意正则表达式,测试数据是否符合给定的正则表达式规范。
  2. 采用Thompson算法将正规式转化为NFA并输出NFA状态转换矩阵;
  3. 利用子集法构造DFA并输出DFA状态转换矩阵;
  4. 用最小化算法得到最小DFA并输出该DFA的状态转换矩阵,用DFA的模拟器算法识别任意输入单词;
  5. 程序测试数据的一个示例如下:
    输入正则表达式:(a|b)*abb
    采用Thompson算法将正规式转化为NFA并输出NFA状态转换矩阵,利用子集法构造DFA并输出DFA状态转换矩阵,用最小化算法得到最小DFA并输出该DFA的状态转换矩阵,最后用DFA的模拟器算法识别任意输入单词:
    输入测试表达式: abb 输出判定结果:符合词法定义
    输入测试表达式:abab 输出判定结果:不符合词法定义

【实验算法】

(1)Thompson算法:语法树构造

算法1. 构造语法树
输入:正则表达式
输出:由正则表达式构建的语法分析树

  • 建符号栈和语法栈

  • 将#压入符号栈

  • 扫描正则表达式,直到扫到结束符#为止,对每次扫描的字符进行如下操作
    字符为操作数,则包装为叶子节点,节点指针入操作数栈;
    字符为操作符,做如下操作:

    1. 当操作符为’)‘时 ,将与第一个’('之间的操作符栈清空,具体方法如下:
      (1)读取栈顶,将栈顶操作符取出;
      (2)根据操作符对操作数栈实行相应操作;
      (循环(1)(2)步骤直到栈顶为’(’)
      (3)删除栈顶操作符‘(’;

    2. 当操作符为’'时,’’优先级最高,操作数栈顶,重新包装入栈。

    3. 当操作符‘|’、‘+’、‘(’时
      (1)与栈顶操作符进行优先级比较;
      (2)比栈顶优先级低,则栈顶运算符出栈,根据操作符对操作数栈实行相应操作; (循环(1)(2)直到不满足条件(2)条件)
      (3)此时操作符比栈顶优先级高,压入栈;

  • 此时正则表达式全部扫描结束,清空操作符栈,具体方法如下:
    (1)读取栈顶,将栈顶操作符取出;
    (2)根据操作符对操作数栈实行相应操作;
    (循环(1)(2)步骤直到栈顶为’#’)
    结束,此时操作数栈内唯一一个节点指针为语法树树根。

(2)Thompson算法:Thompson算法构造NFA

算法1. Thompson算法构造NFA
输入:语法树
输出:NFA状态转移矩阵Skips_graph
在这里插入图片描述
(3)由NFA到DFA

算法1. NFA到DFA(子集法)
输入:状态集Set,NFA的空跳转
输出:状态集Set的空闭包
在这里插入图片描述在这里插入图片描述
(4)最小化DFA

算法1. 最小化DFA算法
输入:DFA
输出:最小化后的DFA
在这里插入图片描述

【实验完整代码】

#include <iostream>
#include <typeinfo>
#include <stdio.h>
#include <iomanip>
using namespace std;

const int Maxnum=100;

//数据结构
//根节点
typedef struct Node{
    char type;//根节点类型
    char Char;//叶子结点代表的字符
    Node *lchild;//左子树
    Node *rchild;//右子树
    int start_S;//起始状态
    int end_S;//终结状态
    }*Tree_root;
//初始化根节点
void default_Node(Node* N){
    N->lchild=N->rchild=NULL;
}
//包装叶子节点
Node* default_L_Node(char c){
    Node *N=new Node;
    default_Node(N);
    N->Char=c;
    N->type='l';
    return N;
}
//后根遍历语法树
int vist_Tree(Tree_root Tree){
    if(Tree->type=='l') //是根节点
        {cout<<Tree->Char<<" ";return 1;}
    else
    {
        vist_Tree(Tree->lchild);
        if(Tree->rchild!=NULL) vist_Tree(Tree->rchild);
        cout<<Tree->type<<" ";return 1;}
}

//包装根节点
Node* default_R_Node(char type,Node* lchild,Node* rchild){

    Node *N=new Node;
    default_Node(N);
    N->type=type;
    N->lchild=lchild;
    N->rchild=rchild;
    return N;
}

//符号栈
typedef struct operator_Stack{
    char* top;//栈顶
    char* bottom;//栈底
    char St[Maxnum]; //数组作为栈
    };

//初始化栈
void default_op_stack(operator_Stack &S){
    S.top=S.bottom=S.St;
}
//入栈
void push_op(operator_Stack &S,char a){
    *(S.top)=a;
    S.top++;
}
//出栈
char pop_op(operator_Stack &S){
    S.top--;
    return *S.top;
}
//获得栈顶元素
char top_op(operator_Stack &S){
    return *(S.top-1);
}

//语法栈
typedef struct syntax_Stack{
    int top;//栈顶
    int bottom;//栈底
    Node* St[Maxnum]; //节点数组作为栈
    };
//初始化栈
void default_sy_stack(syntax_Stack &S){
    S.top=S.bottom=0;
}
//入栈
void push_char(syntax_Stack &S,Node* a){
    S.St[S.top]=a;
    S.top++;
}
//出栈
Node* pop_char(syntax_Stack &S){
    S.top--;
    return S.St[S.top];
}

//运算符转换对应优先级
int o_astype(char o){
    switch ( o ){
    case '#':
        return 1;
    case  '('   :
       return  2;
    case  '|':
        return 3;
    case  '+':
        return 4;
    case  ')':
        return 5;
    case '*':
        return 6;
    default  :
        return 0; //不是操作符
    }
}


//判断是否加入连接运算符
bool if_cat(char l,char r){

    if(!o_astype(l)&&r=='(')  //char+(
        return 1;
    else if(!o_astype(l)&&!o_astype(r)) //char+char
        return 1;
    else if(l==')'&&!o_astype(r))  //)+char
        return 1;
    else if(l=='*'&&!o_astype(r))  //*+char
        return 1;
    else if(l==')'&&r=='(')  //)+(
        return 1;
    else if(l=='*'&&r=='(')  //*+(
        return 1;
    else return 0;
       }

//输入正则表达式
string cin_Regular_Exp(){
    cout<<"请输入正则表达式:";
    string R_exp;
    cin>>R_exp;
    R_exp.insert(0,"#");
    R_exp.append("#");  //加入结束符
    //将正则表达式加入cat连接符
    int l=0,r=1;
    while(R_exp[r]!='#'){
        if(if_cat(R_exp[l],R_exp[r]))
            R_exp.insert(l+1,"+");
        l++;r++;}
    return R_exp;
}

//比较运算符优先级
bool if_high(char odd_op,char new_op){
    int odd_=o_astype(odd_op);
    int new_=o_astype(new_op);
    if(new_>odd_) return 1;
    return 0;
}
//根据运算符连接节点
Node* Connect_Nodes(char op,syntax_Stack& char_st){
    switch ( op ){
    case  '|': //双目运算符
        return default_R_Node(op,pop_char(char_st),pop_char(char_st));
    case  '+': //双目运算符
        return default_R_Node(op,pop_char(char_st),pop_char(char_st));;
    case  '*': //单目运算符
        return default_R_Node(op,pop_char(char_st),NULL);
    }
}
//构造语法树
Tree_root Syntax_Tree(string exp){
    //建符号栈和语法栈
    operator_Stack op_st;
    syntax_Stack char_st;
    default_op_stack(op_st);
    default_sy_stack(char_st);
    //将#压入符号栈
    push_op(op_st,exp[0]);
    //扫描(除了开头和结尾的#)
    for(int i=1;i<exp.size()-1;i++)
    {
        char c=exp[i];
        if(!o_astype(c)) //语法内容
            push_char(char_st,default_L_Node(c)); //包装叶子节点,压入语法栈
        else//符号
        {
            if(c=='(')
            {
                push_op(op_st,'(');//直接入栈
            }
            else if(c==')') //将遇到'('之间栈清空
            {   while(top_op(op_st)!='(')
                {
                    char op=pop_op(op_st);
                    push_char(char_st,Connect_Nodes(op,char_st));
                }
                pop_op(op_st);
            }
            else if(c=='*') //遇到最高运算符,直接操作
                push_char(char_st,Connect_Nodes(c,char_st));
            else{
            while(!if_high(top_op(op_st),c)) //循环比较,直到比栈顶操作符优先级高
            {
                char op=pop_op(op_st);//栈顶元素出栈
                push_char(char_st,Connect_Nodes(op,char_st));//得到新的根节点
            }
                push_op(op_st,c);//压入符号栈
            }
        }
    }
    //扫描全部结束 将栈内剩余部分连接
    while(top_op(op_st)!='#')
    {
        char op=pop_op(op_st);
        push_char(char_st,Connect_Nodes(op,char_st));
    }
    cout<<"结束"<<endl;
    return char_st.St[char_st.bottom];
}


//在字符数组中加入新元素,若已经存在,则返回数组编号
int add_find_char(char *A,char a,int& size_){
    if(size_==0) {A[0]=a;size_++;return Maxnum;}
    else{
        int i;
        for(i=0;i<size_;i++)
            if(*(A+i)==a) return i;  //找到了 不添加
        A[i]=a;size_++;
        return Maxnum; //没找到,添加
    } }
//得到正则表达式的吸收符号
int Get_absorb_char(string exp,char *ab_chars){
    int char_size = 0;
    for(int i=0;i<exp.size();i++){
        if(!o_astype(exp[i])) //不是操作符
            add_find_char(ab_chars,exp[i],char_size);}
    return char_size;
}
//状态集
typedef struct states_set{
    int st_set[Maxnum];
    int length=0;};
//图的矩阵表示
typedef struct Skips_graph{
    int S_size;//状态数
    int ab_char_size; //吸收字符种类数
    char absorb_char[Maxnum]; //吸收字符
    int Skips[Maxnum][Maxnum]; //状态跳转
    int empty_Skips[Maxnum][Maxnum]; //空状态跳转 每行第一列放该状态的空跳转数
    int start_S; //起点
    int end_S; //终点(对nfa而言,只有一个终点)
    states_set end_set; //终点集(对于dfa而言,有多个终点)
};
//初始化状态转移矩阵
void default_graph(Skips_graph &S,char *ab_char,int ab_char_size){
    S.S_size=0;
    S.ab_char_size=ab_char_size;
    for(int i=0;i<ab_char_size;i++)
        S.absorb_char[i]=ab_char[i];
    for(int i=0;i<Maxnum;i++)
        for(int j=0;j<Maxnum;j++)
            S.Skips[i][j]=Maxnum;   //表示无跳转
    for(int i=0;i<Maxnum;i++)
        S.empty_Skips[i][0]=0;   //空跳转个数为0
    }
//添加新的状态跳转 图 起点 终点 吸收字符
void add_Skips(Skips_graph& S,int B,int E,char c){
    int ab_char=add_find_char(S.absorb_char,c,S.ab_char_size);
    S.Skips[B][ab_char]=E;
    }
void add_empty_Skips(Skips_graph& S,int B,int E){
    S.empty_Skips[B][0]=S.empty_Skips[B][0]+1; //空跳转数加一
    int size_=S.empty_Skips[B][0];
    S.empty_Skips[B][size_]=E;}
//构造叶子节点状态转移
void Leaf_Skip(Skips_graph& S,Node& N){
    N.start_S=S.S_size;S.S_size++;
    N.end_S=S.S_size;S.S_size++;
    add_Skips(S,N.start_S,N.end_S,N.Char); //添加始末状态转移
    }
//构造根状态转移
void root_Skip(Skips_graph& S,Node& N){
    //或根构造
    if(N.type=='|'){
        N.start_S=S.S_size;S.S_size++;
        N.end_S=S.S_size;S.S_size++;
        add_empty_Skips(S,N.start_S,N.lchild->start_S);
        add_empty_Skips(S,N.start_S,N.rchild->start_S);
        add_empty_Skips(S,N.lchild->end_S,N.end_S);
        add_empty_Skips(S,N.rchild->end_S,N.end_S);}
    //闭包构造
    else if(N.type=='*'){
        N.start_S=S.S_size;S.S_size++;
        N.end_S=S.S_size;S.S_size++;
        add_empty_Skips(S,N.start_S,N.lchild->start_S);
        add_empty_Skips(S,N.start_S,N.end_S);
        add_empty_Skips(S,N.lchild->end_S,N.lchild->start_S);
        add_empty_Skips(S,N.lchild->end_S,N.end_S);}
    //连接构造
    else if(N.type=='+'){
        N.start_S=N.lchild->start_S;
        N.end_S=N.rchild->end_S;
        add_empty_Skips(S,N.lchild->end_S,N.rchild->start_S);}
    else {cout<<"fault!";}
}

//递归构造NFA
void NFA(Tree_root Tree, Skips_graph &S, string exp){
    //构造状态转移矩阵
    if(Tree->type=='l') //叶子状态转移
        Leaf_Skip(S,*Tree);
    else
    {
        NFA(Tree->lchild,S,exp); //构造左子树状态转移
        if(Tree->rchild!=NULL) NFA(Tree->rchild,S,exp); //构造右子树状态转移
        root_Skip(S,*Tree);//构造根状态转移}
}}

void NFA_(Tree_root Tree, Skips_graph &S, string exp){
    //得到吸收符号
    char ab_chars[Maxnum]; //正则表达式中的吸收符号
    int ab_chars_size=Get_absorb_char(exp,ab_chars);
    //初始化状态转移(NFA)
    default_graph(S,ab_chars,ab_chars_size);
    //构造
    NFA(Tree,S,exp);
    S.start_S=Tree->start_S;S.end_S=Tree->end_S;}
//读NFA
void vist_Graph(Skips_graph &S,string type){
    cout<<"状态跳转矩阵:"<<endl;
    cout<<"状态";
    for(int i=0;i<S.ab_char_size;i++)
        cout<<setw(6)<<S.absorb_char[i];
    cout<<setw(8)<<"空跳转";
    cout<<endl;
    for(int i=0;i<S.S_size;i++)
        {cout<<setw(3)<<i;
        for(int j=0;j<S.ab_char_size;j++)
            if(S.Skips[i][j]==Maxnum) cout<<setw(6)<<"-";
            else cout<<setw(6)<<S.Skips[i][j];
        //输出空跳转
        cout<<setw(6)<<" ";
        for(int j=0;j<S.empty_Skips[i][0];j++)
            cout<<S.empty_Skips[i][j+1]<<" ";
        cout<<endl;}
    cout<<"起点:"<<S.start_S<<" ";
    if(type=="nfa") cout<<"终点:"<<S.end_S<<" ";
    else{
        cout<<"终点:";
        for(int i=0;i<S.end_set.length;i++)
            cout<<S.end_set.st_set[i]<<" ";
    }
    cout<<endl;}

//向状态集中添加元素
bool add_s_to_set(states_set &Set,int s){
    for(int i=0;i<Set.length;i++){
        if(Set.st_set[i]==s) return 0;
    }
    Set.st_set[Set.length]=s;
    Set.length++;
    return 1;
}
//求集合的空闭包 空跳转
void empty_closure(states_set &Set,int empty_Skips[][Maxnum]){
    for(int i=0;i<Set.length;i++){
        int p=Set.st_set[i];
        for(int j=0;j<empty_Skips[p][0];j++){
            add_s_to_set(Set,empty_Skips[p][j+1]);}
        }
    cout<<"闭包:"<<endl;
    for(int i=0;i<Set.length;i++) cout<<Set.st_set[i]<<" ";cout<<endl;
}

//计算从当前状态集出发,经过a字符,能到的下一个状态集
void Smove(states_set Set,states_set &next_Set,int absorb_char,Skips_graph &nfa){
    //对每个状态都计算经过a得到的新状态
    for(int i=0;i<Set.length;i++)
    {   int nfa_i=Set.st_set[i];  //在nfa中的状态
        if(nfa.Skips[nfa_i][absorb_char]!=Maxnum) //有跳转
            add_s_to_set(next_Set,nfa.Skips[nfa_i][absorb_char]);}
}
//判断当前状态集是否存在,若存在则返回新状态,若不存在则返回0
int if_exist(states_set *Sets,states_set Set,int sets_length){
    //找到长度相等的进行比对
    int T; //判断是否有相同的状态集
    for(int i=0;i<sets_length;i++){
        if(Sets[i].length==Set.length){
            T=1; //先假设该集合是
            for(int j=0;j<Set.length;j++){
                int t=0; //判断是否找到相同元素
                for(int k=0;k<Sets[i].length;k++)
                    if(Set.st_set[j]==Sets[i].st_set[k]){t=1;break;}
                if(t==0) {T=0;break;} //找不到,该集合不是
                }
            if(T==1) return i;
        }}
    return 0;
}
//NFA转为DFA
void DFA(Skips_graph &nfa,Skips_graph &dfa,states_set *sets){
    for(int i=0;i<dfa.S_size;i++){
        //计算当前状态的跳转状态集 c为吸收字符
        for(int c=0;c<dfa.ab_char_size;c++){
            states_set next_set;
            Smove(sets[i],next_set,c,nfa);//计算Smove(j,char)
            if(next_set.length==0) continue; //该状态不吸收该字符
            empty_closure(next_set,nfa.empty_Skips);//计算Smove的空闭包
            //判断该状态集是否已经存在,如果不存在则作为新状态集加入dfa
            int S=if_exist(sets,next_set,dfa.S_size);
            if(!S){
                S=dfa.S_size;
                sets[S]=next_set;
                dfa.S_size++;
            }
            //在dfa上添加当前状态吸收字符的跳转
            dfa.Skips[i][c]=S;
        }
    }
}
//判断集合中是否有某个元素
bool find_s(states_set set_,int s){
    for(int i=0;i<set_.length;i++)
        if(set_.st_set[i]==s) return 1;
    return 0;
    }
void DFA_(Skips_graph &nfa,Skips_graph &dfa){
    //初始化dfa
    default_graph(dfa,nfa.absorb_char,nfa.ab_char_size);
    states_set sets[Maxnum];//新旧状态表
    //先求起始状态的空闭包
    states_set begin_set;
    add_s_to_set(begin_set,nfa.start_S);
    empty_closure(begin_set,nfa.empty_Skips);
    //将起始状态集作为DFA的起始状态加入
    dfa.start_S=0;
    //将起始状态集加入状态集与新状态的对照表中
    sets[dfa.S_size]=begin_set;
    dfa.S_size++;
    DFA(nfa,dfa,sets);
    //找到dfa的所有终点状态
    int end_s=nfa.end_S;
    for(int i=0;i<dfa.S_size;i++){
        if(find_s(sets[i],end_s)){
            add_s_to_set(dfa.end_set,i);
        }}
}

//将终点集根据吸收的字符划分
bool crack_end(Skips_graph &dfa,int *new_states,int &find_num){
    states_set new_end_sets;
    //将终态分出:构造nfa到dfa,每个状态只吸收一个符号,找到每个符号对应的终态集,将其标为相同的状态
    if(dfa.end_set.length==1)
        {new_states[(dfa.end_set.st_set[0])]=dfa.end_set.st_set[0];find_num++;
         add_s_to_set(new_end_sets,dfa.end_set.st_set[0]);}
    else{
        int not_find_num=dfa.end_set.length; //未找到的元素
        for(int c=0;c<dfa.ab_char_size;c++){
            int T=Maxnum;  //表示还未找到第一个终态
            for(int i=dfa.S_size-1;i>=0;i--){ //从后往前找
                if(find_s(dfa.end_set,dfa.Skips[i][c])) //在接受该字符的跳转里找到终态
                {
                    if(T==Maxnum)
                        {T=dfa.Skips[i][c];
                         add_s_to_set(new_end_sets,T);}
                    new_states[(dfa.Skips[i][c])]=T; //用第一个发现的终态 作为该吸收的终态
                    not_find_num--;
                    find_num++;
                }
                if(not_find_num==0) break;}
                if(not_find_num==0) break; }
    }
    dfa.end_set=new_end_sets;
}
//分裂,分裂成功返回1,不可再分返回0
bool crack(Skips_graph &dfa,int *new_states,int &find_num){
    for(int i=0;i<dfa.S_size;i++){
        if(new_states[i]!=Maxnum) continue;
        for(int c=0;c<dfa.ab_char_size;c++){
            int T=1;//表示是否可以区分
            for(int j=0;j<dfa.S_size;j++){
                if(i==j) continue;
                if(new_states[(dfa.Skips[i][c])]==new_states[(dfa.Skips[j][c])]) //跳转的结果在一个集合
                    {T=0;break;}
            }
            //可再分
            if(T==1) {new_states[i]=i;find_num++;return 1;}}}
    return 0;//表示不可再分
}
//判断数组前n个是否出现过当前字符
bool find_int(int *array_,int n,int s){
    for(int i=0;i<n;i++){
        if(array_[i]==s) return 1;
    return 0;
    }
}
//查找旧状态为s的新状态
int find_s_in_array(int *array,int s,int length){
    for(int i=0;i<length;i++){
        if(array[i]==s) return i;
}}
//整理合并后的dfa
void combine(Skips_graph dfa,Skips_graph& min_dfa,int *old_states){
    default_graph(min_dfa,dfa.absorb_char,dfa.ab_char_size);//初始化
    int new_states[Maxnum];
    //将没有出现过的状态加入
    for(int i=0;i<dfa.S_size;i++){
        if(find_int(old_states,i,old_states[i])) continue;//判断之前是否出现过
        for(int c=0;c<dfa.ab_char_size;c++)
            min_dfa.Skips[min_dfa.S_size][c]=dfa.Skips[i][c];  //复制进去
        new_states[min_dfa.S_size]=old_states[i];//保存老状态
        min_dfa.S_size++;
    }
    //将所有状态调整
    for(int i=0;i<min_dfa.S_size;i++){
        for(int c=0;c<min_dfa.ab_char_size;c++)
            min_dfa.Skips[i][c]=find_s_in_array(new_states,min_dfa.Skips[i][c],min_dfa.S_size);}
    //记录起点
    min_dfa.start_S=find_s_in_array(new_states,dfa.start_S,min_dfa.S_size);
    //终结状态作调整
    for(int i=0;i<dfa.end_set.length;i++){

        add_s_to_set(min_dfa.end_set,find_s_in_array(new_states,dfa.end_set.st_set[i],min_dfa.S_size));
    }
//    cout<<min_dfa.end_set.length;
//        for(int i=0;i<min_dfa.end_set.length;i++)
//            cout<<min_dfa.end_set.st_set[i]<<" ";
    }
//最简化DFA
void minimize_DFA(Skips_graph dfa,Skips_graph &min_dfa){
    //新状态
    int find_num=0; //确定新状态的状态数
    int new_states[Maxnum];
    for(int i=0;i<dfa.S_size;i++) new_states[i]=Maxnum;
    //将终态分出:构造nfa到dfa,每个状态只吸收一个符号,找到每个符号对应的终态集,将其标位相同的状态
    crack_end(dfa,new_states,find_num);
    //将每个可区分的状态区分出来 条件:未找完或者还可以继续区分
    while(find_num!=dfa.S_size&&crack(dfa,new_states,find_num)){;}
    //将剩余状态划分为一个状态
    if(find_num!=dfa.S_size){
        int T=Maxnum;
        for(int i=0;i<dfa.S_size;i++){
            if(new_states[i]!=Maxnum) continue; //已经找到的
            if(T==Maxnum) T=i;
            new_states[i]=T;}}
    //将新旧状态不同的 修改符号
    for(int i=0;i<dfa.S_size;i++){
        if(i==new_states[i]) continue;
        for(int j=0;j<dfa.S_size;j++){
            for(int c=0;c<dfa.ab_char_size;c++){
                if(dfa.Skips[j][c]==i) dfa.Skips[j][c]=new_states[i];
            }}}
    dfa.start_S=new_states[dfa.start_S];//将改变的起点记录下来
    combine(dfa,min_dfa,new_states);
}
//返回吸收字母的数字
bool find_ab_char(char a,Skips_graph dfa,int &c){
    for(int i=0;i<dfa.ab_char_size;i++)
        if(dfa.absorb_char[i]==a){c=i;return 1;}
    return 0;
    }
//根据dfa作词法分析
bool  lexical_analysis(Skips_graph dfa){
    string exp;
    cout<<"输入词:";
    cin>>exp;
    cout<<"过程:";
    int p=dfa.start_S;cout<<p<<"->";
    //根据读入跳转
    for(int i=0;i<exp.size();i++){
         char char_=exp[i];
         int c; //字符在吸收字符数组中的位置
         //字符不可被接受
         if(!find_ab_char(char_,dfa,c))
            {cout<<"失败:"<<char_<<"输入字符不被接受"<<endl;return 0;}
         //可以被接受
         p=dfa.Skips[p][c];cout<<p<<"->";
         //无法跳转
         if(p==Maxnum)
            {cout<<"失败:吸收"<<char_<<"跳转出错"<<endl;return 0;}}
    //全部字符读取成功:若能到达终点
    if(find_s(dfa.end_set,p)) //移动到终点处
        cout<<"成功"<<endl;
    else
        cout<<"失败:未到达终点"<<endl;
    return 1;
    }


int main()
{
    int start;
    cout<<"开始:";
    cin>>start;
  while(start){
  string exp=cin_Regular_Exp();
  cout<<exp<<endl;
  //构建语法树
  Node* Tree=Syntax_Tree(exp);
  //遍历语法树
  cout<<"后序遍历语法树: ";
  vist_Tree(Tree);
  cout<<endl;
  //构造NFA
  cout<<endl<<"********************Thompson算法构造NFA***********************"<<endl;
  Skips_graph nfa;
  NFA_(Tree,nfa,exp);
  vist_Graph(nfa,"nfa");
  //由NFA构造DFA
  cout<<endl<<"************************由NFA转为DFA**************************"<<endl;
  Skips_graph dfa;
  DFA_(nfa,dfa);
  vist_Graph(dfa,"dfa");
  //最小化dfa
  cout<<endl<<"**************************最小化DFA**************************"<<endl;
  Skips_graph min_dfa;
  minimize_DFA(dfa,min_dfa);
  vist_Graph(min_dfa,"dfa");
  //进行词法分析
  cout<<"*********************************词法分析**************************"<<endl;
  char a;
  cin>>a;
  while(a!='#')
  {lexical_analysis(dfa);cin>>a;}
  cout<<endl<<"开始:";
  cin>>start;
  }
}

【实验示例】

在这里插入图片描述

【注意事项】

实验未实现 ‘+’,开始时要输入‘1’。

  • 11
    点赞
  • 49
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值