Logo Search packages:      
Sourcecode: antlr version File versions

void antlr::JavaCodeGenerator::genRule ( RuleSymbol  s,
boolean  startSymbol,
int  ruleNum 
) [inline]

Gen a named rule block. ASTs are generated for each element of an alternative unless the rule or the alternative have a '!' modifier.

If an alternative defeats the default tree construction, it must set <rule>_AST to the root of the returned AST.

Each alternative that does automatic tree construction, builds up root and child list pointers in an ASTPair structure.

A rule finishes by setting the returnAST variable from the ASTPair.

Parameters:
rule The name of the rule to generate
startSymbol true if the rule is a start symbol (i.e., not referenced elsewhere)

Definition at line 2378 of file JavaCodeGenerator.java.

References antlr::CodeGenerator::_print(), antlr::CodeGenerator::_println(), antlr::AlternativeBlock::alternatives, antlr::RuleBlock::argAction, antlr::Grammar::buildAST, currentASTResult, currentRule, antlr::CodeGenerator::DEBUG_CODE_GENERATOR, antlr::Grammar::debuggingOutput, declaredASTVariables, antlr::RuleBlock::endNode, antlr::CodeGenerator::extractIdOfAction(), antlr::CodeGenerator::extractTypeOfAction(), antlr::RuleBlock::findExceptionSpec(), antlr::Lookahead::fset, genAlt(), genBlockFinish(), genBlockInitAction(), genBlockPreamble(), genCommonBlock(), genErrorHandler(), antlr::AlternativeBlock::getAlternativeAt(), antlr::AlternativeBlock::getAutoGen(), antlr::CodeGenerator::getBitsetName(), antlr::GrammarElement::getColumn(), antlr::RuleBlock::getDefaultErrorHandler(), antlr::Grammar::getFilename(), antlr::GrammarElement::getLine(), antlr::RuleBlock::getTestLiterals(), antlr::CodeGenerator::grammar, antlr::Grammar::hasSyntacticPredicate, antlr::GrammarElement::line, antlr::CodeGenerator::markBitsetForGen(), antlr::CodeGenerator::print(), antlr::CodeGenerator::println(), antlr::RuleBlock::returnAction, antlr::RuleBlock::ruleName, antlr::Alternative::semPred, antlr::Alternative::synPred, antlr::CodeGenerator::tabs, antlr::Grammar::theLLkAnalyzer, antlr::RuleBlock::throwsSpec, and antlr::Grammar::traceRules.

Referenced by gen().

                                                                        {
        tabs = 1;

        if (DEBUG_CODE_GENERATOR) System.out.println("genRule(" + s.getId() + ")");
        if (!s.isDefined()) {
            antlrTool.error("undefined rule: " + s.getId());
            return;
        }

        // Generate rule return type, name, arguments
        RuleBlock rblk = s.getBlock();

        currentRule = rblk;
        currentASTResult = s.getId();

        // clear list of declared ast variables..
        declaredASTVariables.clear();

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

        // boolean oldsaveTest = saveText;
        saveText = rblk.getAutoGen();

        // print javadoc comment if any
        if (s.comment != null) {
            _println(s.comment);
        }

        // Gen method access and final qualifier
        print(s.access + " final ");

        // Gen method return type (note lexer return action set at rule creation)
        if (rblk.returnAction != null) {
            // Has specified return value
            _print(extractTypeOfAction(rblk.returnAction, rblk.getLine(), rblk.getColumn()) + " ");
        }
        else {
            // No specified return value
            _print("void ");
        }

        // Gen method name
        _print(s.getId() + "(");

        // Additional rule parameters common to all rules for this grammar
        _print(commonExtraParams);
        if (commonExtraParams.length() != 0 && rblk.argAction != null) {
            _print(",");
        }

        // Gen arguments
        if (rblk.argAction != null) {
            // Has specified arguments
            _println("");
            tabs++;
            println(rblk.argAction);
            tabs--;
            print(")");
        }
        else {
            // No specified arguments
            _print(")");
        }

        // Gen throws clause and open curly
        _print(" throws " + exceptionThrown);
        if (grammar instanceof ParserGrammar) {
            _print(", TokenStreamException");
        }
        else if (grammar instanceof LexerGrammar) {
            _print(", CharStreamException, TokenStreamException");
        }
        // Add user-defined exceptions unless lexer (for now)
        if (rblk.throwsSpec != null) {
            if (grammar instanceof LexerGrammar) {
                antlrTool.error("user-defined throws spec not allowed (yet) for lexer rule " + rblk.ruleName);
            }
            else {
                _print(", " + rblk.throwsSpec);
            }
        }

        _println(" {");
        tabs++;

        // Convert return action to variable declaration
        if (rblk.returnAction != null)
            println(rblk.returnAction + ";");

        // print out definitions needed by rules for various grammar types
        println(commonLocalVars);

        if (grammar.traceRules) {
            if (grammar instanceof TreeWalkerGrammar) {
                println("traceIn(\"" + s.getId() + "\",_t);");
            }
            else {
                println("traceIn(\"" + s.getId() + "\");");
            }
        }

        if (grammar instanceof LexerGrammar) {
            // lexer rule default return value is the rule's token name
            // This is a horrible hack to support the built-in EOF lexer rule.
            if (s.getId().equals("mEOF"))
                println("_ttype = Token.EOF_TYPE;");
            else
                println("_ttype = " + s.getId().substring(1) + ";");
            println("int _saveIndex;");         // used for element! (so we can kill text matched for element)
            /*
                   println("boolean old_saveConsumedInput=saveConsumedInput;");
                   if ( !rblk.getAutoGen() ) {        // turn off "save input" if ! on rule
                   println("saveConsumedInput=false;");
                   }
                   */
        }

        // if debugging, write code to mark entry to the rule
        if (grammar.debuggingOutput)
            if (grammar instanceof ParserGrammar)
                println("fireEnterRule(" + ruleNum + ",0);");
            else if (grammar instanceof LexerGrammar)
                println("fireEnterRule(" + ruleNum + ",_ttype);");

        // Generate trace code if desired
        if (grammar.debuggingOutput || grammar.traceRules) {
            println("try { // debugging");
            tabs++;
        }

        // Initialize AST variables
        if (grammar instanceof TreeWalkerGrammar) {
            // "Input" value for rule
            println(labeledElementASTType + " " + s.getId() + "_AST_in = (" + labeledElementASTType + ")_t;");
        }
        if (grammar.buildAST) {
            // Parser member used to pass AST returns from rule invocations
            println("returnAST = null;");
            // Tracks AST construction
            // println("ASTPair currentAST = (inputState.guessing==0) ? new ASTPair() : null;");
            println("ASTPair currentAST = new ASTPair();");
            // User-settable return value for rule.
            println(labeledElementASTType + " " + s.getId() + "_AST = null;");
        }

        genBlockPreamble(rblk);
        genBlockInitAction(rblk);
        println("");

        // Search for an unlabeled exception specification attached to the rule
        ExceptionSpec unlabeledUserSpec = rblk.findExceptionSpec("");

        // Generate try block around the entire rule for  error handling
        if (unlabeledUserSpec != null || rblk.getDefaultErrorHandler()) {
            println("try {      // for error handling");
            tabs++;
        }

        // Generate the alternatives
        if (rblk.alternatives.size() == 1) {
            // One alternative -- use simple form
            Alternative alt = rblk.getAlternativeAt(0);
            String pred = alt.semPred;
            if (pred != null)
                genSemPred(pred, currentRule.line);
            if (alt.synPred != null) {
                antlrTool.warning(
                    "Syntactic predicate ignored for single alternative",
                    grammar.getFilename(),
                    alt.synPred.getLine(),
                    alt.synPred.getColumn()
                );
            }
            genAlt(alt, rblk);
        }
        else {
            // Multiple alternatives -- generate complex form
            boolean ok = grammar.theLLkAnalyzer.deterministic(rblk);

            JavaBlockFinishingInfo howToFinish = genCommonBlock(rblk, false);
            genBlockFinish(howToFinish, throwNoViable);
        }

        // Generate catch phrase for error handling
        if (unlabeledUserSpec != null || rblk.getDefaultErrorHandler()) {
            // Close the try block
            tabs--;
            println("}");
        }

        // Generate user-defined or default catch phrases
        if (unlabeledUserSpec != null) {
            genErrorHandler(unlabeledUserSpec);
        }
        else if (rblk.getDefaultErrorHandler()) {
            // Generate default catch phrase
            println("catch (" + exceptionThrown + " ex) {");
            tabs++;
            // Generate code to handle error if not guessing
            if (grammar.hasSyntacticPredicate) {
                println("if (inputState.guessing==0) {");
                tabs++;
            }
            println("reportError(ex);");
            if (!(grammar instanceof TreeWalkerGrammar)) {
                // Generate code to consume until token in k==1 follow set
                Lookahead follow = grammar.theLLkAnalyzer.FOLLOW(1, rblk.endNode);
                String followSetName = getBitsetName(markBitsetForGen(follow.fset));
                println("consume();");
                println("consumeUntil(" + followSetName + ");");
            }
            else {
                // Just consume one token
                println("if (_t!=null) {_t = _t.getNextSibling();}");
            }
            if (grammar.hasSyntacticPredicate) {
                tabs--;
                // When guessing, rethrow exception
                println("} else {");
                println("  throw ex;");
                println("}");
            }
            // Close catch phrase
            tabs--;
            println("}");
        }

        // Squirrel away the AST "return" value
        if (grammar.buildAST) {
            println("returnAST = " + s.getId() + "_AST;");
        }

        // Set return tree value for tree walkers
        if (grammar instanceof TreeWalkerGrammar) {
            println("_retTree = _t;");
        }

        // Generate literals test for lexer rules so marked
        if (rblk.getTestLiterals()) {
            if (s.access.equals("protected")) {
                genLiteralsTestForPartialToken();
            }
            else {
                genLiteralsTest();
            }
        }

        // if doing a lexer rule, dump code to create token if necessary
        if (grammar instanceof LexerGrammar) {
            println("if ( _createToken && _token==null && _ttype!=Token.SKIP ) {");
            println("   _token = makeToken(_ttype);");
            println("   _token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));");
            println("}");
            println("_returnToken = _token;");
        }

        // Gen the return statement if there is one (lexer has hard-wired return action)
        if (rblk.returnAction != null) {
            println("return " + extractIdOfAction(rblk.returnAction, rblk.getLine(), rblk.getColumn()) + ";");
        }

        if (grammar.debuggingOutput || grammar.traceRules) {
            tabs--;
            println("} finally { // debugging");
            tabs++;

            // If debugging, generate calls to mark exit of rule
            if (grammar.debuggingOutput)
                if (grammar instanceof ParserGrammar)
                    println("fireExitRule(" + ruleNum + ",0);");
                else if (grammar instanceof LexerGrammar)
                    println("fireExitRule(" + ruleNum + ",_ttype);");

            if (grammar.traceRules) {
                if (grammar instanceof TreeWalkerGrammar) {
                    println("traceOut(\"" + s.getId() + "\",_t);");
                }
                else {
                    println("traceOut(\"" + s.getId() + "\");");
                }
            }

            tabs--;
            println("}");
        }

        tabs--;
        println("}");
        println("");

        // Restore the AST generation state
        genAST = savegenAST;

        // restore char save state
        // saveText = oldsaveTest;
    }


Generated by  Doxygen 1.6.0   Back to index