📄 sathercodegenerator.java
字号:
}
// AST
genElementAST(r);
// match
println("match_range( " + r.beginText + ", " + r.endText + " );");
genErrorCatchForElement(r);
}
/** Generate code for the given grammar element.
* @param blk The token-reference to generate
*/
public void gen(TokenRefElement atom) {
if ( DEBUG_CODE_GENERATOR ) System.out.println("genTokenRef("+atom+")");
if ( grammar instanceof LexerGrammar ) {
tool.panic("Token reference found in lexer");
}
genErrorTryForElement(atom);
// Assign Token value to token label variable
if ( atom.getLabel()!=null && syntacticPredLevel == 0) {
println(atom.getLabel() + " := " + lt1Value + ";");
}
// AST
genElementAST(atom);
// matching
genMatch(atom);
genErrorCatchForElement(atom);
// tack on tree cursor motion if doing a tree walker
if (grammar instanceof TreeWalkerGrammar) {
println("sa_t := sa_t.next_sibling;");
}
}
public void gen(TreeElement t) {
// save AST cursor
println("sa__t" + t.ID + " : " + labeledElementASTType + " := sa_t;");
// If there is a label on the root, then assign that to the variable
if (t.root.getLabel() != null) {
println("if ( SYS::is_eq( sa_t , AST::ASTNULL ) ) then");
tabs++;
println(t.root.getLabel() + " := void;");
println("else");
println(t.root.getLabel() + " := sa_t;");
println("end; -- if");
}
// Generate AST variables
genElementAST(t.root);
if (grammar.buildAST) {
// Save the AST construction state
println("sa__current_ast" + t.ID + " : ANTLR_AST_PAIR{AST} := current_ast.copy;");
// Make the next item added a child of the TreeElement root
println("current_ast.root := current_ast.child;");
println("current_ast.child := void;");
}
// match root
genMatch(t.root);
// move to list of children
println("sa_t := sa_t.first_child;");
// walk list of children, generating code for each
for (int i=0; i<t.getAlternatives().size(); i++) {
Alternative a = t.getAlternativeAt(i);
AlternativeElement e = a.head;
while ( e != null ) {
e.generate();
e = e.next;
}
}
if (grammar.buildAST) {
// restore the AST construction state to that just after the
// tree root was added
println("current_ast := sa__current_ast" + t.ID + ";");
}
// restore AST cursor
println("sa_t := sa__t" + t.ID + ";");
// move cursor to sibling of tree just parsed
println("sa_t := sa_t.next_sibling;");
}
/** Generate the tree-parser Java file */
public void gen(TreeWalkerGrammar g) throws IOException {
// SAS: debugging stuff removed for now...
setGrammar(g);
if (!(grammar instanceof TreeWalkerGrammar)) {
tool.panic("Internal error generating tree-walker");
}
// Open the output stream for the parser and set the currentOutput
// SAS: move file open to method so subclass can override it
// (mainly 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 premamble
println(grammar.preambleAction.getText());
// Generate parser class definition
String sup=null;
if ( grammar.superClass!=null ) {
sup = grammar.superClass.toUpperCase();
}
else {
sup = "ANTLR_TREE_PARSER";
}
// print javadoc comment if any
if ( grammar.comment!=null ) {
_println(grammar.comment);
}
println("class " + grammar.getClassName() + "{AST < $ANTLR_AST{AST} } is" );
println("");
tabs++;
println("include " + sup + "{" + labeledElementASTType + "} create -> tree_parser_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
}
}
*/
// Generate user-defined parser class members
print(
processActionForTreeSpecifiers(grammar.classMemberAction.getText(), 0, currentRule, null)
);
println("attr token_names : ARRAY{STR};");
println("");
// Generate default parser class constructor
println("create : SAME is" );
tabs++;
println("res : SAME := tree_parser_create;");
println("res.token_names := sa_token_names;");
println("return res;");
tabs--;
println("end; -- create");
println("");
// Generate code for each rule in the grammar
Enumeration ids = grammar.rules.elements();
int ruleNum=0;
String ruleNameInits = "";
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());
// Close class definition
tabs--;
println("end; -- class");
println("");
// Close the parser output stream
currentOutput.close();
currentOutput = null;
}
/** Generate code for the given grammar element.
* @param wc The wildcard element to generate
*/
public void gen(WildcardElement wc) {
// Variable assignment for labeled elements
if (wc.getLabel()!=null && syntacticPredLevel == 0) {
println(wc.getLabel() + " := " + lt1Value + ";");
}
// AST
genElementAST(wc);
// Match anything but EOF
if (grammar instanceof TreeWalkerGrammar) {
println("if ( void(sa_t) ) then");
tabs++;
println("raise #ANTLR_MISMATCHED_TOKEN_EXCEPTION;");
tabs--;
println("end;");
}
else if (grammar instanceof LexerGrammar) {
if ( grammar instanceof LexerGrammar &&
(!saveText||wc.getAutoGenType()==GrammarElement.AUTO_GEN_BANG) ) {
println("sa_save_index := text.length;");
}
println("match_not(EOF_CHAR);");
if ( grammar instanceof LexerGrammar &&
(!saveText||wc.getAutoGenType()==GrammarElement.AUTO_GEN_BANG) ) {
// kill text atom put in buffer
println("text := text.substring( 0 , sa_save_index);");
}
}
else {
println("match_not(" + getValueString(Token.EOF_TYPE) + ");");
}
// 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 (...)* block to generate
*/
public void gen(ZeroOrMoreBlock blk) {
if ( DEBUG_CODE_GENERATOR ) System.out.println("gen*("+blk+")");
// println("{");
genBlockPreamble(blk);
String label;
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;
}
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 ( " + predictExit + " ) then break! end; -- if");
}
JavaBlockFinishingInfo howToFinish = genCommonBlock(blk, false);
genBlockFinish(howToFinish, "break!;" );
tabs--;
println("end; -- loop ");
// Restore previous AST generation
currentASTResult = saveCurrentASTResult;
}
/** Generate an alternative.
* @param alt The alternative to generate
* @param blk The block to which the alternative belongs
*/
protected void genAlt(Alternative alt, AlternativeBlock blk) {
// Save the AST generation state, and set it to that of the alt
boolean savegenAST = genAST;
genAST = genAST && alt.getAutoGen();
boolean oldsaveTest = saveText;
saveText = saveText && alt.getAutoGen();
// Reset the variable name map for the alternative
Hashtable saveMap = treeVariableMap;
treeVariableMap = new Hashtable();
// Generate try block around the alt for error handling
if (alt.exceptionSpec != null) {
println("protect -- for error handling");
tabs++;
}
AlternativeElement elem = alt.head;
while ( !(elem instanceof BlockEndElement) ) {
elem.generate(); // alt can begin with anything. Ask target to gen.
elem = elem.next;
}
if ( genAST) {
if (blk instanceof RuleBlock) {
// Set the AST return value for the rule
RuleBlock rblk = (RuleBlock)blk;
println(rblk.getRuleName() + "_ast := current_ast.root;");
}
else if (blk.getLabel() != null) {
// ### future: also set AST value for labeled subrules.
// println(blk.getLabel() + "_ast = ("+labeledElementASTType+")currentAST.root;");
}
}
if (alt.exceptionSpec != null) {
// close try block
tabs--;
genErrorHandler(alt.exceptionSpec);
}
genAST = savegenAST;
saveText = oldsaveTest;
treeVariableMap = saveMap;
}
/** Generate all the bitsets to be used in the parser or lexer
* Generate the raw bitset data like "long _tokenSet1_data[] = {...};"
* and the BitSet object declarations like "BitSet _tokenSet1 = new BitSet(_tokenSet1_data);"
* Note that most languages do not support object initialization inside a
* class definition, so other code-generators may have to separate the
* bitset declarations from the initializations (e.g., put the initializations
* in the generated constructor instead).
* @param bitsetList The list of bitsets to generate.
* @param maxVocabulary Ensure that each generated bitset can contain at least this value.
*/
protected void genBitsets(
Vector bitsetList,
int maxVocabulary
) {
SatherCharFormatter satherCharFormatter = new SatherCharFormatter();
println("");
// here, I differ from the Java code generator. Lexer's bitsets are implemented as
// Sather sets of CHAR's, Parser bitesets as Sather sets INT's
if ( grammar instanceof LexerGrammar ) {
for ( int i = 0 ; i < bitsetList.size() ; i++) {
BitSet p = (BitSet)bitsetList.elementAt(i);
// Ensure that generated BitSet is large enough for vocabulary
p.growToInclude(maxVocabulary);
String boolList = satherCharFormatter.BitSet2BoolList( p, ", " );
String bitsetName = "sa" + getBitsetName(i);
String bitsetData = bitsetName + "_data_";
// initialization data
println(
"const " + bitsetData +
" : ARRAY{BOOL} := " +
"| " +
boolList +
" |;"
);
println( "const " + bitsetName + " : CHAR_SET := bitset( " +
bitsetData + " );" );
}
}
else {
for ( int i = 0 ; i < bitsetList.size() ; i++) {
BitSet p = (BitSet)bitsetList.elementAt(i);
// Ensure that generated BitSet is large enough for vocabulary
p.growToInclude(maxVocabulary);
String charList = satherCharFormatter.BitSet2IntList( p, ", " );
String bitsetName = "sa" + getBitsetName(i);
String bitsetData = bitsetName + "_data_";
// initialization data
println(
"const " + bitsetData +
" : ARRAY{INT} := " +
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -