消除文法中一切左遞歸算法

第一次寫博客。。。編譯原理課的一個實驗,覺得挺有意思的,跟大家分享一下。如果有BUG可以隨時提出。。。反正我也不一定改大笑

感覺自己花了挺長的時間,所以作爲博客保留下來,挺有紀念意義的  (因爲我是菜鳥害羞

註釋比較多,大家湊合着看看吧。。。

package com.insist.entity;

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
/**
 * 
 * @author SNOOPY
 *消除一切左遞歸
 */
public class EliminateLeftRecursion {

	private static int n;//實際輸入產生式個數
	public static void main(String[] args) {
		Scanner scan = new Scanner(System.in);
		System.out.println("請輸入產生式個數:");
		n = scan.nextInt();
		//創建產生式數組存放輸入的產生式
		List<Regular> regulars = new ArrayList<Regular>();
		for (int i=0;i<n;i++) {
			Regular reg = new Regular();
			System.out.println("請輸入產生式左部:");
			String left = scan.next();
			reg.setLeft(left);
			System.out.println("請輸入產生式的右部:");
			String right = scan.next();
			reg.setRight(right);
			regulars.add(reg);
		}
		/*測試輸出------->成功
		for (Regular reg: regulars) {
			System.out.println(reg.getLeft()+"---->"+reg.getRight());
		}*/
		
		//構造一個字符型的數組用來存放排序好的非終結符
		String[] Vn = new String[50];
		//對所有的產生式按照一定的順序存放
		Vn[0] = regulars.get(0).getLeft();//把產生式第一個非終結符放到集合中
		int flag=0;
		int count=0;
		for (int i = 1; i < n; i++) {//對非終結符排序並存取   1、遍歷產生式數組
			for (int j = 0; j < i; j++) {
				//如果產生式左部等於在它前面的產生式的左部
				if(regulars.get(i).getLeft().equals(regulars.get(j).getLeft())){//說明有重複的
					flag++;
				}
			}
			if(flag == 0){//說明沒有重複,則加入非終結符數組中
				count++;
				Vn[count] = regulars.get(i).getLeft();
			}
			flag=0;
		}
		/*測試非終結符數組------------>成功
		for (int i = 0; i < Vn.length; i++) {
			if(Vn[i]!=null){
				System.out.println(Vn[i]);
			}
		}
		*/
		for (Regular reg: regulars) {
			if(reg != null){
				System.out.println(reg.getLeft()+"---->"+reg.getRight());
			}
		}
		regulars = subFunction(regulars, Vn, count);
		for (Regular reg: regulars) {
			if(reg != null){
				System.out.println(reg.getLeft()+"---->"+reg.getRight());
			}
		}
	}
	
	public static List<Regular> subFunction(List<Regular> regulars , String[] Vn , int count){
		int flag=0;
		//判斷是否存在間接左遞歸併轉化爲直接左遞歸
		for( int i=0;i <= count;i++){//對每一個非終結符    迭代
			for(int j=0;j < i;j++){//對每一個小於i的非終結符遍歷
				for(int k=0;k < regulars.size();k++) //對每一個產生式
					if(Vn[i].equals(regulars.get(k).getLeft())){//i非終結符與第k產生式左邊第一個字母相等-->鎖定非終結符集合中的一個非終結符的產生式
						if(regulars.get(k).getRight().substring(0,1).equals(Vn[j])){  //g產生式右邊產生式第一個符號與第j個非終結符相等-->說明存在間接左遞歸
							for(int h=0;h < regulars.size();h++){
								if(regulars.get(h).getLeft().equals(Vn[j])){//進行替換
									String str;
									str=regulars.get(k).getRight().substring(1);//截取右邊第一個以後的字符
									Regular reg = new Regular();
									reg.setLeft(regulars.get(k).getLeft());
									reg.setRight(regulars.get(h).getRight()+str);
									regulars.add(reg);
								}
							}
							regulars.remove(k);
						}
					}
				}
			}
		//消除所有直接左遞歸
		for(int  i=0;i <= count;i++) {
			flag=0;
			for(int j=0;j < regulars.size();j++){//判斷是否存在直接左遞歸
				if(regulars.get(j).getLeft().equals(Vn[i])){
System.out.println(regulars.get(j).getLeft()+" ======= "+Vn[i]);
					if(regulars.get(j).getLeft().equals(regulars.get(j).getRight().substring(0, 1))){
System.out.println("消除間接左遞歸後存在直接左遞歸");
						flag++;
					}
				}
			}
			if(flag !=0 ){//存在直接左遞歸
				for(int j=0;j < regulars.size();j++){
					if(regulars.get(j).getLeft().equals(Vn[i])){//尋找與存在直接左遞歸的非終結符左部相同的的產生式
						if(regulars.get(j).getLeft().equals(regulars.get(j).getRight().substring(0,1))){
							//直接左遞歸的產生式
							String str=regulars.get(j).getRight().substring(1);
							String temp=regulars.get(j).getLeft();
							String temp1="'";
							regulars.get(j).setLeft(temp+temp1);
							regulars.get(j).setRight(str+regulars.get(j).getLeft());
							Regular reg = new Regular();
							reg.setLeft(regulars.get(j).getLeft());
							reg.setRight("ε");
							regulars.add(reg);
							
						}else{
							String temp=regulars.get(j).getLeft();
							String temp1="'";
							temp=temp+temp1;
							regulars.get(j).setRight(regulars.get(j).getRight()+temp);
						}
					}
				}
			}
		}
		return regulars;
	}
}


package com.insist.entity;

import java.io.Serializable;

/**
 * 
 * @author SNOOPY
 *
 */
public class Regular implements Serializable{

	private static final long serialVersionUID = 1L;

	private String right;//定義產生式右部
	
	private String left;//定義產生式左部

	public String getRight() {
		return right;
	}

	public void setRight(String right) {
		this.right = right;
	}

	public String getLeft() {
		return left;
	}

	public void setLeft(String left) {
		this.left = left;
	}
}















































發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章