📄 sathercodegenerator.java
字号:
// Close the lexer output stream
currentOutput.close();
currentOutput = null;
}
/** Generate code for the given grammar element.
* @param blk The (...)+ block to generate
*/
public void gen(OneOrMoreBlock blk) {
if ( DEBUG_CODE_GENERATOR ) System.out.println("gen+("+blk+")");
String label;
String cnt;
// println("{"); // cannot nest Sather scopes within a routine
genBlockPreamble(blk);
if ( blk.getLabel() != null ) {
cnt = getNextSatherPrefix() + "_cnt_"+ blk.getLabel();
}
else {
cnt = getNextSatherPrefix() + "_cnt" + blk.ID;
}
println( cnt + " : INT := 0;");
// if ( blk.getLabel() != null ) {
// label = blk.getLabel();
// }
// else {
// label = "_loop" + blk.ID;
// }
// println(label+":");
println("loop");
tabs++;
// Tell AST generation to build subrule result
String saveCurrentASTResult = currentASTResult;
if (blk.getLabel() != null) {
currentASTResult = blk.getLabel();
}
boolean ok = grammar.theLLkAnalyzer.deterministic(blk);
// generate exit test if greedy set to false
// and an alt is ambiguous with exit branch
// or when lookahead derived purely from end-of-file
// Lookahead analysis stops when end-of-file is hit,
// returning set {epsilon}. Since {epsilon} is not
// ambig with any real tokens, no error is reported
// by deterministic() routines and we have to check
// for the case where the lookahead depth didn't get
// set to NONDETERMINISTIC (this only happens when the
// FOLLOW contains real atoms + epsilon).
boolean generateNonGreedyExitPath = false;
int nonGreedyExitDepth = grammar.maxk;
if ( !blk.greedy &&
blk.exitLookaheadDepth<=grammar.maxk &&
blk.exitCache[blk.exitLookaheadDepth].containsEpsilon() )
{
generateNonGreedyExitPath = true;
nonGreedyExitDepth = blk.exitLookaheadDepth;
}
else if ( !blk.greedy &&
blk.exitLookaheadDepth==LLkGrammarAnalyzer.NONDETERMINISTIC )
{
generateNonGreedyExitPath = true;
}
// generate exit test if greedy set to false
// and an alt is ambiguous with exit branch
if ( generateNonGreedyExitPath ) {
if ( DEBUG_CODE_GENERATOR ) {
System.out.println("nongreedy (...)+ loop; exit depth is "+
blk.exitLookaheadDepth);
}
String predictExit =
getLookaheadTestExpression(blk.exitCache,
nonGreedyExitDepth);
println("-- nongreedy exit test");
println("if ( " + cnt + " >= 1 and " + predictExit + " ) then break! end; -- if");
}
JavaBlockFinishingInfo howToFinish = genCommonBlock(blk, false);
genBlockFinish(
howToFinish,
"if ( " + cnt + " >= 1 ) then break! else " + throwNoViable + " end; -- if"
);
println( cnt + " := " + cnt + " + 1;" );
tabs--;
println("end; -- loop");
// println("}"); // cannot nest Sather scopes within a routine
// Restore previous AST generation
currentASTResult = saveCurrentASTResult;
}
/** Generate the parser Java file */
public void gen(ParserGrammar g) throws IOException {
// if debugging, set up a new vector to keep track of sempred
// strings for this grammar
if (g.debuggingOutput)
semPreds = new Vector();
setGrammar(g);
if (!(grammar instanceof ParserGrammar)) {
tool.panic("Internal error generating parser");
}
// Open the output stream for the parser and set the currentOutput
// SAS: moved file setup so subclass could do it (for VAJ interface)
setupOutput(grammar.getClassName());
genAST = grammar.buildAST;
tabs = 0;
// Generate the header common to all output files.
genHeader();
// Do not use printAction because we assume tabs==0
println(behavior.getHeaderAction(""));
// Output the user-defined parser preamble
println(grammar.preambleAction.getText());
// Generate parser class definition
String sup=null;
if ( grammar.superClass != null )
sup = grammar.superClass.toUpperCase();
else
sup = "ANTLR_" + grammar.getSuperClass().toUpperCase();
// print javadoc comment if any
if ( grammar.comment!=null ) {
_println(grammar.comment);
}
println("class " + grammar.getClassName() + "{ TOKEN < $ANTLR_TOKEN, AST < $ANTLR_AST{AST} } is");
tabs++;
println("include " + sup + "{ TOKEN, " + labeledElementASTType + " } create -> super_create;" );
println("include " + grammar.tokenManager.getName() + "_"
+ TokenTypesFileSuffix.toUpperCase() + ";" );
println("");
/*
Token tsuffix = (Token)grammar.options.get("classHeaderSuffix");
if ( tsuffix != null ) {
String suffix = Tool.stripFrontBack(tsuffix.getText(),"\"","\"");
if ( suffix != null )
print(", "+suffix); // must be an interface name for Java
}
*/
// set up an array of all the rule names so the debugger can
// keep track of them only by number -- less to store in tree...
if (grammar.debuggingOutput) {
println("const sa_rule_names : ARRAY{STR} := |");
Enumeration ids = grammar.rules.elements();
int ruleNum=0;
while ( ids.hasMoreElements() ) {
GrammarSymbol sym = (GrammarSymbol) ids.nextElement();
if ( sym instanceof RuleSymbol)
println(" \""+((RuleSymbol)sym).getId()+"\",");
}
println("|;");
}
// Generate user-defined parser class members
print(
processActionForTreeSpecifiers(grammar.classMemberAction.getText(), 0, currentRule, null)
);
// Generate parser class constructor from TokenBuffer
println("");
println( "create ( token_buf : ANTLR_TOKEN_BUFFER{TOKEN} , k : INT ) : SAME is");
tabs++;
println("res : SAME := super_create( token_buf, k );");
println("res.token_names := sa_token_names;");
// println("res.ast_factory := #ANTLR_COMMON_AST_FACTORY;");
// if debugging, set up arrays and call the user-overridable
// debugging setup method
if ( grammar.debuggingOutput ) {
println("res.rule_names := sa_rule_names;");
println("res.sem_pred_names := sa_sem_pred_names;");
println("res.setup_debugging( token_buf );");
}
println("return res;");
tabs--;
println("end; -- create");
println("");
println( "create ( token_buf : ANTLR_TOKEN_BUFFER{TOKEN} ) : SAME is");
tabs++;
println("return #SAME( token_buf, " + grammar.maxk + ");");
tabs--;
println("end; -- create");
println("");
// Generate parser class constructor from TokenStream
println( "create ( lexer : $ANTLR_TOKEN_STREAM{TOKEN} , k : INT ) : SAME is");
tabs++;
println("res : SAME := super_create( lexer, k );");
println("res.token_names := sa_token_names;");
// println("res.ast_factory := #ANTLR_COMMON_AST_FACTORY;");
// if debugging, set up arrays and call the user-overridable
// debugging setup method
if ( grammar.debuggingOutput ) {
println("res.rule_names := sa_rule_names;");
println("res.sem_pred_names := sa_sem_pred_names;");
println("res.setup_debugging( lexer );");
}
println("return res;");
tabs--;
println("end; -- create");
println("");
println( "create( lexer : $ANTLR_TOKEN_STREAM{TOKEN} ) : SAME is");
tabs++;
println("res : SAME := #SAME( lexer, " + grammar.maxk + ");");
println("return res;");
tabs--;
println("end; -- create");
println("");
println( "create ( state : ANTLR_PARSER_SHARED_INPUT_STATE{TOKEN} ) : SAME is ");
tabs++;
println("res : SAME := super_create( state," + grammar.maxk + ");");
println("res.token_names := sa_token_names;");
// println("res.ast_factory := #ANTLR_COMMON_AST_FACTORY;");
println("return res;");
tabs--;
println("end; -- create");
println("");
// Generate code for each rule in the grammar
Enumeration ids = grammar.rules.elements();
int ruleNum=0;
while ( ids.hasMoreElements() ) {
GrammarSymbol sym = (GrammarSymbol) ids.nextElement();
if ( sym instanceof RuleSymbol) {
RuleSymbol rs = (RuleSymbol)sym;
genRule(rs, rs.references.size()==0, ruleNum++);
}
exitIfError();
}
// Generate the token names
genTokenStrings();
// Generate the bitsets used throughout the grammar
genBitsets(bitsetsUsed, grammar.tokenManager.maxTokenType());
// Generate the semantic predicate map for debugging
if (grammar.debuggingOutput)
genSemPredMap();
// Close class definition
println("");
tabs--;
println("end; -- class");
// Close the parser output stream
currentOutput.close();
currentOutput = null;
}
/** Generate code for the given grammar element.
* @param blk The rule-reference to generate
*/
public void gen(RuleRefElement rr) {
if ( DEBUG_CODE_GENERATOR ) System.out.println("genRR("+rr+")");
RuleSymbol rs = (RuleSymbol)grammar.getSymbol(rr.targetRule);
if (rs == null || !rs.isDefined())
{
// Is this redundant???
tool.error("Rule '" + rr.targetRule + "' is not defined", grammar.getFilename(), rr.getLine());
return;
}
if (!(rs instanceof RuleSymbol))
{
// Is this redundant???
tool.error("'" + rr.targetRule + "' does not name a grammar rule", grammar.getFilename(), rr.getLine());
return;
}
genErrorTryForElement(rr);
// AST value for labeled rule refs in tree walker.
// This is not AST construction; it is just the input tree node value.
if ( grammar instanceof TreeWalkerGrammar &&
rr.getLabel() != null &&
syntacticPredLevel == 0 )
{
println("if ( SYS::is_eq( sa_t , " + labeledElementASTType + "::ASTNULL ) ) then");
tabs++;
println( rr.getLabel() + " := void;");
tabs--;
println("else");
println(rr.getLabel() + " := " + lt1Value + ";" );
println("end; -- if");
}
// if in lexer and ! on rule ref or alt or rule, save buffer index to kill later
if ( grammar instanceof LexerGrammar && (!saveText||rr.getAutoGenType()==GrammarElement.AUTO_GEN_BANG) ) {
println("sa_save_index := text.length;");
}
// Process return value assignment if any
printTabs();
if (rr.idAssign != null)
{
// Warn if the rule has no return type
if (rs.block.returnAction == null)
{
tool.warning("Rule '" + rr.targetRule + "' has no return type", grammar.getFilename(), rr.getLine());
}
_print(rr.idAssign + ":=");
} else {
// Warn about return value if any, but not inside syntactic predicate
if ( !(grammar instanceof LexerGrammar) && syntacticPredLevel == 0 && rs.block.returnAction != null)
{
tool.warning("Rule '" + rr.targetRule + "' returns a value", grammar.getFilename(), rr.getLine());
}
}
// Call the rule
GenRuleInvocation(rr);
// if in lexer and ! on element or alt or rule, save buffer index to kill later
if ( grammar instanceof LexerGrammar && (!saveText||rr.getAutoGenType()==GrammarElement.AUTO_GEN_BANG) ) {
println("text := text.substring( 0, sa_save_index); -- truncate");
}
// if not in a syntactic predicate
if (syntacticPredLevel == 0) {
boolean doNoGuessTest = (
grammar.hasSyntacticPredicate &&
(
grammar.buildAST && rr.getLabel() != null ||
(genAST && rr.getAutoGenType() == GrammarElement.AUTO_GEN_NONE)
)
);
if (doNoGuessTest) {
println("if ( input_state.guessing = 0 ) then");
tabs++;
}
if (grammar.buildAST && rr.getLabel() != null) {
// always gen variable for rule return on labeled rules
println( rr.getLabel() + "_ast := return_ast;");
}
if (genAST) {
switch (rr.getAutoGenType()) {
case GrammarElement.AUTO_GEN_NONE:
println("current_ast.add_child( return_ast );");
break;
case GrammarElement.AUTO_GEN_CARET:
tool.error("Internal: encountered ^ after rule reference");
break;
default:
break;
}
}
// if a lexer and labeled, Token label defined at rule level, just set it here
if ( grammar instanceof LexerGrammar && rr.getLabel() != null ) {
println(rr.getLabel()+" := sa_return_token;");
}
if (doNoGuessTest) {
tabs--;
println("end;");
}
}
genErrorCatchForElement(rr);
}
/** Generate code for the given grammar element.
* @param blk The string-literal reference to generate
*/
public void gen(StringLiteralElement atom) {
if ( DEBUG_CODE_GENERATOR ) System.out.println("genString("+atom+")");
// Variable declarations for labeled elements
if (atom.getLabel()!=null && syntacticPredLevel == 0) {
println(atom.getLabel() + " := " + lt1Value + ";");
}
// AST
genElementAST(atom);
// is there a bang on the literal?
boolean oldsaveText = saveText;
saveText = saveText && atom.getAutoGenType()==GrammarElement.AUTO_GEN_NONE;
// matching
genMatch(atom);
saveText = oldsaveText;
// tack on tree cursor motion if doing a tree walker
if (grammar instanceof TreeWalkerGrammar) {
println("sa_t := sa_t.next_sibling;");
}
}
/** Generate code for the given grammar element.
* @param blk The token-range reference to generate
*/
public void gen(TokenRangeElement r) {
genErrorTryForElement(r);
if ( r.getLabel()!=null && syntacticPredLevel == 0) {
println(r.getLabel() + " := " + lt1Value + ";");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -