1 31 32 package org.antlr.works.visualization.graphics; 33 34 import org.antlr.works.visualization.fa.FAAnalysis; 35 import org.antlr.works.visualization.fa.FAState; 36 import org.antlr.works.visualization.fa.FATransition; 37 import org.antlr.works.visualization.graphics.graph.GGraph; 38 import org.antlr.works.visualization.graphics.primitive.GDimension; 39 import org.antlr.works.visualization.graphics.primitive.GPoint; 40 import org.antlr.works.visualization.graphics.shape.GLink; 41 import org.antlr.works.visualization.graphics.shape.GNode; 42 43 import java.util.ArrayList ; 44 import java.util.HashMap ; 45 import java.util.List ; 46 import java.util.Map ; 47 48 public class GRenderer { 49 50 protected List <GNode> graphicNodes = new ArrayList <GNode>(); 51 52 protected FAAnalysis analysis = new FAAnalysis(); 53 protected Map <FAState,GNode> nodes = new HashMap <FAState, GNode>(); 54 protected Map <FAState, EOAInfo> endOfAlternativeInfoMap = new HashMap <FAState, EOAInfo>(); 55 56 public GRenderer() { 57 } 58 59 64 65 public synchronized GGraph render(FAState state) { 66 GGraph graph = new GGraph(); 67 graph.setDimension(renderSize(state)); 68 renderPosition(state); 69 70 72 GNode lastNode = graphicNodes.get(graphicNodes.size()-1); 73 if(lastNode != null) 74 lastNode.lastNodeOfRule = true; 75 76 graph.setNodes((ArrayList <GNode>)((ArrayList )graphicNodes).clone()); 77 return graph; 78 } 79 80 public void renderPosition(FAState state) { 81 recursiveRenderPositionNode(state, null, new GPoint()); 82 } 83 84 public void recursiveRenderPositionNode(FAState state, FAState endState, GPoint basePoint) { 85 while(state != endState) { 86 GNode node = getNode(state); 87 if(node == null) { 88 System.err.println("Cannot find SDNode associated with state \""+state+"\""); 89 return; 90 } 91 92 node.setPosition(basePoint); 93 94 if(state.isAlternative()) { 95 state = recursiveRenderPositionAlternative(state, basePoint); 96 basePoint.addX(node.nodeDimension.width+node.linkDimension.width); 97 } else if(state.isSingle()) { 98 basePoint.addX(node.nodeDimension.width+node.linkDimension.width); 99 state = state.getNextFirstState(); 100 } else { 101 state = null; 102 } 103 } 104 } 105 106 public FAState recursiveRenderPositionAlternative(FAState state, GPoint basePoint) { 107 FAState alternativeEndState = alternativeEndState(state); 108 109 GPoint point = new GPoint(basePoint); 111 point.addX(GContext.NODE_WIDTH+GContext.EPSILON_WIDTH); 112 113 GDimension firstAlternativeDimension = null; 114 115 for(int t=0; t<state.getNumberOfTransitions(); t++) { 116 FATransition transition = state.transition(t); 117 GLink link = getNode(state).getLink(transition); 118 119 if(t == 0) { 120 firstAlternativeDimension = link.branchDim; 124 } 125 126 if(t > 0 && !transition.loop) { 127 point.addY(GContext.LINE_SPACE); 130 point.addY(link.branchDim.up); 131 } 132 133 if(transition.target == alternativeEndState) { 134 if(transition.loop) { 136 GPoint vp = new GPoint(basePoint); 138 vp.subY(firstAlternativeDimension.up); 139 vp.subY(link.branchDim.down); 140 141 getNode(state).getLink(transition).setVirtualPosition(vp); 144 } else { 145 getNode(state).getLink(transition).setVirtualPosition(point); 146 point.addY(link.branchDim.down); 147 } 148 } else { 149 recursiveRenderPositionNode(transition.target, alternativeEndState, new GPoint(point)); 151 point.addY(link.branchDim.down); 152 } 153 } 154 return alternativeEndState; 155 } 156 157 public GDimension renderSize(FAState state) { 158 graphicNodes.clear(); 159 nodes.clear(); 160 endOfAlternativeInfoMap.clear(); 161 analysis.analyze(state); 162 return recursiveRenderSizeSingle(state, null); 163 } 164 165 public GDimension recursiveRenderSizeSingle(FAState state, FAState endState) { 166 GDimension dimension = new GDimension(); 167 168 dimension.addUp(GContext.NODE_UP); 169 dimension.addDown(GContext.NODE_DOWN); 170 171 while(state != endState) { 172 if(state.isAlternative()) { 173 GDimension altDim = recursiveRenderSizeAlternative(state); 174 dimension.addWidth(GContext.NODE_WIDTH+altDim.width); 175 dimension.maxUp(altDim.up); 176 dimension.maxDown(altDim.down); 177 state = alternativeEndState(state); 178 } else if(state.isSingle()) { 179 GNode n1 = createNode(state); 181 182 FATransition transition = state.getFirstTransition(); 184 if(transition.isEpsilon()) { 185 n1.linkDimension.width = GContext.EPSILON_WIDTH; 186 n1.linkDimension.up = GContext.EPSILON_UP; 187 n1.linkDimension.down = GContext.EPSILON_DOWN; 188 } else { 189 n1.linkDimension.width = GContext.getBoxWidth(transition.label); 190 n1.linkDimension.up = GContext.BOX_UP; 191 n1.linkDimension.down = GContext.BOX_DOWN; 192 } 193 194 dimension.addWidth(GContext.NODE_WIDTH+n1.linkDimension.width); 195 dimension.maxUp(n1.linkDimension.up); 196 dimension.maxDown(n1.linkDimension.down); 197 198 state = transition.target; 200 GNode n2 = createNode(state); 201 202 GLink link = new GLink(); 204 link.transition = transition; 205 link.target = n2; 206 n1.addLink(link); 207 208 if(state == endState) { 209 EOAInfo eoa = endOfAlternativeInfoMap.get(state); 212 if(eoa != null) { 213 link.setLast(eoa.last); 214 } 215 } 216 } else { 217 dimension.addWidth(GContext.NODE_WIDTH); 218 state = null; 219 } 220 } 221 return dimension; 222 } 223 224 public GDimension recursiveRenderSizeAlternative(FAState state) { 225 FAState alternativeEndState = alternativeEndState(state); 226 227 GNode norigin = createNode(state); 228 229 GDimension dimension = norigin.linkDimension; 230 dimension.addWidth(GContext.EPSILON_WIDTH); 231 232 GDimension firstTransitionDimension = null; 233 234 for(int t=0; t<state.getNumberOfTransitions(); t++) { 235 FATransition transition = state.transition(t); 236 237 GLink link = new GLink(); 238 link.transition = transition; 239 link.target = createNode(transition.target); 240 norigin.addLink(link); 241 242 boolean last = t == state.getNumberOfTransitions()-1; 243 if(t == state.getNumberOfTransitions()-2 && state.transition(t+1).loop) { 244 last = true; 248 } 249 250 link.setLast(last); 251 252 if(transition.target == alternativeEndState) { 253 GDimension transitionDimension = new GDimension(); 254 transitionDimension.addUp(GContext.EPSILON_UP); 255 transitionDimension.addDown(GContext.EPSILON_DOWN); 256 if(transition.loop) 257 transitionDimension.addDown(GContext.LINE_SPACE); 258 259 if(transition.loop) { 260 link.setBranchDimension(transitionDimension); 261 dimension.maxUp(firstTransitionDimension.up+transitionDimension.up+transitionDimension.down); 262 } else { 263 link.setBranchDimension(transitionDimension); 264 if(t == 0) 265 firstTransitionDimension = transitionDimension; 266 dimension.addDown(transitionDimension.up); 267 dimension.addDown(transitionDimension.down); 268 } 269 } else { 270 endOfAlternativeInfoMap.put(alternativeEndState, new EOAInfo(last)); 271 GDimension transitionDimension = recursiveRenderSizeSingle(transition.target, alternativeEndState); 272 273 if(((t > 0) || (t == 0 && !state.transition(1).loop)) && !last) 274 dimension.addDown(GContext.LINE_SPACE); 275 276 link.setBranchDimension(transitionDimension); 277 278 transitionDimension.addWidth(GContext.EPSILON_WIDTH); 279 dimension.maxWidth(transitionDimension.width); 280 if(t == 0) { 281 firstTransitionDimension = transitionDimension; 283 dimension.maxUp(transitionDimension.up); 285 dimension.addDown(transitionDimension.down); 286 } else { 287 dimension.addDown(transitionDimension.up); 288 dimension.addDown(transitionDimension.down); 289 } 290 } 291 } 292 return dimension; 293 } 294 295 public GNode createNode(FAState state) { 296 GNode node = getNode(state); 297 if(node == null) { 298 node = new GNode(); 299 node.setState(state); 300 graphicNodes.add(node); 301 nodes.put(state, node); 302 } 303 return node; 304 } 305 306 public GNode getNode(FAState state) { 307 return nodes.get(state); 308 } 309 310 public FAState alternativeEndState(FAState alt) { 311 int counter = 1; 312 FAState state = alt; 313 while(state != null) { 314 FATransition transition = state.getFirstTransition(); 315 if(transition == null) 316 break; 317 else 318 state = transition.target; 319 320 322 if(analysis.numberOfIncomingTransition(state)>1) { 323 counter--; 324 if(counter == 0) 325 break; 326 } 327 328 if(state.isAlternative()) 329 counter++; 330 } 331 return state; 332 } 333 334 private class EOAInfo { 335 public boolean last = false; 336 337 public EOAInfo(boolean last) { 338 this.last = last; 339 } 340 } 341 } 342 | Popular Tags |