public Parser build(Grammar grammar, boolean useHeadSet) {
        NontermTable nontermTable = new NontermTable();

        // Construct automation.
        State.StateGenerator stateGenerator = new State.StateGenerator();
        State startState = stateGenerator.generate();
        for (Grammar.Production production: grammar.getProductions()) {
            Nonterm head = nontermTable.get(production.head.name());
            State current = startState;
            int len = production.body.length;
            for (int i = 0; i < len; i ++) {
                Grammar.ISymbol symbol = production.body[i];
                if (symbol instanceof Grammar.Nonterm) {
                    Nonterm n = nontermTable.get(symbol.name());
                    if (i == 0) {
                        // For left-most nonterm situation
                        current = n.addLeftMostRule(head.id, stateGenerator);
                    } else {
                        current = current.addNontermTransition(n.id, head.id, stateGenerator);
                    }
                } else if (symbol instanceof Grammar.Term) {
                    current = current.addTermTransition(symbol.name(), head.id, stateGenerator);
                } else {
                    throw new ParseException("Unknown symbol type: " + symbol.getClass());
                }
            }

            // Set accepting state
            current.setAcceptedNonterm(head.id);
        }

        // Extend transitions' head set.
        if (useHeadSet) {
            extendTransitionHeadSet(stateGenerator, nontermTable);
        }

        // Top head
        Grammar.Nonterm topHead = grammar.getTopHead();
        int topHeadId = topHead == null ? Nonterm.ANY : nontermTable.get(topHead.name()).id;

        // Build parser.
        Nonterm[] table = new Nonterm[nontermTable.size()];
        for (Nonterm n: nontermTable.getAll()) {
            table[n.id] = n;
        }

        return new Parser(table, startState, topHeadId, useHeadSet);
    }