1. 程式人生 > >java實現C語言子集的語法分析器

java實現C語言子集的語法分析器

如題,只是做一個演算法的演示,所以並不能識別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;
		
	}
}
詞法分析器類:
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;
			}
		}
		
	}
}
Main函式類:
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();
			}
		}
	
}

看到這了,還不點贊?