1. 程式人生 > >語法設計——基於LL(1)文法的預測分析表法

語法設計——基於LL(1)文法的預測分析表法

實驗二、語法設計——基於LL(1)文法的預測分析表法

一、實驗目的

通過實驗教學,加深學生對所學的關於編譯的理論知識的理解,增強學生對所學知識的綜合應用能力,並通過實踐達到對所學的知識進行驗證。通過對基於LL(1)文法的預測分析表法DFA模擬程式實驗,使學生掌握確定的自上而下的語法分析的實現技術,及具體實現方法。通過本實驗加深對語詞法分析程式的功能及實現方法的理解 。

二、實驗環境

供Windows系統的PC機,可用C++/C#/Java等程式設計工具編寫

三、實驗內容

1、自己定義一個LL(1)文法

示例如(僅供參考) G[E]:E →TE' E' → +TE' | ε

T →FT' T' → *FT' | ε F → i | ( E )

2、構造其預測分析表,如

img
3、LL(1)文法的預測分析表的模型示意圖

img

4、預測分析控制程式的演算法流程

img

5、執行結果,示例如下

img

四、實驗方式與要求

1、設計的下推自動機具有通用性,上機程式設計實現;

2、實驗報告格式要求書寫要點:概要設計(總體設計思想);詳細設計(程式主流程、自動機的儲存格式、關鍵函式的流程圖);結果分析(輸入與輸出結果、存在問題及有待改進善的地方、實驗心得);

3、實驗報告限4頁內。

設計思路:我就講解一下核心部分程式碼,首先,進棧函式在 298 行處左右,我們用 ArrayList 去定義一個動態陣列 analyzeProduces ,我們定義了一個棧 analyzeStatck

,而這個棧在我們在定義 Analyzer 類中初始化化過了,所以在建立 analyzeStatck 中首先會進行初始化操作, push 了一個 # ,所以analyzeStatck 棧中會存在 # 這個字元(以這個 # 作為標記),然後 302 行,我們向 analyzeStack 中推入開始符號,也就是我們在主函式設定的字元 E ,然後打印出開始符號以及一些格式要求(步驟,符號棧,輸入串,產生式等等),設定 index 的值來記錄走過的步驟次數 。

308 行開始,我們開始對棧進行分析。我們設定一個判斷棧 analyzeStatck 是否為空,由前面可知,棧中存在 #E 兩個字元,顯然字元是非空的,通過 index++

記錄當前的步數,然後我們去通過 peek 函式去彈出當前棧頂元素的第一個字元,通過和剩餘輸入串 str 的第一個字元進行匹配。

如果棧頂元素與當前輸入串的第一個字元不可以匹配,我們就去分析表 TextUtil 中利用函式 findUseExp 去找到這個產生式,而 findUseExp 函式我們通過去定義了一個雜湊表去儲存查找出來的棧頂元素,用一個集合 keySet 去儲存雜湊表的所有鍵值,通過 for 迴圈,利用定義一個紅黑樹 treeSet 去存取表示式,然後去進行匹配,如果在紅黑樹中包含了當前查詢的字元,我們就返回當前從雜湊表中所獲取到的表示式。將當前所找到的產生式存入到 nowUseExpStr 中,打印出此時所進行到的步驟值,符號棧,輸入棧,產生式。316 行,我們建立一個分析棧 produce 去記錄上一步的值(位置,符號棧,輸入串),判斷當前的產生式是否為空,如果不為空,設定下當前分析棧的產生式,將整個分析棧加入到動態陣列 analyzeProduces 中,再將之前的分析棧中的棧頂彈出,如果當前的表示式不為空且第一個字元不是空字元,我們再將需要用到的表示式進行反序入棧。

如果棧頂元素與當前輸入串的第一個字元可以匹配,分析棧出棧,串去掉一位,建立一個新的分析棧 produce ,記錄上一步的值(位置,符號棧,輸入串),設定當前產生式為當前輸入串的第一個字元可以匹配,將整個分析棧加入到動態陣列 analyzeProduces 中,再將之前的分析棧中的棧頂彈出,將剩餘的字串記錄在 str 字串中。

注:produce 相當於是一個持久化儲存中間引數的一個分析棧

實驗程式碼如下:

package python;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet; 
import java.util.Stack;

/**
 * @author Angel_Kitty
 * @createTime 2018年11月24日 上午0:46:33
 */

class TextUtil {
    /**
     * (3)B->aA,=Follow(B)
     * 
     * @param nvSet
     * @param itemCharStr
     * @param a
     * @param expressionMap
     * @return
     */
    public static boolean containsbA(TreeSet<Character> nvSet, String itemCharStr, Character a,
            HashMap<Character, ArrayList<String>> expressionMap) {
        String aStr = a.toString();
        String lastStr = itemCharStr.substring(itemCharStr.length() - 1);
        if (lastStr.equals(aStr)) {
            return true;
        }
        return false;
 
    }
 
    /**
     * 形如aBb,b=空
     * 
     * @param nvSet
     * @param itemCharStr
     * @param a
     * @param expressionMap
     * @return
     */
    public static boolean containsbAbIsNull(TreeSet<Character> nvSet, String itemCharStr, Character a,
            HashMap<Character, ArrayList<String>> expressionMap) {
        String aStr = a.toString();
        if (containsAB(nvSet, itemCharStr, a)) {
            Character alastChar = getAlastChar(itemCharStr, a);
            System.out.println("----------------+++++++++++++++++++--" + expressionMap.toString());
            ArrayList<String> arrayList = expressionMap.get(alastChar);
            if (arrayList.contains("ε")) {
                System.out.println(alastChar + "  contains('ε')" + aStr);
                return true;
            }
        }
        return false;
 
    }
 
    /**
     * 是否包含這種的字串<Br>
     * (2)Ab,=First(b)-ε,直接新增終結符
     * 
     * @param str
     * @param a
     * @return
     */
    public static boolean containsAb(TreeSet<Character> ntSet, String itemCharStr, Character a) {
        String aStr = a.toString();
        if (itemCharStr.contains(aStr)) {
            int aIndex = itemCharStr.indexOf(aStr);
            String findStr;
            try {
                findStr = itemCharStr.substring(aIndex + 1, aIndex + 2);
            } catch (Exception e) {
                return false;
            }
            if (ntSet.contains(findStr.charAt(0))) {
                return true;
            } else {
                return false;
            }
        } else {
            return false;
        }
    }
 
    /**
     * 是否包含這種的字串<Br>
     * (2).2Ab,=First(b)-ε
     * 
     * @param str
     * @param a
     * @return
     */
    public static boolean containsAB(TreeSet<Character> nvSet, String itemCharStr, Character a) {
        String aStr = a.toString();
        if (itemCharStr.contains(aStr)) {
            int aIndex = itemCharStr.indexOf(aStr);
            String findStr;
            try {
                findStr = itemCharStr.substring(aIndex + 1, aIndex + 2);
            } catch (Exception e) {
                return false;
            }
            if (nvSet.contains(findStr.charAt(0))) {
                return true;
            } else {
                return false;
            }
        } else {
            return false;
        }
    }
 
    /**
     * 獲取A後的字元
     * 
     * @param itemCharStr
     * @param a
     * @return
     */
    public static Character getAlastChar(String itemCharStr, Character a) {
        String aStr = a.toString();
        if (itemCharStr.contains(aStr)) {
            int aIndex = itemCharStr.indexOf(aStr);
            String findStr = "";
            try {
                findStr = itemCharStr.substring(aIndex + 1, aIndex + 2);
            } catch (Exception e) {
                return null;
            }
            return findStr.charAt(0);
        }
        return null;
    }
 
    /**
     * 是否為ε開始的
     * 
     * @param selectExp
     * @return
     */
    public static boolean isEmptyStart(String selectExp) {
        char charAt = selectExp.charAt(0);
        if (charAt == 'ε') {
            return true;
        }
        return false;
    }
 
    /**
     * 是否是終結符開始的
     * 
     * @param ntSet
     * @param selectExp
     * @return
     */
    public static boolean isNtStart(TreeSet<Character> ntSet, String selectExp) {
        char charAt = selectExp.charAt(0);
        if (ntSet.contains(charAt)) {
            return true;
        }
        return false;
    }
 
    /**
     * 是否是非終結符開始的
     * 
     * @param nvSet
     * @param selectExp
     * @return
     */
    public static boolean isNvStart(TreeSet<Character> nvSet, String selectExp) {
        char charAt = selectExp.charAt(0);
        if (nvSet.contains(charAt)) {
            return true;
        }
        return false;
    }
 
    /**
     * 查詢產生式
     * 
     * @param selectMap
     * @param peek
     *            當前Nv
     * @param charAt
     *            當前字元
     * @return
     */
    public static String findUseExp(TreeMap<Character, HashMap<String, TreeSet<Character>>> selectMap, Character peek,
            char charAt) {
        try {
            HashMap<String, TreeSet<Character>> hashMap = selectMap.get(peek);
            Set<String> keySet = hashMap.keySet();
            for (String useExp : keySet) {
                TreeSet<Character> treeSet = hashMap.get(useExp);
                if (treeSet.contains(charAt)) {
                    return useExp;
                }
            }
        } catch (Exception e) {
            return null;
        }
        return null;
    }
}

class Analyzer {
 
    public Analyzer() {
        super();
        analyzeStatck = new Stack<Character>();
        // 結束符進棧
        analyzeStatck.push('#');
    }
 
    private ArrayList<AnalyzeProduce> analyzeProduces;
 
    /**
     * LL(1)文法
     */
    private Gs ll1Gs;
 
    public Gs getLl1Gs() {
        return ll1Gs;
    }
 
    public void setLl1Gs(Gs ll1Gs) {
        this.ll1Gs = ll1Gs;
    }
 
    /**
     * 開始符
     */
    private Character startChar;
 
    /**
     * 分析棧
     */
    private Stack<Character> analyzeStatck;
    /**
     * 剩餘輸入串
     */
    private String str;
    /**
     * 推導所用產生或匹配
     */
    private String useExp;
 
    public ArrayList<AnalyzeProduce> getAnalyzeProduces() {
        return analyzeProduces;
    }
 
    public void setAnalyzeProduces(ArrayList<AnalyzeProduce> analyzeProduces) {
        this.analyzeProduces = analyzeProduces;
    }
 
    public Character getStartChar() {
        return startChar;
    }
 
    public void setStartChar(Character startChar) {
        this.startChar = startChar;
    }
 
    public Stack<Character> getAnalyzeStatck() {
        return analyzeStatck;
    }
 
    public void setAnalyzeStatck(Stack<Character> analyzeStatck) {
        this.analyzeStatck = analyzeStatck;
    }
 
    public String getStr() {
        return str;
    }
 
    public void setStr(String str) {
        this.str = str;
    }
 
    public String getUseExp() {
        return useExp;
    }
 
    public void setUseExp(String useExp) {
        this.useExp = useExp;
    }
 
    /**
     * 分析
     */
    //進棧 flag is here
    public void analyze() {
        analyzeProduces = new ArrayList<AnalyzeProduce>();
 
        // 開始符進棧
        analyzeStatck.push(startChar);
        System.out.println("開始符:" + startChar);
        System.out.println("步驟\t\t\t " + "符號棧\t\t        " + "\t輸入串 \t\t\t" + "所用產生式 ");
        int index = 0;
        // 開始分析
        // while (analyzeStatck.peek() != '#' && str.charAt(0) != '#') {
        while (!analyzeStatck.empty()) {
            index++;
            //返回棧頂元素
            if (analyzeStatck.peek() != str.charAt(0)) {
                // 到分析表中找到這個產生式
                String nowUseExpStr = TextUtil.findUseExp(ll1Gs.getSelectMap(), analyzeStatck.peek(), str.charAt(0));
                System.out.println(index + "\t\t\t" + analyzeStatck.toString() + "\t\t\t" + str + "\t\t\t"
                        + analyzeStatck.peek() + "->" + nowUseExpStr);
                AnalyzeProduce produce = new AnalyzeProduce();
                produce.setIndex(index);
                produce.setAnalyzeStackStr(analyzeStatck.toString());
                produce.setStr(str);
                if (null == nowUseExpStr) {
                    produce.setUseExpStr("無法匹配!");
                } else {
                    produce.setUseExpStr(analyzeStatck.peek() + "->" + nowUseExpStr);
                }
                analyzeProduces.add(produce);
                // 將之前的分析棧中的棧頂出棧
                analyzeStatck.pop();
                // 將要用到的表示式入棧,反序入棧
                if (null != nowUseExpStr && nowUseExpStr.charAt(0) != 'ε') {
                    for (int j = nowUseExpStr.length() - 1; j >= 0; j--) {
                        char currentChar = nowUseExpStr.charAt(j);
                        analyzeStatck.push(currentChar);
                    }
                }
                continue;
            }
            // 如果可以匹配,分析棧出棧,串去掉一位
            if (analyzeStatck.peek() == str.charAt(0)) {
                System.out.println(index + "\t\t\t" + analyzeStatck.toString() + "\t\t\t" + str + "\t\t\t" + "“"
                        + str.charAt(0) + "”匹配");
                AnalyzeProduce produce = new AnalyzeProduce();
                produce.setIndex(index);
                produce.setAnalyzeStackStr(analyzeStatck.toString());
                produce.setStr(str);
                produce.setUseExpStr("“" + str.charAt(0) + "”匹配");
                analyzeProduces.add(produce);
                analyzeStatck.pop();
                str = str.substring(1);
                continue;
            }
        }
 
    }
 
}

class AnalyzeProduce implements Serializable{
    private static final long serialVersionUID = 10L;
    private Integer index;
    private String analyzeStackStr;
    private String str;
    private String useExpStr;
 
    public Integer getIndex() {
        return index;
    }
 
    public void setIndex(Integer index) {
        this.index = index;
    }
 
    public String getAnalyzeStackStr() {
        return analyzeStackStr;
    }
 
    public void setAnalyzeStackStr(String analyzeStackStr) {
        this.analyzeStackStr = analyzeStackStr;
    }
 
    public String getStr() {
        return str;
    }
 
    public void setStr(String str) {
        this.str = str;
    }
 
    public String getUseExpStr() {
        return useExpStr;
    }
 
    public void setUseExpStr(String useExpStr) {
        this.useExpStr = useExpStr;
    }
 
}

class Gs implements Serializable {
 
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
 
    public Gs() {
        super();
        gsArray = new ArrayList<String>();
        nvSet = new TreeSet<Character>();
        ntSet = new TreeSet<Character>();
        firstMap = new HashMap<Character, TreeSet<Character>>();
        followMap = new HashMap<Character, TreeSet<Character>>();
        selectMap = new TreeMap<Character, HashMap<String, TreeSet<Character>>>();
    }
 
    private String[][] analyzeTable;
 
    /**
     * Select集合
     */
    private TreeMap<Character, HashMap<String, TreeSet<Character>>> selectMap;
    /**
     * LL(1)文法產生集合
     */
    private ArrayList<String> gsArray;
    /**
     * 表示式集合
     */
    private HashMap<Character, ArrayList<String>> expressionMap;
    /**
     * 開始符
     */
    private Character s;
    /**
     * Vn非終結符集合
     */
    private TreeSet<Character> nvSet;
    /**
     * Vt終結符集合
     */
    private TreeSet<Character> ntSet;
    /**
     * First集合
     */
    private HashMap<Character, TreeSet<Character>> firstMap;
    /**
     * Follow集合
     */
    private HashMap<Character, TreeSet<Character>> followMap;
 
    public String[][] getAnalyzeTable() {
        return analyzeTable;
    }
 
    public void setAnalyzeTable(String[][] analyzeTable) {
        this.analyzeTable = analyzeTable;
    }
 
    public TreeMap<Character, HashMap<String, TreeSet<Character>>> getSelectMap() {
        return selectMap;
    }
 
    public void setSelectMap(TreeMap<Character, HashMap<String, TreeSet<Character>>> selectMap) {
        this.selectMap = selectMap;
    }
 
    public HashMap<Character, TreeSet<Character>> getFirstMap() {
        return firstMap;
    }
 
    public void setFirstMap(HashMap<Character, TreeSet<Character>> firstMap) {
        this.firstMap = firstMap;
    }
 
    public HashMap<Character, TreeSet<Character>> getFollowMap() {
        return followMap;
    }
 
    public void setFollowMap(HashMap<Character, TreeSet<Character>> followMap) {
        this.followMap = followMap;
    }
 
    public HashMap<Character, ArrayList<String>> getExpressionMap() {
        return expressionMap;
    }
 
    public void setExpressionMap(HashMap<Character, ArrayList<String>> expressionMap) {
        this.expressionMap = expressionMap;
    }
 
    public ArrayList<String> getGsArray() {
        return gsArray;
    }
 
    public void setGsArray(ArrayList<String> gsArray) {
        this.gsArray = gsArray;
    }
 
    public Character getS() {
        return s;
    }
 
    public void setS(Character s) {
        this.s = s;
    }
 
    public TreeSet<Character> getNvSet() {
        return nvSet;
    }
 
    public void setNvSet(TreeSet<Character> nvSet) {
        this.nvSet = nvSet;
    }
 
    public TreeSet<Character> getNtSet() {
        return ntSet;
    }
 
    public void setNtSet(TreeSet<Character> ntSet) {
        this.ntSet = ntSet;
    }
 
    /**
     * 獲取非終結符集與終結符集
     * 
     * @param gsArray
     * @param nvSet
     * @param ntSet
     */
    public void getNvNt() {
        for (String gsItem : gsArray) {
            String[] nvNtItem = gsItem.split("->");
            String charItemStr = nvNtItem[0];
            char charItem = charItemStr.charAt(0);
            // nv在左邊
            nvSet.add(charItem);
        }
        for (String gsItem : gsArray) {
            String[] nvNtItem = gsItem.split("->");
            // nt在右邊
            String nvItemStr = nvNtItem[1];
            // 遍歷每一個字
            for (int i = 0; i < nvItemStr.length(); i++) {
                char charItem = nvItemStr.charAt(i);
                if (!nvSet.contains(charItem)) {
                    ntSet.add(charItem);
                }
            }
        }
    }
 
    /**
     * 初始化表示式集合
     */
    public void initExpressionMaps() {
        expressionMap = new HashMap<Character, ArrayList<String>>();
        for (String gsItem : gsArray) {
            String[] nvNtItem = gsItem.split("->");
            String charItemStr = nvNtItem[0];
            String charItemRightStr = nvNtItem[1];
            char charItem = charItemStr.charAt(0);
            if (!expressionMap.containsKey(charItem)) {
                ArrayList<String> expArr = new ArrayList<String>();
                expArr.add(charItemRightStr);
                expressionMap.put(charItem, expArr);
            } else {
                ArrayList<String> expArr = expressionMap.get(charItem);
                expArr.add(charItemRightStr);
                expressionMap.put(charItem, expArr);
            }
        }
    }
 
    /**
     * 獲取First集
     */
    public void getFirst() {
        // 遍歷所有Nv,求出它們的First集合
        Iterator<Character> iterator = nvSet.iterator();
        while (iterator.hasNext()) {
            Character charItem = iterator.next();
            ArrayList<String> arrayList = expressionMap.get(charItem);
            for (String itemStr : arrayList) {
                boolean shouldBreak = false;
                // Y1Y2Y3...Yk
                for (int i = 0; i < itemStr.length(); i++) {
                    char itemitemChar = itemStr.charAt(i);
                    TreeSet<Character> itemSet = firstMap.get(charItem);
                    if (null == itemSet) {
                        itemSet = new TreeSet<Character>();
                    }
                    shouldBreak = calcFirst(itemSet, charItem, itemitemChar);
                    if (shouldBreak) {
                        break;
                    }
                }
            }
        }
    }
 
    /**
     * 計算First函式
     * 
     * @param itemSet
     * @param charItem
     * @param itemitemChar
     * @return
     */
    private boolean calcFirst(TreeSet<Character> itemSet, Character charItem, char itemitemChar) {
        // get ago
        // TreeSet<Character> itemSet = new TreeSet<Character>();
        // 將它的每一位和Nt判斷下
        // 是終結符或空串,就停止,並將它加到FirstMap中
        if (itemitemChar == 'ε' || ntSet.contains(itemitemChar)) {
            itemSet.add(itemitemChar);
            firstMap.put(charItem, itemSet);
            // break;
            return true;
        } else if (nvSet.contains(itemitemChar)) {// 這一位是一個非終結符
            ArrayList<String> arrayList = expressionMap.get(itemitemChar);
            for (int i = 0; i < arrayList.size(); i++) {
                String string = arrayList.get(i);
                char tempChar = string.charAt(0);
                calcFirst(itemSet, charItem, tempChar);
            }
        }
        return true;
    }
 
    /**
     * 獲取Follow集合
     */
    public void getFollow() {
        for (Character tempKey : nvSet) {
            TreeSet<Character> tempSet = new TreeSet<Character>();
            followMap.put(tempKey, tempSet);
        }
        // 遍歷所有Nv,求出它們的First集合
        Iterator<Character> iterator = nvSet.descendingIterator();
        // nvSet.descendingIterator();
 
        while (iterator.hasNext()) {
            Character charItem = iterator.next();
            System.out.println("charItem:" + charItem);
            Set<Character> keySet = expressionMap.keySet();
            for (Character keyCharItem : keySet) {
                ArrayList<String> charItemArray = expressionMap.get(keyCharItem);
                for (String itemCharStr : charItemArray) {
                    System.out.println(keyCharItem + "->" + itemCharStr);
                    TreeSet<Character> itemSet = followMap.get(charItem);
                    calcFollow(charItem, charItem, keyCharItem, itemCharStr, itemSet);
                }
            }
        }
    }
 
    /**
     * 計算Follow集
     * 
     * @param putCharItem
     *            正在查詢item
     * @param charItem
     *            待找item
     * @param keyCharItem
     *            節點名
     * @param itemCharStr
     *            符號集
     * @param itemSet
     *            結果集合
     */
    private void calcFollow(Character putCharItem, Character charItem, Character keyCharItem, String itemCharStr,
            TreeSet<Character> itemSet) {
        ///////
        // (1)A是S(開始符),加入#
        if (charItem.equals(s)) {
            itemSet.add('#');
            System.out.println("---------------find S:" + charItem + "   ={#}+Follow(E)");
            followMap.put(putCharItem, itemSet);
            // return;
        }
        // (2)Ab,=First(b)-ε,直接新增終結符
        if (TextUtil.containsAb(ntSet, itemCharStr, charItem)) {
            Character alastChar = TextUtil.getAlastChar(itemCharStr, charItem);
            System.out.println("---------------find Ab:" + itemCharStr + "    " + charItem + "   =" + alastChar);
            itemSet.add(alastChar);
            followMap.put(putCharItem, itemSet);
            // return;
        }
        // (2).2AB,=First(B)-ε,=First(B)-ε,新增first集合
        if (TextUtil.containsAB(nvSet, itemCharStr, charItem)) {
            Character alastChar = TextUtil.getAlastChar(itemCharStr, charItem);
            System.out.println(
                    "---------------find AB:" + itemCharStr + "    " + charItem + "   =First(" + alastChar + ")");
            TreeSet<Character> treeSet = firstMap.get(alastChar);
            itemSet.addAll(treeSet);
            if (treeSet.contains('ε')) {
                itemSet.add('#');
            }
            itemSet.remove('ε');
            followMap.put(putCharItem, itemSet);
            ///////////////////////
            if (TextUtil.containsbAbIsNull(nvSet, itemCharStr, charItem, expressionMap)) {
                char tempChar = TextUtil.getAlastChar(itemCharStr, charItem);
                System.out.println("tempChar:" + tempChar + "  key" + keyCharItem);
                if (!keyCharItem.equals(charItem)) {
                    System.out.println("---------------find tempChar bA: " + "tempChar:" + tempChar + keyCharItem
                            + "   " + itemCharStr + "    " + charItem + "   =Follow(" + keyCharItem + ")");
                    Set<Character> keySet = expressionMap.keySet();
                    for (Character keyCharItems : keySet) {
                        ArrayList<String> charItemArray = expressionMap.get(keyCharItems);
                        for (String itemCharStrs : charItemArray) {
                            calcFollow(putCharItem, keyCharItem, keyCharItems, itemCharStrs, itemSet);
                        }
                    }
                }
            }
        }
        // (3)B->aA,=Follow(B),新增followB
        if (TextUtil.containsbA(nvSet, itemCharStr, charItem, expressionMap)) {
            if (!keyCharItem.equals(charItem)) {
                System.out.println("---------------find bA: " + keyCharItem + "   " + itemCharStr + "    " + charItem
                        + "   =Follow(" + keyCharItem + ")");
                Set<Character> keySet = expressionMap.keySet();
                for (Character keyCharItems : keySet) {
                    ArrayList<String> charItemArray = expressionMap.get(keyCharItems);
                    for (String itemCharStrs : charItemArray) {
                        calcFollow(putCharItem, keyCharItem, keyCharItems, itemCharStrs, itemSet);
                    }
                }
            }
        }
    }
 
    /**
     * 獲取Select集合
     */
    public void getSelect() {
        // 遍歷每一個表示式
        // HashMap<Character, HashMap<String, TreeSet<Character>>>
        Set<Character> keySet = expressionMap.keySet();
        for (Character selectKey : keySet) {
            ArrayList<String> arrayList = expressionMap.get(selectKey);
            // 每一個表示式
            HashMap<String, TreeSet<Character>> selectItemMap = new HashMap<String, TreeSet<Character>>();
            for (String selectExp : arrayList) {
                /**
                 * 存放select結果的集合
                 */
                TreeSet<Character> selectSet = new TreeSet<Character>();
                // set裡存放的資料分3種情況,由selectExp決定
                // 1.A->ε,=follow(A)
                if (TextUtil.isEmptyStart(selectExp)) {
                    selectSet = followMap.get(selectKey);
                    selectSet.remove('ε');
                    selectItemMap.put(selectExp, selectSet);
                }
                // 2.Nt開始,=Nt
                // <br>終結符開始
                if (TextUtil.isNtStart(ntSet, selectExp)) {
                    selectSet.add(selectExp.charAt(0));
                    selectSet.remove('ε');
                    selectItemMap.put(selectExp, selectSet);
                }
                // 3.Nv開始,=first(Nv)
                if (TextUtil.isNvStart(nvSet, selectExp)) {
                    selectSet = firstMap.get(selectKey);
                    selectSet.remove('ε');
                    selectItemMap.put(selectExp, selectSet);
                }
                selectMap.put(selectKey, selectItemMap);
            }
        }
    }
 
    /**
     * 生成預測分析表
     */
    public void genAnalyzeTable() throws Exception {
        Object[] ntArray = ntSet.toArray();
        Object[] nvArray = nvSet.toArray();
        // 預測分析表初始化
        analyzeTable = new String[nvArray.length + 1][ntArray.length + 1];
 
        // 輸出一個佔位符
        System.out.print("Nv/Nt" + "\t\t");
        analyzeTable[0][0] = "Nv/Nt";
        // 初始化首行
        for (int i = 0; i < ntArray.length; i++) {
            if (ntArray[i].equals('ε')) {
                ntArray[i] = '#';
            }
            System.out.print(ntArray[i] + "\t\t");
            analyzeTable[0][i + 1] = ntArray[i] + "";
        }
 
        System.out.println("");
        for (int i = 0; i < nvArray.length; i++) {
            // 首列初始化
            System.out.print(nvArray[i] + "\t\t");
            analyzeTable[i + 1][0] = nvArray[i] + "";
            for (int j = 0; j < ntArray.length; j++) {
                String findUseExp = TextUtil.findUseExp(selectMap, Character.valueOf((Character) nvArray[i]),
                        Character.valueOf((Character) ntArray[j]));
                if (null == findUseExp) {
                    System.out.print("\t\t");
                    analyzeTable[i + 1][j + 1] = "";
                } else {
                    System.out.print(nvArray[i] + "->" + findUseExp + "\t\t");
                    analyzeTable[i + 1][j + 1] = nvArray[i] + "->" + findUseExp;
                }
            }
            System.out.println();
        }
    }
}

/*主程式*/
public class LL1_modify {

    public static void main(String[] args) throws Exception {
        // TODO Auto-generated method stub
        // // LL(1)文法產生集合
                ArrayList<String> gsArray = new ArrayList<String>();
                // // Vn非終結符集合
                // TreeSet<Character> nvSet = new TreeSet<Character>();
                // // Vt終結符集合
                // TreeSet<Character> ntSet = new TreeSet<Character>();
                Gs gs = new Gs();
                initGs(gsArray);
                gs.setGsArray(gsArray);
                // getNvNt(gsArray, gs.getNvSet(), gs.getNtSet());
                gs.getNvNt();
                gs.initExpressionMaps();
                gs.getFirst();
                // 設定開始符
                gs.setS('E');
                gs.getFollow();
                gs.getSelect();
                // 建立一個分析器
                Analyzer analyzer = new Analyzer();
                analyzer.setStartChar('E');
                analyzer.setLl1Gs(gs);
                analyzer.setStr("i+i*i#");
                analyzer.analyze();
                gs.genAnalyzeTable();
                System.out.println("");
            }
         
            /**
             * 獲取非終結符集與終結符集
             * 
             * @param gsArray
             * @param nvSet
             * @param ntSet
             */
            private static void getNvNt(ArrayList<String> gsArray, TreeSet<Character> nvSet, TreeSet<Character> ntSet) {
                for (String gsItem : gsArray) {
                    String[] nvNtItem = gsItem.split("->");
                    String charItemStr = nvNtItem[0];
                    char charItem = charItemStr.charAt(0);
                    // nv在左邊
                    nvSet.add(charItem);
                }
                for (String gsItem : gsArray) {
                    String[] nvNtItem = gsItem.split("->");
                    // nt在右邊
                    String nvItemStr = nvNtItem[1];
                    // 遍歷每一個字
                    for (int i = 0; i < nvItemStr.length(); i++) {
                        char charItem = nvItemStr.charAt(i);
                        if (!nvSet.contains(charItem)) {
                            ntSet.add(charItem);
                        }
                    }
                }
         
            }
         
            /**
             * 初始化LL(1)文法
             * 
             * @param gsArray
             */
            private static void initGs(ArrayList<String> gsArray) {
                // Z相當於E',Y相當於T'
                gsArray.add("E->TZ");
                gsArray.add("Z->+TZ");
                gsArray.add("Z->ε");
                gsArray.add("Z->+TZ");
                gsArray.add("T->FY");
                gsArray.add("Z->+TZ");
                gsArray.add("Y->*FY");
                gsArray.add("Y->ε");
                gsArray.add("F->i");
                gsArray.add("F->(E)");
            }

}

測試結果如下: