java實現C語言子集的語法分析器
阿新 • • 發佈:2019-02-05
如題,只是做一個演算法的演示,所以並不能識別C語言全部的關鍵字,像int 等關鍵字會被識別為識別符號。可以按照自己需求自行擴充保留字表。
程式功能:
詞法分析器從input檔案中讀入一小段C語言源程式,以二元式形式按順序輸出所有單詞。輸出結果在顯示器上顯示,同時存入output檔案中。輸入的C語言源程式中的所有識別符號都要新增到識別符號表id-list中,所有無符號整數都要新增到無符號整數表uint-list中。
程式的輸出檔案包括: output, id-list, uint-list,
該程式的缺點:由於每讀一行都要向輸出檔案寫入,大大影響程式執行速度。有興趣的可以自行改進啦。
首先詞法分析器的輸出是以二元組的形式,建立二元組類如下:
public class TableItem {
public String type;
public String value;
public TableItem(String type,String value){
this.type=type;
this.value=value;
}
public TableItem(String type){
this.type=type;
}
}
詞法分析器類:
Main函式類:import java.awt.print.Printable; import java.io.BufferedWriter; import java.io.File; import java.io.FileNotFoundException; import java.io.FileWriter; import java.io.IOException; import java.io.RandomAccessFile; import java.sql.ResultSet; import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class Machine {//輸入一個單詞,輸出相應判斷,如果必要的話加入相應表中 public List<TableItem> resultList; public String token; public List<TableItem> reserveTable;//C語言的保留字表 public Machine(){ //只需要將保留字表初始化 reserveTable=new ArrayList<TableItem>(); reserveTable.add(new TableItem("res", "while")); reserveTable.add(new TableItem("res", "if")); reserveTable.add(new TableItem("res", "else")); reserveTable.add(new TableItem("res", "switch")); reserveTable.add(new TableItem("res", "case")); //reserveTable.add(new TableItem("id")); //reserveTable.add(new TableItem("num"));這兩個以後用到了現加 reserveTable.add(new TableItem("op", "+")); reserveTable.add(new TableItem("op", "-")); reserveTable.add(new TableItem("op", "*")); reserveTable.add(new TableItem("=")); reserveTable.add(new TableItem(";")); reserveTable.add(new TableItem("rop", "<=")); reserveTable.add(new TableItem("rop", "==")); reserveTable.add(new TableItem("rop", "<")); } public void printId() throws IOException{//將表中id儲存成txt RandomAccessFile randomFile = new RandomAccessFile("F://idoutput.txt", "rw"); long fileLength = randomFile.length(); for (TableItem tableItem : resultList) { if ("id".equals(tableItem.type)) { fileLength = randomFile.length(); // 將寫檔案指標移到檔案尾。 randomFile.seek(fileLength); randomFile.writeBytes(tableItem.value+" "); } } } public void printToScreen(){ for (TableItem tableItem : resultList) { System.out.println(tableItem.type+" "+tableItem.value+" "); } } public void printNum() throws IOException { RandomAccessFile randomFile = new RandomAccessFile("F://numoutput.txt", "rw"); long fileLength = randomFile.length(); for (TableItem tableItem : resultList) { if ("num".equals(tableItem.type)) { fileLength = randomFile.length(); // 將寫檔案指標移到檔案尾。 randomFile.seek(fileLength); randomFile.writeBytes(tableItem.value+" "); } } } public void printResult() throws IOException{ RandomAccessFile randomFile = new RandomAccessFile("F://output.txt", "rw"); // 檔案長度,位元組數 long fileLength = randomFile.length(); for (TableItem tableItem : resultList) { fileLength = randomFile.length(); // 將寫檔案指標移到檔案尾。 randomFile.seek(fileLength); randomFile.writeBytes(tableItem.type+" "+tableItem.value+" "); } randomFile.close(); } public void error(){ System.out.println("error"); } public int reserve(){ int i=0; for (TableItem tableItem : reserveTable) { String value= tableItem.value; String type=tableItem.type; i++; if (token.equals(value)&&"res".equals(type)) { return i; } } return 0; } public boolean AlreadyHave()//表中有沒有該項,不管是id還是res { for (TableItem tableItem : reserveTable) { String value= tableItem.value; if (token.equals(value)) { return true; } } return false; } public void analyseLex(String string)//一行一行的分析字串 { resultList=new ArrayList<TableItem>();//儲存分析結果的集合,每一項為一個二元組 char character; token=null; int length= string.length(); for (int i = 0; i < length; i++) {//一直迴圈到string結束 token=""; character=string.charAt(i);//將token和character重置 switch (character) { case' ': continue;//空格代表之前的識別已經結束,進入下一個單詞的識別 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z'://識別符號識別的入口 while (Character.isLetter(character)||Character.isDigit(character)) { //把s中字元送入token陣列 token+=character; i++; if (i>=length) { break; } character=string.charAt(i); } i--; character=string.charAt(i);//掃描指標回退一個字元 int isReserved=reserve(); if (isReserved==0) {//該單詞為識別符號 TableItem tableItem=new TableItem("id",token); if (!AlreadyHave()) { reserveTable.add(tableItem); //把識別符號登陸到符號表 } resultList.add(tableItem); } else { TableItem tableItem=new TableItem("res",token); resultList.add(tableItem); } continue;//一個單詞分析完了,迴圈繼續分析後面的單詞 case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': while (Character.isDigit(character)) { token+=character; i++; if (i>=length) { break; } character=string.charAt(i); } if (Character.isLetter(character)) { token+=character; resultList.add(new TableItem("error",token));//數字後面不能緊跟字母 continue; } i--; character=string.charAt(i);//確認緊跟的不是字母后掃描指標回退一個字元 TableItem tableItem=new TableItem("num",token); reserveTable.add(tableItem); //把常數登入到常數表 resultList.add(tableItem); continue; case '+': resultList.add(new TableItem("op","+")); continue; case '-': resultList.add(new TableItem("op","-")); continue; case '*': resultList.add(new TableItem("op","*")); continue; case'<': i++;//指標後移必須考慮下標越界 if (i>=length) { i--;//<是最後一個字元,詞法分析不用報錯 } character=string.charAt(i); if (character=='=') { resultList.add(new TableItem("relop","LE")); } else { i--; character=string.charAt(i); resultList.add(new TableItem("relop","LT")); } continue; case'=': i++; if (i>=length) { i--; character=string.charAt(i); resultList.add(new TableItem("="," ")); continue; } character=string.charAt(i); if (character=='=') { resultList.add(new TableItem("relop","EQ")); } else { i--; character=string.charAt(i); resultList.add(new TableItem("="," ")); } continue; case ';': resultList.add(new TableItem(";"," ")); continue; case '(': resultList.add(new TableItem("("," ")); continue; case ')': resultList.add(new TableItem(")"," ")); continue; case '>': resultList.add(new TableItem(">"," ")); continue; case '#': resultList.add(new TableItem("#"," ")); continue; case '{': resultList.add(new TableItem("{"," ")); continue; case '}': resultList.add(new TableItem("}"," ")); continue; case '[': resultList.add(new TableItem("(["," ")); continue; case ']': resultList.add(new TableItem("]"," ")); continue; default: resultList.add(new TableItem("error","token")); continue; } } } }
看到這了,還不點贊?import java.io.*; import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class M { public static void main(String[] args) throws IOException{ RandomAccessFile randomFile = new RandomAccessFile("F://output.txt", "rw"); randomFile.setLength(0);//清空上次執行程式時填入的資料 RandomAccessFile randomAccessFile=new RandomAccessFile("F://idoutput.txt", "rw"); randomAccessFile.setLength(0); RandomAccessFile randomAccessFile2=new RandomAccessFile("F://numoutput.txt", "rw"); randomAccessFile2.setLength(0); randomAccessFile.close(); randomAccessFile2.close(); randomFile.close(); String pathname = "D:\\input.txt"; // File filename = new File(pathname); // 要讀取以上路徑的input.txt檔案 InputStreamReader reader; try { reader = new InputStreamReader( new FileInputStream(filename)); BufferedReader br = new BufferedReader(reader); Machine machine=new Machine(); String line = ""; line = br.readLine(); while (line != null) { try { machine.analyseLex(line); machine.printResult(); machine.printToScreen(); machine.printId(); machine.printNum(); } catch (Exception e1) { // TODO Auto-generated catch block e1.printStackTrace(); } // 建立一個輸入流物件reader line=br.readLine(); } br.close(); } catch(Exception e){ e.printStackTrace(); } } }