Logo Search packages:      
Sourcecode: antlr version File versions

CSharpBlockFinishingInfo antlr::CSharpCodeGenerator::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 1783 of file CSharpCodeGenerator.java.

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

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

      {
            int nIF=0;
            boolean createdLL1Switch = false;
            int closingBracesOfIFSequence = 0;
            CSharpBlockFinishingInfo finishingInfo = new CSharpBlockFinishingInfo();
            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) {
                        if ( usingCustomAST )
                              astArgs = "(AST)_t,";
                        else
                              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 (null == _t)");
                        tabs++;
                        println("_t = ASTNULL;");
                        tabs--;
                  }
                  println("switch ( " + testExpr+" )");
                  println("{");
                  //tabs++;
                  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);
                                    println("{");
                              }
                              else {
                                    println("else if " + e);
                                    println("{");
                              }
                        }
                        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,"+ //FIXME
                                                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)");
                                                tabs++;
                                                println("_t = ASTNULL;");
                                                tabs--;
                                          }
                                          println("if " + e);
                                          println("{");
                                    }
                              }

                        }

                        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+"break; }";
                  finishingInfo.generatedSwitch = true;
                  finishingInfo.generatedAnIf = nIF>0;
                  //return new CSharpBlockFinishingInfo(ps+"}",true,nIF>0); // close up switch statement

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


Generated by  Doxygen 1.6.0   Back to index