use of org.antlr.v4.runtime.misc.NotNull in project antlr4 by tunnelvisionlabs.
the class ParserATNFactory method star.
/**
* From {@code (blk)*} build {@code ( blk+ )?} with *two* decisions, one for
* entry and one for choosing alts of {@code blk}.
*
* <pre>
* |-------------|
* v |
* o--[o-blk-o]->o o
* | ^
* -----------------|
* </pre>
*
* Note that the optional bypass must jump outside the loop as
* {@code (A|B)*} is not the same thing as {@code (A|B|)+}.
*/
@NotNull
@Override
public Handle star(@NotNull GrammarAST starAST, @NotNull Handle elem) {
StarBlockStartState blkStart = (StarBlockStartState) elem.left;
BlockEndState blkEnd = (BlockEndState) elem.right;
preventEpsilonClosureBlocks.add(Tuple.create(currentRule, blkStart, blkEnd));
StarLoopEntryState entry = newState(StarLoopEntryState.class, starAST);
entry.nonGreedy = !((QuantifierAST) starAST).isGreedy();
// no way to express SLL restriction
entry.sll = false;
atn.defineDecisionState(entry);
LoopEndState end = newState(LoopEndState.class, starAST);
StarLoopbackState loop = newState(StarLoopbackState.class, starAST);
entry.loopBackState = loop;
end.loopBackState = loop;
BlockAST blkAST = (BlockAST) starAST.getChild(0);
if (((QuantifierAST) starAST).isGreedy()) {
if (expectNonGreedy(blkAST)) {
g.tool.errMgr.grammarError(ErrorType.EXPECTED_NON_GREEDY_WILDCARD_BLOCK, g.fileName, starAST.getToken(), starAST.getToken().getText());
}
// loop enter edge (alt 1)
epsilon(entry, blkStart);
// bypass loop edge (alt 2)
epsilon(entry, end);
} else {
// if not greedy, priority to exit branch; make it first
// bypass loop edge (alt 1)
epsilon(entry, end);
// loop enter edge (alt 2)
epsilon(entry, blkStart);
}
// block end hits loop back
epsilon(blkEnd, loop);
// loop back to entry/exit decision
epsilon(loop, entry);
// decision is to enter/exit; blk is its own decision
starAST.atnState = entry;
return new Handle(entry, end);
}
use of org.antlr.v4.runtime.misc.NotNull in project antlr4 by tunnelvisionlabs.
the class ParserATNFactory method elemList.
@NotNull
public Handle elemList(@NotNull List<Handle> els) {
int n = els.size();
for (int i = 0; i < n - 1; i++) {
// hook up elements (visit all but last)
Handle el = els.get(i);
// if el is of form o-x->o for x in {rule, action, pred, token, ...}
// and not last in alt
Transition tr = null;
if (el.left.getNumberOfTransitions() == 1)
tr = el.left.transition(0);
boolean isRuleTrans = tr instanceof RuleTransition;
if (el.left.getStateType() == ATNState.BASIC && el.right.getStateType() == ATNState.BASIC && tr != null && (isRuleTrans && ((RuleTransition) tr).followState == el.right || tr.target == el.right)) {
// we can avoid epsilon edge to next el
if (isRuleTrans)
((RuleTransition) tr).followState = els.get(i + 1).left;
else
tr.target = els.get(i + 1).left;
// we skipped over this state
atn.removeState(el.right);
} else {
// need epsilon if previous block's right end node is complicated
epsilon(el.right, els.get(i + 1).left);
}
}
Handle first = els.get(0);
Handle last = els.get(n - 1);
if (first == null || last == null) {
g.tool.errMgr.toolError(ErrorType.INTERNAL_ERROR, "element list has first|last == null");
}
return new Handle(first.left, last.right);
}
use of org.antlr.v4.runtime.misc.NotNull in project antlr4 by tunnelvisionlabs.
the class ParserATNFactory method createATN.
@NotNull
@Override
public ATN createATN() {
_createATN(g.rules.values());
assert atn.maxTokenType == g.getMaxTokenType();
addRuleFollowLinks();
addEOFTransitionToStartRules();
ATNOptimizer.optimize(g, atn);
for (Tuple3<? extends Rule, ? extends ATNState, ? extends ATNState> pair : preventEpsilonClosureBlocks) {
LL1Analyzer analyzer = new LL1Analyzer(atn);
ATNState blkStart = pair.getItem2();
ATNState blkStop = pair.getItem3();
IntervalSet lookahead = analyzer.LOOK(blkStart, blkStop, PredictionContext.EMPTY_LOCAL);
if (lookahead.contains(org.antlr.v4.runtime.Token.EPSILON)) {
ErrorType errorType = pair.getItem1() instanceof LeftRecursiveRule ? ErrorType.EPSILON_LR_FOLLOW : ErrorType.EPSILON_CLOSURE;
g.tool.errMgr.grammarError(errorType, g.fileName, ((GrammarAST) pair.getItem1().ast.getChild(0)).getToken(), pair.getItem1().name);
}
}
optionalCheck: for (Tuple3<? extends Rule, ? extends ATNState, ? extends ATNState> pair : preventEpsilonOptionalBlocks) {
int bypassCount = 0;
for (int i = 0; i < pair.getItem2().getNumberOfTransitions(); i++) {
ATNState startState = pair.getItem2().transition(i).target;
if (startState == pair.getItem3()) {
bypassCount++;
continue;
}
LL1Analyzer analyzer = new LL1Analyzer(atn);
if (analyzer.LOOK(startState, pair.getItem3(), PredictionContext.EMPTY_LOCAL).contains(org.antlr.v4.runtime.Token.EPSILON)) {
g.tool.errMgr.grammarError(ErrorType.EPSILON_OPTIONAL, g.fileName, ((GrammarAST) pair.getItem1().ast.getChild(0)).getToken(), pair.getItem1().name);
continue optionalCheck;
}
}
if (bypassCount != 1) {
throw new UnsupportedOperationException("Expected optional block with exactly 1 bypass alternative.");
}
}
return atn;
}
use of org.antlr.v4.runtime.misc.NotNull in project antlr4 by tunnelvisionlabs.
the class ParserATNFactory method makeBlock.
@NotNull
protected Handle makeBlock(@NotNull BlockStartState start, @NotNull BlockAST blkAST, @NotNull List<Handle> alts) {
start.sll = isSLLDecision(blkAST);
BlockEndState end = newState(BlockEndState.class, blkAST);
start.endState = end;
for (Handle alt : alts) {
// hook alts up to decision block
epsilon(start, alt.left);
epsilon(alt.right, end);
// no back link in ATN so must walk entire alt to see if we can
// strip out the epsilon to 'end' state
TailEpsilonRemover opt = new TailEpsilonRemover(atn);
opt.visit(alt.left);
}
Handle h = new Handle(start, end);
// FASerializer ser = new FASerializer(g, h.left);
// System.out.println(blkAST.toStringTree()+":\n"+ser);
blkAST.atnState = start;
return h;
}
use of org.antlr.v4.runtime.misc.NotNull in project antlr4 by tunnelvisionlabs.
the class ParserATNFactory method block.
/**
* From {@code A|B|..|Z} alternative block build
*
* <pre>
* o->o-A->o->o (last ATNState is BlockEndState pointed to by all alts)
* | ^
* |->o-B->o--|
* | |
* ... |
* | |
* |->o-Z->o--|
* </pre>
*
* So start node points at every alternative with epsilon transition and
* every alt right side points at a block end ATNState.
* <p>
* Special case: only one alternative: don't make a block with alt
* begin/end.
* <p>
* Special case: if just a list of tokens/chars/sets, then collapse to a
* single edged o-set->o graph.
* <p>
* TODO: Set alt number (1..n) in the states?
*/
@NotNull
@Override
public Handle block(@NotNull BlockAST blkAST, @NotNull GrammarAST ebnfRoot, @NotNull List<Handle> alts) {
if (ebnfRoot == null) {
if (alts.size() == 1) {
Handle h = alts.get(0);
blkAST.atnState = h.left;
return h;
}
BlockStartState start = newState(BasicBlockStartState.class, blkAST);
if (alts.size() > 1)
atn.defineDecisionState(start);
return makeBlock(start, blkAST, alts);
}
switch(ebnfRoot.getType()) {
case ANTLRParser.OPTIONAL:
BlockStartState start = newState(BasicBlockStartState.class, blkAST);
atn.defineDecisionState(start);
Handle h = makeBlock(start, blkAST, alts);
return optional(ebnfRoot, h);
case ANTLRParser.CLOSURE:
BlockStartState star = newState(StarBlockStartState.class, ebnfRoot);
if (alts.size() > 1)
atn.defineDecisionState(star);
h = makeBlock(star, blkAST, alts);
return star(ebnfRoot, h);
case ANTLRParser.POSITIVE_CLOSURE:
PlusBlockStartState plus = newState(PlusBlockStartState.class, ebnfRoot);
if (alts.size() > 1)
atn.defineDecisionState(plus);
h = makeBlock(plus, blkAST, alts);
return plus(ebnfRoot, h);
}
return null;
}
Aggregations