├── .gitignore ├── README.md ├── graphs ├── exercise3.dot ├── exercise3.svg ├── exercise4.dot ├── killsequence.dot ├── livevariablestest.dot ├── simpleconditional.dot ├── simplesequence.dot └── stronglylivevariablestest.dot ├── graphviz.properties ├── lib └── commons-lang3-3.1.jar └── src └── ch └── yvu └── dfa ├── analysis ├── AnalysisStrategy.java ├── AvailableExpressionStrategy.java ├── BackwardStrategy.java ├── ConstantPropagationStrategy.java ├── DataFlowAnalysis.java ├── ForwardStrategy.java ├── LiveVariableStrategy.java ├── PreciseConstantPropagationStrategy.java ├── ReachingDefinitionsStrategy.java ├── State.java └── StronglyLiveVariableStrategy.java ├── controlflowgraph ├── AssignmentNode.java ├── ConditionalNode.java ├── ControlflowGraph.java └── Node.java ├── expressions ├── Expression.java ├── LabeledVariable.java ├── Number.java ├── NumberTop.java ├── Operation.java ├── StateExpression.java ├── Variable.java └── VariableToValue.java ├── gui ├── GraphViz.java └── MainFrame.java ├── main ├── Program.java └── Worker.java ├── parser ├── FormatException.java ├── dot │ └── SimpleDOTParser.java └── expression │ └── ExpressionParser.java ├── ressources └── icon.png └── tests ├── DOTParserTest.java ├── ExplorationalTests.java ├── ExpressionNodeTest.java ├── ExpressionParserTest.java └── NodeTest.java /.gitignore: -------------------------------------------------------------------------------- 1 | .project 2 | .classpath 3 | bin 4 | .settings -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Dafa Flow Analysis 2 | ================== 3 | 4 | A small tool which takes a control flow graph - described in the DOT/Graphviz format - as an input and executes the selected data flow analysis. 5 | As an output you receive an image of the control flow graph and the result of the executed data flow analysis (entry and exit sets of each program point). 6 | 7 | Available Data Flow Analysis 8 | ---------------------------- 9 | - Available Expressions: For each program point, which expressions must have already been computed and not later modified, on all paths to the program point 10 | - Live variables: For each program point, which variables may be live at the exit from the program point. A variable is live if its content will be read in some paths starting from the program point. 11 | - Strongly live variables: For each program point, which variables may be strongly live at the exit from the program point. A variable is strongly live, if it is live and it is not only used to calculate values of dead variables. 12 | - Reaching Definitions: For each program point, which assignments have been made and not overwritten, when program execution reaches this point along some path. 13 | - Constant Propagation: For each program point, whether or not a variable has a constant value, whenever execution reaches that point. 14 | - Precise constant propagation: The same as constant propagation. But it takes condition expressions into account. If a branch is never executed, this will be considered. 15 | 16 | Installation 17 | ---------------------------- 18 | 1. Download and compile the source 19 | 2. Install[Graphviz][graphviz] 20 | 3. Adapt the paths in graphviz.properties 21 | 22 | [graphviz]:http://www.graphviz.org -------------------------------------------------------------------------------- /graphs/exercise3.dot: -------------------------------------------------------------------------------- 1 | digraph Assignment1{ 2 | 1[label="a:=0"]; 3 | 2[label="x:=a+b"]; 4 | 3[label="x>a"]; 5 | 4[label="a==0"]; 6 | 5[label="z:=a*b"]; 7 | 6[label="x:=x-1"]; 8 | 7[label="x:=x"]; 9 | 8[label="a:=b+a"]; 10 | 11 | 1->2; 12 | 2->3; 13 | 3->4; 14 | 3->8; 15 | 4->5; 16 | 5->6; 17 | 6->3; 18 | 4->7; 19 | 7->3; 20 | } -------------------------------------------------------------------------------- /graphs/exercise3.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | Assignment1 11 | 12 | 13 | 1 14 | 15 | a:=0 16 | 17 | 18 | 2 19 | 20 | x:=a+b 21 | 22 | 23 | 1->2 24 | 25 | 26 | 27 | 28 | 3 29 | 30 | x>a 31 | 32 | 33 | 2->3 34 | 35 | 36 | 37 | 38 | 4 39 | 40 | a==0 41 | 42 | 43 | 3->4 44 | 45 | 46 | 47 | 48 | 8 49 | 50 | a:=b+a 51 | 52 | 53 | 3->8 54 | 55 | 56 | 57 | 58 | 5 59 | 60 | z:=a*b 61 | 62 | 63 | 4->5 64 | 65 | 66 | 67 | 68 | 7 69 | 70 | x:=x 71 | 72 | 73 | 4->7 74 | 75 | 76 | 77 | 78 | 6 79 | 80 | x:=x-1 81 | 82 | 83 | 5->6 84 | 85 | 86 | 87 | 88 | 6->3 89 | 90 | 91 | 92 | 93 | 7->3 94 | 95 | 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /graphs/exercise4.dot: -------------------------------------------------------------------------------- 1 | digraph Exercise4{ 2 | node[shape=box]; 3 | 1[label="1: a:=5"]; 4 | 2[label="2: b:=8"]; 5 | 3[label="3: a2; 13 | 2->3; 14 | 3->4; 15 | 4->6; 16 | 3->5; 17 | 5->6; 18 | 6->7; 19 | 7->6; 20 | 6->8; 21 | } -------------------------------------------------------------------------------- /graphs/killsequence.dot: -------------------------------------------------------------------------------- 1 | digraph KillSequence{ 2 | 1[label="x:=a+b"]; 3 | 2[label="a:=b*x"]; 4 | 3[label="x:=x+1"]; 5 | 6 | 1->2; 7 | } -------------------------------------------------------------------------------- /graphs/livevariablestest.dot: -------------------------------------------------------------------------------- 1 | digraph Test { 2 | 1[label="x:=a"]; 3 | 2[label="x:=a+b"]; 4 | 3[label="a:=3"]; 5 | 4[label="x:=c"]; 6 | 7 | 1->2; 8 | 2->3; 9 | 3->4; 10 | } -------------------------------------------------------------------------------- /graphs/simpleconditional.dot: -------------------------------------------------------------------------------- 1 | digraph SimpleConditional{ 2 | 1[label="x < a"]; 3 | 2[label="y:=a+b"]; 4 | 3[label="y:=a*b"]; 5 | 4[label="y:=2*y"]; 6 | 1->2; 7 | 1->3; 8 | 2->4; 9 | 3->4; 10 | } -------------------------------------------------------------------------------- /graphs/simplesequence.dot: -------------------------------------------------------------------------------- 1 | digraph Test{ 2 | 1[label="x:=a+b"]; 3 | 2[label="y:=a*b"]; 4 | 1->2; 5 | } -------------------------------------------------------------------------------- /graphs/stronglylivevariablestest.dot: -------------------------------------------------------------------------------- 1 | digraph StronglyLiveTest{ 2 | 1[label="x:=5"]; 3 | 2[label="x:=x"]; 4 | 3[label="x:=1"]; 5 | 6 | 1->2; 7 | 2->3; 8 | } 9 | 10 | digraph StronglyLiveTest{ 11 | 1[label="x:=5"]; 12 | 2[label="a:=x"]; 13 | 3[label="a==x"]; 14 | 4[label="b:=c"]; 15 | 5[label="c:=b"]; 16 | 6[label="d:=c"]; 17 | 18 | 1->2; 19 | 2->3; 20 | 3->4; 21 | 4->6; 22 | 3->5; 23 | 5->6; 24 | 25 | } -------------------------------------------------------------------------------- /graphviz.properties: -------------------------------------------------------------------------------- 1 | graphvizTempDir=c:/temp 2 | #graphvizTempDir=/tmp 3 | 4 | graphvizDOTBinary=C:/Program Files (x86)/Graphviz 2.28/bin/dot.exe 5 | #graphvizDOTBinary=/usr/bin/dot -------------------------------------------------------------------------------- /lib/commons-lang3-3.1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ybonjour/Data-Flow-Analysis/025c811d28221e66e084f7515b8e467a93ae4602/lib/commons-lang3-3.1.jar -------------------------------------------------------------------------------- /src/ch/yvu/dfa/analysis/AnalysisStrategy.java: -------------------------------------------------------------------------------- 1 | package ch.yvu.dfa.analysis; 2 | 3 | import java.util.Map; 4 | import java.util.Set; 5 | 6 | import ch.yvu.dfa.controlflowgraph.AssignmentNode; 7 | import ch.yvu.dfa.controlflowgraph.ConditionalNode; 8 | import ch.yvu.dfa.controlflowgraph.ControlflowGraph; 9 | import ch.yvu.dfa.controlflowgraph.Node; 10 | import ch.yvu.dfa.expressions.Expression; 11 | 12 | public abstract class AnalysisStrategy { 13 | 14 | public void applyStatement(Node node, Set incoming, Set outgoing){ 15 | node.applyStatement(incoming, outgoing, this); 16 | } 17 | 18 | public abstract int getIdOfInitialNode(ControlflowGraph graph) throws Exception; 19 | public abstract Set getInitializationOutgoing(ControlflowGraph graph); 20 | public abstract Set getInitializationIncoming(ControlflowGraph graph); 21 | 22 | public abstract void calculateIncoming(Node node, Set incoming, Map> outgoing, ControlflowGraph graph); 23 | 24 | public abstract Set selectEntry(Set outgoing, Set incoming); 25 | public abstract Set selectExit(Set outgoing, Set incoming); 26 | public abstract Set getNodesToRecalculate(Node changedNode, ControlflowGraph graph); 27 | 28 | public abstract void applyStatement(AssignmentNode node, Set incoming, Set outgoing); 29 | public abstract void applyStatement(ConditionalNode node, Set incoming, Set outgoing); 30 | } 31 | -------------------------------------------------------------------------------- /src/ch/yvu/dfa/analysis/AvailableExpressionStrategy.java: -------------------------------------------------------------------------------- 1 | package ch.yvu.dfa.analysis; 2 | 3 | import java.util.HashSet; 4 | import java.util.Map; 5 | import java.util.Set; 6 | 7 | import ch.yvu.dfa.controlflowgraph.AssignmentNode; 8 | import ch.yvu.dfa.controlflowgraph.ConditionalNode; 9 | import ch.yvu.dfa.controlflowgraph.ControlflowGraph; 10 | import ch.yvu.dfa.controlflowgraph.Node; 11 | import ch.yvu.dfa.expressions.Expression; 12 | 13 | public class AvailableExpressionStrategy extends ForwardStrategy{ 14 | 15 | public Set getInitializationOutgoing(ControlflowGraph graph){ 16 | return getAllExpressions(graph); 17 | } 18 | 19 | @Override 20 | public Set getInitializationIncoming(ControlflowGraph graph) { 21 | return new HashSet(); 22 | } 23 | 24 | @Override 25 | public void calculateIncoming(Node node, Set incomings, Map> outgoings, 26 | ControlflowGraph graph) { 27 | incomings.clear(); 28 | incomings.addAll(getAllExpressions(graph)); 29 | 30 | Set parents = graph.getParents(node); 31 | for (Node parent : parents) { 32 | incomings.retainAll(outgoings.get(parent)); 33 | } 34 | } 35 | 36 | private Set getAllExpressions(ControlflowGraph graph){ 37 | Set expressions = new HashSet(); 38 | for(Node node : graph.getNodes()){ 39 | expressions.add(node.getExpression()); 40 | } 41 | return expressions; 42 | } 43 | 44 | @Override 45 | public void applyStatement(AssignmentNode node, Set incoming, 46 | Set outgoing) { 47 | outgoing.clear(); 48 | outgoing.addAll(incoming); 49 | kill(node, outgoing, incoming); 50 | gen(node, outgoing, incoming); 51 | } 52 | 53 | @Override 54 | public void applyStatement(ConditionalNode node, Set incoming, 55 | Set outgoing) { 56 | outgoing.clear(); 57 | outgoing.addAll(incoming); 58 | kill(node, outgoing, incoming); 59 | gen(node, outgoing, incoming); 60 | } 61 | 62 | private void kill(AssignmentNode node, Set outgoing, Set incoming) { 63 | Set killExpressions = new HashSet(); 64 | for (Expression expression : outgoing) { 65 | if(expression.containsVariable(node.getLhs())){ 66 | killExpressions.add(expression); 67 | } 68 | } 69 | outgoing.removeAll(killExpressions); 70 | } 71 | 72 | private void kill(ConditionalNode node, Set outgoing, Set incoming) { 73 | //Nothing to kill 74 | } 75 | 76 | private void gen(AssignmentNode node, Set outgoing, Set incoming) { 77 | //Do not add the expressions if it contains a free variable, 78 | //that the expression is assigned to. 79 | //(allows for independent ordering between gen and kill operations) 80 | if(node.containsRightHandSideVariableInLeftHandSide()) return; 81 | 82 | if(!node.isComposedExpression()) return; 83 | 84 | outgoing.add(node.getRhs()); 85 | } 86 | 87 | private void gen(ConditionalNode node, Set outgoing, Set incoming) { 88 | outgoing.add(node.getExpression()); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/ch/yvu/dfa/analysis/BackwardStrategy.java: -------------------------------------------------------------------------------- 1 | package ch.yvu.dfa.analysis; 2 | 3 | import java.util.Set; 4 | 5 | import ch.yvu.dfa.controlflowgraph.ControlflowGraph; 6 | import ch.yvu.dfa.controlflowgraph.Node; 7 | import ch.yvu.dfa.expressions.Expression; 8 | 9 | public abstract class BackwardStrategy extends AnalysisStrategy { 10 | 11 | @Override 12 | public int getIdOfInitialNode(ControlflowGraph graph) throws Exception { 13 | return graph.getMaxId(); 14 | } 15 | 16 | @Override 17 | public Set selectEntry(Set outgoing, 18 | Set incoming) { 19 | return outgoing; 20 | } 21 | 22 | @Override 23 | public Set selectExit(Set outgoing, 24 | Set incoming) { 25 | return incoming; 26 | } 27 | 28 | @Override 29 | public Set getNodesToRecalculate(Node changedNode, ControlflowGraph graph) { 30 | return graph.getParents(changedNode); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/ch/yvu/dfa/analysis/ConstantPropagationStrategy.java: -------------------------------------------------------------------------------- 1 | package ch.yvu.dfa.analysis; 2 | 3 | import java.util.HashSet; 4 | import java.util.Iterator; 5 | import java.util.Map; 6 | import java.util.Set; 7 | 8 | import ch.yvu.dfa.controlflowgraph.AssignmentNode; 9 | import ch.yvu.dfa.controlflowgraph.ConditionalNode; 10 | import ch.yvu.dfa.controlflowgraph.ControlflowGraph; 11 | import ch.yvu.dfa.controlflowgraph.Node; 12 | import ch.yvu.dfa.expressions.Expression; 13 | import ch.yvu.dfa.expressions.NumberTop; 14 | import ch.yvu.dfa.expressions.StateExpression; 15 | import ch.yvu.dfa.expressions.Variable; 16 | import ch.yvu.dfa.expressions.VariableToValue; 17 | 18 | public class ConstantPropagationStrategy extends AnalysisStrategy { 19 | 20 | @Override 21 | public int getIdOfInitialNode(ControlflowGraph graph) throws Exception { 22 | return 1; 23 | } 24 | 25 | @Override 26 | public Set getInitializationOutgoing(ControlflowGraph graph) { 27 | HashSet initial = new HashSet(); 28 | initial.add(StateExpression.invalidSateExpression()); 29 | return initial; 30 | } 31 | 32 | @Override 33 | public Set getInitializationIncoming(ControlflowGraph graph) { 34 | HashSet initial = new HashSet(); 35 | initial.add(new StateExpression()); 36 | return initial; 37 | } 38 | 39 | @Override 40 | public void calculateIncoming(Node node, Set incoming, 41 | Map> outgoing, ControlflowGraph graph) { 42 | 43 | State mergedState = new State(); 44 | for(Node predecessor : graph.getParents(node)){ 45 | Set predecessorOutgoing = outgoing.get(predecessor); 46 | if(predecessorOutgoing.size() != 1) throw new RuntimeException("More than one expression"); 47 | State predecessorState = new State((StateExpression) predecessorOutgoing.toArray()[0]); 48 | 49 | Iterator varIt = predecessorState.variableIterator(); 50 | while(varIt.hasNext()){ 51 | Variable variable = varIt.next(); 52 | NumberTop nt; 53 | if(mergedState.containsVariable(variable) && mergedState.getValue(variable) != predecessorState.getValue(variable)){ 54 | nt = NumberTop.top(); 55 | } else { 56 | nt = predecessorState.getValue(variable); 57 | } 58 | mergedState.setVariable(variable, nt); 59 | } 60 | } 61 | 62 | incoming.clear(); 63 | incoming.add(mergedState.createStateExpression()); 64 | } 65 | 66 | @Override 67 | public Set selectEntry(Set outgoing, 68 | Set incoming) { 69 | return incoming; 70 | } 71 | 72 | @Override 73 | public Set selectExit(Set outgoing, 74 | Set incoming) { 75 | return outgoing; 76 | } 77 | 78 | @Override 79 | public Set getNodesToRecalculate(Node changedNode, 80 | ControlflowGraph graph) { 81 | Set set = new HashSet(); 82 | Iterator children = changedNode.childrenIterator(); 83 | while(children.hasNext()){ 84 | Node child = children.next(); 85 | set.add(child); 86 | } 87 | 88 | return set; 89 | } 90 | 91 | //requires: Set only contains VariableToValue Expressions 92 | public Set castExpressionSet(Set expressions){ 93 | Set resultSet = new HashSet(); 94 | for(Expression expression : expressions){ 95 | resultSet.add((VariableToValue) expression); 96 | } 97 | 98 | return resultSet; 99 | } 100 | 101 | 102 | @Override 103 | public void applyStatement(AssignmentNode node, Set incoming, 104 | Set outgoing) { 105 | 106 | //for constant propagation only one Expression can be tracked (state) 107 | if(incoming.size() != 1) throw new RuntimeException("More than one expression"); 108 | 109 | StateExpression incomingStateExpression = (StateExpression) incoming.toArray()[0]; 110 | StateExpression outgoingStateExpression; 111 | if(incomingStateExpression.isInvalid()){ 112 | outgoingStateExpression = StateExpression.invalidSateExpression(); 113 | } else { 114 | State state = new State(incomingStateExpression); 115 | NumberTop value = node.getRhs().evaluate(state); 116 | if(value == null) 117 | { 118 | outgoingStateExpression = StateExpression.invalidSateExpression(); 119 | } else { 120 | state.setVariable(node.getLhs(), value); 121 | outgoingStateExpression = state.createStateExpression(); 122 | } 123 | } 124 | 125 | outgoing.clear(); 126 | outgoing.add(outgoingStateExpression); 127 | } 128 | 129 | @Override 130 | public void applyStatement(ConditionalNode node, Set incoming, 131 | Set outgoing) { 132 | outgoing.clear(); 133 | outgoing.addAll(incoming); 134 | } 135 | 136 | } 137 | -------------------------------------------------------------------------------- /src/ch/yvu/dfa/analysis/DataFlowAnalysis.java: -------------------------------------------------------------------------------- 1 | package ch.yvu.dfa.analysis; 2 | 3 | import java.util.HashMap; 4 | import java.util.HashSet; 5 | import java.util.Iterator; 6 | import java.util.Map; 7 | import java.util.Set; 8 | import java.util.SortedSet; 9 | import java.util.TreeSet; 10 | 11 | import ch.yvu.dfa.controlflowgraph.ControlflowGraph; 12 | import ch.yvu.dfa.controlflowgraph.Node; 13 | import ch.yvu.dfa.expressions.Expression; 14 | 15 | import org.apache.commons.lang3.StringEscapeUtils; 16 | 17 | public class DataFlowAnalysis { 18 | private Map> incoming; 19 | private Map> outgoing; 20 | private ControlflowGraph graph; 21 | private AnalysisStrategy strategy; 22 | 23 | 24 | public DataFlowAnalysis(ControlflowGraph graph, AnalysisStrategy strategy){ 25 | this.incoming = new HashMap>(); 26 | this.outgoing = new HashMap>(); 27 | this.graph = graph; 28 | this.strategy = strategy; 29 | } 30 | 31 | private void initializeAllOutgoing(){ 32 | Set initSet = this.strategy.getInitializationOutgoing(this.graph); 33 | for(Node node : graph.getNodes()){ 34 | this.outgoing.put(node, new HashSet(initSet)); 35 | } 36 | } 37 | 38 | public String analyse(){ 39 | this.outgoing.clear(); 40 | this.incoming.clear(); 41 | 42 | initializeAllOutgoing(); 43 | 44 | int initId; 45 | try 46 | { 47 | initId = this.strategy.getIdOfInitialNode(this.graph); 48 | }catch(Exception e){ 49 | throw new RuntimeException(e); 50 | } 51 | 52 | Set changed = new HashSet(graph.getNodes()); 53 | Node initialNode = graph.getNode(initId); 54 | Set initialSetIncoming = this.strategy.getInitializationIncoming(this.graph); 55 | this.incoming.put(initialNode, initialSetIncoming); 56 | this.strategy.applyStatement(initialNode, this.incoming.get(initialNode), this.outgoing.get(initialNode)); 57 | changed.remove(initialNode); 58 | 59 | while(!changed.isEmpty()){ 60 | Node currentNode = getAnyNode(changed); 61 | assert(currentNode != null); 62 | changed.remove(currentNode); 63 | 64 | calculateIncoming(currentNode); 65 | 66 | Set oldOutgoing = new HashSet(this.outgoing.get(currentNode)); 67 | this.strategy.applyStatement(currentNode, this.incoming.get(currentNode), this.outgoing.get(currentNode)); 68 | 69 | if(!this.outgoing.get(currentNode).equals(oldOutgoing)){ 70 | changed.addAll(this.strategy.getNodesToRecalculate(currentNode, this.graph)); 71 | } 72 | } 73 | 74 | return getExpressionsHTML(); 75 | } 76 | 77 | private void calculateIncoming(Node currentNode){ 78 | if(this.incoming.get(currentNode) == null){ 79 | this.incoming.put(currentNode, new HashSet()); 80 | } 81 | this.strategy.calculateIncoming(currentNode, this.incoming.get(currentNode), this.outgoing, this.graph); 82 | } 83 | 84 | private String setToString(Set set){ 85 | String output = "{"; 86 | boolean first = true; 87 | for(Expression expr : set){ 88 | if(!first){ 89 | output += ", "; 90 | } 91 | 92 | output += expr.getExpression(); 93 | 94 | first = false; 95 | } 96 | 97 | return output + "}"; 98 | } 99 | 100 | private String getExpressionsHTML(){ 101 | SortedSet sortedNodes = new TreeSet(); 102 | sortedNodes.addAll(this.graph.getNodes()); 103 | 104 | String output = ""; 105 | 106 | for(Node node : sortedNodes){ 107 | output += ""; 112 | } 113 | 114 | output += "
" + node.getId() + "" + StringEscapeUtils.escapeHtml4(node.getStatement()) + ""; 108 | output += StringEscapeUtils.escapeHtml4(setToString(this.strategy.selectEntry(this.outgoing.get(node), this.incoming.get(node)))); 109 | output += ""; 110 | output += StringEscapeUtils.escapeHtml4(setToString(this.strategy.selectExit(this.outgoing.get(node), this.incoming.get(node)))); 111 | output += "
"; 115 | return output; 116 | } 117 | 118 | private static Node getAnyNode(Set nodes){ 119 | Iterator it = nodes.iterator(); 120 | return it.hasNext() ? it.next() : null; 121 | } 122 | } -------------------------------------------------------------------------------- /src/ch/yvu/dfa/analysis/ForwardStrategy.java: -------------------------------------------------------------------------------- 1 | package ch.yvu.dfa.analysis; 2 | 3 | import java.util.HashSet; 4 | import java.util.Iterator; 5 | import java.util.Set; 6 | 7 | import ch.yvu.dfa.controlflowgraph.ControlflowGraph; 8 | import ch.yvu.dfa.controlflowgraph.Node; 9 | import ch.yvu.dfa.expressions.Expression; 10 | 11 | public abstract class ForwardStrategy extends AnalysisStrategy { 12 | 13 | @Override 14 | public int getIdOfInitialNode(ControlflowGraph graph) throws Exception { 15 | return 1; 16 | } 17 | 18 | @Override 19 | public Set selectEntry(Set outgoing, Set incoming) { 20 | return incoming; 21 | } 22 | 23 | @Override 24 | public Set selectExit(Set outgoing, Set incoming) { 25 | return outgoing; 26 | } 27 | 28 | @Override 29 | public Set getNodesToRecalculate(Node changedNode, ControlflowGraph graph) { 30 | Set set = new HashSet(); 31 | Iterator children = changedNode.childrenIterator(); 32 | while(children.hasNext()){ 33 | Node child = children.next(); 34 | set.add(child); 35 | } 36 | 37 | return set; 38 | } 39 | 40 | } -------------------------------------------------------------------------------- /src/ch/yvu/dfa/analysis/LiveVariableStrategy.java: -------------------------------------------------------------------------------- 1 | package ch.yvu.dfa.analysis; 2 | 3 | import java.util.HashSet; 4 | import java.util.Iterator; 5 | import java.util.Map; 6 | import java.util.Set; 7 | 8 | import ch.yvu.dfa.controlflowgraph.AssignmentNode; 9 | import ch.yvu.dfa.controlflowgraph.ConditionalNode; 10 | import ch.yvu.dfa.controlflowgraph.ControlflowGraph; 11 | import ch.yvu.dfa.controlflowgraph.Node; 12 | import ch.yvu.dfa.expressions.Expression; 13 | import ch.yvu.dfa.expressions.Variable; 14 | 15 | public class LiveVariableStrategy extends BackwardStrategy { 16 | 17 | @Override 18 | public Set getInitializationOutgoing(ControlflowGraph graph) { 19 | return new HashSet(); 20 | } 21 | 22 | @Override 23 | public Set getInitializationIncoming(ControlflowGraph graph) { 24 | return new HashSet(); 25 | } 26 | 27 | @Override 28 | public void calculateIncoming(Node node, Set incoming, 29 | Map> outgoing, ControlflowGraph graph) { 30 | //Start with empty set 31 | incoming.clear(); 32 | Iterator itChildren = node.childrenIterator(); 33 | while(itChildren.hasNext()){ 34 | Node child = itChildren.next(); 35 | incoming.addAll(outgoing.get(child)); 36 | } 37 | } 38 | 39 | @Override 40 | public void applyStatement(AssignmentNode node, Set incoming, 41 | Set outgoing) { 42 | outgoing.clear(); 43 | outgoing.addAll(incoming); 44 | kill(node, outgoing, incoming); 45 | gen(node, outgoing, incoming); 46 | } 47 | 48 | @Override 49 | public void applyStatement(ConditionalNode node, Set incoming, 50 | Set outgoing) { 51 | outgoing.clear(); 52 | outgoing.addAll(incoming); 53 | kill(node, outgoing, incoming); 54 | gen(node, outgoing, incoming); 55 | } 56 | 57 | private void kill(AssignmentNode node, Set outgoing, Set incoming) { 58 | outgoing.remove(node.getLhs()); 59 | } 60 | 61 | private void kill(ConditionalNode node, Set outgoing, Set incoming) { 62 | //nothing to kill 63 | 64 | } 65 | 66 | private void gen(AssignmentNode node, Set outgoing, Set incoming) { 67 | for(Variable freeVariable : node.getFreeVariablesRhs()){ 68 | outgoing.add(freeVariable); 69 | } 70 | } 71 | 72 | private void gen(ConditionalNode node, Set outgoing, Set incoming) { 73 | for(Variable freeVariable : node.getFreeVariables()){ 74 | outgoing.add(freeVariable); 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/ch/yvu/dfa/analysis/PreciseConstantPropagationStrategy.java: -------------------------------------------------------------------------------- 1 | package ch.yvu.dfa.analysis; 2 | 3 | import java.util.Set; 4 | 5 | import ch.yvu.dfa.controlflowgraph.ConditionalNode; 6 | import ch.yvu.dfa.expressions.Expression; 7 | import ch.yvu.dfa.expressions.NumberTop; 8 | import ch.yvu.dfa.expressions.Variable; 9 | import ch.yvu.dfa.expressions.StateExpression; 10 | 11 | public class PreciseConstantPropagationStrategy extends ConstantPropagationStrategy { 12 | // private Set internalConditionalVariables; 13 | // 14 | // public PreciseConstantPropagationStrategy(){ 15 | // this.internalConditionalVariables = new HashSet(); 16 | // } 17 | 18 | @Override 19 | public void applyStatement(ConditionalNode node, Set incoming, 20 | Set outgoing) { 21 | 22 | //for constant propagation only one Expression can be tracked (state) 23 | if(incoming.size() != 1) throw new RuntimeException("More than one expression"); 24 | 25 | StateExpression incomingStateExpression = (StateExpression) incoming.toArray()[0]; 26 | State state = new State(incomingStateExpression); 27 | 28 | StateExpression outgoingStateExpresssion; 29 | NumberTop nt = node.getExpression().evaluate(state); 30 | if(nt != null){ 31 | Variable conditionalVariable = new Variable("b" + node.getId()); 32 | state.setVariable(conditionalVariable, nt); 33 | outgoingStateExpresssion = state.createStateExpression(); 34 | } else { 35 | outgoingStateExpresssion = StateExpression.invalidSateExpression(); 36 | } 37 | 38 | outgoing.clear(); 39 | outgoing.add(outgoingStateExpresssion); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/ch/yvu/dfa/analysis/ReachingDefinitionsStrategy.java: -------------------------------------------------------------------------------- 1 | package ch.yvu.dfa.analysis; 2 | 3 | import java.util.HashSet; 4 | import java.util.Map; 5 | import java.util.Set; 6 | 7 | import ch.yvu.dfa.controlflowgraph.AssignmentNode; 8 | import ch.yvu.dfa.controlflowgraph.ConditionalNode; 9 | import ch.yvu.dfa.controlflowgraph.ControlflowGraph; 10 | import ch.yvu.dfa.controlflowgraph.Node; 11 | import ch.yvu.dfa.expressions.LabeledVariable; 12 | import ch.yvu.dfa.expressions.Expression; 13 | 14 | public class ReachingDefinitionsStrategy extends ForwardStrategy { 15 | 16 | public Set getInitializationOutgoing(ControlflowGraph graph){ 17 | return new HashSet(); 18 | } 19 | 20 | @Override 21 | public Set getInitializationIncoming(ControlflowGraph graph) { 22 | return new HashSet(); 23 | } 24 | 25 | @Override 26 | public void calculateIncoming(Node node, Set incoming, 27 | Map> outgoings, ControlflowGraph graph) { 28 | incoming.clear(); 29 | Set parents = graph.getParents(node); 30 | for (Node parent : parents) { 31 | incoming.addAll(outgoings.get(parent)); 32 | } 33 | } 34 | 35 | @Override 36 | public void applyStatement(AssignmentNode node, Set incoming, 37 | Set outgoing) { 38 | outgoing.clear(); 39 | outgoing.addAll(incoming); 40 | kill(node, outgoing, incoming); 41 | gen(node, outgoing, incoming); 42 | } 43 | 44 | @Override 45 | public void applyStatement(ConditionalNode node, Set incoming, 46 | Set outgoing) { 47 | outgoing.clear(); 48 | outgoing.addAll(incoming); 49 | kill(node, outgoing, incoming); 50 | gen(node, outgoing, incoming); 51 | } 52 | 53 | private void kill(AssignmentNode node, Set outgoing, Set incoming) { 54 | Set killExpressions = new HashSet(); 55 | for (Expression expression : outgoing) { 56 | if(expression.containsVariable(node.getLhs())){ 57 | killExpressions.add(expression); 58 | } 59 | } 60 | outgoing.removeAll(killExpressions); 61 | } 62 | 63 | private void kill(ConditionalNode node, Set outgoing, Set incoming) { 64 | //Nothing to kill 65 | } 66 | 67 | private void gen(AssignmentNode node, Set outgoing, Set incoming) { 68 | outgoing.add(new LabeledVariable(node.getId(), node.getLhs())); 69 | } 70 | 71 | private void gen(ConditionalNode node, Set outgoing, Set incoming) { 72 | //Nothing to generate 73 | } 74 | } -------------------------------------------------------------------------------- /src/ch/yvu/dfa/analysis/State.java: -------------------------------------------------------------------------------- 1 | package ch.yvu.dfa.analysis; 2 | 3 | import java.util.ArrayList; 4 | import java.util.HashMap; 5 | import java.util.Iterator; 6 | import java.util.List; 7 | import java.util.Map; 8 | 9 | import ch.yvu.dfa.expressions.Variable; 10 | import ch.yvu.dfa.expressions.VariableToValue; 11 | import ch.yvu.dfa.expressions.NumberTop; 12 | import ch.yvu.dfa.expressions.StateExpression; 13 | 14 | public class State { 15 | 16 | //Expression must be a number or Bottom / Top 17 | private Map variables; 18 | 19 | public State(){ 20 | this.variables = new HashMap(); 21 | } 22 | 23 | public State(StateExpression stateExpression){ 24 | this(); 25 | for(VariableToValue expression : stateExpression.getExpressions()){ 26 | if(this.variables.containsKey(expression.getVariable())) throw new IllegalArgumentException(); 27 | this.variables.put(expression.getVariable(), expression.getValue()); 28 | } 29 | } 30 | 31 | public boolean containsVariable(Variable variable){ 32 | return this.variables.containsKey(variable); 33 | } 34 | 35 | public void setVariable(Variable variable, NumberTop number){ 36 | this.variables.put(variable, number); 37 | } 38 | 39 | public NumberTop getValue(Variable variable){ 40 | return this.variables.get(variable); 41 | } 42 | 43 | public Iterator variableIterator(){ 44 | return this.variables.keySet().iterator(); 45 | } 46 | 47 | public StateExpression createStateExpression(){ 48 | List variableList = new ArrayList(); 49 | for(Variable var : this.variables.keySet()){ 50 | NumberTop nt = this.variables.get(var); 51 | if(nt == null){ 52 | throw new RuntimeException(); 53 | } 54 | VariableToValue varToVal = new VariableToValue(var, nt); 55 | variableList.add(varToVal); 56 | } 57 | 58 | return new StateExpression(variableList); 59 | } 60 | } -------------------------------------------------------------------------------- /src/ch/yvu/dfa/analysis/StronglyLiveVariableStrategy.java: -------------------------------------------------------------------------------- 1 | package ch.yvu.dfa.analysis; 2 | 3 | import java.util.HashSet; 4 | import java.util.Iterator; 5 | import java.util.Map; 6 | import java.util.Set; 7 | 8 | import ch.yvu.dfa.controlflowgraph.AssignmentNode; 9 | import ch.yvu.dfa.controlflowgraph.ConditionalNode; 10 | import ch.yvu.dfa.controlflowgraph.ControlflowGraph; 11 | import ch.yvu.dfa.controlflowgraph.Node; 12 | import ch.yvu.dfa.expressions.Variable; 13 | import ch.yvu.dfa.expressions.Expression; 14 | 15 | public class StronglyLiveVariableStrategy extends BackwardStrategy { 16 | 17 | @Override 18 | public Set getInitializationOutgoing(ControlflowGraph graph) { 19 | return new HashSet(); 20 | } 21 | 22 | @Override 23 | public Set getInitializationIncoming(ControlflowGraph graph) { 24 | return new HashSet(); 25 | } 26 | 27 | @Override 28 | public void calculateIncoming(Node node, Set incoming, 29 | Map> outgoing, ControlflowGraph graph) { 30 | //Start with empty set 31 | incoming.clear(); 32 | Iterator itChildren = node.childrenIterator(); 33 | while(itChildren.hasNext()){ 34 | Node child = itChildren.next(); 35 | incoming.addAll(outgoing.get(child)); 36 | } 37 | } 38 | 39 | @Override 40 | public void applyStatement(AssignmentNode node, Set incoming, 41 | Set outgoing) { 42 | outgoing.clear(); 43 | outgoing.addAll(incoming); 44 | kill(node, outgoing, incoming); 45 | gen(node, outgoing, incoming); 46 | } 47 | 48 | @Override 49 | public void applyStatement(ConditionalNode node, Set incoming, 50 | Set outgoing) { 51 | outgoing.clear(); 52 | outgoing.addAll(incoming); 53 | kill(node, outgoing, incoming); 54 | gen(node, outgoing, incoming); 55 | } 56 | 57 | 58 | private void kill(AssignmentNode node, Set outgoing, Set incoming) { 59 | outgoing.remove(node.getLhs()); 60 | } 61 | 62 | private void kill(ConditionalNode node, Set outgoing, Set incoming) { 63 | //nothing to kill 64 | 65 | } 66 | 67 | private void gen(AssignmentNode node, Set outgoing, Set incoming) { 68 | //strongly live means, we do not consider reads that are assigned to a variable 69 | //which is later on never read (-> which is not live at the exit point 70 | // (exit point = incoming because it is a backward analysis)) 71 | if(!incoming.contains(node.getLhs())) return; 72 | 73 | for(Variable freeVariable : node.getFreeVariablesRhs()){ 74 | outgoing.add(freeVariable); 75 | } 76 | } 77 | 78 | private void gen(ConditionalNode node, Set outgoing, Set incoming) { 79 | for(Variable freeVariable : node.getFreeVariables()){ 80 | outgoing.add(freeVariable); 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/ch/yvu/dfa/controlflowgraph/AssignmentNode.java: -------------------------------------------------------------------------------- 1 | package ch.yvu.dfa.controlflowgraph; 2 | 3 | import java.util.Set; 4 | 5 | import ch.yvu.dfa.analysis.AnalysisStrategy; 6 | import ch.yvu.dfa.expressions.Expression; 7 | import ch.yvu.dfa.expressions.Variable; 8 | 9 | public class AssignmentNode extends Node { 10 | 11 | private Variable lhs; 12 | private Expression rhs; 13 | 14 | public AssignmentNode(int id, Variable lhs, Expression rhs){ 15 | super(id); 16 | this.lhs = lhs; 17 | this.rhs = rhs; 18 | } 19 | 20 | @Override 21 | public void applyStatement(Set incoming, 22 | Set outgoing, AnalysisStrategy strategy) { 23 | strategy.applyStatement(this, incoming, outgoing); 24 | } 25 | 26 | @Override 27 | public Expression getExpression() { 28 | return this.rhs; 29 | } 30 | 31 | public Variable getLhs() { 32 | return lhs; 33 | } 34 | 35 | public Expression getRhs() { 36 | return rhs; 37 | } 38 | 39 | public boolean isComposedExpression(){ 40 | return this.rhs.isComposed(); 41 | } 42 | 43 | @Override 44 | public String getStatement() { 45 | return this.lhs.getExpression() + ":=" + this.rhs.getExpression(); 46 | } 47 | 48 | public Set getFreeVariablesRhs(){ 49 | return this.rhs.getFreeVariables(); 50 | } 51 | 52 | public boolean containsRightHandSideVariableInLeftHandSide(){ 53 | return this.rhs.containsVariable(this.lhs); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/ch/yvu/dfa/controlflowgraph/ConditionalNode.java: -------------------------------------------------------------------------------- 1 | package ch.yvu.dfa.controlflowgraph; 2 | 3 | import java.util.HashSet; 4 | import java.util.Set; 5 | 6 | import ch.yvu.dfa.analysis.AnalysisStrategy; 7 | import ch.yvu.dfa.expressions.Expression; 8 | import ch.yvu.dfa.expressions.Variable; 9 | import ch.yvu.dfa.expressions.Operation; 10 | 11 | public class ConditionalNode extends Node{ 12 | 13 | private Expression rhs; 14 | private Expression lhs; 15 | private String operator; 16 | 17 | 18 | public ConditionalNode(int id, Expression lhs, Expression rhs, String operator){ 19 | super(id); 20 | this.rhs = rhs; 21 | this.lhs = lhs; 22 | this.operator = operator; 23 | } 24 | 25 | @Override 26 | public void applyStatement(Set incoming, 27 | Set outgoing, AnalysisStrategy strategy) { 28 | strategy.applyStatement(this, incoming, outgoing); 29 | } 30 | 31 | @Override 32 | public Expression getExpression() { 33 | return new Operation(lhs, rhs, this.operator); 34 | } 35 | 36 | @Override 37 | public String getStatement() { 38 | return lhs.getExpression() + " " + operator + " " + rhs.getExpression(); 39 | } 40 | 41 | public Set getFreeVariables(){ 42 | Set freeVariables = new HashSet(); 43 | freeVariables.addAll(this.rhs.getFreeVariables()); 44 | freeVariables.addAll(this.lhs.getFreeVariables()); 45 | return freeVariables; 46 | } 47 | } -------------------------------------------------------------------------------- /src/ch/yvu/dfa/controlflowgraph/ControlflowGraph.java: -------------------------------------------------------------------------------- 1 | package ch.yvu.dfa.controlflowgraph; 2 | 3 | import java.util.HashMap; 4 | import java.util.HashSet; 5 | import java.util.Map; 6 | import java.util.Set; 7 | 8 | import ch.yvu.dfa.expressions.Expression; 9 | import ch.yvu.dfa.expressions.Variable; 10 | 11 | public class ControlflowGraph { 12 | 13 | private Map nodes; 14 | 15 | public ControlflowGraph(){ 16 | this.nodes = new HashMap(); 17 | } 18 | 19 | public Node getNode(int id){ 20 | return this.nodes.get(id); 21 | } 22 | 23 | public AssignmentNode createAssignmentNode(int id, Variable lhs, Expression rhs) throws Exception{ 24 | if(this.nodes.containsKey(id)) throw new Exception("Node already exists"); 25 | 26 | AssignmentNode node = new AssignmentNode(id, lhs, rhs); 27 | this.nodes.put(id, node); 28 | 29 | return node; 30 | } 31 | 32 | public ConditionalNode createConditionalNode(int id, Expression lhs, Expression rhs, String operation) throws Exception { 33 | if(this.nodes.containsKey(id)) throw new Exception("Node already exists"); 34 | 35 | ConditionalNode node = new ConditionalNode(id, lhs, rhs, operation); 36 | this.nodes.put(id, node); 37 | return node; 38 | } 39 | 40 | public void addEdge(int fromId, int toId) throws Exception{ 41 | if(!this.nodes.containsKey(fromId) || !this.nodes.containsKey(toId)) throw new Exception(fromId + " or " + toId + " does not exist"); 42 | 43 | this.nodes.get(fromId).addChild(this.nodes.get(toId)); 44 | } 45 | 46 | public int numChildren(Node node){ 47 | return node.numChildren(); 48 | } 49 | 50 | public Set getNodes(){ 51 | Set nodeSet = new HashSet(); 52 | for(Node node : this.nodes.values()){ 53 | nodeSet.add(node); 54 | } 55 | return nodeSet; 56 | } 57 | 58 | public Set getParents(Node node){ 59 | Set parents = new HashSet(); 60 | for(Node paretnCandidate : this.nodes.values()){ 61 | if(paretnCandidate.hasChild(node)){ 62 | parents.add(paretnCandidate); 63 | } 64 | } 65 | return parents; 66 | } 67 | 68 | public int getMaxId() { 69 | int maxId = -1; 70 | for(int key : this.nodes.keySet()){ 71 | if(key > maxId){ 72 | maxId = key; 73 | } 74 | } 75 | 76 | return maxId; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/ch/yvu/dfa/controlflowgraph/Node.java: -------------------------------------------------------------------------------- 1 | package ch.yvu.dfa.controlflowgraph; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Iterator; 5 | import java.util.List; 6 | import java.util.Set; 7 | 8 | import ch.yvu.dfa.analysis.AnalysisStrategy; 9 | import ch.yvu.dfa.expressions.Expression; 10 | 11 | public abstract class Node implements Comparable { 12 | private List children; 13 | private int id; 14 | 15 | public Node(int id){ 16 | this.children = new ArrayList(); 17 | this.id = id; 18 | } 19 | 20 | public void addChild(Node n){ 21 | if(n == null) throw new IllegalArgumentException(); 22 | if(this.children.contains(n)) return; 23 | 24 | this.children.add(n); 25 | } 26 | 27 | public boolean hasChild(Node node){ 28 | return this.children.contains(node); 29 | } 30 | 31 | public int numChildren(){ 32 | return this.children.size(); 33 | } 34 | 35 | public Iterator childrenIterator(){ 36 | return this.children.iterator(); 37 | } 38 | 39 | public int getId(){ 40 | return id; 41 | } 42 | 43 | public String toString(){ 44 | return this.id + ": " + getStatement(); 45 | } 46 | 47 | @Override 48 | public int compareTo(Node node) { 49 | return this.getId() - node.getId(); 50 | } 51 | 52 | public abstract Expression getExpression(); 53 | public abstract String getStatement(); 54 | public abstract void applyStatement(Set incoming, Set outgoing, AnalysisStrategy strategy); 55 | } -------------------------------------------------------------------------------- /src/ch/yvu/dfa/expressions/Expression.java: -------------------------------------------------------------------------------- 1 | package ch.yvu.dfa.expressions; 2 | 3 | import java.util.Set; 4 | import ch.yvu.dfa.analysis.State; 5 | 6 | public abstract class Expression { 7 | 8 | public abstract boolean containsVariable(Variable name); 9 | 10 | public abstract String getExpression(); 11 | 12 | public abstract Set getFreeVariables(); 13 | 14 | public abstract boolean isComposed(); 15 | 16 | public abstract NumberTop evaluate(State state); 17 | 18 | @Override 19 | public boolean equals(Object obj) { 20 | if(obj == null) return false; 21 | if(!(obj instanceof Expression)) return false; 22 | Expression expression = (Expression) obj; 23 | return this.getExpression().compareTo(expression.getExpression()) == 0; 24 | } 25 | 26 | @Override 27 | public int hashCode() { 28 | return this.getExpression().hashCode(); 29 | } 30 | } -------------------------------------------------------------------------------- /src/ch/yvu/dfa/expressions/LabeledVariable.java: -------------------------------------------------------------------------------- 1 | package ch.yvu.dfa.expressions; 2 | 3 | import java.util.HashSet; 4 | import java.util.Set; 5 | 6 | import ch.yvu.dfa.analysis.State; 7 | 8 | public class LabeledVariable extends Expression{ 9 | 10 | private int id; 11 | private Variable variable; 12 | 13 | public LabeledVariable(int id, Variable variable){ 14 | this.id = id; 15 | this.variable = variable; 16 | } 17 | 18 | @Override 19 | public boolean containsVariable(Variable variable) { 20 | return this.variable.containsVariable(variable); 21 | } 22 | 23 | @Override 24 | public String getExpression() { 25 | return "(" + this.variable.getExpression() + ", " + this.id + ")"; 26 | } 27 | 28 | @Override 29 | public Set getFreeVariables() { 30 | Set freeVariables = new HashSet(); 31 | freeVariables.add(this.variable); 32 | return freeVariables; 33 | } 34 | 35 | @Override 36 | public boolean isComposed() { 37 | return true; 38 | } 39 | 40 | @Override 41 | public NumberTop evaluate(State state) { 42 | throw new RuntimeException(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/ch/yvu/dfa/expressions/Number.java: -------------------------------------------------------------------------------- 1 | package ch.yvu.dfa.expressions; 2 | 3 | import java.util.HashSet; 4 | import java.util.Set; 5 | 6 | import ch.yvu.dfa.analysis.State; 7 | 8 | public class Number extends Expression { 9 | 10 | private int number; 11 | 12 | public Number(int number){ 13 | this.number = number; 14 | } 15 | 16 | @Override 17 | public boolean containsVariable(Variable name) { 18 | return false; 19 | } 20 | 21 | @Override 22 | public String getExpression() { 23 | return String.valueOf(this.number); 24 | } 25 | 26 | @Override 27 | public Set getFreeVariables() { 28 | return new HashSet(); 29 | } 30 | 31 | @Override 32 | public boolean isComposed() { 33 | return false; 34 | } 35 | 36 | @Override 37 | public NumberTop evaluate(State state) { 38 | return NumberTop.number(this.number); 39 | } 40 | 41 | public int value(){ 42 | return this.number; 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/ch/yvu/dfa/expressions/NumberTop.java: -------------------------------------------------------------------------------- 1 | package ch.yvu.dfa.expressions; 2 | 3 | import java.util.HashSet; 4 | import java.util.Set; 5 | 6 | import ch.yvu.dfa.analysis.State; 7 | 8 | public class NumberTop extends Expression { 9 | 10 | //If number is null -> Expression is Top 11 | private Number number; 12 | 13 | private NumberTop(){ 14 | } 15 | 16 | public static NumberTop number(int number){ 17 | NumberTop nt = new NumberTop(); 18 | nt.number = new Number(number); 19 | return nt; 20 | } 21 | 22 | public static NumberTop top(){ 23 | NumberTop nt = new NumberTop(); 24 | nt.number = null; 25 | return nt; 26 | } 27 | 28 | public static NumberTop booleanValue(boolean value){ 29 | return NumberTop.number(value ? 1 : 0); 30 | } 31 | 32 | public int number(){ 33 | if(this.number == null) throw new RuntimeException("invalid state"); 34 | return this.number.value(); 35 | } 36 | 37 | public boolean isTop(){ 38 | return this.number == null; 39 | } 40 | 41 | @Override 42 | public boolean equals(Object obj) { 43 | if(obj == null) return false; 44 | if(!(obj instanceof NumberTop)) return false; 45 | NumberTop nt = (NumberTop) obj; 46 | 47 | if(this.number == null || nt.number == null){ 48 | return this.number == nt.number; 49 | } 50 | 51 | return this.number.equals(nt.number); 52 | } 53 | 54 | @Override 55 | public int hashCode() { 56 | return this.number.hashCode(); 57 | } 58 | 59 | @Override 60 | public boolean containsVariable(Variable name) { 61 | return false; 62 | } 63 | 64 | @Override 65 | public String getExpression() { 66 | return this.number != null ? this.number.getExpression() : "T"; 67 | } 68 | 69 | @Override 70 | public Set getFreeVariables() { 71 | return new HashSet(); 72 | } 73 | 74 | @Override 75 | public boolean isComposed() { 76 | return false; 77 | } 78 | 79 | @Override 80 | public NumberTop evaluate(State state) { 81 | return this; 82 | } 83 | 84 | public NumberTop add(NumberTop nt){ 85 | if(this.isTop() || nt.isTop()) return NumberTop.top(); 86 | 87 | return NumberTop.number(this.number() + nt.number()); 88 | } 89 | 90 | public NumberTop subtract(NumberTop nt){ 91 | if(this.isTop() || nt.isTop()) return NumberTop.top(); 92 | 93 | return NumberTop.number(this.number() - nt.number()); 94 | } 95 | 96 | public NumberTop multiply(NumberTop nt){ 97 | if(this.isTop() || nt.isTop()) return NumberTop.top(); 98 | 99 | return NumberTop.number(this.number() * nt.number()); 100 | } 101 | 102 | public NumberTop greaterThan(NumberTop nt){ 103 | if(this.isTop() || nt.isTop()) return NumberTop.top(); 104 | return NumberTop.booleanValue(this.number() > nt.number()); 105 | } 106 | 107 | public NumberTop greaterOrEqualThan(NumberTop nt){ 108 | if(this.isTop() || nt.isTop()) return NumberTop.top(); 109 | return NumberTop.booleanValue(this.number() >= nt.number()); 110 | } 111 | 112 | public NumberTop smallerThan(NumberTop nt){ 113 | if(this.isTop() || nt.isTop()) return NumberTop.top(); 114 | return NumberTop.booleanValue(this.number() < nt.number()); 115 | } 116 | 117 | public NumberTop smallerOrEqualThan(NumberTop nt){ 118 | if(this.isTop() || nt.isTop()) return NumberTop.top(); 119 | return NumberTop.booleanValue(this.number() <= nt.number()); 120 | } 121 | 122 | public NumberTop equalTo(NumberTop nt){ 123 | if(this.isTop() || nt.isTop()) return NumberTop.top(); 124 | return NumberTop.booleanValue(this.number() == nt.number()); 125 | } 126 | } -------------------------------------------------------------------------------- /src/ch/yvu/dfa/expressions/Operation.java: -------------------------------------------------------------------------------- 1 | package ch.yvu.dfa.expressions; 2 | 3 | import java.util.HashSet; 4 | import java.util.Set; 5 | 6 | import ch.yvu.dfa.analysis.State; 7 | 8 | public class Operation extends Expression { 9 | 10 | private Expression leftOperand; 11 | private Expression rightOperand; 12 | private String operation; 13 | 14 | public Operation(Expression leftOperand, Expression rightOperand, String operation){ 15 | this.leftOperand = leftOperand; 16 | this.rightOperand = rightOperand; 17 | this.operation = operation; 18 | } 19 | 20 | public boolean containsVariable(Variable variable){ 21 | return this.leftOperand.containsVariable(variable) || this.rightOperand.containsVariable(variable); 22 | } 23 | 24 | @Override 25 | public String getExpression() { 26 | return this.leftOperand.getExpression() + " " + this.operation + " " + this.rightOperand.getExpression(); 27 | } 28 | 29 | @Override 30 | public Set getFreeVariables() { 31 | HashSet freeVariables = new HashSet(); 32 | freeVariables.addAll(this.leftOperand.getFreeVariables()); 33 | freeVariables.addAll(this.rightOperand.getFreeVariables()); 34 | return freeVariables; 35 | } 36 | 37 | @Override 38 | public boolean isComposed() { 39 | return true; 40 | } 41 | 42 | @Override 43 | public NumberTop evaluate(State state){ 44 | NumberTop rightNumber = this.rightOperand.evaluate(state); 45 | NumberTop leftNumber = this.leftOperand.evaluate(state); 46 | 47 | if(rightNumber == null || leftNumber == null){ 48 | return null; 49 | } 50 | 51 | if(this.operation.equals("+")){ 52 | return rightNumber.add(leftNumber); 53 | } else if(this.operation.equals("-")){ 54 | return rightNumber.subtract(leftNumber); 55 | } else if(this.operation.equals("*")){ 56 | return rightNumber.multiply(leftNumber); 57 | } else if(this.operation.equals(">")){ 58 | return rightNumber.greaterThan(leftNumber); 59 | } else if(this.operation.equals(">=")){ 60 | return rightNumber.greaterOrEqualThan(leftNumber); 61 | } else if(this.operation.equals("<")){ 62 | return rightNumber.smallerThan(leftNumber); 63 | } else if(this.operation.equals("<=")){ 64 | return rightNumber.smallerOrEqualThan(leftNumber); 65 | } else if(this.operation.equals("==")){ 66 | return rightNumber.equalTo(leftNumber); 67 | } 68 | 69 | throw new RuntimeException(); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/ch/yvu/dfa/expressions/StateExpression.java: -------------------------------------------------------------------------------- 1 | package ch.yvu.dfa.expressions; 2 | 3 | import java.util.ArrayList; 4 | import java.util.HashSet; 5 | import java.util.List; 6 | import java.util.Set; 7 | 8 | import ch.yvu.dfa.analysis.State; 9 | 10 | public class StateExpression extends Expression { 11 | private List state; 12 | 13 | public StateExpression(){ 14 | this.state = new ArrayList(); 15 | } 16 | 17 | public StateExpression(List state){ 18 | this.state = state; 19 | } 20 | 21 | public static StateExpression invalidSateExpression(){ 22 | StateExpression state = new StateExpression(null); 23 | return state; 24 | } 25 | 26 | @Override 27 | public boolean containsVariable(Variable name) { 28 | if(this.state == null) return false; 29 | 30 | for(VariableToValue v : this.state){ 31 | if(v.containsVariable(name)) return true; 32 | } 33 | 34 | return false; 35 | } 36 | 37 | @Override 38 | public String getExpression() { 39 | if(this.state == null) return "B"; 40 | 41 | String expression = ""; 42 | 43 | boolean first = true; 44 | for(VariableToValue v : this.state){ 45 | if(!first){ 46 | expression += ","; 47 | } 48 | first = false; 49 | 50 | expression += v.getExpression(); 51 | } 52 | 53 | return expression; 54 | } 55 | 56 | @Override 57 | public Set getFreeVariables() { 58 | return new HashSet(); 59 | } 60 | 61 | @Override 62 | public boolean isComposed() { 63 | return true; 64 | } 65 | 66 | @Override 67 | public NumberTop evaluate(State state){ 68 | throw new RuntimeException(); 69 | } 70 | 71 | public boolean isInvalid(){ 72 | return this.state == null; 73 | } 74 | 75 | public List getExpressions(){ 76 | ArrayList list = new ArrayList(); 77 | if(this.state != null){ 78 | list.addAll(this.state); 79 | } 80 | return list; 81 | } 82 | } -------------------------------------------------------------------------------- /src/ch/yvu/dfa/expressions/Variable.java: -------------------------------------------------------------------------------- 1 | package ch.yvu.dfa.expressions; 2 | 3 | import java.util.HashSet; 4 | import java.util.Set; 5 | 6 | import ch.yvu.dfa.analysis.State; 7 | 8 | public class Variable extends Expression { 9 | 10 | private String name; 11 | 12 | public Variable(String name){ 13 | this.name = name; 14 | } 15 | 16 | @Override 17 | public boolean containsVariable(Variable variable) { 18 | return this.name.compareTo(variable.name) == 0; 19 | } 20 | 21 | @Override 22 | public String getExpression() { 23 | return this.name; 24 | } 25 | 26 | @Override 27 | public Set getFreeVariables() { 28 | Set freeVariables = new HashSet(); 29 | freeVariables.add(this); 30 | return freeVariables; 31 | } 32 | 33 | @Override 34 | public boolean isComposed() { 35 | return false; 36 | } 37 | 38 | @Override 39 | public NumberTop evaluate(State state) { 40 | NumberTop nt = state.getValue(this); 41 | return nt; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/ch/yvu/dfa/expressions/VariableToValue.java: -------------------------------------------------------------------------------- 1 | package ch.yvu.dfa.expressions; 2 | 3 | import java.util.HashSet; 4 | import java.util.Set; 5 | 6 | import ch.yvu.dfa.analysis.State; 7 | import ch.yvu.dfa.expressions.Expression; 8 | 9 | public class VariableToValue extends Expression { 10 | private Variable variable; 11 | private NumberTop value; 12 | 13 | public VariableToValue(Variable variable, NumberTop value){ 14 | this.variable = variable; 15 | this.value = value; 16 | } 17 | 18 | @Override 19 | public boolean containsVariable(Variable name) { 20 | return variable.containsVariable(name); 21 | } 22 | 23 | @Override 24 | public String getExpression() { 25 | return this.variable.getExpression() + " -> " + this.value.getExpression(); 26 | } 27 | 28 | @Override 29 | public Set getFreeVariables() { 30 | return new HashSet(); 31 | } 32 | 33 | @Override 34 | public boolean isComposed() { 35 | return true; 36 | } 37 | 38 | @Override 39 | public NumberTop evaluate(State state){ 40 | throw new RuntimeException(); 41 | } 42 | 43 | public Variable getVariable(){ 44 | return this.variable; 45 | } 46 | 47 | public NumberTop getValue(){ 48 | return this.value; 49 | } 50 | } -------------------------------------------------------------------------------- /src/ch/yvu/dfa/gui/GraphViz.java: -------------------------------------------------------------------------------- 1 | package ch.yvu.dfa.gui; 2 | // GraphViz.java - a simple API to call dot from Java programs 3 | 4 | /*$Id$*/ 5 | /* 6 | ****************************************************************************** 7 | * * 8 | * (c) Copyright 2003 Laszlo Szathmary * 9 | * * 10 | * This program is free software; you can redistribute it and/or modify it * 11 | * under the terms of the GNU Lesser General Public License as published by * 12 | * the Free Software Foundation; either version 2.1 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | * This program is distributed in the hope that it will be useful, but * 16 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * 17 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * 18 | * License for more details. * 19 | * * 20 | * You should have received a copy of the GNU Lesser General Public License * 21 | * along with this program; if not, write to the Free Software Foundation, * 22 | * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * 23 | * * 24 | ****************************************************************************** 25 | */ 26 | 27 | import java.io.BufferedReader; 28 | import java.io.DataInputStream; 29 | import java.io.File; 30 | import java.io.FileInputStream; 31 | import java.io.FileOutputStream; 32 | import java.io.FileWriter; 33 | import java.io.InputStreamReader; 34 | 35 | /** 36 | *
37 | *
Purpose: GraphViz Java API 38 | *
39 | * 40 | *
Description: 41 | *
With this Java class you can simply call dot 42 | * from your Java programs 43 | *
Example usage: 44 | *
45 | *
 46 |  *    GraphViz gv = new GraphViz();
 47 |  *    gv.addln(gv.start_graph());
 48 |  *    gv.addln("A -> B;");
 49 |  *    gv.addln("A -> C;");
 50 |  *    gv.addln(gv.end_graph());
 51 |  *    System.out.println(gv.getDotSource());
 52 |  *
 53 |  *    String type = "gif";
 54 |  *    File out = new File("out." + type);   // out.gif in this example
 55 |  *    gv.writeGraphToFile( gv.getGraph( gv.getDotSource(), type ), out );
 56 |  * 
57 | *
58 | * 59 | *
60 | * 61 | * @version v0.4, 2011/02/05 (February) -- Patch of Keheliya Gallaba is added. Now you 62 | * can specify the type of the output file: gif, dot, fig, pdf, ps, svg, png, etc. 63 | * @version v0.3, 2010/11/29 (November) -- Windows support + ability 64 | * to read the graph from a text file 65 | * @version v0.2, 2010/07/22 (July) -- bug fix 66 | * @version v0.1, 2003/12/04 (December) -- first release 67 | * @author Laszlo Szathmary (jabba.laci@gmail.com) 68 | */ 69 | public class GraphViz 70 | { 71 | /** 72 | * The dir. where temporary files will be created. 73 | */ 74 | private String tmpDir; 75 | 76 | /** 77 | * Where is your dot program located? It will be called externally. 78 | */ 79 | private String dotBinary; 80 | 81 | /** 82 | * The source of the graph written in dot language. 83 | */ 84 | private StringBuilder graph = new StringBuilder(); 85 | 86 | /** 87 | * Constructor: creates a new GraphViz object that will contain 88 | * a graph. 89 | */ 90 | public GraphViz(String dotBinary, String tempDir) { 91 | this.tmpDir = tempDir; 92 | this.dotBinary = dotBinary; 93 | } 94 | 95 | /** 96 | * Returns the graph's source description in dot language. 97 | * @return Source of the graph in dot language. 98 | */ 99 | public String getDotSource() { 100 | return graph.toString(); 101 | } 102 | 103 | /** 104 | * Adds a string to the graph's source (without newline). 105 | */ 106 | public void add(String line) { 107 | graph.append(line); 108 | } 109 | 110 | /** 111 | * Adds a string to the graph's source (with newline). 112 | */ 113 | public void addln(String line) { 114 | graph.append(line + "\n"); 115 | } 116 | 117 | /** 118 | * Adds a newline to the graph's source. 119 | */ 120 | public void addln() { 121 | graph.append('\n'); 122 | } 123 | 124 | /** 125 | * Returns the graph as an image in binary format. 126 | * @param dot_source Source of the graph to be drawn. 127 | * @param type Type of the output image to be produced, e.g.: gif, dot, fig, pdf, ps, svg, png. 128 | * @return A byte array containing the image of the graph. 129 | */ 130 | public byte[] getGraph(String dot_source, String type) 131 | { 132 | File dot; 133 | byte[] img_stream = null; 134 | 135 | try { 136 | dot = writeDotSourceToFile(dot_source); 137 | if (dot != null) 138 | { 139 | img_stream = get_img_stream(dot, type); 140 | if (dot.delete() == false) 141 | System.err.println("Warning: " + dot.getAbsolutePath() + " could not be deleted!"); 142 | return img_stream; 143 | } 144 | return null; 145 | } catch (java.io.IOException ioe) { return null; } 146 | } 147 | 148 | /** 149 | * Writes the graph's image in a file. 150 | * @param img A byte array containing the image of the graph. 151 | * @param file Name of the file to where we want to write. 152 | * @return Success: 1, Failure: -1 153 | */ 154 | public int writeGraphToFile(byte[] img, String file) 155 | { 156 | File to = new File(file); 157 | return writeGraphToFile(img, to); 158 | } 159 | 160 | /** 161 | * Writes the graph's image in a file. 162 | * @param img A byte array containing the image of the graph. 163 | * @param to A File object to where we want to write. 164 | * @return Success: 1, Failure: -1 165 | */ 166 | public int writeGraphToFile(byte[] img, File to) 167 | { 168 | try { 169 | FileOutputStream fos = new FileOutputStream(to); 170 | fos.write(img); 171 | fos.close(); 172 | } catch (java.io.IOException ioe) { return -1; } 173 | return 1; 174 | } 175 | 176 | /** 177 | * It will call the external dot program, and return the image in 178 | * binary format. 179 | * @param dot Source of the graph (in dot language). 180 | * @param type Type of the output image to be produced, e.g.: gif, dot, fig, pdf, ps, svg, png. 181 | * @return The image of the graph in .gif format. 182 | */ 183 | private byte[] get_img_stream(File dot, String type) 184 | { 185 | File img; 186 | byte[] img_stream = null; 187 | 188 | try { 189 | img = File.createTempFile("graph_", "."+type, new File(this.tmpDir)); 190 | Runtime rt = Runtime.getRuntime(); 191 | 192 | // patch by Mike Chenault 193 | String[] args = {this.dotBinary, "-T"+type, dot.getAbsolutePath(), "-o", img.getAbsolutePath()}; 194 | Process p = rt.exec(args); 195 | 196 | p.waitFor(); 197 | 198 | FileInputStream in = new FileInputStream(img.getAbsolutePath()); 199 | img_stream = new byte[in.available()]; 200 | in.read(img_stream); 201 | // Close it if we need to 202 | if( in != null ) in.close(); 203 | 204 | if (img.delete() == false) 205 | System.err.println("Warning: " + img.getAbsolutePath() + " could not be deleted!"); 206 | } 207 | catch (java.io.IOException ioe) { 208 | System.err.println("Error: in I/O processing of tempfile in dir " + this.tmpDir+"\n"); 209 | System.err.println(" or in calling external command"); 210 | ioe.printStackTrace(); 211 | } 212 | catch (java.lang.InterruptedException ie) { 213 | System.err.println("Error: the execution of the external program was interrupted"); 214 | ie.printStackTrace(); 215 | } 216 | 217 | return img_stream; 218 | } 219 | 220 | /** 221 | * Writes the source of the graph in a file, and returns the written file 222 | * as a File object. 223 | * @param str Source of the graph (in dot language). 224 | * @return The file (as a File object) that contains the source of the graph. 225 | */ 226 | private File writeDotSourceToFile(String str) throws java.io.IOException 227 | { 228 | File temp; 229 | try { 230 | temp = File.createTempFile("graph_", ".dot.tmp", new File(this.tmpDir)); 231 | FileWriter fout = new FileWriter(temp); 232 | fout.write(str); 233 | fout.close(); 234 | } 235 | catch (Exception e) { 236 | System.err.println("Error: I/O error while writing the dot source to temp file!"); 237 | return null; 238 | } 239 | return temp; 240 | } 241 | 242 | /** 243 | * Returns a string that is used to start a graph. 244 | * @return A string to open a graph. 245 | */ 246 | public String start_graph() { 247 | return "digraph G {"; 248 | } 249 | 250 | /** 251 | * Returns a string that is used to end a graph. 252 | * @return A string to close a graph. 253 | */ 254 | public String end_graph() { 255 | return "}"; 256 | } 257 | 258 | /** 259 | * Read a DOT graph from a text file. 260 | * 261 | * @param input Input text file containing the DOT graph 262 | * source. 263 | */ 264 | public void readSource(String input) 265 | { 266 | StringBuilder sb = new StringBuilder(); 267 | 268 | try 269 | { 270 | FileInputStream fis = new FileInputStream(input); 271 | DataInputStream dis = new DataInputStream(fis); 272 | BufferedReader br = new BufferedReader(new InputStreamReader(dis)); 273 | String line; 274 | while ((line = br.readLine()) != null) { 275 | sb.append(line); 276 | } 277 | dis.close(); 278 | } 279 | catch (Exception e) { 280 | System.err.println("Error: " + e.getMessage()); 281 | } 282 | 283 | this.graph = sb; 284 | } 285 | 286 | } // end of class GraphViz -------------------------------------------------------------------------------- /src/ch/yvu/dfa/gui/MainFrame.java: -------------------------------------------------------------------------------- 1 | package ch.yvu.dfa.gui; 2 | 3 | import java.awt.Container; 4 | import java.awt.Dimension; 5 | import java.awt.Graphics; 6 | import java.awt.Component; 7 | import java.awt.Image; 8 | import java.awt.Toolkit; 9 | import java.awt.event.ActionEvent; 10 | import java.awt.event.ActionListener; 11 | import java.awt.image.BufferedImage; 12 | 13 | import javax.swing.JButton; 14 | import javax.swing.JFrame; 15 | import javax.swing.JOptionPane; 16 | import javax.swing.JPanel; 17 | import javax.swing.JComboBox; 18 | import javax.swing.JScrollPane; 19 | import javax.swing.JTextArea; 20 | import javax.swing.text.html.HTMLEditorKit; 21 | import javax.swing.JEditorPane; 22 | import javax.swing.text.Document; 23 | import javax.swing.BoxLayout; 24 | 25 | import ch.yvu.dfa.analysis.AvailableExpressionStrategy; 26 | import ch.yvu.dfa.analysis.LiveVariableStrategy; 27 | import ch.yvu.dfa.analysis.ReachingDefinitionsStrategy; 28 | import ch.yvu.dfa.analysis.AnalysisStrategy; 29 | import ch.yvu.dfa.analysis.StronglyLiveVariableStrategy; 30 | import ch.yvu.dfa.analysis.ConstantPropagationStrategy; 31 | import ch.yvu.dfa.analysis.PreciseConstantPropagationStrategy; 32 | 33 | import ch.yvu.dfa.main.Worker; 34 | 35 | import java.util.HashMap; 36 | import java.util.Map; 37 | 38 | import java.net.URL; 39 | 40 | public class MainFrame extends JFrame implements ActionListener { 41 | 42 | private Map strategies = new HashMap(); 43 | 44 | private JPanel panel = new JPanel(); 45 | private JButton analyzeButton = new JButton("Analyze"); 46 | private JTextArea input = new JTextArea(30,20); 47 | private ImagePanel image = new ImagePanel(); 48 | private JEditorPane output = new JEditorPane(); 49 | private JComboBox strategyList = new JComboBox(); 50 | 51 | public MainFrame(){ 52 | super("Dataflow Analysis"); 53 | initializeStrategies(); 54 | 55 | setIcon(); 56 | 57 | Container con = this.getContentPane(); 58 | con.add(this.panel); 59 | 60 | this.panel.setLayout(new BoxLayout(this.panel, BoxLayout.LINE_AXIS)); 61 | 62 | JPanel inputPanel = new JPanel(); 63 | inputPanel.setLayout(new BoxLayout(inputPanel, BoxLayout.PAGE_AXIS)); 64 | 65 | JScrollPane inputScrollPane = new JScrollPane(this.input); 66 | inputPanel.add(inputScrollPane); 67 | 68 | JPanel buttonPanel = new JPanel(); 69 | this.strategyList = new JComboBox(this.strategies.keySet().toArray()); 70 | buttonPanel.add(this.strategyList); 71 | this.analyzeButton.setMnemonic('A'); 72 | this.analyzeButton.addActionListener(this); 73 | buttonPanel.add(this.analyzeButton); 74 | 75 | inputPanel.add(buttonPanel); 76 | 77 | this.panel.add(inputPanel); 78 | 79 | JPanel outputPanel = new JPanel(); 80 | outputPanel.setLayout(new BoxLayout(outputPanel, BoxLayout.PAGE_AXIS)); 81 | 82 | outputPanel.add(this.image); 83 | 84 | this.output.setEditable(false); 85 | HTMLEditorKit kit = new HTMLEditorKit(); 86 | this.output.setEditorKit(kit); 87 | Document doc = kit.createDefaultDocument(); 88 | this.output.setDocument(doc); 89 | this.output.setText("No output yet"); 90 | 91 | JScrollPane outputScrollPane = new JScrollPane(this.output); 92 | outputPanel.add(outputScrollPane); 93 | 94 | JScrollPane totalOutputScrollPane = new JScrollPane(outputPanel); 95 | 96 | this.panel.add(totalOutputScrollPane); 97 | 98 | setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 99 | pack(); 100 | setVisible(true); 101 | } 102 | 103 | public void updateOutput(String html, BufferedImage image){ 104 | this.image.setImage(image); 105 | String htmlExpressions = html; 106 | this.output.setText(htmlExpressions); 107 | 108 | pack(); 109 | repaint(); 110 | } 111 | 112 | public void showErrorMessage(String message){ 113 | JOptionPane.showMessageDialog(this, message); 114 | } 115 | 116 | private void setIcon(){ 117 | URL url = ClassLoader.getSystemResource("ch/yvu/dfa/ressources/icon.png"); 118 | Toolkit kit = Toolkit.getDefaultToolkit(); 119 | Image img = kit.createImage(url); 120 | this.setIconImage(img); 121 | } 122 | 123 | private void initializeStrategies(){ 124 | this.strategies.put("Available Expressions", new AvailableExpressionStrategy()); 125 | this.strategies.put("Reaching Definitions", new ReachingDefinitionsStrategy()); 126 | this.strategies.put("Live Variable", new LiveVariableStrategy()); 127 | this.strategies.put("Strongly Live Variables", new StronglyLiveVariableStrategy()); 128 | this.strategies.put("Constant Propagation", new ConstantPropagationStrategy()); 129 | this.strategies.put("Precise Constant Propagation", new PreciseConstantPropagationStrategy()); 130 | } 131 | 132 | @Override 133 | public void actionPerformed(ActionEvent arg0) { 134 | Worker worker = new Worker(this, this.input.getText(), this.strategies.get(this.strategyList.getSelectedItem())); 135 | Thread t = new Thread(worker); 136 | t.start(); 137 | } 138 | 139 | private class ImagePanel extends Component{ 140 | private BufferedImage image; 141 | 142 | @Override 143 | public Dimension getPreferredSize() { 144 | if(this.image == null){ 145 | return new Dimension(200, 200); 146 | } else{ 147 | return new Dimension(this.image.getWidth(), this.image.getHeight()); 148 | } 149 | } 150 | 151 | public void setImage(BufferedImage image){ 152 | this.image = image; 153 | setSize(image.getWidth(), image.getHeight()); 154 | } 155 | 156 | @Override 157 | public void paint(Graphics g) { 158 | g.drawImage(image, 0, 0, null); 159 | } 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /src/ch/yvu/dfa/main/Program.java: -------------------------------------------------------------------------------- 1 | package ch.yvu.dfa.main; 2 | 3 | import javax.swing.SwingUtilities; 4 | 5 | import ch.yvu.dfa.gui.MainFrame; 6 | 7 | public class Program { 8 | public static final String GRAPHVIZ_PROPERTIES_FILE = "graphviz.properties"; 9 | public static final String GRAPHVIZ_PROPERTY_TMPDIR = "graphvizTempDir"; 10 | public static final String GRAPHVIZ_PROPERTY_DOTBIN = "graphvizDOTBinary"; 11 | 12 | public static void main(String[] args){ 13 | 14 | 15 | Program p = new Program(); 16 | //p.runWithGraphsFromFile(args); 17 | p.runGUI(); 18 | } 19 | 20 | public void runGUI(){ 21 | SwingUtilities.invokeLater(new Runnable() { 22 | @Override 23 | public void run() { 24 | new MainFrame(); 25 | } 26 | }); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/ch/yvu/dfa/main/Worker.java: -------------------------------------------------------------------------------- 1 | package ch.yvu.dfa.main; 2 | 3 | import java.awt.image.BufferedImage; 4 | import java.io.BufferedInputStream; 5 | import java.io.ByteArrayInputStream; 6 | import java.io.FileInputStream; 7 | import java.io.IOException; 8 | import java.util.Properties; 9 | 10 | import javax.imageio.ImageIO; 11 | import javax.swing.SwingUtilities; 12 | 13 | import ch.yvu.dfa.analysis.AnalysisStrategy; 14 | import ch.yvu.dfa.analysis.DataFlowAnalysis; 15 | import ch.yvu.dfa.controlflowgraph.ControlflowGraph; 16 | import ch.yvu.dfa.gui.GraphViz; 17 | import ch.yvu.dfa.gui.MainFrame; 18 | import ch.yvu.dfa.parser.FormatException; 19 | import ch.yvu.dfa.parser.dot.SimpleDOTParser; 20 | import ch.yvu.dfa.parser.expression.ExpressionParser; 21 | 22 | public class Worker implements Runnable{ 23 | 24 | private MainFrame frame; 25 | private String input; 26 | private AnalysisStrategy strategy; 27 | 28 | 29 | public Worker(MainFrame frame, String input, AnalysisStrategy strategy){ 30 | this.frame = frame; 31 | this.input = input; 32 | this.strategy = strategy; 33 | } 34 | 35 | @Override 36 | public void run() { 37 | final String html; 38 | final BufferedImage image; 39 | try{ 40 | html = runAnalysis(); 41 | image = createImage(); 42 | }catch(FormatException e){ 43 | invokeErrorMessage("Syntax to describe graph not recognized. Use DOT Syntax."); 44 | return; 45 | } catch(IOException e){ 46 | invokeErrorMessage("A problem occured while generationg the graph."); 47 | return; 48 | } 49 | 50 | SwingUtilities.invokeLater(new Runnable(){ 51 | @Override 52 | public void run() { 53 | frame.updateOutput(html, image); 54 | } 55 | }); 56 | } 57 | 58 | private void invokeErrorMessage(final String message){ 59 | SwingUtilities.invokeLater(new Runnable() { 60 | 61 | @Override 62 | public void run() { 63 | frame.showErrorMessage(message); 64 | } 65 | }); 66 | } 67 | 68 | private String runAnalysis() throws FormatException{ 69 | SimpleDOTParser parser = new SimpleDOTParser(this.input, new ExpressionParser()); 70 | ControlflowGraph graph = parser.parse(); 71 | DataFlowAnalysis analysis = new DataFlowAnalysis(graph, this.strategy); 72 | return analysis.analyse(); 73 | } 74 | 75 | private BufferedImage createImage() throws IOException{ 76 | Properties properties = new Properties(); 77 | try { 78 | properties.load(new BufferedInputStream(new FileInputStream(Program.GRAPHVIZ_PROPERTIES_FILE))); 79 | } catch (IOException e){ 80 | throw e; 81 | } 82 | 83 | String dotBinary = properties.getProperty(Program.GRAPHVIZ_PROPERTY_DOTBIN); 84 | String tempDir = properties.getProperty(Program.GRAPHVIZ_PROPERTY_TMPDIR); 85 | 86 | GraphViz graphViz = new GraphViz(dotBinary, tempDir); 87 | byte[] imageBytes = graphViz.getGraph(this.input, "png"); 88 | if(imageBytes == null) throw new IOException(); 89 | ByteArrayInputStream bais = new ByteArrayInputStream(imageBytes); 90 | return ImageIO.read(bais); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/ch/yvu/dfa/parser/FormatException.java: -------------------------------------------------------------------------------- 1 | package ch.yvu.dfa.parser; 2 | 3 | public class FormatException extends Exception { 4 | public FormatException(Throwable t) { 5 | super(t); 6 | } 7 | 8 | public FormatException(){ 9 | super(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/ch/yvu/dfa/parser/dot/SimpleDOTParser.java: -------------------------------------------------------------------------------- 1 | package ch.yvu.dfa.parser.dot; 2 | 3 | import java.util.StringTokenizer; 4 | import java.util.regex.Matcher; 5 | import java.util.regex.Pattern; 6 | 7 | import ch.yvu.dfa.controlflowgraph.ControlflowGraph; 8 | import ch.yvu.dfa.expressions.Expression; 9 | import ch.yvu.dfa.expressions.Variable; 10 | import ch.yvu.dfa.parser.FormatException; 11 | import ch.yvu.dfa.parser.expression.ExpressionParser; 12 | 13 | public class SimpleDOTParser { 14 | 15 | private final static String ASSIGNMENT_OPERATOR = ":="; 16 | 17 | private final static String GREATER_THAN = ">"; 18 | private final static String GREATER_OR_EQUAL_THAN = ">="; 19 | private final static String SMALLER_THAN = "<"; 20 | private final static String SMALLER_OR_EQUAL_THAN = "<="; 21 | private final static String EQUAL = "=="; 22 | 23 | private String input; 24 | private ControlflowGraph graph; 25 | private ExpressionParser parser; 26 | 27 | public SimpleDOTParser(String input, ExpressionParser parser){ 28 | this.input = input; 29 | this.graph = new ControlflowGraph(); 30 | this.parser = parser; 31 | } 32 | 33 | public ControlflowGraph parse() throws FormatException{ 34 | String trimmedInput = this.input.replaceAll("\\s",""); 35 | String edgeInput = extractEdgeInput(trimmedInput); 36 | 37 | StringTokenizer tokens = new StringTokenizer(edgeInput, ";"); 38 | Pattern edgePattern = Pattern.compile("^([0-9]+)->([0-9]+)(\\[label=\"(true|false)\"\\])?"); 39 | 40 | Pattern nodePattern = Pattern.compile("^([0-9]+)\\[label=\"([0-9]+:)?([^\"]+)\"\\]"); 41 | while(tokens.hasMoreElements()){ 42 | String token = tokens.nextToken(); 43 | Matcher edgeMatcher = edgePattern.matcher(token); 44 | Matcher nodeMatcher = nodePattern.matcher(token); 45 | if(nodeMatcher.find()){ 46 | int nodeId = Integer.parseInt(nodeMatcher.group(1)); 47 | String expression = nodeMatcher.group(3); 48 | createNode(nodeId, expression); 49 | } else if(edgeMatcher.find()){ 50 | int nodeFromId = Integer.parseInt(edgeMatcher.group(1)); 51 | int nodeToId = Integer.parseInt(edgeMatcher.group(2)); 52 | createEdge(nodeFromId, nodeToId); 53 | } else { 54 | //If format not recognize don't consider it for 55 | //controlflow graph but don't throw an execption 56 | //because only a subset of DOT language is supported 57 | //(unrecognized tokens can still be valid DOT) 58 | } 59 | } 60 | return this.graph; 61 | } 62 | 63 | private void createNode(int id, String expression) throws FormatException { 64 | if(expression.contains(ASSIGNMENT_OPERATOR)){ 65 | createAssignmentNode(id, expression); 66 | } else { 67 | createConditionalNode(id, expression); 68 | } 69 | } 70 | 71 | private void createConditionalNode(int id, String conditionalExpression) throws FormatException{ 72 | //Order of if...else if... is important 73 | //as SMALLER ("<") is a substring of SMALLER_OR_EQUAL ("<=") 74 | 75 | String[] tokens; 76 | String operation; 77 | if(conditionalExpression.contains(SMALLER_OR_EQUAL_THAN)){ 78 | tokens = conditionalExpression.split(SMALLER_OR_EQUAL_THAN); 79 | operation = SMALLER_OR_EQUAL_THAN; 80 | } else if(conditionalExpression.contains(GREATER_OR_EQUAL_THAN)){ 81 | tokens = conditionalExpression.split(GREATER_OR_EQUAL_THAN); 82 | operation = GREATER_OR_EQUAL_THAN; 83 | } else if(conditionalExpression.contains(SMALLER_THAN)){ 84 | tokens = conditionalExpression.split(SMALLER_THAN); 85 | operation = SMALLER_THAN; 86 | } else if(conditionalExpression.contains(GREATER_THAN)){ 87 | tokens = conditionalExpression.split(GREATER_THAN); 88 | operation = GREATER_THAN; 89 | } else if(conditionalExpression.contains(EQUAL)){ 90 | tokens = conditionalExpression.split(EQUAL); 91 | operation = EQUAL; 92 | } else { 93 | throw new FormatException(); 94 | } 95 | if(tokens.length != 2) throw new FormatException(); 96 | Expression lhs = this.parser.parse(tokens[0]); 97 | Expression rhs = this.parser.parse(tokens[1]); 98 | try{ 99 | this.graph.createConditionalNode(id, lhs, rhs, operation); 100 | }catch(Exception e){ 101 | throw new FormatException(e); 102 | } 103 | } 104 | 105 | private void createAssignmentNode(int id, String assignmentExpression) throws FormatException{ 106 | String[] tokens = assignmentExpression.split(ASSIGNMENT_OPERATOR); 107 | if(tokens.length != 2) throw new FormatException(); 108 | try{ 109 | Expression lhs = this.parser.parse(tokens[0]); 110 | assert(lhs instanceof Variable); 111 | 112 | Expression rhs = this.parser.parse(tokens[1]); 113 | 114 | this.graph.createAssignmentNode(id, (Variable) lhs, rhs); 115 | } catch(Exception e){ 116 | throw new FormatException(e); 117 | } 118 | } 119 | 120 | private void createEdge(int nodeFromId, int nodeToId) throws FormatException{ 121 | try { 122 | this.graph.addEdge(nodeFromId, nodeToId); 123 | } catch (Exception e) { 124 | throw new FormatException(e); 125 | } 126 | } 127 | 128 | /** 129 | * Extract part from 130 | * digraphgraphName{} 131 | */ 132 | private static String extractEdgeInput(String input) throws FormatException{ 133 | Pattern blockPattern = Pattern.compile("[^\\{]*\\{([^\\}]*)\\}"); 134 | Matcher blockMatcher = blockPattern.matcher(input); 135 | 136 | if(!blockMatcher.find()) throw new FormatException(); 137 | 138 | return blockMatcher.group(1); 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /src/ch/yvu/dfa/parser/expression/ExpressionParser.java: -------------------------------------------------------------------------------- 1 | package ch.yvu.dfa.parser.expression; 2 | 3 | import java.util.regex.Matcher; 4 | import java.util.regex.Pattern; 5 | 6 | import ch.yvu.dfa.expressions.Expression; 7 | import ch.yvu.dfa.expressions.Number; 8 | import ch.yvu.dfa.expressions.Operation; 9 | import ch.yvu.dfa.expressions.Variable; 10 | import ch.yvu.dfa.parser.FormatException; 11 | 12 | public class ExpressionParser { 13 | 14 | public Expression parse(String input) throws FormatException{ 15 | String trimmedInput = input.replaceAll("\\s",""); 16 | //Don't consider brackets 17 | trimmedInput = removeBrackets(trimmedInput); 18 | 19 | Pattern composedExpressionPattern = Pattern.compile("([a-zA-Z0-9]+)([^a-zA-Z0-9]{1,2})(.+)"); 20 | Matcher composedExpressionMatcher = composedExpressionPattern.matcher(trimmedInput); 21 | 22 | Pattern simpleExpressionPattern = Pattern.compile("([a-zA-Z0-9]+)"); 23 | Matcher simpleExpressionMatcher = simpleExpressionPattern.matcher(trimmedInput); 24 | 25 | if(composedExpressionMatcher.find()){ 26 | String lhs = composedExpressionMatcher.group(1); 27 | 28 | Expression lhsExpression = parse(lhs); 29 | 30 | String operation = composedExpressionMatcher.group(2); 31 | 32 | String rhs = composedExpressionMatcher.group(3); 33 | Expression rhsExpression = parse(rhs); 34 | 35 | return new Operation(lhsExpression, rhsExpression, operation); 36 | } else if(simpleExpressionMatcher.find()){ 37 | return createLeafExpression(simpleExpressionMatcher.group(1)); 38 | } else { 39 | throw new FormatException(); 40 | } 41 | } 42 | 43 | private String removeBrackets(String trimmedInput) { 44 | trimmedInput = trimmedInput.replaceAll("\\(", ""); 45 | trimmedInput = trimmedInput.replaceAll("\\)", ""); 46 | return trimmedInput; 47 | } 48 | 49 | private Expression createLeafExpression(String expression) throws FormatException{ 50 | if(isVariable(expression)){ 51 | return new Variable(expression); 52 | } else if(isNumber(expression)){ 53 | return new Number(Integer.parseInt(expression)); 54 | } else { 55 | throw new FormatException(); 56 | } 57 | } 58 | 59 | private boolean isVariable(String input){ 60 | return input.matches("[a-zA-z]+"); 61 | } 62 | 63 | private boolean isNumber(String input){ 64 | return input.matches("[0-9]+"); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/ch/yvu/dfa/ressources/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ybonjour/Data-Flow-Analysis/025c811d28221e66e084f7515b8e467a93ae4602/src/ch/yvu/dfa/ressources/icon.png -------------------------------------------------------------------------------- /src/ch/yvu/dfa/tests/DOTParserTest.java: -------------------------------------------------------------------------------- 1 | package ch.yvu.dfa.tests; 2 | 3 | import junit.framework.Assert; 4 | 5 | import org.junit.Test; 6 | 7 | import ch.yvu.dfa.controlflowgraph.AssignmentNode; 8 | import ch.yvu.dfa.controlflowgraph.ConditionalNode; 9 | import ch.yvu.dfa.controlflowgraph.ControlflowGraph; 10 | import ch.yvu.dfa.parser.FormatException; 11 | import ch.yvu.dfa.parser.dot.SimpleDOTParser; 12 | import ch.yvu.dfa.parser.expression.ExpressionParser; 13 | 14 | 15 | 16 | public class DOTParserTest { 17 | 18 | @Test 19 | public void test_parse_empty(){ 20 | //Arrange 21 | String input = "digraph Test{}"; 22 | SimpleDOTParser parser = new SimpleDOTParser(input, new ExpressionParser()); 23 | 24 | //Act 25 | ControlflowGraph graph; 26 | try{ 27 | graph = parser.parse(); 28 | }catch(FormatException e){ 29 | throw new RuntimeException(e); 30 | } 31 | 32 | //Assert 33 | Assert.assertEquals(0, graph.getNodes().size()); 34 | } 35 | 36 | @Test 37 | public void test_parse_assignment_node(){ 38 | //Arrange 39 | String input = "digraph Test {1[label=\"x:=a+b\"]}"; 40 | SimpleDOTParser parser = new SimpleDOTParser(input, new ExpressionParser()); 41 | 42 | //Act 43 | ControlflowGraph graph; 44 | try{ 45 | graph = parser.parse(); 46 | }catch(FormatException e){ 47 | throw new RuntimeException(e); 48 | } 49 | 50 | //Assert 51 | Assert.assertEquals(1, graph.getNodes().size()); 52 | Assert.assertNotNull(graph.getNode(1)); 53 | Assert.assertTrue(graph.getNode(1) instanceof AssignmentNode); 54 | AssignmentNode node = (AssignmentNode) graph.getNode(1); 55 | Assert.assertEquals("x", node.getLhs().getExpression()); 56 | Assert.assertEquals("a + b", node.getRhs().getExpression()); 57 | } 58 | 59 | @Test 60 | public void test_parse_assignment_node_with_numbering(){ 61 | //Arrange 62 | String input = "digraph Test {1[label=\"1: x:=a+b\"]}"; 63 | SimpleDOTParser parser = new SimpleDOTParser(input, new ExpressionParser()); 64 | 65 | //Act 66 | ControlflowGraph graph; 67 | try{ 68 | graph = parser.parse(); 69 | }catch(FormatException e){ 70 | throw new RuntimeException(e); 71 | } 72 | 73 | //Assert 74 | Assert.assertEquals(1, graph.getNodes().size()); 75 | Assert.assertNotNull(graph.getNode(1)); 76 | Assert.assertTrue(graph.getNode(1) instanceof AssignmentNode); 77 | AssignmentNode node = (AssignmentNode) graph.getNode(1); 78 | Assert.assertEquals("x", node.getLhs().getExpression()); 79 | Assert.assertEquals("a + b", node.getRhs().getExpression()); 80 | } 81 | 82 | @Test 83 | public void test_parse_conditional_node(){ 84 | //Arrange 85 | String input = "digraph Test {1[label=\"x2;}"; 146 | SimpleDOTParser parser = new SimpleDOTParser(input, new ExpressionParser()); 147 | 148 | //Act 149 | ControlflowGraph graph; 150 | try{ 151 | graph = parser.parse(); 152 | }catch(FormatException e){ 153 | throw new RuntimeException(e); 154 | } 155 | 156 | //Assert 157 | Assert.assertEquals(2, graph.getNodes().size()); 158 | Assert.assertNotNull(graph.getNode(1)); 159 | Assert.assertNotNull(graph.getNode(2)); 160 | Assert.assertEquals(1, graph.getNode(1).numChildren()); 161 | Assert.assertTrue(graph.getNode(1).hasChild(graph.getNode(2))); 162 | } 163 | 164 | @Test 165 | public void test_parse_branch(){ 166 | //Arrange 167 | String input = "digraph Test {1[label=\"x2;2->4;1->3;3->4;}"; 168 | SimpleDOTParser parser = new SimpleDOTParser(input, new ExpressionParser()); 169 | 170 | //Act 171 | ControlflowGraph graph; 172 | try{ 173 | graph = parser.parse(); 174 | }catch(FormatException e){ 175 | throw new RuntimeException(e); 176 | } 177 | 178 | //Assert 179 | Assert.assertEquals(4, graph.getNodes().size()); 180 | 181 | Assert.assertNotNull(graph.getNode(1)); 182 | Assert.assertNotNull(graph.getNode(2)); 183 | Assert.assertNotNull(graph.getNode(3)); 184 | Assert.assertNotNull(graph.getNode(4)); 185 | 186 | Assert.assertEquals(2, graph.getNode(1).numChildren()); 187 | Assert.assertTrue(graph.getNode(1).hasChild(graph.getNode(2))); 188 | Assert.assertTrue(graph.getNode(1).hasChild(graph.getNode(3))); 189 | 190 | Assert.assertEquals(1, graph.getNode(2).numChildren()); 191 | Assert.assertTrue(graph.getNode(2).hasChild(graph.getNode(4))); 192 | 193 | Assert.assertEquals(1, graph.getNode(3).numChildren()); 194 | Assert.assertTrue(graph.getNode(3).hasChild(graph.getNode(4))); 195 | } 196 | 197 | @Test 198 | public void test_parse_loop(){ 199 | //Arrange 200 | String input = "digraph Test {1[label=\"x2;1->3;2->1;}"; 201 | SimpleDOTParser parser = new SimpleDOTParser(input, new ExpressionParser()); 202 | 203 | //Act 204 | ControlflowGraph graph; 205 | try{ 206 | graph = parser.parse(); 207 | }catch(FormatException e){ 208 | throw new RuntimeException(e); 209 | } 210 | 211 | //Assert 212 | Assert.assertEquals(3, graph.getNodes().size()); 213 | 214 | Assert.assertNotNull(graph.getNode(1)); 215 | Assert.assertNotNull(graph.getNode(2)); 216 | Assert.assertNotNull(graph.getNode(3)); 217 | 218 | Assert.assertEquals(2, graph.getNode(1).numChildren()); 219 | Assert.assertTrue(graph.getNode(1).hasChild(graph.getNode(2))); 220 | Assert.assertTrue(graph.getNode(1).hasChild(graph.getNode(3))); 221 | 222 | Assert.assertEquals(1, graph.getNode(2).numChildren()); 223 | Assert.assertTrue(graph.getNode(2).hasChild(graph.getNode(1))); 224 | } 225 | 226 | } 227 | -------------------------------------------------------------------------------- /src/ch/yvu/dfa/tests/ExplorationalTests.java: -------------------------------------------------------------------------------- 1 | package ch.yvu.dfa.tests; 2 | 3 | import java.util.regex.Matcher; 4 | import java.util.regex.Pattern; 5 | 6 | import junit.framework.Assert; 7 | import org.junit.Test; 8 | 9 | public class ExplorationalTests { 10 | 11 | @Test 12 | public void test_string_split(){ 13 | //Arrange 14 | String input = "digraph testGraph {0->1; 0->2;}"; 15 | 16 | //Act 17 | String[] tokens = input.split("[{]"); 18 | String[] tokens2 = tokens[1].split("[}]"); 19 | 20 | //Assert 21 | Assert.assertEquals(2, tokens.length); 22 | Assert.assertEquals(1, tokens2.length); 23 | Assert.assertEquals("0->1; 0->2;", tokens2[0]); 24 | } 25 | 26 | @Test 27 | public void test_replace_whitespaces(){ 28 | //Arrange 29 | String input = "diagraph testGraph {\n 0->1;\t\n0->2; } "; 30 | 31 | //Act 32 | String trimmed = input.replaceAll("\\s",""); 33 | 34 | //Assert 35 | Assert.assertEquals("diagraphtestGraph{0->1;0->2;}", trimmed); 36 | } 37 | 38 | @Test 39 | public void test_regex_edge(){ 40 | String regex = "([0-9]+)->([0-9]+)"; 41 | String edge1 = "1->2"; 42 | String edge2 = "10->20"; 43 | String edge3 = "1->2[label=\"bla\"]"; 44 | 45 | Pattern pattern = Pattern.compile(regex); 46 | Matcher matcher1 = pattern.matcher(edge1); 47 | Matcher matcher2 = pattern.matcher(edge2); 48 | Matcher matcher3 = pattern.matcher(edge3); 49 | 50 | Assert.assertTrue(matcher1.find()); 51 | Assert.assertEquals(2, matcher1.groupCount()); 52 | Assert.assertEquals("1", matcher1.group(1)); 53 | Assert.assertEquals("2", matcher1.group(2)); 54 | 55 | Assert.assertTrue(matcher2.find()); 56 | Assert.assertEquals(2, matcher2.groupCount()); 57 | Assert.assertEquals("10", matcher2.group(1)); 58 | Assert.assertEquals("20", matcher2.group(2)); 59 | 60 | Assert.assertTrue(matcher3.find()); 61 | Assert.assertEquals(2, matcher3.groupCount()); 62 | Assert.assertEquals("1", matcher3.group(1)); 63 | Assert.assertEquals("2", matcher3.group(2)); 64 | } 65 | 66 | @Test 67 | public void test_regex_node(){ 68 | String regex = "([0-9]+)\\[label=\"([^\"]+)\"\\]"; 69 | String node1 = "1[label=\"bla\"]"; 70 | String node2 = "10[label=\"bla\"]"; 71 | String node3 = "1"; 72 | 73 | 74 | Pattern pattern = Pattern.compile(regex); 75 | Matcher matcher1 = pattern.matcher(node1); 76 | Matcher matcher2 = pattern.matcher(node2); 77 | Matcher matcher3 = pattern.matcher(node3); 78 | 79 | Assert.assertTrue(matcher1.find()); 80 | Assert.assertEquals(2, matcher1.groupCount()); 81 | Assert.assertEquals("1", matcher1.group(1)); 82 | Assert.assertEquals("bla", matcher1.group(2)); 83 | 84 | Assert.assertTrue(matcher2.find()); 85 | Assert.assertEquals(2, matcher2.groupCount()); 86 | Assert.assertEquals("10", matcher2.group(1)); 87 | Assert.assertEquals("bla", matcher2.group(2)); 88 | 89 | Assert.assertFalse(matcher3.find()); 90 | } 91 | 92 | @Test 93 | public void test_regex_block(){ 94 | String regex = "[^\\{]*\\{([^\\}]*)\\}"; 95 | String myBlock = "blabla{text}"; 96 | 97 | Pattern p = Pattern.compile(regex); 98 | Matcher m = p.matcher(myBlock); 99 | 100 | Assert.assertTrue(m.find()); 101 | Assert.assertEquals(1, m.groupCount()); 102 | Assert.assertEquals("text", m.group(1)); 103 | 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/ch/yvu/dfa/tests/ExpressionNodeTest.java: -------------------------------------------------------------------------------- 1 | package ch.yvu.dfa.tests; 2 | 3 | import java.util.Set; 4 | 5 | import junit.framework.Assert; 6 | 7 | import org.junit.Test; 8 | 9 | import ch.yvu.dfa.expressions.Expression; 10 | import ch.yvu.dfa.expressions.Number; 11 | import ch.yvu.dfa.expressions.Operation; 12 | import ch.yvu.dfa.expressions.Variable; 13 | 14 | public class ExpressionNodeTest { 15 | 16 | @Test 17 | public void test_containsVariable_variable(){ 18 | //Arrange 19 | Variable a = new Variable("a"); 20 | 21 | //Act 22 | boolean contains = a.containsVariable(a); 23 | 24 | //Assert 25 | Assert.assertTrue(contains); 26 | } 27 | 28 | @Test 29 | public void test_containsVariable_different_variables_same_mane(){ 30 | //Arrange 31 | Variable a1 = new Variable("a"); 32 | Variable a2 = new Variable("a"); 33 | 34 | //Act 35 | boolean contains = a1.containsVariable(a2); 36 | 37 | //Assert 38 | Assert.assertTrue(contains); 39 | } 40 | 41 | @Test 42 | public void test_containsVariable_false(){ 43 | //Arrange 44 | Variable a = new Variable("a"); 45 | 46 | //Act 47 | boolean contains = a.containsVariable(new Variable("b")); 48 | 49 | //Assert 50 | Assert.assertFalse(contains); 51 | } 52 | 53 | @Test 54 | public void test_containsVariable_operation_lhs(){ 55 | //Arrange 56 | Expression node = new Operation(new Variable("a"), new Number(0), null); 57 | 58 | //Act 59 | boolean contains = node.containsVariable(new Variable("a")); 60 | 61 | //Assert 62 | Assert.assertTrue(contains); 63 | } 64 | 65 | @Test 66 | public void test_containsVariable_operation_rhs(){ 67 | //Arrange 68 | Expression node = new Operation(new Number(0), new Variable("a"), null); 69 | 70 | //Act 71 | boolean contains = node.containsVariable(new Variable("a")); 72 | 73 | //Assert 74 | Assert.assertTrue(contains); 75 | } 76 | 77 | @Test 78 | public void test_containsVariable_operation_false(){ 79 | //Arrange 80 | Expression node = new Operation(new Variable("b"), new Variable("a"), null); 81 | 82 | //Act 83 | boolean contains = node.containsVariable(new Variable("c")); 84 | 85 | //Assert 86 | Assert.assertFalse(contains); 87 | } 88 | 89 | @Test 90 | public void test_getFreeVariables_variable(){ 91 | //Arrange 92 | Variable variable = new Variable("a"); 93 | 94 | //Act 95 | Set fv = variable.getFreeVariables(); 96 | 97 | //Assert 98 | Assert.assertEquals(1, fv.size()); 99 | Assert.assertTrue(fv.contains(variable)); 100 | } 101 | 102 | @Test 103 | public void test_getFreeVariables_number(){ 104 | //Arrange 105 | Expression node = new Number(0); 106 | 107 | //Act 108 | Set fv = node.getFreeVariables(); 109 | 110 | //Assert 111 | Assert.assertEquals(0, fv.size()); 112 | } 113 | 114 | @Test 115 | public void test_getFreeVariables_operation_lhs(){ 116 | //Arrange 117 | Variable a = new Variable("a"); 118 | Expression node = new Operation(a, new Number(0), null); 119 | 120 | //Act 121 | Set fv = node.getFreeVariables(); 122 | 123 | //Assert 124 | Assert.assertEquals(1, fv.size()); 125 | Assert.assertTrue(fv.contains(a)); 126 | } 127 | 128 | @Test 129 | public void test_getFreeVariables_operation_rhs(){ 130 | //Arrange 131 | Variable a = new Variable("a"); 132 | Expression node = new Operation(new Number(0), a, null); 133 | 134 | //Act 135 | Set fv = node.getFreeVariables(); 136 | 137 | //Assert 138 | Assert.assertEquals(1, fv.size()); 139 | Assert.assertTrue(fv.contains(a)); 140 | } 141 | 142 | @Test 143 | public void test_getFreeVariables_operation_none(){ 144 | //Arrange 145 | Expression node = new Operation(new Number(0), new Number(1), null); 146 | 147 | //Act 148 | Set fv = node.getFreeVariables(); 149 | 150 | //Assert 151 | Assert.assertEquals(0, fv.size()); 152 | } 153 | 154 | @Test 155 | public void test_getFreeVariables_operation_both(){ 156 | //Arrange 157 | Variable a = new Variable("a"); 158 | Variable b = new Variable("b"); 159 | Expression node = new Operation(a, b, null); 160 | 161 | //Act 162 | Set fv = node.getFreeVariables(); 163 | 164 | //Assert 165 | Assert.assertEquals(2, fv.size()); 166 | Assert.assertTrue(fv.contains(a)); 167 | Assert.assertTrue(fv.contains(b)); 168 | } 169 | 170 | 171 | } 172 | -------------------------------------------------------------------------------- /src/ch/yvu/dfa/tests/ExpressionParserTest.java: -------------------------------------------------------------------------------- 1 | package ch.yvu.dfa.tests; 2 | 3 | import junit.framework.Assert; 4 | 5 | import org.junit.Before; 6 | import org.junit.Test; 7 | 8 | import ch.yvu.dfa.expressions.Expression; 9 | import ch.yvu.dfa.expressions.Number; 10 | import ch.yvu.dfa.expressions.Operation; 11 | import ch.yvu.dfa.expressions.Variable; 12 | import ch.yvu.dfa.parser.FormatException; 13 | import ch.yvu.dfa.parser.expression.ExpressionParser; 14 | 15 | public class ExpressionParserTest { 16 | 17 | private ExpressionParser parser; 18 | 19 | @Before 20 | public void setUp(){ 21 | this.parser = new ExpressionParser(); 22 | } 23 | 24 | @Test 25 | public void test_parse_simple_expression_variable(){ 26 | //Arrange 27 | String input = "a"; 28 | 29 | //Act 30 | Expression node; 31 | try{ 32 | node = parser.parse(input); 33 | }catch(FormatException e){ 34 | throw new RuntimeException(e); 35 | } 36 | 37 | //Assert 38 | Assert.assertNotNull(node); 39 | Assert.assertTrue(node instanceof Variable); 40 | Assert.assertEquals("a", node.getExpression()); 41 | } 42 | 43 | @Test 44 | public void test_parse_simple_expression_variable_multiple_chars(){ 45 | //Arrange 46 | String input = "aVariable"; 47 | 48 | //Act 49 | Expression node; 50 | try{ 51 | node = parser.parse(input); 52 | }catch(FormatException e){ 53 | throw new RuntimeException(e); 54 | } 55 | 56 | //Assert 57 | Assert.assertNotNull(node); 58 | Assert.assertTrue(node instanceof Variable); 59 | Assert.assertEquals("aVariable", node.getExpression()); 60 | } 61 | 62 | @Test 63 | public void test_parse_simple_expression_number(){ 64 | //Arrange 65 | String input = "0"; 66 | 67 | //Act 68 | Expression node; 69 | try{ 70 | node = parser.parse(input); 71 | }catch(FormatException e){ 72 | throw new RuntimeException(e); 73 | } 74 | 75 | //Assert 76 | Assert.assertNotNull(node); 77 | Assert.assertTrue(node instanceof Number); 78 | Assert.assertEquals("0", node.getExpression()); 79 | } 80 | 81 | @Test 82 | public void test_parse_composed_expression_add_two_variables(){ 83 | //Arrange 84 | String input = "a + b"; 85 | 86 | //Act 87 | Expression node; 88 | try{ 89 | node = parser.parse(input); 90 | }catch(FormatException e){ 91 | throw new RuntimeException(e); 92 | } 93 | 94 | //Assert 95 | Assert.assertNotNull(node); 96 | Assert.assertTrue(node instanceof Operation); 97 | Assert.assertEquals("a + b", node.getExpression()); 98 | } 99 | 100 | @Test 101 | public void test_parse_composed_expression_add_variable_number(){ 102 | //Arrange 103 | String input = "a + 10"; 104 | 105 | //Act 106 | Expression node; 107 | try{ 108 | node = parser.parse(input); 109 | }catch(FormatException e){ 110 | throw new RuntimeException(e); 111 | } 112 | 113 | //Assert 114 | Assert.assertNotNull(node); 115 | Assert.assertTrue(node instanceof Operation); 116 | Assert.assertEquals("a + 10", node.getExpression()); 117 | } 118 | 119 | @Test 120 | public void test_parse_composed_expression_add_number_variable(){ 121 | //Arrange 122 | String input = "10 + a"; 123 | 124 | //Act 125 | Expression node; 126 | try{ 127 | node = parser.parse(input); 128 | }catch(FormatException e){ 129 | throw new RuntimeException(e); 130 | } 131 | 132 | //Assert 133 | Assert.assertNotNull(node); 134 | Assert.assertTrue(node instanceof Operation); 135 | Assert.assertEquals("10 + a", node.getExpression()); 136 | } 137 | 138 | @Test 139 | public void test_parse_composed_expression_compare_two_chars(){ 140 | //Arrange 141 | String input = "10 <= a"; 142 | 143 | //Act 144 | Expression node; 145 | try{ 146 | node = parser.parse(input); 147 | }catch(FormatException e){ 148 | throw new RuntimeException(e); 149 | } 150 | 151 | //Assert 152 | Assert.assertNotNull(node); 153 | Assert.assertTrue(node instanceof Operation); 154 | Assert.assertEquals("10 <= a", node.getExpression()); 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /src/ch/yvu/dfa/tests/NodeTest.java: -------------------------------------------------------------------------------- 1 | package ch.yvu.dfa.tests; 2 | 3 | import junit.framework.Assert; 4 | import org.junit.Before; 5 | import org.junit.Test; 6 | 7 | import ch.yvu.dfa.controlflowgraph.ConditionalNode; 8 | import ch.yvu.dfa.controlflowgraph.Node; 9 | import ch.yvu.dfa.expressions.*; 10 | 11 | public class NodeTest { 12 | 13 | private Node node; 14 | 15 | @Before 16 | public void setUp(){ 17 | this.node = new ConditionalNode(1, new Variable("a"), new Variable("b"), "=="); 18 | } 19 | 20 | @Test(expected=IllegalArgumentException.class) 21 | public void test_addChild_null(){ 22 | this.node.addChild(null); 23 | } 24 | 25 | @Test 26 | public void test_addChild_non_existing_child(){ 27 | //Arrange 28 | ConditionalNode child = new ConditionalNode(2, new Variable("a"), new Variable("b"), "=="); 29 | 30 | //Act 31 | this.node.addChild(child); 32 | 33 | //Assert 34 | Assert.assertEquals(1, node.numChildren()); 35 | } 36 | 37 | @Test 38 | public void test_addChild_existing_child(){ 39 | //Arrange 40 | ConditionalNode child = new ConditionalNode(2, new Variable("a"), new Variable("b"), "=="); 41 | this.node.addChild(child); 42 | 43 | //Act 44 | this.node.addChild(child); 45 | 46 | //Assert 47 | Assert.assertEquals(1, this.node.numChildren()); 48 | } 49 | } 50 | --------------------------------------------------------------------------------