正規表示式轉NFA的一點思考和嘗試(c )

2021-10-25 04:37:58 字數 4488 閱讀 2446

2.**基礎

總結聯絡

這學期的編譯原理課需要從正規表示式轉為nfa,但是對thompson演算法如何實現很是費解,對於其他部落格的**理解的很困難。於是我開始嘗試利用棧直接對正規表示式進行掃瞄檢索,通過冗餘解決括號的匹配,實現了乙個比較簡陋的正規表示式轉nfa,於是寫這個部落格記錄一下。

首先講一下預設條件。我們假設輸入的正規表示式是一串僅由大小寫字母、數字、『(』、『)』、『×』、『|』組成的字串,預設輸入的字串是左右括號匹配的,且符合正規表示式的構造規則。

然後是基本思路,主要是分治的思想,我們對括號分層處理(具體操作我們後續講),而對於每乙個基礎運算符號(『』、『|』),我們都將其轉換為雙目運算(同上),同時我們要求運算的運算體必須要用()包起來。

對於每一層括號深度,我們都有乙個node棧儲存中間節點。同時應該有乙個or棧儲存或運算的節點(為什麼這麼做我們後面說)。

對於第n+1層和第n層的連線,我們在第n+1層的『)』符號處進行處理。

在開始,我們在第0層的node棧中壓入開始符號『s』。

對正規表示式的當前字元我們記為temp_char。

對於非運算子,我們將當前括號深度的node棧的棧頂取出放到node0,並產生新node1,產生邊node0->node1的邊,這條邊的權為temp_char。同時當當前深度的node棧的大小大於2時pop掉中間節點,僅留下當前深度的頭節點和尾節點。

示例:正規表示式:abc

0.開始符號 s 壓入node[0]

node[2]

node[1]

node[0] s

1.temp_char=『a』 產生新符號a,產生新邊s->a:a

node[2]

node[1]

node[0] s a

2.temp_char=『b』 彈出a 產生新符號b,產生新邊s->b:b

node[2]

node[1]

node[0] s b

3.temp_char=『c』 彈出b 產生新符號c,產生新邊b->c:c

node[2]

node[1]

node[0] s c

*運算由於我們要求了其閉包體必須在()中,因此在)中處理

當檢測到左括號,括號深度+1,並在+1後的括號深度的node棧中壓入乙個新的符號。

示例:正規表示式:a(b)

0.開始符號 s 壓入node[0]

node[2]

node[1]

node[0] s

1.temp_char=『a』 產生新符號a,產生新邊s->a:a

node[2]

node[1]

node[0] s a

2.temp_char=』(』 括號深度+1 產生新符號b

node[2]

node[1] b

node[0] s a

3.temp_char=『b』 產生新符號c,產生新邊b->c:b

node[2]

node[1] b c

node[0] s a

對『)』的處理,我們最後再講。

當檢測到『|』符號,我們首先將當前深度的node棧的棧頂壓入當前深度的or棧中,然後將其從node棧中pop出來,然後將棧頂放到node0中,然後產生乙個新符號放到node1中,產生乙個新邊node0->node1,權為ε (如果是在第0層這樣就結束了),(如果是括號內的)然後在對『)』處理時將那時的當前深度的node棧棧頂和每乙個or棧中的符號產生一條邊,權為ε 。

示例(不包含『)』):

正規表示式:a|b|c

0.開始符號 s 壓入node[0]

node[2]

node[1]

node[0] s

1.temp_char=『a』 產生新符號a,產生新邊s->a:a

node[2]

node[1]

node[0] s a

2.temp_char=』|』 產生新符號b,產生新邊s->b:ε

node[2] or[2]

node[1] or[1]

node[0] s b or[0] a

3.temp_char=『b』 產生新符號c,產生新邊b->c:b

node[2] or[2]

node[1] or[1]

node[0] s c or[0] a

4.temp_char=』|』 產生新符號d,產生新邊s->d:ε

node[2] or[2]

node[1] or[1]

node[0] s d or[0] a c

5.temp_char=『c』 產生新符號e,產生新邊d->e:c

node[2] or[2]

node[1] or[1]

node[0] s e or[0] a c

首先將當前深度的node棧的棧頂pop到node0中,然後如果or棧不為空,則產生or棧中的每乙個node->node0的邊,權為ε。然後我們再取當前深度node棧的棧頂到node1中。

然後超前檢測下乙個符號是否是『×』,如果是,就產生一條node0到node1的邊,權為ε,然後令node0等於node1(保證*運算為雙目運算子),並且跳過下乙個字元的處理。

然後開始當前括號深度和上一層的連線,首先從上一層的node棧中pop棧頂到node2中,產生一條從node2到node1的邊,權為ε。

然後將上一層的node棧pop到僅剩乙個起始符號,最後將node0壓入上一層的node棧中。

示例:正規表示式:ab((bc)×|d)

0.開始符號 s 壓入node[0]

node[2]

node[1]

node[0] s

1.temp_char=『a』 產生新符號a,產生新邊s->a:a

node[2]

node[1]

node[0] s a

2.temp_char=『b』 產生新符號b,產生新邊a->b:b

node[2] or[2]

node[1] or[1]

node[0] s b or[0]

3.temp_char=』(』 產生新符號c

node[2] or[2]

node[1] c or[1]

node[0] s b or[0]

4.temp_char=』(』 產生新符號d

node[2] d or[2]

node[1] c or[1]

node[0] s b or[0]

5.temp_char=『b』 產生新符號e 產生新邊d->e:b

node[2] d e or[2]

node[1] c or[1]

node[0] s b or[0]

6.temp_char=『c』 產生新符號f 產生新邊e->f:c

node[2] d f or[2]

node[1] c or[1]

node[0] s b or[0]

7.temp_char=』)』 產生新邊f->d:ε,新邊c->d:ε

node[2] or[2]

node[1] c f or[1]

node[0] s b or[0]

8.temp_char=』|』 產生新符號g,新邊c->g:ε

node[2] or[2]

node[1] c g or[1] f

node[0] s b or[0]

9.temp_char=『d』 產生新符號h 產生新邊g->h:d

node[2] or[2]

node[1] c h or[1] f

node[0] s b or[0]

10.temp_char=』)』 產生新邊f->h:ε,新邊b->c:ε

node[2] or[2]

node[1] or[1]

node[0] s h or[0]

#define max_depth 10 //括號最大深度

#define max_node_count 1000 //最大節點數量

node nodes[max_node_count]; //node陣列

#define max_line_count 5000 //最多邊數

line lines[max_line_count]; //邊陣列

node結構體:

struct node;

stack node_stack[max_depth];//node棧

stack or_node_stack[max_depth];//or棧

int brackets=0;//當前括號深度

void creat_new_node(int index);//在index深度的node棧新建乙個符號

//新建乙個從index1指向index2,權為value的邊

void creat_new_line(int index1,int index2,char value);

源**已上傳到碼雲

傳送門:

我自己測試了大約十幾個測試資料,基本都可以通過產生冗餘來完成nfa的構造,但是無法完成不帶括號的閉包運算,算是乙個小小的遺憾吧。

正規表示式轉NFA

最近一直在忙著寫大作業,考試複習,複習演算法的時候寫了一些隨筆,現在忙起來都落下了部落格,這裡有乙個vc 寫的大作業,主要是正規表示式轉nfa並顯示。內容如下。介紹一下nfa在表示的結構設計,由於nfa本身是一種有向圖,所以這裡的儲存結構設計和鄰接表相似,圖中的每個節點後面是一些與其連線的節點的值,...

正規表示式轉NFA

正規表示式有三種基本的運算 連線 concatenation 例如 abc,由a,b,c組成 聯合 union 例如 a b c,表示a或者b或者c kleene閉包 kleene 例如 ab 表示ab串不出現,或者出現1次或一次以上 其它的運算如 等都可以用以上三種基本運算或者運算的組合來表示。2...

編譯原理 正規表示式轉NFA

從txt檔案中讀入正規表示式 include include include include include define max token 100 using namespace std 詞struct token int readtxt string filename,vector token...