use of org.antlr.v4.runtime.atn.Transition in project antlr4 by antlr.
the class DOTGenerator method getDOT.
/** Return a String containing a DOT description that, when displayed,
* will show the incoming state machine visually. All nodes reachable
* from startState will be included.
*/
public String getDOT(ATNState startState, String[] ruleNames, boolean isLexer) {
if (startState == null)
return null;
// The output DOT graph for visualization
Set<ATNState> markedStates = new HashSet<ATNState>();
ST dot = stlib.getInstanceOf("atn");
dot.add("startState", startState.stateNumber);
dot.add("rankdir", rankdir);
List<ATNState> work = new LinkedList<ATNState>();
work.add(startState);
while (!work.isEmpty()) {
ATNState s = work.get(0);
if (markedStates.contains(s)) {
work.remove(0);
continue;
}
markedStates.add(s);
// don't go past end of rule node to the follow states
if (s instanceof RuleStopState)
continue;
// special case: if decision point, then line up the alt start states
// unless it's an end of block
// if ( s instanceof BlockStartState ) {
// ST rankST = stlib.getInstanceOf("decision-rank");
// DecisionState alt = (DecisionState)s;
// for (int i=0; i<alt.getNumberOfTransitions(); i++) {
// ATNState target = alt.transition(i).target;
// if ( target!=null ) {
// rankST.add("states", target.stateNumber);
// }
// }
// dot.add("decisionRanks", rankST);
// }
// make a DOT edge for each transition
ST edgeST;
for (int i = 0; i < s.getNumberOfTransitions(); i++) {
Transition edge = s.transition(i);
if (edge instanceof RuleTransition) {
RuleTransition rr = ((RuleTransition) edge);
// don't jump to other rules, but display edge to follow node
edgeST = stlib.getInstanceOf("edge");
String label = "<" + ruleNames[rr.ruleIndex];
if (((RuleStartState) rr.target).isLeftRecursiveRule) {
label += "[" + rr.precedence + "]";
}
label += ">";
edgeST.add("label", label);
edgeST.add("src", "s" + s.stateNumber);
edgeST.add("target", "s" + rr.followState.stateNumber);
edgeST.add("arrowhead", arrowhead);
dot.add("edges", edgeST);
work.add(rr.followState);
continue;
}
if (edge instanceof ActionTransition) {
edgeST = stlib.getInstanceOf("action-edge");
edgeST.add("label", getEdgeLabel(edge.toString()));
} else if (edge instanceof AbstractPredicateTransition) {
edgeST = stlib.getInstanceOf("edge");
edgeST.add("label", getEdgeLabel(edge.toString()));
} else if (edge.isEpsilon()) {
edgeST = stlib.getInstanceOf("epsilon-edge");
edgeST.add("label", getEdgeLabel(edge.toString()));
boolean loopback = false;
if (edge.target instanceof PlusBlockStartState) {
loopback = s.equals(((PlusBlockStartState) edge.target).loopBackState);
} else if (edge.target instanceof StarLoopEntryState) {
loopback = s.equals(((StarLoopEntryState) edge.target).loopBackState);
}
edgeST.add("loopback", loopback);
} else if (edge instanceof AtomTransition) {
edgeST = stlib.getInstanceOf("edge");
AtomTransition atom = (AtomTransition) edge;
String label = String.valueOf(atom.label);
if (isLexer)
label = "'" + getEdgeLabel(new StringBuilder().appendCodePoint(atom.label).toString()) + "'";
else if (grammar != null)
label = grammar.getTokenDisplayName(atom.label);
edgeST.add("label", getEdgeLabel(label));
} else if (edge instanceof SetTransition) {
edgeST = stlib.getInstanceOf("edge");
SetTransition set = (SetTransition) edge;
String label = set.label().toString();
if (isLexer)
label = set.label().toString(true);
else if (grammar != null)
label = set.label().toString(grammar.getVocabulary());
if (edge instanceof NotSetTransition)
label = "~" + label;
edgeST.add("label", getEdgeLabel(label));
} else if (edge instanceof RangeTransition) {
edgeST = stlib.getInstanceOf("edge");
RangeTransition range = (RangeTransition) edge;
String label = range.label().toString();
if (isLexer)
label = range.toString();
else if (grammar != null)
label = range.label().toString(grammar.getVocabulary());
edgeST.add("label", getEdgeLabel(label));
} else {
edgeST = stlib.getInstanceOf("edge");
edgeST.add("label", getEdgeLabel(edge.toString()));
}
edgeST.add("src", "s" + s.stateNumber);
edgeST.add("target", "s" + edge.target.stateNumber);
edgeST.add("arrowhead", arrowhead);
if (s.getNumberOfTransitions() > 1) {
edgeST.add("transitionIndex", i);
} else {
edgeST.add("transitionIndex", false);
}
dot.add("edges", edgeST);
work.add(edge.target);
}
}
// }
for (ATNState s : markedStates) {
if (!(s instanceof RuleStopState))
continue;
ST st = stlib.getInstanceOf("stopstate");
st.add("name", "s" + s.stateNumber);
st.add("label", getStateLabel(s));
dot.add("states", st);
}
for (ATNState s : markedStates) {
if (s instanceof RuleStopState)
continue;
ST st = stlib.getInstanceOf("state");
st.add("name", "s" + s.stateNumber);
st.add("label", getStateLabel(s));
st.add("transitions", s.getTransitions());
dot.add("states", st);
}
return dot.render();
}
use of org.antlr.v4.runtime.atn.Transition in project antlr4 by antlr.
the class ParserATNFactory method addEOFTransitionToStartRules.
/** 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
* are start symbols then.
*
* Return the number of grammar entry points; i.e., how many rules are
* not invoked by another rule (they can only be invoked from outside).
* These are the start rules.
*/
public int addEOFTransitionToStartRules() {
int n = 0;
// one unique EOF target for all rules
ATNState eofTarget = newState(null);
for (Rule r : g.rules.values()) {
ATNState stop = atn.ruleToStopState[r.index];
if (stop.getNumberOfTransitions() > 0)
continue;
n++;
Transition t = new AtomTransition(eofTarget, Token.EOF);
stop.addTransition(t);
}
return n;
}
use of org.antlr.v4.runtime.atn.Transition in project antlr4 by antlr.
the class LeftRecursionDetector method check.
/** From state s, look for any transition to a rule that is currently
* being traced. When tracing r, visitedPerRuleCheck has r
* initially. If you reach a rule stop state, return but notify the
* invoking rule that the called rule is nullable. This implies that
* invoking rule must look at follow transition for that invoking state.
*
* The visitedStates tracks visited states within a single rule so
* we can avoid epsilon-loop-induced infinite recursion here. Keep
* filling the cycles in listOfRecursiveCycles and also, as a
* side-effect, set leftRecursiveRules.
*/
public boolean check(Rule enclosingRule, ATNState s, Set<ATNState> visitedStates) {
if (s instanceof RuleStopState)
return true;
if (visitedStates.contains(s))
return false;
visitedStates.add(s);
//System.out.println("visit "+s);
int n = s.getNumberOfTransitions();
boolean stateReachesStopState = false;
for (int i = 0; i < n; i++) {
Transition t = s.transition(i);
if (t instanceof RuleTransition) {
RuleTransition rt = (RuleTransition) t;
Rule r = g.getRule(rt.ruleIndex);
if (rulesVisitedPerRuleCheck.contains((RuleStartState) t.target)) {
addRulesToCycle(enclosingRule, r);
} else {
// must visit if not already visited; mark target, pop when done
rulesVisitedPerRuleCheck.add((RuleStartState) t.target);
// send new visitedStates set per rule invocation
boolean nullable = check(r, t.target, new HashSet<ATNState>());
// we're back from visiting that rule
rulesVisitedPerRuleCheck.remove((RuleStartState) t.target);
if (nullable) {
stateReachesStopState |= check(enclosingRule, rt.followState, visitedStates);
}
}
} else if (t.isEpsilon()) {
stateReachesStopState |= check(enclosingRule, t.target, visitedStates);
}
// else ignore non-epsilon transitions
}
return stateReachesStopState;
}
use of org.antlr.v4.runtime.atn.Transition in project antlr4 by antlr.
the class LexerATNFactory method tokenRef.
@Override
public Handle tokenRef(TerminalAST node) {
// Ref to EOF in lexer yields char transition on -1
if (node.getText().equals("EOF")) {
ATNState left = newState(node);
ATNState right = newState(node);
left.addTransition(new AtomTransition(right, IntStream.EOF));
return new Handle(left, right);
}
return _ruleRef(node);
}
use of org.antlr.v4.runtime.atn.Transition in project antlr4 by antlr.
the class LexerATNFactory method stringLiteral.
/** For a lexer, a string is a sequence of char to match. That is,
* "fog" is treated as 'f' 'o' 'g' not as a single transition in
* the DFA. Machine== o-'f'->o-'o'->o-'g'->o and has n+1 states
* for n characters.
*/
@Override
public Handle stringLiteral(TerminalAST stringLiteralAST) {
String chars = stringLiteralAST.getText();
ATNState left = newState(stringLiteralAST);
ATNState right;
chars = CharSupport.getStringFromGrammarStringLiteral(chars);
if (chars == null) {
g.tool.errMgr.grammarError(ErrorType.INVALID_ESCAPE_SEQUENCE, g.fileName, stringLiteralAST.getToken());
return new Handle(left, left);
}
int n = chars.length();
ATNState prev = left;
right = null;
for (int i = 0; i < n; ) {
right = newState(stringLiteralAST);
int codePoint = chars.codePointAt(i);
prev.addTransition(CodePointTransitions.createWithCodePoint(right, codePoint));
prev = right;
i += Character.charCount(codePoint);
}
stringLiteralAST.atnState = left;
return new Handle(left, right);
}
Aggregations