程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> JAVA綜合教程 >> 用java開發編譯器之:代碼實現Thompson構造1,輸入文本預處理

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

編輯:JAVA綜合教程

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


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

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

\

 

我們程序的目的,是希望將文本格式的正則表達式轉換為鏈表式的NFA,即將文本:

D[0-9]

{D}+return ICON

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

轉換為

\

 

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

D[0-9]

 

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

{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, 放入到哈希表中。

 

當對正則表達式進行解析時,需要進行宏替換,也就是通過給定宏的名字,獲取宏的內容,接口expandMacro 要實現的是獲取宏的內容:

\

 

 

正則表達式的文本替換:

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

(調出eclipse)

\

 

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

\

 

preProcessExpr將輸入的正則表達式逐字符讀入,一旦遇到左括號{ 時,便准備開始進行宏替換,但如果左括號 { 是在雙引號中,例如[“{}”] , 那麼就將括號{當做普通字符處理,不進行替換,如果不是在雙引號中,就進行宏替換。

 

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

\

 

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

 

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

 

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

 


  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved