一、 實驗目的
1. 通過實驗對編譯系統的基本理論、編譯程序的基本結構有更為深入的理解和掌握;
2. 掌握編譯程序設計的基本方法和步驟;
3. 能夠設計實現編譯系統的重要環節詞法分析,同時增強編寫和調試程序的能力。
二、 實驗要求
- 單詞的分類
可將所有標識符歸為一類;將常數歸為另一類;保留字和分隔符則采取一詞一類。
- 符號表的建立
可事先建立一保留字表,以備在識別保留字時進行查詢。變量名表及常數表則在詞法分析過程中建立。
- 單詞串的輸出形式
所輸出的每一單詞,均按形如(CLASS,VALUE)的二元式編碼。
4.數據獲取及存儲
本設計中默認./src/output.txt讀取源文件,運算結果存儲./src/output.txt文件中
三、 單詞分類表
注:具體及詳細編碼以com.nonefly.test.KeyTypes類中定義為准
1. 關鍵字表
關鍵字,java中共50個關鍵字,如下,對其按順序一字一編碼
"abstract", "boolean", "break", "byte","case", "catch", "char", "class", "continue", "default", "do","double", "else", "extends", "final", "finally", "float", "for","if", "implements", "import", "instanceof", "int", "interface", "long", "native", "new", "package", "private", "protected", "public", "return", "short", "static", "super", "switch","synchronized", "this", "throw","throws", "transient", "try","void","volatile","while","strictfp","enum","goto","const","assert"
助記符 | 種別編碼 | 關鍵字 |
---|---|---|
ABSTRACT | 1 | abstract |
BOOLEAN | 2 | boolean |
BREAK | 3 | break |
BYTE | 4 | byte |
CASE | 5 | case |
... | ... | ... |
ASSERT | 50 | assert |
2. 運算符表
運算符,設計中涉及到+ - * / > = < & | ~十種,對於組合運算符如++ +=等未定義,將其分開描述。
運算符|助記符|種別編碼
-----|------|---
- | PLUS | 51
- | MIN | 52
- | MUL | 53
/ | DIV | 54
& | AND | 55
\ || OR | 56
~ | NOT | 57
> | GT | 58
= | EQ | 59
< | LT | 60
3. 分隔符表
界符(分隔符)涉及如下幾種
, ; { } ( ) [ ] _ : . " \未一詞一符定義,統一歸為 SEPARATORS(助記符):61(單詞種別)
4. 其他(標識符、常數、非法字符)
類型 | 種別編碼 | 助記符 |
---|---|---|
標識符 | 71 | ID |
常數 | 0 | DIGIT |
非法字符 | -1 | ERROR |
四、單詞狀態圖
五、 算法描述
程序中用到的函數列表:
函數名或變量 | 解釋 |
---|---|
TestLexer(String fileSrc) | 通過路徑構造詞法分析器 |
StringBuffer buffer; | 文件讀入緩沖區 |
char ch; | 字符變量,存放最新讀進的源程序字符 |
String strToken; | 字符數組,存放構成單詞符號的字符串 |
boolean isLetter(char ch) | 判斷ch是否為字母 |
boolean isDigit(char ch) | 判斷是否為數字 |
boolean isKeyWord(String) | 判斷是否為關鍵字 |
boolean isOperator(char) | 判斷是否為運算符 |
boolean isSeparators(char) | 判斷是否為分隔符 |
void analyse() | 分析程序(關鍵代碼) |
void getChar() | 將下一字符讀到ch中,搜索指示器前移一個字符 |
void getBC() | 檢查ch空白則調用getChar()至ch中進入非空白字符 |
void concat() | 將ch連接到strToken之后 |
void retract() | 將搜索指示器回調一個字符位置,將ch值為空白字 |
void writeFile(String,String) | 按照二元式規則寫入文件 |
int getType(String args) | 利用反射獲取種別編碼 |
六、 程序結構
1. 整體目錄結構如下,其中:
a.FileUtil.java 對文件的讀寫等操作
b.KeyTypes.java 定義了單詞種類對應的種別編碼
c.TestLexer.java 是分析器類,繼承KeyTypes類,對源程序詞法分析
d.TypeUtil.java 是一個簡單的判斷字符種類的類
e.MainTest.java 是測試主方法類,是程序入口,通過源程序路徑創建TestLexer類,調用其中詞法分析方法,最后結果保存在文件中
2. 上述類中定義方法如下,方法詳細功能見(算法描述)中表格
七、 運行結果
1. 准備
在input.txt中輸入源程序(我們以本程序源代碼為例,此文件必須有),output.txt中為空,作為結果輸出(可以不創建,運行時自動創建)如下圖:
2. 運行
在文本中,按照要求,我們以(種類編碼,VALUE)格式保存結果,在控制台中,為方便觀察,以(助記符,VALUE)格式打印出。(運行結果如下)
八、 設計技巧及體會
這是學習編譯原理時的第一次實驗,回憶試驗中的過程,雖然對編程語言的提升並沒有太多,但是重要的是讓我們了解編程語言在通往機器與之交流的一個重要環節。了解詞法分析對源程序處理分類的思想。
在設計中,實現了簡單的要求並加入了自己一些想法,最終程序也可以成功運行並能按要求對結果保存。當然,其中還有一些不足,其中一部分因為與大部分設計幾乎一樣,因此便"簡寫"。比如對分隔符種類處理,類似於操作符以及關鍵字處理,因此並沒有一詞一類,而是統一作為一類。還有對於注釋的分析,因為"//"的注釋沒有想到很好的處理辦法讓忽視代碼到行尾,因此將其當做普通分隔符處理。(后續中在得到老師幫助后已解決注釋問題,對於//單行注釋以及/* */多行注釋都可以處理)
*對於注釋處理測試如下