正規式轉換為NFA(tompson算法) Devc++實現


參考資料:https://blog.csdn.net/gongsai20141004277/article/details/52949995

代碼:

tompson。cpp

#pragma once

#include "Thompson.h"
#include<string.h>
#include<iostream>
using namespace std;


int STATE_NUM = 0;

/**表達式轉NFA處理函數,返回最終的NFA結合
*/
cell express_2_NFA(string expression)
{
    int length = expression.size();
    char element;
    cell Cell, Left, Right;
    stack<cell> STACK;
    for (int i = 0; i<length; i++)
    {
        element = expression.at(i);
        switch (element)
        {
        case '|':
            Right = STACK.top();
            STACK.pop();
            Left = STACK.top();
            STACK.pop();
            Cell = do_Unite(Left, Right);
            STACK.push(Cell);
            break;
        case '*':
            Left = STACK.top();
            STACK.pop();
            Cell = do_Star(Left);
            STACK.push(Cell);
            break;
        case '+':
            Right = STACK.top();
            STACK.pop();
            Left = STACK.top();
            STACK.pop();
            Cell = do_Join(Left, Right);
            STACK.push(Cell);
            break;
        default:
            Cell = do_Cell(element);
            STACK.push(Cell);
        }
    }
    cout << "處理完畢!" << endl;
    Cell = STACK.top();
    STACK.pop();

    return Cell;
}

//處理 a|b
cell do_Unite(cell Left, cell Right)
{
    cell NewCell;
    NewCell.EdgeCount = 0;
    edge Edge1, Edge2, Edge3, Edge4;
    //獲得新的新狀態節點
    state StartState = new_StateNode();
    state EndState = new_StateNode();
    //構建邊
    Edge1.StartState = StartState;
    Edge1.EndState = Left.EdgeSet[0].StartState;
    Edge1.TransSymbol = '#';  //代表空串

    Edge2.StartState = StartState;
    Edge2.EndState = Right.EdgeSet[0].StartState;
    Edge2.TransSymbol = '#';

    Edge3.StartState = Left.EdgeSet[Left.EdgeCount - 1].EndState;
    Edge3.EndState = EndState;
    Edge3.TransSymbol = '#';

    Edge4.StartState = Right.EdgeSet[Right.EdgeCount - 1].EndState;
    Edge4.EndState = EndState;
    Edge4.TransSymbol = '#';

    //構建單元
    //先將Left和Right的EdgeSet復制到NewCell
    cell_EdgeSet_Copy(NewCell, Left);
    cell_EdgeSet_Copy(NewCell, Right);

    //將新構建的四條邊加入EdgeSet
    NewCell.EdgeSet[NewCell.EdgeCount++] = Edge1;
    NewCell.EdgeSet[NewCell.EdgeCount++] = Edge2;
    NewCell.EdgeSet[NewCell.EdgeCount++] = Edge3;
    NewCell.EdgeSet[NewCell.EdgeCount++] = Edge4;

    //構建NewCell的啟示狀態和結束狀態
    NewCell.StartState = StartState;
    NewCell.EndState = EndState;

    return NewCell;
}
//處理 ab
cell do_Join(cell Left, cell Right)
{
    //將Left的結束狀態和Right的開始狀態合並,將Right的邊復制給Left,將Left返回
    //將Right中所有以StartState開頭的邊全部修改
    for (int i = 0; i<Right.EdgeCount; i++)
    {
        if (Right.EdgeSet[i].StartState.StateName.compare(Right.StartState.StateName) == 0)
        {
                Right.EdgeSet[i].StartState = Left.EndState;
            STATE_NUM--;  
        }
        else if (Right.EdgeSet[i].EndState.StateName.compare(Right.StartState.StateName) == 0)
        {
            Right.EdgeSet[i].EndState = Left.EndState;
            STATE_NUM--;
        }
    }
    Right.StartState = Left.EndState;

    cell_EdgeSet_Copy(Left, Right);
    //將Left的結束狀態更新為Right的結束狀態
    Left.EndState = Right.EndState;
    return Left;
}
//處理 a*
cell do_Star(cell Cell)
{
    cell NewCell;
    NewCell.EdgeCount = 0;
    edge Edge1, Edge2, Edge3, Edge4;
    //獲得新的新狀態節點
    state StartState = new_StateNode();
    state EndState = new_StateNode();
    //構建邊
    Edge1.StartState = StartState;
    Edge1.EndState = EndState;
    Edge1.TransSymbol = '#';  //閉包取空串

    Edge2.StartState = Cell.EndState;
    Edge2.EndState = Cell.StartState;
    Edge2.TransSymbol = '#';  //取字符,自連接

    Edge3.StartState = StartState;
    Edge3.EndState = Cell.StartState;
    Edge3.TransSymbol = '#';

    Edge4.StartState = Cell.EndState;
    Edge4.EndState = EndState;
    Edge4.TransSymbol = '#';
    //構建單元
    //先將Cell的EdgeSet復制到NewCell
    cell_EdgeSet_Copy(NewCell, Cell);
    //將新構建的四條邊加入EdgeSet
    NewCell.EdgeSet[NewCell.EdgeCount++] = Edge1;
    NewCell.EdgeSet[NewCell.EdgeCount++] = Edge2;
    NewCell.EdgeSet[NewCell.EdgeCount++] = Edge3;
    NewCell.EdgeSet[NewCell.EdgeCount++] = Edge4;
    //構建NewCell的啟示狀態和結束狀態
    NewCell.StartState = StartState;
    NewCell.EndState = EndState;

    return NewCell;
}
//處理 a
cell do_Cell(char element)
{
    cell NewCell;
    NewCell.EdgeCount = 0;
    edge NewEdge;
    //獲得新的新狀態節點
    state StartState = new_StateNode();
    state EndState = new_StateNode();
    //構建邊
    NewEdge.StartState = StartState;
    NewEdge.EndState = EndState;
    NewEdge.TransSymbol = element;
    //構建單元
    NewCell.EdgeSet[NewCell.EdgeCount++] = NewEdge;
    NewCell.StartState = NewCell.EdgeSet[0].StartState;
    NewCell.EndState = NewCell.EdgeSet[0].EndState;//EdgeCount此時為1
    return NewCell;
}
void cell_EdgeSet_Copy(cell& Destination, cell Source)
{
    int D_count = Destination.EdgeCount;
    int S_count = Source.EdgeCount;
    for (int i = 0; i<S_count; i++)
    {
        Destination.EdgeSet[D_count + i] = Source.EdgeSet[i];
    }
    Destination.EdgeCount = D_count + S_count;
}
/*
獲得新的狀態節點,統一產生,便於管理,不能產生重復的狀態
並添加到state_set[]數組中
*/
state new_StateNode()
{
    state newState;
    newState.StateName = STATE_NUM + 65;//轉換成大寫字母
    STATE_NUM++;
    return newState;
}
//接收輸入正規表達式,RegularExpression作為回傳函數
void input(string &RegularExpression)
{
    cout << "請輸入正則表達式:  (操作符:() * |;字符集:a~z A~Z)" << endl;
//    do
//    {
        cin >> RegularExpression;
//    } while (!check_legal(RegularExpression));
    
}
/**檢測輸入的正則表達式是否合法
*/
/*int check_legal(string check_string)
{
    if (check_character(check_string) && check_parenthesis(check_string))
    {
        return true;
    }
    return false;
}
/**
檢查輸入的字符是否合適 () * | a~z A~Z
合法返回true,非法返回false
*/
/*/*int check_character(string check_string)
{
    int length = check_string.size();
    for (int i = 0; i<length; i++)
    {
        char check = check_string.at(i);
        if (is_letter(check))//小寫和大寫之間有5個字符,故不能連續判斷
        {
            //cout<<"字母 合法";
        }
        else if (check == '(' || check == ')' || check == '*' || check == '|')
        {
            //cout<<"操作符 合法";
        }
        else
        {
            cout << "含有不合法的字符!" << endl;
            cout << "請重新輸入:" << endl;
            return false;
        }
    }
    return true;
}
/**先檢查括號是否匹配
*合法返回true,非法返回false
*/
/*int check_parenthesis(string check_string)
{
    int length = check_string.size();
    char * check = new char[length+1];
    strcpy_s(check, length+1, check_string.c_str());
    stack<int> STACK;
    for (int i = 0; i<length; i++)
    {
        if (check[i] == '(')
            STACK.push(i);
        else if (check[i] == ')')
        {
            if (STACK.empty())
            {
                cerr << "有多余的右括號" << endl;//暫時不記錄匹配位置location
                cout << "請重新輸入:" << endl;
                return false;
            }
            else
                STACK.pop();
        }
    }
    if (!STACK.empty())
    {
        //暫時不記錄匹配位置location
        cerr << "有多余的左括號" << endl;
        cout << "請重新輸入:" << endl;
        return false;
    }
    
    return true;
}*/
/**檢測是否是字母
是返回true,否則false
*/
int is_letter(char check)
{
    if (check >= 'a'&&check <= 'z' || check >= 'A'&&check <= 'Z')
        return true;
    return false;
}

/**添加交操作符“+”,便於中綴轉后綴表達式
例如 abb->a+b+b
*/
string add_join_symbol(string add_string)
{
    /*  測試終止符\0
    string check_string = "abcdefg\0aaa";
    cout<<check_string<<endl;
    int length = check_string.size();
    char * check = new char[2*length];
    strcpy(check,check_string.c_str());
    cout<<check<<endl;
    char *s = "ssss\0  aa";
    cout<<s<<endl;
    string a(s);
    cout<<a<<endl;
    */
    int length = add_string.size();
    int return_string_length = 0;
    char *return_string = new char[2 * length+2];//最多是兩倍
    char first, second;
    for (int i = 0; i<length - 1; i++)
    {
        first = add_string.at(i);
        second = add_string.at(i + 1);
        return_string[return_string_length++] = first;
        //要加的可能性如ab 、 *b 、 a( 、 )b 等情況
        //若第二個是字母、第一個不是'('、'|'都要添加
        if (first != '('&&first != '|'&&is_letter(second))
        {
            return_string[return_string_length++] = '+';
        }
        //若第二個是'(',第一個不是'|'、'(',也要加
        else if (second == '('&&first != '|'&&first != '(')
        {
            return_string[return_string_length++] = '+';
        }
    }
    //將最后一個字符寫入
    return_string[return_string_length++] = second;
    return_string[return_string_length] = '\0';
    string STRING(return_string);
    cout << "加'+'后的表達式:" << STRING << endl;
    return STRING;
}
/*
構造優先級表規則:(1)先括號內,再括號外;(2)優先級由高到低:閉包、|、+;(3)同級別,先左后右。
優先級表:
     #    (    *    |    +    )
isp  0    1    7    5    3    8
icp     0    8    6    4    2    1
*/

/*********************運算符優先級關系表********************/
/*
    c1\c2    (    *    |    +    )    #   

    (        <    <    <    <    =    >

    *        <    >    >    >    >    >

    |        <    <    >    >    >    >

    +        <    <    <    >    >    >

    #        <    <    <    <    <    =
*/
/***********************************************************/

//in stack priority  棧內優先級,棧頂的字符的優先級
int isp(char c)
{
    switch (c)
    {
    case '#': return 0;
    case '(': return 1;
    case '*': return 7;
    case '|': return 5;
    case '+': return 3;
    case ')': return 8;
    }
    //若走到這一步,說明出錯了
    cerr << "ERROR!" << endl;
    return false;
}
//in coming priority 棧外優先級,當前掃描到的字符的優先級
int icp(char c)
{
    switch (c)
    {
    case '#': return 0;
    case '(': return 8;
    case '*': return 6;
    case '|': return 4;
    case '+': return 2;
    case ')': return 1;
    }
    //若走到這一步,說明出錯了
    cerr << "ERROR!" << endl;
    return false;
}
/**中綴表達式轉后綴表達式
*/
string postfix(string e)
{
    //設定e的最后一個符號式“#”,而其“#”一開始先放在棧s的棧底
    e = e + "#";

    stack<char> s;
    char ch = '#', ch1, op;
    s.push(ch);
    //讀一個字符
    string out_string = "";
    int read_location = 0;
    ch = e.at(read_location++);
    while (!s.empty())
    {
        if (is_letter(ch))
        {
            out_string = out_string + ch;
            //cout<<ch;
            ch = e.at(read_location++);
        }
        else
        {
            //cout<<"輸出操作符:"<<ch<<endl;
            ch1 = s.top();
            if (isp(ch1)<icp(ch))
            {
                s.push(ch);
                //cout<<"壓棧"<<ch<<"  讀取下一個"<<endl;
                ch = e.at(read_location++);
            }
            else if (isp(ch1)>icp(ch))
            {
                op = s.top();
                s.pop();
                //cout<<"退棧"<<op<<" 添加到輸出字符串"<<endl;
                out_string = out_string + op;
                //cout<<op;
            }
            else  //考慮優先級相等的情況
            {
                op = s.top();
                s.pop();
                //cout<<"退棧"<<op<<"  但不添加到輸入字符串"<<endl;

                if (op == '(')
                    ch = e.at(read_location++);
            }
        }
    }

    cout << "后綴表達式:" << out_string << endl;
    return out_string;
}
/*
    顯示NFA
*/
void Display(cell Cell)
{
    cout << "NFA 的邊數:" << Cell.EdgeCount << endl;
    cout << "NFA 的起始狀態:" << Cell.StartState.StateName << endl;
    cout << "NFA 的結束狀態:" << Cell.EndState.StateName << endl;
    for (int i = 0; i<Cell.EdgeCount; i++)
    {
        cout << "第" << i + 1 << "條邊的起始狀態:" << Cell.EdgeSet[i].StartState.StateName
            << "  結束狀態:" << Cell.EdgeSet[i].EndState.StateName
            << "  轉換符:" << Cell.EdgeSet[i].TransSymbol << endl;
    }
    cout << "結束" << endl;
}



//主函數
int main()
{
    string Regular_Expression = "(a|b)*abb";
    cell NFA_Cell;
    Regular_Expression = "(a|b)*abb";
    //接受輸入
    input(Regular_Expression);//調試需要先屏蔽
    //添加“+”,便於轉后綴表達式
    Regular_Expression = add_join_symbol(Regular_Expression);
    //中綴轉后綴
    Regular_Expression = postfix(Regular_Expression);
    //表達式轉NFA
    NFA_Cell = express_2_NFA(Regular_Expression);
    //顯示
    Display(NFA_Cell);
}

 

 

 

tompson.h

#ifndef THOMPSON_H
#define THOMPSON_H

#include <iostream>
#include <stdio.h>
#include <cctype>
#include <stack>
#include <string>

using namespace std;

#define MAX 100

//節點,定義成結構體,便於以后擴展
struct state
{
    string StateName;
};
//邊,空轉換符用'#'表示
struct edge
{
    state StartState;
    state EndState;
    char TransSymbol;
};

//NFA單元
struct cell
{
    edge EdgeSet[MAX];
    int EdgeCount;
    state StartState;
    state EndState;
};

/***************NFA的矩陣結構****************/

/*struct node
{
    edge* In_edges;
    edge* Out_edges;
    state
};*/

/********************************************/

//函數聲明
void input(string&);
int check_legal(string);
int check_character(string);
int check_parenthesis(string);
int is_letter(char);
//添加“+”,便於轉后綴表達式
string add_join_symbol(string);
//中綴轉后綴
string postfix(string);
//優先級 in stack priority
int isp(char);
//優先級 in coming priority
int scp(char);
//表達式轉NFA
cell express_2_NFA(string);
//處理 a|b
cell do_Unite(cell, cell);
//處理 ab
cell do_Join(cell, cell);
//處理 a*
cell do_Star(cell);
//處理 a
cell do_Cell(char);
//將一個單元的邊的集合復制到另一個單元
void cell_EdgeSet_Copy(cell&, cell);

//產生一個新的狀態節點,便於管理
state new_StateNode();
//顯示
void Display(cell);

#endif  //THOMPSON.H

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM