java编译器id_JAVA 词法编译器
(1)詞法分析概述(主要介紹詞法分析的主要功能)
1. 將正規式轉化為NFA
2. 將NFA轉化為DFA
3. 將DFA轉化為最小DFA
4. 模擬DFA
5. 識別源程序
6. 錯誤信息判斷
(2)?采用的技術及平臺安裝(主要介紹采用了什么開發語言,如何部署軟件運行環境,簡要說明不超過300字)
本實驗采用Java語言編寫,IDE為Eclipse Jee Oxygen,部署時直接下載安裝對應軟件即可,Java語言的配置需要在安裝相應文件后,設置環境變量和系統變量。
(3)?算法分析(主要介紹采用的算法及數據結構,以及如何用數據結構實現算法,包含:數據結構和算法分析兩部分內容,在對應算法分析部分,必須給出示例說明算法)
1.?棧,優先級識別正規式
數據結構:使用棧,分為運算符棧和字符棧
算法:將‘#’符號壓入運算符棧,當輸入表達式的字符坐標不等于表達式的長度或者運算符棧頂不等于‘#’時,做循環,在循環體中,判斷表達式的各個字符,若不是運算符則壓入字符棧,若是運算符,則與運算符棧的棧頂元素進行優先級比較,若棧頂元素優先級低,將運算符壓棧,若相等,運算符棧彈棧,若棧頂元素優先級高,則彈出運算符棧,以及連續彈出兩次字符棧,將上述彈出的兩個字符和一個運算符作為一個運算組。
2.?Thompson算法
數據結構:構造節點和弧的結構來表示NFA,構造的結果類似圖。通過結點和弧可以遍歷整個圖;NFA棧,用來保存中間的NFA結果。
算法:在通過優先級判斷后得到的表達式單元,比如AB|(A或B)這樣的正規式后,判斷運算符是 | ,則調用事先編寫好的五個構造函數(分別是或運算,連接運算,閉包運算,單個字符,ε運算)中的或運算,構造A|B的NFA,同時將構造好的NFA壓進NFA棧,這一過程實際就是將NFA構造過程和表達式優先級判斷過程同步。不斷重復過程,最終得到的NFA棧的棧頂元素就是完整的NFA。
3.?最小子集法
數據結構:定義了表示DFA的矩陣和 表示狀態集合的結構。
算法:首先定義了ε閉包和smove函數,設計遞歸的部分用棧來模擬遞歸。然后用表示狀態集合的數據結構表示ε閉包+smove操作所得到的的狀態集合,在運算過程中對于新的狀態標號,并在后續對新的狀態進行對應字符的smove+ε閉包運算,直到不再產生新狀態為止。完成上述運算后,根據表示的新狀態號和對應的字符,構造DFA矩陣。
4.?最小DFA算法
數據結構:定義了表示一個劃分的數據結構,以及記錄可以合并狀態(即同屬一個劃分的兩個狀態)的集合。
算法:計算兩個狀態是否可以合并時,采用的是n!的時間復雜度的算法,即第一步為第一個狀態和第2至n的狀態進行是否可以合并為一組的判斷,將可以合并的兩個狀態進行記錄,第二步為判斷第2個狀態和第3至n的狀態的判斷,同樣將可以合并的兩個狀態進行記錄,循環上述步驟,直到n-1個狀態和第n各狀態進行上述過程。在完成上述步驟后,對于得到的記錄可以合并為一組的狀態的集合,判斷二元組之間是否有公共狀態,則表示這兩個二元組的三個狀態可以合并。比如,(1,2)和(2,3)表示1,2狀態可以合并,2,3狀態可以合并,通過判斷知道,1,2,和2,3有公共狀態2,則表示1,2,3這三個狀態可以合并為一個組,即(1,2,3),其他組的判斷也是這樣,在全部合并完之后,得到最終的劃分結果,再依照原先的DFA矩陣和劃分結果,構造一個新的最小DFA矩陣。
5.?DFA模擬器算法
數據結構:無新定義數據結構。
算法:主要是將源程序代碼段的各個字符依序進行再矩陣里的狀態轉移,觀察最終結果是處于終態,非終態,還是出現錯誤的字符。
6.?字符串最大匹配識別
數據結構:將構造的最小DFA進行集合化,即定義list這樣的集合
算法:主要是判斷在最大匹配的過程中,會產生什么樣的不同情況,比如當前字符串無法被所有DFA識別,或者能識別但是不處于終態,或者能識別且處于終態,明確各種情況下的操作即可。在這里要注意將構造的幾個最小DFA按照關鍵字,數字,特殊字符,。。。標識符的順序進行DFA模擬,確保沒有誤識別。
(4)?流程圖(繪制并說明算法流程)
在這一過程中,文件流會不斷將生成的中間結果寫入txt文件中。
(5)?程序運行截圖(根據實驗指導書第3節提供的內容及要求顯示輸出結果,并提供對應交互信息)
1. 輸入正規式
課本例子:case:(a|b)* a b b
生成的dfa和最小dfa
結果
用例:case:(0|1|2|3|4|5|6|7|8|9)
2. 對于每一個正規式所生成的DFA和最小DFA,數字代表狀態,null代表空
Void
id:(a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z) (a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|0|1|2|3|4|5|6|7|8|9)*
digital:(0|1|2|3|4|5|6|7|8|9) (0|1|2|3|4|5|6|7|8|9)*
因為正規式比較多且比較復雜,所以只展示出其中兩個,所有的結構式保存在工程文件的resource.txt中。
3. 輸入源程序
4. 識別結果
控制臺
Resource.txt
5. 錯誤信息
對于數字開頭的標識符,能將其非法性識別出來,見下圖第四行的11a
(6)?測試用例
1.?正規式
KW:v o i d
KW:i n t
KW:f l o a t
KW:i f
KW:e l s e
id:(a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z) (a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|0|1|2|3|4|5|6|7|8|9)*
ks:(|)|{|,|;|+|/|>|=|}
digital:(0|1|2|3|4|5|6|7|8|9) (0|1|2|3|4|5|6|7|8|9)*
(id這個用例在粘貼到界面內時注意讓它的內容顯示在同一行)
2.?源程序
void main(){
int x,a,b;
float y,c,d;
x=a+b;11a
??????y=c/d;
??????if(x>y)
??x=10;
??????else
???y=100;
}
?(7)?代碼結構說明
?
(8)程序分析(主要介紹編程中出現的錯誤以及修改的說明以及實驗心得)
1. 正規式的優先級是構造NFA的關鍵,運用數據結構課中的算數表達式優先級可以解決。
2. 構造NFA的五個子結構,因為NFA很像圖,所以定義了結點和弧這兩種結構,還定義了深度優先遍歷NFA的函數,更深體會到了大二學習的數據結構知識對于編程的重要性。
3.在將NFA轉化為DFA的過程中,由于對于數字,或者標識符這樣字符很多的正規式的NFA,會含有大量ε,所以一開始用函數遞歸進行空閉包操作時,堆棧會溢出,后來將函數遞歸的形式用數據結構棧來模擬后,成功解決,由此體會到函數調用時以堆棧形式調用這一方式,以及告誡自己在使用遞歸時,雖然函數遞歸從代碼上看結構更清楚,但是用棧來模擬遞歸的過程的性能會更好。
4. 接上一點,在最初使用函數遞歸的形式模擬空閉包和Smove操作時,由于中間變量的不斷更新,導致在遞歸函數逐層退出到最外面一層時,中間變量的值已經改變,所以為了能暫時保存最外層函數的中間變量的原值,學習了Java語言的深拷貝和淺拷貝,這一機制是為了在存儲內部增加一塊存儲空間,而不是簡單的引用變量。
5.在設計最大匹配掃描源程序的字符串的算法時,因為在掃描過程中遇到的情況特別多,如果不將所有的過程用流程圖或偽代碼的形式預先定義好,編寫程序時代碼結構會顯得臃腫。所以在編寫代碼時,按照流程圖或偽代碼的參照來寫,代碼的結構的簡潔性以及程序的正確性會提高。
6. 在對字符串進行較為復雜的操作,比如提取某個特定的中間字符串時,使用java語言本身定義的正規式函數,進行split等操作時,會方便很多,不過要明確正規式的規則。
7. 在源程序字符串匹配過程中,想象int這個關鍵詞,被用來識別字符串的DFA集合是有次序的,如果在識別int時,標識符DFA先于關鍵字intDFA,則int會被識別成一個標識符,而不是關鍵字,所以要明確這些DFA的識別優先級。
《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的java编译器id_JAVA 词法编译器的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java kafka 设置分区_Java
- 下一篇: python中easygui最新下载教程