第一次寫博客。。。編譯原理課的一個實驗,覺得挺有意思的,跟大家分享一下。如果有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;
}
}