📄 sathercodegenerator.java
字号:
"| " +
charList +
" |;"
);
println( "const " + bitsetName + " : INT_SET := int_set( " +
bitsetData + " );" );
}
}
}
/** Generate the finish of a block, using a combination of the info
* returned from genCommonBlock() and the action to perform when
* no alts were taken
* @param howToFinish The return of genCommonBlock()
* @param noViableAction What to generate when no alt is taken
*/
private void genBlockFinish(JavaBlockFinishingInfo howToFinish, String noViableAction)
{
if (howToFinish.needAnErrorClause &&
(howToFinish.generatedAnIf || howToFinish.generatedSwitch)) {
if ( howToFinish.generatedAnIf ) {
tabs++;
println("else");
}
else {
// println("{");
}
tabs++;
println(noViableAction);
tabs--;
if ( howToFinish.generatedAnIf ) {
println("end; -- if");
tabs--;
}
if ( howToFinish.generatedSwitch )
println("end; -- case");
}
if ( !howToFinish.needAnErrorClause && howToFinish.generatedSwitch )
println("end; -- case");
if ( howToFinish.postscript!=null ) {
println(howToFinish.postscript);
}
}
/** Generate the header for a block, which may be a RuleBlock or a
* plain AlternativeBLock. This generates any variable declarations,
* init-actions, and syntactic-predicate-testing variables.
* @blk The block for which the preamble is to be generated.
*/
protected void genBlockPreamble(AlternativeBlock blk) {
// define labels for rule blocks.
if ( blk instanceof RuleBlock ) {
RuleBlock rblk = (RuleBlock)blk;
if ( rblk.labeledElements!=null ) {
for (int i=0; i<rblk.labeledElements.size(); i++) {
AlternativeElement a = (AlternativeElement)rblk.labeledElements.elementAt(i);
//System.out.println("looking at labeled element: "+a);
// Variables for labeled rule refs and subrules are different than
// variables for grammar atoms. This test is a little tricky because
// we want to get all rule refs and ebnf, but not rule blocks or
// syntactic predicates
if (
a instanceof RuleRefElement ||
a instanceof AlternativeBlock &&
!(a instanceof RuleBlock) &&
!(a instanceof SynPredBlock)
) {
if (
!(a instanceof RuleRefElement) &&
((AlternativeBlock)a).not &&
analyzer.subruleCanBeInverted(((AlternativeBlock)a), grammar instanceof LexerGrammar)
) {
// Special case for inverted subrules that will be inlined.
// Treat these like token or char literal references
println( a.getLabel() + " : " + labeledElementType + " := " + labeledElementInit + ";");
if (grammar.buildAST) {
println( a.getLabel() + "_ast : " + labeledElementASTType+ ";" );
}
}
else {
if (grammar.buildAST) {
// Always gen AST variables for labeled elements, even if the
// element itself is marked with !
println( a.getLabel() + "_ast : " + labeledElementASTType+ ";" );
}
if ( grammar instanceof LexerGrammar ) {
println( a.getLabel() + " : $ANTLR_TOKEN; " );
}
if (grammar instanceof TreeWalkerGrammar) {
// always generate rule-ref variables for tree walker
println( a.getLabel() + " : " + labeledElementType + " := " + labeledElementInit + ";");
}
}
}
else {
// It is a token or literal reference. Generate the
// correct variable type for this grammar
println( a.getLabel() + " : " + labeledElementType + " := " + labeledElementInit + ";");
// In addition, generate *_AST variables if building ASTs
if (grammar.buildAST) {
println( a.getLabel() + "_ast : " + labeledElementASTType + ";");
}
}
}
}
}
// dump out init action
if ( blk.initAction!=null ) {
printAction(
processActionForTreeSpecifiers(blk.initAction, 0, currentRule, null)
);
}
}
/** Generate a series of case statements that implement a BitSet test.
* @param p The Bitset for which cases are to be generated
*/
protected void genCases(BitSet p) {
if ( DEBUG_CODE_GENERATOR ) System.out.println("genCases("+p+")");
int[] elems;
elems = p.toArray();
// Wrap cases four-per-line for lexer, one-per-line for parser
int wrap = (grammar instanceof LexerGrammar) ? 4 : 1;
int j=1;
boolean startOfLine = true;
for (int i = 0; i < elems.length; i++) {
if (j==1) {
print("");
} else {
_print(" ");
}
if ( i == 0 )
_print("when " + getValueString(elems[i]) );
else
_print(", " + getValueString(elems[i]) );
if (j==wrap) {
_println("");
startOfLine = true;
j=1;
}
else {
j++;
startOfLine = false;
}
}
if (!startOfLine) {
_println("");
}
}
/**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.
* @param blk The block to generate
* @param noTestForSingle If true, then it does not generate a test for a single alternative.
*/
public JavaBlockFinishingInfo genCommonBlock(
AlternativeBlock blk,
boolean noTestForSingle)
{
int nIF=0;
boolean createdLL1Switch = false;
int closingBracesOfIFSequence = 0;
JavaBlockFinishingInfo finishingInfo = new JavaBlockFinishingInfo();
if ( DEBUG_CODE_GENERATOR ) System.out.println("genCommonBlk("+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)
) {
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="sa_t,";
}
// match the bitset for the alternative
println("match( sa" + astArgs + getBitsetName(markBitsetForGen(p.fset)) + ");");
// tack on tree cursor motion if doing a tree walker
if (grammar instanceof TreeWalkerGrammar) {
println("sa_t := sa_t.next_sibling;");
}
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)
{
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 ( void(sa_t) ) then");
tabs++;
println("sa_t := AST::ASTNULL;");
tabs--;
println("end; -- if");
}
println("case ( " + 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()) {
tool.warning("Alternate omitted due to empty prediction set",
grammar.getFilename(),
alt.head.getLine());
}
else {
genCases(p.fset);
println("then");
tabs++;
genAlt(alt, blk);
// println("break;");
tabs--;
// println("}");
}
}
println("else -- 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);
}
boolean defaultBlock = true;
// Was it a big unicode range that forced
// unsuitability for a case expression?
if ( alt.cache[1].fset.degree()>caseSizeThreshold ) {
if ( nIF==0 ) {
println("if " + e + " then");
}
else {
println("elsif " + e + " then");
}
}
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 ");
defaultBlock = false; // else is for an if statement, not a case statement.
}
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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -