use of org.antlr.works.visualization.fa.FATransition in project antlrworks by antlr.
the class GRenderer method recursiveRenderPositionAlternative.
public FAState recursiveRenderPositionAlternative(FAState state, GPoint basePoint) {
FAState alternativeEndState = alternativeEndState(state);
// This point is used to position each transition
GPoint point = new GPoint(basePoint);
point.addX(GContext.NODE_WIDTH + GContext.EPSILON_WIDTH);
GDimension firstAlternativeDimension = null;
for (int t = 0; t < state.getNumberOfTransitions(); t++) {
FATransition transition = state.transition(t);
GLink link = getNode(state).getLink(transition);
if (t == 0) {
// We remember here the size of the first transition because if we find later
// a "loop" transition, we will have to offset this "loop" by the size of the first
// transition (because the "loop" is always drawed above the first transition).
firstAlternativeDimension = link.branchDim;
}
if (t > 0 && !transition.loop) {
// Offset the current point for each transition (except for a "loop" because it is
// displayed above the first transition)
point.addY(GContext.LINE_SPACE);
point.addY(link.branchDim.up);
}
if (transition.target == alternativeEndState) {
// The transition is simply a single transition (epsilon normally).
if (transition.loop) {
// If this is a "loop", draw it above the first transition
GPoint vp = new GPoint(basePoint);
vp.subY(firstAlternativeDimension.up);
vp.subY(link.branchDim.down);
// The "virtual position" is used by the link to know where to display itself
// when it has to "curve" (because both start and end point are on the same y-axis value)
getNode(state).getLink(transition).setVirtualPosition(vp);
} else {
getNode(state).getLink(transition).setVirtualPosition(point);
point.addY(link.branchDim.down);
}
} else {
// The transition is more than a single transition, continue recursively...
recursiveRenderPositionNode(transition.target, alternativeEndState, new GPoint(point));
point.addY(link.branchDim.down);
}
}
return alternativeEndState;
}
use of org.antlr.works.visualization.fa.FATransition in project antlrworks by antlr.
the class GRenderer method recursiveRenderSizeSingle.
public GDimension recursiveRenderSizeSingle(FAState state, FAState endState) {
GDimension dimension = new GDimension();
dimension.addUp(GContext.NODE_UP);
dimension.addDown(GContext.NODE_DOWN);
while (state != endState && state != null) {
if (state.isAlternative()) {
GDimension altDim = recursiveRenderSizeAlternative(state);
dimension.addWidth(GContext.NODE_WIDTH + altDim.width);
dimension.maxUp(altDim.up);
dimension.maxDown(altDim.down);
state = alternativeEndState(state);
} else if (state.isSingle()) {
// Create the first node...
GNode n1 = createNode(state);
// ... and compute the size of the transition...
FATransition transition = state.getFirstTransition();
if (transition.isEpsilon()) {
n1.linkDimension.width = GContext.EPSILON_WIDTH;
n1.linkDimension.up = GContext.EPSILON_UP;
n1.linkDimension.down = GContext.EPSILON_DOWN;
} else {
n1.linkDimension.width = GContext.getBoxWidth(transition.label);
n1.linkDimension.up = GContext.BOX_UP;
n1.linkDimension.down = GContext.BOX_DOWN;
}
dimension.addWidth(GContext.NODE_WIDTH + n1.linkDimension.width);
dimension.maxUp(n1.linkDimension.up);
dimension.maxDown(n1.linkDimension.down);
// ... then create the target node...
state = transition.target;
GNode n2 = createNode(state);
// ... and create the link between these two states
GLink link = new GLink();
link.transition = transition;
link.target = n2;
n1.addLink(link);
if (state == endState) {
// If we have reached the end of an alternative, we must set the "last" flag
// to the SDLink in order for it to be correctly rendered on screen.
EOAInfo eoa = endOfAlternativeInfoMap.get(state);
if (eoa != null) {
link.setLast(eoa.last);
}
}
} else {
dimension.addWidth(GContext.NODE_WIDTH);
state = null;
}
}
return dimension;
}
use of org.antlr.works.visualization.fa.FATransition in project antlrworks by antlr.
the class GRenderer method alternativeEndState.
public FAState alternativeEndState(FAState alt) {
int counter = alt.getNumberOfTransitions() - 1;
FAState state = alt;
while (true) {
FATransition transition = state.getFirstTransition();
if (transition == null)
break;
state = transition.target;
// Note: a state can be both an end-of-alternative and an alternative itself ;-)
if (analysis.numberOfIncomingTransition(state) > 1) {
counter -= analysis.numberOfIncomingTransition(state) - 1;
if (counter <= 0)
break;
}
if (state.isAlternative()) {
counter += state.getNumberOfTransitions() - 1;
}
}
return state;
}
use of org.antlr.works.visualization.fa.FATransition in project antlrworks by antlr.
the class GGraphGroup method addNextElementInOtherRule.
public void addNextElementInOtherRule(List<GPathElement> elements, GNode node, GNode externalNode, GNode nextNode, NFAState nextState) {
if (externalNode == null) {
// The external node is not specified. Try to find it.
if (node.state.getFirstTransition() == null) {
// If the node contains no transition (probably if it is at the end of a rule), then
// ignore externalNode. We will draw only a link from node to nextNode.
} else {
// Find the transition that points to the external rule ref
FATransition t = node.state.getTransitionToExternalStateRule(nextState.enclosingRule.name);
if (t == null) {
System.err.println("[GGraphGroup] No transition to external state " + nextState.stateNumber + "[" + nextState.enclosingRule.name + "] - using first transition by default");
t = node.state.getFirstTransition();
}
externalNode = findNodeForStateNumber(t.target.stateNumber);
}
}
if (externalNode == null) {
// Add the link between node and nextNode, ignore externalNode because it doesn't exist
elements.add(GPathElement.createElement(node));
elements.add(GPathElement.createLink(node, nextNode));
} else {
elements.add(GPathElement.createElement(node));
// Add the link between node and externalNode.
FATransition t = node.state.getTransitionToStateNumber(externalNode.state.stateNumber);
elements.add(GPathElement.createElement(node.getLink(t)));
elements.add(GPathElement.createElement(externalNode));
// Add the link between externalNode and nextNode
elements.add(GPathElement.createLink(externalNode, nextNode));
}
}
use of org.antlr.works.visualization.fa.FATransition in project antlrworks by antlr.
the class GGraphGroup method addPath.
public void addPath(List path, boolean disabled, Map<Integer, FAState> skippedStates) {
List<GPathElement> elements = new ArrayList<GPathElement>();
/** path contains a list of NFAState states (from ANTLR): they represent
* all the states along the path. The graphical representation of the NFA/SD
* does not necessarily contains all the states of the path because the representation
* can be simplified to remove all unecessary states.
* The problem here is to use the information stored in the transition of the
* graphical representation to figure out exactly which graphical node corresponds
* to the path.
*/
NFAState state;
GNode node;
NFAState nextState = null;
GNode nextNode = null;
for (pathIndex = 0; getPathIndex() < path.size(); pathIndex = getPathIndex() + 1) {
if (getPathIndex() == 0) {
nextState = (NFAState) path.get(getPathIndex());
nextNode = findNodeForStateNumber(nextState.stateNumber);
if (nextNode == null) {
// A path can start from anywhere in the graph. It might happen
// that the starting state of the path has been skipped by
// the optimization in FAFactory. We use the skippedStates mapping
// to find out what is the parent state of the skipped state.
FAState parentState = skippedStates.get(nextState.stateNumber);
if (parentState == null) {
System.err.println("[GGraphGroup] Starting path state " + nextState.stateNumber + "[" + nextState.enclosingRule.name + "] cannot be found in the graph");
return;
} else {
nextNode = findNodeForStateNumber(parentState.stateNumber);
}
}
continue;
} else {
state = nextState;
node = nextNode;
}
nextState = (NFAState) path.get(getPathIndex());
nextNode = findNodeForStateNumber(nextState.stateNumber);
GNode externalNode = null;
if (nextNode == null) {
// The state has probably been skipped during the graphical rendering.
// Find the next non-skipped state.
FATransition t = getNodeTransitionToNextNonSkippedState(node, path);
if (t == null) {
// No transition found. Look in the skipped states mapping because
// it might be possible that the next state is in another rule but
// cannot be found because it has been skipped.
FAState parentState = skippedStates.get(nextState.stateNumber);
if (parentState == null) {
// OK. The node really does not exist. Continue by skipping it.
nextNode = node;
continue;
} else {
nextNode = findNodeForStateNumber(parentState.stateNumber);
}
} else {
// is incrementing it
if (getPathIndex() >= path.size()) {
nextNode = findNodeForStateNumber(t.target.stateNumber);
} else {
nextState = (NFAState) path.get(getPathIndex());
if (t.target.stateNumber == nextState.stateNumber) {
nextNode = findNodeForStateNumber(t.target.stateNumber);
} else {
// The only case that the target state of the transition if not
// the next state of the path is when the next state of the path
// is in another rule. In this case, the target state of the transition
// will contain a negative state number indicating an external rule reference:
// this external rule reference is added by AW during rendering and is not
// part of any ANTLR NFA.
// This node is the node representing the external rule reference
// before jumping outside of the rule
externalNode = findNodeForStateNumber(t.target.stateNumber);
// This node is the first node in the other rule
nextNode = findNodeForStateNumber(nextState.stateNumber);
}
}
}
}
if (state == null || node == null || nextNode == null)
continue;
if (state.enclosingRule.name.equals(nextState.enclosingRule.name))
addNextElementInSameRule(elements, node, nextNode);
else
addNextElementInOtherRule(elements, node, externalNode, nextNode, nextState);
}
if (nextNode != null)
elements.add(GPathElement.createElement(nextNode));
getPathGroup().addPath(new GPath(elements, disabled));
}
Aggregations