📄 cppcodegenerator.java
字号:
// Generate a warning if there is a synPred for single alt.
if (alt.synPred != null)
{
tool.warning(
"Syntactic predicate superfluous for single alternative",
grammar.getFilename(),
blk.getAlternativeAt(0).synPred.getLine()
);
}
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 == "+labeledElementASTInit+" )");
tabs++;
println("_t = ASTNULL;");
tabs--;
}
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
// or end-of-token alts for case expressions
if ( !suitableForCaseExpression(alt) ) {
continue;
}
Lookahead p = alt.cache[1];
if (p.fset.degree() == 0 && !p.containsEpsilon()) {
tool.warning("Alternate omitted due to empty prediction set",
grammar.getFilename(),
alt.head.getLine());
}
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
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 )
{
if ( nIF==0 )
{
// generate this only for the first if the elseif's
// are covered by this one
if ( grammar instanceof TreeWalkerGrammar ) {
println("if (_t == "+labeledElementASTInit+" )");
tabs++;
println("_t = ASTNULL;");
tabs--;
}
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 = processActionForTreeSpecifiers(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_oaa.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 == "+labeledElementASTInit+" )");
tabs++;
println("_t = ASTNULL;");
tabs--;
}
println("if " + e + " {");
}
}
}
nIF++;
tabs++;
genAlt(alt, blk);
tabs--;
println("}");
}
}
String ps = "";
for (int i=1; i<=closingBracesOfIFSequence; i++) {
tabs--; // does JavaCodeGenerator need this?
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 CppBlockFinishingInfo(ps+"}",true,nIF>0); // close up switch statement
}
else {
finishingInfo.postscript = ps;
finishingInfo.generatedSwitch = false;
finishingInfo.generatedAnIf = nIF>0;
//return new CppBlockFinishingInfo(ps, false,nIF>0);
}
return finishingInfo;
}
private static boolean suitableForCaseExpression(Alternative a) {
return a.lookaheadDepth == 1 &&
a.semPred == null &&
!a.cache[1].containsEpsilon() &&
a.cache[1].fset.degree()<=caseSizeThreshold;
}
/** Generate code to link an element reference into the AST */
private void genElementAST(AlternativeElement el) {
// handle case where you're not building trees, but are in tree walker.
// Just need to get labels set up.
if ( grammar instanceof TreeWalkerGrammar && !grammar.buildAST ) {
String elementRef;
String astName;
// Generate names and declarations of the AST variable(s)
if (el.getLabel() == null) {
elementRef = lt1Value;
// Generate AST variables for unlabeled stuff
astName = "tmp" + astVarNumber + "_AST";
astVarNumber++;
// Map the generated AST variable in the alternate
mapTreeVariable(el, astName);
// Generate an "input" AST variable also
println(labeledElementASTType+" "+astName+"_in = "+elementRef+";");
}
return;
}
if (grammar.buildAST && syntacticPredLevel == 0) {
boolean doNoGuessTest = (
grammar.hasSyntacticPredicate &&
(
el.getLabel() != null ||
el.getAutoGenType() != GrammarElement.AUTO_GEN_BANG
)
);
String elementRef;
String astName;
// Generate names and declarations of the AST variable(s)
if (el.getLabel() != null) {
elementRef = el.getLabel();
astName = el.getLabel() + "_AST";
} else {
elementRef = lt1Value;
// Generate AST variables for unlabeled stuff
astName = "tmp" + astVarNumber + "_AST";
astVarNumber++;
// Generate the declaration
if ( el instanceof GrammarAtom ) {
GrammarAtom ga = (GrammarAtom)el;
if ( ga.getASTNodeType()!=null ) {
println("Ref"+ga.getASTNodeType()+" " + astName + ";");
}
else {
println(labeledElementASTType+" " + astName + " = "+labeledElementASTInit+";");
}
}
else {
println(labeledElementASTType+" " + astName + " = "+labeledElementASTInit+";");
}
// Map the generated AST variable in the alternate
mapTreeVariable(el, astName);
if (grammar instanceof TreeWalkerGrammar) {
// Generate an "input" AST variable also
println(labeledElementASTType+" " + astName + "_in = "+labeledElementASTInit+";");
}
}
// Enclose actions with !guessing
if (doNoGuessTest) {
println("if (inputState->guessing==0) {");
tabs++;
}
if (el.getLabel() != null) {
if ( el instanceof GrammarAtom ) {
println(astName + " = "+
getASTCreateString((GrammarAtom)el,elementRef) + ";");
}
else {
println(astName + " = "+
getASTCreateString(elementRef) + ";");
}
} else {
elementRef = lt1Value;
if ( el instanceof GrammarAtom ) {
println(astName + " = "+
getASTCreateString((GrammarAtom)el,elementRef) + ";");
}
else {
println(astName + " = "+
getASTCreateString(elementRef) + ";");
}
// Map the generated AST variable in the alternate
if (grammar instanceof TreeWalkerGrammar) {
// set "input" AST variable also
println(astName + "_in = " + elementRef + ";");
}
}
if (genAST) {
switch (el.getAutoGenType()) {
case GrammarElement.AUTO_GEN_NONE:
println("astFactory.addASTChild(currentAST, "+namespaceAntlr+"RefAST(" + astName + "));");
break;
case GrammarElement.AUTO_GEN_CARET:
// println("astFactory.makeASTRoot(currentAST, " + astName + ");");
println("astFactory.makeASTRoot(currentAST, "+namespaceAntlr+"RefAST(" + astName + "));");
break;
default:
break;
}
}
if (doNoGuessTest) {
tabs--;
println("}");
}
}
}
/** Close the try block and generate catch phrases
* if the element has a labeled handler in the rule
*/
private void genErrorCatchForElement(AlternativeElement el) {
if (el.getLabel() == null) return;
String r = el.enclosingRuleName;
if ( grammar instanceof LexerGrammar ) {
r = CodeGenerator.lexerRuleName(el.enclosingRuleName);
}
RuleSymbol rs = (RuleSymbol)grammar.getSymbol(r);
if (rs == null) {
tool.panic("Enclosing rule not found!");
}
ExceptionSpec ex = rs.block.findExceptionSpec(el.getLabel());
if (ex != null) {
tabs--;
println("}");
genErrorHandler(ex);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -