编译原理——java 词法分析【有穷自动机实现】
編譯原理——實驗1
實驗要求
1) 基于詞法規則設計詞法分析器(20分)
畫出確定的有窮自動機(確定化),并提供必要的文字說明。提交狀態轉換圖.doc
2) 詞法分析程序的編程實現(80分)
(1) 編程實現詞法分析器,提交可執行詞法分析程序的源程序
用java(或C++或C語言或其它預言)手工編程實現詞法分析程序,該詞法分析程序能夠讀取測試輸入文件中的源程序,并將其詞法分析的結果即token序列或詞法分析的所有錯誤信息輸出到tokenOut.txt中,以便于檢查你的詞法分析程序的正確性。輸出的錯誤信息要包括錯誤所在行數,錯誤類型等信息(編譯原理課程設計文件夾下有測試輸入源文件testX.txt)。
(2) 提交所生成的詞法分析程序的測試方案.doc
注:將狀態轉換圖.doc、源程序、以及詞法分析程序測試方案.doc文件放在一個文件夾下,按照“班級學號姓名”的命名方式打包提交。如果還有其它需要說明的問題須寫在readme.doc中。
程序
輸入:
文件(包含java源程序或txt文件)
輸出:
tokenOut.txt(文件)
token序列
每個token包括兩個方面的內容:
?token = 字符串(語義)+類型(語法)舉例:if 關鍵字y 標識符= 操作符3 數字需要注意的問題
1)mjava中使用的是整數,未使用浮點數(浮點數報錯)
2)因為無法引入系統函數,將 System.out.println作為關鍵字使用
3)mjava中內置了計算長度的方法,將length作為關鍵字使用
4)操作符中未提供“|”或運算
5)空白、換行符和制表符在詞法分析時忽略掉。
6)注釋在詞法分析是忽略掉。
7)正規表達式處理不了語法錯誤
8)System.out.println在自動機里面要體現(最好是,所有的編程邏輯都在自動機中體現)
9)關鍵字可以直接在程序內部枚舉,不在DFA中體現
如何實現?
確定的有窮自動機:
1、復習+練習——ok
2、畫圖
詞法分析程序:
1、讀文件
2、獲取每一行字符串,使用狀態機進行分析
3、每分析一行,輸出對應的token【字符串(語義)+類型(詞法)】
?????? 3.1 狀態機設計
?????? 3.2 正則表達式學習+設計
4、如果該行出錯,繼續分析(要報出所有的錯誤),但是要報出這一行的錯誤類型和行號
如何運行?
運行Ex1.java
import java.io.*; import java.util.ArrayList;public class Ex1 {public static String fileName; // 讀入的文件public static String pathname = "E:\\"+"tokenOut.txt"; // 寫入的文件路徑和文件名static BufferedReader br;static BufferedWriter bw;public static int state = 0; // 記錄DFA的狀態public static ArrayList<String> result = new ArrayList<String>(); // 記錄結果tokenpublic static ArrayList<String> error = new ArrayList<String>(); // 記錄錯誤public static String info = ""; // 用于添加進result 或 error的基本單位public static String token = ""; // 記錄輸入的字符public static int lineNumber = 1; // 記錄行號/*** 判斷c是否是a-Z中的字母* @param c* @return*/public static boolean isLetter(int c) {if ((c>=65&&c<=90)||(c>=97&&c<=122)) {if(state == 0 || state == 2) {token += (char)c;}return true;}elsereturn false;}/*** 判斷c是否是0-9中的數字* @param c* @return*/public static boolean isDigit(int c){if (c>=48&&c<=57) {if(state == 0 || state == 1 || state == 2) {token += (char)c;}return true;}elsereturn false;}/*** 判斷c是否是下劃線_* @param c* @return*/public static boolean isUnderline(int c){if (c==95) {if(state == 2) {token += (char)c;}return true;}elsereturn false;}/*** 判斷c是否是符號* @param c* @return*/public static boolean isSymbol(int c, BufferedReader br) throws IOException {if (c==91||c==93||c==123||c==125||c==59||c==61||c==60||c==33||(c>=40&&c<=45) || c==16) {if(state == 0) { // 上一狀態是0token += (char) c;addInfo(); // 提交符號} else if(state == 1) { // 上一狀態是1addInfo(); // 提交上一個狀態的token,并清零token += (char) c;state = 0;addInfo(); // 提交符號} else if(state == 2) {addInfo(); // 提交上一個狀態的token,并清零token += (char) c;state = 0;addInfo(); // 提交符號}return true;} else if(c==38) {if(state == 0) { // 上一狀態是0token += (char) c;} else if(state == 1) { // 上一狀態是1addInfo(); // 提交上一個狀態的token,并清零token += (char) c;} else if(state == 2) {addInfo(); // 提交上一個狀態的token,并清零token += (char) c;}if ((c=br.read()) == 38) {if(state == 0) {token += (char) c;state = 0;addInfo(); // 提交符號}return true;}else return false;} else if(c == 46) { // . 特殊處理if(state == 0) { // 上一狀態是0token += (char) c;c = br.read(); // 查詢下一符號if(isDigit(c)) { //識別.01錯誤token += br.readLine();info = fileName + ":" + lineNumber + ": 錯誤: 不是合法的數字\n" + token + "\n";error.add(info);zeroing();} else addInfo();} else if(state == 1) { // 上一狀態是1(數字)token += (char) c; // 臨時存儲token += br.readLine();info = fileName + ":" + lineNumber + ": 錯誤: 不是整數\n" + token + "\n";error.add(info);zeroing();} else if(state == 2 && (token.equals("System") || token.equals("System.out"))) {token += (char) c;} else if(state == 2 && !token.equals("System") && !token.equals("System.out")) {addInfo(); // 提交上一個狀態的token,并清零token += (char) c;state = 0;addInfo(); // 提交符號}return true;} elsereturn false;}/*** 處理空格、換行符和其他字符(錯誤)* @param c* @param br* @throws IOException*/public static void isEnd(int c, BufferedReader br) throws IOException {if (c == 32 || c == 9) { // 空格addInfo();state = 0; // 狀態歸零} else if (c == 13 || c == 10) { // 記錄換行,行號++addInfo();state = 0; // 狀態歸零lineNumber++;} else if (state == 0) {state = 3;token += (char) c;token += br.readLine();info = fileName + ":" + lineNumber + ": 錯誤: 不是語句\n" + token + "\n";error.add(info);zeroing();} else if (state == 2) {state = 3;token += (char) c;token += br.readLine();info = fileName + ":" + lineNumber + ": 錯誤: 非法字符:"+ (char)c +"\n" + token + "\n";error.add(info);zeroing();}}/*** 判斷token是否是關鍵字* @param token* @return*/public static boolean isKey(String token) {if(token.equals("class") || token.equals("public") || token.equals("static") || token.equals("void") ||token.equals("main") || token.equals("String") || token.equals("extends") || token.equals("return") ||token.equals("int") || token.equals("boolean") || token.equals("if") || token.equals("else") ||token.equals("while") || token.equals("System.out.println") || token.equals("length") ||token.equals("true") || token.equals("false") || token.equals("this") || token.equals("new")) {return true;} else return false;}/*** 清空info token*/public static void zeroing() {info = "";token = "";}/*** 添加info*/public static void addInfo() {if(token.length() != 0 && state == 2 && isKey(token)) {info = token + " 關鍵字\n";result.add(info);zeroing();} else if(token.length() != 0 && state == 2) {info = token + " 標識符\n";result.add(info);zeroing();} else if(token.length() != 0 && state == 1) {info = token + " 數字\n";result.add(info);zeroing();} else if(token.length() != 0) {info = token + " 專用符號\n";result.add(info);zeroing();}}/*** 確定性有窮自動機* @param c 當前讀入的字符* @param br 文件讀入* @param bw 文件寫* @throws IOException*/public static void DFA(int c, BufferedReader br, BufferedWriter bw) throws IOException {switch (state) {case 0:if (isLetter(c)) {state = 2;break;} else if (isDigit(c)) {state = 1;break;} else if (isSymbol(c, br)) {state = 3;break;} else {isEnd(c,br);break;}case 1:if (isDigit(c)) {state = 1;break;} else if(isSymbol(c,br)) {state = 3; // 結束狀態1,進入狀態3break;} else if(isLetter(c)) {state = 3; // 出錯token += (char) c;token += br.readLine();info = fileName + ":" + lineNumber + ": 錯誤: 需要<標識符>\n" + token + "\n";error.add(info);zeroing();break;} else {isEnd(c,br);break;}case 2:if(isUnderline(c) || isLetter(c) || isDigit(c)) {state = 2;} else if(isSymbol(c, br)) {state = 3;} else {isEnd(c,br);}break;case 3:state = 0;if (isLetter(c)) {state = 2;break;} else if (isDigit(c)) {state = 1;break;} else if (isSymbol(c, br)) {state = 3;break;} else {isEnd(c,br);break;}}}/**** @param args* @throws IOException*/public static void main(String[] args) throws IOException {/*** 判斷輸入參數*/if (args.length == 0) {System.out.println("輸入數據為空");return;} else if(args.length == 1) {fileName = args[0];} else if(args.length > 1) {System.out.println("輸入參數多于1個,請調整參數個數");return;}/*** 檢查fileName是否是文件*/File check = new File(fileName);if (check.isDirectory()) { // 判斷是否是目錄System.out.println("請輸入正確的文件名,不要輸入文件夾的路徑");return;}br = new BufferedReader(new FileReader(fileName)); // 初始化文件輸入流/*** 創建tokenOut.txt文件*/File file = new File(pathname);if(!file.exists()) {file.createNewFile();}bw = new BufferedWriter(new FileWriter(file.getAbsoluteFile())); // 必須是getAbsoluteFile()?int c = 0;while (true) {c = br.read();if(c == -1) {addInfo();break;}DFA(c,br,bw);}/*** 寫文件*/if(error.size() != 0) {for (String line:error) {bw.write(line);}bw.close();br.close();return;}for(String line:result) {bw.write(line);}bw.close();br.close();} }?
總結
以上是生活随笔為你收集整理的编译原理——java 词法分析【有穷自动机实现】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 详解向图像加入高斯白噪声
- 下一篇: 使用 Arduino 测量血氧饱和度