1. 程式人生 > >編譯原理:FIRST set概念及其演算法的程式碼實現

編譯原理:FIRST set概念及其演算法的程式碼實現

 本篇博文是作為陳老師的編譯器課程學習筆記

課程地址:

https://study.163.com/course/courseLearn.htm?courseId=1002830012#/learn/video?lessonId=1003433001&courseId=1002830012

下面,我們先給出first set 的演算法流程,然後我們再以上面的語法推導為例子,走一步演算法。

  1. 如果A是一個終結符,那麼FIRST(A)={A}
  2. 對於以下形式的語法推導:

      s -> A a

     s是非終結符,A是終結符,a 是零個或多個終結符或非終結符的組合,那麼 A 屬於 FIRST(s).

     3.對於推導表示式:

      s -> b a

     s 和 b 是非終結符,而且b 不是nullable的,那麼first(s) = first(b)

     4.對於推導表示式:

     s -> a1 a2 … an b

     如果a1, a2 … an 是nullable 的非終結符,b是非終結符但不是nullable的,或者b是終結符,那麼first(s) 是 first(a1)… first(an) 以及first(b)的集合。

public class ParseTableBuilder {
    
    private HashMap<Integer, Symbols> symbolMap = new HashMap<Integer, Symbols>();
    private ArrayList<Symbols> symbolArray = new ArrayList<Symbols>();
    private boolean runFirstSetPass = true;
    private boolean runFollowSetPass = true;
    
    public ParseTableBuilder() {
        initProductions();
    }
    
    private void initProductions() {
        ArrayList<int[]> productions = new ArrayList<int[]>();
        productions.add(new int[]{SymbolDefine.EXPR, SymbolDefine.SEMI});
        Symbols stmt = new Symbols(SymbolDefine.STMT, false, productions);
        symbolMap.put(SymbolDefine.STMT, stmt);
        symbolArray.add(stmt);
        
        
        productions = new ArrayList<int[]>();
        productions.add(new int[] {SymbolDefine.TERM, SymbolDefine.EXPR_PRIME});
        Symbols expr = new Symbols(SymbolDefine.EXPR, true, productions);
        symbolMap.put(SymbolDefine.EXPR, expr);
        symbolArray.add(expr);
        
        productions = new ArrayList<int[]>();
        productions.add(new int[] {SymbolDefine.PLUS, SymbolDefine.TERM, SymbolDefine.EXPR_PRIME});
        Symbols expr_prime = new Symbols(SymbolDefine.EXPR_PRIME, true, productions);
        symbolMap.put(SymbolDefine.EXPR_PRIME, expr_prime);
        symbolArray.add(expr_prime);
        
        productions = new ArrayList<int[]>();
        productions.add(new int[]{SymbolDefine.FACTOR, SymbolDefine.TERM_PRIME});
        Symbols term = new Symbols(SymbolDefine.TERM, false, productions);
        symbolMap.put(SymbolDefine.TERM, term);
        symbolArray.add(term);
        
        productions = new ArrayList<int[]>();
        productions.add(new int[] {SymbolDefine.TIMES, SymbolDefine.FACTOR, SymbolDefine.TERM_PRIME});
        Symbols term_prime = new Symbols(SymbolDefine.TERM_PRIME, true, productions);
        symbolMap.put(SymbolDefine.TERM_PRIME, term_prime);
        symbolArray.add(term_prime);
        
        productions = new ArrayList<int[]>();
        productions.add(new int[] {SymbolDefine.LP, SymbolDefine.EXPR, SymbolDefine.RP});
        productions.add(new int[] {SymbolDefine.NUM_OR_ID});
        Symbols factor = new Symbols(SymbolDefine.FACTOR, false, productions);
        symbolMap.put(SymbolDefine.FACTOR, factor);
        symbolArray.add(factor);
        
        Symbols semi = new Symbols(SymbolDefine.SEMI, false, null);
        symbolMap.put(SymbolDefine.SEMI, semi);
        symbolArray.add(semi);
        
        Symbols plus = new Symbols(SymbolDefine.PLUS, false, null);
        symbolMap.put(SymbolDefine.PLUS, plus);
        symbolArray.add(plus);
        
        Symbols times = new Symbols(SymbolDefine.TIMES, false, null);
        symbolMap.put(SymbolDefine.TIMES, times);
        symbolArray.add(times);
        
        Symbols lp = new Symbols(SymbolDefine.LP, false, null);
        symbolMap.put(SymbolDefine.LP, lp);
        symbolArray.add(lp);
        
        Symbols rp = new Symbols(SymbolDefine.RP, false, null);
        symbolMap.put(SymbolDefine.RP, rp);
        symbolArray.add(rp);
        
        Symbols num_or_id = new Symbols(SymbolDefine.NUM_OR_ID, false, null);
        symbolMap.put(SymbolDefine.NUM_OR_ID, num_or_id);
        symbolArray.add(num_or_id);
    }
    
    public void runFirstSets() {
        while (runFirstSetPass) {
            runFirstSetPass = false;
            
            Iterator<Symbols> it = symbolArray.iterator();
            while (it.hasNext()) {
                Symbols symbol = it.next();
                addSymbolFirstSet(symbol);
            }
            
            printAllFirstSet();
            System.out.println("============");
        }
    }
    
    private void addSymbolFirstSet(Symbols symbol) {
        if (isSymbolTerminals(symbol.value) == true) {
            return;
        }
        
        for (int i = 0;  i < symbol.productions.size(); i++) {
            int[] rightSize = symbol.productions.get(i);
            if (isSymbolTerminals(rightSize[0]) && symbol.firstSet.contains(rightSize[0]) == false) {
                runFirstSetPass = true;
                symbol.firstSet.add(rightSize[0]);
            }
            else if (isSymbolTerminals(rightSize[0]) == false) {
                //add first set of nullable
                int pos = 0;
                Symbols curSymbol = null;
                do {
                    curSymbol = symbolMap.get(rightSize[pos]);
                    if (symbol.firstSet.containsAll(curSymbol.firstSet) == false) {
                        runFirstSetPass = true;
                        
                        for (int j = 0; j < curSymbol.firstSet.size(); j++) {
                            if (symbol.firstSet.contains(curSymbol.firstSet.get(j)) == false) {
                                symbol.firstSet.add(curSymbol.firstSet.get(j));
                            }
                        }//for (int j = 0; j < curSymbol.firstSet.size(); j++)
                        
                    }//if (symbol.firstSet.containsAll(curSymbol.firstSet) == false)
                    
                    pos++;
                }while(pos < rightSize.length && curSymbol.isNullable);
            } // else
            
        }//for (int i = 0; i < symbol.productions.size(); i++)
    }
    
    private boolean isSymbolTerminals(int symbol) {
        return symbol < 256;
    }
}