added method to get context for non-arg rules

[git-p4: depot-paths = "//depot/code/antlr4/main/": change = 8921]
This commit is contained in:
parrt 2011-07-28 19:36:56 -08:00
parent cce6c70b2e
commit dcfb804ed3
15 changed files with 125 additions and 74 deletions

View File

@ -56,9 +56,7 @@ public class ParserRuleContext extends RuleContext {
public ParserRuleContext() { super(); }
public ParserRuleContext(RuleContext parent, int stateNumber) {
// capture state that called us as we create this context; use later for
// return state in closure
super(parent, parent!=null ? parent.s : -1, stateNumber);
super(parent, stateNumber);
}
public Object getTree() { return tree; }

View File

@ -226,7 +226,17 @@ public class Recognizer<ATNInterpreter> {
public void action(RuleContext _localctx, int ruleIndex, int actionIndex) {
}
public ParserRuleContext newContext(RuleContext _localctx, int s, int ruleIndex, int actionIndex) {
/** Create context for a rule reference IN fromRuleIndex using parent _localctx.
* Used only when there are arguments to the rule function.
*/
public RuleContext newContext(RuleContext _localctx, int s, int fromRuleIndex, int actionIndex) {
return new ParserRuleContext(_localctx, s);
}
/** Map a rule index to appropriate RuleContext subclass. Used when rule
* has no arguments.
*/
public RuleContext newContext(RuleContext _localctx, int s, int targetRuleIndex) {
return new ParserRuleContext(_localctx, s);
}
}

View File

@ -69,13 +69,11 @@ public class RuleContext {
public RuleContext() {}
// public RuleContext(RuleContext parent) {
// this.parent = parent;
//// while ( p!=null ) {
//// System.out.println();
//// p = p.parent;
//// }
// }
public RuleContext(RuleContext parent, int stateNumber) {
// capture state that called us as we create this context; use later for
// return state in closure
this(parent, parent!=null ? parent.s : -1, stateNumber);
}
public RuleContext(RuleContext parent, int invokingState, int stateNumber) {
this.parent = parent;

View File

@ -108,10 +108,11 @@ public abstract class ATNSimulator {
int ttype = toInt(data[p+2]);
int arg1 = toInt(data[p+3]);
int arg2 = toInt(data[p+4]);
Transition trans = edgeFactory(atn, ttype, src, trg, arg1, arg2, sets);
int arg3 = toInt(data[p+5]);
Transition trans = edgeFactory(atn, ttype, src, trg, arg1, arg2, arg3, sets);
ATNState srcState = atn.states.get(src);
srcState.addTransition(trans);
p += 5;
p += 6;
}
int ndecisions = toInt(data[p++]);
for (int i=1; i<=ndecisions; i++) {
@ -130,24 +131,25 @@ public abstract class ATNSimulator {
public static Transition edgeFactory(ATN atn,
int type, int src, int trg,
int arg1, int arg2,
int arg1, int arg2, int arg3,
List<IntervalSet> sets)
{
ATNState target = atn.states.get(trg);
switch (type) {
case Transition.EPSILON : return new EpsilonTransition(target);
case Transition.RANGE : return new RangeTransition(arg1, arg2, target);
case Transition.RULE : return new RuleTransition(arg2, atn.states.get(arg1), target);
case Transition.PREDICATE : return new PredicateTransition(target, arg1, arg2);
case Transition.DEPENDENT_PREDICATE :
PredicateTransition p = new PredicateTransition(target, arg1, arg2);
p.isCtxDependent = true;
return p;
case Transition.RULE :
RuleTransition rt = new RuleTransition(arg2, atn.states.get(arg1), target);
rt.argIndex = arg3;
return rt;
case Transition.PREDICATE :
PredicateTransition pt = new PredicateTransition(target, arg1, arg2);
pt.isCtxDependent = arg3==1;
return pt;
case Transition.ATOM : return new AtomTransition(arg1, target);
case Transition.ACTION : return new ActionTransition(target, arg1, arg2);
case Transition.FORCED_DEPENDENT_ACTION :
case Transition.ACTION :
ActionTransition a = new ActionTransition(target, arg1, arg2);
a.isCtxDependent = true;
a.isCtxDependent = arg3==1;
return a;
case Transition.FORCED_ACTION : return new ActionTransition(target, arg1, arg2);
case Transition.SET : return new SetTransition(sets.get(arg1), target);

View File

@ -37,7 +37,7 @@ import org.stringtemplate.v4.misc.MultiMap;
import java.util.*;
public class ParserATNSimulator extends ATNSimulator {
public static boolean debug = true;
public static boolean debug = false;
public static boolean dfa_debug = false;
public static int ATN_failover = 0;
@ -492,8 +492,24 @@ public class ParserATNSimulator extends ATNSimulator {
ATNState p = config.state;
RuleContext newContext;
if ( parser != null ) {
// System.out.println("rule trans to rule "+parser.getRuleNames()[t.target.ruleIndex]);
newContext = parser.newContext(config.context, t.target.stateNumber, t.target.ruleIndex, -999);
RuleContext ctx = getCurrentExecContext(config);
int argIndex = ((RuleTransition) t).argIndex;
if ( debug ) {
System.out.println("CALL rule "+parser.getRuleNames()[t.target.ruleIndex]+
", arg="+ argIndex +
", using context="+ctx);
}
int fromRuleIndex = config.state.ruleIndex;
if ( argIndex>=0 ) {
newContext = parser.newContext(ctx, t.target.stateNumber,
fromRuleIndex,
argIndex);
}
else {
int targetRuleIndex = t.target.ruleIndex;
newContext = parser.newContext(ctx, t.target.stateNumber, targetRuleIndex);
}
newContext.invokingState = p.stateNumber;
// System.out.println("new ctx type is "+newContext.getClass().getSimpleName());
}
@ -514,11 +530,7 @@ public class ParserATNSimulator extends ATNSimulator {
// preds are epsilon if we're not doing preds (we saw an action).
// if we are doing preds, pred must eval to true
// Cannot exec preds out of context if they are context dependent
RuleContext ctx = config.context; // use context created after entry into interp
if ( ctx == RuleContext.EMPTY ) {
if ( config.reachesIntoOuterContext==0 ) ctx = originalContext;
else ctx = null; // no context if we in outer context
}
RuleContext ctx = getCurrentExecContext(config);
boolean ctxIssue = pt.isCtxDependent && config.reachesIntoOuterContext>0;
boolean seeThroughPred =
ignorePreds || ctxIssue ||
@ -534,11 +546,7 @@ public class ParserATNSimulator extends ATNSimulator {
if ( debug ) System.out.println("ACTION edge "+at.ruleIndex+":"+at.actionIndex);
if ( at.actionIndex>=0 ) {
if ( debug ) System.out.println("DO ACTION "+at.ruleIndex+":"+at.actionIndex);
RuleContext ctx = config.context;
if ( ctx == RuleContext.EMPTY ) {
if ( config.reachesIntoOuterContext==0 ) ctx = originalContext;
else ctx = null; // no context if we in outer context
}
RuleContext ctx = getCurrentExecContext(config);
boolean ctxIssue = at.isCtxDependent && config.reachesIntoOuterContext>0;
// Only exec forced action that isCtxDependent if we are not
// doing global FOLLOW; we don't know context
@ -587,6 +595,15 @@ public class ParserATNSimulator extends ATNSimulator {
return alt;
}
public RuleContext getCurrentExecContext(ATNConfig config) {
RuleContext ctx = config.context; // use context created after entry into interp
if ( ctx == RuleContext.EMPTY ) {
if ( config.reachesIntoOuterContext==0 ) ctx = originalContext;
else ctx = null; // no context if we in outer context
}
return ctx;
}
public Set<Integer> getAmbiguousAlts(OrderedHashSet<ATNConfig> configs) {
// System.err.println("check ambiguous "+configs);
Set<Integer> ambigAlts = null;

View File

@ -32,8 +32,8 @@ package org.antlr.v4.runtime.atn;
/** */
public class RuleTransition extends Transition {
/** Ptr to the rule definition object for this rule ref */
//public Rule rule;
public int ruleIndex; // no Rule object at runtime
public int ruleIndex; // no Rule object at runtime
public int argIndex = -1; // args are forced actions
/** What node to begin computations following ref to rule */
public ATNState followState;

View File

@ -50,15 +50,13 @@ public abstract class Transition {
public static final int EPSILON = 1;
public static final int RANGE = 2;
public static final int RULE = 3;
public static final int PREDICATE = 4; // e.g., {isType(input.LT(1))}?
public static final int DEPENDENT_PREDICATE = 5; // e.g., {$p>3}?
public static final int ATOM = 6;
public static final int ACTION = 7;
public static final int FORCED_ACTION = 8;
public static final int FORCED_DEPENDENT_ACTION = 9;
public static final int SET = 10; // ~(A|B) or ~atom, wildcard, which convert to next 2
public static final int NOT_SET = 11;
public static final int WILDCARD = 12;
public static final int PREDICATE = 4; // e.g., {isType(input.LT(1))}?
public static final int ATOM = 5;
public static final int ACTION = 6;
public static final int FORCED_ACTION = 7;
public static final int SET = 8; // ~(A|B) or ~atom, wildcard, which convert to next 2
public static final int NOT_SET = 9;
public static final int WILDCARD = 10;
public static String[] serializationNames = {
@ -67,11 +65,9 @@ public abstract class Transition {
"RANGE",
"RULE",
"PREDICATE",
"DEPENDENT_PREDICATE",
"ATOM",
"ACTION",
"FORCED_ACTION",
"FORCED_DEPENDENT_ACTION",
"SET",
"NOT_SET",
"WILDCARD",

View File

@ -1,13 +1,22 @@
grammar T;
options {output=AST;}
s returns [int j=9999] : e[9] {{System.out.println("after-e "+$j);}} {true}? ';' ;
s : e EOF ;
e[int i]
: {$i>=0}? {{System.out.println("i=="+$i);}} ID
| ID '!'
;
e : e_[0] ;
foo[int j] : e[8] {$j==2}? '$' ; // not called but in FOLLOW(e)
e_[int _p]
: e_primary
( {$_p <= 5}? '*'^ e_[6]{}
| {$_p <= 4}? '+'^ e_[5]{}
| {$_p <= 2}? '='<assoc=right>^ e_[2]{}
| {$_p <= 3}? '?'<assoc=right>^ e ':'! e_[3]{}
)*
;
e_primary
: ID
;
ID : 'a'..'z'+;

View File

@ -60,18 +60,29 @@ public class <parser.name> extends Parser {
public ATN getATN() { return _ATN; }
<dumpActions(parser, argFuncs, actionFuncs, sempredFuncs)>
/** Map a rule index to appropriate RuleContext subclass */
public RuleContext newContext(RuleContext _localctx, int s, int targetRuleIndex) {
switch ( targetRuleIndex ) {
<parser.funcs:{rf |
case <rf.index> : return new <rf.ctxType>(_localctx, s);}; separator="\n">
}
return null;
}
<atn>
}
>>
dumpActions(recog, argFuncs, actionFuncs, sempredFuncs) ::= <<
<if(argFuncs)>
public ParserRuleContext newContext(RuleContext _localctx, int s, int ruleIndex, int actionIndex) {
switch ( ruleIndex ) {
/** Create context for a rule reference IN fromRuleIndex using parent _localctx */
public RuleContext newContext(RuleContext _localctx, int s, int fromRuleIndex, int actionIndex) {
switch ( fromRuleIndex ) {
<recog.argFuncs.values:{f|
case <f.ruleIndex> : return <f.name>_argEval((<f.ctxType>)_localctx, s, actionIndex);}; separator="\n">
case <f.ruleIndex> : return <f.name>_argEval(_localctx, s, actionIndex);}; separator="\n">
}
return new ParserRuleContext(_localctx, s);
return new RuleContext(_localctx, s);
}
<argFuncs.values; separator="\n">
<endif>
@ -105,7 +116,7 @@ public <p.name>(TokenStream input) {
RuleArgFunction(r, actions) ::= <<
/** arg computations for rules called FROM and evaluated in context of <r.name> */
public ParserRuleContext <r.name>_argEval(ParserRuleContext _localctx, int s, int actionIndex) {
public RuleContext <r.name>_argEval(RuleContext _localctx, int s, int actionIndex) {
switch ( actionIndex ) {
<actions:{index|
case <index> : return new <r.actions.(index).ctxType>(_localctx, s, <actions.(index)>);}; separator="\n">
@ -419,7 +430,8 @@ CaptureNextTokenType(d) ::= "<d.varName> = input.LA(1);"
StructDecl(s,attrs) ::= <<
public static class <s.name> extends ParserRuleContext {
<attrs:{a | public <a>;}; separator="\n">
public <s.name>(ParserRuleContext parent, int state<s.ctorAttrs:{a | , <a>}>) {
<if(s.ctorAttrs)>public <s.name>(RuleContext parent, int state) { super(parent, state); }<endif>
public <s.name>(RuleContext parent, int state<s.ctorAttrs:{a | , <a>}>) {
super(parent, state);
<s.ctorAttrs:{a | this.<a.name> = <a.name>;}; separator="\n">
}

View File

@ -133,17 +133,20 @@ public class ATNSerializer {
int edgeType = Transition.serializationTypes.get(t.getClass());
int arg1 = 0;
int arg2 = 0;
int arg3 = 0;
switch ( edgeType ) {
case Transition.RULE :
trg = ((RuleTransition)t).followState.stateNumber;
arg1 = ((RuleTransition)t).target.stateNumber;
arg2 = ((RuleTransition)t).ruleIndex;
arg3 = ((RuleTransition)t).argIndex;
break;
case Transition.PREDICATE :
PredicateTransition pt = (PredicateTransition)t;
arg1 = pt.ruleIndex;
arg2 = pt.predIndex;
if ( pt.isCtxDependent ) edgeType = Transition.DEPENDENT_PREDICATE;
// if ( pt.isCtxDependent ) edgeType = Transition.DEPENDENT_PREDICATE;
arg3 = pt.isCtxDependent ? 1 : 0 ;
break;
case Transition.RANGE :
arg1 = ((RangeTransition)t).from;
@ -156,14 +159,12 @@ public class ATNSerializer {
ActionTransition at = (ActionTransition)t;
arg1 = at.ruleIndex;
arg2 = at.actionIndex;
if ( at.isCtxDependent ) edgeType = Transition.FORCED_DEPENDENT_ACTION;
arg3 = at.isCtxDependent ? 1 : 0 ;
// if ( at.isCtxDependent ) edgeType = Transition.FORCED_DEPENDENT_ACTION;
break;
case Transition.SET :
arg1 = setIndex++;
break;
// case Transition.NOT_ATOM :
// arg1 = ((NotAtomTransition)t).label;
// break;
case Transition.NOT_SET :
arg1 = setIndex++;
break;
@ -175,6 +176,7 @@ public class ATNSerializer {
data.add(edgeType);
data.add(arg1);
data.add(arg2);
data.add(arg3);
}
}
int ndecisions = atn.decisionToState.size();
@ -230,11 +232,12 @@ public class ATNSerializer {
int ttype = ATNSimulator.toInt(data[p + 2]);
int arg1 = ATNSimulator.toInt(data[p + 3]);
int arg2 = ATNSimulator.toInt(data[p + 4]);
int arg3 = ATNSimulator.toInt(data[p + 5]);
buf.append(src+"->"+trg+
" "+Transition.serializationNames[ttype]+
" "+arg1+","+arg2+
" "+arg1+","+arg2+","+arg3+
"\n");
p += 5;
p += 6;
}
int ndecisions = ATNSimulator.toInt(data[p++]);
for (int i=1; i<=ndecisions; i++) {

View File

@ -191,6 +191,11 @@ public class ParserATNFactory implements ATNFactory {
ATNState left = newState(node);
ATNState right = newState(node);
RuleTransition call = new RuleTransition(r.index, start, right);
ActionAST arg = (ActionAST)node.getFirstChildWithType(ANTLRParser.ARG_ACTION);
if ( arg!=null ) {
call.argIndex = g.actions.get(arg);
}
left.addTransition(call);
node.atnState = left;

View File

@ -151,7 +151,7 @@ public void finishAltWithRewrite(AltAST alt) { }
public void discoverSTRewrite(GrammarAST rew) { }
public void discoverTreeRewrite(GrammarAST rew) { }
public void ruleRef(GrammarAST ref, GrammarAST arg) { }
public void ruleRef(GrammarAST ref, ActionAST arg) { }
public void tokenRef(TerminalAST ref, GrammarAST options) { }
public void terminalOption(TerminalAST t, GrammarAST ID, GrammarAST value) { }
public void stringRef(TerminalAST ref, GrammarAST options) { }
@ -412,7 +412,7 @@ block
ruleref
: ^(RULE_REF arg=ARG_ACTION?)
{
ruleRef($RULE_REF, $ARG_ACTION);
ruleRef($RULE_REF, (ActionAST)$ARG_ACTION);
if ( $arg!=null ) actionInAlt((ActionAST)$arg);
}
;

View File

@ -207,7 +207,7 @@ public class BasicSemanticChecks extends GrammarTreeVisitor {
}
@Override
public void ruleRef(GrammarAST ref, GrammarAST arg) {
public void ruleRef(GrammarAST ref, ActionAST arg) {
checkInvalidRuleRef(ref.token);
}

View File

@ -188,7 +188,7 @@ public class SymbolCollector extends GrammarTreeVisitor {
}
@Override
public void ruleRef(GrammarAST ref, GrammarAST arg) {
public void ruleRef(GrammarAST ref, ActionAST arg) {
if ( inContext("DOT ...") ) qualifiedRulerefs.add((GrammarAST)ref.getParent());
rulerefs.add(ref);
if ( currentRule!=null ) {

View File

@ -134,15 +134,16 @@ public class Grammar implements AttributeResolver {
*/
public Map<String,ActionAST> namedActions = new HashMap<String,ActionAST>();
/** Tracks all forced actions in all alternatives of all rules.
* This is includes rule arguments.
* Or if lexer all actions period. Doesn't track sempreds.
* maps tree node to action index.
*/
public LinkedHashMap<ActionAST, Integer> actions = new LinkedHashMap<ActionAST, Integer>();
/** All sempreds found in grammar; maps tree node to sempred index;
* sempred index is 0..n-1 */
* sempred index is 0..n-1
*/
public LinkedHashMap<PredAST, Integer> sempreds = new LinkedHashMap<PredAST, Integer>();
public static final String AUTO_GENERATED_TOKEN_NAME_PREFIX = "T__";