Logo Search packages:      
Sourcecode: antlr version File versions

JavaBlockFinishingInfo antlr::JavaCodeGenerator::genCommonBlock ( AlternativeBlock  blk,
boolean  noTestForSingle 
) [inline]

Generate common code for a block of alternatives; return a postscript that needs to be generated at the end of the block. Other routines may append else-clauses and such for error checking before the postfix is generated. If the grammar is a lexer, then generate alternatives in an order where alternatives requiring deeper lookahead are generated first, and EOF in the lookahead set reduces the depth of the lookahead.

Parameters:
blk The block to generate
noTestForSingle If true, then it does not generate a test for a single alternative.

Definition at line 1527 of file JavaCodeGenerator.java.

References addSemPred(), antlr::AlternativeBlock::alternatives, antlr::CodeGenerator::analyzer, antlr::Alternative::cache, antlr::CodeGenerator::charFormatter, antlr::Lookahead::containsEpsilon(), currentRule, antlr::CodeGenerator::DEBUG_CODE_GENERATOR, antlr::Grammar::debuggingOutput, antlr::collections::impl::BitSet::degree(), antlr::CharFormatter::escapeString(), antlr::Lookahead::fset, genAlt(), genCases(), genElementAST(), antlr::AlternativeBlock::getAlternativeAt(), antlr::AlternativeBlock::getAlternatives(), antlr::AlternativeBlock::getAutoGen(), antlr::CodeGenerator::getBitsetName(), antlr::Grammar::getFilename(), antlr::AlternativeBlock::getLabel(), antlr::CodeGenerator::grammar, antlr::Alternative::head, antlr::GrammarElement::line, antlr::Alternative::lookaheadDepth, lookaheadIsEmpty(), antlr::CodeGenerator::makeSwitchThreshold, antlr::CodeGenerator::markBitsetForGen(), antlr::Grammar::maxk, antlr::AlternativeBlock::not, antlr::CodeGenerator::println(), processActionForSpecialSymbols(), antlr::Alternative::semPred, antlr::Alternative::synPred, and antlr::CodeGenerator::tabs.

Referenced by gen(), genNextToken(), and genRule().

                                                                          {
        int nIF = 0;
        boolean createdLL1Switch = false;
        int closingBracesOfIFSequence = 0;
        JavaBlockFinishingInfo finishingInfo = new JavaBlockFinishingInfo();
        if (DEBUG_CODE_GENERATOR) System.out.println("genCommonBlock(" + blk + ")");

        // Save the AST generation state, and set it to that of the block
        boolean savegenAST = genAST;
        genAST = genAST && blk.getAutoGen();

        boolean oldsaveTest = saveText;
        saveText = saveText && blk.getAutoGen();

        // Is this block inverted?  If so, generate special-case code
        if (
            blk.not &&
            analyzer.subruleCanBeInverted(blk, grammar instanceof LexerGrammar)
        ) {
            if (DEBUG_CODE_GENERATOR) System.out.println("special case: ~(subrule)");
            Lookahead p = analyzer.look(1, blk);
            // Variable assignment for labeled elements
            if (blk.getLabel() != null && syntacticPredLevel == 0) {
                println(blk.getLabel() + " = " + lt1Value + ";");
            }

            // AST
            genElementAST(blk);

            String astArgs = "";
            if (grammar instanceof TreeWalkerGrammar) {
                astArgs = "_t,";
            }

            // match the bitset for the alternative
            println("match(" + astArgs + getBitsetName(markBitsetForGen(p.fset)) + ");");

            // tack on tree cursor motion if doing a tree walker
            if (grammar instanceof TreeWalkerGrammar) {
                println("_t = _t.getNextSibling();");
            }
            return finishingInfo;
        }

        // Special handling for single alt
        if (blk.getAlternatives().size() == 1) {
            Alternative alt = blk.getAlternativeAt(0);
            // Generate a warning if there is a synPred for single alt.
            if (alt.synPred != null) {
                antlrTool.warning(
                    "Syntactic predicate superfluous for single alternative",
                    grammar.getFilename(),
                    blk.getAlternativeAt(0).synPred.getLine(),
                    blk.getAlternativeAt(0).synPred.getColumn()
                );
            }
            if (noTestForSingle) {
                if (alt.semPred != null) {
                    // Generate validating predicate
                    genSemPred(alt.semPred, blk.line);
                }
                genAlt(alt, blk);
                return finishingInfo;
            }
        }

        // count number of simple LL(1) cases; only do switch for
        // many LL(1) cases (no preds, no end of token refs)
        // We don't care about exit paths for (...)*, (...)+
        // because we don't explicitly have a test for them
        // as an alt in the loop.
        //
        // Also, we now count how many unicode lookahead sets
        // there are--they must be moved to DEFAULT or ELSE
        // clause.
        int nLL1 = 0;
        for (int i = 0; i < blk.getAlternatives().size(); i++) {
            Alternative a = blk.getAlternativeAt(i);
            if (suitableForCaseExpression(a)) {
                nLL1++;
            }
        }

        // do LL(1) cases
        if (nLL1 >= makeSwitchThreshold) {
            // Determine the name of the item to be compared
            String testExpr = lookaheadString(1);
            createdLL1Switch = true;
            // when parsing trees, convert null to valid tree node with NULL lookahead
            if (grammar instanceof TreeWalkerGrammar) {
                println("if (_t==null) _t=ASTNULL;");
            }
            println("switch ( " + testExpr + ") {");
            for (int i = 0; i < blk.alternatives.size(); i++) {
                Alternative alt = blk.getAlternativeAt(i);
                // ignore any non-LL(1) alts, predicated alts,
                // or end-of-token alts for case expressions
                if (!suitableForCaseExpression(alt)) {
                    continue;
                }
                Lookahead p = alt.cache[1];
                if (p.fset.degree() == 0 && !p.containsEpsilon()) {
                    antlrTool.warning("Alternate omitted due to empty prediction set",
                                 grammar.getFilename(),
                                 alt.head.getLine(), alt.head.getColumn());
                }
                else {
                    genCases(p.fset);
                    println("{");
                    tabs++;
                    genAlt(alt, blk);
                    println("break;");
                    tabs--;
                    println("}");
                }
            }
            println("default:");
            tabs++;
        }

        // do non-LL(1) and nondeterministic cases This is tricky in
        // the lexer, because of cases like: STAR : '*' ; ASSIGN_STAR
        // : "*="; Since nextToken is generated without a loop, then
        // the STAR will have end-of-token as it's lookahead set for
        // LA(2).  So, we must generate the alternatives containing
        // trailing end-of-token in their lookahead sets *after* the
        // alternatives without end-of-token.  This implements the
        // usual lexer convention that longer matches come before
        // shorter ones, e.g.  "*=" matches ASSIGN_STAR not STAR
        //
        // For non-lexer grammars, this does not sort the alternates
        // by depth Note that alts whose lookahead is purely
        // end-of-token at k=1 end up as default or else clauses.
        int startDepth = (grammar instanceof LexerGrammar) ? grammar.maxk : 0;
        for (int altDepth = startDepth; altDepth >= 0; altDepth--) {
            if (DEBUG_CODE_GENERATOR) System.out.println("checking depth " + altDepth);
            for (int i = 0; i < blk.alternatives.size(); i++) {
                Alternative alt = blk.getAlternativeAt(i);
                if (DEBUG_CODE_GENERATOR) System.out.println("genAlt: " + i);
                // if we made a switch above, ignore what we already took care
                // of.  Specifically, LL(1) alts with no preds
                // that do not have end-of-token in their prediction set
                // and that are not giant unicode sets.
                if (createdLL1Switch && suitableForCaseExpression(alt)) {
                    if (DEBUG_CODE_GENERATOR) System.out.println("ignoring alt because it was in the switch");
                    continue;
                }
                String e;

                boolean unpredicted = false;

                if (grammar instanceof LexerGrammar) {
                    // Calculate the "effective depth" of the alt,
                    // which is the max depth at which
                    // cache[depth]!=end-of-token
                    int effectiveDepth = alt.lookaheadDepth;
                    if (effectiveDepth == GrammarAnalyzer.NONDETERMINISTIC) {
                        // use maximum lookahead
                        effectiveDepth = grammar.maxk;
                    }
                    while (effectiveDepth >= 1 &&
                        alt.cache[effectiveDepth].containsEpsilon()) {
                        effectiveDepth--;
                    }
                    // Ignore alts whose effective depth is other than
                    // the ones we are generating for this iteration.
                    if (effectiveDepth != altDepth) {
                        if (DEBUG_CODE_GENERATOR)
                            System.out.println("ignoring alt because effectiveDepth!=altDepth;" + effectiveDepth + "!=" + altDepth);
                        continue;
                    }
                    unpredicted = lookaheadIsEmpty(alt, effectiveDepth);
                    e = getLookaheadTestExpression(alt, effectiveDepth);
                }
                else {
                    unpredicted = lookaheadIsEmpty(alt, grammar.maxk);
                    e = getLookaheadTestExpression(alt, grammar.maxk);
                }

                // Was it a big unicode range that forced unsuitability
                // for a case expression?
                if (alt.cache[1].fset.degree() > caseSizeThreshold &&
                    suitableForCaseExpression(alt)) {
                    if (nIF == 0) {
                        println("if " + e + " {");
                    }
                    else {
                        println("else if " + e + " {");
                    }
                }
                else if (unpredicted &&
                    alt.semPred == null &&
                    alt.synPred == null) {
                    // The alt has empty prediction set and no
                    // predicate to help out.  if we have not
                    // generated a previous if, just put {...} around
                    // the end-of-token clause
                    if (nIF == 0) {
                        println("{");
                    }
                    else {
                        println("else {");
                    }
                    finishingInfo.needAnErrorClause = false;
                }
                else { // check for sem and syn preds

                    // Add any semantic predicate expression to the
                    // lookahead test
                    if (alt.semPred != null) {
                        // if debugging, wrap the evaluation of the
                        // predicate in a method translate $ and #
                        // references
                        ActionTransInfo tInfo = new ActionTransInfo();
                        String actionStr =
                            processActionForSpecialSymbols(alt.semPred,
                                                           blk.line,
                                                           currentRule,
                                                           tInfo);
                        // ignore translation info...we don't need to
                        // do anything with it.  call that will inform
                        // SemanticPredicateListeners of the result
                        if (((grammar instanceof ParserGrammar) ||
                            (grammar instanceof LexerGrammar)) &&
                            grammar.debuggingOutput) {
                            e = "(" + e + "&& fireSemanticPredicateEvaluated(antlr.debug.SemanticPredicateEvent.PREDICTING," +
                                addSemPred(charFormatter.escapeString(actionStr)) + "," + actionStr + "))";
                        }
                        else {
                            e = "(" + e + "&&(" + actionStr + "))";
                        }
                    }

                    // Generate any syntactic predicates
                    if (nIF > 0) {
                        if (alt.synPred != null) {
                            println("else {");
                            tabs++;
                            genSynPred(alt.synPred, e);
                            closingBracesOfIFSequence++;
                        }
                        else {
                            println("else if " + e + " {");
                        }
                    }
                    else {
                        if (alt.synPred != null) {
                            genSynPred(alt.synPred, e);
                        }
                        else {
                            // when parsing trees, convert null to
                            // valid tree node with NULL lookahead.
                            if (grammar instanceof TreeWalkerGrammar) {
                                println("if (_t==null) _t=ASTNULL;");
                            }
                            println("if " + e + " {");
                        }
                    }

                }

                nIF++;
                tabs++;
                genAlt(alt, blk);
                tabs--;
                println("}");
            }
        }
        String ps = "";
        for (int i = 1; i <= closingBracesOfIFSequence; i++) {
            ps += "}";
        }

        // Restore the AST generation state
        genAST = savegenAST;

        // restore save text state
        saveText = oldsaveTest;

        // Return the finishing info.
        if (createdLL1Switch) {
            tabs--;
            finishingInfo.postscript = ps + "}";
            finishingInfo.generatedSwitch = true;
            finishingInfo.generatedAnIf = nIF > 0;
            //return new JavaBlockFinishingInfo(ps+"}",true,nIF>0); // close up switch statement

        }
        else {
            finishingInfo.postscript = ps;
            finishingInfo.generatedSwitch = false;
            finishingInfo.generatedAnIf = nIF > 0;
            // return new JavaBlockFinishingInfo(ps, false,nIF>0);
        }
        return finishingInfo;
    }


Generated by  Doxygen 1.6.0   Back to index