用java開發編譯器之:代碼實現Thompson構造1,輸入文本預先處理

來源:互聯網
上載者:User

用java開發編譯器之:代碼實現Thompson構造1,輸入文本預先處理

本節目的是Thompson構造實現的第一步,輸入文本預先處理.本節的代碼可以在雲課堂的附件中提取。

本節代碼的目錄結構如下:

 

我們程式的目的,是希望將文字格式設定的Regex轉換為鏈表式的NFA,即將文本:

D[0-9]

{D}+return ICON

({D}+ | {D}*\.{D}+ | {D}+\.{D}*)(e{D}+)

轉換為

 

在轉換前,我們需要對文本進行預先處理,在上面的文本中,其實分成了兩個不同的部分,第一部分稱為宏定義即:

D[0-9]

 

就像C語言中的宏定義,在代碼編譯前要將宏進行替換,我們在轉換前,也需要將Regex中的宏進行替換,也就是要將

{D}+return ICON

({D}+ | {D}*\.{D}+ | {D}+\.{D}*)(e{D}+)

 

轉換成:

{[0-9]}+ returnICON

([0-9]+ | [0-9]*\.[0-9]+ | [0-9]+\.[0-9]*)(e[0-9]+)

 

也就是把雙括弧D 換成[0-9]

宏定義的轉換看似僅僅是簡單的字串替換,但它有一個痛點是需要處理宏定義的間套情況,例如:

D[0-9]

A [a-z]

AD{D}|{A}

{AD}\.{AD}+

 

大家可以看到,宏定義AD 中,它自身的定義需要其他宏定義來組成(D和A),

替換了宏AD之後,還需要繼續替換D 和A.也就是替換分成兩部

1.由{AD}\.{AD}+ 替換成( {D}|{A} ) \. ( {D} | {A} )+

2.由({D}|{A}) \. ({D} | {A})+ 替換成 ([0-9]|[a-z])\.([0-9]|[a-z])+

 

因此,在替換宏定義的時候,需要小心處理這種間套情況,間套甚至有可能會是很多層。

 

宏定義的組成方式如下:

 

名稱 <一系列空格> 宏定義的內容 <一系列空格或換行>

 

因此,程式對宏定義的解析也根據上面的格式來入手, 宏定義的解析由類MacroHandler來處理:

 

 

我們利用一個雜湊表macroMap來儲存所有宏定義,如果有兩個宏的名字相同,那下一個宏將會覆蓋上一個, 輸入系統inputSystem,將從控制台擷取宏定義的內容,然後調用newMacro函數對輸入的內容進行解析(調出elipse).

 

newMacro 函數通過解析從控制台讀入的一行內容來構造宏定義,首先是先忽略掉空格和空行,直到遇到第一個有意義的字元才開始解析。從第一個字元開始,根據宏定義的格式,我們要構造的是宏定義的名稱,將所有字元集合起來,直到遇到空格為止,所集合的字元構成的字串就是宏定義的名稱。

 

越過宏定義的名稱後面的空格,遇到的有效內容就是宏定義的內容了,將他們收集起來,放入macroContent變數,然後以宏定義的名字為key, 放入到雜湊表中。

 

當對Regex進行解析時,需要進行宏替換,也就是通過給定宏的名字,擷取宏的內容,介面expandMacro 要實現的是擷取宏的內容:

 

 

Regex的文本替換:

在代碼中,我們使用類RegularExpressionHandler來對Regex的輸入進行替換,它的基本流程是,讀入Regex文本,然後解析讀入的內容,如果內容中有{}這一對符號時,程式確認需要進行宏替換,他將{}中的字串提前出來作為宏定義的名字,通過上面提到的介面expandMacro擷取宏定義的內容,用得到的內容進行替換,如果替換後還有宏定義,那麼繼續重複替換流程。該類的代碼如下:

(調出eclipse)

 

input是輸入系統,用於擷取Regex的輸入,macroHandler是上面我們提到的宏定義處理器。該類將所有預先處理後的Regex都儲存在一個數組中,以備後面的程式使用。在一系列初始化完成後,調用processRegularExprs 開始執行Regex的預先處理流程。

 

preProcessExpr將輸入的Regex逐字元讀入,一旦遇到左括弧{ 時,便準備開始進行宏替換,但如果左括弧 { 是在雙引號中,例如[“{}”] , 那麼就將括弧{當做一般字元處理,不進行替換,如果不是在雙引號中,就進行宏替換。

 

它先將處於{ 和 } 中的字串抽出來,作為宏定義的名字,抽取的過程通過介面extractMacroNameFromInput實現,拿到宏的名字後,調用expandMacro來進行替換操作。

 

expandMacro 從macroHandler中擷取宏定義的內容,由於宏定義可能會間套,因此擷取內容後,還需要判斷,宏定義中是否間套了其他宏定義,macroContent.indexOf(“{“} 就是用於判斷宏定義是否間套,如果有間套,那麼將{}中的內容抽取出來,再進行宏定義替換,替換完後再次檢驗是否還有間套,一直這麼進行直到宏定義再無間套為止。

 

在判斷宏定義時做了一些檢查,如果遇到括弧{, 但沒有遇到對應的},那表明輸入出錯,同時將出錯資訊列印出來。

 

這節,我們只對代碼進行了簡單的介紹,下一節,我將以運行調試的方式,進一步給大家展現代碼的流程,讓大家能更好的理解代碼。

 


聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.