rebuilt the code generator so that I generate a separate class for each labeled alternative and modify the listener so that it's always enter and exit rule; the type of the argument that distinguishes between them. I now create the overall rule context and then copy it into the alternative context if they have a label.

[git-p4: depot-paths = "//depot/code/antlr4/main/": change = 9064]
This commit is contained in:
parrt 2011-09-11 15:09:55 -08:00
parent bf19465437
commit 64ccba4168
12 changed files with 171 additions and 99 deletions

View File

@ -677,24 +677,32 @@ public abstract class BaseRecognizer extends Recognizer<ParserATNSimulator> {
if ( traceATNStates ) _ctx.trace(atnState);
}
public void enterRule(int ruleIndex) { }
/** Always called by generated parsers upon entry to a rule.
* This occurs after the new context has been pushed. Access field
* _ctx get the current context.
*
* This is flexible because users do not have to regenerate parsers
* to get trace facilities.
*
* These methods along with an override of match() are used to build
* parse trees as well.
*/
public void enterRule(int ruleIndex) {
public void enterRule(ParserRuleContext localctx, int ruleIndex) {
_ctx = localctx;
_ctx.start = _input.LT(1);
_ctx.ruleIndex = ruleIndex;
}
public void enterOuterAlt(ParserRuleContext localctx, int altNum) {
_ctx = localctx;
_ctx.altNum = altNum;
if ( buildParseTrees ) {
if ( _ctx.parent!=null ) _ctx.parent.addChild(_ctx);
}
}
public void exitRule(int ruleIndex) { }
public void exitRule(int ruleIndex) {
_ctx = (ParserRuleContext)_ctx.parent;
}
/* In v3, programmers altered error messages by overriding
displayRecognitionError() and possibly getTokenErrorDisplay().

View File

@ -59,7 +59,22 @@ public class ParserRuleContext extends RuleContext {
/** Set during parsing to identify which alt of rule parser is in. */
public int altNum;
public ParserRuleContext() { super(); }
public ParserRuleContext() { }
/** COPY a ctx
*/
public void copyFrom(ParserRuleContext ctx) {
// from RuleContext
this.parent = ctx.parent;
this.s = ctx.s;
this.invokingState = ctx.invokingState;
this.start = ctx.start;
this.stop = ctx.stop;
this.tree = ctx.tree;
this.st = ctx.st;
this.ruleIndex = ctx.ruleIndex;
}
public ParserRuleContext(RuleContext parent, int stateNumber) {
super(parent, stateNumber);

View File

@ -28,15 +28,11 @@
*/
package org.antlr.v4.runtime;
import org.antlr.v4.runtime.atn.ATN;
import org.antlr.v4.runtime.atn.ATNState;
import org.antlr.v4.runtime.atn.*;
import org.antlr.v4.runtime.misc.Interval;
import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.tree.ParseTreeListener;
import org.antlr.v4.runtime.tree.Trees;
import org.antlr.v4.runtime.tree.*;
import java.util.ArrayList;
import java.util.List;
import java.util.*;
/** Rules can return start/stop info as well as possible trees and templates.
* Each context knows about invoking context and pointer into ATN so we
@ -103,6 +99,10 @@ public class RuleContext implements ParseTree.RuleNode {
public RuleContext() {}
public RuleContext(RuleContext parent) {
this(parent, -1);
}
public RuleContext(RuleContext parent, int stateNumber) {
// capture state that called us as we create this context; use later for
// return state in closure

View File

@ -41,9 +41,9 @@ import org.antlr.v4.runtime.tree.ParseTreeListener;
@SuppressWarnings({"all", "warnings", "unchecked", "unused"})
public interface <listener.grammarName>Listener extends ParseTreeListener {
<listener.listenerNames,listener.ruleNames:{lname,rname |
void enter<lname>(<listener.parserName>.<rname>Context ctx);
void exit<lname>(<listener.parserName>.<rname>Context ctx);}; separator="\n">
<listener.listenerNames:{lname |
void enterRule(<listener.parserName>.<lname>Context ctx);
void exitRule(<listener.parserName>.<lname>Context ctx);}; separator="\n">
}
>>
@ -55,9 +55,9 @@ import org.antlr.v4.runtime.Token;
@SuppressWarnings({"all", "warnings", "unchecked", "unused"})
public class Blank<listener.grammarName>Listener implements <listener.grammarName>Listener {
<listener.listenerNames,listener.ruleNames:{lname,rname |
public void enter<lname>(<listener.parserName>.<rname>Context ctx) { \}
public void exit<lname>(<listener.parserName>.<rname>Context ctx) { \}}; separator="\n">
<listener.listenerNames:{lname |
public void enterRule(<listener.parserName>.<lname>Context ctx) { \}
public void exitRule(<listener.parserName>.<lname>Context ctx) { \}}; separator="\n">
public void enterEveryRule(ParserRuleContext ctx) { }
public void exitEveryRule(ParserRuleContext ctx) { }
@ -154,16 +154,17 @@ case <index> : return <actions.(index)>;}; separator="\n">
}
>>
RuleFunction(currentRule,code,locals,ruleCtx,namedActions,finallyAction,postamble) ::= <<
RuleFunction(currentRule,code,locals,ruleCtx,altLabelCtxs,namedActions,finallyAction,postamble) ::= <<
<ruleCtx>
<altLabelCtxs; separator="\n">
public QStack\<<currentRule.ctxType>\> <currentRule.name>_stk = new QStack\<<currentRule.ctxType>\>();
<if(currentRule.modifiers)><currentRule.modifiers:{f | <f> }><else>public final <endif><currentRule.ctxType> <currentRule.name>(<currentRule.args; separator=",">) throws RecognitionException {
<currentRule.ctxType> _localctx = new <currentRule.ctxType>(_ctx, <currentRule.startState><currentRule.args:{a | , <a.name>}>);
<currentRule.name>_stk.push(_localctx);
_ctx = _localctx;
enterRule(<currentRule.index>);
_localctx.start = _input.LT(1);
enterRule(_localctx, <currentRule.index>);
//System.out.println("enter "+ruleNames[<currentRule.index>]+", LT(1)="+_input.LT(1).getText());
<namedActions.init>
<locals; separator="\n">
@ -179,7 +180,6 @@ public QStack\<<currentRule.ctxType>\> <currentRule.name>_stk = new QStack\<<cur
}
finally {
<currentRule.name>_stk.pop();
_ctx = (ParserRuleContext)_ctx.parent;
<finallyAction>
exitRule(<currentRule.index>);
// System.out.println("exit "+ruleNames[<currentRule.index>]);
@ -189,7 +189,8 @@ public QStack\<<currentRule.ctxType>\> <currentRule.name>_stk = new QStack\<<cur
>>
CodeBlockForOuterMostAlt(c, locals, preamble, ops) ::= <<
_ctx.altNum = <c.altNum>;
<if(c.altLabel)>_localctx = new <c.altLabel>Context(_localctx);<endif>
enterOuterAlt(_localctx, <c.alt.altNum>);
<CodeBlockForAlt(...)>
>>
@ -455,16 +456,31 @@ public static class <s.name> extends ParserRuleContext {
super(parent, state);
<s.ctorAttrs:{a | this.<a.name> = <a.name>;}; separator="\n">
}
<if(!visitorDispatchMethods)> <! don't need copy if no subclasses !>
public <s.name>() { }
public void copyFrom(<s.name> ctx) {
super.copyFrom(ctx);
<s.attrs:{a | this.<a.name> = ctx.<a.name>;}; separator="\n">
}
<endif>
<visitorDispatchMethods; separator="\n">
}
>>
AltLabelStructDecl(s,attrs,visitorDispatchMethods) ::= <<
public static class <s.label>Context extends <currentRule.name>Context {
public <s.label>Context(<currentRule.name>Context ctx) { copyFrom(ctx); }
<visitorDispatchMethods; separator="\n">
}
>>
VisitorDispatchMethod(method) ::= <<
public void <if(method.isEnter)>enter<else>exit<endif>Rule(ParseTreeListener listener) {
((<parser.grammarName>Listener)listener).<if(method.isEnter)>enter<else>exit<endif><method.listenerName>(this);
((<parser.grammarName>Listener)listener).<if(method.isEnter)>enter<else>exit<endif>Rule(this);
}
>>
/*
SwitchedVisitorDispatchMethod(method) ::= <<
public void <if(method.isEnter)>enter<else>exit<endif>Rule(ParseTreeListener listener) {
switch ( altNum ) {
@ -473,6 +489,7 @@ case <i> : ((<parser.grammarName>Listener)listener).<if(method.isEnter)>enter<el
}
}
>>
*/
AttributeDecl(d) ::= "<d.decl>"

View File

@ -33,13 +33,10 @@ import org.antlr.runtime.tree.CommonTreeNodeStream;
import org.antlr.v4.codegen.model.*;
import org.antlr.v4.codegen.model.ast.*;
import org.antlr.v4.codegen.model.decl.CodeBlock;
import org.antlr.v4.parse.ANTLRParser;
import org.antlr.v4.parse.GrammarASTAdaptor;
import org.antlr.v4.parse.*;
import org.antlr.v4.tool.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
import java.util.*;
/** This receives events from SourceGenTriggers.g and asks factory to do work.
* Then runs extensions in order on resulting SrcOps to get final list.
@ -157,7 +154,6 @@ public class OutputModelController {
}
function.ctxType = gen.target.getRuleFunctionContextStructName(function);
function.ruleCtx.name = function.ctxType;
function.postamble = rulePostamble(function, r);

View File

@ -34,9 +34,7 @@ import org.antlr.v4.codegen.model.*;
import org.antlr.v4.codegen.model.ast.*;
import org.antlr.v4.codegen.model.decl.*;
import org.antlr.v4.parse.ANTLRParser;
import org.antlr.v4.runtime.atn.DecisionState;
import org.antlr.v4.runtime.atn.PlusBlockStartState;
import org.antlr.v4.runtime.atn.StarLoopEntryState;
import org.antlr.v4.runtime.atn.*;
import org.antlr.v4.runtime.misc.IntervalSet;
import org.antlr.v4.semantics.UseDefAnalyzer;
import org.antlr.v4.tool.*;
@ -62,7 +60,7 @@ public class ParserFactory extends DefaultOutputModelFactory {
public CodeBlockForAlt epsilon() { return new CodeBlockForAlt(this); }
public CodeBlockForAlt alternative(Alternative alt, boolean outerMost) {
if ( outerMost ) return new CodeBlockForOuterMostAlt(this, alt.altNum);
if ( outerMost ) return new CodeBlockForOuterMostAlt(this, alt);
return new CodeBlockForAlt(this);
}

View File

@ -1,16 +1,19 @@
package org.antlr.v4.codegen.model;
import org.antlr.v4.codegen.OutputModelFactory;
import org.antlr.v4.tool.Alternative;
/** The code associated with an outermost alternative overrule.
* Sometimes we might want to treat them differently in the
* code generation.
*/
public class CodeBlockForOuterMostAlt extends CodeBlockForAlt {
public int altNum;
public String altLabel;
public Alternative alt;
public CodeBlockForOuterMostAlt(OutputModelFactory factory, int altNum) {
public CodeBlockForOuterMostAlt(OutputModelFactory factory, Alternative alt) {
super(factory);
this.altNum = altNum;
this.alt = alt;
altLabel = alt.ast.altLabel!=null ? alt.ast.altLabel.getText() : null;
}
}

View File

@ -1,13 +1,9 @@
package org.antlr.v4.codegen.model;
import org.antlr.v4.codegen.OutputModelFactory;
import org.antlr.v4.misc.CharSupport;
import org.antlr.v4.tool.ActionAST;
import org.antlr.v4.tool.Grammar;
import org.antlr.v4.tool.Rule;
import org.antlr.v4.tool.*;
import java.util.ArrayList;
import java.util.List;
import java.util.*;
/** A model object representing a parse tree listener file.
* These are the rules specific events triggered by a parse tree visitor.
@ -17,7 +13,7 @@ public class ListenerFile extends OutputModelObject {
public String grammarName;
public String parserName;
public List<String> listenerNames = new ArrayList<String>();
public List<String> ruleNames = new ArrayList<String>();
// public List<String> ruleNames = new ArrayList<String>();
@ModelElement public Action header;
@ -30,12 +26,11 @@ public class ListenerFile extends OutputModelObject {
for (Rule r : g.rules.values()) {
List<String> labels = r.getAltLabels();
if ( labels==null ) {
listenerNames.add("Rule"); ruleNames.add(r.name);
listenerNames.add(r.name);
}
else { // alt(s) with label(s)
for (String label : labels) {
String labelCapitalized = CharSupport.capitalize(label);
listenerNames.add(labelCapitalized); ruleNames.add(r.name);
listenerNames.add(label);
}
}
}

View File

@ -30,14 +30,11 @@
package org.antlr.v4.codegen.model;
import org.antlr.v4.codegen.OutputModelFactory;
import org.antlr.v4.codegen.model.decl.Decl;
import org.antlr.v4.codegen.model.decl.StructDecl;
import org.antlr.v4.codegen.model.decl.*;
import org.antlr.v4.misc.Utils;
import org.antlr.v4.runtime.atn.ATNState;
import org.antlr.v4.runtime.misc.OrderedHashSet;
import org.antlr.v4.tool.Attribute;
import org.antlr.v4.tool.GrammarAST;
import org.antlr.v4.tool.Rule;
import org.antlr.v4.tool.*;
import java.util.*;
@ -57,7 +54,8 @@ public class RuleFunction extends OutputModelObject {
@ModelElement public List<SrcOp> code;
@ModelElement public OrderedHashSet<Decl> locals; // TODO: move into ctx?
@ModelElement public StructDecl ruleCtx; //@ModelElement public DynamicScopeStruct scope;
@ModelElement public StructDecl ruleCtx;
@ModelElement public List<AltLabelStructDecl> altLabelCtxs;
@ModelElement public Map<String, Action> namedActions;
@ModelElement public Action finallyAction;
@ModelElement public List<SrcOp> postamble;
@ -74,9 +72,16 @@ public class RuleFunction extends OutputModelObject {
index = r.index;
// might need struct; build but drop later if no elements
ruleCtx = new StructDecl(factory, r);
List<String> labels = r.getAltLabels();
if ( labels!=null ) {
altLabelCtxs = new ArrayList<AltLabelStructDecl>();
for (String label : labels) {
altLabelCtxs.add(new AltLabelStructDecl(factory, r, label));
}
}
if ( r.args!=null ) {
ruleCtx.addDecls(r.args.attributes.values());
args = r.args.attributes.values();

View File

@ -1,23 +0,0 @@
package org.antlr.v4.codegen.model;
import org.antlr.v4.codegen.OutputModelFactory;
import org.antlr.v4.misc.CharSupport;
import org.antlr.v4.tool.Rule;
import java.util.ArrayList;
import java.util.List;
public class SwitchedVisitorDispatchMethod extends VisitorDispatchMethod {
public List<String> listenerNames = new ArrayList<String>();
public SwitchedVisitorDispatchMethod(OutputModelFactory factory, Rule r, boolean isEnter) {
super(factory, r, isEnter);
RuleFunction rf = factory.getCurrentRuleFunction();
this.isEnter = isEnter;
List<String> labels = r.getAltLabels();
for (String label : labels) {
String labelCapitalized = CharSupport.capitalize(label);
listenerNames.add(labelCapitalized);
}
}
}

View File

@ -0,0 +1,51 @@
/*
[The "BSD license"]
Copyright (c) 2011 Terence Parr
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.antlr.v4.codegen.model.decl;
import org.antlr.v4.codegen.OutputModelFactory;
import org.antlr.v4.codegen.model.VisitorDispatchMethod;
import org.antlr.v4.tool.Rule;
import java.util.ArrayList;
public class AltLabelStructDecl extends StructDecl {
public String label;
public AltLabelStructDecl(OutputModelFactory factory, Rule r, String label) {
super(factory, r);
this.label = label;
}
@Override
public void addVisitorDispatchMethods(Rule r) {
visitorDispatchMethods = new ArrayList<VisitorDispatchMethod>();
visitorDispatchMethods.add(new VisitorDispatchMethod(factory, r, true));
visitorDispatchMethods.add(new VisitorDispatchMethod(factory, r, false));
}
}

View File

@ -30,36 +30,43 @@
package org.antlr.v4.codegen.model.decl;
import org.antlr.v4.codegen.OutputModelFactory;
import org.antlr.v4.codegen.model.ModelElement;
import org.antlr.v4.codegen.model.SwitchedVisitorDispatchMethod;
import org.antlr.v4.codegen.model.VisitorDispatchMethod;
import org.antlr.v4.codegen.model.*;
import org.antlr.v4.runtime.misc.OrderedHashSet;
import org.antlr.v4.tool.Attribute;
import org.antlr.v4.tool.Rule;
import org.antlr.v4.tool.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.*;
/** */
/** This object models the structure holding all of the parameters,
* return values, local variables, and labels associated with a rule.
*/
public class StructDecl extends Decl {
@ModelElement public OrderedHashSet<Decl> attrs = new OrderedHashSet<Decl>();
@ModelElement public Collection<Attribute> ctorAttrs;
@ModelElement public List<VisitorDispatchMethod> visitorDispatchMethods;
public StructDecl(OutputModelFactory factory, Rule r) {
super(factory, null);
super(factory, factory.getGenerator().target.getRuleFunctionContextStructName(r));
addVisitorDispatchMethods(r);
// boolean multiAlts = labels!=null && labels.size()>1;
// visitorDispatchMethods = new ArrayList<VisitorDispatchMethod>();
// VisitorDispatchMethod enter = multiAlts ?
// new SwitchedVisitorDispatchMethod(factory, r, true) :
// new VisitorDispatchMethod(factory, r, true);
// visitorDispatchMethods.add(enter);
// VisitorDispatchMethod exit = multiAlts ?
// new SwitchedVisitorDispatchMethod(factory, r, false) :
// new VisitorDispatchMethod(factory, r, false);
// visitorDispatchMethods.add(exit);
}
public void addVisitorDispatchMethods(Rule r) {
List<String> labels = r.getAltLabels();
boolean multiAlts = labels!=null && labels.size()>1;
visitorDispatchMethods = new ArrayList<VisitorDispatchMethod>();
VisitorDispatchMethod enter = multiAlts ?
new SwitchedVisitorDispatchMethod(factory, r, true) :
new VisitorDispatchMethod(factory, r, true);
visitorDispatchMethods.add(enter);
VisitorDispatchMethod exit = multiAlts ?
new SwitchedVisitorDispatchMethod(factory, r, false) :
new VisitorDispatchMethod(factory, r, false);
visitorDispatchMethods.add(exit);
if ( labels==null ) {
visitorDispatchMethods = new ArrayList<VisitorDispatchMethod>();
visitorDispatchMethods.add(new VisitorDispatchMethod(factory, r, true));
visitorDispatchMethods.add(new VisitorDispatchMethod(factory, r, false));
}
}
public void addDecl(Decl d) { attrs.add(d); }