forked from jasder/antlr
rm'd epsilon transition in ATN after rule refs.
[git-p4: depot-paths = "//depot/code/antlr4/main/": change = 9518]
This commit is contained in:
parent
2b8a821c21
commit
80fd90d363
|
@ -38,7 +38,7 @@ public class RuleTransition extends Transition {
|
||||||
|
|
||||||
/** What node to begin computations following ref to rule */
|
/** What node to begin computations following ref to rule */
|
||||||
@NotNull
|
@NotNull
|
||||||
public final ATNState followState;
|
public ATNState followState;
|
||||||
|
|
||||||
public RuleTransition(@NotNull RuleStartState ruleStart,
|
public RuleTransition(@NotNull RuleStartState ruleStart,
|
||||||
int ruleIndex,
|
int ruleIndex,
|
||||||
|
|
|
@ -1,8 +1,4 @@
|
||||||
grammar T;
|
grammar T;
|
||||||
s : b ';' | b '.' ;
|
s : b c ;
|
||||||
b : a ;
|
b : A ;
|
||||||
a : {false}? ID {System.out.println("alt 1");}
|
c : C ;
|
||||||
| {true}? ID {System.out.println("alt 2");}
|
|
||||||
;ID : 'a'..'z'+ ;
|
|
||||||
INT : '0'..'9'+;
|
|
||||||
WS : (' '|'\n') {skip();} ;
|
|
||||||
|
|
|
@ -58,11 +58,26 @@ import java.util.List;
|
||||||
* No side-effects. It builds an ATN object and returns it.
|
* No side-effects. It builds an ATN object and returns it.
|
||||||
*/
|
*/
|
||||||
public class ParserATNFactory implements ATNFactory {
|
public class ParserATNFactory implements ATNFactory {
|
||||||
class TailEpsilonRemover extends ATNVisitor {
|
/** Add follow links from rule stop states to every following state for rule invocations.
|
||||||
@Override
|
* Must do after construction since we optimize away some epsilon transitions.
|
||||||
public void visitState(ATNState p) {
|
*/
|
||||||
if ( p.getClass() == ATNState.class && p.getNumberOfTransitions()==1 ) {
|
class FollowLinkAdder extends ATNVisitor {
|
||||||
ATNState q = p.transition(0).target;
|
@Override
|
||||||
|
public void visitState(ATNState p) {
|
||||||
|
if ( p.getClass() == ATNState.class && p.getNumberOfTransitions()==1 &&
|
||||||
|
p.transition(0) instanceof RuleTransition )
|
||||||
|
{
|
||||||
|
RuleTransition rt = (RuleTransition) p.transition(0);
|
||||||
|
addFollowLink(rt.ruleIndex, rt.followState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TailEpsilonRemover extends ATNVisitor {
|
||||||
|
@Override
|
||||||
|
public void visitState(ATNState p) {
|
||||||
|
if ( p.getClass() == ATNState.class && p.getNumberOfTransitions()==1 ) {
|
||||||
|
ATNState q = p.transition(0).target;
|
||||||
if ( q.getClass() == ATNState.class ) {
|
if ( q.getClass() == ATNState.class ) {
|
||||||
// we have p-x->q for x in {rule, action, pred, token, ...}
|
// we have p-x->q for x in {rule, action, pred, token, ...}
|
||||||
// if edge out of q is single epsilon to block end
|
// if edge out of q is single epsilon to block end
|
||||||
|
@ -96,11 +111,12 @@ public class ParserATNFactory implements ATNFactory {
|
||||||
public ATN createATN() {
|
public ATN createATN() {
|
||||||
_createATN(g.rules.values());
|
_createATN(g.rules.values());
|
||||||
atn.maxTokenType = g.getMaxTokenType();
|
atn.maxTokenType = g.getMaxTokenType();
|
||||||
|
addRuleFollowLinks();
|
||||||
addEOFTransitionToStartRules();
|
addEOFTransitionToStartRules();
|
||||||
return atn;
|
return atn;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void _createATN(Collection<Rule> rules) {
|
public void _createATN(Collection<Rule> rules) {
|
||||||
createRuleStartAndStopATNStates();
|
createRuleStartAndStopATNStates();
|
||||||
|
|
||||||
GrammarASTAdaptor adaptor = new GrammarASTAdaptor();
|
GrammarASTAdaptor adaptor = new GrammarASTAdaptor();
|
||||||
|
@ -205,8 +221,8 @@ public class ParserATNFactory implements ATNFactory {
|
||||||
*/
|
*/
|
||||||
public Handle ruleRef(GrammarAST node) {
|
public Handle ruleRef(GrammarAST node) {
|
||||||
Handle h = _ruleRef(node);
|
Handle h = _ruleRef(node);
|
||||||
Rule r = g.getRule(node.getText());
|
// Rule r = g.getRule(node.getText());
|
||||||
addFollowLink(r, h.right);
|
// addFollowLink(r, h.right);
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,9 +238,9 @@ public class ParserATNFactory implements ATNFactory {
|
||||||
return new Handle(left, right);
|
return new Handle(left, right);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addFollowLink(Rule r, ATNState right) {
|
public void addFollowLink(int ruleIndex, ATNState right) {
|
||||||
// add follow edge from end of invoked rule
|
// add follow edge from end of invoked rule
|
||||||
RuleStopState stop = atn.ruleToStopState[r.index];
|
RuleStopState stop = atn.ruleToStopState[ruleIndex];
|
||||||
epsilon(stop, right);
|
epsilon(stop, right);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -349,13 +365,16 @@ public class ParserATNFactory implements ATNFactory {
|
||||||
Handle el = els.get(i);
|
Handle el = els.get(i);
|
||||||
// if el is of form o-x->o for x in {rule, action, pred, token, ...}
|
// if el is of form o-x->o for x in {rule, action, pred, token, ...}
|
||||||
// and not last in alt
|
// and not last in alt
|
||||||
if ( el.left.getClass() == ATNState.class &&
|
Transition tr = null;
|
||||||
|
if ( el.left.getNumberOfTransitions()==1 ) tr = el.left.transition(0);
|
||||||
|
boolean isRuleTrans = tr instanceof RuleTransition;
|
||||||
|
if ( el.left.getClass() == ATNState.class &&
|
||||||
el.right.getClass() == ATNState.class &&
|
el.right.getClass() == ATNState.class &&
|
||||||
el.left.getNumberOfTransitions()==1 &&
|
tr!=null && (isRuleTrans || tr.target == el.right) )
|
||||||
el.left.transition(0).target == el.right)
|
|
||||||
{
|
{
|
||||||
// we can avoid epsilon edge to next el
|
// we can avoid epsilon edge to next el
|
||||||
el.left.transition(0).target = els.get(i+1).left;
|
if ( isRuleTrans ) ((RuleTransition)tr).followState = els.get(i+1).left;
|
||||||
|
else tr.target = els.get(i+1).left;
|
||||||
atn.removeState(el.right); // we skipped over this state
|
atn.removeState(el.right); // we skipped over this state
|
||||||
}
|
}
|
||||||
else { // need epsilon if previous block's right end node is complicated
|
else { // need epsilon if previous block's right end node is complicated
|
||||||
|
@ -501,6 +520,14 @@ public class ParserATNFactory implements ATNFactory {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addRuleFollowLinks() {
|
||||||
|
FollowLinkAdder flinker = new FollowLinkAdder();
|
||||||
|
for (Rule r : g.rules.values()) {
|
||||||
|
ATNState start = atn.ruleToStartState[r.index];
|
||||||
|
flinker.visit(start);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** add an EOF transition to any rule end ATNState that points to nothing
|
/** add an EOF transition to any rule end ATNState that points to nothing
|
||||||
* (i.e., for all those rules not invoked by another rule). These
|
* (i.e., for all those rules not invoked by another rule). These
|
||||||
* are start symbols then.
|
* are start symbols then.
|
||||||
|
|
|
@ -184,17 +184,16 @@ public class TestATNConstruction extends BaseTest {
|
||||||
"b : B ;");
|
"b : B ;");
|
||||||
String expecting =
|
String expecting =
|
||||||
"RuleStart_a_0->s4\n" +
|
"RuleStart_a_0->s4\n" +
|
||||||
"s4-b->RuleStart_b_2\n" +
|
"s4-b->RuleStart_b_2\n" +
|
||||||
"s5->s6\n" +
|
"s6-A->s7\n" +
|
||||||
"s6-A->s7\n" +
|
"s7->RuleStop_a_1\n" +
|
||||||
"s7->RuleStop_a_1\n" +
|
"RuleStop_a_1-EOF->s10\n";
|
||||||
"RuleStop_a_1-EOF->s10\n";
|
|
||||||
checkRuleATN(g, "a", expecting);
|
checkRuleATN(g, "a", expecting);
|
||||||
expecting =
|
expecting =
|
||||||
"RuleStart_b_2->s8\n" +
|
"RuleStart_b_2->s8\n" +
|
||||||
"s8-B->s9\n" +
|
"s8-B->s9\n" +
|
||||||
"s9->RuleStop_b_3\n" +
|
"s9->RuleStop_b_3\n" +
|
||||||
"RuleStop_b_3->s5\n";
|
"RuleStop_b_3->s6\n";
|
||||||
checkRuleATN(g, "b", expecting);
|
checkRuleATN(g, "b", expecting);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -206,10 +205,10 @@ public class TestATNConstruction extends BaseTest {
|
||||||
"c : b C;");
|
"c : b C;");
|
||||||
String expecting =
|
String expecting =
|
||||||
"RuleStart_b_2->s10\n" +
|
"RuleStart_b_2->s10\n" +
|
||||||
"s10-B->s11\n" +
|
"s10-B->s11\n" +
|
||||||
"s11->RuleStop_b_3\n" +
|
"s11->RuleStop_b_3\n" +
|
||||||
"RuleStop_b_3->s7\n" +
|
"RuleStop_b_3->s8\n" +
|
||||||
"RuleStop_b_3->s13\n";
|
"RuleStop_b_3->s14\n";
|
||||||
checkRuleATN(g, "b", expecting);
|
checkRuleATN(g, "b", expecting);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue