編譯原理實驗LL1分析
阿新 • • 發佈:2022-05-27
// 下面是實驗三的內容 : class LL1analysis extends JFrame implements ActionListener{ JLabel labelGrammarInput ; JButton buttonOpenFile; JButton buttonCertainGrammar; JButton buttonSaveFile; JLabel labelWarning1; JLabel labelWarning2; JLabel labelWarning3; JTextArea textAreaGrammar; JButton buttonGenerateFirstSet; JButton buttonGenerateFollowSet; JLabel labelFirstSet; JLabel labelFollowSet; JTextArea textAreaFirstSet; JTextArea textAreaFollowSet; JLabel labelForecastAnalysisTable; JButton buttonGenerateForecastAnalysis; JTextArea textAreaForecastAnalysisTable; JLabel labelAnalysisSentence; JLabel labelWaitAnalosisSentence; JTextField textFieldWaitAnalysisSentence; JButton buttonAnalysis , buttonSingleStepShow , buttonOneChickDisplay; JLabel labelAnalysisResult ; JTextArea textAreaAnalysisResult; // 用於 實現功能的變數 grammar currentGrammar ; boolean certainGrammar = false; boolean readyAnalysis = false; // 為句型 分析新增 Stack<Character> analStack = new Stack<>(); char[] sequence; int analIndex; boolean isEnd = false; String law = "*()+"; LL1analysis(){ init(); } void init(){ labelGrammarInput = new JLabel("文法輸入"); buttonOpenFile = new JButton("開啟檔案"); buttonOpenFile.addActionListener(this::actionPerformed); buttonSaveFile = new JButton("儲存文法"); buttonSaveFile.addActionListener(this::actionPerformed); buttonCertainGrammar = new JButton("確認文法"); buttonCertainGrammar.addActionListener(this::actionPerformed); labelWarning1 = new JLabel("注意事項:請輸入滿足L(1)最簡判別的2型文法。-行一個產生式"); labelWarning2 = new JLabel("注意事項:請輸入形式如S->A的產生式,空格用_表示,空用#表示"); labelWarning3 = new JLabel("注意事項:開始符為第一個產生式的左部,非終結符用大寫字母表示"); textAreaGrammar = new JTextArea(15,10); buttonGenerateFirstSet = new JButton("生成First集"); buttonGenerateFirstSet.addActionListener(this::actionPerformed); buttonGenerateFollowSet = new JButton("生成Fllow集"); buttonGenerateFollowSet.addActionListener(this::actionPerformed); labelFirstSet = new JLabel("First集"); textAreaFirstSet = new JTextArea(20,15); labelFollowSet = new JLabel("Follow集"); textAreaFollowSet = new JTextArea(20,15); labelForecastAnalysisTable = new JLabel("預測分析表"); buttonGenerateForecastAnalysis = new JButton("構造預測分析"); buttonGenerateForecastAnalysis.addActionListener(this::actionPerformed); textAreaForecastAnalysisTable = new JTextArea(20,15); labelAnalysisSentence = new JLabel("分析句子"); labelWaitAnalosisSentence = new JLabel("待分析句子"); textFieldWaitAnalysisSentence = new JTextField(15); buttonAnalysis = new JButton("分析"); buttonAnalysis.addActionListener(this::actionPerformed); buttonSingleStepShow = new JButton("單步顯示"); buttonSingleStepShow.addActionListener(this::actionPerformed); buttonOneChickDisplay = new JButton("一鍵顯示"); buttonOneChickDisplay.addActionListener(this::actionPerformed); labelAnalysisResult = new JLabel("分析結果"); textAreaAnalysisResult = new JTextArea(20,15); /* 整體 為一個一行兩列的結構 第一列: 為一個兩行一列的結構 第一行: 為一個五個方向的結構: 上方: 為一個五行一列的結構 第二行用一個一行三列的結構包括三個按鈕 其餘都只有一個標籤 center 為一個textarea ;south 為一個一行兩列的結構 包含兩個按鈕 第二行: 為一個四行一列的結構: 分別是兩個標籤和兩個area */ setLayout(new GridLayout(1,2)); JPanel panel1 = new JPanel(); panel1.setLayout(new GridLayout(2,1)); JPanel panel1_1 = new JPanel(); panel1_1.setLayout(new BorderLayout()); JPanel panel1_1_1 = new JPanel(); panel1_1_1.setLayout(new GridLayout(5,1)); JPanel panel1_1_1_1 = new JPanel(); panel1_1_1_1.setLayout(new GridLayout(1,3)); panel1_1_1_1.add(buttonOpenFile); panel1_1_1_1.add(buttonCertainGrammar); panel1_1_1_1.add(buttonSaveFile); panel1_1_1.add(labelGrammarInput); panel1_1_1.add(panel1_1_1_1); panel1_1_1.add(labelWarning1); panel1_1_1.add(labelWarning2); panel1_1_1.add(labelWarning3); panel1_1.add(panel1_1_1 , BorderLayout.NORTH); /* JScrollPane scroller = new JScrollPane(textAreaSourcePrograme); scroller.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); panel1.add(scroller, BorderLayout.CENTER);//向視窗新增文字編輯區 textAreaSourcePrograme.setWrapStyleWord(true);//設定單詞在一行不足容納時換行 textAreaSourcePrograme.setLineWrap(true);//設定文字編輯區自動換行預設為true,即會"自動換行" */ JScrollPane scrollPane1 = new JScrollPane(textAreaGrammar); scrollPane1.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); panel1.add(scrollPane1, BorderLayout.CENTER);//向視窗新增文字編輯區 textAreaGrammar.setWrapStyleWord(true);//設定單詞在一行不足容納時換行 textAreaGrammar.setLineWrap(true);//設定文字編輯區自動換行預設為true,即會"自動換行" panel1_1.add(scrollPane1,BorderLayout.CENTER); JPanel panel1_1_2 = new JPanel(); panel1_1_2.setLayout(new GridLayout(1,2)); panel1_1_2.add(buttonGenerateFirstSet); panel1_1_2.add(buttonGenerateFollowSet); panel1_1.add(panel1_1_2 , BorderLayout.SOUTH); JPanel panel1_2 = new JPanel(); panel1_2.setLayout(new GridLayout(2,1)); JPanel panel1_2_1 = new JPanel(); panel1_2_1.setLayout(new BorderLayout()); panel1_2_1.add(labelFirstSet ,BorderLayout.NORTH ); JScrollPane scrollPane3 = new JScrollPane(textAreaFirstSet); scrollPane3.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); panel1.add(scrollPane3, BorderLayout.CENTER);//向視窗新增文字編輯區 textAreaFirstSet.setWrapStyleWord(true);//設定單詞在一行不足容納時換行 textAreaFirstSet.setLineWrap(true);//設定文字編輯區自動換行預設為true,即會"自動換行" panel1_2_1.add(scrollPane3 , BorderLayout.CENTER); JPanel panel1_2_2 = new JPanel(); panel1_2_2.setLayout(new BorderLayout()); panel1_2_2.add(labelFollowSet ,BorderLayout.NORTH ); JScrollPane scrollPane2 = new JScrollPane(textAreaFollowSet); scrollPane2.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); panel1.add(scrollPane2, BorderLayout.CENTER);//向視窗新增文字編輯區 textAreaFollowSet.setWrapStyleWord(true);//設定單詞在一行不足容納時換行 textAreaFollowSet.setLineWrap(true);//設定文字編輯區自動換行預設為true,即會"自動換行" panel1_2_2.add(scrollPane2 , BorderLayout.CENTER); panel1_2.add(panel1_2_1); panel1_2.add(panel1_2_2); panel1.add(panel1_1); panel1.add(panel1_2); this.add(panel1); /* 第二列: 為一個五個方向的結構: 上方: 用三行一列的 包含 標籤 按鈕 area 中間 用一個五個方向的結構 上: 一個標籤 中: 兩行一列 標籤 fild 下: 三行一列 三個按鈕 下方: 兩行一列: 標籤 area */ JPanel panel2 = new JPanel(); panel2.setLayout(new GridLayout(2,1)); JPanel panel2_1 = new JPanel(); panel2_1.setLayout(new BorderLayout()); JPanel panel2_1_1 = new JPanel(); panel2_1_1.setLayout(new GridLayout(1,2)); panel2_1_1.add(labelForecastAnalysisTable); panel2_1_1.add(buttonGenerateForecastAnalysis); panel2_1.add(panel2_1_1 , BorderLayout.NORTH ); JScrollPane scrollPane4 = new JScrollPane(textAreaForecastAnalysisTable); scrollPane4.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); panel1.add(scrollPane4, BorderLayout.CENTER);//向視窗新增文字編輯區 textAreaForecastAnalysisTable.setWrapStyleWord(true);//設定單詞在一行不足容納時換行 textAreaForecastAnalysisTable.setLineWrap(true);//設定文字編輯區自動換行預設為true,即會"自動換行" panel2_1.add(scrollPane4 , BorderLayout.CENTER); panel2_1.add(labelAnalysisSentence , BorderLayout.SOUTH); JPanel panel2_2 = new JPanel(); panel2_2.setLayout(new BorderLayout()); // JPanel panel2_2_1 = new JPanel(); // panel2_2_1.setLayout(new GridLayout(2,1)); // panel2_2_1.add(labelAnalysisSentence ); JPanel panel2_2_2 = new JPanel(); panel2_2_2.setLayout(new BorderLayout()); panel2_2_2.add(labelWaitAnalosisSentence ,BorderLayout.WEST); panel2_2_2.add(textFieldWaitAnalysisSentence , BorderLayout.CENTER); JPanel panel2_2_3 = new JPanel(); panel2_2_3.setLayout(new GridLayout(1,3)); panel2_2_3.add(buttonAnalysis); panel2_2_3.add(buttonSingleStepShow); panel2_2_3.add(buttonOneChickDisplay); // panel2_2.add(panel2_2_1 , BorderLayout.NORTH); panel2_2.add(panel2_2_2 , BorderLayout.CENTER); panel2_2.add(panel2_2_3 , BorderLayout.SOUTH); JPanel panel2_3 = new JPanel(); panel2_3.setLayout(new BorderLayout()); panel2_3.add(labelAnalysisResult , BorderLayout.NORTH); JScrollPane scrollPane5 = new JScrollPane(textAreaAnalysisResult); scrollPane5.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); panel1.add(scrollPane5, BorderLayout.CENTER);//向視窗新增文字編輯區 textAreaAnalysisResult.setWrapStyleWord(true);//設定單詞在一行不足容納時換行 textAreaAnalysisResult.setLineWrap(true);//設定文字編輯區自動換行預設為true,即會"自動換行" panel2_3.add(scrollPane5 , BorderLayout.CENTER); JPanel t = new JPanel(); t.setLayout(new BorderLayout()); t.add(panel2_2 , BorderLayout.NORTH); t.add(panel2_3 , BorderLayout.CENTER); panel2.add(panel2_1 ); panel2.add(t ); // panel2.add(panel2_3 ); this.add(panel2); //設定視窗在螢幕上的位置、大小和可見性 this.setLocation(100, 100); this.setSize(1000, 700); this.setVisible(true); // addWindowListener(new WindowAdapter() { // public void windowClosing(WindowEvent e) { // exitWindowChoose(); // } // }); this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);//使用 System exit 方法退出應用程式 // 測試專用: textAreaGrammar.setText("S->AB\n" + "S->bC\n"+"C->AD\n"+"C->b\nA->#\nA->b\nD->aS\nD->c\nB->#\nB->aD"); buttonCertainGrammar.doClick(); // textAreaGrammar.setText("E->TR\n" // + "R->+TR\n" // + "R->#\n" // + "T->TY\n" // + "Y->*FY\n" // + "Y->#\n" // + "F->(E)\n" // + "F->a"); // // buttonCertainGrammar.doClick(); /* E->TR R->+TR R-># T->TY Y->*FY Y-># F->(E) F->a */ } boolean certainGrammar(){ if (currentGrammar !=null){ return currentGrammar.isL1L(); } return false; } @Override public void actionPerformed(ActionEvent e) { if (e.getSource() == buttonCertainGrammar){ initGrammar(); textAreaFirstSet.setText(""); if (certainGrammar() ){ textAreaFirstSet.append("合法"); }else { textAreaFirstSet.append("不合法"); currentGrammar = null; } // currentGrammar.show(textAreaFirstSet); }else if(e.getSource() == buttonGenerateFirstSet){ // 生成First集 if (currentGrammar !=null){ currentGrammar.showFirstSet(textAreaFirstSet); } }else if (e.getSource() == buttonGenerateFollowSet){ if (currentGrammar !=null){ currentGrammar.showFollowSet(textAreaFollowSet); } }else if (e.getSource() == buttonGenerateForecastAnalysis){ // 顯示 構造 預測分析表 if (currentGrammar !=null){ currentGrammar.showGenerateForecastTable(textAreaForecastAnalysisTable); } }else if (e.getSource() == buttonAnalysis){ initAnalysis(); if (readyAnalysis == false){ textAreaAnalysisResult.append("無法啟動"+ "\n"); }else { textAreaAnalysisResult.setText(""); startAnalysis(); textAreaAnalysisResult.append("準備完畢"+ "\n"); } }else if (e.getSource() == buttonOneChickDisplay) { while (isEnd == false){ oneStep(); } }else if (e.getSource() == buttonSingleStepShow){ oneStep(); }else if (e.getSource() == buttonOpenFile){ String ass = openGrammar(); if (ass !=null){ textAreaGrammar.setText(""); textAreaGrammar.append(ass); }else { textAreaGrammar.append("錯誤"); } }if (e.getSource() == buttonSaveFile){ save(); } } String openGrammar() { String str = null; JFileChooser fileChooser = new JFileChooser(); fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); fileChooser.setDialogTitle("開啟檔案"); int result = fileChooser.showOpenDialog(this); if (result == JFileChooser.CANCEL_OPTION) { return null; } File fileName = fileChooser.getSelectedFile(); if (fileName == null || fileName.getName().equals("")) { JOptionPane.showMessageDialog(this, "不合法的檔名", "不合法的檔名", JOptionPane.ERROR_MESSAGE); } else { try { FileInputStream fis = new FileInputStream(fileName); InputStreamReader isr = new InputStreamReader(fis, "gbk");//避免中文亂碼 BufferedReader bfr = new BufferedReader(isr); // FileReader fr = new FileReader(fileName); // BufferedReader bfr = new BufferedReader(fr); String ans = ""; int count = 0; if ((str = bfr.readLine()) != null) { count = 1; } while (count != 0) { // System.out.print(str); ans = ans.concat(str) + "\n"; if ((str = bfr.readLine()) != null) { count = 1; // System.out.print("\n"); } else { count = 0; } } return ans; } catch (Exception e) { } } return null; } void save( ){ String str = null; JFileChooser fileChooser = new JFileChooser(); fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); //fileChooser.setApproveButtonText("確定"); fileChooser.setDialogTitle("儲存"); int result = fileChooser.showSaveDialog(this); File saveFileName = fileChooser.getSelectedFile(); if (saveFileName == null || saveFileName.getName().equals("")) { JOptionPane.showMessageDialog(this, "不合法的檔名", "不合法的檔名", JOptionPane.ERROR_MESSAGE); } else { try { FileWriter fw = new FileWriter(saveFileName); BufferedWriter bfw = new BufferedWriter(fw); String ans = textAreaGrammar.getText(); bfw.write(ans); bfw.flush();//重新整理該流的緩衝 bfw.close(); } catch (IOException ioException) { } } } void oneStep(){ // 往前分析一步 if (analIndex == sequence.length){ isEnd =true; textAreaAnalysisResult.append("分析結束\n"); return; } char sour = analStack.peek(); char des = sequence[analIndex]; if (sour == des){ analIndex++; analStack.pop(); textAreaAnalysisResult.append("匹配" + sour + "\n"); textAreaAnalysisResult.append("當前句子" + String.valueOf(sequence).substring(analIndex)+ "\n"); textAreaAnalysisResult.append("當前分析棧" + analStack.toString()+ "\n"); textAreaAnalysisResult.append("\n\n"); return; } Map<Character , pUnit> now = currentGrammar.forecastAnalysisTable.get(new Character(sour)); pUnit ans = now.get(new Character(des)); if (ans == null){ textAreaAnalysisResult.append("出錯"+ "\n"); return; } textAreaAnalysisResult.append("匹配產生式"+ans.toString()+ "\n"); analStack.pop(); String lll = ans.des; char[] lis = lll.toCharArray(); int len = lis.length; int i = len-1; for (;i>=0 ; i--){ if (lis[i] == '#'){ break; } analStack.push(new Character(lis[i])); } textAreaAnalysisResult.append("當前句子" + String.valueOf(sequence).substring(analIndex)+ "\n"); textAreaAnalysisResult.append("當前分析棧" + analStack.toString()+ "\n"); textAreaAnalysisResult.append("\n\n"); } void initAnalysis(){ if (currentGrammar == null || currentGrammar.forecastAnalysisTable == null){ readyAnalysis = false; }else { readyAnalysis = true; } } void startAnalysis(){ // 啟動 分析 String a = textFieldWaitAnalysisSentence.getText(); a = a+"#"; sequence = a.toCharArray(); analIndex = 0; analStack.clear(); analStack.push(new Character(new Character('#'))); analStack.push(new Character(currentGrammar.S)); isEnd = false; } void initGrammar(){ String text = textAreaGrammar.getText(); initGrammar(text); } void initGrammar(String text){ String[] gra = text.split("\n"); // 根據 輸入的產生式 初始化 文法 // 先統計 終結符 和 非終結符 grammar ans = new grammar(); Set<Character> VN = new HashSet<>(); Set<Character> VT = new HashSet<>(); char[] all = text.toCharArray(); // 先單獨抽出 S ans.S = all[0]; for (char a : all){ if (isBigLetter(a)){ VN.add(new Character(a)); } if (isSmallLetter(a)){ VT.add(new Character(a)); } } // 將集合 轉換為陣列 初始化 VN 和VT ans.VN = setToCharArray(VN); ans.VT = setToCharArray(VT); // System.out.println(VN); // System.out.println(VT); // 建立一個 非終結符 到下標的對映 Map<Character , Integer> indexMap = new HashMap<>(); int i=0; for (Character a : VN){ indexMap.put(a , new Integer(i++)); } // 下面 根據非終結符的數量 初始化P 然後遍歷文法 新增產生式 ans.P = new ArrayList[VN.size()]; for (i=0 ; i<VN.size() ; i++){ ans.P[i] = new ArrayList<>(); } // 下面 遍歷 新增 for (String now : gra){ // 每一行 是一個產生式 now= now.replaceAll(" ",""); char[] arr = now.toCharArray(); char source = arr[0]; String des = now.substring(3); pUnit x = new pUnit(String.valueOf(source) , des); ans.P[ indexMap.get(source) ].add(x); } // 初始化完成 // System.out.println("初始化結果"); // System.out.println(ans.P); currentGrammar = ans; // currentGrammar.show(); } // 判斷 是大寫字母 還是小寫字母 boolean isBigLetter( char a){ if (a >= 'A' && a<='Z') { return true; } return false; } boolean isSmallLetter( char a ){ if (a >= 'a' && a<='z') { return true; } if (law.indexOf(String.valueOf(a)) !=-1){ return true; } return false; } public char[] setToCharArray(Set<Character> a){ char[] ans = new char[a.size()]; int inde = 0; for (Character s: a){ ans[inde++] = s; } return ans; } } // 文法類 class grammar{ char[] VN ; char[] VT; ArrayList<pUnit>[] P; // P[i] 以VN[i] 開頭 static int UNKNOWN = -1; static int YES = 1; static int NO = 0; private Map<Character , Set<Character>> firstSet = null; private boolean[] isIntroductionEmpty = null; private Map<Character , Set<Character>> followSet = null; private Map<String , Set<Character>> selectSet = null; Map<Character , Map<Character , pUnit>> forecastAnalysisTable= null; char S; void showGenerateForecastTable(JTextArea panel){ if (forecastAnalysisTable == null){ generateForecastTable(); } panel.setText(""); Set<Character> VT = arrToSet(this.VT); VT.add(new Character('#')); for (char a : VN){ panel.append(a + ": \n"); Map<Character , pUnit> now = forecastAnalysisTable.get(new Character(a)); for (char s : VT){ if (now.containsKey(new Character(s))){ // 包含 panel.append(" "+String.valueOf(s) + " "); panel.append( now.get(new Character(s)).toString() + "\n"); }else { panel.append(" "+String.valueOf(s) + " null" + "\n"); } } } } boolean isL1L(){ if (selectSet == null){ getSelectSet(); } // 判斷是不是 LL1 int i=0; for (ArrayList<pUnit> a : P){ // 第i個的所有產生式 int count = 0; Set<Character> sc = new HashSet<>(); for (pUnit b : a){ if (selectSet.containsKey(b.toString())){ Set<Character> now = selectSet.get(b.toString()); sc.addAll(now); count += now.size(); } } if (count != sc.size()){ return false; } i++; } return true; } void generateForecastTable(){ if (selectSet == null){ getSelectSet(); } if (forecastAnalysisTable != null){ return; } Map<Character , Map<Character , pUnit>> table = new HashMap<>(); int i=0; for (ArrayList<pUnit> a : P){ // 第i個的所有產生式 Map<Character , pUnit> k = new HashMap<>(); for (pUnit b : a){ Set<Character> no = selectSet.get(b.toString()); for(char ass : no){ k.put(new Character(ass) , b); } } table.put( new Character(VN[i]) , k ); i++; } this.forecastAnalysisTable = table; } void showFirstSet(JTextArea panel){ // 顯示 first集 panel.setText(""); Map<Character , Set<Character>> ans = getFirstSet(); panel.append("顯示 各終結符/非終結符的first集合 \n"); panel.append("\n"); panel.append(ans.toString()); panel.append("顯示 各產生式的first集合 \n"); for (ArrayList<pUnit> a : P){ for (pUnit b : a){ panel.append(b.toString() + " "); // 這裡展示各產生式的右部符號串的first集合 panel.append(getFirstSet(b).toString() + "\n"); // System.out.println(b.toString()); } } } void showFollowSet(JTextArea panel){ panel.setText(""); Map<Character , Set<Character>> an = getFollowSet(); panel.append("顯示 follow集合 \n"); panel.append("\n"); panel.append(an.toString()); } public grammar() { // P = new ArrayLis } void show(JTextArea panel){ panel.setText(""); for (ArrayList<pUnit> a : P){ for (pUnit b : a){ panel.append(b.toString() + " "); // 這裡展示各產生式的右部符號串的first集合 panel.append(getFirstSet(b).toString() + "\n"); // System.out.println(b.toString()); } } // 顯示 first集合 // 這裡展示 first集合 Map<Character , Set<Character>> ans = getFirstSet(); panel.append("顯示 first集合 \n"); panel.append("\n\n"); panel.append(ans.toString()); // 這裡展示 follow集合 Map<Character , Set<Character>> an = getFollowSet(); panel.append("顯示 follow集合 \n"); panel.append("\n\n"); panel.append(an.toString()); panel.append("\n顯示 select集\n"); for (ArrayList<pUnit> a : P){ for (pUnit b : a){ panel.append(b.toString() + " "); // 這裡展示各產生式的右部符號串的first集合 panel.append(getSelectSet(b).toString() + "\n"); // System.out.println(b.toString()); } } } void show(){ System.out.println(VT); System.out.println(VN); for (ArrayList<pUnit> a : P){ for (pUnit b : a){ System.out.print(b.toString() + "\n"); // System.out.println(b.toString()); } } } public grammar(char[] VN, char[] VT, ArrayList<pUnit>[] p, char s) { this.VN = VN; this.VT = VT; P = p; S = s; } void add( char source , String des ){ int x = String.valueOf(VN).charAt(source); pUnit a = new pUnit(source , des); P[x].add(a); } boolean[] getIsIntroductionEmpty(){ if (isIntroductionEmpty !=null){ return isIntroductionEmpty; } int[] ans = new int[VN.length]; boolean[] aans = new boolean[VN.length]; int i; int l = VN.length; for (i=0 ; i<l ; i++){ ans[i] = UNKNOWN; } grammar now = this.copy(); // 刪除右部含有非終結符的產生式 int j; for (i=0 ; i<l ; i++){ for (j=0 ; j<now.P[i].size() ; j++){ pUnit s = now.P[i].get(j); if (s.desIsEmpty()){ ans[i]= YES; // System.out.println("fdsv"); now.P[i].clear(); // System.out.println("sd----"); } if (s.desContainEndChar(VT)){ now.P[i].remove(j); } } if (now.P[i].size() == 0 && ans[i] == UNKNOWN){ ans[i] = NO; } } // now.show(); // 重複掃描 int count = 1; while (count ==1){ count = 0; for (i=0 ; i<l ; i++){ // System.out.println(i); for (j=0 ; j<now.P[i].size() ; j++){ pUnit s = now.P[i].get(j); // System.out.println(s.toString()); // now.P[i].remove(j); // System.out.print(s.des); // System.out.println("ds"); if (s.desIsEmpty()){ ans[i] = YES; count = 1; now.P[i].clear(); break; } int z; for (z= 0 ; z<l ; z++){ if (ans[z] == YES){ s.des = s.des.replaceAll(String.valueOf(VN[z]) , ""); if (s.desIsEmpty()){ ans[i] = YES; count = 1; now.P[i].clear(); break; } } } } } } for (i = 0 ; i<l ; i++){ if (ans[i] == YES){ aans[i] = true; }else { aans[i] = false; } // System.out.println(aans[i]); } isIntroductionEmpty = aans; return aans; } grammar copy(){ grammar ans = new grammar(); ans.VN = String.valueOf(this.VN).toCharArray(); ans.VT = String.valueOf(this.VT).toCharArray(); ans.S = this.S; ans.P = new ArrayList[VN.length]; int i; int l = VN.length; for (i=0 ; i<l ; i++){ ans.P[i] = new ArrayList<>(); for (pUnit a:this.P[i] ){ ans.P[i].add(new pUnit(a)); } } // ans.show(); return ans; } // 計算 每一個文法符號的 first集 Map<Character , Set<Character>> getFirstSet() { if (firstSet !=null){ return firstSet; } boolean[] isToEmpty = getIsIntroductionEmpty(); // for (boolean a : isToEmpty){ // System.out.println(a); // } // System.out.println(VT); // System.out.println(VN); Map<Character , Integer> indexMap = new HashMap<>(); int i = 0; // for (char a :VT){ // indexMap.put(new Character(a) , i++); // } for (char a :VN){ indexMap.put(new Character(a) , i++); } Map<Character , Set<Character>> ans = new HashMap<>(); // 先統計非終結符的first集 for (char a : VT){ Set<Character> x = new HashSet<>(); x.add(new Character(a)); ans.put(new Character(a) , x); } for (char a : VN){ Set<Character> x = new HashSet<>(); ans.put(new Character(a) , x); } int count = 1; Set<Character> VNSet = arrToSet(VN); Set<Character> VTSet = arrToSet(VT); // 這裡統計一個 可以推出空的集合 用於後面判斷 Set<Character> toEmpty = new HashSet<>(); for (i=0 ; i< VN.length ; i++){ if (isToEmpty[i]){ toEmpty.add(new Character(VN[i])); } } int j; while (count == 1){ count = 0; // 執行第二步 若X∈VN,且有Xa…,a∈ VT,則a∈FIRST(X); 第三步 若X∈VN,X ε ,則ε∈ FIRST(X); // 遍歷 產生式 X必定屬於VN 看右邊 是否 都是終結符 i=0; for (ArrayList<pUnit> now : P){ for (pUnit x : now){ // 當前 為第i個非終結符的產生式 Set<Character> cu = arrToSet(x.des.toCharArray()); // 是否 全為 終結符 第二步 // System.out.println(cu); // System.out.println(VT); if (VTSet.containsAll(cu) && ans.get(VN[i]).contains(new Character( x.des.charAt(0) )) == false){// 符合且未包含 // 全部包含 即全為終結符 // System.out.println(" 第二步 "); ans.get(VN[i]).add(new Character( x.des.charAt(0) )); // System.out.println(VTSet); // System.out.println(x.des.charAt(0)); count = 1; // System.out.println("sdjk"); } // 順便判斷 第三步 if ( isToEmpty[i] == true && ans.get(VN[i]).contains(new Character('#')) == false){ // 該非終結符 可以推出空 ans.get(VN[i]).add(new Character( '#')); // System.out.println("fds"); count = 1; } } i++; } // 執行 第四步和第五步 4)若X∈VN,Y1,Y2,…,Yn都∈VN,且有XY1Y2…Yn 。當Y1,Y2,…,Yi-1都 ε時,(其中1<=i<=n),則FIRST(Y1)-{ε}, FIRST(Y2)-{ε},…,FIRST(Yi-1)-{ε},FIRST(Yi)都包含在FIRST(X)中。 // 都是 非終結符 i=0; for (ArrayList<pUnit> now : P){ // 統計要新增的所有新的 元素 以判斷是否 有新的新增進去 Set<Character> updateSet = new HashSet<>();// 要新增的 最後判斷 是否有新的 for (pUnit x : now){ // 當前 為第i個非終結符的產生式 Set<Character> cu = arrToSet(x.des.toCharArray()); // 是否 全為 非終結符 第四步 if (VNSet.containsAll(cu)) { // 全部包含 即全為非終結符 // 判斷 第四步 還是 第五步 即: -> 是否 全都可以推出空 if (toEmpty.containsAll(cu)){ // 全都可以推出空 第五步 // 更新 updateSet for (Character aa : cu){ for (Character as : ans.get(aa)){ if (as !='#'){ updateSet.add(aa); } } } updateSet.add(new Character('#')); // 第五步 }else { // 非 全都可以推出空 第四步 char[] curr = x.des.toCharArray(); for (int ii = 0 ; ii < curr.length ; ii++){ if (toEmpty.contains(curr[ii])){ // 屬於 0-(i-1) if (updateSet.contains(new Character('#'))){ updateSet.addAll(ans.get(curr[ii])); }else { updateSet.addAll(ans.get(curr[ii])); updateSet.remove(new Character('#')); } }else { // 屬於 i updateSet.addAll(ans.get(curr[ii])); break; } } } // ok }else { // 這裡就是 含有 非終結符 也有 終結符 char[] akd = x.des.toCharArray(); for ( char ds : akd){ // 非終結符 if (VNSet.contains(new Character(ds))){ if (ans.get(ds).contains('#')){ //可以退空 if (updateSet.contains('#')){ updateSet.addAll(ans.get(ds)); }else { updateSet.addAll(ans.get(ds)); updateSet.remove('#'); } continue; }else { updateSet.addAll(ans.get(ds)); break; } } if (VTSet.contains(ds)){ updateSet.add(new Character(ds)); break; } } } } // 這裡遍歷完 第i的個非終結符的所有產生式 判斷 是否有更新 if (ans.get(new Character(VN[i])).containsAll(updateSet)){ // 包含全部 }else { count = 1; ans.get(new Character(VN[i])).addAll(updateSet); // 更新 } i++; } // System.out.println(ans.toString()); } firstSet = ans; return ans; } public Set<Character> arrToSet(char[] a){ Set<Character> ans = new HashSet<>(); for (char as : a){ ans.add(new Character(as)); } return ans; } Set<Character> getFirstSet(pUnit a){ if (firstSet == null){ getFirstSet(); } //first集未初始化 Set<Character> ans = new HashSet<>(); // Map<Character , Integer> indexMap = new HashMap<>(); int i = 0; // show(); for (char aa :VN){ indexMap.put(new Character(aa) , i++); } // System.out.println(indexMap); Set<Character> VNSet = arrToSet(VN); Set<Character> VTSet = arrToSet(VT); char[] des = a.des.toCharArray(); // System.out.println(a.toString()); if (des[0] == '#'){ ans.add(new Character('#')); return ans; } for (char aa : des){ if(VTSet.contains(aa)){ ans.add(new Character(aa)); return ans; } if (isIntroductionEmpty[ indexMap.get(aa) ] ){ ans.addAll(firstSet.get(new Character(aa))); ans.remove(new Character('#')); }else { ans.addAll(firstSet.get(new Character(aa))); ans.remove(new Character('#')); return ans; } } ans.add(new Character('#')); return ans ; } Set<Character> getFirstSet(String a){ return getFirstSet(new pUnit("2",a)); } Map<Character , Set<Character>> getFollowSet(){ if (followSet !=null){ return followSet; } if (firstSet == null){ getFirstSet(); } Map<Character , Set<Character>> ans = new HashMap<>(); // 由於要統計 每個 follow 都不在增大時 結束 所以 這裡統計一個總數 int count = 0;// 所有follow 為空 int i,j; int l = VN.length; // 初始化 for( char a : VN){ ans.put(new Character(a) , new HashSet<>()); } // 設A為文法開始符號,把#加入FOLLOW(A)中,(#為句子括號) ans.get(new Character(S)).add(new Character('#')); int update = 1; Set<Character> VNSet = arrToSet(VN); Set<Character> VTSet = arrToSet(VT); while (count != update){ count = update; // 遍歷 所有產生式 i=0; for (ArrayList<pUnit> now : P){ for (pUnit x : now){ String des = x.des; char[] lis = des.toCharArray(); char source = x.source.charAt(0); // 第二步 /* 2)若BαAβ是一個產生式,則把FIRST(β)的非空元素加入FOLLOW(A)中。 如果β ε,則把FOLLOW(B)也加入FOLLOW(A): 因為當有形如Dα1Bβ1 BαAβ的產生式時,A、B、D∈VN, α1,β1,α,β∈V*,在推導過程中可能出現句型序列如 S …α1Bβ1…=>…α1αAββ1 …=> …α1αAβ1, 故FIRST(β1)∈FOLLOW(B)和FIRST(β1) ∈ FOLLOW(A),所以FOLLOW(B)FOLLOW(A) */ // 過濾掉 右側為空的 和 全為終結符的產生式 if (des.equals("#" )|| VTSet.containsAll(arrToSet(lis)) ){ continue; } // 含有 非終結符 檢測 for(i=0 ;i<lis.length ; i++){ if (VNSet.contains(lis[i])){ // 是非終結符 if (i== lis.length-1){ // 最後一個 ans.get(lis[i]).addAll( ans.get(new Character(source)) ); continue; } String sub = des.substring(i+1); Set<Character> fir = getFirstSet(sub); // ans.get(lis[i]).addAll(fir); if (fir.contains(new Character('#'))){ ans.get(lis[i]).addAll( ans.get(new Character(source)) ); }else { } } } } } update = 0; for(char aaa: VN){ update = update+ ans.get(new Character(aaa)).size(); } } this.followSet = ans; return ans; } Map<String , Set<Character>> getSelectSet() { if (selectSet != null){ return selectSet; } if (firstSet == null){ getFirstSet(); } if (followSet == null){ getFollowSet(); } Map<String, Set<Character>> ans = new HashMap<>(); for (ArrayList<pUnit> a : P) { for (pUnit b : a) { // 這裡展示各產生式的右部符號串的first集合 ans.put(b.toString(), getSelectSet(b)); // System.out.println(b.toString()); } } selectSet = ans; return ans; } Set<Character> getSelectSet( pUnit a ){ // if (selectSet == null){ // getSelectSet(); // } // System.out.println(a.toString()); if (a.des == "#"){ return followSet.get(new Character(a.source.charAt(0))); } Set<Character> now = getFirstSet(a); if (now.contains(new Character('#'))){ now.remove(new Character('#')); if (this.followSet == null){ getFollowSet(); } Set<Character> as = followSet.get(new Character(a.source.charAt(0))); now.addAll(as); return now; }else { return now; } } } class pUnit { String source; String des; public pUnit() { } @Override public String toString() { return source + "->" + des; } public pUnit(String source, String des) { this.source = source; this.des = des.replaceAll("\n",""); } public pUnit(char source, String des) { this.source = String.valueOf(source); this.des = des; } public pUnit(pUnit a) { this.des = a.des; this.source = a.source; } boolean desContainEndChar(char[] VT){ for (char a : VT){ if (des.indexOf(a) !=-1){ return true; } } return false; } boolean desIsEmpty(){ if (des.equals("#") || des.equals("")){ return true; } return false; } }
這裡沒有新增main 函式ou 直接新建一個LL1analysis類就行了