diff options
95 files changed, 3772 insertions, 1483 deletions
diff --git a/chapter01/README.md b/chapter01/README.md index e09b61a3..f5f31f82 100644 --- a/chapter01/README.md +++ b/chapter01/README.md @@ -164,5 +164,7 @@ return 1;  -* Control nodes appear as square boxes +* Control nodes appear as square boxes with yellow background * Control edges are in bold red +* The edges from Constants to Start are shown in dotted lines as these are not true control edges +* We label each edge with its position in the `_inputs` array, thus `0` means the edge is `_inputs[0]`. diff --git a/chapter01/docs/01-graph.gv b/chapter01/docs/01-graph.gv index 82d1b40a..df256f52 100644 --- a/chapter01/docs/01-graph.gv +++ b/chapter01/docs/01-graph.gv @@ -1,11 +1,17 @@ digraph chapter01 { +/* +return 1; +*/ rankdir=BT; + ordering="in"; + concentrate="true"; subgraph cluster_Nodes { Start1 [ shape=box style=filled fillcolor=yellow label="Start" ]; - Con12 [ label="Con1" ]; + Con_2 [ label="#1" ]; Return3 [ shape=box style=filled fillcolor=yellow label="Return" ]; } - Con12 -> Start1 [style=dotted]; - Return3 -> Start1 [color=red]; - Return3 -> Con12; + edge [ fontname=Helvetica, fontsize=8 ]; + Con_2 -> Start1[taillabel=0 style=dotted]; + Return3 -> Start1[taillabel=0 color=red]; + Return3 -> Con_2[taillabel=1]; } diff --git a/chapter01/docs/01-graph.svg b/chapter01/docs/01-graph.svg index 8e478f4d..7f511966 100644 --- a/chapter01/docs/01-graph.svg +++ b/chapter01/docs/01-graph.svg @@ -4,50 +4,53 @@ <!-- Generated by graphviz version 2.43.0 (0) --> <!-- Title: chapter01 Pages: 1 --> -<svg width="128pt" height="220pt" - viewBox="0.00 0.00 128.00 220.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> +<svg width="114pt" height="220pt" + viewBox="0.00 0.00 114.00 220.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 216)"> <title>chapter01</title> -<polygon fill="white" stroke="transparent" points="-4,4 -4,-216 124,-216 124,4 -4,4"/> +<polygon fill="white" stroke="transparent" points="-4,4 -4,-216 110,-216 110,4 -4,4"/> <g id="clust1" class="cluster"> <title>cluster_Nodes</title> -<polygon fill="none" stroke="black" points="8,-8 8,-204 112,-204 112,-8 8,-8"/> +<polygon fill="none" stroke="black" points="8,-8 8,-204 98,-204 98,-8 8,-8"/> </g> <!-- Start1 --> <g id="node1" class="node"> <title>Start1</title> -<polygon fill="yellow" stroke="black" points="83,-196 29,-196 29,-160 83,-160 83,-196"/> -<text text-anchor="middle" x="56" y="-174.3" font-family="Times,serif" font-size="14.00">Start</text> +<polygon fill="yellow" stroke="black" points="80,-196 26,-196 26,-160 80,-160 80,-196"/> +<text text-anchor="middle" x="53" y="-174.3" font-family="Times,serif" font-size="14.00">Start</text> </g> -<!-- Con12 --> +<!-- Con_2 --> <g id="node2" class="node"> -<title>Con12</title> -<ellipse fill="none" stroke="black" cx="70" cy="-106" rx="34.39" ry="18"/> -<text text-anchor="middle" x="70" y="-102.3" font-family="Times,serif" font-size="14.00">Con1</text> +<title>Con_2</title> +<ellipse fill="none" stroke="black" cx="43" cy="-106" rx="27" ry="18"/> +<text text-anchor="middle" x="43" y="-102.3" font-family="Times,serif" font-size="14.00">#1</text> </g> -<!-- Con12->Start1 --> +<!-- Con_2->Start1 --> <g id="edge1" class="edge"> -<title>Con12->Start1</title> -<path fill="none" stroke="black" stroke-dasharray="1,5" d="M66.61,-123.95C65.07,-131.65 63.21,-140.97 61.47,-149.64"/> -<polygon fill="black" stroke="black" points="57.98,-149.23 59.46,-159.72 64.85,-150.61 57.98,-149.23"/> +<title>Con_2->Start1</title> +<path fill="none" stroke="black" stroke-dasharray="1,5" d="M45.42,-123.95C46.52,-131.65 47.85,-140.97 49.09,-149.64"/> +<polygon fill="black" stroke="black" points="45.65,-150.32 50.53,-159.72 52.58,-149.33 45.65,-150.32"/> +<text text-anchor="middle" x="42.42" y="-126.55" font-family="Helvetica,sans-Serif" font-size="8.00">0</text> </g> <!-- Return3 --> <g id="node3" class="node"> <title>Return3</title> -<polygon fill="yellow" stroke="black" points="92,-52 26,-52 26,-16 92,-16 92,-52"/> -<text text-anchor="middle" x="59" y="-30.3" font-family="Times,serif" font-size="14.00">Return</text> +<polygon fill="yellow" stroke="black" points="86,-52 20,-52 20,-16 86,-16 86,-52"/> +<text text-anchor="middle" x="53" y="-30.3" font-family="Times,serif" font-size="14.00">Return</text> </g> <!-- Return3->Start1 --> <g id="edge2" class="edge"> <title>Return3->Start1</title> -<path fill="none" stroke="red" d="M45.44,-52.03C38.44,-61.91 30.63,-74.95 27,-88 22.71,-103.41 23.04,-108.5 27,-124 29.38,-133.3 33.76,-142.73 38.42,-151"/> -<polygon fill="red" stroke="red" points="35.54,-153.01 43.69,-159.78 41.54,-149.41 35.54,-153.01"/> +<path fill="none" stroke="red" d="M64.05,-52.39C69.74,-62.38 76.08,-75.42 79,-88 82.62,-103.59 82.62,-108.41 79,-124 76.9,-133.04 73.03,-142.32 68.91,-150.53"/> +<polygon fill="red" stroke="red" points="65.69,-149.14 64.05,-159.61 71.86,-152.45 65.69,-149.14"/> +<text text-anchor="middle" x="61.05" y="-54.99" font-family="Helvetica,sans-Serif" font-size="8.00">0</text> </g> -<!-- Return3->Con12 --> +<!-- Return3->Con_2 --> <g id="edge3" class="edge"> -<title>Return3->Con12</title> -<path fill="none" stroke="black" d="M61.72,-52.3C62.93,-60.02 64.39,-69.29 65.74,-77.89"/> -<polygon fill="black" stroke="black" points="62.3,-78.56 67.31,-87.9 69.22,-77.47 62.3,-78.56"/> +<title>Return3->Con_2</title> +<path fill="none" stroke="black" d="M50.53,-52.3C49.43,-60.02 48.1,-69.29 46.87,-77.89"/> +<polygon fill="black" stroke="black" points="43.39,-77.5 45.44,-87.9 50.32,-78.49 43.39,-77.5"/> +<text text-anchor="middle" x="47.53" y="-54.9" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> </g> </g> </svg> diff --git a/chapter01/src/main/java/com/seaofnodes/simple/Parser.java b/chapter01/src/main/java/com/seaofnodes/simple/Parser.java index a71def25..e2c1ca71 100644 --- a/chapter01/src/main/java/com/seaofnodes/simple/Parser.java +++ b/chapter01/src/main/java/com/seaofnodes/simple/Parser.java @@ -1,20 +1,16 @@ package com.seaofnodes.simple; -import com.seaofnodes.simple.node.ConstantNode; -import com.seaofnodes.simple.node.Node; -import com.seaofnodes.simple.node.ReturnNode; -import com.seaofnodes.simple.node.StartNode; +import com.seaofnodes.simple.node.*; /** - * The Parser converts a Simple source program to the Sea of Nodes intermediate representation - * directly in one pass. There is no intermediate Abstract Syntax Tree structure. - * + * The Parser converts a Simple source program to the Sea of Nodes intermediate + * representation directly in one pass. There is no intermediate Abstract + * Syntax Tree structure. + * <p> * This is a simple recursive descent parser. All lexical analysis is done here as well. */ public class Parser { - private final Lexer _lexer; - /** * A Global Static, unique to each compilation. This is a public, so we * can make constants everywhere without having to thread the StartNode @@ -24,6 +20,10 @@ public class Parser { */ public static StartNode START; + // The Lexer. Thin wrapper over a byte[] buffer with a cursor. + private final Lexer _lexer; + + public Parser(String source) { _lexer = new Lexer(source); Node.reset(); @@ -31,21 +31,21 @@ public class Parser { } public ReturnNode parse() { + require("return"); return parseReturn(); } /** - * Parses return statement. + * Parses a return statement; "return" already parsed. * * <pre> - * return expr ; + * 'return' expr ; * </pre> + * @return an expression {@link Node}, never {@code null} */ private ReturnNode parseReturn() { - require("return"); - var returnExpr = parseExpression(); - require(";"); - return new ReturnNode(START, returnExpr); + var expr = require(parseExpression(), ";"); + return new ReturnNode(START, expr); } /** @@ -54,6 +54,7 @@ public class Parser { * <pre> * expr : primaryExpr * </pre> + * @return an expression {@link Node}, never {@code null} */ private Node parseExpression() { return parsePrimary(); @@ -81,25 +82,28 @@ public class Parser { * </pre> */ private ConstantNode parseIntegerLiteral() { - return new ConstantNode(_lexer.parseNumber(), START); - } - - static RuntimeException error(String errorMessage) { - return new RuntimeException(errorMessage); + return new ConstantNode(_lexer.parseNumber()); } ////////////////////////////////// // Utilities for lexical analysis // Return true and skip if "syntax" is next in the stream. - private boolean match(String syntax) { - return _lexer.match(syntax); - } + private boolean match(String syntax) { return _lexer.match(syntax); } // Require an exact match - private void require(String syntax) { - if (match(syntax)) return; - throw error("Syntax error, expected " + syntax + ": " + _lexer.getAnyNextToken()); + private void require(String syntax) { require(null, syntax); } + private Node require(Node n, String syntax) { + if (match(syntax)) return n; + throw errorSyntax(syntax); + } + + RuntimeException errorSyntax(String syntax) { + return error("Syntax error, expected " + syntax + ": " + _lexer.getAnyNextToken()); + } + + static RuntimeException error(String errorMessage) { + return new RuntimeException(errorMessage); } //////////////////////////////////// @@ -152,8 +156,7 @@ public class Parser { * Return the next non-white-space character */ private void skipWhiteSpace() { - while (isWhiteSpace()) - _position++; + while (isWhiteSpace()) _position++; } @@ -163,8 +166,7 @@ public class Parser { boolean match(String syntax) { skipWhiteSpace(); int len = syntax.length(); - if (_position + len > _input.length) - return false; + if (_position + len > _input.length) return false; for (int i = 0; i < len; i++) if ((char) _input[_position + i] != syntax.charAt(i)) return false; @@ -175,20 +177,13 @@ public class Parser { // Used for errors String getAnyNextToken() { if (isEOF()) return ""; - if (isIdentifierStart(peek())) - return parseIdentifier(); - if (isPunctuation(peek())) - return parsePunctuation(); + if (isIdStart(peek())) return parseId(); + if (isPunctuation(peek())) return parsePunctuation(); return String.valueOf(peek()); } - boolean isNumber() { - return isNumber(peek()); - } - - boolean isNumber(char ch) { - return Character.isDigit(ch); - } + boolean isNumber() {return isNumber(peek());} + boolean isNumber(char ch) {return Character.isDigit(ch);} private long parseNumber() { int start = _position; @@ -200,18 +195,18 @@ public class Parser { } // First letter of an identifier - private boolean isIdentifierStart(char ch) { + private boolean isIdStart(char ch) { return Character.isAlphabetic(ch) || ch == '_'; } // All characters of an identifier, e.g. "_x123" - private boolean isIdentifierLetter(char ch) { + private boolean isIdLetter(char ch) { return Character.isLetterOrDigit(ch) || ch == '_'; } - private String parseIdentifier() { + private String parseId() { int start = _position; - while (isIdentifierLetter(nextChar())) ; + while (isIdLetter(nextChar())) ; return new String(_input, start, --_position - start); } @@ -222,8 +217,7 @@ public class Parser { private String parsePunctuation() { int start = _position; - if (isPunctuation(nextChar())) ; - return new String(_input, start, --_position - start); + return new String(_input, start, 1); } } diff --git a/chapter01/src/main/java/com/seaofnodes/simple/node/ConstantNode.java b/chapter01/src/main/java/com/seaofnodes/simple/node/ConstantNode.java index 7644daf2..21f65084 100644 --- a/chapter01/src/main/java/com/seaofnodes/simple/node/ConstantNode.java +++ b/chapter01/src/main/java/com/seaofnodes/simple/node/ConstantNode.java @@ -1,5 +1,7 @@ package com.seaofnodes.simple.node; +import com.seaofnodes.simple.Parser; + /** * A Constant node represents a constant value. At present, the only constants * that we allow are integer literals; therefore Constants contain an integer @@ -16,8 +18,8 @@ public class ConstantNode extends Node { public final long _value; - public ConstantNode(long value, StartNode startNode) { - super(startNode); + public ConstantNode(long value) { + super(Parser.START); _value = value; } } diff --git a/chapter01/src/main/java/com/seaofnodes/simple/node/Control.java b/chapter01/src/main/java/com/seaofnodes/simple/node/Control.java deleted file mode 100644 index 48cf2b7a..00000000 --- a/chapter01/src/main/java/com/seaofnodes/simple/node/Control.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.seaofnodes.simple.node; - - -/** - * Control interface is a marker interface to be implemented - * by Control nodes. - */ -public interface Control { -} diff --git a/chapter01/src/main/java/com/seaofnodes/simple/node/Node.java b/chapter01/src/main/java/com/seaofnodes/simple/node/Node.java index b6ce3160..cf465e94 100644 --- a/chapter01/src/main/java/com/seaofnodes/simple/node/Node.java +++ b/chapter01/src/main/java/com/seaofnodes/simple/node/Node.java @@ -1,7 +1,6 @@ package com.seaofnodes.simple.node; -import java.util.ArrayList; -import java.util.Collections; +import java.util.*; /** * All Nodes in the Sea of Nodes IR inherit from the Node class. @@ -22,8 +21,7 @@ public abstract class Node { * <p> * Generally fixed length, ordered, nulls allowed, no unused trailing space. * Ordering is required because e.g. "a/b" is different from "b/a". - * The first input (offset 0) is often a Control node. - * @see Control + * The first input (offset 0) is often a {@link #isCFG} node. */ public final ArrayList<Node> _inputs; @@ -45,17 +43,16 @@ public abstract class Node { * */ private static int UNIQUE_ID = 1; - protected Node(Node ...inputs) { + protected Node(Node... inputs) { _nid = UNIQUE_ID++; // allocate unique dense ID _inputs = new ArrayList<>(); Collections.addAll(_inputs,inputs); _outputs = new ArrayList<>(); - for( Node n : _inputs ) { + for( Node n : _inputs ) if( n != null ) n._outputs.add( this ); - } } - + /** * Gets the ith input node * @param i Offset of the input node @@ -65,23 +62,16 @@ public abstract class Node { public int nIns() { return _inputs.size(); } - /** - * Gets the ith output node - * @param i Offset of the output node - * @return Output node (not null) - */ - public Node out(int i) { return _outputs.get(i); } - public int nOuts() { return _outputs.size(); } + public boolean isUnused() { return nOuts() == 0; } + + public boolean isCFG() { return false; } + + /** * Used to allow repeating tests in the same JVM. This just resets the * Node unique id generator, and is done as part of making a new Parser. */ - public static void reset() { - UNIQUE_ID = 1; - } - /* - * hashCode and equals implementation to be added in later chapter. - */ + public static void reset() { UNIQUE_ID = 1; } } diff --git a/chapter01/src/main/java/com/seaofnodes/simple/node/ReturnNode.java b/chapter01/src/main/java/com/seaofnodes/simple/node/ReturnNode.java index a2321e2b..5e083cf2 100644 --- a/chapter01/src/main/java/com/seaofnodes/simple/node/ReturnNode.java +++ b/chapter01/src/main/java/com/seaofnodes/simple/node/ReturnNode.java @@ -9,17 +9,15 @@ package com.seaofnodes.simple.node; * <p> * The Return's output is the value from the data node. */ -public class ReturnNode extends Node implements Control { +public class ReturnNode extends Node { public ReturnNode(Node ctrl, Node data) { super(ctrl, data); } - public Node ctrl() { - return in(0); - } + public Node ctrl() { return in(0); } + public Node expr() { return in(1); } - public Node expr() { - return in(1); - } + @Override public boolean isCFG() { return true; } + } diff --git a/chapter01/src/main/java/com/seaofnodes/simple/node/StartNode.java b/chapter01/src/main/java/com/seaofnodes/simple/node/StartNode.java index c29ba53c..04bd6bb4 100644 --- a/chapter01/src/main/java/com/seaofnodes/simple/node/StartNode.java +++ b/chapter01/src/main/java/com/seaofnodes/simple/node/StartNode.java @@ -5,9 +5,12 @@ package com.seaofnodes.simple.node; * yet accept parameters. When we add parameters the value of Start will be a tuple, and will require Projections to extract the values. * We discuss this in detail in Chapter 9: Functions and Calls. */ -public class StartNode extends Node implements Control { +public class StartNode extends Node { public StartNode(/*arguments go here*/) { super(); } + + @Override public boolean isCFG() { return true; } + } diff --git a/chapter01/src/test/java/com/seaofnodes/simple/Chapter01Test.java b/chapter01/src/test/java/com/seaofnodes/simple/Chapter01Test.java index ce8c2822..cb5a8a69 100644 --- a/chapter01/src/test/java/com/seaofnodes/simple/Chapter01Test.java +++ b/chapter01/src/test/java/com/seaofnodes/simple/Chapter01Test.java @@ -1,15 +1,11 @@ package com.seaofnodes.simple; -import com.seaofnodes.simple.node.ConstantNode; -import com.seaofnodes.simple.node.Node; -import com.seaofnodes.simple.node.ReturnNode; -import com.seaofnodes.simple.node.StartNode; +import com.seaofnodes.simple.node.*; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; +import static org.junit.Assert.*; public class Chapter01Test { @@ -21,11 +17,11 @@ public class Chapter01Test { Parser parser = new Parser("return 1;"); ReturnNode ret = parser.parse(); StartNode start = Parser.START; - + assertEquals(start, ret.ctrl()); Node expr = ret.expr(); - if (expr instanceof ConstantNode con) { - assertEquals(start, con.in(0)); + if( expr instanceof ConstantNode con ) { + assertEquals(start,con.in(0)); assertEquals(1, con._value); } else { fail(); @@ -44,16 +40,22 @@ public class Chapter01Test { @Test public void testBad1() { - exceptionRule.expect(RuntimeException.class); - exceptionRule.expectMessage("Syntax error, expected return: ret"); - new Parser("ret").parse(); + try { + new Parser("ret").parse(); + fail(); + } catch( RuntimeException e ) { + assertEquals("Syntax error, expected return: ret",e.getMessage()); + } } @Test public void testBad2() { - exceptionRule.expect(RuntimeException.class); - exceptionRule.expectMessage("Syntax error: integer values cannot start with '0'"); - new Parser("return 0123;").parse(); + try { + new Parser("return 0123;").parse(); + fail(); + } catch( RuntimeException e ) { + assertEquals("Syntax error: integer values cannot start with '0'",e.getMessage()); + } } @Test @@ -65,9 +67,12 @@ public class Chapter01Test { @Test public void testBad4() { - exceptionRule.expect(RuntimeException.class); - exceptionRule.expectMessage("Syntax error, expected ;:"); - new Parser("return 100").parse(); + try { + new Parser("return 100").parse(); + fail(); + } catch( RuntimeException e ) { + assertEquals("Syntax error, expected ;: ",e.getMessage()); + } } // Negative numbers require unary operator support that is not in scope diff --git a/chapter02/README.md b/chapter02/README.md index b89a3059..e1ee19aa 100644 --- a/chapter02/README.md +++ b/chapter02/README.md @@ -117,9 +117,10 @@ The following visual shows how the graph looks like pre-peephole optimization:  -* Control nodes appear as square boxes +* Control nodes appear as square boxes with yellow background * Control edges are in bold red -* The edges from Start to Constants are shown in dotted lines as these are not true def-use edges +* The edges from Constants to Start are shown in dotted lines as these are not true control edges +* We label each edge with its position in the node's list of inputs. ## Post-peephole diff --git a/chapter02/docs/02-post-peephole-ex1.gv b/chapter02/docs/02-post-peephole-ex1.gv index 290a1178..6c2b23ae 100644 --- a/chapter02/docs/02-post-peephole-ex1.gv +++ b/chapter02/docs/02-post-peephole-ex1.gv @@ -1,11 +1,17 @@ digraph chapter02 { +/* +return 1+2*3+-5; +*/ rankdir=BT; + ordering="in"; + concentrate="true"; subgraph cluster_Nodes { Start1 [ shape=box style=filled fillcolor=yellow label="Start" ]; - Con213 [ label="Con2" ]; + Con_13 [ label="#2" ]; Return14 [ shape=box style=filled fillcolor=yellow label="Return" ]; } - Con213 -> Start1 [style=dotted]; - Return14 -> Start1 [color=red]; - Return14 -> Con213; -}
\ No newline at end of file + edge [ fontname=Helvetica, fontsize=8 ]; + Con_13 -> Start1[taillabel=0 style=dotted]; + Return14 -> Start1[taillabel=0 color=red]; + Return14 -> Con_13[taillabel=1]; +} diff --git a/chapter02/docs/02-post-peephole-ex1.svg b/chapter02/docs/02-post-peephole-ex1.svg index b3c42c7d..db27e30d 100644 --- a/chapter02/docs/02-post-peephole-ex1.svg +++ b/chapter02/docs/02-post-peephole-ex1.svg @@ -4,50 +4,53 @@ <!-- Generated by graphviz version 2.43.0 (0) --> <!-- Title: chapter02 Pages: 1 --> -<svg width="128pt" height="220pt" - viewBox="0.00 0.00 128.00 220.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> +<svg width="114pt" height="220pt" + viewBox="0.00 0.00 114.00 220.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 216)"> <title>chapter02</title> -<polygon fill="white" stroke="transparent" points="-4,4 -4,-216 124,-216 124,4 -4,4"/> +<polygon fill="white" stroke="transparent" points="-4,4 -4,-216 110,-216 110,4 -4,4"/> <g id="clust1" class="cluster"> <title>cluster_Nodes</title> -<polygon fill="none" stroke="black" points="8,-8 8,-204 112,-204 112,-8 8,-8"/> +<polygon fill="none" stroke="black" points="8,-8 8,-204 98,-204 98,-8 8,-8"/> </g> <!-- Start1 --> <g id="node1" class="node"> <title>Start1</title> -<polygon fill="yellow" stroke="black" points="83,-196 29,-196 29,-160 83,-160 83,-196"/> -<text text-anchor="middle" x="56" y="-174.3" font-family="Times,serif" font-size="14.00">Start</text> +<polygon fill="yellow" stroke="black" points="80,-196 26,-196 26,-160 80,-160 80,-196"/> +<text text-anchor="middle" x="53" y="-174.3" font-family="Times,serif" font-size="14.00">Start</text> </g> -<!-- Con213 --> +<!-- Con_13 --> <g id="node2" class="node"> -<title>Con213</title> -<ellipse fill="none" stroke="black" cx="70" cy="-106" rx="34.39" ry="18"/> -<text text-anchor="middle" x="70" y="-102.3" font-family="Times,serif" font-size="14.00">Con2</text> +<title>Con_13</title> +<ellipse fill="none" stroke="black" cx="43" cy="-106" rx="27" ry="18"/> +<text text-anchor="middle" x="43" y="-102.3" font-family="Times,serif" font-size="14.00">#2</text> </g> -<!-- Con213->Start1 --> +<!-- Con_13->Start1 --> <g id="edge1" class="edge"> -<title>Con213->Start1</title> -<path fill="none" stroke="black" stroke-dasharray="1,5" d="M66.61,-123.95C65.07,-131.65 63.21,-140.97 61.47,-149.64"/> -<polygon fill="black" stroke="black" points="57.98,-149.23 59.46,-159.72 64.85,-150.61 57.98,-149.23"/> +<title>Con_13->Start1</title> +<path fill="none" stroke="black" stroke-dasharray="1,5" d="M45.42,-123.95C46.52,-131.65 47.85,-140.97 49.09,-149.64"/> +<polygon fill="black" stroke="black" points="45.65,-150.32 50.53,-159.72 52.58,-149.33 45.65,-150.32"/> +<text text-anchor="middle" x="42.42" y="-126.55" font-family="Helvetica,sans-Serif" font-size="8.00">0</text> </g> <!-- Return14 --> <g id="node3" class="node"> <title>Return14</title> -<polygon fill="yellow" stroke="black" points="92,-52 26,-52 26,-16 92,-16 92,-52"/> -<text text-anchor="middle" x="59" y="-30.3" font-family="Times,serif" font-size="14.00">Return</text> +<polygon fill="yellow" stroke="black" points="86,-52 20,-52 20,-16 86,-16 86,-52"/> +<text text-anchor="middle" x="53" y="-30.3" font-family="Times,serif" font-size="14.00">Return</text> </g> <!-- Return14->Start1 --> <g id="edge2" class="edge"> <title>Return14->Start1</title> -<path fill="none" stroke="red" d="M45.44,-52.03C38.44,-61.91 30.63,-74.95 27,-88 22.71,-103.41 23.04,-108.5 27,-124 29.38,-133.3 33.76,-142.73 38.42,-151"/> -<polygon fill="red" stroke="red" points="35.54,-153.01 43.69,-159.78 41.54,-149.41 35.54,-153.01"/> +<path fill="none" stroke="red" d="M64.05,-52.39C69.74,-62.38 76.08,-75.42 79,-88 82.62,-103.59 82.62,-108.41 79,-124 76.9,-133.04 73.03,-142.32 68.91,-150.53"/> +<polygon fill="red" stroke="red" points="65.69,-149.14 64.05,-159.61 71.86,-152.45 65.69,-149.14"/> +<text text-anchor="middle" x="61.05" y="-54.99" font-family="Helvetica,sans-Serif" font-size="8.00">0</text> </g> -<!-- Return14->Con213 --> +<!-- Return14->Con_13 --> <g id="edge3" class="edge"> -<title>Return14->Con213</title> -<path fill="none" stroke="black" d="M61.72,-52.3C62.93,-60.02 64.39,-69.29 65.74,-77.89"/> -<polygon fill="black" stroke="black" points="62.3,-78.56 67.31,-87.9 69.22,-77.47 62.3,-78.56"/> +<title>Return14->Con_13</title> +<path fill="none" stroke="black" d="M50.53,-52.3C49.43,-60.02 48.1,-69.29 46.87,-77.89"/> +<polygon fill="black" stroke="black" points="43.39,-77.5 45.44,-87.9 50.32,-78.49 43.39,-77.5"/> +<text text-anchor="middle" x="47.53" y="-54.9" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> </g> </g> </svg> diff --git a/chapter02/docs/02-pre-peephole-ex1.gv b/chapter02/docs/02-pre-peephole-ex1.gv index c2eab457..411de5ee 100644 --- a/chapter02/docs/02-pre-peephole-ex1.gv +++ b/chapter02/docs/02-pre-peephole-ex1.gv @@ -1,28 +1,34 @@ digraph chapter02 { +/* +return 1+2*3+-5; +*/ rankdir=BT; + ordering="in"; + concentrate="true"; subgraph cluster_Nodes { Start1 [ shape=box style=filled fillcolor=yellow label="Start" ]; - Con12 [ label="Con1" ]; - Con23 [ label="Con2" ]; - Con34 [ label="Con3" ]; - Mul5 [ label="Mul" ]; - Con56 [ label="Con5" ]; - Minus7 [ label="Minus" ]; - Add8 [ label="Add" ]; - Add9 [ label="Add" ]; + Con_2 [ label="#1" ]; + Con_3 [ label="#2" ]; + Con_4 [ label="#3" ]; + Mul5 [ label="*" ]; + Con_6 [ label="#5" ]; + Minus7 [ label="-" ]; + Add8 [ label="+" ]; + Add9 [ label="+" ]; Return10 [ shape=box style=filled fillcolor=yellow label="Return" ]; } - Con12 -> Start1 [style=dotted]; - Con23 -> Start1 [style=dotted]; - Con34 -> Start1 [style=dotted]; - Mul5 -> Con23; - Mul5 -> Con34; - Con56 -> Start1 [style=dotted]; - Minus7 -> Con56; - Add8 -> Mul5; - Add8 -> Minus7; - Add9 -> Con12; - Add9 -> Add8; - Return10 -> Start1 [color=red]; - Return10 -> Add9; -}
\ No newline at end of file + edge [ fontname=Helvetica, fontsize=8 ]; + Con_2 -> Start1[taillabel=0 style=dotted]; + Con_3 -> Start1[taillabel=0 style=dotted]; + Con_4 -> Start1[taillabel=0 style=dotted]; + Mul5 -> Con_3[taillabel=1]; + Mul5 -> Con_4[taillabel=2]; + Con_6 -> Start1[taillabel=0 style=dotted]; + Minus7 -> Con_6[taillabel=1]; + Add8 -> Mul5[taillabel=1]; + Add8 -> Minus7[taillabel=2]; + Add9 -> Con_2[taillabel=1]; + Add9 -> Add8[taillabel=2]; + Return10 -> Start1[taillabel=0 color=red]; + Return10 -> Add9[taillabel=1]; +} diff --git a/chapter02/docs/02-pre-peephole-ex1.svg b/chapter02/docs/02-pre-peephole-ex1.svg index 8a1ef457..29c76bd8 100644 --- a/chapter02/docs/02-pre-peephole-ex1.svg +++ b/chapter02/docs/02-pre-peephole-ex1.svg @@ -4,152 +4,165 @@ <!-- Generated by graphviz version 2.43.0 (0) --> <!-- Title: chapter02 Pages: 1 --> -<svg width="322pt" height="436pt" - viewBox="0.00 0.00 322.00 436.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> +<svg width="278pt" height="436pt" + viewBox="0.00 0.00 278.00 436.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 432)"> <title>chapter02</title> -<polygon fill="white" stroke="transparent" points="-4,4 -4,-432 318,-432 318,4 -4,4"/> +<polygon fill="white" stroke="transparent" points="-4,4 -4,-432 274,-432 274,4 -4,4"/> <g id="clust1" class="cluster"> <title>cluster_Nodes</title> -<polygon fill="none" stroke="black" points="8,-8 8,-420 306,-420 306,-8 8,-8"/> +<polygon fill="none" stroke="black" points="8,-8 8,-420 262,-420 262,-8 8,-8"/> </g> <!-- Start1 --> <g id="node1" class="node"> <title>Start1</title> -<polygon fill="yellow" stroke="black" points="117,-412 63,-412 63,-376 117,-376 117,-412"/> -<text text-anchor="middle" x="90" y="-390.3" font-family="Times,serif" font-size="14.00">Start</text> +<polygon fill="yellow" stroke="black" points="162,-412 108,-412 108,-376 162,-376 162,-412"/> +<text text-anchor="middle" x="135" y="-390.3" font-family="Times,serif" font-size="14.00">Start</text> </g> -<!-- Con12 --> +<!-- Con_2 --> <g id="node2" class="node"> -<title>Con12</title> -<ellipse fill="none" stroke="black" cx="70" cy="-178" rx="34.39" ry="18"/> -<text text-anchor="middle" x="70" y="-174.3" font-family="Times,serif" font-size="14.00">Con1</text> +<title>Con_2</title> +<ellipse fill="none" stroke="black" cx="222" cy="-178" rx="27" ry="18"/> +<text text-anchor="middle" x="222" y="-174.3" font-family="Times,serif" font-size="14.00">#1</text> </g> -<!-- Con12->Start1 --> +<!-- Con_2->Start1 --> <g id="edge1" class="edge"> -<title>Con12->Start1</title> -<path fill="none" stroke="black" stroke-dasharray="1,5" d="M62.43,-195.98C50.2,-225.92 29.16,-289.7 47,-340 50.66,-350.32 57.29,-360.1 64.26,-368.39"/> -<polygon fill="black" stroke="black" points="61.67,-370.74 70.96,-375.84 66.87,-366.06 61.67,-370.74"/> +<title>Con_2->Start1</title> +<path fill="none" stroke="black" stroke-dasharray="1,5" d="M230.65,-195.54C245.5,-226.47 271.62,-294.07 243,-340 227.56,-364.77 196.8,-378.29 172.04,-385.46"/> +<polygon fill="black" stroke="black" points="170.97,-382.13 162.2,-388.08 172.77,-388.89 170.97,-382.13"/> +<text text-anchor="middle" x="227.65" y="-198.14" font-family="Helvetica,sans-Serif" font-size="8.00">0</text> </g> -<!-- Con23 --> +<!-- Con_3 --> <g id="node3" class="node"> -<title>Con23</title> -<ellipse fill="none" stroke="black" cx="90" cy="-322" rx="34.39" ry="18"/> -<text text-anchor="middle" x="90" y="-318.3" font-family="Times,serif" font-size="14.00">Con2</text> +<title>Con_3</title> +<ellipse fill="none" stroke="black" cx="63" cy="-322" rx="27" ry="18"/> +<text text-anchor="middle" x="63" y="-318.3" font-family="Times,serif" font-size="14.00">#2</text> </g> -<!-- Con23->Start1 --> +<!-- Con_3->Start1 --> <g id="edge2" class="edge"> -<title>Con23->Start1</title> -<path fill="none" stroke="black" stroke-dasharray="1,5" d="M90,-340.3C90,-348.02 90,-357.29 90,-365.89"/> -<polygon fill="black" stroke="black" points="86.5,-365.9 90,-375.9 93.5,-365.9 86.5,-365.9"/> +<title>Con_3->Start1</title> +<path fill="none" stroke="black" stroke-dasharray="1,5" d="M77.57,-337.17C86.92,-346.25 99.3,-358.29 110.17,-368.86"/> +<polygon fill="black" stroke="black" points="107.79,-371.43 117.4,-375.89 112.67,-366.41 107.79,-371.43"/> +<text text-anchor="middle" x="74.57" y="-339.77" font-family="Helvetica,sans-Serif" font-size="8.00">0</text> </g> -<!-- Con34 --> +<!-- Con_4 --> <g id="node4" class="node"> -<title>Con34</title> -<ellipse fill="none" stroke="black" cx="177" cy="-322" rx="34.39" ry="18"/> -<text text-anchor="middle" x="177" y="-318.3" font-family="Times,serif" font-size="14.00">Con3</text> +<title>Con_4</title> +<ellipse fill="none" stroke="black" cx="135" cy="-322" rx="27" ry="18"/> +<text text-anchor="middle" x="135" y="-318.3" font-family="Times,serif" font-size="14.00">#3</text> </g> -<!-- Con34->Start1 --> +<!-- Con_4->Start1 --> <g id="edge3" class="edge"> -<title>Con34->Start1</title> -<path fill="none" stroke="black" stroke-dasharray="1,5" d="M158.97,-337.5C147.52,-346.72 132.42,-358.87 119.27,-369.45"/> -<polygon fill="black" stroke="black" points="116.98,-366.8 111.38,-375.8 121.37,-372.25 116.98,-366.8"/> +<title>Con_4->Start1</title> +<path fill="none" stroke="black" stroke-dasharray="1,5" d="M135,-340.3C135,-348.02 135,-357.29 135,-365.89"/> +<polygon fill="black" stroke="black" points="131.5,-365.9 135,-375.9 138.5,-365.9 131.5,-365.9"/> +<text text-anchor="middle" x="132" y="-342.9" font-family="Helvetica,sans-Serif" font-size="8.00">0</text> </g> <!-- Mul5 --> <g id="node5" class="node"> <title>Mul5</title> -<ellipse fill="none" stroke="black" cx="161" cy="-250" rx="28.7" ry="18"/> -<text text-anchor="middle" x="161" y="-246.3" font-family="Times,serif" font-size="14.00">Mul</text> +<ellipse fill="none" stroke="black" cx="135" cy="-250" rx="27" ry="18"/> +<text text-anchor="middle" x="135" y="-246.3" font-family="Times,serif" font-size="14.00">*</text> </g> -<!-- Mul5->Con23 --> +<!-- Mul5->Con_3 --> <g id="edge4" class="edge"> -<title>Mul5->Con23</title> -<path fill="none" stroke="black" d="M146.29,-265.5C136.65,-275 123.86,-287.62 112.91,-298.42"/> -<polygon fill="black" stroke="black" points="110.34,-296.03 105.68,-305.54 115.26,-301.02 110.34,-296.03"/> +<title>Mul5->Con_3</title> +<path fill="none" stroke="black" d="M120.43,-265.17C110.25,-275.06 96.48,-288.45 84.97,-299.64"/> +<polygon fill="black" stroke="black" points="82.53,-297.13 77.8,-306.62 87.41,-302.15 82.53,-297.13"/> +<text text-anchor="middle" x="117.43" y="-267.77" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> </g> -<!-- Mul5->Con34 --> +<!-- Mul5->Con_4 --> <g id="edge5" class="edge"> -<title>Mul5->Con34</title> -<path fill="none" stroke="black" d="M164.87,-267.95C166.65,-275.74 168.81,-285.18 170.81,-293.92"/> -<polygon fill="black" stroke="black" points="167.41,-294.76 173.05,-303.72 174.24,-293.2 167.41,-294.76"/> +<title>Mul5->Con_4</title> +<path fill="none" stroke="black" d="M135,-268.3C135,-276.02 135,-285.29 135,-293.89"/> +<polygon fill="black" stroke="black" points="131.5,-293.9 135,-303.9 138.5,-293.9 131.5,-293.9"/> +<text text-anchor="middle" x="132" y="-270.9" font-family="Helvetica,sans-Serif" font-size="8.00">2</text> </g> -<!-- Con56 --> +<!-- Con_6 --> <g id="node6" class="node"> -<title>Con56</title> -<ellipse fill="none" stroke="black" cx="264" cy="-322" rx="34.39" ry="18"/> -<text text-anchor="middle" x="264" y="-318.3" font-family="Times,serif" font-size="14.00">Con5</text> +<title>Con_6</title> +<ellipse fill="none" stroke="black" cx="207" cy="-322" rx="27" ry="18"/> +<text text-anchor="middle" x="207" y="-318.3" font-family="Times,serif" font-size="14.00">#5</text> </g> -<!-- Con56->Start1 --> +<!-- Con_6->Start1 --> <g id="edge6" class="edge"> -<title>Con56->Start1</title> -<path fill="none" stroke="black" stroke-dasharray="1,5" d="M237.57,-333.63C207.98,-345.54 159.83,-364.91 126.62,-378.27"/> -<polygon fill="black" stroke="black" points="125.22,-375.06 117.25,-382.04 127.83,-381.55 125.22,-375.06"/> +<title>Con_6->Start1</title> +<path fill="none" stroke="black" stroke-dasharray="1,5" d="M192.43,-337.17C183.08,-346.25 170.7,-358.29 159.83,-368.86"/> +<polygon fill="black" stroke="black" points="157.33,-366.41 152.6,-375.89 162.21,-371.43 157.33,-366.41"/> +<text text-anchor="middle" x="189.43" y="-339.77" font-family="Helvetica,sans-Serif" font-size="8.00">0</text> </g> <!-- Minus7 --> <g id="node7" class="node"> <title>Minus7</title> -<ellipse fill="none" stroke="black" cx="252" cy="-250" rx="39.79" ry="18"/> -<text text-anchor="middle" x="252" y="-246.3" font-family="Times,serif" font-size="14.00">Minus</text> +<ellipse fill="none" stroke="black" cx="207" cy="-250" rx="27" ry="18"/> +<text text-anchor="middle" x="207" y="-246.3" font-family="Times,serif" font-size="14.00">-</text> </g> -<!-- Minus7->Con56 --> +<!-- Minus7->Con_6 --> <g id="edge7" class="edge"> -<title>Minus7->Con56</title> -<path fill="none" stroke="black" d="M254.97,-268.3C256.29,-276.02 257.88,-285.29 259.35,-293.89"/> -<polygon fill="black" stroke="black" points="255.93,-294.63 261.07,-303.9 262.83,-293.45 255.93,-294.63"/> +<title>Minus7->Con_6</title> +<path fill="none" stroke="black" d="M207,-268.3C207,-276.02 207,-285.29 207,-293.89"/> +<polygon fill="black" stroke="black" points="203.5,-293.9 207,-303.9 210.5,-293.9 203.5,-293.9"/> +<text text-anchor="middle" x="204" y="-270.9" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> </g> <!-- Add8 --> <g id="node8" class="node"> <title>Add8</title> -<ellipse fill="none" stroke="black" cx="161" cy="-178" rx="28.7" ry="18"/> -<text text-anchor="middle" x="161" y="-174.3" font-family="Times,serif" font-size="14.00">Add</text> +<ellipse fill="none" stroke="black" cx="140" cy="-178" rx="27" ry="18"/> +<text text-anchor="middle" x="140" y="-174.3" font-family="Times,serif" font-size="14.00">+</text> </g> <!-- Add8->Mul5 --> <g id="edge8" class="edge"> <title>Add8->Mul5</title> -<path fill="none" stroke="black" d="M161,-196.3C161,-204.02 161,-213.29 161,-221.89"/> -<polygon fill="black" stroke="black" points="157.5,-221.9 161,-231.9 164.5,-221.9 157.5,-221.9"/> +<path fill="none" stroke="black" d="M138.76,-196.3C138.21,-204.02 137.55,-213.29 136.94,-221.89"/> +<polygon fill="black" stroke="black" points="133.44,-221.67 136.22,-231.9 140.43,-222.17 133.44,-221.67"/> +<text text-anchor="middle" x="135.76" y="-198.9" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> </g> <!-- Add8->Minus7 --> <g id="edge9" class="edge"> <title>Add8->Minus7</title> -<path fill="none" stroke="black" d="M178.55,-192.5C191.62,-202.55 209.72,-216.48 224.68,-227.99"/> -<polygon fill="black" stroke="black" points="222.56,-230.77 232.62,-234.09 226.83,-225.22 222.56,-230.77"/> +<path fill="none" stroke="black" d="M153.88,-193.5C163.14,-203.17 175.47,-216.06 185.93,-226.98"/> +<polygon fill="black" stroke="black" points="183.69,-229.71 193.14,-234.51 188.75,-224.87 183.69,-229.71"/> +<text text-anchor="middle" x="150.88" y="-196.1" font-family="Helvetica,sans-Serif" font-size="8.00">2</text> </g> <!-- Add9 --> <g id="node9" class="node"> <title>Add9</title> -<ellipse fill="none" stroke="black" cx="70" cy="-106" rx="28.7" ry="18"/> -<text text-anchor="middle" x="70" y="-102.3" font-family="Times,serif" font-size="14.00">Add</text> +<ellipse fill="none" stroke="black" cx="140" cy="-106" rx="27" ry="18"/> +<text text-anchor="middle" x="140" y="-102.3" font-family="Times,serif" font-size="14.00">+</text> </g> -<!-- Add9->Con12 --> +<!-- Add9->Con_2 --> <g id="edge10" class="edge"> -<title>Add9->Con12</title> -<path fill="none" stroke="black" d="M70,-124.3C70,-132.02 70,-141.29 70,-149.89"/> -<polygon fill="black" stroke="black" points="66.5,-149.9 70,-159.9 73.5,-149.9 66.5,-149.9"/> +<title>Add9->Con_2</title> +<path fill="none" stroke="black" d="M156.2,-120.83C168.18,-131.06 184.69,-145.15 198.18,-156.66"/> +<polygon fill="black" stroke="black" points="196.23,-159.61 206.11,-163.44 200.78,-154.28 196.23,-159.61"/> +<text text-anchor="middle" x="153.2" y="-123.43" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> </g> <!-- Add9->Add8 --> <g id="edge11" class="edge"> <title>Add9->Add8</title> -<path fill="none" stroke="black" d="M87.55,-120.5C101.14,-130.96 120.18,-145.6 135.46,-157.35"/> -<polygon fill="black" stroke="black" points="133.45,-160.22 143.51,-163.54 137.72,-154.67 133.45,-160.22"/> +<path fill="none" stroke="black" d="M140,-124.3C140,-132.02 140,-141.29 140,-149.89"/> +<polygon fill="black" stroke="black" points="136.5,-149.9 140,-159.9 143.5,-149.9 136.5,-149.9"/> +<text text-anchor="middle" x="137" y="-126.9" font-family="Helvetica,sans-Serif" font-size="8.00">2</text> </g> <!-- Return10 --> <g id="node10" class="node"> <title>Return10</title> -<polygon fill="yellow" stroke="black" points="92,-52 26,-52 26,-16 92,-16 92,-52"/> -<text text-anchor="middle" x="59" y="-30.3" font-family="Times,serif" font-size="14.00">Return</text> +<polygon fill="yellow" stroke="black" points="125,-52 59,-52 59,-16 125,-16 125,-52"/> +<text text-anchor="middle" x="92" y="-30.3" font-family="Times,serif" font-size="14.00">Return</text> </g> <!-- Return10->Start1 --> <g id="edge12" class="edge"> <title>Return10->Start1</title> -<path fill="none" stroke="red" d="M48.61,-52.09C42.9,-62.2 36.15,-75.45 32,-88 19.42,-126.09 17,-136.89 17,-177 17,-177 17,-177 17,-251 17,-291.54 17.45,-304.48 37,-340 42.87,-350.67 51.53,-360.62 60.16,-368.95"/> -<polygon fill="red" stroke="red" points="57.93,-371.65 67.66,-375.84 62.66,-366.5 57.93,-371.65"/> +<path fill="none" stroke="red" d="M75.73,-52.27C53.67,-77.55 17,-127.09 17,-177 17,-177 17,-177 17,-251 17,-290.8 4.09,-307.45 27,-340 43.69,-363.72 74.05,-377.3 98.34,-384.76"/> +<polygon fill="red" stroke="red" points="97.41,-388.14 107.99,-387.51 99.33,-381.4 97.41,-388.14"/> +<text text-anchor="middle" x="72.73" y="-54.87" font-family="Helvetica,sans-Serif" font-size="8.00">0</text> </g> <!-- Return10->Add9 --> <g id="edge13" class="edge"> <title>Return10->Add9</title> -<path fill="none" stroke="black" d="M61.72,-52.3C62.93,-60.02 64.39,-69.29 65.74,-77.89"/> -<polygon fill="black" stroke="black" points="62.3,-78.56 67.31,-87.9 69.22,-77.47 62.3,-78.56"/> +<path fill="none" stroke="black" d="M103.87,-52.3C109.82,-60.98 117.12,-71.63 123.6,-81.08"/> +<polygon fill="black" stroke="black" points="120.71,-83.06 129.25,-89.33 126.49,-79.1 120.71,-83.06"/> +<text text-anchor="middle" x="100.87" y="-54.9" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> </g> </g> </svg> diff --git a/chapter02/src/main/java/com/seaofnodes/simple/GraphVisualizer.java b/chapter02/src/main/java/com/seaofnodes/simple/GraphVisualizer.java index 1af19d80..df128674 100644 --- a/chapter02/src/main/java/com/seaofnodes/simple/GraphVisualizer.java +++ b/chapter02/src/main/java/com/seaofnodes/simple/GraphVisualizer.java @@ -1,9 +1,6 @@ package com.seaofnodes.simple; -import com.seaofnodes.simple.node.ConstantNode; -import com.seaofnodes.simple.node.Control; -import com.seaofnodes.simple.node.Node; -import com.seaofnodes.simple.node.StartNode; +import com.seaofnodes.simple.node.*; import java.util.*; @@ -21,7 +18,10 @@ public class GraphVisualizer { Collection<Node> all = findAll(parser); StringBuilder sb = new StringBuilder(); sb.append("digraph chapter02 {\n"); - + sb.append("/*\n"); + sb.append(parser.src()); + sb.append("\n*/\n"); + // To keep the Scopes below the graph and pointing up into the graph we // need to group the Nodes in a subgraph cluster, and the scopes into a // different subgraph cluster. THEN we can draw edges between the @@ -29,12 +29,19 @@ public class GraphVisualizer { // still making the subgraphs DOT gets confused. sb.append("\trankdir=BT;\n"); // Force Nodes before Scopes + // Preserve node input order + sb.append("\tordering=\"in\";\n"); + + // Merge multiple edges hitting the same node. Makes common shared + // nodes much prettier to look at. + sb.append("\tconcentrate=\"true\";\n"); + // Just the Nodes first, in a cluster no edges nodes(sb, all); // Walk the Node edges nodeEdges(sb, all); - + sb.append("}\n"); return sb.toString(); } @@ -43,13 +50,14 @@ public class GraphVisualizer { private void nodes(StringBuilder sb, Collection<Node> all) { // Just the Nodes first, in a cluster no edges sb.append("\tsubgraph cluster_Nodes {\n"); // Magic "cluster_" in the subgraph name - for (Node n : all) { + for( Node n : all ) { sb.append("\t\t").append(n.uniqueName()).append(" [ "); + String lab = n.glabel(); // control nodes have box shape // other nodes are ellipses, i.e. default shape - if (n instanceof Control) + if( n.isCFG() ) sb.append("shape=box style=filled fillcolor=yellow "); - sb.append("label=\"").append(n.label()).append("\" "); + sb.append("label=\"").append(lab).append("\" "); sb.append("];\n"); } sb.append("\t}\n"); // End Node cluster @@ -58,25 +66,32 @@ public class GraphVisualizer { // Walk the node edges private void nodeEdges(StringBuilder sb, Collection<Node> all) { - for( Node n : all ) - for( Node out : n._inputs ) - if( out != null ) { - sb.append('\t').append(n.uniqueName()).append(" -> ").append(out.uniqueName()); - // Control edges are colored red - if( n instanceof ConstantNode && out instanceof StartNode ) - sb.append(" [style=dotted]"); - else if( n instanceof Control && out instanceof Control ) - sb.append(" [color=red]"); - sb.append(";\n"); + // All them edge labels + sb.append("\tedge [ fontname=Helvetica, fontsize=8 ];\n"); + for( Node n : all ) { + // In this chapter we do display the Constant->Start edge; + int i=0; + for( Node def : n._inputs ) { + if( def != null ) { + // Most edges land here use->def + sb.append('\t').append(n.uniqueName()).append(" -> "); + sb.append(def.uniqueName()); + // Number edges, so we can see how they track + sb.append("[taillabel=").append(i); + if( n instanceof ConstantNode && def instanceof StartNode ) + sb.append(" style=dotted"); + // control edges are colored red + else if( def.isCFG() ) + sb.append(" color=red"); + sb.append("];\n"); + } + i++; + } } } - + /** - * Walks the whole graph, starting from Start. - * Since Start is the input to all constants - we look at the outputs for - * Start, but for then subsequently we look at the inputs of each node. - * During graph construction not all nodes are reachable this way, so we - * also scan the symbol tables. + * Finds all nodes in the graph. */ private Collection<Node> findAll(Parser parser) { final StartNode start = Parser.START; @@ -91,9 +106,12 @@ public class GraphVisualizer { */ private void walk(HashMap<Integer, Node> all, Node n) { if (all.get(n._nid) != null) return; // Been there, done that - all.put(n._nid, n); - for (Node c : n._inputs) - if (c != null) - walk(all, c); + all.put(n._nid, n); + for (Node c : n._inputs) + if (c != null) + walk(all, c); + for (Node c : n._outputs) + if (c != null) + walk(all, c); } } diff --git a/chapter02/src/main/java/com/seaofnodes/simple/Parser.java b/chapter02/src/main/java/com/seaofnodes/simple/Parser.java index 3ca13c3f..5422ea66 100644 --- a/chapter02/src/main/java/com/seaofnodes/simple/Parser.java +++ b/chapter02/src/main/java/com/seaofnodes/simple/Parser.java @@ -21,29 +21,34 @@ public class Parser { */ public static StartNode START; + // The Lexer. Thin wrapper over a byte[] buffer with a cursor. private final Lexer _lexer; - public Parser( String source ) { + + public Parser(String source) { _lexer = new Lexer(source); Node.reset(); START = new StartNode(); } + String src() { return new String( _lexer._input ); } + public ReturnNode parse() { require("return"); - return parseReturn(); + return (ReturnNode) parseReturn(); } /** - * Parses returnStatement; "return" already parsed + * Parses a return statement; "return" already parsed. * * <pre> * 'return' expr ; * </pre> + * @return an expression {@link Node}, never {@code null} */ - private ReturnNode parseReturn() { - var expr = require(parseExpression(),";"); - return new ReturnNode(START, expr); + private Node parseReturn() { + var expr = require(parseExpression(), ";"); + return new ReturnNode(START, expr).peephole(); } /** @@ -52,6 +57,7 @@ public class Parser { * <pre> * expr : additiveExpr * </pre> + * @return an expression {@link Node}, never {@code null} */ private Node parseExpression() { return parseAddition(); } @@ -61,11 +67,12 @@ public class Parser { * <pre> * additiveExpr : multiplicativeExpr (('+' | '-') multiplicativeExpr)* * </pre> + * @return an add expression {@link Node}, never {@code null} */ private Node parseAddition() { var lhs = parseMultiplication(); - if( match("+") ) return new AddNode(lhs, parseAddition()).peephole(); - if( match("-") ) return new SubNode(lhs, parseAddition()).peephole(); + if (match("+")) return new AddNode(lhs, parseAddition()).peephole(); + if (match("-")) return new SubNode(lhs, parseAddition()).peephole(); return lhs; } @@ -75,11 +82,12 @@ public class Parser { * <pre> * multiplicativeExpr : unaryExpr (('*' | '/') unaryExpr)* * </pre> + * @return a multiply expression {@link Node}, never {@code null} */ private Node parseMultiplication() { var lhs = parseUnary(); - if( match("*") ) return new MulNode(lhs, parseMultiplication()).peephole(); - if( match("/") ) return new DivNode(lhs, parseMultiplication()).peephole(); + if (match("*")) return new MulNode(lhs, parseMultiplication()).peephole(); + if (match("/")) return new DivNode(lhs, parseMultiplication()).peephole(); return lhs; } @@ -89,9 +97,10 @@ public class Parser { * <pre> * unaryExpr : ('-') unaryExpr | primaryExpr * </pre> + * @return a unary expression {@link Node}, never {@code null} */ private Node parseUnary() { - if( match("-") ) return new MinusNode(parseUnary()).peephole(); + if (match("-")) return new MinusNode(parseUnary()).peephole(); return parsePrimary(); } @@ -99,12 +108,13 @@ public class Parser { * Parse a primary expression: * * <pre> - * primaryExpr : integerLiteral + * primaryExpr : integerLiteral | Identifier | '(' expression ')' * </pre> + * @return a primary {@link Node}, never {@code null} */ private Node parsePrimary() { if( _lexer.isNumber() ) return parseIntegerLiteral(); - if( match("(") ) return require(parseExpression(),")"); + if( match("(") ) return require(parseExpression(), ")"); throw errorSyntax("integer literal"); } @@ -116,7 +126,7 @@ public class Parser { * </pre> */ private ConstantNode parseIntegerLiteral() { - return (ConstantNode)new ConstantNode(_lexer.parseNumber()).peephole(); + return (ConstantNode) new ConstantNode(_lexer.parseNumber()).peephole(); } ////////////////////////////////// @@ -126,7 +136,7 @@ public class Parser { private boolean match(String syntax) { return _lexer.match(syntax); } // Require an exact match - private void require(String syntax) { require(null,syntax); } + private void require(String syntax) { require(null, syntax); } private Node require(Node n, String syntax) { if (match(syntax)) return n; throw errorSyntax(syntax); @@ -135,7 +145,7 @@ public class Parser { RuntimeException errorSyntax(String syntax) { return error("Syntax error, expected " + syntax + ": " + _lexer.getAnyNextToken()); } - + static RuntimeException error(String errorMessage) { return new RuntimeException(errorMessage); } @@ -167,9 +177,9 @@ public class Parser { // Very handy in the debugger, shows the unparsed program @Override public String toString() { - return new String(_input,_position,_input.length-_position); + return new String(_input, _position, _input.length - _position); } - + // True if at EOF private boolean isEOF() { return _position >= _input.length; @@ -203,12 +213,12 @@ public class Parser { // Return true, if we find "syntax" after skipping white space; also // then advance the cursor past syntax. // Return false otherwise, and do not advance the cursor. - boolean match( String syntax ) { + boolean match(String syntax) { skipWhiteSpace(); int len = syntax.length(); - if( _position + len > _input.length ) return false; - for( int i = 0; i < len; i++ ) - if( (char)_input[_position + i] != syntax.charAt(i) ) + if (_position + len > _input.length) return false; + for (int i = 0; i < len; i++) + if ((char) _input[_position + i] != syntax.charAt(i)) return false; _position += len; return true; @@ -216,14 +226,14 @@ public class Parser { // Used for errors String getAnyNextToken() { - if( isEOF() ) return ""; - if( isIdStart(peek()) ) return parseId(); - if( isPunctuation(peek()) ) return parsePunctuation(); + if (isEOF()) return ""; + if (isIdStart(peek())) return parseId(); + if (isPunctuation(peek())) return parsePunctuation(); return String.valueOf(peek()); } - boolean isNumber() { return isNumber(peek()); } - boolean isNumber(char ch) { return Character.isDigit(ch); } + boolean isNumber() {return isNumber(peek());} + boolean isNumber(char ch) {return Character.isDigit(ch);} private Type parseNumber() { int start = _position; @@ -231,7 +241,7 @@ public class Parser { String snum = new String(_input, start, --_position - start); if (snum.length() > 1 && snum.charAt(0) == '0') throw error("Syntax error: integer values cannot start with '0'"); - return new TypeInteger(Long.parseLong(snum)); + return TypeInteger.constant(Long.parseLong(snum)); } // First letter of an identifier @@ -257,8 +267,7 @@ public class Parser { private String parsePunctuation() { int start = _position; - if (isPunctuation(nextChar())) ; - return new String(_input, start, --_position - start); + return new String(_input, start, 1); } } diff --git a/chapter02/src/main/java/com/seaofnodes/simple/node/AddNode.java b/chapter02/src/main/java/com/seaofnodes/simple/node/AddNode.java index 015779dc..6784ad60 100644 --- a/chapter02/src/main/java/com/seaofnodes/simple/node/AddNode.java +++ b/chapter02/src/main/java/com/seaofnodes/simple/node/AddNode.java @@ -3,17 +3,16 @@ package com.seaofnodes.simple.node; import com.seaofnodes.simple.type.*; public class AddNode extends Node { - public AddNode(Node lhs, Node rhs) { - super(null, lhs, rhs); - } + public AddNode(Node lhs, Node rhs) { super(null, lhs, rhs); } - @Override - public String label() { return "Add"; } + @Override public String label() { return "Add"; } + + @Override public String glabel() { return "+"; } @Override - StringBuilder _print(StringBuilder sb) { - in(1)._print(sb.append("(")); - in(2)._print(sb.append("+")); + StringBuilder _print1(StringBuilder sb) { + in(1)._print0(sb.append("(")); + in(2)._print0(sb.append("+")); return sb.append(")"); } @@ -21,8 +20,9 @@ public class AddNode extends Node { @Override public Type compute() { if( in(1)._type instanceof TypeInteger i0 && - in(2)._type instanceof TypeInteger i1 ) - return new TypeInteger(i0._con + i1._con); + in(2)._type instanceof TypeInteger i1 ) { + return TypeInteger.constant(i0.value()+i1.value()); + } return TypeBot.BOTTOM; } diff --git a/chapter02/src/main/java/com/seaofnodes/simple/node/ConstantNode.java b/chapter02/src/main/java/com/seaofnodes/simple/node/ConstantNode.java index 99ccf4b5..ec85bf1f 100644 --- a/chapter02/src/main/java/com/seaofnodes/simple/node/ConstantNode.java +++ b/chapter02/src/main/java/com/seaofnodes/simple/node/ConstantNode.java @@ -16,22 +16,25 @@ import com.seaofnodes.simple.type.Type; * The Constant's value is the value stored in it. */ public class ConstantNode extends Node { - + Type _con; public ConstantNode( Type type ) { super(Parser.START); - _type = type; + _con = type; } @Override - public String label() { return "Con" + _type; } + public String label() { return "#"+_con; } + + @Override + public String uniqueName() { return "Con_" + _nid; } @Override - StringBuilder _print(StringBuilder sb) { - return _type._print(sb); + StringBuilder _print1(StringBuilder sb) { + return _con._print(sb); } @Override - public Type compute() { return _type; } + public Type compute() { return _con; } @Override public Node idealize() { return null; } diff --git a/chapter02/src/main/java/com/seaofnodes/simple/node/Control.java b/chapter02/src/main/java/com/seaofnodes/simple/node/Control.java deleted file mode 100644 index 48cf2b7a..00000000 --- a/chapter02/src/main/java/com/seaofnodes/simple/node/Control.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.seaofnodes.simple.node; - - -/** - * Control interface is a marker interface to be implemented - * by Control nodes. - */ -public interface Control { -} diff --git a/chapter02/src/main/java/com/seaofnodes/simple/node/DivNode.java b/chapter02/src/main/java/com/seaofnodes/simple/node/DivNode.java index 0056c42d..ca7df79c 100644 --- a/chapter02/src/main/java/com/seaofnodes/simple/node/DivNode.java +++ b/chapter02/src/main/java/com/seaofnodes/simple/node/DivNode.java @@ -5,17 +5,16 @@ import com.seaofnodes.simple.type.TypeBot; import com.seaofnodes.simple.type.TypeInteger; public class DivNode extends Node { - public DivNode(Node lhs, Node rhs) { - super(null, lhs, rhs); - } + public DivNode(Node lhs, Node rhs) { super(null, lhs, rhs); } + + @Override public String label() { return "Div"; } + + @Override public String glabel() { return "//"; } @Override - public String label() { return "Div"; } - - @Override - StringBuilder _print(StringBuilder sb) { - in(1)._print(sb.append("(")); - in(2)._print(sb.append("/")); + StringBuilder _print1(StringBuilder sb) { + in(1)._print0(sb.append("(")); + in(2)._print0(sb.append("/")); return sb.append(")"); } @@ -23,11 +22,9 @@ public class DivNode extends Node { public Type compute() { if (in(1)._type instanceof TypeInteger i0 && in(2)._type instanceof TypeInteger i1) { - if (i0.isConstant() && i1.isConstant()) - return i1._con == 0 - ? TypeInteger.ZERO - : new TypeInteger(i0._con/i1._con); - return new TypeInteger(i0._con / i1._con); + return i1.value() == 0 + ? TypeInteger.ZERO + : TypeInteger.constant(i0.value()/i1.value()); } return TypeBot.BOTTOM; } diff --git a/chapter02/src/main/java/com/seaofnodes/simple/node/MinusNode.java b/chapter02/src/main/java/com/seaofnodes/simple/node/MinusNode.java index 7fab83b0..834f4c11 100644 --- a/chapter02/src/main/java/com/seaofnodes/simple/node/MinusNode.java +++ b/chapter02/src/main/java/com/seaofnodes/simple/node/MinusNode.java @@ -5,23 +5,22 @@ import com.seaofnodes.simple.type.TypeBot; import com.seaofnodes.simple.type.TypeInteger; public class MinusNode extends Node { - public MinusNode(Node in) { - super(null, in); - } + public MinusNode(Node in) { super(null, in); } - @Override - public String label() { return "Minus"; } + @Override public String label() { return "Minus"; } + + @Override public String glabel() { return "-"; } @Override - StringBuilder _print(StringBuilder sb) { - in(1)._print(sb.append("(-")); + StringBuilder _print1(StringBuilder sb) { + in(1)._print0(sb.append("(-")); return sb.append(")"); } @Override public Type compute() { if (in(1)._type instanceof TypeInteger i0) - return new TypeInteger(-i0._con); + return TypeInteger.constant(-i0.value()); return TypeBot.BOTTOM; } diff --git a/chapter02/src/main/java/com/seaofnodes/simple/node/MulNode.java b/chapter02/src/main/java/com/seaofnodes/simple/node/MulNode.java index e1a26858..0fa54966 100644 --- a/chapter02/src/main/java/com/seaofnodes/simple/node/MulNode.java +++ b/chapter02/src/main/java/com/seaofnodes/simple/node/MulNode.java @@ -5,25 +5,25 @@ import com.seaofnodes.simple.type.TypeBot; import com.seaofnodes.simple.type.TypeInteger; public class MulNode extends Node { - public MulNode(Node lhs, Node rhs) { - super(null, lhs, rhs); - } - - @Override - public String label() { return "Mul"; } + public MulNode(Node lhs, Node rhs) { super(null, lhs, rhs); } + + @Override public String label() { return "Mul"; } + @Override public String glabel() { return "*"; } + @Override - StringBuilder _print(StringBuilder sb) { - in(1)._print(sb.append("(")); - in(2)._print(sb.append("*")); + StringBuilder _print1(StringBuilder sb) { + in(1)._print0(sb.append("(")); + in(2)._print0(sb.append("*")); return sb.append(")"); } - + @Override public Type compute() { if (in(1)._type instanceof TypeInteger i0 && - in(2)._type instanceof TypeInteger i1) - return new TypeInteger(i0._con * i1._con); + in(2)._type instanceof TypeInteger i1) { + return TypeInteger.constant(i0.value()*i1.value()); + } return TypeBot.BOTTOM; } diff --git a/chapter02/src/main/java/com/seaofnodes/simple/node/Node.java b/chapter02/src/main/java/com/seaofnodes/simple/node/Node.java index 7c39083e..dbef984e 100644 --- a/chapter02/src/main/java/com/seaofnodes/simple/node/Node.java +++ b/chapter02/src/main/java/com/seaofnodes/simple/node/Node.java @@ -2,8 +2,7 @@ package com.seaofnodes.simple.node; import com.seaofnodes.simple.type.Type; -import java.util.ArrayList; -import java.util.Collections; +import java.util.*; /** * All Nodes in the Sea of Nodes IR inherit from the Node class. @@ -24,8 +23,7 @@ public abstract class Node { * <p> * Generally fixed length, ordered, nulls allowed, no unused trailing space. * Ordering is required because e.g. "a/b" is different from "b/a". - * The first input (offset 0) is often a Control node. - * @see Control + * The first input (offset 0) is often a {@link #isCFG} node. */ public final ArrayList<Node> _inputs; @@ -40,6 +38,13 @@ public abstract class Node { */ public final ArrayList<Node> _outputs; + + /** + * Current computed type for this Node. This value changes as the graph + * changes and more knowledge is gained about the program. + */ + public Type _type; + /** * A private Global Static mutable counter, for unique node id generation. * To make the compiler multi-threaded, this field will have to move into a TLS. @@ -47,7 +52,7 @@ public abstract class Node { * */ private static int UNIQUE_ID = 1; - protected Node(Node ...inputs) { + protected Node(Node... inputs) { _nid = UNIQUE_ID++; // allocate unique dense ID _inputs = new ArrayList<>(); Collections.addAll(_inputs,inputs); @@ -55,26 +60,39 @@ public abstract class Node { for( Node n : _inputs ) if( n != null ) n._outputs.add( this ); - // Do an initial type computation - _type = compute(); } + // Easy reading label for debugger, e.g. "Add" or "Region" or "EQ" public abstract String label(); + // Unique label for graph visualization, e.g. "Add12" or "Region30" or "EQ99" public String uniqueName() { return label() + _nid; } + // Graphical label, e.g. "+" or "Region" or "==" + public String glabel() { return label(); } + @Override public final String toString() { // TODO: This needs a lot of work - return uniqueName(); + return print(); } // This is a *deep* print. This version will fail on cycles, which we will - // correct later when we can parse programs with loops. + // correct later when we can parse programs with loops. We print with a + // tik-tok style; the common _print0 calls the per-Node _print1, which + // calls back to _print0; public final String print() { - return _print(new StringBuilder()).toString(); + return _print0(new StringBuilder()).toString(); + } + // This is the common print: check for DEAD and print "DEAD" else call the + // per-Node print1. + final StringBuilder _print0(StringBuilder sb) { + return isDead() + ? sb.append(uniqueName()).append(":DEAD") + : _print1(sb); } - abstract StringBuilder _print(StringBuilder sb); + // Every Node implements this. + abstract StringBuilder _print1(StringBuilder sb); /** @@ -86,25 +104,21 @@ public abstract class Node { public int nIns() { return _inputs.size(); } - /** - * Gets the ith output node - * @param i Offset of the output node - * @return Output node (not null) - */ - public Node out(int i) { return _outputs.get(i); } - public int nOuts() { return _outputs.size(); } + public boolean isUnused() { return nOuts() == 0; } + + public boolean isCFG() { return false; } + /** * We allow disabling peephole opt so that we can observe the * full graph, vs the optimized graph. */ public static boolean _disablePeephole = false; - /** * Try to peephole at this node and return a better replacement Node if - * possible. We check and replace: + * possible. We compute a {@link Type} and then check and replace: * <ul> * <li>if the Type {@link Type#isConstant}, we replace with a {@link ConstantNode}</li> * <li>in a future chapter we will look for a @@ -114,19 +128,21 @@ public abstract class Node { * </ul> */ public final Node peephole( ) { + // Compute initial or improved Type + Type type = _type = compute(); + if (_disablePeephole) return this; // Peephole optimizations turned off // Replace constant computations from non-constants with a constant node - Type type = compute(); if (!(this instanceof ConstantNode) && type.isConstant()) { kill(); // Kill `this` because replacing with a Constant - return new ConstantNode(type); + return new ConstantNode(type).peephole(); } // Future chapter: Global Value Numbering goes here - // Ask each node for a replacement + // Ask each node for a better replacement Node n = idealize(); if( n != null ) return n; @@ -134,27 +150,17 @@ public abstract class Node { } /** - * Kill a Node with no <em>uses</em>, by setting all of its <em>defs</em> - * to null. This may recursively kill more Nodes and is basically dead - * code elimination. This function is co-recursive with {@link #set_def}. - */ - void kill( ) { - assert nOuts()==0; // Has no uses, so it is dead - for( int i=0; i<nIns(); i++ ) - set_def(i,null); // Set all inputs to null, recursively killing unused Nodes - } - - /** * Change a <em>def</em> into a Node. Keeps the edges correct, by removing * the corresponding <em>use->def</em> edge. This may make the original * <em>def</em> go dead. This function is co-recursive with {@link #kill}. * * @param idx which def to set * @param new_def the new definition + * @return this for flow coding */ - void set_def(int idx, Node new_def ) { + Node set_def(int idx, Node new_def ) { Node old_def = in(idx); - if( old_def == new_def ) return; // No change + if( old_def == new_def ) return this; // No change // If new def is not null, add the corresponding def->use edge // This needs to happen before removing the old node's def->use edge as // the new_def might get killed if the old node kills it recursively. @@ -174,15 +180,26 @@ public abstract class Node { } // Set the new_def over the old (killed) edge _inputs.set(idx,new_def); + // Return self for easy flow-coding + return this; } - - /** - * Current computed type for this Node. This value changes as the graph - * changes and more knowledge is gained about the program. + * Kill a Node with no <em>uses</em>, by setting all of its <em>defs</em> + * to null. This may recursively kill more Nodes and is basically dead + * code elimination. This function is co-recursive with {@link #set_def}. */ - public Type _type; - + public void kill( ) { + assert isUnused(); // Has no uses, so it is dead + for( int i=0; i<nIns(); i++ ) + set_def(i,null); // Set all inputs to null, recursively killing unused Nodes + _inputs.clear(); + _type=null; // Flag as dead + assert isDead(); // Really dead now + } + + // Mostly used for asserts and printing. + boolean isDead() { return isUnused() && nIns()==0 && _type==null; } + /** * This function needs to be * <a href="https://en.wikipedia.org/wiki/Monotonic_function">Monotonic</a> @@ -208,9 +225,4 @@ public abstract class Node { * Node unique id generator, and is done as part of making a new Parser. */ public static void reset() { UNIQUE_ID = 1; } - - /* - * hashCode and equals implementation to be added in later chapter. - */ - } diff --git a/chapter02/src/main/java/com/seaofnodes/simple/node/ReturnNode.java b/chapter02/src/main/java/com/seaofnodes/simple/node/ReturnNode.java index c188ca79..18f5eed9 100644 --- a/chapter02/src/main/java/com/seaofnodes/simple/node/ReturnNode.java +++ b/chapter02/src/main/java/com/seaofnodes/simple/node/ReturnNode.java @@ -1,6 +1,6 @@ package com.seaofnodes.simple.node; -import com.seaofnodes.simple.type.TypeBot; +import com.seaofnodes.simple.type.*; /** * The Return node has two inputs. The first input is a control node and the @@ -11,7 +11,7 @@ import com.seaofnodes.simple.type.TypeBot; * <p> * The Return's output is the value from the data node. */ -public class ReturnNode extends Node implements Control { +public class ReturnNode extends Node { public ReturnNode(Node ctrl, Node data) { super(ctrl, data); @@ -24,10 +24,11 @@ public class ReturnNode extends Node implements Control { public String label() { return "Return"; } @Override - StringBuilder _print(StringBuilder sb) { - return expr()._print(sb.append("return ")).append(";"); + StringBuilder _print1(StringBuilder sb) { + return expr()._print0(sb.append("return ")).append(";"); } + @Override public boolean isCFG() { return true; } @Override public TypeBot compute() { diff --git a/chapter02/src/main/java/com/seaofnodes/simple/node/StartNode.java b/chapter02/src/main/java/com/seaofnodes/simple/node/StartNode.java index 8d8031bb..08b8333a 100644 --- a/chapter02/src/main/java/com/seaofnodes/simple/node/StartNode.java +++ b/chapter02/src/main/java/com/seaofnodes/simple/node/StartNode.java @@ -3,11 +3,13 @@ package com.seaofnodes.simple.node; import com.seaofnodes.simple.type.TypeBot; /** - * The Start node represents the start of the function. For now, we do not have any inputs to Start because our function does not - * yet accept parameters. When we add parameters the value of Start will be a tuple, and will require Projections to extract the values. - * We discuss this in detail in Chapter 9: Functions and Calls. + * The Start node represents the start of the function. For now, we do not + * have any inputs to Start because our function does not yet accept + * parameters. When we add parameters the value of Start will be a tuple, and + * will require Projections to extract the values. We discuss this in detail + * in Chapter 9: Functions and Calls. */ -public class StartNode extends Node implements Control { +public class StartNode extends Node { public StartNode(/*arguments go here*/) { super(); @@ -17,10 +19,12 @@ public class StartNode extends Node implements Control { public String label() { return "Start"; } @Override - StringBuilder _print(StringBuilder sb) { + StringBuilder _print1(StringBuilder sb) { return sb.append(label()); } - + + @Override public boolean isCFG() { return true; } + @Override public TypeBot compute() { return TypeBot.BOTTOM; diff --git a/chapter02/src/main/java/com/seaofnodes/simple/node/SubNode.java b/chapter02/src/main/java/com/seaofnodes/simple/node/SubNode.java index 2d7db8d3..71d70fa6 100644 --- a/chapter02/src/main/java/com/seaofnodes/simple/node/SubNode.java +++ b/chapter02/src/main/java/com/seaofnodes/simple/node/SubNode.java @@ -5,25 +5,25 @@ import com.seaofnodes.simple.type.TypeBot; import com.seaofnodes.simple.type.TypeInteger; public class SubNode extends Node { - public SubNode(Node lhs, Node rhs) { - super(null, lhs, rhs); - } + public SubNode(Node lhs, Node rhs) { super(null, lhs, rhs); } - @Override - public String label() { return "Sub"; } + @Override public String label() { return "Sub"; } + + @Override public String glabel() { return "-"; } @Override - StringBuilder _print(StringBuilder sb) { - in(1)._print(sb.append("(")); - in(2)._print(sb.append("-")); + StringBuilder _print1(StringBuilder sb) { + in(1)._print0(sb.append("(")); + in(2)._print0(sb.append("-")); return sb.append(")"); } @Override public Type compute() { if (in(1)._type instanceof TypeInteger i0 && - in(2)._type instanceof TypeInteger i1) - return new TypeInteger(i0._con - i1._con); + in(2)._type instanceof TypeInteger i1) { + return TypeInteger.constant(i0.value()-i1.value()); + } return TypeBot.BOTTOM; } diff --git a/chapter02/src/main/java/com/seaofnodes/simple/type/TypeBot.java b/chapter02/src/main/java/com/seaofnodes/simple/type/TypeBot.java index 5284884a..bc191241 100644 --- a/chapter02/src/main/java/com/seaofnodes/simple/type/TypeBot.java +++ b/chapter02/src/main/java/com/seaofnodes/simple/type/TypeBot.java @@ -8,7 +8,7 @@ public class TypeBot extends Type { @Override public String toString() { return "Bottom"; } - - @Override + + @Override public StringBuilder _print(StringBuilder sb) { return sb.append(toString()); } } diff --git a/chapter02/src/main/java/com/seaofnodes/simple/type/TypeInteger.java b/chapter02/src/main/java/com/seaofnodes/simple/type/TypeInteger.java index 06cac15e..ff6e865b 100644 --- a/chapter02/src/main/java/com/seaofnodes/simple/type/TypeInteger.java +++ b/chapter02/src/main/java/com/seaofnodes/simple/type/TypeInteger.java @@ -14,6 +14,8 @@ public class TypeInteger extends Type { public TypeInteger(long con) { _con = con; } + public static TypeInteger constant(long con) { return new TypeInteger(con); } + @Override public String toString() { return _print(new StringBuilder()).toString(); @@ -25,7 +27,7 @@ public class TypeInteger extends Type { @Override public boolean isConstant() { return true; } - public long getConstant() { return _con; } + public long value() { return _con; } @Override public boolean equals( Object o ) { diff --git a/chapter02/src/test/java/com/seaofnodes/simple/Chapter02Test.java b/chapter02/src/test/java/com/seaofnodes/simple/Chapter02Test.java index 83cd7a0f..971b60ba 100644 --- a/chapter02/src/test/java/com/seaofnodes/simple/Chapter02Test.java +++ b/chapter02/src/test/java/com/seaofnodes/simple/Chapter02Test.java @@ -1,16 +1,12 @@ package com.seaofnodes.simple; -import com.seaofnodes.simple.node.ConstantNode; -import com.seaofnodes.simple.node.Node; -import com.seaofnodes.simple.node.ReturnNode; -import com.seaofnodes.simple.node.StartNode; +import com.seaofnodes.simple.node.*; import com.seaofnodes.simple.type.TypeInteger; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; +import static org.junit.Assert.*; public class Chapter02Test { @@ -76,15 +72,13 @@ public class Chapter02Test { public void testSimpleProgram() { Parser parser = new Parser("return 1;"); ReturnNode ret = parser.parse(); - GraphVisualizer gv = new GraphVisualizer(); - System.out.println(gv.generateDotOutput(parser)); StartNode start = Parser.START; assertEquals(start, ret.ctrl()); Node expr = ret.expr(); if( expr instanceof ConstantNode con ) { assertEquals(start,con.in(0)); - assertEquals(new TypeInteger(1), con._type); + assertEquals(TypeInteger.constant(1), con._type); } else { fail(); } @@ -97,21 +91,27 @@ public class Chapter02Test { StartNode start = Parser.START; for( Node use : start._outputs ) if( use instanceof ConstantNode con ) - assertEquals(new TypeInteger(0),con._type); + assertEquals(TypeInteger.constant(0),con._type); } @Test public void testBad1() { - exceptionRule.expect(RuntimeException.class); - exceptionRule.expectMessage("Syntax error, expected return: ret"); - new Parser("ret").parse(); + try { + new Parser("ret").parse(); + fail(); + } catch( RuntimeException e ) { + assertEquals("Syntax error, expected return: ret",e.getMessage()); + } } @Test public void testBad2() { - exceptionRule.expect(RuntimeException.class); - exceptionRule.expectMessage("Syntax error: integer values cannot start with '0'"); - new Parser("return 0123;").parse(); + try { + new Parser("return 0123;").parse(); + fail(); + } catch( RuntimeException e ) { + assertEquals("Syntax error: integer values cannot start with '0'",e.getMessage()); + } } @Test @@ -122,9 +122,12 @@ public class Chapter02Test { @Test public void testBad4() { - exceptionRule.expect(RuntimeException.class); - exceptionRule.expectMessage("Syntax error, expected ;:"); - new Parser("return 100").parse(); + try { + new Parser("return 100").parse(); + fail(); + } catch( RuntimeException e ) { + assertEquals("Syntax error, expected ;: ",e.getMessage()); + } } @Test diff --git a/chapter03/docs/03-graph1.gv b/chapter03/docs/03-graph1.gv index 5983f622..2bdca351 100644 --- a/chapter03/docs/03-graph1.gv +++ b/chapter03/docs/03-graph1.gv @@ -1,33 +1,39 @@ digraph chapter03 { +/* +int a=1; int b=2; int c=0; { int b=3; c=a+b; #showGraph; } return c; #showGraph; +*/ rankdir=BT; + ordering="in"; + concentrate="true"; subgraph cluster_Nodes { - Start1 [ shape=box style=filled fillcolor=yellow label="Start" ]; - Con_2 [ label="#1" ]; - Con_3 [ label="#2" ]; - Con_5 [ label="#3" ]; - Add6 [ label="Add" ]; + Start2 [ shape=box style=filled fillcolor=yellow label="Start" ]; + Con_3 [ label="#1" ]; + Con_4 [ label="#2" ]; + Con_6 [ label="#3" ]; + Add7 [ label="+" ]; } node [shape=plaintext]; - subgraph cluster_0 { - scope0 [label=< + subgraph cluster_Scope1_0 { + Scope1_0 [label=< <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0"> - <TR><TD BGCOLOR="aqua">0</TD><TD PORT="scope0_a">a</TD><TD PORT="scope0_b">b</TD><TD PORT="scope0_c">c</TD></TR> + <TR><TD BGCOLOR="cyan">0</TD><TD PORT="Scope1_0_a">a</TD><TD PORT="Scope1_0_b">b</TD><TD PORT="Scope1_0_c">c</TD></TR> </TABLE>>]; - subgraph cluster_1 { - scope1 [label=< + subgraph cluster_Scope1_1 { + Scope1_1 [label=< <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0"> - <TR><TD BGCOLOR="aqua">1</TD><TD PORT="scope1_b">b</TD></TR> + <TR><TD BGCOLOR="cyan">1</TD><TD PORT="Scope1_1_b">b</TD></TR> </TABLE>>]; } } - Con_2 -> Start1 [style=dotted]; - Con_3 -> Start1 [style=dotted]; - Con_5 -> Start1 [style=dotted]; - Add6 -> Con_2; - Add6 -> Con_5; + edge [ fontname=Helvetica, fontsize=8 ]; + Con_3 -> Start2[taillabel=0 style=dotted]; + Con_4 -> Start2[taillabel=0 style=dotted]; + Con_6 -> Start2[taillabel=0 style=dotted]; + Add7 -> Con_3[taillabel=1]; + Add7 -> Con_6[taillabel=2]; edge [style=dashed color=cornflowerblue]; - scope0:scope0_a -> Con_2; - scope0:scope0_b -> Con_3; - scope0:scope0_c -> Add6; - scope1:scope1_b -> Con_5; + Scope1_0:"Scope1_0_a" -> Con_3; + Scope1_0:"Scope1_0_b" -> Con_4; + Scope1_0:"Scope1_0_c" -> Add7; + Scope1_1:"Scope1_1_b" -> Con_6; } diff --git a/chapter03/docs/03-graph1.svg b/chapter03/docs/03-graph1.svg index 364cd42c..ab6f9600 100644 --- a/chapter03/docs/03-graph1.svg +++ b/chapter03/docs/03-graph1.svg @@ -14,77 +14,82 @@ <polygon fill="none" stroke="black" points="8,-88 8,-284 222,-284 222,-88 8,-88"/> </g> <g id="clust2" class="cluster"> -<title>cluster_0</title> +<title>cluster_Scope1_0</title> <polygon fill="none" stroke="black" points="36,-8 36,-76 210,-76 210,-8 36,-8"/> </g> <g id="clust3" class="cluster"> -<title>cluster_1</title> +<title>cluster_Scope1_1</title> <polygon fill="none" stroke="black" points="132,-16 132,-68 202,-68 202,-16 132,-16"/> </g> -<!-- Start1 --> +<!-- Start2 --> <g id="node1" class="node"> -<title>Start1</title> +<title>Start2</title> <polygon fill="yellow" stroke="black" points="142,-276 88,-276 88,-240 142,-240 142,-276"/> <text text-anchor="middle" x="115" y="-254.3" font-family="Times,serif" font-size="14.00">Start</text> </g> -<!-- Con_2 --> +<!-- Con_3 --> <g id="node2" class="node"> -<title>Con_2</title> +<title>Con_3</title> <ellipse fill="none" stroke="black" cx="43" cy="-186" rx="27" ry="18"/> <text text-anchor="middle" x="43" y="-182.3" font-family="Times,serif" font-size="14.00">#1</text> </g> -<!-- Con_2->Start1 --> +<!-- Con_3->Start2 --> <g id="edge1" class="edge"> -<title>Con_2->Start1</title> +<title>Con_3->Start2</title> <path fill="none" stroke="black" stroke-dasharray="1,5" d="M57.57,-201.17C66.92,-210.25 79.3,-222.29 90.17,-232.86"/> <polygon fill="black" stroke="black" points="87.79,-235.43 97.4,-239.89 92.67,-230.41 87.79,-235.43"/> +<text text-anchor="middle" x="54.57" y="-203.77" font-family="Helvetica,sans-Serif" font-size="8.00">0</text> </g> -<!-- Con_3 --> +<!-- Con_4 --> <g id="node3" class="node"> -<title>Con_3</title> +<title>Con_4</title> <ellipse fill="none" stroke="black" cx="115" cy="-186" rx="27" ry="18"/> <text text-anchor="middle" x="115" y="-182.3" font-family="Times,serif" font-size="14.00">#2</text> </g> -<!-- Con_3->Start1 --> +<!-- Con_4->Start2 --> <g id="edge2" class="edge"> -<title>Con_3->Start1</title> +<title>Con_4->Start2</title> <path fill="none" stroke="black" stroke-dasharray="1,5" d="M115,-204.3C115,-212.02 115,-221.29 115,-229.89"/> <polygon fill="black" stroke="black" points="111.5,-229.9 115,-239.9 118.5,-229.9 111.5,-229.9"/> +<text text-anchor="middle" x="112" y="-206.9" font-family="Helvetica,sans-Serif" font-size="8.00">0</text> </g> -<!-- Con_5 --> +<!-- Con_6 --> <g id="node4" class="node"> -<title>Con_5</title> +<title>Con_6</title> <ellipse fill="none" stroke="black" cx="187" cy="-186" rx="27" ry="18"/> <text text-anchor="middle" x="187" y="-182.3" font-family="Times,serif" font-size="14.00">#3</text> </g> -<!-- Con_5->Start1 --> +<!-- Con_6->Start2 --> <g id="edge3" class="edge"> -<title>Con_5->Start1</title> +<title>Con_6->Start2</title> <path fill="none" stroke="black" stroke-dasharray="1,5" d="M172.43,-201.17C163.08,-210.25 150.7,-222.29 139.83,-232.86"/> <polygon fill="black" stroke="black" points="137.33,-230.41 132.6,-239.89 142.21,-235.43 137.33,-230.41"/> +<text text-anchor="middle" x="169.43" y="-203.77" font-family="Helvetica,sans-Serif" font-size="8.00">0</text> </g> -<!-- Add6 --> +<!-- Add7 --> <g id="node5" class="node"> -<title>Add6</title> -<ellipse fill="none" stroke="black" cx="138" cy="-114" rx="28.7" ry="18"/> -<text text-anchor="middle" x="138" y="-110.3" font-family="Times,serif" font-size="14.00">Add</text> +<title>Add7</title> +<ellipse fill="none" stroke="black" cx="136" cy="-114" rx="27" ry="18"/> +<text text-anchor="middle" x="136" y="-110.3" font-family="Times,serif" font-size="14.00">+</text> </g> -<!-- Add6->Con_2 --> +<!-- Add7->Con_3 --> <g id="edge4" class="edge"> -<title>Add6->Con_2</title> -<path fill="none" stroke="black" d="M120.13,-128.17C105.58,-138.89 84.84,-154.17 68.53,-166.18"/> -<polygon fill="black" stroke="black" points="66.44,-163.38 60.47,-172.13 70.59,-169.01 66.44,-163.38"/> +<title>Add7->Con_3</title> +<path fill="none" stroke="black" d="M118.51,-128.17C104.48,-138.73 84.58,-153.7 68.74,-165.63"/> +<polygon fill="black" stroke="black" points="66.3,-163.08 60.41,-171.89 70.51,-168.68 66.3,-163.08"/> +<text text-anchor="middle" x="115.51" y="-130.77" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> </g> -<!-- Add6->Con_5 --> +<!-- Add7->Con_6 --> <g id="edge5" class="edge"> -<title>Add6->Con_5</title> -<path fill="none" stroke="black" d="M149.12,-130.88C155.32,-139.74 163.17,-150.96 170.12,-160.88"/> -<polygon fill="black" stroke="black" points="167.32,-162.99 175.93,-169.18 173.06,-158.98 167.32,-162.99"/> +<title>Add7->Con_6</title> +<path fill="none" stroke="black" d="M147.32,-130.54C153.92,-139.6 162.38,-151.21 169.8,-161.39"/> +<polygon fill="black" stroke="black" points="167,-163.49 175.71,-169.51 172.65,-159.36 167,-163.49"/> +<text text-anchor="middle" x="144.32" y="-133.14" font-family="Helvetica,sans-Serif" font-size="8.00">2</text> </g> -<!-- scope0 --> +<!-- Scope1_0 --> <g id="node6" class="node"> -<title>scope0</title> -<polygon fill="aqua" stroke="transparent" points="53,-31 53,-52 69,-52 69,-31 53,-31"/> +<title>Scope1_0</title> +<polygon fill="cyan" stroke="transparent" points="53,-31 53,-52 69,-52 69,-31 53,-31"/> <polygon fill="none" stroke="black" points="53,-31 53,-52 69,-52 69,-31 53,-31"/> <text text-anchor="start" x="56" y="-37.8" font-family="Times,serif" font-size="14.00">0</text> <polygon fill="none" stroke="black" points="69,-31 69,-52 84,-52 84,-31 69,-31"/> @@ -94,36 +99,36 @@ <polygon fill="none" stroke="black" points="100,-31 100,-52 114,-52 114,-31 100,-31"/> <text text-anchor="start" x="103" y="-37.8" font-family="Times,serif" font-size="14.00">c</text> </g> -<!-- scope0->Con_2 --> +<!-- Scope1_0->Con_3 --> <g id="edge6" class="edge"> -<title>scope0:scope0_a->Con_2</title> +<title>Scope1_0:Scope1_0_a->Con_3</title> <path fill="none" stroke="cornflowerblue" stroke-dasharray="5,2" d="M76,-53C76,-90.54 63.29,-132.33 53.64,-158.64"/> <polygon fill="cornflowerblue" stroke="cornflowerblue" points="50.27,-157.66 50,-168.25 56.81,-160.14 50.27,-157.66"/> </g> -<!-- scope0->Con_3 --> +<!-- Scope1_0->Con_4 --> <g id="edge7" class="edge"> -<title>scope0:scope0_b->Con_3</title> +<title>Scope1_0:Scope1_0_b->Con_4</title> <path fill="none" stroke="cornflowerblue" stroke-dasharray="5,2" d="M92,-53C92,-88.29 93.39,-97.33 100,-132 101.65,-140.68 104.07,-150 106.48,-158.37"/> <polygon fill="cornflowerblue" stroke="cornflowerblue" points="103.14,-159.42 109.37,-168 109.85,-157.41 103.14,-159.42"/> </g> -<!-- scope0->Add6 --> +<!-- Scope1_0->Add7 --> <g id="edge8" class="edge"> -<title>scope0:scope0_c->Add6</title> -<path fill="none" stroke="cornflowerblue" stroke-dasharray="5,2" d="M107,-53C107,-65.88 112.71,-78.75 119.22,-89.25"/> -<polygon fill="cornflowerblue" stroke="cornflowerblue" points="116.52,-91.5 125.03,-97.81 122.31,-87.57 116.52,-91.5"/> +<title>Scope1_0:Scope1_0_c->Add7</title> +<path fill="none" stroke="cornflowerblue" stroke-dasharray="5,2" d="M107,-53C107,-65.71 112.34,-78.55 118.43,-89.08"/> +<polygon fill="cornflowerblue" stroke="cornflowerblue" points="115.57,-91.1 123.87,-97.68 121.48,-87.35 115.57,-91.1"/> </g> -<!-- scope1 --> +<!-- Scope1_1 --> <g id="node7" class="node"> -<title>scope1</title> -<polygon fill="aqua" stroke="transparent" points="151,-31 151,-52 167,-52 167,-31 151,-31"/> +<title>Scope1_1</title> +<polygon fill="cyan" stroke="transparent" points="151,-31 151,-52 167,-52 167,-31 151,-31"/> <polygon fill="none" stroke="black" points="151,-31 151,-52 167,-52 167,-31 151,-31"/> <text text-anchor="start" x="154" y="-37.8" font-family="Times,serif" font-size="14.00">1</text> <polygon fill="none" stroke="black" points="167,-31 167,-52 183,-52 183,-31 167,-31"/> <text text-anchor="start" x="170" y="-37.8" font-family="Times,serif" font-size="14.00">b</text> </g> -<!-- scope1->Con_5 --> +<!-- Scope1_1->Con_6 --> <g id="edge9" class="edge"> -<title>scope1:scope1_b->Con_5</title> +<title>Scope1_1:Scope1_1_b->Con_6</title> <path fill="none" stroke="cornflowerblue" stroke-dasharray="5,2" d="M175,-53C175,-89.4 179.58,-131.23 183.08,-157.87"/> <polygon fill="cornflowerblue" stroke="cornflowerblue" points="179.64,-158.52 184.46,-167.96 186.58,-157.58 179.64,-158.52"/> </g> diff --git a/chapter03/docs/03-graph2.gv b/chapter03/docs/03-graph2.gv index c6c55028..f570b13e 100644 --- a/chapter03/docs/03-graph2.gv +++ b/chapter03/docs/03-graph2.gv @@ -1,29 +1,35 @@ digraph chapter03 { +/* +int a=1; int b=2; int c=0; { int b=3; c=a+b; #showGraph; } return c; #showGraph; +*/ rankdir=BT; + ordering="in"; + concentrate="true"; subgraph cluster_Nodes { - Start1 [ shape=box style=filled fillcolor=yellow label="Start" ]; - Con_2 [ label="#1" ]; - Con_3 [ label="#2" ]; - Con_5 [ label="#3" ]; - Add6 [ label="Add" ]; - Return7 [ shape=box style=filled fillcolor=yellow label="Return" ]; + Start2 [ shape=box style=filled fillcolor=yellow label="Start" ]; + Con_3 [ label="#1" ]; + Con_4 [ label="#2" ]; + Con_6 [ label="#3" ]; + Add7 [ label="+" ]; + Return8 [ shape=box style=filled fillcolor=yellow label="Return" ]; } node [shape=plaintext]; - subgraph cluster_0 { - scope0 [label=< + subgraph cluster_Scope1_0 { + Scope1_0 [label=< <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0"> - <TR><TD BGCOLOR="aqua">0</TD><TD PORT="scope0_a">a</TD><TD PORT="scope0_b">b</TD><TD PORT="scope0_c">c</TD></TR> + <TR><TD BGCOLOR="cyan">0</TD><TD PORT="Scope1_0_a">a</TD><TD PORT="Scope1_0_b">b</TD><TD PORT="Scope1_0_c">c</TD></TR> </TABLE>>]; } - Con_2 -> Start1 [style=dotted]; - Con_3 -> Start1 [style=dotted]; - Con_5 -> Start1 [style=dotted]; - Add6 -> Con_2; - Add6 -> Con_5; - Return7 -> Start1 [color=red]; - Return7 -> Add6; + edge [ fontname=Helvetica, fontsize=8 ]; + Con_3 -> Start2[taillabel=0 style=dotted]; + Con_4 -> Start2[taillabel=0 style=dotted]; + Con_6 -> Start2[taillabel=0 style=dotted]; + Add7 -> Con_3[taillabel=1]; + Add7 -> Con_6[taillabel=2]; + Return8 -> Start2[taillabel=0 color=red]; + Return8 -> Add7[taillabel=1]; edge [style=dashed color=cornflowerblue]; - scope0:scope0_a -> Con_2; - scope0:scope0_b -> Con_3; - scope0:scope0_c -> Add6; -} + Scope1_0:"Scope1_0_a" -> Con_3; + Scope1_0:"Scope1_0_b" -> Con_4; + Scope1_0:"Scope1_0_c" -> Add7; +}
\ No newline at end of file diff --git a/chapter03/docs/03-graph2.svg b/chapter03/docs/03-graph2.svg index 4ab5a8b6..0a539c6a 100644 --- a/chapter03/docs/03-graph2.svg +++ b/chapter03/docs/03-graph2.svg @@ -14,91 +14,98 @@ <polygon fill="none" stroke="black" points="8,-8 8,-276 242,-276 242,-8 8,-8"/> </g> <g id="clust2" class="cluster"> -<title>cluster_0</title> +<title>cluster_Scope1_0</title> <polygon fill="none" stroke="black" points="250,-8 250,-60 344,-60 344,-8 250,-8"/> </g> -<!-- Start1 --> +<!-- Start2 --> <g id="node1" class="node"> -<title>Start1</title> +<title>Start2</title> <polygon fill="yellow" stroke="black" points="126,-268 72,-268 72,-232 126,-232 126,-268"/> <text text-anchor="middle" x="99" y="-246.3" font-family="Times,serif" font-size="14.00">Start</text> </g> -<!-- Con_2 --> +<!-- Con_3 --> <g id="node2" class="node"> -<title>Con_2</title> +<title>Con_3</title> <ellipse fill="none" stroke="black" cx="135" cy="-178" rx="27" ry="18"/> <text text-anchor="middle" x="135" y="-174.3" font-family="Times,serif" font-size="14.00">#1</text> </g> -<!-- Con_2->Start1 --> +<!-- Con_3->Start2 --> <g id="edge1" class="edge"> -<title>Con_2->Start1</title> +<title>Con_3->Start2</title> <path fill="none" stroke="black" stroke-dasharray="1,5" d="M126.65,-195.24C122.46,-203.39 117.27,-213.47 112.53,-222.69"/> <polygon fill="black" stroke="black" points="109.27,-221.38 107.81,-231.88 115.49,-224.58 109.27,-221.38"/> +<text text-anchor="middle" x="123.65" y="-197.84" font-family="Helvetica,sans-Serif" font-size="8.00">0</text> </g> -<!-- Con_3 --> +<!-- Con_4 --> <g id="node3" class="node"> -<title>Con_3</title> +<title>Con_4</title> <ellipse fill="none" stroke="black" cx="207" cy="-178" rx="27" ry="18"/> <text text-anchor="middle" x="207" y="-174.3" font-family="Times,serif" font-size="14.00">#2</text> </g> -<!-- Con_3->Start1 --> +<!-- Con_4->Start2 --> <g id="edge2" class="edge"> -<title>Con_3->Start1</title> +<title>Con_4->Start2</title> <path fill="none" stroke="black" stroke-dasharray="1,5" d="M188.19,-191.19C173.23,-200.89 151.89,-214.72 133.84,-226.42"/> <polygon fill="black" stroke="black" points="131.77,-223.59 125.28,-231.97 135.58,-229.46 131.77,-223.59"/> +<text text-anchor="middle" x="185.19" y="-193.79" font-family="Helvetica,sans-Serif" font-size="8.00">0</text> </g> -<!-- Con_5 --> +<!-- Con_6 --> <g id="node4" class="node"> -<title>Con_5</title> +<title>Con_6</title> <ellipse fill="none" stroke="black" cx="63" cy="-178" rx="27" ry="18"/> <text text-anchor="middle" x="63" y="-174.3" font-family="Times,serif" font-size="14.00">#3</text> </g> -<!-- Con_5->Start1 --> +<!-- Con_6->Start2 --> <g id="edge3" class="edge"> -<title>Con_5->Start1</title> +<title>Con_6->Start2</title> <path fill="none" stroke="black" stroke-dasharray="1,5" d="M71.35,-195.24C75.54,-203.39 80.73,-213.47 85.47,-222.69"/> <polygon fill="black" stroke="black" points="82.51,-224.58 90.19,-231.88 88.73,-221.38 82.51,-224.58"/> +<text text-anchor="middle" x="68.35" y="-197.84" font-family="Helvetica,sans-Serif" font-size="8.00">0</text> </g> -<!-- Add6 --> +<!-- Add7 --> <g id="node5" class="node"> -<title>Add6</title> -<ellipse fill="none" stroke="black" cx="89" cy="-106" rx="28.7" ry="18"/> -<text text-anchor="middle" x="89" y="-102.3" font-family="Times,serif" font-size="14.00">Add</text> +<title>Add7</title> +<ellipse fill="none" stroke="black" cx="71" cy="-106" rx="27" ry="18"/> +<text text-anchor="middle" x="71" y="-102.3" font-family="Times,serif" font-size="14.00">+</text> </g> -<!-- Add6->Con_2 --> +<!-- Add7->Con_3 --> <g id="edge4" class="edge"> -<title>Add6->Con_2</title> -<path fill="none" stroke="black" d="M99.44,-122.88C105.2,-131.66 112.48,-142.74 118.96,-152.58"/> -<polygon fill="black" stroke="black" points="116.19,-154.74 124.6,-161.18 122.04,-150.9 116.19,-154.74"/> +<title>Add7->Con_3</title> +<path fill="none" stroke="black" d="M84.57,-121.85C93.31,-131.4 104.83,-144.01 114.66,-154.75"/> +<polygon fill="black" stroke="black" points="112.12,-157.16 121.45,-162.18 117.28,-152.43 112.12,-157.16"/> +<text text-anchor="middle" x="81.57" y="-124.45" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> </g> -<!-- Add6->Con_5 --> +<!-- Add7->Con_6 --> <g id="edge5" class="edge"> -<title>Add6->Con_5</title> -<path fill="none" stroke="black" d="M82.84,-123.59C79.84,-131.66 76.16,-141.57 72.79,-150.65"/> -<polygon fill="black" stroke="black" points="69.5,-149.45 69.3,-160.04 76.06,-151.89 69.5,-149.45"/> +<title>Add7->Con_6</title> +<path fill="none" stroke="black" d="M69.02,-124.3C68.14,-132.02 67.08,-141.29 66.1,-149.89"/> +<polygon fill="black" stroke="black" points="62.61,-149.56 64.95,-159.9 69.57,-150.36 62.61,-149.56"/> +<text text-anchor="middle" x="66.02" y="-126.9" font-family="Helvetica,sans-Serif" font-size="8.00">2</text> </g> -<!-- Return7 --> +<!-- Return8 --> <g id="node6" class="node"> -<title>Return7</title> -<polygon fill="yellow" stroke="black" points="96,-52 30,-52 30,-16 96,-16 96,-52"/> -<text text-anchor="middle" x="63" y="-30.3" font-family="Times,serif" font-size="14.00">Return</text> +<title>Return8</title> +<polygon fill="yellow" stroke="black" points="89,-52 23,-52 23,-16 89,-16 89,-52"/> +<text text-anchor="middle" x="56" y="-30.3" font-family="Times,serif" font-size="14.00">Return</text> </g> -<!-- Return7->Start1 --> +<!-- Return8->Start2 --> <g id="edge6" class="edge"> -<title>Return7->Start1</title> -<path fill="none" stroke="red" d="M51.87,-52.38C33.84,-82.96 2.57,-147.69 27,-196 34.7,-211.23 49.06,-223.15 62.94,-231.8"/> +<title>Return8->Start2</title> +<path fill="none" stroke="red" d="M46.1,-52.47C30.13,-83.17 2.78,-148.1 27,-196 34.7,-211.23 49.06,-223.15 62.94,-231.8"/> <polygon fill="red" stroke="red" points="61.52,-235.02 71.92,-237.01 65.03,-228.96 61.52,-235.02"/> +<text text-anchor="middle" x="43.1" y="-55.07" font-family="Helvetica,sans-Serif" font-size="8.00">0</text> </g> -<!-- Return7->Add6 --> +<!-- Return8->Add7 --> <g id="edge7" class="edge"> -<title>Return7->Add6</title> -<path fill="none" stroke="black" d="M69.43,-52.3C72.4,-60.3 75.99,-69.98 79.29,-78.85"/> -<polygon fill="black" stroke="black" points="76.06,-80.22 82.83,-88.38 82.63,-77.78 76.06,-80.22"/> +<title>Return8->Add7</title> +<path fill="none" stroke="black" d="M59.71,-52.3C61.36,-60.02 63.35,-69.29 65.19,-77.89"/> +<polygon fill="black" stroke="black" points="61.82,-78.85 67.33,-87.9 68.66,-77.38 61.82,-78.85"/> +<text text-anchor="middle" x="56.71" y="-54.9" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> </g> -<!-- scope0 --> +<!-- Scope1_0 --> <g id="node7" class="node"> -<title>scope0</title> -<polygon fill="aqua" stroke="transparent" points="267,-23 267,-44 283,-44 283,-23 267,-23"/> +<title>Scope1_0</title> +<polygon fill="cyan" stroke="transparent" points="267,-23 267,-44 283,-44 283,-23 267,-23"/> <polygon fill="none" stroke="black" points="267,-23 267,-44 283,-44 283,-23 267,-23"/> <text text-anchor="start" x="270" y="-29.8" font-family="Times,serif" font-size="14.00">0</text> <polygon fill="none" stroke="black" points="283,-23 283,-44 298,-44 298,-23 283,-23"/> @@ -108,23 +115,23 @@ <polygon fill="none" stroke="black" points="314,-23 314,-44 328,-44 328,-23 314,-23"/> <text text-anchor="start" x="317" y="-29.8" font-family="Times,serif" font-size="14.00">c</text> </g> -<!-- scope0->Con_2 --> +<!-- Scope1_0->Con_3 --> <g id="edge8" class="edge"> -<title>scope0:scope0_a->Con_2</title> +<title>Scope1_0:Scope1_0_a->Con_3</title> <path fill="none" stroke="cornflowerblue" stroke-dasharray="5,2" d="M290,-45C290,-77.9 208.02,-132.76 163.3,-160.24"/> <polygon fill="cornflowerblue" stroke="cornflowerblue" points="161.36,-157.33 154.63,-165.51 164.99,-163.31 161.36,-157.33"/> </g> -<!-- scope0->Con_3 --> +<!-- Scope1_0->Con_4 --> <g id="edge9" class="edge"> -<title>scope0:scope0_b->Con_3</title> +<title>Scope1_0:Scope1_0_b->Con_4</title> <path fill="none" stroke="cornflowerblue" stroke-dasharray="5,2" d="M306,-45C306,-93.23 263.17,-135.12 233.85,-158.15"/> <polygon fill="cornflowerblue" stroke="cornflowerblue" points="231.47,-155.56 225.62,-164.4 235.7,-161.14 231.47,-155.56"/> </g> -<!-- scope0->Add6 --> +<!-- Scope1_0->Add7 --> <g id="edge10" class="edge"> -<title>scope0:scope0_c->Add6</title> -<path fill="none" stroke="cornflowerblue" stroke-dasharray="5,2" d="M321,-45C321,-86.77 178.12,-76.36 138,-88 132.99,-89.45 127.75,-91.12 122.62,-92.82"/> -<polygon fill="cornflowerblue" stroke="cornflowerblue" points="121.34,-89.56 113.02,-96.11 123.61,-96.18 121.34,-89.56"/> +<title>Scope1_0:Scope1_0_c->Add7</title> +<path fill="none" stroke="cornflowerblue" stroke-dasharray="5,2" d="M321,-45C321,-86.77 178.58,-78.08 138,-88 127.51,-90.56 116.11,-93.43 105.75,-96.06"/> +<polygon fill="cornflowerblue" stroke="cornflowerblue" points="104.62,-92.74 95.79,-98.6 106.35,-99.52 104.62,-92.74"/> </g> </g> </svg> diff --git a/chapter03/docs/03-graph3.gv b/chapter03/docs/03-graph3.gv index 717024e3..50cb6d27 100644 --- a/chapter03/docs/03-graph3.gv +++ b/chapter03/docs/03-graph3.gv @@ -1,32 +1,37 @@ digraph chapter03 { +/* +int x0=1; int y0=2; int x1=3; int y1=4; return (x0-x1)*(x0-x1) + (y0-y1)*(y0-y1); #showGraph; +*/ rankdir=BT; + ordering="in"; + concentrate="true"; subgraph cluster_Nodes { - Start1 [ shape=box style=filled fillcolor=yellow label="Start" ]; - Con_2 [ label="#1" ]; - Con_3 [ label="#2" ]; - Con_19 [ label="#8" ]; - Con_4 [ label="#3" ]; - Return20 [ shape=box style=filled fillcolor=yellow label="Return" ]; - Con_5 [ label="#4" ]; + Start2 [ shape=box style=filled fillcolor=yellow label="Start" ]; + Con_3 [ label="#1" ]; + Con_4 [ label="#2" ]; + Con_20 [ label="#8" ]; + Con_5 [ label="#3" ]; + Return21 [ shape=box style=filled fillcolor=yellow label="Return" ]; + Con_6 [ label="#4" ]; } node [shape=plaintext]; - subgraph cluster_0 { - scope0 [label=< + subgraph cluster_Scope1_0 { + Scope1_0 [label=< <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0"> - <TR><TD BGCOLOR="cyan">0</TD><TD PORT="scope0_y0">y0</TD><TD PORT="scope0_x0">x0</TD><TD PORT="scope0_y1">y1</TD><TD PORT="scope0_x1">x1</TD></TR> + <TR><TD BGCOLOR="cyan">0</TD><TD PORT="Scope1_0_y0">y0</TD><TD PORT="Scope1_0_x0">x0</TD><TD PORT="Scope1_0_y1">y1</TD><TD PORT="Scope1_0_x1">x1</TD></TR> </TABLE>>]; } - Con_2 -> Start1 [style=dotted]; - Con_3 -> Start1 [style=dotted]; - Con_19 -> Start1 [style=dotted]; - Con_4 -> Start1 [style=dotted]; - Return20 -> Start1 [color=red]; - Return20 -> Con_19; - Con_5 -> Start1 [style=dotted]; + edge [ fontname=Helvetica, fontsize=8 ]; + Con_3 -> Start2[taillabel=0 style=dotted]; + Con_4 -> Start2[taillabel=0 style=dotted]; + Con_20 -> Start2[taillabel=0 style=dotted]; + Con_5 -> Start2[taillabel=0 style=dotted]; + Return21 -> Start2[taillabel=0 color=red]; + Return21 -> Con_20[taillabel=1]; + Con_6 -> Start2[taillabel=0 style=dotted]; edge [style=dashed color=cornflowerblue]; - scope0:scope0_y0 -> Con_3; - scope0:scope0_x0 -> Con_2; - scope0:scope0_y1 -> Con_5; - scope0:scope0_x1 -> Con_4; + Scope1_0:"Scope1_0_y0" -> Con_4; + Scope1_0:"Scope1_0_x0" -> Con_3; + Scope1_0:"Scope1_0_y1" -> Con_6; + Scope1_0:"Scope1_0_x1" -> Con_5; } - diff --git a/chapter03/docs/03-graph3.svg b/chapter03/docs/03-graph3.svg index 3b720323..623bd902 100644 --- a/chapter03/docs/03-graph3.svg +++ b/chapter03/docs/03-graph3.svg @@ -14,96 +14,103 @@ <polygon fill="none" stroke="black" points="8,-8 8,-204 386,-204 386,-8 8,-8"/> </g> <g id="clust2" class="cluster"> -<title>cluster_0</title> +<title>cluster_Scope1_0</title> <polygon fill="none" stroke="black" points="394,-8 394,-60 538,-60 538,-8 394,-8"/> </g> -<!-- Start1 --> +<!-- Start2 --> <g id="node1" class="node"> -<title>Start1</title> +<title>Start2</title> <polygon fill="yellow" stroke="black" points="198,-196 144,-196 144,-160 198,-160 198,-196"/> <text text-anchor="middle" x="171" y="-174.3" font-family="Times,serif" font-size="14.00">Start</text> </g> -<!-- Con_2 --> +<!-- Con_3 --> <g id="node2" class="node"> -<title>Con_2</title> +<title>Con_3</title> <ellipse fill="none" stroke="black" cx="207" cy="-106" rx="27" ry="18"/> <text text-anchor="middle" x="207" y="-102.3" font-family="Times,serif" font-size="14.00">#1</text> </g> -<!-- Con_2->Start1 --> +<!-- Con_3->Start2 --> <g id="edge1" class="edge"> -<title>Con_2->Start1</title> +<title>Con_3->Start2</title> <path fill="none" stroke="black" stroke-dasharray="1,5" d="M198.65,-123.24C194.46,-131.39 189.27,-141.47 184.53,-150.69"/> <polygon fill="black" stroke="black" points="181.27,-149.38 179.81,-159.88 187.49,-152.58 181.27,-149.38"/> +<text text-anchor="middle" x="195.65" y="-125.84" font-family="Helvetica,sans-Serif" font-size="8.00">0</text> </g> -<!-- Con_3 --> +<!-- Con_4 --> <g id="node3" class="node"> -<title>Con_3</title> +<title>Con_4</title> <ellipse fill="none" stroke="black" cx="135" cy="-106" rx="27" ry="18"/> <text text-anchor="middle" x="135" y="-102.3" font-family="Times,serif" font-size="14.00">#2</text> </g> -<!-- Con_3->Start1 --> +<!-- Con_4->Start2 --> <g id="edge2" class="edge"> -<title>Con_3->Start1</title> +<title>Con_4->Start2</title> <path fill="none" stroke="black" stroke-dasharray="1,5" d="M143.35,-123.24C147.54,-131.39 152.73,-141.47 157.47,-150.69"/> <polygon fill="black" stroke="black" points="154.51,-152.58 162.19,-159.88 160.73,-149.38 154.51,-152.58"/> +<text text-anchor="middle" x="140.35" y="-125.84" font-family="Helvetica,sans-Serif" font-size="8.00">0</text> </g> -<!-- Con_19 --> +<!-- Con_20 --> <g id="node4" class="node"> -<title>Con_19</title> -<ellipse fill="none" stroke="black" cx="43" cy="-106" rx="27" ry="18"/> -<text text-anchor="middle" x="43" y="-102.3" font-family="Times,serif" font-size="14.00">#8</text> +<title>Con_20</title> +<ellipse fill="none" stroke="black" cx="63" cy="-106" rx="27" ry="18"/> +<text text-anchor="middle" x="63" y="-102.3" font-family="Times,serif" font-size="14.00">#8</text> </g> -<!-- Con_19->Start1 --> +<!-- Con_20->Start2 --> <g id="edge3" class="edge"> -<title>Con_19->Start1</title> -<path fill="none" stroke="black" stroke-dasharray="1,5" d="M63.28,-118.09C82.45,-128.57 111.64,-144.54 134.8,-157.2"/> -<polygon fill="black" stroke="black" points="133.21,-160.32 143.67,-162.05 136.57,-154.18 133.21,-160.32"/> +<title>Con_20->Start2</title> +<path fill="none" stroke="black" stroke-dasharray="1,5" d="M81.81,-119.19C96.77,-128.89 118.11,-142.72 136.16,-154.42"/> +<polygon fill="black" stroke="black" points="134.42,-157.46 144.72,-159.97 138.23,-151.59 134.42,-157.46"/> +<text text-anchor="middle" x="78.81" y="-121.79" font-family="Helvetica,sans-Serif" font-size="8.00">0</text> </g> -<!-- Con_4 --> +<!-- Con_5 --> <g id="node5" class="node"> -<title>Con_4</title> +<title>Con_5</title> <ellipse fill="none" stroke="black" cx="351" cy="-106" rx="27" ry="18"/> <text text-anchor="middle" x="351" y="-102.3" font-family="Times,serif" font-size="14.00">#3</text> </g> -<!-- Con_4->Start1 --> +<!-- Con_5->Start2 --> <g id="edge4" class="edge"> -<title>Con_4->Start1</title> +<title>Con_5->Start2</title> <path fill="none" stroke="black" stroke-dasharray="1,5" d="M329.82,-117.38C324.99,-119.65 319.84,-121.97 315,-124 279.07,-139.06 237.19,-154.21 207.89,-164.43"/> <polygon fill="black" stroke="black" points="206.38,-161.25 198.08,-167.84 208.68,-167.87 206.38,-161.25"/> +<text text-anchor="middle" x="326.82" y="-119.98" font-family="Helvetica,sans-Serif" font-size="8.00">0</text> </g> -<!-- Return20 --> +<!-- Return21 --> <g id="node6" class="node"> -<title>Return20</title> -<polygon fill="yellow" stroke="black" points="102,-52 36,-52 36,-16 102,-16 102,-52"/> -<text text-anchor="middle" x="69" y="-30.3" font-family="Times,serif" font-size="14.00">Return</text> +<title>Return21</title> +<polygon fill="yellow" stroke="black" points="89,-52 23,-52 23,-16 89,-16 89,-52"/> +<text text-anchor="middle" x="56" y="-30.3" font-family="Times,serif" font-size="14.00">Return</text> </g> -<!-- Return20->Start1 --> +<!-- Return21->Start2 --> <g id="edge5" class="edge"> -<title>Return20->Start1</title> -<path fill="none" stroke="red" d="M71.6,-52.16C75.16,-71.21 83.04,-102.14 99,-124 108.52,-137.04 122.19,-148.23 135.06,-156.92"/> -<polygon fill="red" stroke="red" points="133.48,-160.07 143.79,-162.53 137.27,-154.18 133.48,-160.07"/> +<title>Return21->Start2</title> +<path fill="none" stroke="red" d="M42.04,-52.06C28.34,-71.02 11.57,-101.87 27,-124 50.89,-158.26 99.53,-170.43 133.64,-174.72"/> +<polygon fill="red" stroke="red" points="133.4,-178.22 143.72,-175.82 134.16,-171.26 133.4,-178.22"/> +<text text-anchor="middle" x="39.04" y="-54.66" font-family="Helvetica,sans-Serif" font-size="8.00">0</text> </g> -<!-- Return20->Con_19 --> +<!-- Return21->Con_20 --> <g id="edge6" class="edge"> -<title>Return20->Con_19</title> -<path fill="none" stroke="black" d="M62.57,-52.3C59.6,-60.3 56.01,-69.98 52.71,-78.85"/> -<polygon fill="black" stroke="black" points="49.37,-77.78 49.17,-88.38 55.94,-80.22 49.37,-77.78"/> +<title>Return21->Con_20</title> +<path fill="none" stroke="black" d="M57.73,-52.3C58.5,-60.02 59.43,-69.29 60.29,-77.89"/> +<polygon fill="black" stroke="black" points="56.81,-78.29 61.29,-87.9 63.78,-77.6 56.81,-78.29"/> +<text text-anchor="middle" x="54.73" y="-54.9" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> </g> -<!-- Con_5 --> +<!-- Con_6 --> <g id="node7" class="node"> -<title>Con_5</title> +<title>Con_6</title> <ellipse fill="none" stroke="black" cx="279" cy="-106" rx="27" ry="18"/> <text text-anchor="middle" x="279" y="-102.3" font-family="Times,serif" font-size="14.00">#4</text> </g> -<!-- Con_5->Start1 --> +<!-- Con_6->Start2 --> <g id="edge7" class="edge"> -<title>Con_5->Start1</title> +<title>Con_6->Start2</title> <path fill="none" stroke="black" stroke-dasharray="1,5" d="M260.19,-119.19C245.23,-128.89 223.89,-142.72 205.84,-154.42"/> <polygon fill="black" stroke="black" points="203.77,-151.59 197.28,-159.97 207.58,-157.46 203.77,-151.59"/> +<text text-anchor="middle" x="257.19" y="-121.79" font-family="Helvetica,sans-Serif" font-size="8.00">0</text> </g> -<!-- scope0 --> +<!-- Scope1_0 --> <g id="node8" class="node"> -<title>scope0</title> +<title>Scope1_0</title> <polygon fill="cyan" stroke="transparent" points="410,-23 410,-44 426,-44 426,-23 410,-23"/> <polygon fill="none" stroke="black" points="410,-23 410,-44 426,-44 426,-23 410,-23"/> <text text-anchor="start" x="413" y="-29.8" font-family="Times,serif" font-size="14.00">0</text> @@ -116,27 +123,27 @@ <polygon fill="none" stroke="black" points="498,-23 498,-44 522,-44 522,-23 498,-23"/> <text text-anchor="start" x="501" y="-29.8" font-family="Times,serif" font-size="14.00">x1</text> </g> -<!-- scope0->Con_2 --> +<!-- Scope1_0->Con_3 --> <g id="edge9" class="edge"> -<title>scope0:scope0_x0->Con_2</title> +<title>Scope1_0:Scope1_0_x0->Con_3</title> <path fill="none" stroke="cornflowerblue" stroke-dasharray="5,2" d="M462,-45C462,-94.6 290.16,-72.65 243,-88 241.08,-88.63 239.12,-89.33 237.17,-90.09"/> <polygon fill="cornflowerblue" stroke="cornflowerblue" points="235.39,-87.04 227.58,-94.19 238.15,-93.48 235.39,-87.04"/> </g> -<!-- scope0->Con_3 --> +<!-- Scope1_0->Con_4 --> <g id="edge8" class="edge"> -<title>scope0:scope0_y0->Con_3</title> +<title>Scope1_0:Scope1_0_y0->Con_4</title> <path fill="none" stroke="cornflowerblue" stroke-dasharray="5,2" d="M438,-45C438,-67.35 411.84,-55.23 390,-60 294.13,-80.94 265.19,-60.49 171,-88 169.06,-88.57 167.09,-89.23 165.13,-89.95"/> <polygon fill="cornflowerblue" stroke="cornflowerblue" points="163.39,-86.88 155.5,-93.97 166.08,-93.34 163.39,-86.88"/> </g> -<!-- scope0->Con_4 --> +<!-- Scope1_0->Con_5 --> <g id="edge11" class="edge"> -<title>scope0:scope0_x1->Con_4</title> +<title>Scope1_0:Scope1_0_x1->Con_5</title> <path fill="none" stroke="cornflowerblue" stroke-dasharray="5,2" d="M510,-45C510,-71.13 433.9,-89.82 387,-98.86"/> <polygon fill="cornflowerblue" stroke="cornflowerblue" points="386.09,-95.47 376.9,-100.75 387.37,-102.35 386.09,-95.47"/> </g> -<!-- scope0->Con_5 --> +<!-- Scope1_0->Con_6 --> <g id="edge10" class="edge"> -<title>scope0:scope0_y1->Con_5</title> +<title>Scope1_0:Scope1_0_y1->Con_6</title> <path fill="none" stroke="cornflowerblue" stroke-dasharray="5,2" d="M486,-45C486,-123.37 388.78,-61.59 315,-88 313.15,-88.66 311.26,-89.39 309.37,-90.16"/> <polygon fill="cornflowerblue" stroke="cornflowerblue" points="307.8,-87.02 300.03,-94.23 310.6,-93.44 307.8,-87.02"/> </g> diff --git a/chapter03/src/main/java/com/seaofnodes/simple/GraphVisualizer.java b/chapter03/src/main/java/com/seaofnodes/simple/GraphVisualizer.java index dc5358f4..a85a670e 100644 --- a/chapter03/src/main/java/com/seaofnodes/simple/GraphVisualizer.java +++ b/chapter03/src/main/java/com/seaofnodes/simple/GraphVisualizer.java @@ -18,6 +18,9 @@ public class GraphVisualizer { Collection<Node> all = findAll(parser); StringBuilder sb = new StringBuilder(); sb.append("digraph chapter03 {\n"); + sb.append("/*\n"); + sb.append(parser.src()); + sb.append("\n*/\n"); // To keep the Scopes below the graph and pointing up into the graph we // need to group the Nodes in a subgraph cluster, and the scopes into a @@ -25,6 +28,13 @@ public class GraphVisualizer { // scopes and nodes. If we try to cross subgraph cluster borders while // still making the subgraphs DOT gets confused. sb.append("\trankdir=BT;\n"); // Force Nodes before Scopes + + // Preserve node input order + sb.append("\tordering=\"in\";\n"); + + // Merge multiple edges hitting the same node. Makes common shared + // nodes much prettier to look at. + sb.append("\tconcentrate=\"true\";\n"); // Just the Nodes first, in a cluster no edges nodes(sb, all); @@ -47,12 +57,15 @@ public class GraphVisualizer { // Just the Nodes first, in a cluster no edges sb.append("\tsubgraph cluster_Nodes {\n"); // Magic "cluster_" in the subgraph name for( Node n : all ) { + if( n instanceof ScopeNode ) + continue; // Do not emit, rolled into Scope cluster already sb.append("\t\t").append(n.uniqueName()).append(" [ "); + String lab = n.glabel(); // control nodes have box shape // other nodes are ellipses, i.e. default shape - if( n instanceof Control ) + if( n.isCFG() ) sb.append("shape=box style=filled fillcolor=yellow "); - sb.append("label=\"").append(n.label()).append("\" "); + sb.append("label=\"").append(lab).append("\" "); sb.append("];\n"); } sb.append("\t}\n"); // End Node cluster @@ -62,12 +75,12 @@ public class GraphVisualizer { sb.append("\tnode [shape=plaintext];\n"); int level=0; for( HashMap<String,Integer> scope : scopenode._scopes ) { - sb.append("\tsubgraph cluster_").append(level).append(" {\n"); // Magic "cluster_" in the subgraph name - String scopeName = makeScopeName(level); + String scopeName = makeScopeName(scopenode, level); + sb.append("\tsubgraph cluster_").append(scopeName).append(" {\n"); // Magic "cluster_" in the subgraph name sb.append("\t\t").append(scopeName).append(" [label=<\n"); sb.append("\t\t\t<TABLE BORDER=\"0\" CELLBORDER=\"1\" CELLSPACING=\"0\">\n"); // Add the scope level - sb.append("\t\t\t<TR><TD BGCOLOR=\"aqua\">").append(level).append("</TD>"); + sb.append("\t\t\t<TR><TD BGCOLOR=\"cyan\">").append(level).append("</TD>"); for( String name : scope.keySet() ) sb.append("<TD PORT=\"").append(makePortName(scopeName, name)).append("\">").append(name).append("</TD>"); sb.append("</TR>\n"); @@ -79,23 +92,37 @@ public class GraphVisualizer { // We close them all at once here. sb.append( "\t}\n".repeat( level ) ); // End all Scope clusters } - - private String makeScopeName(int level) { return "scope" + level; } + + private String makeScopeName(ScopeNode sn, int level) { return sn.uniqueName() + "_" + level; } private String makePortName(String scopeName, String varName) { return scopeName + "_" + varName; } // Walk the node edges private void nodeEdges(StringBuilder sb, Collection<Node> all) { - for( Node n : all ) - for( Node out : n._inputs ) - if( out != null ) { - sb.append('\t').append(n.uniqueName()).append(" -> ").append(out.uniqueName()); - // Control edges are colored red - if( n instanceof ConstantNode && out instanceof StartNode ) - sb.append(" [style=dotted]"); - else if( n instanceof Control && out instanceof Control ) - sb.append(" [color=red]"); - sb.append(";\n"); + // All them edge labels + sb.append("\tedge [ fontname=Helvetica, fontsize=8 ];\n"); + for( Node n : all ) { + // In this chapter we do display the Constant->Start edge; + // ScopeNodes are done separately + if( n instanceof ScopeNode ) + continue; + int i=0; + for( Node def : n._inputs ) { + if( def != null ) { + // Most edges land here use->def + sb.append('\t').append(n.uniqueName()).append(" -> "); + sb.append(def.uniqueName()); + // Number edges, so we can see how they track + sb.append("[taillabel=").append(i); + if( n instanceof ConstantNode && def instanceof StartNode ) + sb.append(" style=dotted"); + // control edges are colored red + else if( def.isCFG() ) + sb.append(" color=red"); + sb.append("];\n"); } + i++; + } + } } // Walk the scope edges @@ -103,19 +130,23 @@ public class GraphVisualizer { sb.append("\tedge [style=dashed color=cornflowerblue];\n"); int level=0; for( HashMap<String,Integer> scope : scopenode._scopes ) { - String scopeName = makeScopeName(level); - for( String name : scope.keySet() ) - sb.append("\t").append(scopeName).append(":").append(makePortName(scopeName, name)).append(" -> ").append(scopenode.in(scope.get(name)).uniqueName()).append(";\n"); + String scopeName = makeScopeName(scopenode, level); + for( String name : scope.keySet() ) { + Node def = scopenode.in(scope.get(name)); + if( def==null ) continue; + sb.append("\t") + .append(scopeName).append(":") + .append('"').append(makePortName(scopeName, name)).append('"') // wrap port name with quotes because $ctrl is not valid unquoted + .append(" -> "); + sb.append(def.uniqueName()); + sb.append(";\n"); + } level++; } } /** - * Walks the whole graph, starting from Start. - * Since Start is the input to all constants - we look at the outputs for - * Start, but for then subsequently we look at the inputs of each node. - * During graph construction not all nodes are reachable this way, so we - * also scan the symbol tables. + * Finds all nodes in the graph. */ private Collection<Node> findAll(Parser parser) { final StartNode start = Parser.START; @@ -133,10 +164,14 @@ public class GraphVisualizer { * Walk a subgraph and populate distinct nodes in the all list. */ private void walk(HashMap<Integer, Node> all, Node n) { + if(n == null ) return; if (all.get(n._nid) != null) return; // Been there, done that all.put(n._nid, n); for (Node c : n._inputs) if (c != null) walk(all, c); + for (Node c : n._outputs) + if (c != null) + walk(all, c); } } diff --git a/chapter03/src/main/java/com/seaofnodes/simple/Parser.java b/chapter03/src/main/java/com/seaofnodes/simple/Parser.java index 3d06a9c3..c8195882 100644 --- a/chapter03/src/main/java/com/seaofnodes/simple/Parser.java +++ b/chapter03/src/main/java/com/seaofnodes/simple/Parser.java @@ -23,6 +23,7 @@ public class Parser { */ public static StartNode START; + // The Lexer. Thin wrapper over a byte[] buffer with a cursor. private final Lexer _lexer; /** @@ -31,17 +32,35 @@ public class Parser { */ public ScopeNode _scope; + /** + * List of keywords disallowed as identifiers + */ + private final HashSet<String> KEYWORDS = new HashSet<>(){{ + add("int"); + add("return"); + }}; + + public Parser(String source) { _lexer = new Lexer(source); - _scope = new ScopeNode(); Node.reset(); + _scope = new ScopeNode(); START = new StartNode(); } - public ReturnNode parse() { - return (ReturnNode) parseBlock(false); - } + String src() { return new String( _lexer._input ); } + public ReturnNode parse() { return parse(false); } + public ReturnNode parse(boolean show) { + try { + var ret = (ReturnNode) parseBlock(); + if (!_lexer.isEOF()) throw error("Syntax error, unexpected " + _lexer.getAnyNextToken()); + return ret; + } + finally { + if( show ) showGraph(); + } + } /** * Parses a block @@ -49,23 +68,17 @@ public class Parser { * <pre> * '{' statements '}' * </pre> + * Does not parse the opening or closing '{}' + * @return a {@link Node} or {@code null} */ - private Node parseBlock(boolean requireClosingBracket) { + private Node parseBlock() { // Enter a new scope _scope.push(); Node n = null; - do { - if (match("}")) { - if (requireClosingBracket) break; - else throw error("unexpected '}' token"); - } else if (_lexer.isEOF()) { - if (requireClosingBracket) require("}"); - else break; - } - + while (!peek('}') && !_lexer.isEOF()) { Node n0 = parseStatement(); if (n0 != null) n = n0; // Allow null returns from eg showGraph - } while (true); + }; // Exit scope _scope.pop(); return n; @@ -77,32 +90,34 @@ public class Parser { * <pre> * returnStatement | declStatement | blockStatement | expressionStatement * </pre> + * @return a {@link Node} or {@code null} */ private Node parseStatement() { - if (match("return")) return parseReturn(); - else if (match("int")) return parseDecl(); - else if (match("{")) return parseBlock(true); - else if (match("#showGraph")) return showGraph(); + if (matchx("return") ) return parseReturn(); + else if (matchx("int")) return parseDecl(); + else if (match ("{" )) return require(parseBlock(),"}"); + else if (matchx("#showGraph")) return require(showGraph(),";"); else return parseExpressionStatement(); } /** - * Parses returnStatement; "return" already parsed + * Parses a return statement; "return" already parsed. * * <pre> * 'return' expr ; * </pre> + * @return an expression {@link Node}, never {@code null} */ private Node parseReturn() { var expr = require(parseExpression(), ";"); - return new ReturnNode(START, expr); + return new ReturnNode(START, expr).peephole(); } /** * Dumps out the node graph + * @return {@code null} */ private Node showGraph() { - require(";"); System.out.println(new GraphVisualizer().generateDotOutput(this)); return null; } @@ -113,6 +128,7 @@ public class Parser { * <pre> * name '=' expression ';' * </pre> + * @return an expression {@link Node}, never {@code null} */ private Node parseExpressionStatement() { var name = requireId(); @@ -129,6 +145,7 @@ public class Parser { * <pre> * 'int' name = expression ';' * </pre> + * @return an expression {@link Node}, never {@code null} */ private Node parseDecl() { // Type is 'int' for now @@ -146,8 +163,9 @@ public class Parser { * <pre> * expr : additiveExpr * </pre> + * @return an expression {@link Node}, never {@code null} */ - private Node parseExpression() {return parseAddition();} + private Node parseExpression() { return parseAddition(); } /** * Parse an additive expression @@ -155,6 +173,7 @@ public class Parser { * <pre> * additiveExpr : multiplicativeExpr (('+' | '-') multiplicativeExpr)* * </pre> + * @return an add expression {@link Node}, never {@code null} */ private Node parseAddition() { var lhs = parseMultiplication(); @@ -169,6 +188,7 @@ public class Parser { * <pre> * multiplicativeExpr : unaryExpr (('*' | '/') unaryExpr)* * </pre> + * @return a multiply expression {@link Node}, never {@code null} */ private Node parseMultiplication() { var lhs = parseUnary(); @@ -183,6 +203,7 @@ public class Parser { * <pre> * unaryExpr : ('-') unaryExpr | primaryExpr * </pre> + * @return a unary expression {@link Node}, never {@code null} */ private Node parseUnary() { if (match("-")) return new MinusNode(parseUnary()).peephole(); @@ -195,15 +216,16 @@ public class Parser { * <pre> * primaryExpr : integerLiteral | Identifier | '(' expression ')' * </pre> + * @return a primary {@link Node}, never {@code null} */ private Node parsePrimary() { - if (_lexer.isNumber()) return parseIntegerLiteral(); - if (match("(")) return require(parseExpression(), ")"); - String name = requireId(); - Node id = _scope.lookup(name); - if( id==null ) - throw error("Undefined name '" + name + "'"); - return id; + if( _lexer.isNumber() ) return parseIntegerLiteral(); + if( match("(") ) return require(parseExpression(), ")"); + String name = _lexer.matchId(); + if( name == null) throw errorSyntax("an identifier or expression"); + Node n = _scope.lookup(name); + if( n!=null ) return n; + throw error("Undefined name '" + name + "'"); } /** @@ -221,17 +243,21 @@ public class Parser { // Utilities for lexical analysis // Return true and skip if "syntax" is next in the stream. - private boolean match(String syntax) {return _lexer.match(syntax);} + private boolean match (String syntax) { return _lexer.match (syntax); } + // Match must be "exact", not be followed by more id letters + private boolean matchx(String syntax) { return _lexer.matchx(syntax); } + // Return true and do NOT skip if 'ch' is next + private boolean peek(char ch) { return _lexer.peek(ch); } // Require and return an identifier private String requireId() { String id = _lexer.matchId(); - if (id != null) return id; - throw error("identifier"); + if (id != null && !KEYWORDS.contains(id) ) return id; + throw error("Expected an identifier, found '"+id+"'"); } // Require an exact match - private void require(String syntax) {require(null, syntax);} + private void require(String syntax) { require(null, syntax); } private Node require(Node n, String syntax) { if (match(syntax)) return n; throw errorSyntax(syntax); @@ -313,11 +339,24 @@ public class Parser { int len = syntax.length(); if (_position + len > _input.length) return false; for (int i = 0; i < len; i++) - if ((char) _input[_position + i] != syntax.charAt(i)) return false; + if ((char) _input[_position + i] != syntax.charAt(i)) + return false; _position += len; return true; } + boolean matchx(String syntax) { + if( !match(syntax) ) return false; + if( !isIdLetter(peek()) ) return true; + _position -= syntax.length(); + return false; + } + + private boolean peek(char ch) { + skipWhiteSpace(); + return peek()==ch; + } + // Return an identifier or null String matchId() { skipWhiteSpace(); @@ -341,7 +380,7 @@ public class Parser { String snum = new String(_input, start, --_position - start); if (snum.length() > 1 && snum.charAt(0) == '0') throw error("Syntax error: integer values cannot start with '0'"); - return new TypeInteger(Long.parseLong(snum)); + return TypeInteger.constant(Long.parseLong(snum)); } // First letter of an identifier @@ -367,8 +406,7 @@ public class Parser { private String parsePunctuation() { int start = _position; - if (isPunctuation(nextChar())) ; - return new String(_input, start, --_position - start); + return new String(_input, start, 1); } } diff --git a/chapter03/src/main/java/com/seaofnodes/simple/node/AddNode.java b/chapter03/src/main/java/com/seaofnodes/simple/node/AddNode.java index 015779dc..6784ad60 100644 --- a/chapter03/src/main/java/com/seaofnodes/simple/node/AddNode.java +++ b/chapter03/src/main/java/com/seaofnodes/simple/node/AddNode.java @@ -3,17 +3,16 @@ package com.seaofnodes.simple.node; import com.seaofnodes.simple.type.*; public class AddNode extends Node { - public AddNode(Node lhs, Node rhs) { - super(null, lhs, rhs); - } + public AddNode(Node lhs, Node rhs) { super(null, lhs, rhs); } - @Override - public String label() { return "Add"; } + @Override public String label() { return "Add"; } + + @Override public String glabel() { return "+"; } @Override - StringBuilder _print(StringBuilder sb) { - in(1)._print(sb.append("(")); - in(2)._print(sb.append("+")); + StringBuilder _print1(StringBuilder sb) { + in(1)._print0(sb.append("(")); + in(2)._print0(sb.append("+")); return sb.append(")"); } @@ -21,8 +20,9 @@ public class AddNode extends Node { @Override public Type compute() { if( in(1)._type instanceof TypeInteger i0 && - in(2)._type instanceof TypeInteger i1 ) - return new TypeInteger(i0._con + i1._con); + in(2)._type instanceof TypeInteger i1 ) { + return TypeInteger.constant(i0.value()+i1.value()); + } return TypeBot.BOTTOM; } diff --git a/chapter03/src/main/java/com/seaofnodes/simple/node/ConstantNode.java b/chapter03/src/main/java/com/seaofnodes/simple/node/ConstantNode.java index 798d40d5..ec85bf1f 100644 --- a/chapter03/src/main/java/com/seaofnodes/simple/node/ConstantNode.java +++ b/chapter03/src/main/java/com/seaofnodes/simple/node/ConstantNode.java @@ -16,25 +16,25 @@ import com.seaofnodes.simple.type.Type; * The Constant's value is the value stored in it. */ public class ConstantNode extends Node { - + Type _con; public ConstantNode( Type type ) { super(Parser.START); - _type = type; + _con = type; } @Override - public String label() { return "#"+_type; } + public String label() { return "#"+_con; } @Override public String uniqueName() { return "Con_" + _nid; } @Override - StringBuilder _print(StringBuilder sb) { - return _type._print(sb); + StringBuilder _print1(StringBuilder sb) { + return _con._print(sb); } @Override - public Type compute() { return _type; } + public Type compute() { return _con; } @Override public Node idealize() { return null; } diff --git a/chapter03/src/main/java/com/seaofnodes/simple/node/Control.java b/chapter03/src/main/java/com/seaofnodes/simple/node/Control.java deleted file mode 100644 index 48cf2b7a..00000000 --- a/chapter03/src/main/java/com/seaofnodes/simple/node/Control.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.seaofnodes.simple.node; - - -/** - * Control interface is a marker interface to be implemented - * by Control nodes. - */ -public interface Control { -} diff --git a/chapter03/src/main/java/com/seaofnodes/simple/node/DivNode.java b/chapter03/src/main/java/com/seaofnodes/simple/node/DivNode.java index 0056c42d..ca7df79c 100644 --- a/chapter03/src/main/java/com/seaofnodes/simple/node/DivNode.java +++ b/chapter03/src/main/java/com/seaofnodes/simple/node/DivNode.java @@ -5,17 +5,16 @@ import com.seaofnodes.simple.type.TypeBot; import com.seaofnodes.simple.type.TypeInteger; public class DivNode extends Node { - public DivNode(Node lhs, Node rhs) { - super(null, lhs, rhs); - } + public DivNode(Node lhs, Node rhs) { super(null, lhs, rhs); } + + @Override public String label() { return "Div"; } + + @Override public String glabel() { return "//"; } @Override - public String label() { return "Div"; } - - @Override - StringBuilder _print(StringBuilder sb) { - in(1)._print(sb.append("(")); - in(2)._print(sb.append("/")); + StringBuilder _print1(StringBuilder sb) { + in(1)._print0(sb.append("(")); + in(2)._print0(sb.append("/")); return sb.append(")"); } @@ -23,11 +22,9 @@ public class DivNode extends Node { public Type compute() { if (in(1)._type instanceof TypeInteger i0 && in(2)._type instanceof TypeInteger i1) { - if (i0.isConstant() && i1.isConstant()) - return i1._con == 0 - ? TypeInteger.ZERO - : new TypeInteger(i0._con/i1._con); - return new TypeInteger(i0._con / i1._con); + return i1.value() == 0 + ? TypeInteger.ZERO + : TypeInteger.constant(i0.value()/i1.value()); } return TypeBot.BOTTOM; } diff --git a/chapter03/src/main/java/com/seaofnodes/simple/node/MinusNode.java b/chapter03/src/main/java/com/seaofnodes/simple/node/MinusNode.java index 7fab83b0..834f4c11 100644 --- a/chapter03/src/main/java/com/seaofnodes/simple/node/MinusNode.java +++ b/chapter03/src/main/java/com/seaofnodes/simple/node/MinusNode.java @@ -5,23 +5,22 @@ import com.seaofnodes.simple.type.TypeBot; import com.seaofnodes.simple.type.TypeInteger; public class MinusNode extends Node { - public MinusNode(Node in) { - super(null, in); - } + public MinusNode(Node in) { super(null, in); } - @Override - public String label() { return "Minus"; } + @Override public String label() { return "Minus"; } + + @Override public String glabel() { return "-"; } @Override - StringBuilder _print(StringBuilder sb) { - in(1)._print(sb.append("(-")); + StringBuilder _print1(StringBuilder sb) { + in(1)._print0(sb.append("(-")); return sb.append(")"); } @Override public Type compute() { if (in(1)._type instanceof TypeInteger i0) - return new TypeInteger(-i0._con); + return TypeInteger.constant(-i0.value()); return TypeBot.BOTTOM; } diff --git a/chapter03/src/main/java/com/seaofnodes/simple/node/MulNode.java b/chapter03/src/main/java/com/seaofnodes/simple/node/MulNode.java index e1a26858..0fa54966 100644 --- a/chapter03/src/main/java/com/seaofnodes/simple/node/MulNode.java +++ b/chapter03/src/main/java/com/seaofnodes/simple/node/MulNode.java @@ -5,25 +5,25 @@ import com.seaofnodes.simple.type.TypeBot; import com.seaofnodes.simple.type.TypeInteger; public class MulNode extends Node { - public MulNode(Node lhs, Node rhs) { - super(null, lhs, rhs); - } - - @Override - public String label() { return "Mul"; } + public MulNode(Node lhs, Node rhs) { super(null, lhs, rhs); } + + @Override public String label() { return "Mul"; } + @Override public String glabel() { return "*"; } + @Override - StringBuilder _print(StringBuilder sb) { - in(1)._print(sb.append("(")); - in(2)._print(sb.append("*")); + StringBuilder _print1(StringBuilder sb) { + in(1)._print0(sb.append("(")); + in(2)._print0(sb.append("*")); return sb.append(")"); } - + @Override public Type compute() { if (in(1)._type instanceof TypeInteger i0 && - in(2)._type instanceof TypeInteger i1) - return new TypeInteger(i0._con * i1._con); + in(2)._type instanceof TypeInteger i1) { + return TypeInteger.constant(i0.value()*i1.value()); + } return TypeBot.BOTTOM; } diff --git a/chapter03/src/main/java/com/seaofnodes/simple/node/Node.java b/chapter03/src/main/java/com/seaofnodes/simple/node/Node.java index 9c71c424..a778687d 100644 --- a/chapter03/src/main/java/com/seaofnodes/simple/node/Node.java +++ b/chapter03/src/main/java/com/seaofnodes/simple/node/Node.java @@ -2,8 +2,7 @@ package com.seaofnodes.simple.node; import com.seaofnodes.simple.type.Type; -import java.util.ArrayList; -import java.util.Collections; +import java.util.*; /** * All Nodes in the Sea of Nodes IR inherit from the Node class. @@ -24,8 +23,7 @@ public abstract class Node { * <p> * Generally fixed length, ordered, nulls allowed, no unused trailing space. * Ordering is required because e.g. "a/b" is different from "b/a". - * The first input (offset 0) is often a Control node. - * @see Control + * The first input (offset 0) is often a {@link #isCFG} node. */ public final ArrayList<Node> _inputs; @@ -40,6 +38,13 @@ public abstract class Node { */ public final ArrayList<Node> _outputs; + + /** + * Current computed type for this Node. This value changes as the graph + * changes and more knowledge is gained about the program. + */ + public Type _type; + /** * A private Global Static mutable counter, for unique node id generation. * To make the compiler multi-threaded, this field will have to move into a TLS. @@ -47,34 +52,47 @@ public abstract class Node { * */ private static int UNIQUE_ID = 1; - protected Node(Node ...inputs) { + protected Node(Node... inputs) { _nid = UNIQUE_ID++; // allocate unique dense ID _inputs = new ArrayList<>(); Collections.addAll(_inputs,inputs); _outputs = new ArrayList<>(); for( Node n : _inputs ) if( n != null ) - n._outputs.add( this ); - // Do an initial type computation - _type = compute(); + n.addUse( this ); } + // Easy reading label for debugger, e.g. "Add" or "Region" or "EQ" public abstract String label(); + // Unique label for graph visualization, e.g. "Add12" or "Region30" or "EQ99" public String uniqueName() { return label() + _nid; } + // Graphical label, e.g. "+" or "Region" or "==" + public String glabel() { return label(); } + @Override public final String toString() { // TODO: This needs a lot of work - return uniqueName(); + return print(); } // This is a *deep* print. This version will fail on cycles, which we will - // correct later when we can parse programs with loops. + // correct later when we can parse programs with loops. We print with a + // tik-tok style; the common _print0 calls the per-Node _print1, which + // calls back to _print0; public final String print() { - return _print(new StringBuilder()).toString(); + return _print0(new StringBuilder()).toString(); + } + // This is the common print: check for DEAD and print "DEAD" else call the + // per-Node print1. + final StringBuilder _print0(StringBuilder sb) { + return isDead() + ? sb.append(uniqueName()).append(":DEAD") + : _print1(sb); } - abstract StringBuilder _print(StringBuilder sb); + // Every Node implements this. + abstract StringBuilder _print1(StringBuilder sb); /** @@ -86,25 +104,21 @@ public abstract class Node { public int nIns() { return _inputs.size(); } - /** - * Gets the ith output node - * @param i Offset of the output node - * @return Output node (not null) - */ - public Node out(int i) { return _outputs.get(i); } - public int nOuts() { return _outputs.size(); } + public boolean isUnused() { return nOuts() == 0; } + + public boolean isCFG() { return false; } + /** * We allow disabling peephole opt so that we can observe the * full graph, vs the optimized graph. */ public static boolean _disablePeephole = false; - /** * Try to peephole at this node and return a better replacement Node if - * possible. We check and replace: + * possible. We compute a {@link Type} and then check and replace: * <ul> * <li>if the Type {@link Type#isConstant}, we replace with a {@link ConstantNode}</li> * <li>in a future chapter we will look for a @@ -114,19 +128,21 @@ public abstract class Node { * </ul> */ public final Node peephole( ) { + // Compute initial or improved Type + Type type = _type = compute(); + if (_disablePeephole) return this; // Peephole optimizations turned off // Replace constant computations from non-constants with a constant node - Type type = compute(); if (!(this instanceof ConstantNode) && type.isConstant()) { kill(); // Kill `this` because replacing with a Constant - return new ConstantNode(type); + return new ConstantNode(type).peephole(); } // Future chapter: Global Value Numbering goes here - // Ask each node for a replacement + // Ask each node for a better replacement Node n = idealize(); if( n != null ) return n; @@ -134,23 +150,13 @@ public abstract class Node { } /** - * Kill a Node with no <em>uses</em>, by setting all of its <em>defs</em> - * to null. This may recursively kill more Nodes and is basically dead - * code elimination. This function is co-recursive with {@link #set_def}. - */ - public void kill( ) { - assert nOuts()==0; // Has no uses, so it is dead - for( int i=0; i<nIns(); i++ ) - set_def(i,null); // Set all inputs to null, recursively killing unused Nodes - } - - /** * Change a <em>def</em> into a Node. Keeps the edges correct, by removing * the corresponding <em>use->def</em> edge. This may make the original * <em>def</em> go dead. This function is co-recursive with {@link #kill}. * * @param idx which def to set * @param new_def the new definition + * @return this for flow coding */ Node set_def(int idx, Node new_def ) { Node old_def = in(idx); @@ -159,10 +165,10 @@ public abstract class Node { // This needs to happen before removing the old node's def->use edge as // the new_def might get killed if the old node kills it recursively. if( new_def != null ) - new_def._outputs.add(this); + new_def.addUse(this); if( old_def != null && // If the old def exists, remove a def->use edge old_def.delUse(this) ) // If we removed the last use, the old def is now dead - old_def.kill(); // Kill old def + old_def.kill(); // Kill old def // Set the new_def over the old (killed) edge _inputs.set(idx,new_def); // Return self for easy flow-coding @@ -181,11 +187,10 @@ public abstract class Node { _inputs.add(new_def); // If new def is not null, add the corresponding def->use edge if( new_def != null ) - new_def._outputs.add(this); + new_def.addUse(this); return new_def; } - // Breaks the edge invariants, used temporarily private void addUse(Node n) { _outputs.add(n); } @@ -194,10 +199,10 @@ public abstract class Node { // Error is 'use' does not exist; ok for 'use' to be null. private boolean delUse( Node use ) { ArrayList<Node> outs = _outputs; - int lidx = outs.size()-1; // Last index + int lidx = outs.size()-1; // Last index // This 1-line hack compresses an element out of an ArrayList // without having to copy the contents. The last element is - // stuffed over the deleted element, and then the size is reduced. + // stuffed over the deleted element, and then the size is reduced. outs.set(outs.indexOf(use),outs.get(lidx)); outs.remove(lidx); // Reduce ArrayList size without copying anything return lidx==0; @@ -209,17 +214,26 @@ public abstract class Node { for( int i=0; i<n; i++ ) { Node old_def = _inputs.remove(_inputs.size()-1); if( old_def != null && // If it exists and - old_def.delUse(this) ) // If we removed the last use, the old def is now dead + old_def.delUse(this) ) // If we removed the last use, the old def is now dead old_def.kill(); // Kill old def } } /** - * Current computed type for this Node. This value changes as the graph - * changes and more knowledge is gained about the program. + * Kill a Node with no <em>uses</em>, by setting all of its <em>defs</em> + * to null. This may recursively kill more Nodes and is basically dead + * code elimination. This function is co-recursive with {@link #pop_n}. */ - public Type _type; - + public void kill( ) { + assert isUnused(); // Has no uses, so it is dead + pop_n(nIns()); // Set all inputs to null, recursively killing unused Nodes + _type=null; // Flag as dead + assert isDead(); // Really dead now + } + + // Mostly used for asserts and printing. + boolean isDead() { return isUnused() && nIns()==0 && _type==null; } + /** * This function needs to be * <a href="https://en.wikipedia.org/wiki/Monotonic_function">Monotonic</a> @@ -245,9 +259,4 @@ public abstract class Node { * Node unique id generator, and is done as part of making a new Parser. */ public static void reset() { UNIQUE_ID = 1; } - - /* - * hashCode and equals implementation to be added in later chapter. - */ - } diff --git a/chapter03/src/main/java/com/seaofnodes/simple/node/ReturnNode.java b/chapter03/src/main/java/com/seaofnodes/simple/node/ReturnNode.java index c188ca79..18f5eed9 100644 --- a/chapter03/src/main/java/com/seaofnodes/simple/node/ReturnNode.java +++ b/chapter03/src/main/java/com/seaofnodes/simple/node/ReturnNode.java @@ -1,6 +1,6 @@ package com.seaofnodes.simple.node; -import com.seaofnodes.simple.type.TypeBot; +import com.seaofnodes.simple.type.*; /** * The Return node has two inputs. The first input is a control node and the @@ -11,7 +11,7 @@ import com.seaofnodes.simple.type.TypeBot; * <p> * The Return's output is the value from the data node. */ -public class ReturnNode extends Node implements Control { +public class ReturnNode extends Node { public ReturnNode(Node ctrl, Node data) { super(ctrl, data); @@ -24,10 +24,11 @@ public class ReturnNode extends Node implements Control { public String label() { return "Return"; } @Override - StringBuilder _print(StringBuilder sb) { - return expr()._print(sb.append("return ")).append(";"); + StringBuilder _print1(StringBuilder sb) { + return expr()._print0(sb.append("return ")).append(";"); } + @Override public boolean isCFG() { return true; } @Override public TypeBot compute() { diff --git a/chapter03/src/main/java/com/seaofnodes/simple/node/ScopeNode.java b/chapter03/src/main/java/com/seaofnodes/simple/node/ScopeNode.java index c7d6edb9..5f5d66a0 100644 --- a/chapter03/src/main/java/com/seaofnodes/simple/node/ScopeNode.java +++ b/chapter03/src/main/java/com/seaofnodes/simple/node/ScopeNode.java @@ -1,9 +1,9 @@ package com.seaofnodes.simple.node; +import com.seaofnodes.simple.Parser; import com.seaofnodes.simple.type.TypeBot; -import java.util.HashMap; -import java.util.Stack; +import java.util.*; /** * The Scope node is a purely parser helper - it tracks names to nodes with a @@ -17,12 +17,15 @@ public class ScopeNode extends Node { * The top of this stack represents current scope. */ public final Stack<HashMap<String, Integer>> _scopes = new Stack<>(); - - @Override - public String label() { return "Scope"; } - + + // Reverse lookup for nicer graph printing + private final ArrayList<String> _rlabels = new ArrayList<>(); + + @Override public String label() { return "Scope"; } + @Override - StringBuilder _print(StringBuilder sb) { + StringBuilder _print1(StringBuilder sb) { + sb.append(label()); for( HashMap<String,Integer> scope : _scopes ) { sb.append("["); boolean first=true; @@ -32,22 +35,21 @@ public class ScopeNode extends Node { sb.append(name).append(":"); Node n = in(scope.get(name)); if( n==null ) sb.append("null"); - else n._print(sb); + else n._print0(sb); } sb.append("]"); } return sb; } - + @Override public TypeBot compute() { return TypeBot.BOTTOM; } - @Override - public Node idealize() { return null; } + @Override public Node idealize() { return null; } // Add an empty lexical scope - public void push() { - _scopes.push(new HashMap<>()); + public HashMap<String, Integer> push() { + return _scopes.push(new HashMap<>()); } // Remove the current lexical scope, killing all unused nodes. @@ -61,6 +63,7 @@ public class ScopeNode extends Node { HashMap<String,Integer> scope = _scopes.lastElement(); if( scope.put(name,nIns()) != null ) return null; // Double define + _rlabels.add(name); return add_def(n); } @@ -73,7 +76,7 @@ public class ScopeNode extends Node { return null; } - + // If the name is present in any scope, then redefine public Node update(String name, Node n) { for (int i = _scopes.size() - 1; i >= 0; i--) { @@ -85,5 +88,4 @@ public class ScopeNode extends Node { return null; } - } diff --git a/chapter03/src/main/java/com/seaofnodes/simple/node/StartNode.java b/chapter03/src/main/java/com/seaofnodes/simple/node/StartNode.java index 8d8031bb..08b8333a 100644 --- a/chapter03/src/main/java/com/seaofnodes/simple/node/StartNode.java +++ b/chapter03/src/main/java/com/seaofnodes/simple/node/StartNode.java @@ -3,11 +3,13 @@ package com.seaofnodes.simple.node; import com.seaofnodes.simple.type.TypeBot; /** - * The Start node represents the start of the function. For now, we do not have any inputs to Start because our function does not - * yet accept parameters. When we add parameters the value of Start will be a tuple, and will require Projections to extract the values. - * We discuss this in detail in Chapter 9: Functions and Calls. + * The Start node represents the start of the function. For now, we do not + * have any inputs to Start because our function does not yet accept + * parameters. When we add parameters the value of Start will be a tuple, and + * will require Projections to extract the values. We discuss this in detail + * in Chapter 9: Functions and Calls. */ -public class StartNode extends Node implements Control { +public class StartNode extends Node { public StartNode(/*arguments go here*/) { super(); @@ -17,10 +19,12 @@ public class StartNode extends Node implements Control { public String label() { return "Start"; } @Override - StringBuilder _print(StringBuilder sb) { + StringBuilder _print1(StringBuilder sb) { return sb.append(label()); } - + + @Override public boolean isCFG() { return true; } + @Override public TypeBot compute() { return TypeBot.BOTTOM; diff --git a/chapter03/src/main/java/com/seaofnodes/simple/node/SubNode.java b/chapter03/src/main/java/com/seaofnodes/simple/node/SubNode.java index 2d7db8d3..71d70fa6 100644 --- a/chapter03/src/main/java/com/seaofnodes/simple/node/SubNode.java +++ b/chapter03/src/main/java/com/seaofnodes/simple/node/SubNode.java @@ -5,25 +5,25 @@ import com.seaofnodes.simple.type.TypeBot; import com.seaofnodes.simple.type.TypeInteger; public class SubNode extends Node { - public SubNode(Node lhs, Node rhs) { - super(null, lhs, rhs); - } + public SubNode(Node lhs, Node rhs) { super(null, lhs, rhs); } - @Override - public String label() { return "Sub"; } + @Override public String label() { return "Sub"; } + + @Override public String glabel() { return "-"; } @Override - StringBuilder _print(StringBuilder sb) { - in(1)._print(sb.append("(")); - in(2)._print(sb.append("-")); + StringBuilder _print1(StringBuilder sb) { + in(1)._print0(sb.append("(")); + in(2)._print0(sb.append("-")); return sb.append(")"); } @Override public Type compute() { if (in(1)._type instanceof TypeInteger i0 && - in(2)._type instanceof TypeInteger i1) - return new TypeInteger(i0._con - i1._con); + in(2)._type instanceof TypeInteger i1) { + return TypeInteger.constant(i0.value()-i1.value()); + } return TypeBot.BOTTOM; } diff --git a/chapter03/src/main/java/com/seaofnodes/simple/type/TypeBot.java b/chapter03/src/main/java/com/seaofnodes/simple/type/TypeBot.java index 5284884a..bc191241 100644 --- a/chapter03/src/main/java/com/seaofnodes/simple/type/TypeBot.java +++ b/chapter03/src/main/java/com/seaofnodes/simple/type/TypeBot.java @@ -8,7 +8,7 @@ public class TypeBot extends Type { @Override public String toString() { return "Bottom"; } - - @Override + + @Override public StringBuilder _print(StringBuilder sb) { return sb.append(toString()); } } diff --git a/chapter03/src/main/java/com/seaofnodes/simple/type/TypeInteger.java b/chapter03/src/main/java/com/seaofnodes/simple/type/TypeInteger.java index 06cac15e..ff6e865b 100644 --- a/chapter03/src/main/java/com/seaofnodes/simple/type/TypeInteger.java +++ b/chapter03/src/main/java/com/seaofnodes/simple/type/TypeInteger.java @@ -14,6 +14,8 @@ public class TypeInteger extends Type { public TypeInteger(long con) { _con = con; } + public static TypeInteger constant(long con) { return new TypeInteger(con); } + @Override public String toString() { return _print(new StringBuilder()).toString(); @@ -25,7 +27,7 @@ public class TypeInteger extends Type { @Override public boolean isConstant() { return true; } - public long getConstant() { return _con; } + public long value() { return _con; } @Override public boolean equals( Object o ) { diff --git a/chapter03/src/test/java/com/seaofnodes/simple/Chapter03Test.java b/chapter03/src/test/java/com/seaofnodes/simple/Chapter03Test.java index 21faacac..d86b978f 100644 --- a/chapter03/src/test/java/com/seaofnodes/simple/Chapter03Test.java +++ b/chapter03/src/test/java/com/seaofnodes/simple/Chapter03Test.java @@ -1,16 +1,12 @@ package com.seaofnodes.simple; -import com.seaofnodes.simple.node.ConstantNode; -import com.seaofnodes.simple.node.Node; -import com.seaofnodes.simple.node.ReturnNode; -import com.seaofnodes.simple.node.StartNode; +import com.seaofnodes.simple.node.*; import com.seaofnodes.simple.type.TypeInteger; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; +import static org.junit.Assert.*; public class Chapter03Test { @@ -54,6 +50,15 @@ public class Chapter03Test { assertEquals("return 8;", ret.print()); } + @Test + public void testSelfAssign() { + try { + new Parser("int a=a; return a;").parse(); + fail(); + } catch( RuntimeException e ) { + assertEquals("Undefined name 'a'",e.getMessage()); + } + } @Test public void testChapter2ParseGrammar() { @@ -120,7 +125,7 @@ public class Chapter03Test { Node expr = ret.expr(); if( expr instanceof ConstantNode con ) { assertEquals(start,con.in(0)); - assertEquals(new TypeInteger(1), con._type); + assertEquals(TypeInteger.constant(1), con._type); } else { fail(); } @@ -133,21 +138,27 @@ public class Chapter03Test { StartNode start = Parser.START; for( Node use : start._outputs ) if( use instanceof ConstantNode con ) - assertEquals(new TypeInteger(0),con._type); + assertEquals(TypeInteger.constant(0),con._type); } @Test public void testBad1() { - exceptionRule.expect(RuntimeException.class); - exceptionRule.expectMessage("Syntax error, expected =: "); - new Parser("ret").parse(); + try { + new Parser("ret").parse(); + fail(); + } catch( RuntimeException e ) { + assertEquals("Syntax error, expected =: ",e.getMessage()); + } } @Test public void testBad2() { - exceptionRule.expect(RuntimeException.class); - exceptionRule.expectMessage("Syntax error: integer values cannot start with '0'"); - new Parser("return 0123;").parse(); + try { + new Parser("return 0123;").parse(); + fail(); + } catch( RuntimeException e ) { + assertEquals("Syntax error: integer values cannot start with '0'",e.getMessage()); + } } @Test @@ -158,9 +169,12 @@ public class Chapter03Test { @Test public void testBad4() { - exceptionRule.expect(RuntimeException.class); - exceptionRule.expectMessage("Syntax error, expected ;:"); - new Parser("return 100").parse(); + try { + new Parser("return 100").parse(); + fail(); + } catch( RuntimeException e ) { + assertEquals("Syntax error, expected ;: ",e.getMessage()); + } } @Test @@ -171,8 +185,22 @@ public class Chapter03Test { @Test public void testBad6() { - exceptionRule.expect(RuntimeException.class); - exceptionRule.expectMessage("Syntax error, expected }:"); - new Parser("int a=1; int b=2; int c=0; { int b=3; c=a+b;").parse(); + try { + new Parser("int a=1; int b=2; int c=0; { int b=3; c=a+b;").parse(); + fail(); + } catch( RuntimeException e ) { + assertEquals("Syntax error, expected }: ",e.getMessage()); + } } + + @Test + public void testBad7() { + try { + new Parser("return 1;}").parse(); + fail(); + } catch( RuntimeException e ) { + assertEquals("Syntax error, unexpected }",e.getMessage()); + } + } + } diff --git a/chapter04/README.md b/chapter04/README.md index 2700a6a9..350b08b5 100644 --- a/chapter04/README.md +++ b/chapter04/README.md @@ -15,12 +15,12 @@ Here is the [complete language grammar](docs/04-grammar.md) for this chapter. In this chapter we add some new nodes and revise some existing nodes. Following are revised or new nodes -| Node Name | Type | Description | Inputs | Value | -|-----------|------------------|------------------------------------------------|--------------------------------|-------------------------------------------------------------------------| -| MultiNode | Abstract class | A node that has a tuple result | | A tuple | -| Start | Control | Start of function, now a MultiNode | An input argument named `arg`. | A tuple with a ctrl token and an `arg` data node | -| Proj | ? | Projection nodes extract values from MultiNode | A MultiNode and index | Result is the extracted value from the input MultiNode at offset index | -| Bool | Data | Represents results of a comparison operator | Two data nodes | Result a comparison, represented as integer value where 1=true, 0=false | +| Node Name | Type | Description | Inputs | Value | +|-----------|----------------|------------------------------------------------|-----------------------|----------------------------------------------------------------------------| +| MultiNode | Abstract class | A node that has a tuple result | | A tuple | +| Start | Control | Start of function, now a MultiNode | | A tuple with a ctrl token and an `arg` data node | +| Proj | ? | Projection nodes extract values from MultiNode | A MultiNode and index | Result is the extracted value from the input MultiNode at offset index | +| Bool | Data | Represents results of a comparison operator | Two data nodes | Result is a comparison, represented as integer value where 1=true, 0=false | Below is our list of Nodes from [Chapter 3](../chapter03/README.md): @@ -116,13 +116,18 @@ In previous chapters, we had a hard coded control input edge from Start to Return. In this chapter we no longer have such a hard-wired edge. Instead, we track the current in-scope control node via the name `$ctrl`. This means that when we need to create an edge to the predecessor control node, we simply -lookup this name in the current scope. +look up this name in the current scope. -This introduces the idea that the control flow subgraph is a Petri net model [[1]](#1). +This introduces the idea that the control flow subgraph is a Petri net model.[^1] The control token moves virtually from node to node as execution proceeds. The initial control token is in Start, it then moves via the Proj node to Return. In later chapters we will see how the token moves across branches. +## Note Regarding Visualizations + +From this chapter onwards we omit the edges from Constants to Start node, mainly to reduce +clutter and help draw reader's attention to the more important aspects of the graph. + ## More Peephole Optimizations Now that we have non-constant integer values, we do additional optimizations, rearranging algebraic @@ -246,7 +251,5 @@ The reason this is done is that we know `m` is the new replacement and is alive, but since it is not yet part of the graph up the tree, it has no users yet. By adding a bogus user we prevent it being mistaken for dead and being killed. -## References -<a id="1">[1]</a> -Click, C. (1995). -Combining Analyses, Combining Optimizations, 131. +[^1]: Click, C. (1995). + Combining Analyses, Combining Optimizations, 131. diff --git a/chapter04/docs/04-post-peephole.gv b/chapter04/docs/04-post-peephole.gv index 22f55468..51e176bc 100644 --- a/chapter04/docs/04-post-peephole.gv +++ b/chapter04/docs/04-post-peephole.gv @@ -3,8 +3,10 @@ digraph chapter04 { return 1+arg+2; #showGraph; */ rankdir=BT; + ordering="in"; + concentrate="true"; subgraph cluster_Nodes { - Start1 [ shape=plaintext label=< + Start2 [ shape=plaintext label=< <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4"> <TR><TD BGCOLOR="yellow">Start</TD></TR> <TR><TD> @@ -14,28 +16,28 @@ return 1+arg+2; #showGraph; </TD></TR> </TABLE>> ]; - Con_9 [ label="#3" ]; - Add10 [ label="Add" ]; - Return11 [ shape=box style=filled fillcolor=yellow label="Return" ]; + Con_10 [ label="#3" ]; + Add11 [ label="+" ]; + Return12 [ shape=box style=filled fillcolor=yellow label="Return" ]; } node [shape=plaintext]; - subgraph cluster_0 { - scope0 [label=< + subgraph cluster_Scope1_0 { + Scope1_0 [label=< <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0"> - <TR><TD BGCOLOR="cyan">0</TD><TD PORT="scope0_$ctrl">$ctrl</TD><TD PORT="scope0_arg">arg</TD></TR> + <TR><TD BGCOLOR="cyan">0</TD><TD PORT="Scope1_0_$ctrl">$ctrl</TD><TD PORT="Scope1_0_arg">arg</TD></TR> </TABLE>>]; - subgraph cluster_1 { - scope1 [label=< + subgraph cluster_Scope1_1 { + Scope1_1 [label=< <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0"> <TR><TD BGCOLOR="cyan">1</TD></TR> </TABLE>>]; } } - Add10 -> Start1:p1; - Add10 -> Con_9; - Return11 -> Start1:p0 [color=red]; - Return11 -> Add10; + edge [ fontname=Helvetica, fontsize=8 ]; + Add11 -> Start2:p1[taillabel=1]; + Add11 -> Con_10[taillabel=2]; + Return12 -> Start2:p0[taillabel=0; color=red]; + Return12 -> Add11[taillabel=1]; edge [style=dashed color=cornflowerblue]; - scope0:"scope0_$ctrl" -> Start1:p0; - scope0:"scope0_arg" -> Start1:p1; + Scope1_0:"Scope1_0_arg" -> Start2:p1; }
\ No newline at end of file diff --git a/chapter04/docs/04-post-peephole.svg b/chapter04/docs/04-post-peephole.svg index 5a45722c..550c16ef 100644 --- a/chapter04/docs/04-post-peephole.svg +++ b/chapter04/docs/04-post-peephole.svg @@ -14,16 +14,16 @@ <polygon fill="none" stroke="black" points="8,-8 8,-232 193,-232 193,-8 8,-8"/> </g> <g id="clust2" class="cluster"> -<title>cluster_0</title> +<title>cluster_Scope1_0</title> <polygon fill="none" stroke="black" points="201,-72 201,-140 401,-140 401,-72 201,-72"/> </g> <g id="clust3" class="cluster"> -<title>cluster_1</title> +<title>cluster_Scope1_1</title> <polygon fill="none" stroke="black" points="323,-80 323,-132 393,-132 393,-80 323,-80"/> </g> -<!-- Start1 --> +<!-- Start2 --> <g id="node1" class="node"> -<title>Start1</title> +<title>Start2</title> <polygon fill="yellow" stroke="transparent" points="97,-195 97,-220 178,-220 178,-195 97,-195"/> <polygon fill="none" stroke="black" points="97,-195 97,-220 178,-220 178,-195 97,-195"/> <text text-anchor="start" x="119" y="-203.8" font-family="Times,serif" font-size="14.00">Start</text> @@ -34,51 +34,55 @@ <polygon fill="none" stroke="black" points="142,-169 142,-190 173,-190 173,-169 142,-169"/> <text text-anchor="start" x="145" y="-175.8" font-family="Times,serif" font-size="14.00">arg</text> </g> -<!-- Con_9 --> +<!-- Con_10 --> <g id="node2" class="node"> -<title>Con_9</title> +<title>Con_10</title> <ellipse fill="none" stroke="black" cx="43" cy="-192" rx="27" ry="18"/> <text text-anchor="middle" x="43" y="-188.3" font-family="Times,serif" font-size="14.00">#3</text> </g> -<!-- Add10 --> +<!-- Add11 --> <g id="node3" class="node"> -<title>Add10</title> -<ellipse fill="none" stroke="black" cx="156" cy="-106" rx="28.7" ry="18"/> -<text text-anchor="middle" x="156" y="-102.3" font-family="Times,serif" font-size="14.00">Add</text> +<title>Add11</title> +<ellipse fill="none" stroke="black" cx="158" cy="-106" rx="27" ry="18"/> +<text text-anchor="middle" x="158" y="-102.3" font-family="Times,serif" font-size="14.00">+</text> </g> -<!-- Add10->Start1 --> +<!-- Add11->Start2 --> <g id="edge1" class="edge"> -<title>Add10->Start1:p1</title> -<path fill="none" stroke="black" d="M156.86,-124.09C157.28,-133.54 157.73,-145.77 157.92,-157.68"/> -<polygon fill="black" stroke="black" points="154.42,-158.03 158,-168 161.42,-157.97 154.42,-158.03"/> +<title>Add11->Start2:p1</title> +<path fill="none" stroke="black" d="M158,-124.09C158,-133.55 158,-145.77 158,-157.69"/> +<polygon fill="black" stroke="black" points="154.5,-158 158,-168 161.5,-158 154.5,-158"/> +<text text-anchor="middle" x="155" y="-126.69" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> </g> -<!-- Add10->Con_9 --> +<!-- Add11->Con_10 --> <g id="edge2" class="edge"> -<title>Add10->Con_9</title> -<path fill="none" stroke="black" d="M136.93,-119.61C121.35,-130.08 98.91,-145.53 80,-160 75.7,-163.29 71.22,-166.89 66.91,-170.44"/> -<polygon fill="black" stroke="black" points="64.38,-168 58.96,-177.1 68.87,-173.37 64.38,-168"/> +<title>Add11->Con_10</title> +<path fill="none" stroke="black" d="M139.03,-119.12C123,-129.54 99.59,-145.19 80,-160 75.68,-163.26 71.19,-166.85 66.88,-170.4"/> +<polygon fill="black" stroke="black" points="64.34,-167.96 58.92,-177.06 68.84,-173.32 64.34,-167.96"/> +<text text-anchor="middle" x="136.03" y="-121.72" font-family="Helvetica,sans-Serif" font-size="8.00">2</text> </g> -<!-- Return11 --> +<!-- Return12 --> <g id="node4" class="node"> -<title>Return11</title> -<polygon fill="yellow" stroke="black" points="163,-52 97,-52 97,-16 163,-16 163,-52"/> -<text text-anchor="middle" x="130" y="-30.3" font-family="Times,serif" font-size="14.00">Return</text> +<title>Return12</title> +<polygon fill="yellow" stroke="black" points="165,-52 99,-52 99,-16 165,-16 165,-52"/> +<text text-anchor="middle" x="132" y="-30.3" font-family="Times,serif" font-size="14.00">Return</text> </g> -<!-- Return11->Start1 --> +<!-- Return12->Start2 --> <g id="edge3" class="edge"> -<title>Return11->Start1:p0</title> -<path fill="none" stroke="red" d="M123.24,-52.04C121.12,-58.23 119.05,-65.33 118,-72 113.28,-101.85 115.86,-109.85 118,-140 118.58,-148.23 120.12,-152.3 121.11,-157.68"/> -<polygon fill="red" stroke="red" points="117.66,-158.34 122,-168 124.63,-157.74 117.66,-158.34"/> +<title>Return12->Start2:p0</title> +<path fill="none" stroke="red" d="M126.36,-52.13C124.59,-58.32 122.88,-65.4 122,-72 116.87,-110.66 121.12,-123.21 121.89,-157.66"/> +<polygon fill="red" stroke="red" points="118.39,-158.04 122,-168 125.39,-157.96 118.39,-158.04"/> +<text text-anchor="middle" x="123.36" y="-54.73" font-family="Helvetica,sans-Serif" font-size="8.00">0</text> </g> -<!-- Return11->Add10 --> +<!-- Return12->Add11 --> <g id="edge4" class="edge"> -<title>Return11->Add10</title> -<path fill="none" stroke="black" d="M136.43,-52.3C139.4,-60.3 142.99,-69.98 146.29,-78.85"/> -<polygon fill="black" stroke="black" points="143.06,-80.22 149.83,-88.38 149.63,-77.78 143.06,-80.22"/> +<title>Return12->Add11</title> +<path fill="none" stroke="black" d="M138.43,-52.3C141.4,-60.3 144.99,-69.98 148.29,-78.85"/> +<polygon fill="black" stroke="black" points="145.06,-80.22 151.83,-88.38 151.63,-77.78 145.06,-80.22"/> +<text text-anchor="middle" x="135.43" y="-54.9" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> </g> -<!-- scope0 --> +<!-- Scope1_0 --> <g id="node5" class="node"> -<title>scope0</title> +<title>Scope1_0</title> <polygon fill="cyan" stroke="transparent" points="218,-95 218,-116 234,-116 234,-95 218,-95"/> <polygon fill="none" stroke="black" points="218,-95 218,-116 234,-116 234,-95 218,-95"/> <text text-anchor="start" x="221" y="-101.8" font-family="Times,serif" font-size="14.00">0</text> @@ -87,21 +91,15 @@ <polygon fill="none" stroke="black" points="274,-95 274,-116 305,-116 305,-95 274,-95"/> <text text-anchor="start" x="277" y="-101.8" font-family="Times,serif" font-size="14.00">arg</text> </g> -<!-- scope0->Start1 --> +<!-- Scope1_0->Start2 --> <g id="edge5" class="edge"> -<title>scope0:scope0_$ctrl->Start1:p0</title> -<path fill="none" stroke="cornflowerblue" stroke-dasharray="5,2" d="M254,-117C254,-176.09 137.5,-113.66 123.39,-158.03"/> -<polygon fill="cornflowerblue" stroke="cornflowerblue" points="119.92,-157.61 122,-168 126.85,-158.58 119.92,-157.61"/> -</g> -<!-- scope0->Start1 --> -<g id="edge6" class="edge"> -<title>scope0:scope0_arg->Start1:p1</title> +<title>Scope1_0:Scope1_0_arg->Start2:p1</title> <path fill="none" stroke="cornflowerblue" stroke-dasharray="5,2" d="M290,-117C290,-172.03 239,-178.4 184.25,-178.95"/> <polygon fill="cornflowerblue" stroke="cornflowerblue" points="183.98,-175.45 174,-179 184.02,-182.45 183.98,-175.45"/> </g> -<!-- scope1 --> +<!-- Scope1_1 --> <g id="node6" class="node"> -<title>scope1</title> +<title>Scope1_1</title> <polygon fill="cyan" stroke="transparent" points="350,-95 350,-116 366,-116 366,-95 350,-95"/> <polygon fill="none" stroke="black" points="350,-95 350,-116 366,-116 366,-95 350,-95"/> <text text-anchor="start" x="353" y="-101.8" font-family="Times,serif" font-size="14.00">1</text> diff --git a/chapter04/docs/04-pre-peephole.gv b/chapter04/docs/04-pre-peephole.gv index e8016c87..b6fefc2d 100644 --- a/chapter04/docs/04-pre-peephole.gv +++ b/chapter04/docs/04-pre-peephole.gv @@ -3,8 +3,10 @@ digraph chapter04 { return 1+arg+2; #showGraph; */ rankdir=BT; + ordering="in"; + concentrate="true"; subgraph cluster_Nodes { - Start1 [ shape=plaintext label=< + Start2 [ shape=plaintext label=< <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4"> <TR><TD BGCOLOR="yellow">Start</TD></TR> <TR><TD> @@ -14,32 +16,32 @@ return 1+arg+2; #showGraph; </TD></TR> </TABLE>> ]; - Con_4 [ label="#1" ]; - Con_5 [ label="#2" ]; - Add6 [ label="Add" ]; - Add7 [ label="Add" ]; - Return8 [ shape=box style=filled fillcolor=yellow label="Return" ]; + Con_5 [ label="#1" ]; + Con_6 [ label="#2" ]; + Add7 [ label="+" ]; + Add8 [ label="+" ]; + Return9 [ shape=box style=filled fillcolor=yellow label="Return" ]; } node [shape=plaintext]; - subgraph cluster_0 { - scope0 [label=< + subgraph cluster_Scope1_0 { + Scope1_0 [label=< <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0"> - <TR><TD BGCOLOR="cyan">0</TD><TD PORT="scope0_$ctrl">$ctrl</TD><TD PORT="scope0_arg">arg</TD></TR> + <TR><TD BGCOLOR="cyan">0</TD><TD PORT="Scope1_0_$ctrl">$ctrl</TD><TD PORT="Scope1_0_arg">arg</TD></TR> </TABLE>>]; - subgraph cluster_1 { - scope1 [label=< + subgraph cluster_Scope1_1 { + Scope1_1 [label=< <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0"> <TR><TD BGCOLOR="cyan">1</TD></TR> </TABLE>>]; } } - Add6 -> Start1:p1; - Add6 -> Con_5; - Add7 -> Con_4; - Add7 -> Add6; - Return8 -> Start1:p0 [color=red]; - Return8 -> Add7; + edge [ fontname=Helvetica, fontsize=8 ]; + Add7 -> Start2:p1[taillabel=1]; + Add7 -> Con_6[taillabel=2]; + Add8 -> Con_5[taillabel=1]; + Add8 -> Add7[taillabel=2]; + Return9 -> Start2:p0[taillabel=0; color=red]; + Return9 -> Add8[taillabel=1]; edge [style=dashed color=cornflowerblue]; - scope0:"scope0_$ctrl" -> Start1:p0; - scope0:"scope0_arg" -> Start1:p1; -} + Scope1_0:"Scope1_0_arg" -> Start2:p1; +}
\ No newline at end of file diff --git a/chapter04/docs/04-pre-peephole.svg b/chapter04/docs/04-pre-peephole.svg index b1ab4eee..9ec38d27 100644 --- a/chapter04/docs/04-pre-peephole.svg +++ b/chapter04/docs/04-pre-peephole.svg @@ -14,16 +14,16 @@ <polygon fill="none" stroke="black" points="8,-8 8,-304 193,-304 193,-8 8,-8"/> </g> <g id="clust2" class="cluster"> -<title>cluster_0</title> +<title>cluster_Scope1_0</title> <polygon fill="none" stroke="black" points="201,-144 201,-212 401,-212 401,-144 201,-144"/> </g> <g id="clust3" class="cluster"> -<title>cluster_1</title> +<title>cluster_Scope1_1</title> <polygon fill="none" stroke="black" points="323,-152 323,-204 393,-204 393,-152 323,-152"/> </g> -<!-- Start1 --> +<!-- Start2 --> <g id="node1" class="node"> -<title>Start1</title> +<title>Start2</title> <polygon fill="yellow" stroke="transparent" points="97,-267 97,-292 178,-292 178,-267 97,-267"/> <polygon fill="none" stroke="black" points="97,-267 97,-292 178,-292 178,-267 97,-267"/> <text text-anchor="start" x="119" y="-275.8" font-family="Times,serif" font-size="14.00">Start</text> @@ -34,75 +34,81 @@ <polygon fill="none" stroke="black" points="142,-241 142,-262 173,-262 173,-241 142,-241"/> <text text-anchor="start" x="145" y="-247.8" font-family="Times,serif" font-size="14.00">arg</text> </g> -<!-- Con_4 --> +<!-- Con_5 --> <g id="node2" class="node"> -<title>Con_4</title> -<ellipse fill="none" stroke="black" cx="119" cy="-178" rx="27" ry="18"/> -<text text-anchor="middle" x="119" y="-174.3" font-family="Times,serif" font-size="14.00">#1</text> +<title>Con_5</title> +<ellipse fill="none" stroke="black" cx="115" cy="-178" rx="27" ry="18"/> +<text text-anchor="middle" x="115" y="-174.3" font-family="Times,serif" font-size="14.00">#1</text> </g> -<!-- Con_5 --> +<!-- Con_6 --> <g id="node3" class="node"> -<title>Con_5</title> +<title>Con_6</title> <ellipse fill="none" stroke="black" cx="43" cy="-264" rx="27" ry="18"/> <text text-anchor="middle" x="43" y="-260.3" font-family="Times,serif" font-size="14.00">#2</text> </g> -<!-- Add6 --> +<!-- Add7 --> <g id="node4" class="node"> -<title>Add6</title> -<ellipse fill="none" stroke="black" cx="45" cy="-178" rx="28.7" ry="18"/> -<text text-anchor="middle" x="45" y="-174.3" font-family="Times,serif" font-size="14.00">Add</text> +<title>Add7</title> +<ellipse fill="none" stroke="black" cx="43" cy="-178" rx="27" ry="18"/> +<text text-anchor="middle" x="43" y="-174.3" font-family="Times,serif" font-size="14.00">+</text> </g> -<!-- Add6->Start1 --> +<!-- Add7->Start2 --> <g id="edge1" class="edge"> -<title>Add6->Start1:p1</title> -<path fill="none" stroke="black" d="M59.56,-193.83C66.26,-200.06 74.59,-207 83,-212 110.12,-228.12 148.12,-209.69 156.37,-230.12"/> -<polygon fill="black" stroke="black" points="152.92,-230.7 158,-240 159.83,-229.56 152.92,-230.7"/> +<title>Add7->Start2:p1</title> +<path fill="none" stroke="black" d="M56.63,-193.93C62.95,-200.18 70.86,-207.11 79,-212 107.43,-229.09 147.88,-208.4 156.39,-229.99"/> +<polygon fill="black" stroke="black" points="152.96,-230.68 158,-240 159.87,-229.57 152.96,-230.68"/> +<text text-anchor="middle" x="53.63" y="-196.53" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> </g> -<!-- Add6->Con_5 --> +<!-- Add7->Con_6 --> <g id="edge2" class="edge"> -<title>Add6->Con_5</title> -<path fill="none" stroke="black" d="M44.6,-196C44.33,-207.31 43.97,-222.42 43.66,-235.43"/> -<polygon fill="black" stroke="black" points="40.15,-235.66 43.41,-245.74 47.15,-235.82 40.15,-235.66"/> +<title>Add7->Con_6</title> +<path fill="none" stroke="black" d="M43,-196.4C43,-207.74 43,-222.77 43,-235.68"/> +<polygon fill="black" stroke="black" points="39.5,-235.9 43,-245.9 46.5,-235.9 39.5,-235.9"/> +<text text-anchor="middle" x="40" y="-199" font-family="Helvetica,sans-Serif" font-size="8.00">2</text> </g> -<!-- Add7 --> +<!-- Add8 --> <g id="node5" class="node"> -<title>Add7</title> -<ellipse fill="none" stroke="black" cx="117" cy="-106" rx="28.7" ry="18"/> -<text text-anchor="middle" x="117" y="-102.3" font-family="Times,serif" font-size="14.00">Add</text> +<title>Add8</title> +<ellipse fill="none" stroke="black" cx="115" cy="-106" rx="27" ry="18"/> +<text text-anchor="middle" x="115" y="-102.3" font-family="Times,serif" font-size="14.00">+</text> </g> -<!-- Add7->Con_4 --> +<!-- Add8->Con_5 --> <g id="edge3" class="edge"> -<title>Add7->Con_4</title> -<path fill="none" stroke="black" d="M117.49,-124.3C117.71,-132.02 117.98,-141.29 118.23,-149.89"/> -<polygon fill="black" stroke="black" points="114.73,-150 118.51,-159.9 121.72,-149.8 114.73,-150"/> +<title>Add8->Con_5</title> +<path fill="none" stroke="black" d="M115,-124.3C115,-132.02 115,-141.29 115,-149.89"/> +<polygon fill="black" stroke="black" points="111.5,-149.9 115,-159.9 118.5,-149.9 111.5,-149.9"/> +<text text-anchor="middle" x="112" y="-126.9" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> </g> -<!-- Add7->Add6 --> +<!-- Add8->Add7 --> <g id="edge4" class="edge"> -<title>Add7->Add6</title> -<path fill="none" stroke="black" d="M102.08,-121.5C92.04,-131.27 78.62,-144.31 67.32,-155.3"/> -<polygon fill="black" stroke="black" points="64.63,-153.03 59.9,-162.51 69.51,-158.05 64.63,-153.03"/> +<title>Add8->Add7</title> +<path fill="none" stroke="black" d="M100.43,-121.17C90.25,-131.06 76.48,-144.45 64.97,-155.64"/> +<polygon fill="black" stroke="black" points="62.53,-153.13 57.8,-162.62 67.41,-158.15 62.53,-153.13"/> +<text text-anchor="middle" x="97.43" y="-123.77" font-family="Helvetica,sans-Serif" font-size="8.00">2</text> </g> -<!-- Return8 --> +<!-- Return9 --> <g id="node6" class="node"> -<title>Return8</title> -<polygon fill="yellow" stroke="black" points="167,-52 101,-52 101,-16 167,-16 167,-52"/> -<text text-anchor="middle" x="134" y="-30.3" font-family="Times,serif" font-size="14.00">Return</text> +<title>Return9</title> +<polygon fill="yellow" stroke="black" points="166,-52 100,-52 100,-16 166,-16 166,-52"/> +<text text-anchor="middle" x="133" y="-30.3" font-family="Times,serif" font-size="14.00">Return</text> </g> -<!-- Return8->Start1 --> +<!-- Return9->Start2 --> <g id="edge5" class="edge"> -<title>Return8->Start1:p0</title> -<path fill="none" stroke="red" d="M142.72,-52.17C147.37,-62.31 152.62,-75.56 155,-88 165.33,-142.13 178.15,-161.99 155,-212 148.81,-225.36 132.76,-223.4 125.57,-230.38"/> -<polygon fill="red" stroke="red" points="122.2,-229.41 122,-240 128.76,-231.84 122.2,-229.41"/> +<title>Return9->Start2:p0</title> +<path fill="none" stroke="red" d="M140.48,-52.3C144.47,-62.48 148.97,-75.73 151,-88 159.98,-142.37 172.54,-161.27 151,-212 145.75,-224.37 132.06,-223.86 125.55,-230.39"/> +<polygon fill="red" stroke="red" points="122.18,-229.41 122,-240 128.74,-231.83 122.18,-229.41"/> +<text text-anchor="middle" x="137.48" y="-54.9" font-family="Helvetica,sans-Serif" font-size="8.00">0</text> </g> -<!-- Return8->Add7 --> +<!-- Return9->Add8 --> <g id="edge6" class="edge"> -<title>Return8->Add7</title> -<path fill="none" stroke="black" d="M129.8,-52.3C127.9,-60.1 125.62,-69.49 123.52,-78.17"/> -<polygon fill="black" stroke="black" points="120.11,-77.35 121.15,-87.9 126.92,-79 120.11,-77.35"/> +<title>Return9->Add8</title> +<path fill="none" stroke="black" d="M128.55,-52.3C126.55,-60.1 124.13,-69.49 121.9,-78.17"/> +<polygon fill="black" stroke="black" points="118.5,-77.34 119.4,-87.9 125.28,-79.08 118.5,-77.34"/> +<text text-anchor="middle" x="125.55" y="-54.9" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> </g> -<!-- scope0 --> +<!-- Scope1_0 --> <g id="node7" class="node"> -<title>scope0</title> +<title>Scope1_0</title> <polygon fill="cyan" stroke="transparent" points="218,-167 218,-188 234,-188 234,-167 218,-167"/> <polygon fill="none" stroke="black" points="218,-167 218,-188 234,-188 234,-167 218,-167"/> <text text-anchor="start" x="221" y="-173.8" font-family="Times,serif" font-size="14.00">0</text> @@ -111,21 +117,15 @@ <polygon fill="none" stroke="black" points="274,-167 274,-188 305,-188 305,-167 274,-167"/> <text text-anchor="start" x="277" y="-173.8" font-family="Times,serif" font-size="14.00">arg</text> </g> -<!-- scope0->Start1 --> +<!-- Scope1_0->Start2 --> <g id="edge7" class="edge"> -<title>scope0:scope0_$ctrl->Start1:p0</title> -<path fill="none" stroke="cornflowerblue" stroke-dasharray="5,2" d="M254,-189C254,-248.09 137.5,-185.66 123.39,-230.03"/> -<polygon fill="cornflowerblue" stroke="cornflowerblue" points="119.92,-229.61 122,-240 126.85,-230.58 119.92,-229.61"/> -</g> -<!-- scope0->Start1 --> -<g id="edge8" class="edge"> -<title>scope0:scope0_arg->Start1:p1</title> +<title>Scope1_0:Scope1_0_arg->Start2:p1</title> <path fill="none" stroke="cornflowerblue" stroke-dasharray="5,2" d="M290,-189C290,-244.03 239,-250.4 184.25,-250.95"/> <polygon fill="cornflowerblue" stroke="cornflowerblue" points="183.98,-247.45 174,-251 184.02,-254.45 183.98,-247.45"/> </g> -<!-- scope1 --> +<!-- Scope1_1 --> <g id="node8" class="node"> -<title>scope1</title> +<title>Scope1_1</title> <polygon fill="cyan" stroke="transparent" points="350,-167 350,-188 366,-188 366,-167 350,-167"/> <polygon fill="none" stroke="black" points="350,-167 350,-188 366,-188 366,-167 350,-167"/> <text text-anchor="start" x="353" y="-173.8" font-family="Times,serif" font-size="14.00">1</text> diff --git a/chapter04/src/main/java/com/seaofnodes/simple/GraphVisualizer.java b/chapter04/src/main/java/com/seaofnodes/simple/GraphVisualizer.java index f73bfd3c..f624cbde 100644 --- a/chapter04/src/main/java/com/seaofnodes/simple/GraphVisualizer.java +++ b/chapter04/src/main/java/com/seaofnodes/simple/GraphVisualizer.java @@ -1,7 +1,6 @@ package com.seaofnodes.simple; import com.seaofnodes.simple.node.*; -import com.seaofnodes.simple.type.TypeControl; import java.util.*; @@ -29,6 +28,13 @@ public class GraphVisualizer { // scopes and nodes. If we try to cross subgraph cluster borders while // still making the subgraphs DOT gets confused. sb.append("\trankdir=BT;\n"); // Force Nodes before Scopes + + // Preserve node input order + sb.append("\tordering=\"in\";\n"); + + // Merge multiple edges hitting the same node. Makes common shared + // nodes much prettier to look at. + sb.append("\tconcentrate=\"true\";\n"); // Just the Nodes first, in a cluster no edges nodes(sb, all); @@ -51,10 +57,10 @@ public class GraphVisualizer { // Just the Nodes first, in a cluster no edges sb.append("\tsubgraph cluster_Nodes {\n"); // Magic "cluster_" in the subgraph name for( Node n : all ) { - if( n instanceof ProjNode ) - continue; // Do not emit, rolled into MultiNode already + if( n instanceof ProjNode || n instanceof ScopeNode ) + continue; // Do not emit, rolled into MultiNode or Scope cluster already sb.append("\t\t").append(n.uniqueName()).append(" [ "); - String lab = n.label(); + String lab = n.glabel(); if( n instanceof MultiNode ) { // Make a box with the MultiNode on top, and all the projections on the bottom sb.append("shape=plaintext label=<\n"); @@ -71,8 +77,8 @@ public class GraphVisualizer { sb.append("\t\t\t\t<TR>"); } sb.append("<TD PORT=\"p").append(proj._idx).append("\""); - if( proj._idx==0 ) sb.append(" BGCOLOR=\"yellow\""); - sb.append(">").append(proj.label()).append("</TD>"); + if( proj.isCFG() ) sb.append(" BGCOLOR=\"yellow\""); + sb.append(">").append(proj.glabel()).append("</TD>"); } } if (doProjTable) { @@ -86,7 +92,7 @@ public class GraphVisualizer { } else { // control nodes have box shape // other nodes are ellipses, i.e. default shape - if( n instanceof Control ) + if( n.isCFG() ) sb.append("shape=box style=filled fillcolor=yellow "); sb.append("label=\"").append(lab).append("\" "); } @@ -99,8 +105,8 @@ public class GraphVisualizer { sb.append("\tnode [shape=plaintext];\n"); int level=0; for( HashMap<String,Integer> scope : scopenode._scopes ) { - sb.append("\tsubgraph cluster_").append(level).append(" {\n"); // Magic "cluster_" in the subgraph name - String scopeName = makeScopeName(level); + String scopeName = makeScopeName(scopenode, level); + sb.append("\tsubgraph cluster_").append(scopeName).append(" {\n"); // Magic "cluster_" in the subgraph name sb.append("\t\t").append(scopeName).append(" [label=<\n"); sb.append("\t\t\t<TABLE BORDER=\"0\" CELLBORDER=\"1\" CELLSPACING=\"0\">\n"); // Add the scope level @@ -116,31 +122,38 @@ public class GraphVisualizer { // We close them all at once here. sb.append( "\t}\n".repeat( level ) ); // End all Scope clusters } - - private String makeScopeName(int level) { return "scope" + level; } - private String makePortName(String scopeName, String varName) { return scopeName + "_" + varName; } - private boolean isControlEdge(Node def) { - return def._type instanceof TypeControl; - } + private String makeScopeName(ScopeNode sn, int level) { return sn.uniqueName() + "_" + level; } + private String makePortName(String scopeName, String varName) { return scopeName + "_" + varName; } // Walk the node edges private void nodeEdges(StringBuilder sb, Collection<Node> all) { + // All them edge labels + sb.append("\tedge [ fontname=Helvetica, fontsize=8 ];\n"); for( Node n : all ) { - if( n instanceof ConstantNode || n instanceof ProjNode ) - continue; // Do not display the Constant->Start edge; ProjNodes handled by Multi - for( Node def : n._inputs ) + // Do not display the Constant->Start edge; + // ProjNodes handled by Multi; + // ScopeNodes are done separately + if( n instanceof ConstantNode || n instanceof ProjNode || n instanceof ScopeNode ) + continue; + int i=0; + for( Node def : n._inputs ) { if( def != null ) { + // Most edges land here use->def sb.append('\t').append(n.uniqueName()).append(" -> "); if( def instanceof ProjNode proj ) { String mname = proj.ctrl().uniqueName(); sb.append(mname).append(":p").append(proj._idx); } else sb.append(def.uniqueName()); - // Control edges are colored red - if( isControlEdge(def) ) - sb.append(" [color=red]"); - sb.append(";\n"); + // Number edges, so we can see how they track + sb.append("[taillabel=").append(i); + // control edges are colored red + if( def.isCFG() ) + sb.append(" color=red"); + sb.append("];\n"); } + i++; + } } } @@ -149,7 +162,7 @@ public class GraphVisualizer { sb.append("\tedge [style=dashed color=cornflowerblue];\n"); int level=0; for( HashMap<String,Integer> scope : scopenode._scopes ) { - String scopeName = makeScopeName(level); + String scopeName = makeScopeName(scopenode, level); for( String name : scope.keySet() ) { Node def = scopenode.in(scope.get(name)); if( def==null ) continue; diff --git a/chapter04/src/main/java/com/seaofnodes/simple/Parser.java b/chapter04/src/main/java/com/seaofnodes/simple/Parser.java index 275a4ebd..b505c2c5 100644 --- a/chapter04/src/main/java/com/seaofnodes/simple/Parser.java +++ b/chapter04/src/main/java/com/seaofnodes/simple/Parser.java @@ -15,6 +15,12 @@ import java.util.*; public class Parser { /** + * The control is a name that binds to the currently active control + * node in the graph + */ + public static final String CTRL = "$ctrl"; + + /** * A Global Static, unique to each compilation. This is a public, so we * can make constants everywhere without having to thread the StartNode * through the entire parser and optimizer. @@ -23,6 +29,7 @@ public class Parser { */ public static StartNode START; + // The Lexer. Thin wrapper over a byte[] buffer with a cursor. private final Lexer _lexer; /** @@ -31,10 +38,19 @@ public class Parser { */ public ScopeNode _scope; + /** + * List of keywords disallowed as identifiers + */ + private final HashSet<String> KEYWORDS = new HashSet<>(){{ + add("int"); + add("return"); + }}; + + public Parser(String source, TypeInteger arg) { _lexer = new Lexer(source); - _scope = new ScopeNode(); Node.reset(); + _scope = new ScopeNode(); START = new StartNode(new Type[]{ Type.CONTROL, arg }); START.peephole(); } @@ -45,17 +61,23 @@ public class Parser { String src() { return new String( _lexer._input ); } + private Node ctrl() { return _scope.ctrl(); } + private Node ctrl(Node n) { return _scope.ctrl(n); } - public ReturnNode parse() { + public ReturnNode parse() { return parse(false); } + public ReturnNode parse(boolean show) { _scope.push(); try { - _scope.define("$ctrl", new ProjNode(START, 0, "$ctrl").peephole()); - _scope.define("arg" , new ProjNode(START, 1, "arg" ).peephole()); - return (ReturnNode) parseBlock(false); + _scope.define(CTRL , new ProjNode(START, 0, CTRL ).peephole()); + _scope.define("arg", new ProjNode(START, 1, "arg").peephole()); + var ret = (ReturnNode) parseBlock(); + if (!_lexer.isEOF()) throw error("Syntax error, unexpected " + _lexer.getAnyNextToken()); + return ret; } finally { _scope.pop(); + if( show ) showGraph(); } } @@ -65,23 +87,17 @@ public class Parser { * <pre> * '{' statements '}' * </pre> + * Does not parse the opening or closing '{}' + * @return a {@link Node} or {@code null} */ - private Node parseBlock(boolean requireClosingBracket) { + private Node parseBlock() { // Enter a new scope _scope.push(); Node n = null; - do { - if (match("}")) { - if (requireClosingBracket) break; - else throw error("unexpected '}' token"); - } else if (_lexer.isEOF()) { - if (requireClosingBracket) require("}"); - else break; - } - + while (!peek('}') && !_lexer.isEOF()) { Node n0 = parseStatement(); if (n0 != null) n = n0; // Allow null returns from eg showGraph - } while (true); + }; // Exit scope _scope.pop(); return n; @@ -93,12 +109,13 @@ public class Parser { * <pre> * returnStatement | declStatement | blockStatement | expressionStatement * </pre> + * @return a {@link Node} or {@code null} */ private Node parseStatement() { - if (match("return")) return parseReturn(); - else if (match("int")) return parseDecl(); - else if (match("{")) return parseBlock(true); - else if (match("#showGraph")) return showGraph(); + if (matchx("return") ) return parseReturn(); + else if (matchx("int")) return parseDecl(); + else if (match ("{" )) return require(parseBlock(),"}"); + else if (matchx("#showGraph")) return require(showGraph(),";"); else return parseExpressionStatement(); } @@ -109,19 +126,20 @@ public class Parser { * <pre> * 'return' expr ; * </pre> + * @return an expression {@link Node}, never {@code null} */ private Node parseReturn() { var expr = require(parseExpression(), ";"); - Node ret = new ReturnNode(_scope.lookup("$ctrl"), expr); - _scope.update("$ctrl",null); + Node ret = new ReturnNode(ctrl(), expr).peephole(); + ctrl(null); // Kill control return ret; } /** * Dumps out the node graph + * @return {@code null} */ private Node showGraph() { - require(";"); System.out.println(new GraphVisualizer().generateDotOutput(this)); return null; } @@ -132,6 +150,7 @@ public class Parser { * <pre> * name '=' expression ';' * </pre> + * @return an expression {@link Node}, never {@code null} */ private Node parseExpressionStatement() { var name = requireId(); @@ -148,6 +167,7 @@ public class Parser { * <pre> * 'int' name = expression ';' * </pre> + * @return an expression {@link Node}, never {@code null} */ private Node parseDecl() { // Type is 'int' for now @@ -163,11 +183,20 @@ public class Parser { * Parse an expression of the form: * * <pre> - * expr : additiveExpr + * expr : compareExpr * </pre> + * @return an expression {@link Node}, never {@code null} */ private Node parseExpression() { return parseComparison(); } + /** + * Parse an expression of the form: + * + * <pre> + * expr : additiveExpr op additiveExpr + * </pre> + * @return an comparator expression {@link Node}, never {@code null} + */ private Node parseComparison() { var lhs = parseAddition(); if (match("==")) return new BoolNode.EQNode(lhs, parseComparison()).peephole(); @@ -185,6 +214,7 @@ public class Parser { * <pre> * additiveExpr : multiplicativeExpr (('+' | '-') multiplicativeExpr)* * </pre> + * @return an add expression {@link Node}, never {@code null} */ private Node parseAddition() { var lhs = parseMultiplication(); @@ -199,6 +229,7 @@ public class Parser { * <pre> * multiplicativeExpr : unaryExpr (('*' | '/') unaryExpr)* * </pre> + * @return a multiply expression {@link Node}, never {@code null} */ private Node parseMultiplication() { var lhs = parseUnary(); @@ -213,6 +244,7 @@ public class Parser { * <pre> * unaryExpr : ('-') unaryExpr | primaryExpr * </pre> + * @return a unary expression {@link Node}, never {@code null} */ private Node parseUnary() { if (match("-")) return new MinusNode(parseUnary()).peephole(); @@ -225,15 +257,16 @@ public class Parser { * <pre> * primaryExpr : integerLiteral | Identifier | '(' expression ')' * </pre> + * @return a primary {@link Node}, never {@code null} */ private Node parsePrimary() { - if (_lexer.isNumber()) return parseIntegerLiteral(); - if (match("(")) return require(parseExpression(), ")"); - String name = requireId(); - Node id = _scope.lookup(name); - if( id==null ) - throw error("Undefined name '" + name + "'"); - return id.peephole(); + if( _lexer.isNumber() ) return parseIntegerLiteral(); + if( match("(") ) return require(parseExpression(), ")"); + String name = _lexer.matchId(); + if( name == null) throw errorSyntax("an identifier or expression"); + Node n = _scope.lookup(name); + if( n!=null ) return n; + throw error("Undefined name '" + name + "'"); } /** @@ -251,13 +284,17 @@ public class Parser { // Utilities for lexical analysis // Return true and skip if "syntax" is next in the stream. - private boolean match(String syntax) { return _lexer.match(syntax); } + private boolean match (String syntax) { return _lexer.match (syntax); } + // Match must be "exact", not be followed by more id letters + private boolean matchx(String syntax) { return _lexer.matchx(syntax); } + // Return true and do NOT skip if 'ch' is next + private boolean peek(char ch) { return _lexer.peek(ch); } // Require and return an identifier private String requireId() { String id = _lexer.matchId(); - if (id != null) return id; - throw error("identifier"); + if (id != null && !KEYWORDS.contains(id) ) return id; + throw error("Expected an identifier, found '"+id+"'"); } // Require an exact match @@ -343,11 +380,24 @@ public class Parser { int len = syntax.length(); if (_position + len > _input.length) return false; for (int i = 0; i < len; i++) - if ((char) _input[_position + i] != syntax.charAt(i)) return false; + if ((char) _input[_position + i] != syntax.charAt(i)) + return false; _position += len; return true; } + boolean matchx(String syntax) { + if( !match(syntax) ) return false; + if( !isIdLetter(peek()) ) return true; + _position -= syntax.length(); + return false; + } + + private boolean peek(char ch) { + skipWhiteSpace(); + return peek()==ch; + } + // Return an identifier or null String matchId() { skipWhiteSpace(); @@ -397,8 +447,7 @@ public class Parser { private String parsePunctuation() { int start = _position; - if (isPunctuation(nextChar())) ; - return new String(_input, start, --_position - start); + return new String(_input, start, 1); } } diff --git a/chapter04/src/main/java/com/seaofnodes/simple/node/AddNode.java b/chapter04/src/main/java/com/seaofnodes/simple/node/AddNode.java index 8b157a9c..d4d15bef 100644 --- a/chapter04/src/main/java/com/seaofnodes/simple/node/AddNode.java +++ b/chapter04/src/main/java/com/seaofnodes/simple/node/AddNode.java @@ -3,12 +3,11 @@ package com.seaofnodes.simple.node; import com.seaofnodes.simple.type.*; public class AddNode extends Node { - public AddNode(Node lhs, Node rhs) { - super(null, lhs, rhs); - } + public AddNode(Node lhs, Node rhs) { super(null, lhs, rhs); } - @Override - public String label() { return "Add"; } + @Override public String label() { return "Add"; } + + @Override public String glabel() { return "+"; } @Override StringBuilder _print1(StringBuilder sb) { @@ -36,37 +35,64 @@ public class AddNode extends Node { Type t1 = lhs._type; Type t2 = rhs._type; + // Already handled by peephole constant folding + assert !(t1.isConstant() && t2.isConstant()); + // Add of 0. We do not check for (0+x) because this will already // canonicalize to (x+0) - if ( t2.isConstant() && t2 instanceof TypeInteger i && i.value()==0 ) + if( t2 instanceof TypeInteger i && i.value()==0 ) return lhs; - - // Move constants to RHS: con+arg becomes arg+con - if ( t1.isConstant() && !t2.isConstant() ) { - Node tmp = in(1); // Swap inputs without letting either input go dead during the swap - _inputs.set(1,in(2)); - _inputs.set(2,tmp); - return this; - } - + + // Add of same to a multiply by 2 + if( lhs==rhs ) + return new MulNode(lhs,new ConstantNode(TypeInteger.constant(2)).peephole()); + // Goal: a left-spine set of adds, with constants on the rhs (which then fold). - // Do we have (x + con1) + con2 ? - // Rotate to x +(con1 + con2) - // The constants will fold on the next peephole. - if (t2.isConstant() && lhs instanceof AddNode && lhs.in(2)._type.isConstant() ) - return new AddNode(lhs.in(1),new AddNode(lhs.in(2),rhs).peephole()); + // Move non-adds to RHS + if( !(lhs instanceof AddNode) && rhs instanceof AddNode ) + return swap12(); - // Do we have x + (y + con) ? - // Swap to (x + y) + con - if (rhs instanceof AddNode add && add.in(2)._type.isConstant() ) - return new AddNode(new AddNode(lhs,add.in(1)).peephole(), add.in(2)); + // Now we might see (add add non) or (add non non) or (add add add) but never (add non add) - // Add of same to a multiply by 2 - if( lhs==rhs ) - return new MulNode(lhs,new ConstantNode(TypeInteger.constant(2)).peephole()); + // Do we have x + (y + z) ? + // Swap to (x + y) + z + // Rotate (add add add) to remove the add on RHS + if( rhs instanceof AddNode add ) + return new AddNode(new AddNode(lhs,add.in(1)).peephole(), add.in(2)); + + // Now we might see (add add non) or (add non non) but never (add non add) nor (add add add) + if( !(lhs instanceof AddNode) ) + return spline_cmp(lhs,rhs) ? swap12() : null; + + // Now we only see (add add non) + + // Do we have (x + con1) + con2? + // Replace with (x + (con1+con2) which then fold the constants + if( lhs.in(2)._type.isConstant() && t2.isConstant() ) + return new AddNode(lhs.in(1),new AddNode(lhs.in(2),rhs).peephole()); + + // Now we sort along the spline via rotates, to gather similar things together. + + // Do we rotate (x + y) + z + // into (x + z) + y ? + if( spline_cmp(lhs.in(2),rhs) ) + return new AddNode(new AddNode(lhs.in(1),rhs).peephole(),lhs.in(2)); return null; } + + // Compare two off-spline nodes and decide what order they should be in. + // Do we rotate ((x + hi) + lo) into ((x + lo) + hi) ? + // Generally constants always go right, then others. + // Ties with in a category sort by node ID. + // TRUE if swapping hi and lo. + static boolean spline_cmp( Node hi, Node lo ) { + if( lo._type.isConstant() ) return false; + if( hi._type.isConstant() ) return true ; + + // Same category of "others" + return lo._nid > hi._nid; + } } diff --git a/chapter04/src/main/java/com/seaofnodes/simple/node/BoolNode.java b/chapter04/src/main/java/com/seaofnodes/simple/node/BoolNode.java index b0e0bf42..02eb7ce9 100644 --- a/chapter04/src/main/java/com/seaofnodes/simple/node/BoolNode.java +++ b/chapter04/src/main/java/com/seaofnodes/simple/node/BoolNode.java @@ -13,7 +13,10 @@ abstract public class BoolNode extends Node { abstract String op(); // String opcode name @Override - public String label() { return op(); } + public String label() { return getClass().getSimpleName(); } + + @Override + public String glabel() { return op(); } @Override StringBuilder _print1(StringBuilder sb) { diff --git a/chapter04/src/main/java/com/seaofnodes/simple/node/Control.java b/chapter04/src/main/java/com/seaofnodes/simple/node/Control.java deleted file mode 100644 index 48cf2b7a..00000000 --- a/chapter04/src/main/java/com/seaofnodes/simple/node/Control.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.seaofnodes.simple.node; - - -/** - * Control interface is a marker interface to be implemented - * by Control nodes. - */ -public interface Control { -} diff --git a/chapter04/src/main/java/com/seaofnodes/simple/node/DivNode.java b/chapter04/src/main/java/com/seaofnodes/simple/node/DivNode.java index 1f562378..ae87deac 100644 --- a/chapter04/src/main/java/com/seaofnodes/simple/node/DivNode.java +++ b/chapter04/src/main/java/com/seaofnodes/simple/node/DivNode.java @@ -5,13 +5,12 @@ import com.seaofnodes.simple.type.TypeBot; import com.seaofnodes.simple.type.TypeInteger; public class DivNode extends Node { - public DivNode(Node lhs, Node rhs) { - super(null, lhs, rhs); - } + public DivNode(Node lhs, Node rhs) { super(null, lhs, rhs); } + + @Override public String label() { return "Div"; } + + @Override public String glabel() { return "//"; } - @Override - public String label() { return "Div"; } - @Override StringBuilder _print1(StringBuilder sb) { in(1)._print0(sb.append("(")); diff --git a/chapter04/src/main/java/com/seaofnodes/simple/node/MinusNode.java b/chapter04/src/main/java/com/seaofnodes/simple/node/MinusNode.java index 04084d0f..533155d9 100644 --- a/chapter04/src/main/java/com/seaofnodes/simple/node/MinusNode.java +++ b/chapter04/src/main/java/com/seaofnodes/simple/node/MinusNode.java @@ -5,12 +5,11 @@ import com.seaofnodes.simple.type.TypeBot; import com.seaofnodes.simple.type.TypeInteger; public class MinusNode extends Node { - public MinusNode(Node in) { - super(null, in); - } + public MinusNode(Node in) { super(null, in); } - @Override - public String label() { return "Minus"; } + @Override public String label() { return "Minus"; } + + @Override public String glabel() { return "-"; } @Override StringBuilder _print1(StringBuilder sb) { @@ -21,7 +20,7 @@ public class MinusNode extends Node { @Override public Type compute() { if (in(1)._type instanceof TypeInteger i0) - return TypeInteger.constant(-i0.value()); + return i0.isConstant() ? TypeInteger.constant(-i0.value()) : i0; return TypeBot.BOTTOM; } diff --git a/chapter04/src/main/java/com/seaofnodes/simple/node/MulNode.java b/chapter04/src/main/java/com/seaofnodes/simple/node/MulNode.java index e3e83b38..5f6c1ad8 100644 --- a/chapter04/src/main/java/com/seaofnodes/simple/node/MulNode.java +++ b/chapter04/src/main/java/com/seaofnodes/simple/node/MulNode.java @@ -5,12 +5,11 @@ import com.seaofnodes.simple.type.TypeBot; import com.seaofnodes.simple.type.TypeInteger; public class MulNode extends Node { - public MulNode(Node lhs, Node rhs) { - super(null, lhs, rhs); - } + public MulNode(Node lhs, Node rhs) { super(null, lhs, rhs); } - @Override - public String label() { return "Mul"; } + @Override public String label() { return "Mul"; } + + @Override public String glabel() { return "*"; } @Override StringBuilder _print1(StringBuilder sb) { @@ -43,12 +42,8 @@ public class MulNode extends Node { return lhs; // Move constants to RHS: con*arg becomes arg*con - if ( t1.isConstant() && !t2.isConstant() ) { - Node tmp = in(1); // Swap inputs without letting either input go dead during the swap - _inputs.set(1,in(2)); - _inputs.set(2,tmp); - return this; - } + if ( t1.isConstant() && !t2.isConstant() ) + return swap12(); return null; } diff --git a/chapter04/src/main/java/com/seaofnodes/simple/node/MultiNode.java b/chapter04/src/main/java/com/seaofnodes/simple/node/MultiNode.java index e517c3d5..fe3fddf8 100644 --- a/chapter04/src/main/java/com/seaofnodes/simple/node/MultiNode.java +++ b/chapter04/src/main/java/com/seaofnodes/simple/node/MultiNode.java @@ -4,10 +4,6 @@ import com.seaofnodes.simple.type.Type; public abstract class MultiNode extends Node { - public MultiNode(Node... inputs) { - super(inputs); - } - - // Return the ProjNode with the idx - abstract ProjNode proj(int idx); + public MultiNode(Node... inputs) { super(inputs); } + } diff --git a/chapter04/src/main/java/com/seaofnodes/simple/node/Node.java b/chapter04/src/main/java/com/seaofnodes/simple/node/Node.java index 7cc9291c..804d30e0 100644 --- a/chapter04/src/main/java/com/seaofnodes/simple/node/Node.java +++ b/chapter04/src/main/java/com/seaofnodes/simple/node/Node.java @@ -2,8 +2,7 @@ package com.seaofnodes.simple.node; import com.seaofnodes.simple.type.Type; -import java.util.ArrayList; -import java.util.Collections; +import java.util.*; /** * All Nodes in the Sea of Nodes IR inherit from the Node class. @@ -24,8 +23,7 @@ public abstract class Node { * <p> * Generally fixed length, ordered, nulls allowed, no unused trailing space. * Ordering is required because e.g. "a/b" is different from "b/a". - * The first input (offset 0) is often a Control node. - * @see Control + * The first input (offset 0) is often a {@link #isCFG} node. */ public final ArrayList<Node> _inputs; @@ -61,13 +59,18 @@ public abstract class Node { _outputs = new ArrayList<>(); for( Node n : _inputs ) if( n != null ) - n._outputs.add( this ); + n.addUse( this ); } + // Easy reading label for debugger, e.g. "Add" or "Region" or "EQ" public abstract String label(); + // Unique label for graph visualization, e.g. "Add12" or "Region30" or "EQ99" public String uniqueName() { return label() + _nid; } + // Graphical label, e.g. "+" or "Region" or "==" + public String glabel() { return label(); } + @Override public final String toString() { // TODO: This needs a lot of work @@ -101,24 +104,18 @@ public abstract class Node { public int nIns() { return _inputs.size(); } - /** - * Gets the ith output node - * @param i Offset of the output node - * @return Output node (not null) - */ - public Node out(int i) { return _outputs.get(i); } - public int nOuts() { return _outputs.size(); } public boolean isUnused() { return nOuts() == 0; } + public boolean isCFG() { return false; } + /** * We allow disabling peephole opt so that we can observe the * full graph, vs the optimized graph. */ public static boolean _disablePeephole = false; - /** * Try to peephole at this node and return a better replacement Node if * possible. We compute a {@link Type} and then check and replace: @@ -197,7 +194,7 @@ public abstract class Node { // This needs to happen before removing the old node's def->use edge as // the new_def might get killed if the old node kills it recursively. if( new_def != null ) - new_def._outputs.add(this); + new_def.addUse(this); if( old_def != null && // If the old def exists, remove a def->use edge old_def.delUse(this) ) // If we removed the last use, the old def is now dead old_def.kill(); // Kill old def @@ -219,11 +216,10 @@ public abstract class Node { _inputs.add(new_def); // If new def is not null, add the corresponding def->use edge if( new_def != null ) - new_def._outputs.add(this); + new_def.addUse(this); return new_def; } - // Breaks the edge invariants, used temporarily private void addUse(Node n) { _outputs.add(n); } @@ -266,7 +262,7 @@ public abstract class Node { // Mostly used for asserts and printing. boolean isDead() { return isUnused() && nIns()==0 && _type==null; } - + /** * This function needs to be * <a href="https://en.wikipedia.org/wiki/Monotonic_function">Monotonic</a> @@ -332,14 +328,21 @@ public abstract class Node { */ public abstract Node idealize(); + + // ----------------------- + // Peephole utilities + + // Swap inputs without letting either input go dead during the swap. + Node swap12() { + Node tmp = in(1); + _inputs.set(1,in(2)); + _inputs.set(2,tmp); + return this; + } + /** * Used to allow repeating tests in the same JVM. This just resets the * Node unique id generator, and is done as part of making a new Parser. */ public static void reset() { UNIQUE_ID = 1; } - - /* - * hashCode and equals implementation to be added in later chapter. - */ - } diff --git a/chapter04/src/main/java/com/seaofnodes/simple/node/ProjNode.java b/chapter04/src/main/java/com/seaofnodes/simple/node/ProjNode.java index be37c514..be0556ed 100644 --- a/chapter04/src/main/java/com/seaofnodes/simple/node/ProjNode.java +++ b/chapter04/src/main/java/com/seaofnodes/simple/node/ProjNode.java @@ -22,7 +22,9 @@ public class ProjNode extends Node { public String label() { return _label; } @Override - StringBuilder _print1(StringBuilder sb) { return sb.append("Proj_" +_nid); } + StringBuilder _print1(StringBuilder sb) { return sb.append(_label); } + + @Override public boolean isCFG() { return _idx==0; } public MultiNode ctrl() { return (MultiNode)in(0); } diff --git a/chapter04/src/main/java/com/seaofnodes/simple/node/ReturnNode.java b/chapter04/src/main/java/com/seaofnodes/simple/node/ReturnNode.java index c94115bb..e20d01e5 100644 --- a/chapter04/src/main/java/com/seaofnodes/simple/node/ReturnNode.java +++ b/chapter04/src/main/java/com/seaofnodes/simple/node/ReturnNode.java @@ -1,7 +1,6 @@ package com.seaofnodes.simple.node; -import com.seaofnodes.simple.type.Type; -import com.seaofnodes.simple.type.TypeBot; +import com.seaofnodes.simple.type.*; /** * The Return node has two inputs. The first input is a control node and the @@ -12,7 +11,7 @@ import com.seaofnodes.simple.type.TypeBot; * <p> * The Return's output is the value from the data node. */ -public class ReturnNode extends Node implements Control { +public class ReturnNode extends Node { public ReturnNode(Node ctrl, Node data) { super(ctrl, data); @@ -29,10 +28,11 @@ public class ReturnNode extends Node implements Control { return expr()._print0(sb.append("return ")).append(";"); } + @Override public boolean isCFG() { return true; } @Override public Type compute() { - return expr().compute(); + return new TypeTuple(TypeControl.CONTROL,expr()._type); } @Override diff --git a/chapter04/src/main/java/com/seaofnodes/simple/node/ScopeNode.java b/chapter04/src/main/java/com/seaofnodes/simple/node/ScopeNode.java index 8bd81e82..45966791 100644 --- a/chapter04/src/main/java/com/seaofnodes/simple/node/ScopeNode.java +++ b/chapter04/src/main/java/com/seaofnodes/simple/node/ScopeNode.java @@ -1,5 +1,6 @@ package com.seaofnodes.simple.node; +import com.seaofnodes.simple.Parser; import com.seaofnodes.simple.type.TypeBot; import java.util.*; @@ -16,12 +17,15 @@ public class ScopeNode extends Node { * The top of this stack represents current scope. */ public final Stack<HashMap<String, Integer>> _scopes = new Stack<>(); - - @Override - public String label() { return "Scope"; } + + // Reverse lookup for nicer graph printing + private final ArrayList<String> _rlabels = new ArrayList<>(); + + @Override public String label() { return "Scope"; } @Override StringBuilder _print1(StringBuilder sb) { + sb.append(label()); for( HashMap<String,Integer> scope : _scopes ) { sb.append("["); boolean first=true; @@ -41,12 +45,11 @@ public class ScopeNode extends Node { @Override public TypeBot compute() { return TypeBot.BOTTOM; } - @Override - public Node idealize() { return null; } + @Override public Node idealize() { return null; } // Add an empty lexical scope - public void push() { - _scopes.push(new HashMap<>()); + public HashMap<String, Integer> push() { + return _scopes.push(new HashMap<>()); } // Remove the current lexical scope, killing all unused nodes. @@ -60,6 +63,7 @@ public class ScopeNode extends Node { HashMap<String,Integer> scope = _scopes.lastElement(); if( scope.put(name,nIns()) != null ) return null; // Double define + _rlabels.add(name); return add_def(n); } @@ -72,7 +76,15 @@ public class ScopeNode extends Node { return null; } + public Node ctrl() { assert lookup(Parser.CTRL)==in(0); return in(0); } + + public Node ctrl(Node n) { + assert lookup(Parser.CTRL)==in(0); + set_def(0,n); + return n; + } + // If the name is present in any scope, then redefine public Node update(String name, Node n) { for (int i = _scopes.size() - 1; i >= 0; i--) { @@ -84,5 +96,4 @@ public class ScopeNode extends Node { return null; } - } diff --git a/chapter04/src/main/java/com/seaofnodes/simple/node/StartNode.java b/chapter04/src/main/java/com/seaofnodes/simple/node/StartNode.java index b59e3375..91573de8 100644 --- a/chapter04/src/main/java/com/seaofnodes/simple/node/StartNode.java +++ b/chapter04/src/main/java/com/seaofnodes/simple/node/StartNode.java @@ -11,7 +11,7 @@ import com.seaofnodes.simple.type.TypeTuple; * will require Projections to extract the values. We discuss this in detail * in Chapter 9: Functions and Calls. */ -public class StartNode extends MultiNode implements Control { +public class StartNode extends MultiNode { final TypeTuple _args; @@ -27,20 +27,12 @@ public class StartNode extends MultiNode implements Control { StringBuilder _print1(StringBuilder sb) { return sb.append(label()); } - + + @Override public boolean isCFG() { return true; } + @Override public TypeTuple compute() { return _args; } @Override public Node idealize() { return null; } - - - @Override - public ProjNode proj( int idx ) { - for( Node proj : _outputs ) - if( ((ProjNode)proj)._idx==idx ) - return (ProjNode)proj; - return null; - } - } diff --git a/chapter04/src/main/java/com/seaofnodes/simple/node/SubNode.java b/chapter04/src/main/java/com/seaofnodes/simple/node/SubNode.java index e5939e1b..42ddc1c1 100644 --- a/chapter04/src/main/java/com/seaofnodes/simple/node/SubNode.java +++ b/chapter04/src/main/java/com/seaofnodes/simple/node/SubNode.java @@ -5,12 +5,11 @@ import com.seaofnodes.simple.type.TypeBot; import com.seaofnodes.simple.type.TypeInteger; public class SubNode extends Node { - public SubNode(Node lhs, Node rhs) { - super(null, lhs, rhs); - } + public SubNode(Node lhs, Node rhs) { super(null, lhs, rhs); } - @Override - public String label() { return "Sub"; } + @Override public String label() { return "Sub"; } + + @Override public String glabel() { return "-"; } @Override StringBuilder _print1(StringBuilder sb) { diff --git a/chapter04/src/main/java/com/seaofnodes/simple/type/TypeInteger.java b/chapter04/src/main/java/com/seaofnodes/simple/type/TypeInteger.java index b53b1b29..63c46035 100644 --- a/chapter04/src/main/java/com/seaofnodes/simple/type/TypeInteger.java +++ b/chapter04/src/main/java/com/seaofnodes/simple/type/TypeInteger.java @@ -26,7 +26,7 @@ public class TypeInteger extends Type { @Override public String toString() { - return _print(new StringBuilder()).toString(); + return _print(new StringBuilder()).toString(); } @Override diff --git a/chapter04/src/main/java/com/seaofnodes/simple/type/TypeTuple.java b/chapter04/src/main/java/com/seaofnodes/simple/type/TypeTuple.java index ef87a415..036147a2 100644 --- a/chapter04/src/main/java/com/seaofnodes/simple/type/TypeTuple.java +++ b/chapter04/src/main/java/com/seaofnodes/simple/type/TypeTuple.java @@ -1,10 +1,10 @@ package com.seaofnodes.simple.type; public class TypeTuple extends Type { - + public final Type[] _types; - public TypeTuple(Type[] _types) { + public TypeTuple(Type... _types) { this._types = _types; } diff --git a/chapter04/src/test/java/com/seaofnodes/simple/Chapter04Test.java b/chapter04/src/test/java/com/seaofnodes/simple/Chapter04Test.java index ed999039..ebfe1399 100644 --- a/chapter04/src/test/java/com/seaofnodes/simple/Chapter04Test.java +++ b/chapter04/src/test/java/com/seaofnodes/simple/Chapter04Test.java @@ -15,44 +15,44 @@ public class Chapter04Test { @Test public void testChapter4Peephole() { - Parser parser = new Parser("return 1+arg+2; #showGraph;", TypeInteger.BOT); + Parser parser = new Parser("return 1+arg+2; #showGraph;"); ReturnNode ret = parser.parse(); - assertEquals("return (Proj_3+3);", ret.print()); + assertEquals("return (arg+3);", ret.print()); } @Test public void testChapter4Peephole2() { - Parser parser = new Parser("return (1+arg)+2;", TypeInteger.BOT); + Parser parser = new Parser("return (1+arg)+2;"); ReturnNode ret = parser.parse(); - assertEquals("return (Proj_3+3);", ret.print()); + assertEquals("return (arg+3);", ret.print()); } @Test public void testChapter4Add0() { - Parser parser = new Parser("return 0+arg;", TypeInteger.BOT); + Parser parser = new Parser("return 0+arg;"); ReturnNode ret = parser.parse(); - assertEquals("return Proj_3;", ret.print()); + assertEquals("return arg;", ret.print()); } @Test public void testChapter4AddAddMul() { - Parser parser = new Parser("return arg+0+arg;", TypeInteger.BOT); + Parser parser = new Parser("return arg+0+arg;"); ReturnNode ret = parser.parse(); - assertEquals("return (Proj_3*2);", ret.print()); + assertEquals("return (arg*2);", ret.print()); } @Test public void testChapter4Peephole3() { - Parser parser = new Parser("return 1+arg+2+arg+3; #showGraph;", TypeInteger.BOT); + Parser parser = new Parser("return 1+arg+2+arg+3; #showGraph;"); ReturnNode ret = parser.parse(); - assertEquals("return ((Proj_3*2)+6);", ret.print()); + assertEquals("return ((arg*2)+6);", ret.print()); } @Test public void testChapter4Mul1() { - Parser parser = new Parser("return 1*arg;", TypeInteger.BOT); + Parser parser = new Parser("return 1*arg;"); ReturnNode ret = parser.parse(); - assertEquals("return Proj_3;", ret.print()); + assertEquals("return arg;", ret.print()); } @Test @@ -72,54 +72,64 @@ public class Chapter04Test { @Test public void testChapter4CompEq() { - Parser parser = new Parser("return 3==3; #showGraph;", TypeInteger.BOT); + Parser parser = new Parser("return 3==3; #showGraph;"); ReturnNode ret = parser.parse(); assertEquals("return 1;", ret.print()); } @Test public void testChapter4CompEq2() { - Parser parser = new Parser("return 3==4; #showGraph;", TypeInteger.BOT); + Parser parser = new Parser("return 3==4; #showGraph;"); ReturnNode ret = parser.parse(); assertEquals("return 0;", ret.print()); } @Test public void testChapter4CompNEq() { - Parser parser = new Parser("return 3!=3; #showGraph;", TypeInteger.BOT); + Parser parser = new Parser("return 3!=3; #showGraph;"); ReturnNode ret = parser.parse(); assertEquals("return 0;", ret.print()); } @Test public void testChapter4CompNEq2() { - Parser parser = new Parser("return 3!=4; #showGraph;", TypeInteger.BOT); + Parser parser = new Parser("return 3!=4; #showGraph;"); ReturnNode ret = parser.parse(); assertEquals("return 1;", ret.print()); } @Test public void testChapter4Bug1() { - Parser parser = new Parser("int a=arg+1; int b=a; b=1; return a+2; #showGraph;", TypeInteger.BOT); + Parser parser = new Parser("int a=arg+1; int b=a; b=1; return a+2; #showGraph;"); ReturnNode ret = parser.parse(); - assertEquals("return (Proj_3+3);", ret.print()); + assertEquals("return (arg+3);", ret.print()); } @Test public void testChapter4Bug2() { - Parser parser = new Parser("int a=arg+1; a=a; return a; #showGraph;", TypeInteger.BOT); + Parser parser = new Parser("int a=arg+1; a=a; return a; #showGraph;"); ReturnNode ret = parser.parse(); - assertEquals("return (Proj_3+1);", ret.print()); + assertEquals("return (arg+1);", ret.print()); } @Test public void testChapter4Bug3() { - Parser parser = new Parser("int a=arg*2+1; a=a+-1; return a; #showGraph;", TypeInteger.BOT); - ReturnNode ret = parser.parse(); - assertEquals("return (Proj_3*2);", ret.print()); + try { + new Parser("inta=1; return a;").parse(); + fail(); + } catch( RuntimeException e ) { + assertEquals("Undefined name 'inta'",e.getMessage()); + } } @Test + public void testChapter4Bug4() { + Parser parser = new Parser("return -arg;"); + ReturnNode ret = parser.parse(); + assertEquals("return (-arg);", ret.print()); + } + + @Test public void testVarDecl() { Parser parser = new Parser("int a=1; return a;"); ReturnNode ret = parser.parse(); @@ -158,12 +168,14 @@ public class Chapter04Test { @Test public void testSelfAssign() { - exceptionRule.expect(RuntimeException.class); - exceptionRule.expectMessage("Undefined name 'a'"); - new Parser("int a=a; return a;").parse(); + try { + new Parser("int a=a; return a;").parse(); + fail(); + } catch( RuntimeException e ) { + assertEquals("Undefined name 'a'",e.getMessage()); + } } - @Test public void testChapter2ParseGrammar() { Node._disablePeephole = true; // disable peephole so we can observe full graph @@ -247,16 +259,22 @@ public class Chapter04Test { @Test public void testBad1() { - exceptionRule.expect(RuntimeException.class); - exceptionRule.expectMessage("Syntax error, expected =: "); - new Parser("ret").parse(); + try { + new Parser("ret").parse(); + fail(); + } catch( RuntimeException e ) { + assertEquals("Syntax error, expected =: ",e.getMessage()); + } } @Test public void testBad2() { - exceptionRule.expect(RuntimeException.class); - exceptionRule.expectMessage("Syntax error: integer values cannot start with '0'"); - new Parser("return 0123;").parse(); + try { + new Parser("return 0123;").parse(); + fail(); + } catch( RuntimeException e ) { + assertEquals("Syntax error: integer values cannot start with '0'",e.getMessage()); + } } @Test @@ -267,9 +285,12 @@ public class Chapter04Test { @Test public void testBad4() { - exceptionRule.expect(RuntimeException.class); - exceptionRule.expectMessage("Syntax error, expected ;:"); - new Parser("return 100").parse(); + try { + new Parser("return 100").parse(); + fail(); + } catch( RuntimeException e ) { + assertEquals("Syntax error, expected ;: ",e.getMessage()); + } } @Test @@ -280,8 +301,22 @@ public class Chapter04Test { @Test public void testBad6() { - exceptionRule.expect(RuntimeException.class); - exceptionRule.expectMessage("Syntax error, expected }:"); - new Parser("int a=1; int b=2; int c=0; { int b=3; c=a+b;").parse(); + try { + new Parser("int a=1; int b=2; int c=0; { int b=3; c=a+b;").parse(); + fail(); + } catch( RuntimeException e ) { + assertEquals("Syntax error, expected }: ",e.getMessage()); + } } + + @Test + public void testBad7() { + try { + new Parser("return 1;}").parse(); + fail(); + } catch( RuntimeException e ) { + assertEquals("Syntax error, unexpected }",e.getMessage()); + } + } + } diff --git a/chapter05/README.md b/chapter05/README.md index 23d936c5..78a8b1fe 100644 --- a/chapter05/README.md +++ b/chapter05/README.md @@ -15,7 +15,7 @@ Here is a recap of the nodes introduced in previous chapters: | Node Name | Type | Chapter | Description | Inputs | Value | |-----------|----------------|---------|------------------------------------------------|-------------------------------------------------------------------------------|----------------------------------------------------------------------------| | Multi | Abstract class | 4 | A node that has a tuple result | | A tuple | -| Start | Control | 1 | Start of function, now a MultiNode | A type for the input argument named `arg`. | A tuple with a ctrl token and an `arg` data node | +| Start | Control | 1 | Start of function, now a MultiNode | | A tuple with a ctrl token and an `arg` data node | | Proj | ? | 4 | Projection nodes extract values from MultiNode | A MultiNode and index | Result is the extracted value from the input MultiNode at offset index | | Bool | Data | 4 | Represents results of a comparison operator | Two data nodes | Result is a comparison, represented as integer value where 1=true, 0=false | | Return | Control | 1 | End of function | Predecessor control node and a data node for the return value of the function | Return value of the function | @@ -112,6 +112,115 @@ This involves following: updated to point to the `Phi` node. 10. Finally, we set the `Region` node as the control token, and discard the duplicated `ScopeNode`. +Here is the implementing code. + +```java +/** + * Parses a statement + * + * <pre> + * if ( expression ) statement [else statement] + * </pre> + * @return a {@link Node}, never {@code null} + */ +private Node parseIf() { + require("("); + // Parse predicate + var pred = require(parseExpression(), ")"); + // IfNode takes current control and predicate + IfNode ifNode = (IfNode)new IfNode(ctrl(), pred).peephole(); + // Setup projection nodes + Node ifT = new ProjNode(ifNode, 0, "True" ).peephole(); + Node ifF = new ProjNode(ifNode, 1, "False").peephole(); + // In if true branch, the ifT proj node becomes the ctrl + // But first clone the scope and set it as current + int ndefs = _scope.nIns(); + ScopeNode fScope = _scope.dup(); // Duplicate current scope + _allScopes.push(fScope); // For graph visualization we need all scopes + + // Parse the true side + ctrl(ifT); // set ctrl token to ifTrue projection + parseStatement(); // Parse true-side + ScopeNode tScope = _scope; + + // Parse the false side + _scope = fScope; // Restore scope, then parse else block if any + ctrl(ifF); // Ctrl token is now set to ifFalse projection + if (matchx("else")) parseStatement(); + + if( tScope.nIns() != ndefs || fScope.nIns() != ndefs ) + throw error("Cannot define a new name on one arm of an if"); + + // Merge results + _scope = tScope; + _allScopes.pop(); // Discard pushed from graph display + return ctrl(tScope.mergeScopes(fScope)); +} +``` + +## Operations on ScopeNodes + +As explained above, we duplicate ScopeNodes and merge them at a later point. There are some +subtleties in how this is implemented that is worth going over. + +### Duplicating a ScopeNode + +Below is the code for duplicating a ScopeNode. + +Our goals are: +1) Duplicate the name bindings across all stack levels +2) Make the new ScopeNode a user of all the bound nodes +3) Ensure that the order of defs in the duplicate is the same to allow easy merging + +```java +/** + * Duplicate a ScopeNode; including all levels, up to Nodes. So this is + * neither shallow (would dup the Scope but not the internal HashMap + * tables), nor deep (would dup the Scope, the HashMap tables, but then + * also the program Nodes). + * <p> + * The new Scope is a full-fledged Node with proper use<->def edges. + */ +public ScopeNode dup() { + ScopeNode dup = new ScopeNode(); + for( HashMap<String, Integer> tab : _scopes ) + dup._scopes.push(new HashMap<>(tab)); + for( int i=0; i<nIns(); i++ ) + dup.add_def(in(i)); + return dup; +} +``` + +### Merging two ScopeNodes + +At the merge point we merge two ScopeNodes. The goals are: + +1) Merge names whose bindings have changed between the two nodes. For each such name, a Phi node is created, referencing the two original data nodes. +2) A new Region node is created representing the merged control flow. The phis have this region node as the first input. +3) After the merge is completed, the duplicate is discarded, and its use of each of the nodes is also deleted. + +The merging logic takes advantage of that fact that the two ScopeNodes have the bound nodes in the same order in the list of inputs. This was ensured during duplicating the ScopeNode. +Although only the innermost occurrence of a name can have its binding changed, we scan all the nodes in our input list, and simply ignore ones where the binding has not changed. + +```java +/** + * Merges the names whose node bindings differ, by creating Phi node for such names + * The names could occur at all stack levels, but a given name can only differ in the + * innermost stack level where the name is bound. + * + * @param that The ScopeNode to be merged into this + * @return A new Region node representing the merge point + */ +public RegionNode mergeScopes(ScopeNode that) { + RegionNode r = (RegionNode)ctrl(new RegionNode(null,ctrl(), that.ctrl()).peephole()); + for( int i=1; i<nIns(); i++ ) + if( in(i) != that.in(i) ) // No need for redundant Phis + set_def(i,new PhiNode(r, in(i), that.in(i)).peephole()); + that.kill(); // Kill merged scope, removing it as user of all the nodes + return r; +} +``` + ## Example We show the graph for the following code snippet: @@ -152,6 +261,115 @@ Here is the graph after the `return` statement was parsed and processed.  +## More Peepholes + +Phi's implement a peephole shown below: + +```java +@Override +public Node idealize() { + // Remove a "junk" Phi: Phi(x,x) is just x + if( same_inputs() ) + return in(1); + + // Pull "down" a common data op. One less op in the world. One more + // Phi, but Phis do not make code. + // Phi(op(A,B),op(Q,R),op(X,Y)) becomes + // op(Phi(A,Q,X), Phi(B,R,Y)). + Node op = in(1); + if( op.nIns()==3 && op.in(0)==null && !op.isCFG() && same_op() ) { + Node[] lhss = new Node[nIns()]; + Node[] rhss = new Node[nIns()]; + lhss[0] = rhss[0] = in(0); // Set Region + for( int i=1; i<nIns(); i++ ) { + lhss[i] = in(i).in(1); + rhss[i] = in(i).in(2); + } + Node phi_lhs = new PhiNode(_label,lhss).peephole(); + Node phi_rhs = new PhiNode(_label,rhss).peephole(); + return op.copy(phi_lhs,phi_rhs); + } + + return null; +} + +private boolean same_op() { + for( int i=2; i<nIns(); i++ ) + if( in(1).getClass() != in(i).getClass() ) + return false; + return true; +} + +private boolean same_inputs() { + for( int i=2; i<nIns(); i++ ) + if( in(1) != in(i) ) + return false; + return true; +} +``` + +This is illustrated in the example: + +```java +int a=arg==2; +if( arg==1 ) +{ + a=arg==3; +} +return a; +``` + +Pre-peephole we have: + + + +Post-peephole: + + + +## More examples + +```java +int c = 3; +int b = 2; +if (arg == 1) { + b = 3; + c = 4; +} +``` + + + +```java +int a=arg+1; +int b=arg+2; +if( arg==1 ) + b=b+a; +else + a=b+1; +return a+b; +``` + + + +```java +int a=1; +if( arg==1 ) + if( arg==2 ) + a=2; + else + a=3; +else if( arg==3 ) + a=4; +else + a=5; +return a; +``` + + + + + [^1]: Click, C. (1995). Combining Analyses, Combining Optimizations, 132. diff --git a/chapter05/docs/05-graph2.gv b/chapter05/docs/05-graph2.gv index 0be7c1d6..2adb3da5 100644 --- a/chapter05/docs/05-graph2.gv +++ b/chapter05/docs/05-graph2.gv @@ -9,7 +9,6 @@ else { } #showGraph; return a; - */ rankdir=BT; ordering="in"; @@ -61,15 +60,15 @@ return a; edge [ fontname=Helvetica, fontsize=8 ]; EQNode8 -> Start2:p1[taillabel=1]; EQNode8 -> Con_7[taillabel=2]; - If9 -> Start2:p0[taillabel=0; color=red]; + If9 -> Start2:p0[taillabel=0 color=red]; If9 -> EQNode8[taillabel=1]; Add14 -> Start2:p1[taillabel=1]; Add14 -> Con_13[taillabel=2]; Sub16 -> Start2:p1[taillabel=1]; Sub16 -> Con_15[taillabel=2]; - Region17 -> If9:p0[taillabel=1; color=red]; - Region17 -> If9:p1[taillabel=2; color=red]; - Region17 -> Phi_a18 [style=invis] + Region17 -> If9:p0[taillabel=1 color=red]; + Region17 -> If9:p1[taillabel=2 color=red]; + Phi_a18 -> Region17 [style=dotted taillabel=0]; Phi_a18 -> Add14[taillabel=1]; Phi_a18 -> Sub16[taillabel=2]; edge [style=dashed color=cornflowerblue]; diff --git a/chapter05/docs/05-graph2.svg b/chapter05/docs/05-graph2.svg index ebc4ffac..d5e48a9e 100644 --- a/chapter05/docs/05-graph2.svg +++ b/chapter05/docs/05-graph2.svg @@ -4,220 +4,226 @@ <!-- Generated by graphviz version 2.43.0 (0) --> <!-- Title: chapter05 Pages: 1 --> -<svg width="302pt" height="428pt" - viewBox="0.00 0.00 302.28 428.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> +<svg width="343pt" height="428pt" + viewBox="0.00 0.00 343.03 428.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 424)"> <title>chapter05</title> -<polygon fill="white" stroke="transparent" points="-4,4 -4,-424 298.28,-424 298.28,4 -4,4"/> +<polygon fill="white" stroke="transparent" points="-4,4 -4,-424 339.03,-424 339.03,4 -4,4"/> <g id="clust1" class="cluster"> <title>cluster_Nodes</title> <polygon fill="none" stroke="black" points="8,-88 8,-412 282,-412 282,-88 8,-88"/> </g> <g id="clust3" class="cluster"> <title>cluster_Scope1_0</title> -<polygon fill="none" stroke="black" points="38,-8 38,-76 238,-76 238,-8 38,-8"/> +<polygon fill="none" stroke="black" points="67,-8 67,-76 267,-76 267,-8 67,-8"/> </g> <g id="clust4" class="cluster"> <title>cluster_Scope1_1</title> -<polygon fill="none" stroke="black" points="160,-16 160,-68 230,-68 230,-16 160,-16"/> +<polygon fill="none" stroke="black" points="75,-16 75,-68 145,-68 145,-16 75,-16"/> </g> <!-- Start2 --> <g id="node1" class="node"> <title>Start2</title> -<polygon fill="yellow" stroke="transparent" points="118,-375 118,-400 199,-400 199,-375 118,-375"/> -<polygon fill="none" stroke="black" points="118,-375 118,-400 199,-400 199,-375 118,-375"/> -<text text-anchor="start" x="140" y="-383.8" font-family="Times,serif" font-size="14.00">Start</text> -<polygon fill="none" stroke="black" points="118,-344 118,-375 199,-375 199,-344 118,-344"/> -<polygon fill="yellow" stroke="transparent" points="123,-349 123,-370 163,-370 163,-349 123,-349"/> -<polygon fill="none" stroke="black" points="123,-349 123,-370 163,-370 163,-349 123,-349"/> -<text text-anchor="start" x="126" y="-355.8" font-family="Times,serif" font-size="14.00">$ctrl</text> -<polygon fill="none" stroke="black" points="163,-349 163,-370 194,-370 194,-349 163,-349"/> -<text text-anchor="start" x="166" y="-355.8" font-family="Times,serif" font-size="14.00">arg</text> +<polygon fill="yellow" stroke="transparent" points="113,-375 113,-400 194,-400 194,-375 113,-375"/> +<polygon fill="none" stroke="black" points="113,-375 113,-400 194,-400 194,-375 113,-375"/> +<text text-anchor="start" x="135" y="-383.8" font-family="Times,serif" font-size="14.00">Start</text> +<polygon fill="none" stroke="black" points="113,-344 113,-375 194,-375 194,-344 113,-344"/> +<polygon fill="yellow" stroke="transparent" points="118,-349 118,-370 158,-370 158,-349 118,-349"/> +<polygon fill="none" stroke="black" points="118,-349 118,-370 158,-370 158,-349 118,-349"/> +<text text-anchor="start" x="121" y="-355.8" font-family="Times,serif" font-size="14.00">$ctrl</text> +<polygon fill="none" stroke="black" points="158,-349 158,-370 189,-370 189,-349 158,-349"/> +<text text-anchor="start" x="161" y="-355.8" font-family="Times,serif" font-size="14.00">arg</text> </g> <!-- Con_7 --> <g id="node2" class="node"> <title>Con_7</title> -<ellipse fill="none" stroke="black" cx="63" cy="-372" rx="27" ry="18"/> -<text text-anchor="middle" x="63" y="-368.3" font-family="Times,serif" font-size="14.00">#1</text> +<ellipse fill="none" stroke="black" cx="247" cy="-372" rx="27" ry="18"/> +<text text-anchor="middle" x="247" y="-368.3" font-family="Times,serif" font-size="14.00">#1</text> </g> <!-- EQNode8 --> <g id="node3" class="node"> <title>EQNode8</title> -<ellipse fill="none" stroke="black" cx="63" cy="-286" rx="27" ry="18"/> -<text text-anchor="middle" x="63" y="-282.3" font-family="Times,serif" font-size="14.00">==</text> +<ellipse fill="none" stroke="black" cx="247" cy="-286" rx="27" ry="18"/> +<text text-anchor="middle" x="247" y="-282.3" font-family="Times,serif" font-size="14.00">==</text> </g> <!-- EQNode8->Start2 --> <g id="edge1" class="edge"> <title>EQNode8->Start2:p1</title> -<path fill="none" stroke="black" d="M84.55,-297.13C110.75,-309.58 153.66,-330.41 171.18,-341.44"/> -<polygon fill="black" stroke="black" points="169.09,-344.25 179,-348 173.59,-338.89 169.09,-344.25"/> -<text text-anchor="middle" x="87.55" y="-299.73" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> +<path fill="none" stroke="black" d="M236.57,-302.62C225.76,-318.5 208.98,-342.28 198.26,-353.17"/> +<polygon fill="black" stroke="black" points="196.15,-350.37 190,-359 200.19,-356.09 196.15,-350.37"/> +<text text-anchor="middle" x="233.57" y="-305.22" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> </g> <!-- EQNode8->Con_7 --> <g id="edge2" class="edge"> <title>EQNode8->Con_7</title> -<path fill="none" stroke="black" d="M63,-304.4C63,-315.74 63,-330.77 63,-343.68"/> -<polygon fill="black" stroke="black" points="59.5,-343.9 63,-353.9 66.5,-343.9 59.5,-343.9"/> -<text text-anchor="middle" x="60" y="-307" font-family="Helvetica,sans-Serif" font-size="8.00">2</text> +<path fill="none" stroke="black" d="M247,-304.4C247,-315.74 247,-330.77 247,-343.68"/> +<polygon fill="black" stroke="black" points="243.5,-343.9 247,-353.9 250.5,-343.9 243.5,-343.9"/> +<text text-anchor="middle" x="244" y="-307" font-family="Helvetica,sans-Serif" font-size="8.00">2</text> </g> <!-- If9 --> <g id="node4" class="node"> <title>If9</title> -<polygon fill="yellow" stroke="transparent" points="24,-203 24,-228 118,-228 118,-203 24,-203"/> -<polygon fill="none" stroke="black" points="24,-203 24,-228 118,-228 118,-203 24,-203"/> -<text text-anchor="start" x="65.5" y="-211.8" font-family="Times,serif" font-size="14.00">If</text> -<polygon fill="none" stroke="black" points="24,-172 24,-203 118,-203 118,-172 24,-172"/> -<polygon fill="yellow" stroke="transparent" points="29,-177 29,-198 69,-198 69,-177 29,-177"/> -<polygon fill="none" stroke="black" points="29,-177 29,-198 69,-198 69,-177 29,-177"/> -<text text-anchor="start" x="32" y="-183.8" font-family="Times,serif" font-size="14.00">True</text> -<polygon fill="yellow" stroke="transparent" points="69,-177 69,-198 113,-198 113,-177 69,-177"/> -<polygon fill="none" stroke="black" points="69,-177 69,-198 113,-198 113,-177 69,-177"/> -<text text-anchor="start" x="72" y="-183.8" font-family="Times,serif" font-size="14.00">False</text> +<polygon fill="yellow" stroke="transparent" points="172,-203 172,-228 266,-228 266,-203 172,-203"/> +<polygon fill="none" stroke="black" points="172,-203 172,-228 266,-228 266,-203 172,-203"/> +<text text-anchor="start" x="213.5" y="-211.8" font-family="Times,serif" font-size="14.00">If</text> +<polygon fill="none" stroke="black" points="172,-172 172,-203 266,-203 266,-172 172,-172"/> +<polygon fill="yellow" stroke="transparent" points="177,-177 177,-198 217,-198 217,-177 177,-177"/> +<polygon fill="none" stroke="black" points="177,-177 177,-198 217,-198 217,-177 177,-177"/> +<text text-anchor="start" x="180" y="-183.8" font-family="Times,serif" font-size="14.00">True</text> +<polygon fill="yellow" stroke="transparent" points="217,-177 217,-198 261,-198 261,-177 217,-177"/> +<polygon fill="none" stroke="black" points="217,-177 217,-198 261,-198 261,-177 217,-177"/> +<text text-anchor="start" x="220" y="-183.8" font-family="Times,serif" font-size="14.00">False</text> </g> <!-- If9->Start2 --> <g id="edge3" class="edge"> <title>If9->Start2:p0</title> -<path fill="none" stroke="red" d="M42.24,-232.39C26.58,-253.43 12.99,-281.34 27,-304 45.81,-334.43 69.02,-320.48 99,-340 106.29,-344.75 108.21,-351.45 112.41,-355.49"/> -<polygon fill="red" stroke="red" points="111.41,-358.85 122,-359 113.81,-352.28 111.41,-358.85"/> -<text text-anchor="middle" x="39.24" y="-234.99" font-family="Helvetica,sans-Serif" font-size="8.00">0</text> +<path fill="none" stroke="red" d="M210.31,-232.18C203.59,-253.4 193.07,-281.57 179,-304 166.9,-323.28 145.68,-322.25 139.64,-338.02"/> +<polygon fill="red" stroke="red" points="136.17,-337.56 138,-348 143.08,-338.7 136.17,-337.56"/> +<text text-anchor="middle" x="207.31" y="-234.78" font-family="Helvetica,sans-Serif" font-size="8.00">0</text> </g> <!-- If9->EQNode8 --> <g id="edge4" class="edge"> <title>If9->EQNode8</title> -<path fill="none" stroke="black" d="M68.02,-232.28C67.23,-240.58 66.38,-249.48 65.61,-257.56"/> -<polygon fill="black" stroke="black" points="62.12,-257.31 64.66,-267.6 69.09,-257.97 62.12,-257.31"/> -<text text-anchor="middle" x="65.02" y="-234.88" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> +<path fill="none" stroke="black" d="M229.43,-232.28C232.3,-240.9 235.39,-250.17 238.16,-258.49"/> +<polygon fill="black" stroke="black" points="234.87,-259.69 241.36,-268.07 241.51,-257.48 234.87,-259.69"/> +<text text-anchor="middle" x="226.43" y="-234.88" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> </g> <!-- Con_13 --> <g id="node5" class="node"> <title>Con_13</title> -<ellipse fill="none" stroke="black" cx="227" cy="-286" rx="27" ry="18"/> -<text text-anchor="middle" x="227" y="-282.3" font-family="Times,serif" font-size="14.00">#2</text> +<ellipse fill="none" stroke="black" cx="135" cy="-286" rx="27" ry="18"/> +<text text-anchor="middle" x="135" y="-282.3" font-family="Times,serif" font-size="14.00">#2</text> </g> <!-- Add14 --> <g id="node6" class="node"> <title>Add14</title> -<ellipse fill="none" stroke="black" cx="243" cy="-200" rx="27" ry="18"/> -<text text-anchor="middle" x="243" y="-196.3" font-family="Times,serif" font-size="14.00">+</text> +<ellipse fill="none" stroke="black" cx="119" cy="-200" rx="27" ry="18"/> +<text text-anchor="middle" x="119" y="-196.3" font-family="Times,serif" font-size="14.00">+</text> </g> <!-- Add14->Start2 --> <g id="edge5" class="edge"> <title>Add14->Start2:p1</title> -<path fill="none" stroke="black" d="M255.66,-216.26C268.24,-233.4 284.18,-261.85 273,-285"/> -<path fill="none" stroke="black" d="M273,-287C256.15,-321.89 246.19,-348.04 217.03,-356.27"/> -<polygon fill="black" stroke="black" points="215.98,-352.91 206.86,-358.3 217.35,-359.77 215.98,-352.91"/> -<text text-anchor="middle" x="252.66" y="-218.86" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> +<path fill="none" stroke="black" d="M134.23,-215.02C146.68,-227.55 163.4,-247.1 171,-268 181.92,-298.04 175.64,-309.96 174.25,-337.87"/> +<polygon fill="black" stroke="black" points="170.75,-337.92 174,-348 177.75,-338.09 170.75,-337.92"/> +<text text-anchor="middle" x="131.23" y="-217.62" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> </g> <!-- Add14->Con_13 --> <g id="edge6" class="edge"> <title>Add14->Con_13</title> -<path fill="none" stroke="black" d="M239.76,-218C237.57,-229.5 234.63,-244.93 232.13,-258.08"/> -<polygon fill="black" stroke="black" points="228.67,-257.55 230.23,-268.03 235.54,-258.86 228.67,-257.55"/> -<text text-anchor="middle" x="236.76" y="-220.6" font-family="Helvetica,sans-Serif" font-size="8.00">2</text> +<path fill="none" stroke="black" d="M122.24,-218C124.43,-229.5 127.37,-244.93 129.87,-258.08"/> +<polygon fill="black" stroke="black" points="126.46,-258.86 131.77,-268.03 133.33,-257.55 126.46,-258.86"/> +<text text-anchor="middle" x="119.24" y="-220.6" font-family="Helvetica,sans-Serif" font-size="8.00">2</text> </g> <!-- Con_15 --> <g id="node7" class="node"> <title>Con_15</title> -<ellipse fill="none" stroke="black" cx="135" cy="-286" rx="27" ry="18"/> -<text text-anchor="middle" x="135" y="-282.3" font-family="Times,serif" font-size="14.00">#3</text> +<ellipse fill="none" stroke="black" cx="43" cy="-286" rx="27" ry="18"/> +<text text-anchor="middle" x="43" y="-282.3" font-family="Times,serif" font-size="14.00">#3</text> </g> <!-- Sub16 --> <g id="node8" class="node"> <title>Sub16</title> -<ellipse fill="none" stroke="black" cx="171" cy="-200" rx="27" ry="18"/> -<text text-anchor="middle" x="171" y="-196.3" font-family="Times,serif" font-size="14.00">-</text> +<ellipse fill="none" stroke="black" cx="47" cy="-200" rx="27" ry="18"/> +<text text-anchor="middle" x="47" y="-196.3" font-family="Times,serif" font-size="14.00">-</text> </g> <!-- Sub16->Start2 --> <g id="edge7" class="edge"> <title>Sub16->Start2:p1</title> -<path fill="none" stroke="black" d="M172.54,-218.18C174.7,-243.68 178.43,-293.32 178.94,-337.97"/> -<polygon fill="black" stroke="black" points="175.44,-338.02 179,-348 182.44,-337.98 175.44,-338.02"/> -<text text-anchor="middle" x="169.54" y="-220.78" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> +<path fill="none" stroke="black" d="M54.69,-217.49C67.53,-244.81 92.56,-297.14 99,-304 122.77,-329.31 164.37,-313.46 172.57,-338.01"/> +<polygon fill="black" stroke="black" points="169.12,-338.6 174,-348 176.05,-337.61 169.12,-338.6"/> +<text text-anchor="middle" x="51.69" y="-220.09" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> </g> <!-- Sub16->Con_15 --> <g id="edge8" class="edge"> <title>Sub16->Con_15</title> -<path fill="none" stroke="black" d="M163.89,-217.6C158.81,-229.45 151.88,-245.62 146.08,-259.15"/> -<polygon fill="black" stroke="black" points="142.82,-257.87 142.1,-268.44 149.25,-260.63 142.82,-257.87"/> -<text text-anchor="middle" x="160.89" y="-220.2" font-family="Helvetica,sans-Serif" font-size="8.00">2</text> +<path fill="none" stroke="black" d="M46.19,-218C45.65,-229.31 44.93,-244.42 44.31,-257.43"/> +<polygon fill="black" stroke="black" points="40.8,-257.58 43.82,-267.74 47.79,-257.92 40.8,-257.58"/> +<text text-anchor="middle" x="43.19" y="-220.6" font-family="Helvetica,sans-Serif" font-size="8.00">2</text> </g> <!-- Region17 --> <g id="node9" class="node"> <title>Region17</title> -<polygon fill="yellow" stroke="black" points="124,-132 58,-132 58,-96 124,-96 124,-132"/> -<text text-anchor="middle" x="91" y="-110.3" font-family="Times,serif" font-size="14.00">Region</text> +<polygon fill="yellow" stroke="black" points="232,-132 166,-132 166,-96 232,-96 232,-132"/> +<text text-anchor="middle" x="199" y="-110.3" font-family="Times,serif" font-size="14.00">Region</text> </g> <!-- Region17->If9 --> <g id="edge9" class="edge"> <title>Region17->If9:p0</title> -<path fill="none" stroke="red" d="M70.98,-132.12C62.36,-141.06 53.52,-152.84 50.29,-165.84"/> -<polygon fill="red" stroke="red" points="46.78,-165.64 49,-176 53.73,-166.52 46.78,-165.64"/> -<text text-anchor="middle" x="67.98" y="-134.72" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> +<path fill="none" stroke="red" d="M198.14,-132.09C197.72,-141.54 197.27,-153.77 197.08,-165.68"/> +<polygon fill="red" stroke="red" points="193.58,-165.97 197,-176 200.58,-166.03 193.58,-165.97"/> +<text text-anchor="middle" x="195.14" y="-134.69" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> </g> <!-- Region17->If9 --> <g id="edge10" class="edge"> <title>Region17->If9:p1</title> -<path fill="none" stroke="red" d="M91,-132.09C91,-141.55 91,-153.77 91,-165.69"/> -<polygon fill="red" stroke="red" points="87.5,-166 91,-176 94.5,-166 87.5,-166"/> -<text text-anchor="middle" x="88" y="-134.69" font-family="Helvetica,sans-Serif" font-size="8.00">2</text> +<path fill="none" stroke="red" d="M217.83,-132.05C226.1,-141.05 234.63,-152.92 237.76,-165.89"/> +<polygon fill="red" stroke="red" points="234.31,-166.5 239,-176 241.25,-165.65 234.31,-166.5"/> +<text text-anchor="middle" x="214.83" y="-134.65" font-family="Helvetica,sans-Serif" font-size="8.00">2</text> </g> <!-- Phi_a18 --> <g id="node10" class="node"> <title>Phi_a18</title> -<ellipse fill="lightyellow" stroke="black" cx="187" cy="-114" rx="27" ry="18"/> -<text text-anchor="middle" x="187" y="-110.3" font-family="Times,serif" font-size="14.00">φ_a</text> +<ellipse fill="lightyellow" stroke="black" cx="119" cy="-114" rx="27" ry="18"/> +<text text-anchor="middle" x="119" y="-110.3" font-family="Times,serif" font-size="14.00">φ_a</text> </g> -<!-- Region17->Phi_a18 --> <!-- Phi_a18->Add14 --> <g id="edge12" class="edge"> <title>Phi_a18->Add14</title> -<path fill="none" stroke="black" d="M197.53,-130.8C205.75,-143.12 217.3,-160.45 226.7,-174.55"/> -<polygon fill="black" stroke="black" points="224.05,-176.89 232.51,-183.27 229.88,-173.01 224.05,-176.89"/> -<text text-anchor="middle" x="194.53" y="-133.4" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> +<path fill="none" stroke="black" d="M119,-132.4C119,-143.74 119,-158.77 119,-171.68"/> +<polygon fill="black" stroke="black" points="115.5,-171.9 119,-181.9 122.5,-171.9 115.5,-171.9"/> +<text text-anchor="middle" x="116" y="-135" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> </g> <!-- Phi_a18->Sub16 --> <g id="edge13" class="edge"> <title>Phi_a18->Sub16</title> -<path fill="none" stroke="black" d="M183.76,-132C181.57,-143.5 178.63,-158.93 176.13,-172.08"/> -<polygon fill="black" stroke="black" points="172.67,-171.55 174.23,-182.03 179.54,-172.86 172.67,-171.55"/> -<text text-anchor="middle" x="180.76" y="-134.6" font-family="Helvetica,sans-Serif" font-size="8.00">2</text> +<path fill="none" stroke="black" d="M106.13,-130.02C95.07,-142.92 78.96,-161.71 66.35,-176.42"/> +<polygon fill="black" stroke="black" points="63.61,-174.24 59.76,-184.11 68.93,-178.8 63.61,-174.24"/> +<text text-anchor="middle" x="103.13" y="-132.62" font-family="Helvetica,sans-Serif" font-size="8.00">2</text> +</g> +<!-- Phi_a18->Region17 --> +<g id="edge11" class="edge"> +<title>Phi_a18->Region17</title> +<path fill="none" stroke="black" stroke-dasharray="1,5" d="M146.19,-114C149.39,-114 152.58,-114 155.78,-114"/> +<polygon fill="black" stroke="black" points="155.99,-117.5 165.99,-114 155.99,-110.5 155.99,-117.5"/> +<text text-anchor="middle" x="149.19" y="-107.6" font-family="Helvetica,sans-Serif" font-size="8.00">0</text> </g> <!-- Scope1_0 --> <g id="node11" class="node"> <title>Scope1_0</title> -<polygon fill="cyan" stroke="transparent" points="55,-31 55,-52 71,-52 71,-31 55,-31"/> -<polygon fill="none" stroke="black" points="55,-31 55,-52 71,-52 71,-31 55,-31"/> -<text text-anchor="start" x="58" y="-37.8" font-family="Times,serif" font-size="14.00">0</text> -<polygon fill="none" stroke="black" points="71,-31 71,-52 111,-52 111,-31 71,-31"/> -<text text-anchor="start" x="74" y="-37.8" font-family="Times,serif" font-size="14.00">$ctrl</text> -<polygon fill="none" stroke="black" points="111,-31 111,-52 142,-52 142,-31 111,-31"/> -<text text-anchor="start" x="114" y="-37.8" font-family="Times,serif" font-size="14.00">arg</text> +<polygon fill="cyan" stroke="transparent" points="164,-31 164,-52 180,-52 180,-31 164,-31"/> +<polygon fill="none" stroke="black" points="164,-31 164,-52 180,-52 180,-31 164,-31"/> +<text text-anchor="start" x="167" y="-37.8" font-family="Times,serif" font-size="14.00">0</text> +<polygon fill="none" stroke="black" points="180,-31 180,-52 220,-52 220,-31 180,-31"/> +<text text-anchor="start" x="183" y="-37.8" font-family="Times,serif" font-size="14.00">$ctrl</text> +<polygon fill="none" stroke="black" points="220,-31 220,-52 251,-52 251,-31 220,-31"/> +<text text-anchor="start" x="223" y="-37.8" font-family="Times,serif" font-size="14.00">arg</text> </g> <!-- Scope1_0->Start2 --> <g id="edge15" class="edge"> <title>Scope1_0:Scope1_0_arg->Start2:p1</title> -<path fill="none" stroke="cornflowerblue" stroke-dasharray="5,2" d="M143,-41C159.59,-41 143.27,-65.36 156,-76 179.21,-95.4 197.18,-72.23 223,-88 261.16,-111.31 269.69,-125.64 284,-168 300.71,-217.48 295.71,-237.97 273,-285"/> +<path fill="none" stroke="cornflowerblue" stroke-dasharray="5,2" d="M252,-41C369.7,-41 344.88,-203.88 283,-304 264.19,-334.43 240.54,-319.81 211,-340 204.51,-344.44 202.84,-350.75 199.44,-354.86"/> +<polygon fill="cornflowerblue" stroke="cornflowerblue" points="197.75,-351.78 190,-359 200.56,-358.19 197.75,-351.78"/> </g> <!-- Scope1_0->Region17 --> <g id="edge14" class="edge"> <title>Scope1_0:Scope1_0_$ctrl->Region17</title> -<path fill="none" stroke="cornflowerblue" stroke-dasharray="5,2" d="M91,-53C91,-63.75 91,-75.58 91,-85.87"/> -<polygon fill="cornflowerblue" stroke="cornflowerblue" points="87.5,-85.93 91,-95.93 94.5,-85.93 87.5,-85.93"/> +<path fill="none" stroke="cornflowerblue" stroke-dasharray="5,2" d="M200,-53C200,-63.75 199.84,-75.58 199.64,-85.87"/> +<polygon fill="cornflowerblue" stroke="cornflowerblue" points="196.14,-85.86 199.44,-95.93 203.14,-86.01 196.14,-85.86"/> </g> <!-- Scope1_1 --> <g id="node12" class="node"> <title>Scope1_1</title> -<polygon fill="cyan" stroke="transparent" points="180,-31 180,-52 196,-52 196,-31 180,-31"/> -<polygon fill="none" stroke="black" points="180,-31 180,-52 196,-52 196,-31 180,-31"/> -<text text-anchor="start" x="183" y="-37.8" font-family="Times,serif" font-size="14.00">1</text> -<polygon fill="none" stroke="black" points="196,-31 196,-52 211,-52 211,-31 196,-31"/> -<text text-anchor="start" x="199" y="-37.8" font-family="Times,serif" font-size="14.00">a</text> +<polygon fill="cyan" stroke="transparent" points="95,-31 95,-52 111,-52 111,-31 95,-31"/> +<polygon fill="none" stroke="black" points="95,-31 95,-52 111,-52 111,-31 95,-31"/> +<text text-anchor="start" x="98" y="-37.8" font-family="Times,serif" font-size="14.00">1</text> +<polygon fill="none" stroke="black" points="111,-31 111,-52 126,-52 126,-31 111,-31"/> +<text text-anchor="start" x="114" y="-37.8" font-family="Times,serif" font-size="14.00">a</text> </g> <!-- Scope1_1->Phi_a18 --> <g id="edge16" class="edge"> <title>Scope1_1:Scope1_1_a->Phi_a18</title> -<path fill="none" stroke="cornflowerblue" stroke-dasharray="5,2" d="M204,-53C204,-64.37 201.14,-76.5 197.77,-86.87"/> -<polygon fill="cornflowerblue" stroke="cornflowerblue" points="194.38,-85.95 194.31,-96.54 200.97,-88.3 194.38,-85.95"/> +<path fill="none" stroke="cornflowerblue" stroke-dasharray="5,2" d="M119,-53C119,-63.75 119,-75.58 119,-85.87"/> +<polygon fill="cornflowerblue" stroke="cornflowerblue" points="115.5,-85.93 119,-95.93 122.5,-85.93 115.5,-85.93"/> </g> </g> </svg> diff --git a/chapter05/docs/05-graph3.gv b/chapter05/docs/05-graph3.gv index 59a8a3e2..7e049c9c 100644 --- a/chapter05/docs/05-graph3.gv +++ b/chapter05/docs/05-graph3.gv @@ -9,7 +9,6 @@ else { } #showGraph; return a; - */ rankdir=BT; ordering="in"; @@ -48,20 +47,20 @@ return a; { rank=same; Region17;Phi_a18;} } edge [ fontname=Helvetica, fontsize=8 ]; - Stop3 -> Return19[taillabel=0; color=red]; + Stop3 -> Return19[taillabel=0 color=red]; EQNode8 -> Start2:p1[taillabel=1]; EQNode8 -> Con_7[taillabel=2]; - If9 -> Start2:p0[taillabel=0; color=red]; + If9 -> Start2:p0[taillabel=0 color=red]; If9 -> EQNode8[taillabel=1]; Add14 -> Start2:p1[taillabel=1]; Add14 -> Con_13[taillabel=2]; Sub16 -> Start2:p1[taillabel=1]; Sub16 -> Con_15[taillabel=2]; - Region17 -> If9:p0[taillabel=1; color=red]; - Region17 -> If9:p1[taillabel=2; color=red]; - Region17 -> Phi_a18 [style=invis] + Region17 -> If9:p0[taillabel=1 color=red]; + Region17 -> If9:p1[taillabel=2 color=red]; + Phi_a18 -> Region17 [style=dotted taillabel=0]; Phi_a18 -> Add14[taillabel=1]; Phi_a18 -> Sub16[taillabel=2]; - Return19 -> Region17[taillabel=0; color=red]; + Return19 -> Region17[taillabel=0 color=red]; Return19 -> Phi_a18[taillabel=1]; -} +}
\ No newline at end of file diff --git a/chapter05/docs/05-graph3.svg b/chapter05/docs/05-graph3.svg index 5b6f0c86..855fdc2c 100644 --- a/chapter05/docs/05-graph3.svg +++ b/chapter05/docs/05-graph3.svg @@ -16,195 +16,201 @@ <!-- Start2 --> <g id="node1" class="node"> <title>Start2</title> -<polygon fill="yellow" stroke="transparent" points="97,-439 97,-464 178,-464 178,-439 97,-439"/> -<polygon fill="none" stroke="black" points="97,-439 97,-464 178,-464 178,-439 97,-439"/> -<text text-anchor="start" x="119" y="-447.8" font-family="Times,serif" font-size="14.00">Start</text> -<polygon fill="none" stroke="black" points="97,-408 97,-439 178,-439 178,-408 97,-408"/> -<polygon fill="yellow" stroke="transparent" points="102,-413 102,-434 142,-434 142,-413 102,-413"/> -<polygon fill="none" stroke="black" points="102,-413 102,-434 142,-434 142,-413 102,-413"/> -<text text-anchor="start" x="105" y="-419.8" font-family="Times,serif" font-size="14.00">$ctrl</text> -<polygon fill="none" stroke="black" points="142,-413 142,-434 173,-434 173,-413 142,-413"/> -<text text-anchor="start" x="145" y="-419.8" font-family="Times,serif" font-size="14.00">arg</text> +<polygon fill="yellow" stroke="transparent" points="113,-439 113,-464 194,-464 194,-439 113,-439"/> +<polygon fill="none" stroke="black" points="113,-439 113,-464 194,-464 194,-439 113,-439"/> +<text text-anchor="start" x="135" y="-447.8" font-family="Times,serif" font-size="14.00">Start</text> +<polygon fill="none" stroke="black" points="113,-408 113,-439 194,-439 194,-408 113,-408"/> +<polygon fill="yellow" stroke="transparent" points="118,-413 118,-434 158,-434 158,-413 118,-413"/> +<polygon fill="none" stroke="black" points="118,-413 118,-434 158,-434 158,-413 118,-413"/> +<text text-anchor="start" x="121" y="-419.8" font-family="Times,serif" font-size="14.00">$ctrl</text> +<polygon fill="none" stroke="black" points="158,-413 158,-434 189,-434 189,-413 158,-413"/> +<text text-anchor="start" x="161" y="-419.8" font-family="Times,serif" font-size="14.00">arg</text> </g> <!-- Stop3 --> <g id="node2" class="node"> <title>Stop3</title> -<polygon fill="yellow" stroke="black" points="157,-52 103,-52 103,-16 157,-16 157,-52"/> -<text text-anchor="middle" x="130" y="-30.3" font-family="Times,serif" font-size="14.00">Stop</text> +<polygon fill="yellow" stroke="black" points="185,-52 131,-52 131,-16 185,-16 185,-52"/> +<text text-anchor="middle" x="158" y="-30.3" font-family="Times,serif" font-size="14.00">Stop</text> </g> <!-- Return19 --> <g id="node12" class="node"> <title>Return19</title> -<polygon fill="yellow" stroke="black" points="163,-124 97,-124 97,-88 163,-88 163,-124"/> -<text text-anchor="middle" x="130" y="-102.3" font-family="Times,serif" font-size="14.00">Return</text> +<polygon fill="yellow" stroke="black" points="191,-124 125,-124 125,-88 191,-88 191,-124"/> +<text text-anchor="middle" x="158" y="-102.3" font-family="Times,serif" font-size="14.00">Return</text> </g> <!-- Stop3->Return19 --> <g id="edge1" class="edge"> <title>Stop3->Return19</title> -<path fill="none" stroke="red" d="M130,-52.3C130,-60.02 130,-69.29 130,-77.89"/> -<polygon fill="red" stroke="red" points="126.5,-77.9 130,-87.9 133.5,-77.9 126.5,-77.9"/> -<text text-anchor="middle" x="127" y="-54.9" font-family="Helvetica,sans-Serif" font-size="8.00">0</text> +<path fill="none" stroke="red" d="M158,-52.3C158,-60.02 158,-69.29 158,-77.89"/> +<polygon fill="red" stroke="red" points="154.5,-77.9 158,-87.9 161.5,-77.9 154.5,-77.9"/> +<text text-anchor="middle" x="155" y="-54.9" font-family="Helvetica,sans-Serif" font-size="8.00">0</text> </g> <!-- Con_7 --> <g id="node3" class="node"> <title>Con_7</title> -<ellipse fill="none" stroke="black" cx="43" cy="-436" rx="27" ry="18"/> -<text text-anchor="middle" x="43" y="-432.3" font-family="Times,serif" font-size="14.00">#1</text> +<ellipse fill="none" stroke="black" cx="247" cy="-436" rx="27" ry="18"/> +<text text-anchor="middle" x="247" y="-432.3" font-family="Times,serif" font-size="14.00">#1</text> </g> <!-- EQNode8 --> <g id="node4" class="node"> <title>EQNode8</title> -<ellipse fill="none" stroke="black" cx="63" cy="-350" rx="27" ry="18"/> -<text text-anchor="middle" x="63" y="-346.3" font-family="Times,serif" font-size="14.00">==</text> +<ellipse fill="none" stroke="black" cx="247" cy="-350" rx="27" ry="18"/> +<text text-anchor="middle" x="247" y="-346.3" font-family="Times,serif" font-size="14.00">==</text> </g> <!-- EQNode8->Start2 --> <g id="edge2" class="edge"> <title>EQNode8->Start2:p1</title> -<path fill="none" stroke="black" d="M85.51,-360.31C108.56,-370.43 142.57,-387.19 154.05,-402.35"/> -<polygon fill="black" stroke="black" points="150.97,-404.07 158,-412 157.45,-401.42 150.97,-404.07"/> -<text text-anchor="middle" x="88.51" y="-362.91" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> +<path fill="none" stroke="black" d="M236.57,-366.62C225.76,-382.5 208.98,-406.28 198.26,-417.17"/> +<polygon fill="black" stroke="black" points="196.15,-414.37 190,-423 200.19,-420.09 196.15,-414.37"/> +<text text-anchor="middle" x="233.57" y="-369.22" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> </g> <!-- EQNode8->Con_7 --> <g id="edge3" class="edge"> <title>EQNode8->Con_7</title> -<path fill="none" stroke="black" d="M58.95,-368C56.21,-379.5 52.54,-394.93 49.41,-408.08"/> -<polygon fill="black" stroke="black" points="45.95,-407.49 47.04,-418.03 52.76,-409.11 45.95,-407.49"/> -<text text-anchor="middle" x="55.95" y="-370.6" font-family="Helvetica,sans-Serif" font-size="8.00">2</text> +<path fill="none" stroke="black" d="M247,-368.4C247,-379.74 247,-394.77 247,-407.68"/> +<polygon fill="black" stroke="black" points="243.5,-407.9 247,-417.9 250.5,-407.9 243.5,-407.9"/> +<text text-anchor="middle" x="244" y="-371" font-family="Helvetica,sans-Serif" font-size="8.00">2</text> </g> <!-- If9 --> <g id="node5" class="node"> <title>If9</title> -<polygon fill="yellow" stroke="transparent" points="24,-267 24,-292 118,-292 118,-267 24,-267"/> -<polygon fill="none" stroke="black" points="24,-267 24,-292 118,-292 118,-267 24,-267"/> -<text text-anchor="start" x="65.5" y="-275.8" font-family="Times,serif" font-size="14.00">If</text> -<polygon fill="none" stroke="black" points="24,-236 24,-267 118,-267 118,-236 24,-236"/> -<polygon fill="yellow" stroke="transparent" points="29,-241 29,-262 69,-262 69,-241 29,-241"/> -<polygon fill="none" stroke="black" points="29,-241 29,-262 69,-262 69,-241 29,-241"/> -<text text-anchor="start" x="32" y="-247.8" font-family="Times,serif" font-size="14.00">True</text> -<polygon fill="yellow" stroke="transparent" points="69,-241 69,-262 113,-262 113,-241 69,-241"/> -<polygon fill="none" stroke="black" points="69,-241 69,-262 113,-262 113,-241 69,-241"/> -<text text-anchor="start" x="72" y="-247.8" font-family="Times,serif" font-size="14.00">False</text> +<polygon fill="yellow" stroke="transparent" points="172,-267 172,-292 266,-292 266,-267 172,-267"/> +<polygon fill="none" stroke="black" points="172,-267 172,-292 266,-292 266,-267 172,-267"/> +<text text-anchor="start" x="213.5" y="-275.8" font-family="Times,serif" font-size="14.00">If</text> +<polygon fill="none" stroke="black" points="172,-236 172,-267 266,-267 266,-236 172,-236"/> +<polygon fill="yellow" stroke="transparent" points="177,-241 177,-262 217,-262 217,-241 177,-241"/> +<polygon fill="none" stroke="black" points="177,-241 177,-262 217,-262 217,-241 177,-241"/> +<text text-anchor="start" x="180" y="-247.8" font-family="Times,serif" font-size="14.00">True</text> +<polygon fill="yellow" stroke="transparent" points="217,-241 217,-262 261,-262 261,-241 217,-241"/> +<polygon fill="none" stroke="black" points="217,-241 217,-262 261,-262 261,-241 217,-241"/> +<text text-anchor="start" x="220" y="-247.8" font-family="Times,serif" font-size="14.00">False</text> </g> <!-- If9->Start2 --> <g id="edge4" class="edge"> <title>If9->Start2:p0</title> -<path fill="none" stroke="red" d="M42.97,-296.24C27.91,-316.97 14.73,-344.58 27,-368 40.05,-392.9 56.78,-386.79 79,-404 85.54,-409.07 87.43,-415.44 91.34,-419.37"/> -<polygon fill="red" stroke="red" points="90.41,-422.76 101,-423 92.87,-416.2 90.41,-422.76"/> -<text text-anchor="middle" x="39.97" y="-298.84" font-family="Helvetica,sans-Serif" font-size="8.00">0</text> +<path fill="none" stroke="red" d="M210.31,-296.18C203.59,-317.4 193.07,-345.57 179,-368 166.9,-387.28 145.68,-386.25 139.64,-402.02"/> +<polygon fill="red" stroke="red" points="136.17,-401.56 138,-412 143.08,-402.7 136.17,-401.56"/> +<text text-anchor="middle" x="207.31" y="-298.78" font-family="Helvetica,sans-Serif" font-size="8.00">0</text> </g> <!-- If9->EQNode8 --> <g id="edge5" class="edge"> <title>If9->EQNode8</title> -<path fill="none" stroke="black" d="M68.02,-296.28C67.23,-304.58 66.38,-313.48 65.61,-321.56"/> -<polygon fill="black" stroke="black" points="62.12,-321.31 64.66,-331.6 69.09,-321.97 62.12,-321.31"/> -<text text-anchor="middle" x="65.02" y="-298.88" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> +<path fill="none" stroke="black" d="M229.43,-296.28C232.3,-304.9 235.39,-314.17 238.16,-322.49"/> +<polygon fill="black" stroke="black" points="234.87,-323.69 241.36,-332.07 241.51,-321.48 234.87,-323.69"/> +<text text-anchor="middle" x="226.43" y="-298.88" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> </g> <!-- Con_13 --> <g id="node6" class="node"> <title>Con_13</title> -<ellipse fill="none" stroke="black" cx="247" cy="-350" rx="27" ry="18"/> -<text text-anchor="middle" x="247" y="-346.3" font-family="Times,serif" font-size="14.00">#2</text> +<ellipse fill="none" stroke="black" cx="43" cy="-350" rx="27" ry="18"/> +<text text-anchor="middle" x="43" y="-346.3" font-family="Times,serif" font-size="14.00">#2</text> </g> <!-- Add14 --> <g id="node7" class="node"> <title>Add14</title> -<ellipse fill="none" stroke="black" cx="243" cy="-264" rx="27" ry="18"/> -<text text-anchor="middle" x="243" y="-260.3" font-family="Times,serif" font-size="14.00">+</text> +<ellipse fill="none" stroke="black" cx="47" cy="-264" rx="27" ry="18"/> +<text text-anchor="middle" x="47" y="-260.3" font-family="Times,serif" font-size="14.00">+</text> </g> <!-- Add14->Start2 --> <g id="edge6" class="edge"> <title>Add14->Start2:p1</title> -<path fill="none" stroke="black" d="M235.08,-281.55C223.08,-306.49 200.67,-352.43 191,-368 180.22,-385.36 164.4,-387.36 159.5,-401.83"/> -<polygon fill="black" stroke="black" points="156,-401.6 158,-412 162.92,-402.62 156,-401.6"/> -<text text-anchor="middle" x="232.08" y="-284.15" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> +<path fill="none" stroke="black" d="M54.69,-281.49C67.53,-308.81 92.56,-361.14 99,-368 122.77,-393.31 164.37,-377.46 172.57,-402.01"/> +<polygon fill="black" stroke="black" points="169.12,-402.6 174,-412 176.05,-401.61 169.12,-402.6"/> +<text text-anchor="middle" x="51.69" y="-284.09" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> </g> <!-- Add14->Con_13 --> <g id="edge7" class="edge"> <title>Add14->Con_13</title> -<path fill="none" stroke="black" d="M243.81,-282C244.35,-293.31 245.07,-308.42 245.69,-321.43"/> -<polygon fill="black" stroke="black" points="242.21,-321.92 246.18,-331.74 249.2,-321.58 242.21,-321.92"/> -<text text-anchor="middle" x="240.81" y="-284.6" font-family="Helvetica,sans-Serif" font-size="8.00">2</text> +<path fill="none" stroke="black" d="M46.19,-282C45.65,-293.31 44.93,-308.42 44.31,-321.43"/> +<polygon fill="black" stroke="black" points="40.8,-321.58 43.82,-331.74 47.79,-321.92 40.8,-321.58"/> +<text text-anchor="middle" x="43.19" y="-284.6" font-family="Helvetica,sans-Serif" font-size="8.00">2</text> </g> <!-- Con_15 --> <g id="node8" class="node"> <title>Con_15</title> -<ellipse fill="none" stroke="black" cx="155" cy="-350" rx="27" ry="18"/> -<text text-anchor="middle" x="155" y="-346.3" font-family="Times,serif" font-size="14.00">#3</text> +<ellipse fill="none" stroke="black" cx="135" cy="-350" rx="27" ry="18"/> +<text text-anchor="middle" x="135" y="-346.3" font-family="Times,serif" font-size="14.00">#3</text> </g> <!-- Sub16 --> <g id="node9" class="node"> <title>Sub16</title> -<ellipse fill="none" stroke="black" cx="171" cy="-264" rx="27" ry="18"/> -<text text-anchor="middle" x="171" y="-260.3" font-family="Times,serif" font-size="14.00">-</text> +<ellipse fill="none" stroke="black" cx="119" cy="-264" rx="27" ry="18"/> +<text text-anchor="middle" x="119" y="-260.3" font-family="Times,serif" font-size="14.00">-</text> </g> <!-- Sub16->Start2 --> <g id="edge8" class="edge"> <title>Sub16->Start2:p1</title> -<path fill="none" stroke="black" d="M155.57,-278.95C143,-291.44 126.2,-310.97 119,-332 113.82,-347.14 113.32,-353.04 119,-368 126.82,-388.61 149.21,-387.16 156.01,-401.9"/> -<polygon fill="black" stroke="black" points="152.64,-402.86 158,-412 159.5,-401.51 152.64,-402.86"/> -<text text-anchor="middle" x="152.57" y="-281.55" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> +<path fill="none" stroke="black" d="M134.23,-279.02C146.68,-291.55 163.4,-311.1 171,-332 181.92,-362.04 175.64,-373.96 174.25,-401.87"/> +<polygon fill="black" stroke="black" points="170.75,-401.92 174,-412 177.75,-402.09 170.75,-401.92"/> +<text text-anchor="middle" x="131.23" y="-281.62" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> </g> <!-- Sub16->Con_15 --> <g id="edge9" class="edge"> <title>Sub16->Con_15</title> -<path fill="none" stroke="black" d="M167.76,-282C165.57,-293.5 162.63,-308.93 160.13,-322.08"/> -<polygon fill="black" stroke="black" points="156.67,-321.55 158.23,-332.03 163.54,-322.86 156.67,-321.55"/> -<text text-anchor="middle" x="164.76" y="-284.6" font-family="Helvetica,sans-Serif" font-size="8.00">2</text> +<path fill="none" stroke="black" d="M122.24,-282C124.43,-293.5 127.37,-308.93 129.87,-322.08"/> +<polygon fill="black" stroke="black" points="126.46,-322.86 131.77,-332.03 133.33,-321.55 126.46,-322.86"/> +<text text-anchor="middle" x="119.24" y="-284.6" font-family="Helvetica,sans-Serif" font-size="8.00">2</text> </g> <!-- Region17 --> <g id="node10" class="node"> <title>Region17</title> -<polygon fill="yellow" stroke="black" points="124,-196 58,-196 58,-160 124,-160 124,-196"/> -<text text-anchor="middle" x="91" y="-174.3" font-family="Times,serif" font-size="14.00">Region</text> +<polygon fill="yellow" stroke="black" points="230,-196 164,-196 164,-160 230,-160 230,-196"/> +<text text-anchor="middle" x="197" y="-174.3" font-family="Times,serif" font-size="14.00">Region</text> </g> <!-- Region17->If9 --> <g id="edge10" class="edge"> <title>Region17->If9:p0</title> -<path fill="none" stroke="red" d="M70.98,-196.12C62.36,-205.06 53.52,-216.84 50.29,-229.84"/> -<polygon fill="red" stroke="red" points="46.78,-229.64 49,-240 53.73,-230.52 46.78,-229.64"/> -<text text-anchor="middle" x="67.98" y="-198.72" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> +<path fill="none" stroke="red" d="M197,-196.09C197,-205.55 197,-217.77 197,-229.69"/> +<polygon fill="red" stroke="red" points="193.5,-230 197,-240 200.5,-230 193.5,-230"/> +<text text-anchor="middle" x="194" y="-198.69" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> </g> <!-- Region17->If9 --> <g id="edge11" class="edge"> <title>Region17->If9:p1</title> -<path fill="none" stroke="red" d="M91,-196.09C91,-205.55 91,-217.77 91,-229.69"/> -<polygon fill="red" stroke="red" points="87.5,-230 91,-240 94.5,-230 87.5,-230"/> -<text text-anchor="middle" x="88" y="-198.69" font-family="Helvetica,sans-Serif" font-size="8.00">2</text> +<path fill="none" stroke="red" d="M217.02,-196.12C225.64,-205.06 234.48,-216.84 237.71,-229.84"/> +<polygon fill="red" stroke="red" points="234.27,-230.52 239,-240 241.22,-229.64 234.27,-230.52"/> +<text text-anchor="middle" x="214.02" y="-198.72" font-family="Helvetica,sans-Serif" font-size="8.00">2</text> </g> <!-- Phi_a18 --> <g id="node11" class="node"> <title>Phi_a18</title> -<ellipse fill="lightyellow" stroke="black" cx="170" cy="-178" rx="27" ry="18"/> -<text text-anchor="middle" x="170" y="-174.3" font-family="Times,serif" font-size="14.00">φ_a</text> +<ellipse fill="lightyellow" stroke="black" cx="119" cy="-178" rx="27" ry="18"/> +<text text-anchor="middle" x="119" y="-174.3" font-family="Times,serif" font-size="14.00">φ_a</text> </g> -<!-- Region17->Phi_a18 --> <!-- Phi_a18->Add14 --> <g id="edge13" class="edge"> <title>Phi_a18->Add14</title> -<path fill="none" stroke="black" d="M183.05,-194.02C194.26,-206.92 210.59,-225.71 223.38,-240.42"/> -<polygon fill="black" stroke="black" points="220.86,-242.86 230.06,-248.11 226.14,-238.27 220.86,-242.86"/> -<text text-anchor="middle" x="180.05" y="-196.62" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> +<path fill="none" stroke="black" d="M106.13,-194.02C95.07,-206.92 78.96,-225.71 66.35,-240.42"/> +<polygon fill="black" stroke="black" points="63.61,-238.24 59.76,-248.11 68.93,-242.8 63.61,-238.24"/> +<text text-anchor="middle" x="103.13" y="-196.62" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> </g> <!-- Phi_a18->Sub16 --> <g id="edge14" class="edge"> <title>Phi_a18->Sub16</title> -<path fill="none" stroke="black" d="M170.21,-196.4C170.34,-207.74 170.52,-222.77 170.67,-235.68"/> -<polygon fill="black" stroke="black" points="167.18,-235.95 170.8,-245.9 174.18,-235.86 167.18,-235.95"/> -<text text-anchor="middle" x="167.21" y="-199" font-family="Helvetica,sans-Serif" font-size="8.00">2</text> +<path fill="none" stroke="black" d="M119,-196.4C119,-207.74 119,-222.77 119,-235.68"/> +<polygon fill="black" stroke="black" points="115.5,-235.9 119,-245.9 122.5,-235.9 115.5,-235.9"/> +<text text-anchor="middle" x="116" y="-199" font-family="Helvetica,sans-Serif" font-size="8.00">2</text> +</g> +<!-- Phi_a18->Region17 --> +<g id="edge12" class="edge"> +<title>Phi_a18->Region17</title> +<path fill="none" stroke="black" stroke-dasharray="1,5" d="M146.12,-178C148.58,-178 151.04,-178 153.5,-178"/> +<polygon fill="black" stroke="black" points="153.61,-181.5 163.61,-178 153.61,-174.5 153.61,-181.5"/> +<text text-anchor="middle" x="149.12" y="-171.6" font-family="Helvetica,sans-Serif" font-size="8.00">0</text> </g> <!-- Return19->Region17 --> <g id="edge15" class="edge"> <title>Return19->Region17</title> -<path fill="none" stroke="red" d="M120.36,-124.3C115.87,-132.36 110.44,-142.11 105.48,-151.02"/> -<polygon fill="red" stroke="red" points="102.34,-149.46 100.53,-159.9 108.45,-152.86 102.34,-149.46"/> -<text text-anchor="middle" x="117.36" y="-126.9" font-family="Helvetica,sans-Serif" font-size="8.00">0</text> +<path fill="none" stroke="red" d="M167.64,-124.3C172.13,-132.36 177.56,-142.11 182.52,-151.02"/> +<polygon fill="red" stroke="red" points="179.55,-152.86 187.47,-159.9 185.66,-149.46 179.55,-152.86"/> +<text text-anchor="middle" x="164.64" y="-126.9" font-family="Helvetica,sans-Serif" font-size="8.00">0</text> </g> <!-- Return19->Phi_a18 --> <g id="edge16" class="edge"> <title>Return19->Phi_a18</title> -<path fill="none" stroke="black" d="M139.89,-124.3C144.68,-132.68 150.52,-142.9 155.77,-152.1"/> -<polygon fill="black" stroke="black" points="152.77,-153.91 160.77,-160.86 158.85,-150.44 152.77,-153.91"/> -<text text-anchor="middle" x="136.89" y="-126.9" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> +<path fill="none" stroke="black" d="M148.36,-124.3C143.69,-132.68 138,-142.9 132.87,-152.1"/> +<polygon fill="black" stroke="black" points="129.8,-150.42 127.99,-160.86 135.92,-153.82 129.8,-150.42"/> +<text text-anchor="middle" x="145.36" y="-126.9" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> </g> </g> </svg> diff --git a/chapter05/docs/05-graph4.gv b/chapter05/docs/05-graph4.gv new file mode 100644 index 00000000..ac3dcdd7 --- /dev/null +++ b/chapter05/docs/05-graph4.gv @@ -0,0 +1,63 @@ +digraph chapter05 { +/* +int a=arg==2; +if( arg==1 ) +{ + a=arg==3; +} +return a; +*/ + rankdir=BT; + ordering="in"; + concentrate="true"; + subgraph cluster_Nodes { + Start2 [ shape=plaintext label=< + <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4"> + <TR><TD BGCOLOR="yellow">Start</TD></TR> + <TR><TD> + <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0"> + <TR><TD PORT="p0" BGCOLOR="yellow">$ctrl</TD><TD PORT="p1">arg</TD></TR> + </TABLE> + </TD></TR> + </TABLE>> + ]; + Stop3 [ shape=box style=filled fillcolor=yellow label="Stop" ]; + Con_6 [ label="#2" ]; + EQNode7 [ label="==" ]; + Con_8 [ label="#1" ]; + EQNode9 [ label="==" ]; + If10 [ shape=plaintext label=< + <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4"> + <TR><TD BGCOLOR="yellow">If</TD></TR> + <TR><TD> + <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0"> + <TR><TD PORT="p0" BGCOLOR="yellow">True</TD><TD PORT="p1" BGCOLOR="yellow">False</TD></TR> + </TABLE> + </TD></TR> + </TABLE>> + ]; + Con_14 [ label="#3" ]; + EQNode15 [ label="==" ]; + Region16 [ shape=box style=filled fillcolor=yellow label="Region" ]; + Phi_a17 [ style=filled fillcolor=lightyellow label="φ_a" ]; + Return18 [ shape=box style=filled fillcolor=yellow label="Return" ]; + { rank=same; Region16;Phi_a17;} + } + edge [ fontname=Helvetica, fontsize=8 ]; + Stop3 -> Return18[taillabel=0 color=red]; + EQNode7 -> Start2:p1[taillabel=1]; + EQNode7 -> Con_6[taillabel=2]; + EQNode9 -> Start2:p1[taillabel=1]; + EQNode9 -> Con_8[taillabel=2]; + If10 -> Start2:p0[taillabel=0 color=red]; + If10 -> EQNode9[taillabel=1]; + EQNode15 -> Start2:p1[taillabel=1]; + EQNode15 -> Con_14[taillabel=2]; + Region16 -> If10:p0[taillabel=1 color=red]; + Region16 -> If10:p1[taillabel=2 color=red]; + Phi_a17 -> Region16 [style=dotted taillabel=0]; + Phi_a17 -> EQNode15[taillabel=1]; + Phi_a17 -> EQNode7[taillabel=2]; + Return18 -> Region16[taillabel=0 color=red]; + Return18 -> Phi_a17[taillabel=1]; +}
\ No newline at end of file diff --git a/chapter05/docs/05-graph4.svg b/chapter05/docs/05-graph4.svg new file mode 100644 index 00000000..3fcee500 --- /dev/null +++ b/chapter05/docs/05-graph4.svg @@ -0,0 +1,216 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" + "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<!-- Generated by graphviz version 2.43.0 (0) + --> +<!-- Title: chapter05 Pages: 1 --> +<svg width="298pt" height="492pt" + viewBox="0.00 0.00 298.00 492.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> +<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 488)"> +<title>chapter05</title> +<polygon fill="white" stroke="transparent" points="-4,4 -4,-488 294,-488 294,4 -4,4"/> +<g id="clust1" class="cluster"> +<title>cluster_Nodes</title> +<polygon fill="none" stroke="black" points="8,-8 8,-476 282,-476 282,-8 8,-8"/> +</g> +<!-- Start2 --> +<g id="node1" class="node"> +<title>Start2</title> +<polygon fill="yellow" stroke="transparent" points="113,-439 113,-464 194,-464 194,-439 113,-439"/> +<polygon fill="none" stroke="black" points="113,-439 113,-464 194,-464 194,-439 113,-439"/> +<text text-anchor="start" x="135" y="-447.8" font-family="Times,serif" font-size="14.00">Start</text> +<polygon fill="none" stroke="black" points="113,-408 113,-439 194,-439 194,-408 113,-408"/> +<polygon fill="yellow" stroke="transparent" points="118,-413 118,-434 158,-434 158,-413 118,-413"/> +<polygon fill="none" stroke="black" points="118,-413 118,-434 158,-434 158,-413 118,-413"/> +<text text-anchor="start" x="121" y="-419.8" font-family="Times,serif" font-size="14.00">$ctrl</text> +<polygon fill="none" stroke="black" points="158,-413 158,-434 189,-434 189,-413 158,-413"/> +<text text-anchor="start" x="161" y="-419.8" font-family="Times,serif" font-size="14.00">arg</text> +</g> +<!-- Stop3 --> +<g id="node2" class="node"> +<title>Stop3</title> +<polygon fill="yellow" stroke="black" points="185,-52 131,-52 131,-16 185,-16 185,-52"/> +<text text-anchor="middle" x="158" y="-30.3" font-family="Times,serif" font-size="14.00">Stop</text> +</g> +<!-- Return18 --> +<g id="node12" class="node"> +<title>Return18</title> +<polygon fill="yellow" stroke="black" points="191,-124 125,-124 125,-88 191,-88 191,-124"/> +<text text-anchor="middle" x="158" y="-102.3" font-family="Times,serif" font-size="14.00">Return</text> +</g> +<!-- Stop3->Return18 --> +<g id="edge1" class="edge"> +<title>Stop3->Return18</title> +<path fill="none" stroke="red" d="M158,-52.3C158,-60.02 158,-69.29 158,-77.89"/> +<polygon fill="red" stroke="red" points="154.5,-77.9 158,-87.9 161.5,-77.9 154.5,-77.9"/> +<text text-anchor="middle" x="155" y="-54.9" font-family="Helvetica,sans-Serif" font-size="8.00">0</text> +</g> +<!-- Con_6 --> +<g id="node3" class="node"> +<title>Con_6</title> +<ellipse fill="none" stroke="black" cx="43" cy="-350" rx="27" ry="18"/> +<text text-anchor="middle" x="43" y="-346.3" font-family="Times,serif" font-size="14.00">#2</text> +</g> +<!-- EQNode7 --> +<g id="node4" class="node"> +<title>EQNode7</title> +<ellipse fill="none" stroke="black" cx="47" cy="-264" rx="27" ry="18"/> +<text text-anchor="middle" x="47" y="-260.3" font-family="Times,serif" font-size="14.00">==</text> +</g> +<!-- EQNode7->Start2 --> +<g id="edge2" class="edge"> +<title>EQNode7->Start2:p1</title> +<path fill="none" stroke="black" d="M54.69,-281.49C67.53,-308.81 92.56,-361.14 99,-368 122.77,-393.31 164.37,-377.46 172.57,-402.01"/> +<polygon fill="black" stroke="black" points="169.12,-402.6 174,-412 176.05,-401.61 169.12,-402.6"/> +<text text-anchor="middle" x="51.69" y="-284.09" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> +</g> +<!-- EQNode7->Con_6 --> +<g id="edge3" class="edge"> +<title>EQNode7->Con_6</title> +<path fill="none" stroke="black" d="M46.19,-282C45.65,-293.31 44.93,-308.42 44.31,-321.43"/> +<polygon fill="black" stroke="black" points="40.8,-321.58 43.82,-331.74 47.79,-321.92 40.8,-321.58"/> +<text text-anchor="middle" x="43.19" y="-284.6" font-family="Helvetica,sans-Serif" font-size="8.00">2</text> +</g> +<!-- Con_8 --> +<g id="node5" class="node"> +<title>Con_8</title> +<ellipse fill="none" stroke="black" cx="247" cy="-436" rx="27" ry="18"/> +<text text-anchor="middle" x="247" y="-432.3" font-family="Times,serif" font-size="14.00">#1</text> +</g> +<!-- EQNode9 --> +<g id="node6" class="node"> +<title>EQNode9</title> +<ellipse fill="none" stroke="black" cx="247" cy="-350" rx="27" ry="18"/> +<text text-anchor="middle" x="247" y="-346.3" font-family="Times,serif" font-size="14.00">==</text> +</g> +<!-- EQNode9->Start2 --> +<g id="edge4" class="edge"> +<title>EQNode9->Start2:p1</title> +<path fill="none" stroke="black" d="M236.57,-366.62C225.76,-382.5 208.98,-406.28 198.26,-417.17"/> +<polygon fill="black" stroke="black" points="196.15,-414.37 190,-423 200.19,-420.09 196.15,-414.37"/> +<text text-anchor="middle" x="233.57" y="-369.22" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> +</g> +<!-- EQNode9->Con_8 --> +<g id="edge5" class="edge"> +<title>EQNode9->Con_8</title> +<path fill="none" stroke="black" d="M247,-368.4C247,-379.74 247,-394.77 247,-407.68"/> +<polygon fill="black" stroke="black" points="243.5,-407.9 247,-417.9 250.5,-407.9 243.5,-407.9"/> +<text text-anchor="middle" x="244" y="-371" font-family="Helvetica,sans-Serif" font-size="8.00">2</text> +</g> +<!-- If10 --> +<g id="node7" class="node"> +<title>If10</title> +<polygon fill="yellow" stroke="transparent" points="172,-267 172,-292 266,-292 266,-267 172,-267"/> +<polygon fill="none" stroke="black" points="172,-267 172,-292 266,-292 266,-267 172,-267"/> +<text text-anchor="start" x="213.5" y="-275.8" font-family="Times,serif" font-size="14.00">If</text> +<polygon fill="none" stroke="black" points="172,-236 172,-267 266,-267 266,-236 172,-236"/> +<polygon fill="yellow" stroke="transparent" points="177,-241 177,-262 217,-262 217,-241 177,-241"/> +<polygon fill="none" stroke="black" points="177,-241 177,-262 217,-262 217,-241 177,-241"/> +<text text-anchor="start" x="180" y="-247.8" font-family="Times,serif" font-size="14.00">True</text> +<polygon fill="yellow" stroke="transparent" points="217,-241 217,-262 261,-262 261,-241 217,-241"/> +<polygon fill="none" stroke="black" points="217,-241 217,-262 261,-262 261,-241 217,-241"/> +<text text-anchor="start" x="220" y="-247.8" font-family="Times,serif" font-size="14.00">False</text> +</g> +<!-- If10->Start2 --> +<g id="edge6" class="edge"> +<title>If10->Start2:p0</title> +<path fill="none" stroke="red" d="M210.31,-296.18C203.59,-317.4 193.07,-345.57 179,-368 166.9,-387.28 145.68,-386.25 139.64,-402.02"/> +<polygon fill="red" stroke="red" points="136.17,-401.56 138,-412 143.08,-402.7 136.17,-401.56"/> +<text text-anchor="middle" x="207.31" y="-298.78" font-family="Helvetica,sans-Serif" font-size="8.00">0</text> +</g> +<!-- If10->EQNode9 --> +<g id="edge7" class="edge"> +<title>If10->EQNode9</title> +<path fill="none" stroke="black" d="M229.43,-296.28C232.3,-304.9 235.39,-314.17 238.16,-322.49"/> +<polygon fill="black" stroke="black" points="234.87,-323.69 241.36,-332.07 241.51,-321.48 234.87,-323.69"/> +<text text-anchor="middle" x="226.43" y="-298.88" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> +</g> +<!-- Con_14 --> +<g id="node8" class="node"> +<title>Con_14</title> +<ellipse fill="none" stroke="black" cx="135" cy="-350" rx="27" ry="18"/> +<text text-anchor="middle" x="135" y="-346.3" font-family="Times,serif" font-size="14.00">#3</text> +</g> +<!-- EQNode15 --> +<g id="node9" class="node"> +<title>EQNode15</title> +<ellipse fill="none" stroke="black" cx="119" cy="-264" rx="27" ry="18"/> +<text text-anchor="middle" x="119" y="-260.3" font-family="Times,serif" font-size="14.00">==</text> +</g> +<!-- EQNode15->Start2 --> +<g id="edge8" class="edge"> +<title>EQNode15->Start2:p1</title> +<path fill="none" stroke="black" d="M134.23,-279.02C146.68,-291.55 163.4,-311.1 171,-332 181.92,-362.04 175.64,-373.96 174.25,-401.87"/> +<polygon fill="black" stroke="black" points="170.75,-401.92 174,-412 177.75,-402.09 170.75,-401.92"/> +<text text-anchor="middle" x="131.23" y="-281.62" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> +</g> +<!-- EQNode15->Con_14 --> +<g id="edge9" class="edge"> +<title>EQNode15->Con_14</title> +<path fill="none" stroke="black" d="M122.24,-282C124.43,-293.5 127.37,-308.93 129.87,-322.08"/> +<polygon fill="black" stroke="black" points="126.46,-322.86 131.77,-332.03 133.33,-321.55 126.46,-322.86"/> +<text text-anchor="middle" x="119.24" y="-284.6" font-family="Helvetica,sans-Serif" font-size="8.00">2</text> +</g> +<!-- Region16 --> +<g id="node10" class="node"> +<title>Region16</title> +<polygon fill="yellow" stroke="black" points="230,-196 164,-196 164,-160 230,-160 230,-196"/> +<text text-anchor="middle" x="197" y="-174.3" font-family="Times,serif" font-size="14.00">Region</text> +</g> +<!-- Region16->If10 --> +<g id="edge10" class="edge"> +<title>Region16->If10:p0</title> +<path fill="none" stroke="red" d="M197,-196.09C197,-205.55 197,-217.77 197,-229.69"/> +<polygon fill="red" stroke="red" points="193.5,-230 197,-240 200.5,-230 193.5,-230"/> +<text text-anchor="middle" x="194" y="-198.69" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> +</g> +<!-- Region16->If10 --> +<g id="edge11" class="edge"> +<title>Region16->If10:p1</title> +<path fill="none" stroke="red" d="M217.02,-196.12C225.64,-205.06 234.48,-216.84 237.71,-229.84"/> +<polygon fill="red" stroke="red" points="234.27,-230.52 239,-240 241.22,-229.64 234.27,-230.52"/> +<text text-anchor="middle" x="214.02" y="-198.72" font-family="Helvetica,sans-Serif" font-size="8.00">2</text> +</g> +<!-- Phi_a17 --> +<g id="node11" class="node"> +<title>Phi_a17</title> +<ellipse fill="lightyellow" stroke="black" cx="119" cy="-178" rx="27" ry="18"/> +<text text-anchor="middle" x="119" y="-174.3" font-family="Times,serif" font-size="14.00">φ_a</text> +</g> +<!-- Phi_a17->EQNode7 --> +<g id="edge14" class="edge"> +<title>Phi_a17->EQNode7</title> +<path fill="none" stroke="black" d="M106.13,-194.02C95.07,-206.92 78.96,-225.71 66.35,-240.42"/> +<polygon fill="black" stroke="black" points="63.61,-238.24 59.76,-248.11 68.93,-242.8 63.61,-238.24"/> +<text text-anchor="middle" x="103.13" y="-196.62" font-family="Helvetica,sans-Serif" font-size="8.00">2</text> +</g> +<!-- Phi_a17->EQNode15 --> +<g id="edge13" class="edge"> +<title>Phi_a17->EQNode15</title> +<path fill="none" stroke="black" d="M119,-196.4C119,-207.74 119,-222.77 119,-235.68"/> +<polygon fill="black" stroke="black" points="115.5,-235.9 119,-245.9 122.5,-235.9 115.5,-235.9"/> +<text text-anchor="middle" x="116" y="-199" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> +</g> +<!-- Phi_a17->Region16 --> +<g id="edge12" class="edge"> +<title>Phi_a17->Region16</title> +<path fill="none" stroke="black" stroke-dasharray="1,5" d="M146.12,-178C148.58,-178 151.04,-178 153.5,-178"/> +<polygon fill="black" stroke="black" points="153.61,-181.5 163.61,-178 153.61,-174.5 153.61,-181.5"/> +<text text-anchor="middle" x="149.12" y="-171.6" font-family="Helvetica,sans-Serif" font-size="8.00">0</text> +</g> +<!-- Return18->Region16 --> +<g id="edge15" class="edge"> +<title>Return18->Region16</title> +<path fill="none" stroke="red" d="M167.64,-124.3C172.13,-132.36 177.56,-142.11 182.52,-151.02"/> +<polygon fill="red" stroke="red" points="179.55,-152.86 187.47,-159.9 185.66,-149.46 179.55,-152.86"/> +<text text-anchor="middle" x="164.64" y="-126.9" font-family="Helvetica,sans-Serif" font-size="8.00">0</text> +</g> +<!-- Return18->Phi_a17 --> +<g id="edge16" class="edge"> +<title>Return18->Phi_a17</title> +<path fill="none" stroke="black" d="M148.36,-124.3C143.69,-132.68 138,-142.9 132.87,-152.1"/> +<polygon fill="black" stroke="black" points="129.8,-150.42 127.99,-160.86 135.92,-153.82 129.8,-150.42"/> +<text text-anchor="middle" x="145.36" y="-126.9" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> +</g> +</g> +</svg> diff --git a/chapter05/docs/05-graph5.gv b/chapter05/docs/05-graph5.gv new file mode 100644 index 00000000..b6bfd5f2 --- /dev/null +++ b/chapter05/docs/05-graph5.gv @@ -0,0 +1,60 @@ +digraph chapter05 { +/* +int a=arg==2; +if( arg==1 ) +{ + a=arg==3; +} +return a; +*/ + rankdir=BT; + ordering="in"; + concentrate="true"; + subgraph cluster_Nodes { + Start2 [ shape=plaintext label=< + <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4"> + <TR><TD BGCOLOR="yellow">Start</TD></TR> + <TR><TD> + <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0"> + <TR><TD PORT="p0" BGCOLOR="yellow">$ctrl</TD><TD PORT="p1">arg</TD></TR> + </TABLE> + </TD></TR> + </TABLE>> + ]; + Stop3 [ shape=box style=filled fillcolor=yellow label="Stop" ]; + Con_6 [ label="#2" ]; + Con_8 [ label="#1" ]; + EQNode9 [ label="==" ]; + If10 [ shape=plaintext label=< + <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4"> + <TR><TD BGCOLOR="yellow">If</TD></TR> + <TR><TD> + <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0"> + <TR><TD PORT="p0" BGCOLOR="yellow">True</TD><TD PORT="p1" BGCOLOR="yellow">False</TD></TR> + </TABLE> + </TD></TR> + </TABLE>> + ]; + Con_14 [ label="#3" ]; + Region16 [ shape=box style=filled fillcolor=yellow label="Region" ]; + Phi_a19 [ style=filled fillcolor=lightyellow label="φ_a" ]; + EQNode20 [ label="==" ]; + Return21 [ shape=box style=filled fillcolor=yellow label="Return" ]; + { rank=same; Region16;Phi_a19;} + } + edge [ fontname=Helvetica, fontsize=8 ]; + Stop3 -> Return21[taillabel=0 color=red]; + EQNode9 -> Start2:p1[taillabel=1]; + EQNode9 -> Con_8[taillabel=2]; + If10 -> Start2:p0[taillabel=0 color=red]; + If10 -> EQNode9[taillabel=1]; + Region16 -> If10:p0[taillabel=1 color=red]; + Region16 -> If10:p1[taillabel=2 color=red]; + Phi_a19 -> Region16 [style=dotted taillabel=0]; + Phi_a19 -> Con_14[taillabel=1]; + Phi_a19 -> Con_6[taillabel=2]; + EQNode20 -> Start2:p1[taillabel=1]; + EQNode20 -> Phi_a19[taillabel=2]; + Return21 -> Region16[taillabel=0 color=red]; + Return21 -> EQNode20[taillabel=1]; +}
\ No newline at end of file diff --git a/chapter05/docs/05-graph5.svg b/chapter05/docs/05-graph5.svg new file mode 100644 index 00000000..4f6fa4bd --- /dev/null +++ b/chapter05/docs/05-graph5.svg @@ -0,0 +1,196 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" + "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<!-- Generated by graphviz version 2.43.0 (0) + --> +<!-- Title: chapter05 Pages: 1 --> +<svg width="314pt" height="564pt" + viewBox="0.00 0.00 314.00 564.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> +<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 560)"> +<title>chapter05</title> +<polygon fill="white" stroke="transparent" points="-4,4 -4,-560 310,-560 310,4 -4,4"/> +<g id="clust1" class="cluster"> +<title>cluster_Nodes</title> +<polygon fill="none" stroke="black" points="8,-8 8,-548 298,-548 298,-8 8,-8"/> +</g> +<!-- Start2 --> +<g id="node1" class="node"> +<title>Start2</title> +<polygon fill="yellow" stroke="transparent" points="97,-511 97,-536 178,-536 178,-511 97,-511"/> +<polygon fill="none" stroke="black" points="97,-511 97,-536 178,-536 178,-511 97,-511"/> +<text text-anchor="start" x="119" y="-519.8" font-family="Times,serif" font-size="14.00">Start</text> +<polygon fill="none" stroke="black" points="97,-480 97,-511 178,-511 178,-480 97,-480"/> +<polygon fill="yellow" stroke="transparent" points="102,-485 102,-506 142,-506 142,-485 102,-485"/> +<polygon fill="none" stroke="black" points="102,-485 102,-506 142,-506 142,-485 102,-485"/> +<text text-anchor="start" x="105" y="-491.8" font-family="Times,serif" font-size="14.00">$ctrl</text> +<polygon fill="none" stroke="black" points="142,-485 142,-506 173,-506 173,-485 142,-485"/> +<text text-anchor="start" x="145" y="-491.8" font-family="Times,serif" font-size="14.00">arg</text> +</g> +<!-- Stop3 --> +<g id="node2" class="node"> +<title>Stop3</title> +<polygon fill="yellow" stroke="black" points="148,-52 94,-52 94,-16 148,-16 148,-52"/> +<text text-anchor="middle" x="121" y="-30.3" font-family="Times,serif" font-size="14.00">Stop</text> +</g> +<!-- Return21 --> +<g id="node11" class="node"> +<title>Return21</title> +<polygon fill="yellow" stroke="black" points="154,-124 88,-124 88,-88 154,-88 154,-124"/> +<text text-anchor="middle" x="121" y="-102.3" font-family="Times,serif" font-size="14.00">Return</text> +</g> +<!-- Stop3->Return21 --> +<g id="edge1" class="edge"> +<title>Stop3->Return21</title> +<path fill="none" stroke="red" d="M121,-52.3C121,-60.02 121,-69.29 121,-77.89"/> +<polygon fill="red" stroke="red" points="117.5,-77.9 121,-87.9 124.5,-77.9 117.5,-77.9"/> +<text text-anchor="middle" x="118" y="-54.9" font-family="Helvetica,sans-Serif" font-size="8.00">0</text> +</g> +<!-- Con_6 --> +<g id="node3" class="node"> +<title>Con_6</title> +<ellipse fill="none" stroke="black" cx="263" cy="-336" rx="27" ry="18"/> +<text text-anchor="middle" x="263" y="-332.3" font-family="Times,serif" font-size="14.00">#2</text> +</g> +<!-- Con_8 --> +<g id="node4" class="node"> +<title>Con_8</title> +<ellipse fill="none" stroke="black" cx="43" cy="-508" rx="27" ry="18"/> +<text text-anchor="middle" x="43" y="-504.3" font-family="Times,serif" font-size="14.00">#1</text> +</g> +<!-- EQNode9 --> +<g id="node5" class="node"> +<title>EQNode9</title> +<ellipse fill="none" stroke="black" cx="71" cy="-422" rx="27" ry="18"/> +<text text-anchor="middle" x="71" y="-418.3" font-family="Times,serif" font-size="14.00">==</text> +</g> +<!-- EQNode9->Start2 --> +<g id="edge2" class="edge"> +<title>EQNode9->Start2:p1</title> +<path fill="none" stroke="black" d="M92.51,-433.05C113.44,-443.41 143.59,-460.03 154.16,-474.46"/> +<polygon fill="black" stroke="black" points="151.02,-476.03 158,-484 157.51,-473.42 151.02,-476.03"/> +<text text-anchor="middle" x="89.51" y="-435.65" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> +</g> +<!-- EQNode9->Con_8 --> +<g id="edge3" class="edge"> +<title>EQNode9->Con_8</title> +<path fill="none" stroke="black" d="M65.33,-440C61.44,-451.69 56.19,-467.44 51.76,-480.73"/> +<polygon fill="black" stroke="black" points="48.4,-479.72 48.56,-490.31 55.04,-481.93 48.4,-479.72"/> +<text text-anchor="middle" x="62.33" y="-442.6" font-family="Helvetica,sans-Serif" font-size="8.00">2</text> +</g> +<!-- If10 --> +<g id="node6" class="node"> +<title>If10</title> +<polygon fill="yellow" stroke="transparent" points="24,-339 24,-364 118,-364 118,-339 24,-339"/> +<polygon fill="none" stroke="black" points="24,-339 24,-364 118,-364 118,-339 24,-339"/> +<text text-anchor="start" x="65.5" y="-347.8" font-family="Times,serif" font-size="14.00">If</text> +<polygon fill="none" stroke="black" points="24,-308 24,-339 118,-339 118,-308 24,-308"/> +<polygon fill="yellow" stroke="transparent" points="29,-313 29,-334 69,-334 69,-313 29,-313"/> +<polygon fill="none" stroke="black" points="29,-313 29,-334 69,-334 69,-313 29,-313"/> +<text text-anchor="start" x="32" y="-319.8" font-family="Times,serif" font-size="14.00">True</text> +<polygon fill="yellow" stroke="transparent" points="69,-313 69,-334 113,-334 113,-313 69,-313"/> +<polygon fill="none" stroke="black" points="69,-313 69,-334 113,-334 113,-313 69,-313"/> +<text text-anchor="start" x="72" y="-319.8" font-family="Times,serif" font-size="14.00">False</text> +</g> +<!-- If10->Start2 --> +<g id="edge4" class="edge"> +<title>If10->Start2:p0</title> +<path fill="none" stroke="red" d="M90.29,-368.12C96.41,-379.12 102.69,-391.8 107,-404 117.81,-434.65 121.3,-445.6 121.9,-473.74"/> +<polygon fill="red" stroke="red" points="118.4,-474.03 122,-484 125.4,-473.97 118.4,-474.03"/> +<text text-anchor="middle" x="87.29" y="-370.72" font-family="Helvetica,sans-Serif" font-size="8.00">0</text> +</g> +<!-- If10->EQNode9 --> +<g id="edge5" class="edge"> +<title>If10->EQNode9</title> +<path fill="none" stroke="black" d="M71,-368.28C71,-376.58 71,-385.48 71,-393.56"/> +<polygon fill="black" stroke="black" points="67.5,-393.6 71,-403.6 74.5,-393.6 67.5,-393.6"/> +<text text-anchor="middle" x="68" y="-370.88" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> +</g> +<!-- Con_14 --> +<g id="node7" class="node"> +<title>Con_14</title> +<ellipse fill="none" stroke="black" cx="191" cy="-336" rx="27" ry="18"/> +<text text-anchor="middle" x="191" y="-332.3" font-family="Times,serif" font-size="14.00">#3</text> +</g> +<!-- Region16 --> +<g id="node8" class="node"> +<title>Region16</title> +<polygon fill="yellow" stroke="black" points="125,-268 59,-268 59,-232 125,-232 125,-268"/> +<text text-anchor="middle" x="92" y="-246.3" font-family="Times,serif" font-size="14.00">Region</text> +</g> +<!-- Region16->If10 --> +<g id="edge6" class="edge"> +<title>Region16->If10:p0</title> +<path fill="none" stroke="red" d="M71.51,-268.03C62.68,-276.94 53.63,-288.71 50.32,-301.78"/> +<polygon fill="red" stroke="red" points="46.81,-301.63 49,-312 53.75,-302.53 46.81,-301.63"/> +<text text-anchor="middle" x="68.51" y="-270.63" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> +</g> +<!-- Region16->If10 --> +<g id="edge7" class="edge"> +<title>Region16->If10:p1</title> +<path fill="none" stroke="red" d="M91.57,-268.09C91.36,-277.55 91.13,-289.77 91.04,-301.69"/> +<polygon fill="red" stroke="red" points="87.54,-301.99 91,-312 94.54,-302.01 87.54,-301.99"/> +<text text-anchor="middle" x="88.57" y="-270.69" font-family="Helvetica,sans-Serif" font-size="8.00">2</text> +</g> +<!-- Phi_a19 --> +<g id="node9" class="node"> +<title>Phi_a19</title> +<ellipse fill="lightyellow" stroke="black" cx="191" cy="-250" rx="27" ry="18"/> +<text text-anchor="middle" x="191" y="-246.3" font-family="Times,serif" font-size="14.00">φ_a</text> +</g> +<!-- Phi_a19->Con_6 --> +<g id="edge10" class="edge"> +<title>Phi_a19->Con_6</title> +<path fill="none" stroke="black" d="M203.87,-266.02C214.93,-278.92 231.04,-297.71 243.65,-312.42"/> +<polygon fill="black" stroke="black" points="241.07,-314.8 250.24,-320.11 246.39,-310.24 241.07,-314.8"/> +<text text-anchor="middle" x="200.87" y="-268.62" font-family="Helvetica,sans-Serif" font-size="8.00">2</text> +</g> +<!-- Phi_a19->Con_14 --> +<g id="edge9" class="edge"> +<title>Phi_a19->Con_14</title> +<path fill="none" stroke="black" d="M191,-268.4C191,-279.74 191,-294.77 191,-307.68"/> +<polygon fill="black" stroke="black" points="187.5,-307.9 191,-317.9 194.5,-307.9 187.5,-307.9"/> +<text text-anchor="middle" x="188" y="-271" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> +</g> +<!-- Phi_a19->Region16 --> +<g id="edge8" class="edge"> +<title>Phi_a19->Region16</title> +<path fill="none" stroke="black" stroke-dasharray="1,5" d="M163.78,-250C154.35,-250 144.92,-250 135.49,-250"/> +<polygon fill="black" stroke="black" points="135.26,-246.5 125.26,-250 135.26,-253.5 135.26,-246.5"/> +<text text-anchor="middle" x="160.78" y="-243.6" font-family="Helvetica,sans-Serif" font-size="8.00">0</text> +</g> +<!-- EQNode20 --> +<g id="node10" class="node"> +<title>EQNode20</title> +<ellipse fill="none" stroke="black" cx="145" cy="-178" rx="27" ry="18"/> +<text text-anchor="middle" x="145" y="-174.3" font-family="Times,serif" font-size="14.00">==</text> +</g> +<!-- EQNode20->Start2 --> +<g id="edge11" class="edge"> +<title>EQNode20->Start2:p1</title> +<path fill="none" stroke="black" d="M145.93,-196.36C148.75,-249.2 157.02,-408.5 157.92,-473.67"/> +<polygon fill="black" stroke="black" points="154.42,-474.03 158,-484 161.42,-473.97 154.42,-474.03"/> +<text text-anchor="middle" x="142.93" y="-198.96" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> +</g> +<!-- EQNode20->Phi_a19 --> +<g id="edge12" class="edge"> +<title>EQNode20->Phi_a19</title> +<path fill="none" stroke="black" d="M155.44,-194.88C161.2,-203.66 168.48,-214.74 174.96,-224.58"/> +<polygon fill="black" stroke="black" points="172.19,-226.74 180.6,-233.18 178.04,-222.9 172.19,-226.74"/> +<text text-anchor="middle" x="152.44" y="-197.48" font-family="Helvetica,sans-Serif" font-size="8.00">2</text> +</g> +<!-- Return21->Region16 --> +<g id="edge13" class="edge"> +<title>Return21->Region16</title> +<path fill="none" stroke="red" d="M116.96,-124.15C114.56,-134.51 111.51,-147.99 109,-160 104.69,-180.66 100.23,-204.11 96.96,-221.75"/> +<polygon fill="red" stroke="red" points="93.46,-221.44 95.09,-231.9 100.34,-222.7 93.46,-221.44"/> +<text text-anchor="middle" x="113.96" y="-126.75" font-family="Helvetica,sans-Serif" font-size="8.00">0</text> +</g> +<!-- Return21->EQNode20 --> +<g id="edge14" class="edge"> +<title>Return21->EQNode20</title> +<path fill="none" stroke="black" d="M126.93,-124.3C129.68,-132.3 132.99,-141.98 136.03,-150.85"/> +<polygon fill="black" stroke="black" points="132.75,-152.05 139.3,-160.38 139.37,-149.78 132.75,-152.05"/> +<text text-anchor="middle" x="123.93" y="-126.9" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> +</g> +</g> +</svg> diff --git a/chapter05/docs/05-graph6.gv b/chapter05/docs/05-graph6.gv new file mode 100644 index 00000000..f888e8e9 --- /dev/null +++ b/chapter05/docs/05-graph6.gv @@ -0,0 +1,58 @@ +digraph chapter05 { +/* +int c = 3; +int b = 2; +if (arg == 1) { + b = 3; + c = 4; +} +return c; +*/ + rankdir=BT; + ordering="in"; + concentrate="true"; + subgraph cluster_Nodes { + Start2 [ shape=plaintext label=< + <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4"> + <TR><TD BGCOLOR="yellow">Start</TD></TR> + <TR><TD> + <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0"> + <TR><TD PORT="p0" BGCOLOR="yellow">$ctrl</TD><TD PORT="p1">arg</TD></TR> + </TABLE> + </TD></TR> + </TABLE>> + ]; + Stop3 [ shape=box style=filled fillcolor=yellow label="Stop" ]; + Con_6 [ label="#3" ]; + Con_8 [ label="#1" ]; + EQNode9 [ label="==" ]; + If10 [ shape=plaintext label=< + <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4"> + <TR><TD BGCOLOR="yellow">If</TD></TR> + <TR><TD> + <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0"> + <TR><TD PORT="p0" BGCOLOR="yellow">True</TD><TD PORT="p1" BGCOLOR="yellow">False</TD></TR> + </TABLE> + </TD></TR> + </TABLE>> + ]; + Con_15 [ label="#4" ]; + Region16 [ shape=box style=filled fillcolor=yellow label="Region" ]; + Phi_c17 [ style=filled fillcolor=lightyellow label="φ_c" ]; + Return19 [ shape=box style=filled fillcolor=yellow label="Return" ]; + { rank=same; Region16;Phi_c17;} + } + edge [ fontname=Helvetica, fontsize=8 ]; + Stop3 -> Return19[taillabel=0 color=red]; + EQNode9 -> Start2:p1[taillabel=1]; + EQNode9 -> Con_8[taillabel=2]; + If10 -> Start2:p0[taillabel=0 color=red]; + If10 -> EQNode9[taillabel=1]; + Region16 -> If10:p0[taillabel=1 color=red]; + Region16 -> If10:p1[taillabel=2 color=red]; + Phi_c17 -> Region16 [style=dotted taillabel=0]; + Phi_c17 -> Con_15[taillabel=1]; + Phi_c17 -> Con_6[taillabel=2]; + Return19 -> Region16[taillabel=0 color=red]; + Return19 -> Phi_c17[taillabel=1]; +}
\ No newline at end of file diff --git a/chapter05/docs/05-graph6.svg b/chapter05/docs/05-graph6.svg new file mode 100644 index 00000000..71527d7f --- /dev/null +++ b/chapter05/docs/05-graph6.svg @@ -0,0 +1,176 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" + "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<!-- Generated by graphviz version 2.43.0 (0) + --> +<!-- Title: chapter05 Pages: 1 --> +<svg width="294pt" height="492pt" + viewBox="0.00 0.00 294.00 492.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> +<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 488)"> +<title>chapter05</title> +<polygon fill="white" stroke="transparent" points="-4,4 -4,-488 290,-488 290,4 -4,4"/> +<g id="clust1" class="cluster"> +<title>cluster_Nodes</title> +<polygon fill="none" stroke="black" points="8,-8 8,-476 278,-476 278,-8 8,-8"/> +</g> +<!-- Start2 --> +<g id="node1" class="node"> +<title>Start2</title> +<polygon fill="yellow" stroke="transparent" points="109,-439 109,-464 190,-464 190,-439 109,-439"/> +<polygon fill="none" stroke="black" points="109,-439 109,-464 190,-464 190,-439 109,-439"/> +<text text-anchor="start" x="131" y="-447.8" font-family="Times,serif" font-size="14.00">Start</text> +<polygon fill="none" stroke="black" points="109,-408 109,-439 190,-439 190,-408 109,-408"/> +<polygon fill="yellow" stroke="transparent" points="114,-413 114,-434 154,-434 154,-413 114,-413"/> +<polygon fill="none" stroke="black" points="114,-413 114,-434 154,-434 154,-413 114,-413"/> +<text text-anchor="start" x="117" y="-419.8" font-family="Times,serif" font-size="14.00">$ctrl</text> +<polygon fill="none" stroke="black" points="154,-413 154,-434 185,-434 185,-413 154,-413"/> +<text text-anchor="start" x="157" y="-419.8" font-family="Times,serif" font-size="14.00">arg</text> +</g> +<!-- Stop3 --> +<g id="node2" class="node"> +<title>Stop3</title> +<polygon fill="yellow" stroke="black" points="181,-52 127,-52 127,-16 181,-16 181,-52"/> +<text text-anchor="middle" x="154" y="-30.3" font-family="Times,serif" font-size="14.00">Stop</text> +</g> +<!-- Return19 --> +<g id="node10" class="node"> +<title>Return19</title> +<polygon fill="yellow" stroke="black" points="187,-124 121,-124 121,-88 187,-88 187,-124"/> +<text text-anchor="middle" x="154" y="-102.3" font-family="Times,serif" font-size="14.00">Return</text> +</g> +<!-- Stop3->Return19 --> +<g id="edge1" class="edge"> +<title>Stop3->Return19</title> +<path fill="none" stroke="red" d="M154,-52.3C154,-60.02 154,-69.29 154,-77.89"/> +<polygon fill="red" stroke="red" points="150.5,-77.9 154,-87.9 157.5,-77.9 150.5,-77.9"/> +<text text-anchor="middle" x="151" y="-54.9" font-family="Helvetica,sans-Serif" font-size="8.00">0</text> +</g> +<!-- Con_6 --> +<g id="node3" class="node"> +<title>Con_6</title> +<ellipse fill="none" stroke="black" cx="43" cy="-264" rx="27" ry="18"/> +<text text-anchor="middle" x="43" y="-260.3" font-family="Times,serif" font-size="14.00">#3</text> +</g> +<!-- Con_8 --> +<g id="node4" class="node"> +<title>Con_8</title> +<ellipse fill="none" stroke="black" cx="243" cy="-436" rx="27" ry="18"/> +<text text-anchor="middle" x="243" y="-432.3" font-family="Times,serif" font-size="14.00">#1</text> +</g> +<!-- EQNode9 --> +<g id="node5" class="node"> +<title>EQNode9</title> +<ellipse fill="none" stroke="black" cx="215" cy="-350" rx="27" ry="18"/> +<text text-anchor="middle" x="215" y="-346.3" font-family="Times,serif" font-size="14.00">==</text> +</g> +<!-- EQNode9->Start2 --> +<g id="edge2" class="edge"> +<title>EQNode9->Start2:p1</title> +<path fill="none" stroke="black" d="M197.73,-364.01C187.32,-373.17 175.33,-386.49 171.36,-401.73"/> +<polygon fill="black" stroke="black" points="167.84,-401.63 170,-412 174.78,-402.54 167.84,-401.63"/> +<text text-anchor="middle" x="194.73" y="-366.61" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> +</g> +<!-- EQNode9->Con_8 --> +<g id="edge3" class="edge"> +<title>EQNode9->Con_8</title> +<path fill="none" stroke="black" d="M220.67,-368C224.56,-379.69 229.81,-395.44 234.24,-408.73"/> +<polygon fill="black" stroke="black" points="230.96,-409.93 237.44,-418.31 237.6,-407.72 230.96,-409.93"/> +<text text-anchor="middle" x="217.67" y="-370.6" font-family="Helvetica,sans-Serif" font-size="8.00">2</text> +</g> +<!-- If10 --> +<g id="node6" class="node"> +<title>If10</title> +<polygon fill="yellow" stroke="transparent" points="168,-267 168,-292 262,-292 262,-267 168,-267"/> +<polygon fill="none" stroke="black" points="168,-267 168,-292 262,-292 262,-267 168,-267"/> +<text text-anchor="start" x="209.5" y="-275.8" font-family="Times,serif" font-size="14.00">If</text> +<polygon fill="none" stroke="black" points="168,-236 168,-267 262,-267 262,-236 168,-236"/> +<polygon fill="yellow" stroke="transparent" points="173,-241 173,-262 213,-262 213,-241 173,-241"/> +<polygon fill="none" stroke="black" points="173,-241 173,-262 213,-262 213,-241 173,-241"/> +<text text-anchor="start" x="176" y="-247.8" font-family="Times,serif" font-size="14.00">True</text> +<polygon fill="yellow" stroke="transparent" points="213,-241 213,-262 257,-262 257,-241 213,-241"/> +<polygon fill="none" stroke="black" points="213,-241 213,-262 257,-262 257,-241 213,-241"/> +<text text-anchor="start" x="216" y="-247.8" font-family="Times,serif" font-size="14.00">False</text> +</g> +<!-- If10->Start2 --> +<g id="edge4" class="edge"> +<title>If10->Start2:p0</title> +<path fill="none" stroke="red" d="M185.76,-296.14C164.32,-322.05 138.32,-361.17 134.48,-401.9"/> +<polygon fill="red" stroke="red" points="130.98,-401.84 134,-412 137.97,-402.18 130.98,-401.84"/> +<text text-anchor="middle" x="182.76" y="-298.74" font-family="Helvetica,sans-Serif" font-size="8.00">0</text> +</g> +<!-- If10->EQNode9 --> +<g id="edge5" class="edge"> +<title>If10->EQNode9</title> +<path fill="none" stroke="black" d="M215,-296.28C215,-304.58 215,-313.48 215,-321.56"/> +<polygon fill="black" stroke="black" points="211.5,-321.6 215,-331.6 218.5,-321.6 211.5,-321.6"/> +<text text-anchor="middle" x="212" y="-298.88" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> +</g> +<!-- Con_15 --> +<g id="node7" class="node"> +<title>Con_15</title> +<ellipse fill="none" stroke="black" cx="115" cy="-264" rx="27" ry="18"/> +<text text-anchor="middle" x="115" y="-260.3" font-family="Times,serif" font-size="14.00">#4</text> +</g> +<!-- Region16 --> +<g id="node8" class="node"> +<title>Region16</title> +<polygon fill="yellow" stroke="black" points="226,-196 160,-196 160,-160 226,-160 226,-196"/> +<text text-anchor="middle" x="193" y="-174.3" font-family="Times,serif" font-size="14.00">Region</text> +</g> +<!-- Region16->If10 --> +<g id="edge6" class="edge"> +<title>Region16->If10:p0</title> +<path fill="none" stroke="red" d="M193,-196.09C193,-205.55 193,-217.77 193,-229.69"/> +<polygon fill="red" stroke="red" points="189.5,-230 193,-240 196.5,-230 189.5,-230"/> +<text text-anchor="middle" x="190" y="-198.69" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> +</g> +<!-- Region16->If10 --> +<g id="edge7" class="edge"> +<title>Region16->If10:p1</title> +<path fill="none" stroke="red" d="M213.02,-196.12C221.64,-205.06 230.48,-216.84 233.71,-229.84"/> +<polygon fill="red" stroke="red" points="230.27,-230.52 235,-240 237.22,-229.64 230.27,-230.52"/> +<text text-anchor="middle" x="210.02" y="-198.72" font-family="Helvetica,sans-Serif" font-size="8.00">2</text> +</g> +<!-- Phi_c17 --> +<g id="node9" class="node"> +<title>Phi_c17</title> +<ellipse fill="lightyellow" stroke="black" cx="115" cy="-178" rx="27" ry="18"/> +<text text-anchor="middle" x="115" y="-174.3" font-family="Times,serif" font-size="14.00">φ_c</text> +</g> +<!-- Phi_c17->Con_6 --> +<g id="edge10" class="edge"> +<title>Phi_c17->Con_6</title> +<path fill="none" stroke="black" d="M102.13,-194.02C91.07,-206.92 74.96,-225.71 62.35,-240.42"/> +<polygon fill="black" stroke="black" points="59.61,-238.24 55.76,-248.11 64.93,-242.8 59.61,-238.24"/> +<text text-anchor="middle" x="99.13" y="-196.62" font-family="Helvetica,sans-Serif" font-size="8.00">2</text> +</g> +<!-- Phi_c17->Con_15 --> +<g id="edge9" class="edge"> +<title>Phi_c17->Con_15</title> +<path fill="none" stroke="black" d="M115,-196.4C115,-207.74 115,-222.77 115,-235.68"/> +<polygon fill="black" stroke="black" points="111.5,-235.9 115,-245.9 118.5,-235.9 111.5,-235.9"/> +<text text-anchor="middle" x="112" y="-199" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> +</g> +<!-- Phi_c17->Region16 --> +<g id="edge8" class="edge"> +<title>Phi_c17->Region16</title> +<path fill="none" stroke="black" stroke-dasharray="1,5" d="M142.12,-178C144.58,-178 147.04,-178 149.5,-178"/> +<polygon fill="black" stroke="black" points="149.61,-181.5 159.61,-178 149.61,-174.5 149.61,-181.5"/> +<text text-anchor="middle" x="145.12" y="-171.6" font-family="Helvetica,sans-Serif" font-size="8.00">0</text> +</g> +<!-- Return19->Region16 --> +<g id="edge11" class="edge"> +<title>Return19->Region16</title> +<path fill="none" stroke="red" d="M163.64,-124.3C168.13,-132.36 173.56,-142.11 178.52,-151.02"/> +<polygon fill="red" stroke="red" points="175.55,-152.86 183.47,-159.9 181.66,-149.46 175.55,-152.86"/> +<text text-anchor="middle" x="160.64" y="-126.9" font-family="Helvetica,sans-Serif" font-size="8.00">0</text> +</g> +<!-- Return19->Phi_c17 --> +<g id="edge12" class="edge"> +<title>Return19->Phi_c17</title> +<path fill="none" stroke="black" d="M144.36,-124.3C139.69,-132.68 134,-142.9 128.87,-152.1"/> +<polygon fill="black" stroke="black" points="125.8,-150.42 123.99,-160.86 131.92,-153.82 125.8,-150.42"/> +<text text-anchor="middle" x="141.36" y="-126.9" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> +</g> +</g> +</svg> diff --git a/chapter05/docs/05-graph7.gv b/chapter05/docs/05-graph7.gv new file mode 100644 index 00000000..3abd6455 --- /dev/null +++ b/chapter05/docs/05-graph7.gv @@ -0,0 +1,72 @@ +digraph chapter05 { +/* +int a=arg+1; +int b=arg+2; +if( arg==1 ) + b=b+a; +else + a=b+1; +return a+b; +*/ + rankdir=BT; + ordering="in"; + concentrate="true"; + subgraph cluster_Nodes { + Start2 [ shape=plaintext label=< + <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4"> + <TR><TD BGCOLOR="yellow">Start</TD></TR> + <TR><TD> + <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0"> + <TR><TD PORT="p0" BGCOLOR="yellow">$ctrl</TD><TD PORT="p1">arg</TD></TR> + </TABLE> + </TD></TR> + </TABLE>> + ]; + Stop3 [ shape=box style=filled fillcolor=yellow label="Stop" ]; + Phi_b37 [ style=filled fillcolor=lightyellow label="φ_b" ]; + Con_10 [ label="#1" ]; + Add42 [ label="+" ]; + EQNode11 [ label="==" ]; + If12 [ shape=plaintext label=< + <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4"> + <TR><TD BGCOLOR="yellow">If</TD></TR> + <TR><TD> + <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0"> + <TR><TD PORT="p0" BGCOLOR="yellow">True</TD><TD PORT="p1" BGCOLOR="yellow">False</TD></TR> + </TABLE> + </TD></TR> + </TABLE>> + ]; + Con_46 [ label="#4" ]; + Con_48 [ label="#5" ]; + Phi_ab49 [ style=filled fillcolor=lightyellow label="φ_ab" ]; + Add50 [ label="+" ]; + Con_19 [ label="#2" ]; + Return51 [ shape=box style=filled fillcolor=yellow label="Return" ]; + Mul20 [ label="*" ]; + Region31 [ shape=box style=filled fillcolor=yellow label="Region" ]; + { rank=same; Region31;Phi_b37;Phi_ab49;} + } + edge [ fontname=Helvetica, fontsize=8 ]; + Stop3 -> Return51[taillabel=0 color=red]; + Phi_b37 -> Region31 [style=dotted taillabel=0]; + Phi_b37 -> Mul20[taillabel=1]; + Phi_b37 -> Start2:p1[taillabel=2]; + Add42 -> Phi_b37[taillabel=1]; + Add42 -> Start2:p1[taillabel=2]; + EQNode11 -> Start2:p1[taillabel=1]; + EQNode11 -> Con_10[taillabel=2]; + If12 -> Start2:p0[taillabel=0 color=red]; + If12 -> EQNode11[taillabel=1]; + Phi_ab49 -> Region31 [style=dotted taillabel=0]; + Phi_ab49 -> Con_46[taillabel=1]; + Phi_ab49 -> Con_48[taillabel=2]; + Add50 -> Add42[taillabel=1]; + Add50 -> Phi_ab49[taillabel=2]; + Return51 -> Region31[taillabel=0 color=red]; + Return51 -> Add50[taillabel=1]; + Mul20 -> Start2:p1[taillabel=1]; + Mul20 -> Con_19[taillabel=2]; + Region31 -> If12:p0[taillabel=1 color=red]; + Region31 -> If12:p1[taillabel=2 color=red]; +} diff --git a/chapter05/docs/05-graph7.svg b/chapter05/docs/05-graph7.svg new file mode 100644 index 00000000..8ba5ebd6 --- /dev/null +++ b/chapter05/docs/05-graph7.svg @@ -0,0 +1,269 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" + "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<!-- Generated by graphviz version 2.43.0 (0) + --> +<!-- Title: chapter05 Pages: 1 --> +<svg width="386pt" height="636pt" + viewBox="0.00 0.00 386.00 636.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> +<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 632)"> +<title>chapter05</title> +<polygon fill="white" stroke="transparent" points="-4,4 -4,-632 382,-632 382,4 -4,4"/> +<g id="clust1" class="cluster"> +<title>cluster_Nodes</title> +<polygon fill="none" stroke="black" points="8,-8 8,-620 370,-620 370,-8 8,-8"/> +</g> +<!-- Start2 --> +<g id="node1" class="node"> +<title>Start2</title> +<polygon fill="yellow" stroke="transparent" points="187,-583 187,-608 268,-608 268,-583 187,-583"/> +<polygon fill="none" stroke="black" points="187,-583 187,-608 268,-608 268,-583 187,-583"/> +<text text-anchor="start" x="209" y="-591.8" font-family="Times,serif" font-size="14.00">Start</text> +<polygon fill="none" stroke="black" points="187,-552 187,-583 268,-583 268,-552 187,-552"/> +<polygon fill="yellow" stroke="transparent" points="192,-557 192,-578 232,-578 232,-557 192,-557"/> +<polygon fill="none" stroke="black" points="192,-557 192,-578 232,-578 232,-557 192,-557"/> +<text text-anchor="start" x="195" y="-563.8" font-family="Times,serif" font-size="14.00">$ctrl</text> +<polygon fill="none" stroke="black" points="232,-557 232,-578 263,-578 263,-557 232,-557"/> +<text text-anchor="start" x="235" y="-563.8" font-family="Times,serif" font-size="14.00">arg</text> +</g> +<!-- Stop3 --> +<g id="node2" class="node"> +<title>Stop3</title> +<polygon fill="yellow" stroke="black" points="230,-52 176,-52 176,-16 230,-16 230,-52"/> +<text text-anchor="middle" x="203" y="-30.3" font-family="Times,serif" font-size="14.00">Stop</text> +</g> +<!-- Return51 --> +<g id="node13" class="node"> +<title>Return51</title> +<polygon fill="yellow" stroke="black" points="236,-124 170,-124 170,-88 236,-88 236,-124"/> +<text text-anchor="middle" x="203" y="-102.3" font-family="Times,serif" font-size="14.00">Return</text> +</g> +<!-- Stop3->Return51 --> +<g id="edge1" class="edge"> +<title>Stop3->Return51</title> +<path fill="none" stroke="red" d="M203,-52.3C203,-60.02 203,-69.29 203,-77.89"/> +<polygon fill="red" stroke="red" points="199.5,-77.9 203,-87.9 206.5,-77.9 199.5,-77.9"/> +<text text-anchor="middle" x="200" y="-54.9" font-family="Helvetica,sans-Serif" font-size="8.00">0</text> +</g> +<!-- Phi_b37 --> +<g id="node3" class="node"> +<title>Phi_b37</title> +<ellipse fill="lightyellow" stroke="black" cx="63" cy="-322" rx="27.1" ry="18"/> +<text text-anchor="middle" x="63" y="-318.3" font-family="Times,serif" font-size="14.00">φ_b</text> +</g> +<!-- Phi_b37->Start2 --> +<g id="edge4" class="edge"> +<title>Phi_b37->Start2:p1</title> +<path fill="none" stroke="black" d="M50.14,-338.15C37.78,-354.08 20.49,-380.46 17,-407"/> +<text text-anchor="middle" x="47.14" y="-340.75" font-family="Helvetica,sans-Serif" font-size="8.00">2</text> +</g> +<!-- Mul20 --> +<g id="node14" class="node"> +<title>Mul20</title> +<ellipse fill="none" stroke="black" cx="63" cy="-408" rx="27" ry="18"/> +<text text-anchor="middle" x="63" y="-404.3" font-family="Times,serif" font-size="14.00">*</text> +</g> +<!-- Phi_b37->Mul20 --> +<g id="edge3" class="edge"> +<title>Phi_b37->Mul20</title> +<path fill="none" stroke="black" d="M63,-340.4C63,-351.74 63,-366.77 63,-379.68"/> +<polygon fill="black" stroke="black" points="59.5,-379.9 63,-389.9 66.5,-379.9 59.5,-379.9"/> +<text text-anchor="middle" x="60" y="-343" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> +</g> +<!-- Region31 --> +<g id="node15" class="node"> +<title>Region31</title> +<polygon fill="yellow" stroke="black" points="287,-340 221,-340 221,-304 287,-304 287,-340"/> +<text text-anchor="middle" x="254" y="-318.3" font-family="Times,serif" font-size="14.00">Region</text> +</g> +<!-- Phi_b37->Region31 --> +<g id="edge2" class="edge"> +<title>Phi_b37->Region31</title> +<path fill="none" stroke="black" stroke-dasharray="1,5" d="M83.07,-309.47C97.9,-300.98 118.92,-290.52 139,-286 166.75,-279.76 175.89,-277.4 203,-286 210.99,-288.54 218.81,-292.83 225.83,-297.58"/> +<polygon fill="black" stroke="black" points="224.11,-300.66 234.24,-303.75 228.25,-295.01 224.11,-300.66"/> +<text text-anchor="middle" x="80.07" y="-303.07" font-family="Helvetica,sans-Serif" font-size="8.00">0</text> +</g> +<!-- Con_10 --> +<g id="node4" class="node"> +<title>Con_10</title> +<ellipse fill="none" stroke="black" cx="321" cy="-580" rx="27" ry="18"/> +<text text-anchor="middle" x="321" y="-576.3" font-family="Times,serif" font-size="14.00">#1</text> +</g> +<!-- Add42 --> +<g id="node5" class="node"> +<title>Add42</title> +<ellipse fill="none" stroke="black" cx="63" cy="-250" rx="27" ry="18"/> +<text text-anchor="middle" x="63" y="-246.3" font-family="Times,serif" font-size="14.00">+</text> +</g> +<!-- Add42->Start2 --> +<g id="edge6" class="edge"> +<title>Add42->Start2:p1</title> +<path fill="none" stroke="black" d="M49.72,-266.09C41.69,-276.12 32.07,-289.98 27,-304 11.37,-347.26 22.99,-361.4 17,-407"/> +<path fill="none" stroke="black" d="M17,-409C11.54,-445.93 0.41,-459.55 17,-493"/> +<path fill="none" stroke="black" d="M17,-495C20.89,-502.85 19.85,-506.92 27,-512 102.92,-565.95 228.75,-471 246.01,-537.97"/> +<polygon fill="black" stroke="black" points="242.59,-538.7 247.67,-548 249.49,-537.56 242.59,-538.7"/> +<text text-anchor="middle" x="46.72" y="-268.69" font-family="Helvetica,sans-Serif" font-size="8.00">2</text> +</g> +<!-- Add42->Phi_b37 --> +<g id="edge5" class="edge"> +<title>Add42->Phi_b37</title> +<path fill="none" stroke="black" d="M63,-268.3C63,-276.02 63,-285.29 63,-293.89"/> +<polygon fill="black" stroke="black" points="59.5,-293.9 63,-303.9 66.5,-293.9 59.5,-293.9"/> +<text text-anchor="middle" x="60" y="-270.9" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> +</g> +<!-- EQNode11 --> +<g id="node6" class="node"> +<title>EQNode11</title> +<ellipse fill="none" stroke="black" cx="307" cy="-494" rx="27" ry="18"/> +<text text-anchor="middle" x="307" y="-490.3" font-family="Times,serif" font-size="14.00">==</text> +</g> +<!-- EQNode11->Start2 --> +<g id="edge7" class="edge"> +<title>EQNode11->Start2:p1</title> +<path fill="none" stroke="black" d="M300.78,-511.7C294.25,-528.15 283.48,-552.23 273.01,-562.3"/> +<polygon fill="black" stroke="black" points="271.25,-559.27 264,-567 274.49,-565.48 271.25,-559.27"/> +<text text-anchor="middle" x="297.78" y="-514.3" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> +</g> +<!-- EQNode11->Con_10 --> +<g id="edge8" class="edge"> +<title>EQNode11->Con_10</title> +<path fill="none" stroke="black" d="M309.83,-512C311.75,-523.5 314.32,-538.93 316.51,-552.08"/> +<polygon fill="black" stroke="black" points="313.07,-552.74 318.17,-562.03 319.98,-551.59 313.07,-552.74"/> +<text text-anchor="middle" x="306.83" y="-514.6" font-family="Helvetica,sans-Serif" font-size="8.00">2</text> +</g> +<!-- If12 --> +<g id="node7" class="node"> +<title>If12</title> +<polygon fill="yellow" stroke="transparent" points="260,-411 260,-436 354,-436 354,-411 260,-411"/> +<polygon fill="none" stroke="black" points="260,-411 260,-436 354,-436 354,-411 260,-411"/> +<text text-anchor="start" x="301.5" y="-419.8" font-family="Times,serif" font-size="14.00">If</text> +<polygon fill="none" stroke="black" points="260,-380 260,-411 354,-411 354,-380 260,-380"/> +<polygon fill="yellow" stroke="transparent" points="265,-385 265,-406 305,-406 305,-385 265,-385"/> +<polygon fill="none" stroke="black" points="265,-385 265,-406 305,-406 305,-385 265,-385"/> +<text text-anchor="start" x="268" y="-391.8" font-family="Times,serif" font-size="14.00">True</text> +<polygon fill="yellow" stroke="transparent" points="305,-385 305,-406 349,-406 349,-385 305,-385"/> +<polygon fill="none" stroke="black" points="305,-385 305,-406 349,-406 349,-385 305,-385"/> +<text text-anchor="start" x="308" y="-391.8" font-family="Times,serif" font-size="14.00">False</text> +</g> +<!-- If12->Start2 --> +<g id="edge9" class="edge"> +<title>If12->Start2:p0</title> +<path fill="none" stroke="red" d="M271.9,-440.02C246.84,-465.46 216.84,-504 212.53,-545.87"/> +<polygon fill="red" stroke="red" points="209.02,-545.83 212,-556 216.01,-546.2 209.02,-545.83"/> +<text text-anchor="middle" x="268.9" y="-442.62" font-family="Helvetica,sans-Serif" font-size="8.00">0</text> +</g> +<!-- If12->EQNode11 --> +<g id="edge10" class="edge"> +<title>If12->EQNode11</title> +<path fill="none" stroke="black" d="M307,-440.28C307,-448.58 307,-457.48 307,-465.56"/> +<polygon fill="black" stroke="black" points="303.5,-465.6 307,-475.6 310.5,-465.6 303.5,-465.6"/> +<text text-anchor="middle" x="304" y="-442.88" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> +</g> +<!-- Con_46 --> +<g id="node8" class="node"> +<title>Con_46</title> +<ellipse fill="none" stroke="black" cx="135" cy="-408" rx="27" ry="18"/> +<text text-anchor="middle" x="135" y="-404.3" font-family="Times,serif" font-size="14.00">#4</text> +</g> +<!-- Con_48 --> +<g id="node9" class="node"> +<title>Con_48</title> +<ellipse fill="none" stroke="black" cx="207" cy="-408" rx="27" ry="18"/> +<text text-anchor="middle" x="207" y="-404.3" font-family="Times,serif" font-size="14.00">#5</text> +</g> +<!-- Phi_ab49 --> +<g id="node10" class="node"> +<title>Phi_ab49</title> +<ellipse fill="lightyellow" stroke="black" cx="171" cy="-322" rx="32.49" ry="18"/> +<text text-anchor="middle" x="171" y="-318.3" font-family="Times,serif" font-size="14.00">φ_ab</text> +</g> +<!-- Phi_ab49->Con_46 --> +<g id="edge12" class="edge"> +<title>Phi_ab49->Con_46</title> +<path fill="none" stroke="black" d="M163.89,-339.6C158.81,-351.45 151.88,-367.62 146.08,-381.15"/> +<polygon fill="black" stroke="black" points="142.82,-379.87 142.1,-390.44 149.25,-382.63 142.82,-379.87"/> +<text text-anchor="middle" x="160.89" y="-342.2" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> +</g> +<!-- Phi_ab49->Con_48 --> +<g id="edge13" class="edge"> +<title>Phi_ab49->Con_48</title> +<path fill="none" stroke="black" d="M178.11,-339.6C183.19,-351.45 190.12,-367.62 195.92,-381.15"/> +<polygon fill="black" stroke="black" points="192.75,-382.63 199.9,-390.44 199.18,-379.87 192.75,-382.63"/> +<text text-anchor="middle" x="175.11" y="-342.2" font-family="Helvetica,sans-Serif" font-size="8.00">2</text> +</g> +<!-- Phi_ab49->Region31 --> +<g id="edge11" class="edge"> +<title>Phi_ab49->Region31</title> +<path fill="none" stroke="black" stroke-dasharray="1,5" d="M203.75,-322C206.03,-322 208.32,-322 210.6,-322"/> +<polygon fill="black" stroke="black" points="210.63,-325.5 220.63,-322 210.63,-318.5 210.63,-325.5"/> +<text text-anchor="middle" x="206.75" y="-315.6" font-family="Helvetica,sans-Serif" font-size="8.00">0</text> +</g> +<!-- Add50 --> +<g id="node11" class="node"> +<title>Add50</title> +<ellipse fill="none" stroke="black" cx="171" cy="-178" rx="27" ry="18"/> +<text text-anchor="middle" x="171" y="-174.3" font-family="Times,serif" font-size="14.00">+</text> +</g> +<!-- Add50->Add42 --> +<g id="edge14" class="edge"> +<title>Add50->Add42</title> +<path fill="none" stroke="black" d="M152.19,-191.19C135,-202.33 109.38,-218.94 90.01,-231.5"/> +<polygon fill="black" stroke="black" points="88.08,-228.57 81.6,-236.95 91.89,-234.44 88.08,-228.57"/> +<text text-anchor="middle" x="149.19" y="-193.79" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> +</g> +<!-- Add50->Phi_ab49 --> +<g id="edge15" class="edge"> +<title>Add50->Phi_ab49</title> +<path fill="none" stroke="black" d="M171,-196.13C171,-220.33 171,-264.79 171,-293.61"/> +<polygon fill="black" stroke="black" points="167.5,-293.81 171,-303.81 174.5,-293.81 167.5,-293.81"/> +<text text-anchor="middle" x="168" y="-198.73" font-family="Helvetica,sans-Serif" font-size="8.00">2</text> +</g> +<!-- Con_19 --> +<g id="node12" class="node"> +<title>Con_19</title> +<ellipse fill="none" stroke="black" cx="63" cy="-494" rx="27" ry="18"/> +<text text-anchor="middle" x="63" y="-490.3" font-family="Times,serif" font-size="14.00">#2</text> +</g> +<!-- Return51->Add50 --> +<g id="edge17" class="edge"> +<title>Return51->Add50</title> +<path fill="none" stroke="black" d="M195.09,-124.3C191.39,-132.39 186.91,-142.19 182.83,-151.13"/> +<polygon fill="black" stroke="black" points="179.57,-149.83 178.6,-160.38 185.94,-152.74 179.57,-149.83"/> +<text text-anchor="middle" x="192.09" y="-126.9" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> +</g> +<!-- Return51->Region31 --> +<g id="edge16" class="edge"> +<title>Return51->Region31</title> +<path fill="none" stroke="red" d="M207.09,-124.15C215.93,-161.25 236.89,-249.19 247.54,-293.9"/> +<polygon fill="red" stroke="red" points="244.17,-294.85 249.89,-303.77 250.98,-293.23 244.17,-294.85"/> +<text text-anchor="middle" x="204.09" y="-126.75" font-family="Helvetica,sans-Serif" font-size="8.00">0</text> +</g> +<!-- Mul20->Start2 --> +<g id="edge18" class="edge"> +<title>Mul20->Start2:p1</title> +<path fill="none" stroke="black" d="M46.66,-422.5C28.85,-438.94 4.44,-467.68 17,-493"/> +<text text-anchor="middle" x="43.66" y="-425.1" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> +</g> +<!-- Mul20->Con_19 --> +<g id="edge19" class="edge"> +<title>Mul20->Con_19</title> +<path fill="none" stroke="black" d="M63,-426.4C63,-437.74 63,-452.77 63,-465.68"/> +<polygon fill="black" stroke="black" points="59.5,-465.9 63,-475.9 66.5,-465.9 59.5,-465.9"/> +<text text-anchor="middle" x="60" y="-429" font-family="Helvetica,sans-Serif" font-size="8.00">2</text> +</g> +<!-- Region31->If12 --> +<g id="edge20" class="edge"> +<title>Region31->If12:p0</title> +<path fill="none" stroke="red" d="M268.23,-340.25C274.66,-349.42 281.38,-361.37 283.93,-373.89"/> +<polygon fill="red" stroke="red" points="280.47,-374.42 285,-384 287.43,-373.69 280.47,-374.42"/> +<text text-anchor="middle" x="265.23" y="-342.85" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> +</g> +<!-- Region31->If12 --> +<g id="edge21" class="edge"> +<title>Region31->If12:p1</title> +<path fill="none" stroke="red" d="M287.08,-335.84C303.38,-344.18 320.59,-356.74 325.57,-373.96"/> +<polygon fill="red" stroke="red" points="322.13,-374.59 327,-384 329.06,-373.61 322.13,-374.59"/> +<text text-anchor="middle" x="290.08" y="-329.44" font-family="Helvetica,sans-Serif" font-size="8.00">2</text> +</g> +</g> +</svg> diff --git a/chapter05/docs/05-graph8.gv b/chapter05/docs/05-graph8.gv new file mode 100644 index 00000000..bef29b93 --- /dev/null +++ b/chapter05/docs/05-graph8.gv @@ -0,0 +1,129 @@ +digraph chapter05 { +/* +int a=1; +if( arg==1 ) + if( arg==2 ) + a=2; + else + a=3; +else if( arg==3 ) + a=4; +else + a=5; +return a; +#showGraph; +*/ + rankdir=BT; + ordering="in"; + concentrate="true"; + subgraph cluster_Nodes { + Start2 [ shape=plaintext label=< + <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4"> + <TR><TD BGCOLOR="yellow">Start</TD></TR> + <TR><TD> + <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0"> + <TR><TD PORT="p0" BGCOLOR="yellow">$ctrl</TD><TD PORT="p1">arg</TD></TR> + </TABLE> + </TD></TR> + </TABLE>> + ]; + Stop3 [ shape=box style=filled fillcolor=yellow label="Stop" ]; + Con_7 [ label="#1" ]; + EQNode8 [ label="==" ]; + If9 [ shape=plaintext label=< + <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4"> + <TR><TD BGCOLOR="yellow">If</TD></TR> + <TR><TD> + <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0"> + <TR><TD PORT="p0" BGCOLOR="yellow">True</TD><TD PORT="p1" BGCOLOR="yellow">False</TD></TR> + </TABLE> + </TD></TR> + </TABLE>> + ]; + Con_13 [ label="#2" ]; + EQNode14 [ label="==" ]; + If15 [ shape=plaintext label=< + <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4"> + <TR><TD BGCOLOR="yellow">If</TD></TR> + <TR><TD> + <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0"> + <TR><TD PORT="p0" BGCOLOR="yellow">True</TD><TD PORT="p1" BGCOLOR="yellow">False</TD></TR> + </TABLE> + </TD></TR> + </TABLE>> + ]; + Con_19 [ label="#2" ]; + Con_20 [ label="#3" ]; + Region21 [ shape=box style=filled fillcolor=yellow label="Region" ]; + Phi_a22 [ style=filled fillcolor=lightyellow label="φ_a" ]; + Con_23 [ label="#3" ]; + EQNode24 [ label="==" ]; + If25 [ shape=plaintext label=< + <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4"> + <TR><TD BGCOLOR="yellow">If</TD></TR> + <TR><TD> + <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0"> + <TR><TD PORT="p0" BGCOLOR="yellow">True</TD><TD PORT="p1" BGCOLOR="yellow">False</TD></TR> + </TABLE> + </TD></TR> + </TABLE>> + ]; + Con_29 [ label="#4" ]; + Con_30 [ label="#5" ]; + Region31 [ shape=box style=filled fillcolor=yellow label="Region" ]; + Phi_a32 [ style=filled fillcolor=lightyellow label="φ_a" ]; + Region33 [ shape=box style=filled fillcolor=yellow label="Region" ]; + Phi_a34 [ style=filled fillcolor=lightyellow label="φ_a" ]; + Return35 [ shape=box style=filled fillcolor=yellow label="Return" ]; + { rank=same; Region21;Phi_a22;} + { rank=same; Region31;Phi_a32;} + { rank=same; Region33;Phi_a34;} + } + node [shape=plaintext]; + subgraph cluster_Scope1_0 { + Scope1_0 [label=< + <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0"> + <TR><TD BGCOLOR="cyan">0</TD><TD PORT="Scope1_0_$ctrl">$ctrl</TD><TD PORT="Scope1_0_arg">arg</TD></TR> + </TABLE>>]; + subgraph cluster_Scope1_1 { + Scope1_1 [label=< + <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0"> + <TR><TD BGCOLOR="cyan">1</TD><TD PORT="Scope1_1_a">a</TD></TR> + </TABLE>>]; + } + } + edge [ fontname=Helvetica, fontsize=8 ]; + Stop3 -> Return35[taillabel=0 color=red]; + EQNode8 -> Start2:p1[taillabel=1]; + EQNode8 -> Con_7[taillabel=2]; + If9 -> Start2:p0[taillabel=0 color=red]; + If9 -> EQNode8[taillabel=1]; + EQNode14 -> Start2:p1[taillabel=1]; + EQNode14 -> Con_13[taillabel=2]; + If15 -> If9:p0[taillabel=0 color=red]; + If15 -> EQNode14[taillabel=1]; + Region21 -> If15:p0[taillabel=1 color=red]; + Region21 -> If15:p1[taillabel=2 color=red]; + Phi_a22 -> Region21 [style=dotted taillabel=0]; + Phi_a22 -> Con_19[taillabel=1]; + Phi_a22 -> Con_20[taillabel=2]; + EQNode24 -> Start2:p1[taillabel=1]; + EQNode24 -> Con_23[taillabel=2]; + If25 -> If9:p1[taillabel=0 color=red]; + If25 -> EQNode24[taillabel=1]; + Region31 -> If25:p0[taillabel=1 color=red]; + Region31 -> If25:p1[taillabel=2 color=red]; + Phi_a32 -> Region31 [style=dotted taillabel=0]; + Phi_a32 -> Con_29[taillabel=1]; + Phi_a32 -> Con_30[taillabel=2]; + Region33 -> Region21[taillabel=1 color=red]; + Region33 -> Region31[taillabel=2 color=red]; + Phi_a34 -> Region33 [style=dotted taillabel=0]; + Phi_a34 -> Phi_a22[taillabel=1]; + Phi_a34 -> Phi_a32[taillabel=2]; + Return35 -> Region33[taillabel=0 color=red]; + Return35 -> Phi_a34[taillabel=1]; + edge [style=dashed color=cornflowerblue]; + Scope1_0:"Scope1_0_arg" -> Start2:p1; + Scope1_1:"Scope1_1_a" -> Phi_a34; +}
\ No newline at end of file diff --git a/chapter05/docs/05-graph8.svg b/chapter05/docs/05-graph8.svg new file mode 100644 index 00000000..e5310db4 --- /dev/null +++ b/chapter05/docs/05-graph8.svg @@ -0,0 +1,430 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" + "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<!-- Generated by graphviz version 2.43.0 (0) + --> +<!-- Title: chapter05 Pages: 1 --> +<svg width="774pt" height="664pt" + viewBox="0.00 0.00 774.00 664.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> +<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 660)"> +<title>chapter05</title> +<polygon fill="white" stroke="transparent" points="-4,4 -4,-660 770,-660 770,4 -4,4"/> +<g id="clust1" class="cluster"> +<title>cluster_Nodes</title> +<polygon fill="none" stroke="black" points="8,-8 8,-648 550,-648 550,-8 8,-8"/> +</g> +<g id="clust5" class="cluster"> +<title>cluster_Scope1_0</title> +<polygon fill="none" stroke="black" points="558,-72 558,-140 758,-140 758,-72 558,-72"/> +</g> +<g id="clust6" class="cluster"> +<title>cluster_Scope1_1</title> +<polygon fill="none" stroke="black" points="566,-80 566,-132 636,-132 636,-80 566,-80"/> +</g> +<!-- Start2 --> +<g id="node1" class="node"> +<title>Start2</title> +<polygon fill="yellow" stroke="transparent" points="190,-611 190,-636 271,-636 271,-611 190,-611"/> +<polygon fill="none" stroke="black" points="190,-611 190,-636 271,-636 271,-611 190,-611"/> +<text text-anchor="start" x="212" y="-619.8" font-family="Times,serif" font-size="14.00">Start</text> +<polygon fill="none" stroke="black" points="190,-580 190,-611 271,-611 271,-580 190,-580"/> +<polygon fill="yellow" stroke="transparent" points="195,-585 195,-606 235,-606 235,-585 195,-585"/> +<polygon fill="none" stroke="black" points="195,-585 195,-606 235,-606 235,-585 195,-585"/> +<text text-anchor="start" x="198" y="-591.8" font-family="Times,serif" font-size="14.00">$ctrl</text> +<polygon fill="none" stroke="black" points="235,-585 235,-606 266,-606 266,-585 235,-585"/> +<text text-anchor="start" x="238" y="-591.8" font-family="Times,serif" font-size="14.00">arg</text> +</g> +<!-- Stop3 --> +<g id="node2" class="node"> +<title>Stop3</title> +<polygon fill="yellow" stroke="black" points="286,-52 232,-52 232,-16 286,-16 286,-52"/> +<text text-anchor="middle" x="259" y="-30.3" font-family="Times,serif" font-size="14.00">Stop</text> +</g> +<!-- Return35 --> +<g id="node22" class="node"> +<title>Return35</title> +<polygon fill="yellow" stroke="black" points="292,-124 226,-124 226,-88 292,-88 292,-124"/> +<text text-anchor="middle" x="259" y="-102.3" font-family="Times,serif" font-size="14.00">Return</text> +</g> +<!-- Stop3->Return35 --> +<g id="edge1" class="edge"> +<title>Stop3->Return35</title> +<path fill="none" stroke="red" d="M259,-52.3C259,-60.02 259,-69.29 259,-77.89"/> +<polygon fill="red" stroke="red" points="255.5,-77.9 259,-87.9 262.5,-77.9 255.5,-77.9"/> +<text text-anchor="middle" x="256" y="-54.9" font-family="Helvetica,sans-Serif" font-size="8.00">0</text> +</g> +<!-- Con_7 --> +<g id="node3" class="node"> +<title>Con_7</title> +<ellipse fill="none" stroke="black" cx="136" cy="-608" rx="27" ry="18"/> +<text text-anchor="middle" x="136" y="-604.3" font-family="Times,serif" font-size="14.00">#1</text> +</g> +<!-- EQNode8 --> +<g id="node4" class="node"> +<title>EQNode8</title> +<ellipse fill="none" stroke="black" cx="169" cy="-522" rx="27" ry="18"/> +<text text-anchor="middle" x="169" y="-518.3" font-family="Times,serif" font-size="14.00">==</text> +</g> +<!-- EQNode8->Start2 --> +<g id="edge2" class="edge"> +<title>EQNode8->Start2:p1</title> +<path fill="none" stroke="black" d="M190.12,-533.69C209.67,-544.17 237.18,-560.54 247.18,-574.44"/> +<polygon fill="black" stroke="black" points="244.04,-576.01 251,-584 250.54,-573.42 244.04,-576.01"/> +<text text-anchor="middle" x="187.12" y="-536.29" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> +</g> +<!-- EQNode8->Con_7 --> +<g id="edge3" class="edge"> +<title>EQNode8->Con_7</title> +<path fill="none" stroke="black" d="M162.48,-539.6C157.87,-551.33 151.59,-567.3 146.31,-580.76"/> +<polygon fill="black" stroke="black" points="142.91,-579.85 142.51,-590.44 149.42,-582.41 142.91,-579.85"/> +<text text-anchor="middle" x="159.48" y="-542.2" font-family="Helvetica,sans-Serif" font-size="8.00">2</text> +</g> +<!-- If9 --> +<g id="node5" class="node"> +<title>If9</title> +<polygon fill="yellow" stroke="transparent" points="124,-439 124,-464 218,-464 218,-439 124,-439"/> +<polygon fill="none" stroke="black" points="124,-439 124,-464 218,-464 218,-439 124,-439"/> +<text text-anchor="start" x="165.5" y="-447.8" font-family="Times,serif" font-size="14.00">If</text> +<polygon fill="none" stroke="black" points="124,-408 124,-439 218,-439 218,-408 124,-408"/> +<polygon fill="yellow" stroke="transparent" points="129,-413 129,-434 169,-434 169,-413 129,-413"/> +<polygon fill="none" stroke="black" points="129,-413 129,-434 169,-434 169,-413 129,-413"/> +<text text-anchor="start" x="132" y="-419.8" font-family="Times,serif" font-size="14.00">True</text> +<polygon fill="yellow" stroke="transparent" points="169,-413 169,-434 213,-434 213,-413 169,-413"/> +<polygon fill="none" stroke="black" points="169,-413 169,-434 213,-434 213,-413 169,-413"/> +<text text-anchor="start" x="172" y="-419.8" font-family="Times,serif" font-size="14.00">False</text> +</g> +<!-- If9->Start2 --> +<g id="edge4" class="edge"> +<title>If9->Start2:p0</title> +<path fill="none" stroke="red" d="M189.59,-468.09C195.4,-479.09 201.26,-491.78 205,-504 214.42,-534.78 214.99,-545.9 215,-573.83"/> +<polygon fill="red" stroke="red" points="211.5,-574 215,-584 218.5,-574 211.5,-574"/> +<text text-anchor="middle" x="186.59" y="-470.69" font-family="Helvetica,sans-Serif" font-size="8.00">0</text> +</g> +<!-- If9->EQNode8 --> +<g id="edge5" class="edge"> +<title>If9->EQNode8</title> +<path fill="none" stroke="black" d="M170.26,-468.28C170.06,-476.58 169.85,-485.48 169.65,-493.56"/> +<polygon fill="black" stroke="black" points="166.15,-493.51 169.41,-503.6 173.15,-493.68 166.15,-493.51"/> +<text text-anchor="middle" x="167.26" y="-470.88" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> +</g> +<!-- Con_13 --> +<g id="node6" class="node"> +<title>Con_13</title> +<ellipse fill="none" stroke="black" cx="71" cy="-522" rx="27" ry="18"/> +<text text-anchor="middle" x="71" y="-518.3" font-family="Times,serif" font-size="14.00">#2</text> +</g> +<!-- EQNode14 --> +<g id="node7" class="node"> +<title>EQNode14</title> +<ellipse fill="none" stroke="black" cx="71" cy="-436" rx="27" ry="18"/> +<text text-anchor="middle" x="71" y="-432.3" font-family="Times,serif" font-size="14.00">==</text> +</g> +<!-- EQNode14->Start2 --> +<g id="edge6" class="edge"> +<title>EQNode14->Start2:p1</title> +<path fill="none" stroke="black" d="M79.96,-453.18C95.23,-480.56 125.41,-533.7 133,-540 173.12,-573.31 240.9,-534.16 249.98,-573.92"/> +<polygon fill="black" stroke="black" points="246.51,-574.4 251,-584 253.48,-573.7 246.51,-574.4"/> +<text text-anchor="middle" x="76.96" y="-455.78" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> +</g> +<!-- EQNode14->Con_13 --> +<g id="edge7" class="edge"> +<title>EQNode14->Con_13</title> +<path fill="none" stroke="black" d="M71,-454.4C71,-465.74 71,-480.77 71,-493.68"/> +<polygon fill="black" stroke="black" points="67.5,-493.9 71,-503.9 74.5,-493.9 67.5,-493.9"/> +<text text-anchor="middle" x="68" y="-457" font-family="Helvetica,sans-Serif" font-size="8.00">2</text> +</g> +<!-- If15 --> +<g id="node8" class="node"> +<title>If15</title> +<polygon fill="yellow" stroke="transparent" points="24,-339 24,-364 118,-364 118,-339 24,-339"/> +<polygon fill="none" stroke="black" points="24,-339 24,-364 118,-364 118,-339 24,-339"/> +<text text-anchor="start" x="65.5" y="-347.8" font-family="Times,serif" font-size="14.00">If</text> +<polygon fill="none" stroke="black" points="24,-308 24,-339 118,-339 118,-308 24,-308"/> +<polygon fill="yellow" stroke="transparent" points="29,-313 29,-334 69,-334 69,-313 29,-313"/> +<polygon fill="none" stroke="black" points="29,-313 29,-334 69,-334 69,-313 29,-313"/> +<text text-anchor="start" x="32" y="-319.8" font-family="Times,serif" font-size="14.00">True</text> +<polygon fill="yellow" stroke="transparent" points="69,-313 69,-334 113,-334 113,-313 69,-313"/> +<polygon fill="none" stroke="black" points="69,-313 69,-334 113,-334 113,-313 69,-313"/> +<text text-anchor="start" x="72" y="-319.8" font-family="Times,serif" font-size="14.00">False</text> +</g> +<!-- If15->If9 --> +<g id="edge8" class="edge"> +<title>If15->If9:p0</title> +<path fill="none" stroke="red" d="M88.21,-368.05C98.39,-385.75 110.98,-406.4 119.78,-416.61"/> +<polygon fill="red" stroke="red" points="117.96,-419.62 128,-423 122.25,-414.1 117.96,-419.62"/> +<text text-anchor="middle" x="85.21" y="-370.65" font-family="Helvetica,sans-Serif" font-size="8.00">0</text> +</g> +<!-- If15->EQNode14 --> +<g id="edge9" class="edge"> +<title>If15->EQNode14</title> +<path fill="none" stroke="black" d="M71,-368.01C71,-380.76 71,-395.4 71,-407.73"/> +<polygon fill="black" stroke="black" points="67.5,-407.87 71,-417.87 74.5,-407.87 67.5,-407.87"/> +<text text-anchor="middle" x="68" y="-370.61" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> +</g> +<!-- Con_19 --> +<g id="node9" class="node"> +<title>Con_19</title> +<ellipse fill="none" stroke="black" cx="443" cy="-336" rx="27" ry="18"/> +<text text-anchor="middle" x="443" y="-332.3" font-family="Times,serif" font-size="14.00">#2</text> +</g> +<!-- Con_20 --> +<g id="node10" class="node"> +<title>Con_20</title> +<ellipse fill="none" stroke="black" cx="515" cy="-336" rx="27" ry="18"/> +<text text-anchor="middle" x="515" y="-332.3" font-family="Times,serif" font-size="14.00">#3</text> +</g> +<!-- Region21 --> +<g id="node11" class="node"> +<title>Region21</title> +<polygon fill="yellow" stroke="black" points="147,-268 81,-268 81,-232 147,-232 147,-268"/> +<text text-anchor="middle" x="114" y="-246.3" font-family="Times,serif" font-size="14.00">Region</text> +</g> +<!-- Region21->If15 --> +<g id="edge10" class="edge"> +<title>Region21->If15:p0</title> +<path fill="none" stroke="red" d="M80.74,-267.13C67.62,-275.57 54.67,-287.24 50.44,-301.92"/> +<polygon fill="red" stroke="red" points="46.94,-301.61 49,-312 53.87,-302.59 46.94,-301.61"/> +<text text-anchor="middle" x="77.74" y="-260.73" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> +</g> +<!-- Region21->If15 --> +<g id="edge11" class="edge"> +<title>Region21->If15:p1</title> +<path fill="none" stroke="red" d="M103.71,-268.24C98.93,-277.52 93.86,-289.54 91.87,-301.76"/> +<polygon fill="red" stroke="red" points="88.36,-301.74 91,-312 95.34,-302.33 88.36,-301.74"/> +<text text-anchor="middle" x="100.71" y="-270.84" font-family="Helvetica,sans-Serif" font-size="8.00">2</text> +</g> +<!-- Phi_a22 --> +<g id="node12" class="node"> +<title>Phi_a22</title> +<ellipse fill="lightyellow" stroke="black" cx="407" cy="-250" rx="27" ry="18"/> +<text text-anchor="middle" x="407" y="-246.3" font-family="Times,serif" font-size="14.00">φ_a</text> +</g> +<!-- Phi_a22->Con_19 --> +<g id="edge13" class="edge"> +<title>Phi_a22->Con_19</title> +<path fill="none" stroke="black" d="M414.11,-267.6C419.19,-279.45 426.12,-295.62 431.92,-309.15"/> +<polygon fill="black" stroke="black" points="428.75,-310.63 435.9,-318.44 435.18,-307.87 428.75,-310.63"/> +<text text-anchor="middle" x="411.11" y="-270.2" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> +</g> +<!-- Phi_a22->Con_20 --> +<g id="edge14" class="edge"> +<title>Phi_a22->Con_20</title> +<path fill="none" stroke="black" d="M425.04,-263.7C439.78,-274.21 461.03,-289.69 479,-304 483.17,-307.32 487.52,-310.94 491.71,-314.49"/> +<polygon fill="black" stroke="black" points="489.59,-317.28 499.45,-321.15 494.15,-311.98 489.59,-317.28"/> +<text text-anchor="middle" x="422.04" y="-266.3" font-family="Helvetica,sans-Serif" font-size="8.00">2</text> +</g> +<!-- Phi_a22->Region21 --> +<g id="edge12" class="edge"> +<title>Phi_a22->Region21</title> +<path fill="none" stroke="black" stroke-dasharray="1,5" d="M386.5,-238C370.6,-229.42 347.68,-218.6 326,-214 265.57,-201.18 247.16,-199.97 187,-214 175.19,-216.75 163.08,-221.71 152.22,-227.08"/> +<polygon fill="black" stroke="black" points="150.28,-224.14 143.03,-231.86 153.51,-230.35 150.28,-224.14"/> +<text text-anchor="middle" x="383.5" y="-231.6" font-family="Helvetica,sans-Serif" font-size="8.00">0</text> +</g> +<!-- Con_23 --> +<g id="node13" class="node"> +<title>Con_23</title> +<ellipse fill="none" stroke="black" cx="297" cy="-522" rx="27" ry="18"/> +<text text-anchor="middle" x="297" y="-518.3" font-family="Times,serif" font-size="14.00">#3</text> +</g> +<!-- EQNode24 --> +<g id="node14" class="node"> +<title>EQNode24</title> +<ellipse fill="none" stroke="black" cx="271" cy="-436" rx="27" ry="18"/> +<text text-anchor="middle" x="271" y="-432.3" font-family="Times,serif" font-size="14.00">==</text> +</g> +<!-- EQNode24->Start2 --> +<g id="edge15" class="edge"> +<title>EQNode24->Start2:p1</title> +<path fill="none" stroke="black" d="M267.14,-454.1C261.74,-479.48 252.43,-528.98 251.15,-573.9"/> +<polygon fill="black" stroke="black" points="247.65,-573.95 251,-584 254.65,-574.05 247.65,-573.95"/> +<text text-anchor="middle" x="264.14" y="-456.7" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> +</g> +<!-- EQNode24->Con_23 --> +<g id="edge16" class="edge"> +<title>EQNode24->Con_23</title> +<path fill="none" stroke="black" d="M276.26,-454C279.88,-465.69 284.76,-481.44 288.87,-494.73"/> +<polygon fill="black" stroke="black" points="285.53,-495.8 291.84,-504.31 292.22,-493.73 285.53,-495.8"/> +<text text-anchor="middle" x="273.26" y="-456.6" font-family="Helvetica,sans-Serif" font-size="8.00">2</text> +</g> +<!-- If25 --> +<g id="node15" class="node"> +<title>If25</title> +<polygon fill="yellow" stroke="transparent" points="152,-339 152,-364 246,-364 246,-339 152,-339"/> +<polygon fill="none" stroke="black" points="152,-339 152,-364 246,-364 246,-339 152,-339"/> +<text text-anchor="start" x="193.5" y="-347.8" font-family="Times,serif" font-size="14.00">If</text> +<polygon fill="none" stroke="black" points="152,-308 152,-339 246,-339 246,-308 152,-308"/> +<polygon fill="yellow" stroke="transparent" points="157,-313 157,-334 197,-334 197,-313 157,-313"/> +<polygon fill="none" stroke="black" points="157,-313 157,-334 197,-334 197,-313 157,-313"/> +<text text-anchor="start" x="160" y="-319.8" font-family="Times,serif" font-size="14.00">True</text> +<polygon fill="yellow" stroke="transparent" points="197,-313 197,-334 241,-334 241,-313 197,-313"/> +<polygon fill="none" stroke="black" points="197,-313 197,-334 241,-334 241,-313 197,-313"/> +<text text-anchor="start" x="200" y="-319.8" font-family="Times,serif" font-size="14.00">False</text> +</g> +<!-- If25->If9 --> +<g id="edge17" class="edge"> +<title>If25->If9:p1</title> +<path fill="none" stroke="red" d="M194.16,-368.3C192.87,-378.58 191.7,-390.29 191.23,-401.68"/> +<polygon fill="red" stroke="red" points="187.72,-401.93 191,-412 194.72,-402.08 187.72,-401.93"/> +<text text-anchor="middle" x="191.16" y="-370.9" font-family="Helvetica,sans-Serif" font-size="8.00">0</text> +</g> +<!-- If25->EQNode24 --> +<g id="edge18" class="edge"> +<title>If25->EQNode24</title> +<path fill="none" stroke="black" d="M221.78,-368.01C232.02,-381.95 243.93,-398.15 253.46,-411.12"/> +<polygon fill="black" stroke="black" points="250.89,-413.54 259.63,-419.53 256.53,-409.39 250.89,-413.54"/> +<text text-anchor="middle" x="218.78" y="-370.61" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> +</g> +<!-- Con_29 --> +<g id="node16" class="node"> +<title>Con_29</title> +<ellipse fill="none" stroke="black" cx="299" cy="-336" rx="27" ry="18"/> +<text text-anchor="middle" x="299" y="-332.3" font-family="Times,serif" font-size="14.00">#4</text> +</g> +<!-- Con_30 --> +<g id="node17" class="node"> +<title>Con_30</title> +<ellipse fill="none" stroke="black" cx="371" cy="-336" rx="27" ry="18"/> +<text text-anchor="middle" x="371" y="-332.3" font-family="Times,serif" font-size="14.00">#5</text> +</g> +<!-- Region31 --> +<g id="node18" class="node"> +<title>Region31</title> +<polygon fill="yellow" stroke="black" points="253,-268 187,-268 187,-232 253,-232 253,-268"/> +<text text-anchor="middle" x="220" y="-246.3" font-family="Times,serif" font-size="14.00">Region</text> +</g> +<!-- Region31->If25 --> +<g id="edge19" class="edge"> +<title>Region31->If25:p0</title> +<path fill="none" stroke="red" d="M199.51,-268.03C190.68,-276.94 181.63,-288.71 178.32,-301.78"/> +<polygon fill="red" stroke="red" points="174.81,-301.63 177,-312 181.75,-302.53 174.81,-301.63"/> +<text text-anchor="middle" x="196.51" y="-270.63" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> +</g> +<!-- Region31->If25 --> +<g id="edge20" class="edge"> +<title>Region31->If25:p1</title> +<path fill="none" stroke="red" d="M219.57,-268.09C219.36,-277.55 219.13,-289.77 219.04,-301.69"/> +<polygon fill="red" stroke="red" points="215.54,-301.99 219,-312 222.54,-302.01 215.54,-301.99"/> +<text text-anchor="middle" x="216.57" y="-270.69" font-family="Helvetica,sans-Serif" font-size="8.00">2</text> +</g> +<!-- Phi_a32 --> +<g id="node19" class="node"> +<title>Phi_a32</title> +<ellipse fill="lightyellow" stroke="black" cx="299" cy="-250" rx="27" ry="18"/> +<text text-anchor="middle" x="299" y="-246.3" font-family="Times,serif" font-size="14.00">φ_a</text> +</g> +<!-- Phi_a32->Con_29 --> +<g id="edge22" class="edge"> +<title>Phi_a32->Con_29</title> +<path fill="none" stroke="black" d="M299,-268.4C299,-279.74 299,-294.77 299,-307.68"/> +<polygon fill="black" stroke="black" points="295.5,-307.9 299,-317.9 302.5,-307.9 295.5,-307.9"/> +<text text-anchor="middle" x="296" y="-271" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> +</g> +<!-- Phi_a32->Con_30 --> +<g id="edge23" class="edge"> +<title>Phi_a32->Con_30</title> +<path fill="none" stroke="black" d="M311.87,-266.02C322.93,-278.92 339.04,-297.71 351.65,-312.42"/> +<polygon fill="black" stroke="black" points="349.07,-314.8 358.24,-320.11 354.39,-310.24 349.07,-314.8"/> +<text text-anchor="middle" x="308.87" y="-268.62" font-family="Helvetica,sans-Serif" font-size="8.00">2</text> +</g> +<!-- Phi_a32->Region31 --> +<g id="edge21" class="edge"> +<title>Phi_a32->Region31</title> +<path fill="none" stroke="black" stroke-dasharray="1,5" d="M271.7,-250C268.88,-250 266.06,-250 263.23,-250"/> +<polygon fill="black" stroke="black" points="263.02,-246.5 253.02,-250 263.02,-253.5 263.02,-246.5"/> +<text text-anchor="middle" x="268.7" y="-243.6" font-family="Helvetica,sans-Serif" font-size="8.00">0</text> +</g> +<!-- Region33 --> +<g id="node20" class="node"> +<title>Region33</title> +<polygon fill="yellow" stroke="black" points="253,-196 187,-196 187,-160 253,-160 253,-196"/> +<text text-anchor="middle" x="220" y="-174.3" font-family="Times,serif" font-size="14.00">Region</text> +</g> +<!-- Region33->Region21 --> +<g id="edge24" class="edge"> +<title>Region33->Region21</title> +<path fill="none" stroke="red" d="M194.07,-196.12C180.34,-205.19 163.29,-216.45 148.46,-226.24"/> +<polygon fill="red" stroke="red" points="146.45,-223.38 140.03,-231.81 150.3,-229.22 146.45,-223.38"/> +<text text-anchor="middle" x="191.07" y="-198.72" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> +</g> +<!-- Region33->Region31 --> +<g id="edge25" class="edge"> +<title>Region33->Region31</title> +<path fill="none" stroke="red" d="M220,-196.3C220,-204.02 220,-213.29 220,-221.89"/> +<polygon fill="red" stroke="red" points="216.5,-221.9 220,-231.9 223.5,-221.9 216.5,-221.9"/> +<text text-anchor="middle" x="217" y="-198.9" font-family="Helvetica,sans-Serif" font-size="8.00">2</text> +</g> +<!-- Phi_a34 --> +<g id="node21" class="node"> +<title>Phi_a34</title> +<ellipse fill="lightyellow" stroke="black" cx="299" cy="-178" rx="27" ry="18"/> +<text text-anchor="middle" x="299" y="-174.3" font-family="Times,serif" font-size="14.00">φ_a</text> +</g> +<!-- Phi_a34->Phi_a22 --> +<g id="edge27" class="edge"> +<title>Phi_a34->Phi_a22</title> +<path fill="none" stroke="black" d="M317.81,-191.19C335,-202.33 360.62,-218.94 379.99,-231.5"/> +<polygon fill="black" stroke="black" points="378.11,-234.44 388.4,-236.95 381.92,-228.57 378.11,-234.44"/> +<text text-anchor="middle" x="314.81" y="-193.79" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> +</g> +<!-- Phi_a34->Phi_a32 --> +<g id="edge28" class="edge"> +<title>Phi_a34->Phi_a32</title> +<path fill="none" stroke="black" d="M299,-196.3C299,-204.02 299,-213.29 299,-221.89"/> +<polygon fill="black" stroke="black" points="295.5,-221.9 299,-231.9 302.5,-221.9 295.5,-221.9"/> +<text text-anchor="middle" x="296" y="-198.9" font-family="Helvetica,sans-Serif" font-size="8.00">2</text> +</g> +<!-- Phi_a34->Region33 --> +<g id="edge26" class="edge"> +<title>Phi_a34->Region33</title> +<path fill="none" stroke="black" stroke-dasharray="1,5" d="M271.7,-178C268.88,-178 266.06,-178 263.23,-178"/> +<polygon fill="black" stroke="black" points="263.02,-174.5 253.02,-178 263.02,-181.5 263.02,-174.5"/> +<text text-anchor="middle" x="268.7" y="-171.6" font-family="Helvetica,sans-Serif" font-size="8.00">0</text> +</g> +<!-- Return35->Region33 --> +<g id="edge29" class="edge"> +<title>Return35->Region33</title> +<path fill="none" stroke="red" d="M249.36,-124.3C244.87,-132.36 239.44,-142.11 234.48,-151.02"/> +<polygon fill="red" stroke="red" points="231.34,-149.46 229.53,-159.9 237.45,-152.86 231.34,-149.46"/> +<text text-anchor="middle" x="246.36" y="-126.9" font-family="Helvetica,sans-Serif" font-size="8.00">0</text> +</g> +<!-- Return35->Phi_a34 --> +<g id="edge30" class="edge"> +<title>Return35->Phi_a34</title> +<path fill="none" stroke="black" d="M268.89,-124.3C273.68,-132.68 279.52,-142.9 284.77,-152.1"/> +<polygon fill="black" stroke="black" points="281.77,-153.91 289.77,-160.86 287.85,-150.44 281.77,-153.91"/> +<text text-anchor="middle" x="265.89" y="-126.9" font-family="Helvetica,sans-Serif" font-size="8.00">1</text> +</g> +<!-- Scope1_0 --> +<g id="node23" class="node"> +<title>Scope1_0</title> +<polygon fill="cyan" stroke="transparent" points="655,-95 655,-116 671,-116 671,-95 655,-95"/> +<polygon fill="none" stroke="black" points="655,-95 655,-116 671,-116 671,-95 655,-95"/> +<text text-anchor="start" x="658" y="-101.8" font-family="Times,serif" font-size="14.00">0</text> +<polygon fill="none" stroke="black" points="671,-95 671,-116 711,-116 711,-95 671,-95"/> +<text text-anchor="start" x="674" y="-101.8" font-family="Times,serif" font-size="14.00">$ctrl</text> +<polygon fill="none" stroke="black" points="711,-95 711,-116 742,-116 742,-95 711,-95"/> +<text text-anchor="start" x="714" y="-101.8" font-family="Times,serif" font-size="14.00">arg</text> +</g> +<!-- Scope1_0->Start2 --> +<g id="edge31" class="edge"> +<title>Scope1_0:Scope1_0_arg->Start2:p1</title> +<path fill="none" stroke="cornflowerblue" stroke-dasharray="5,2" d="M727,-117C727,-185.37 648,-180.63 648,-249 648,-249 648,-249 648,-437 648,-525.53 378.1,-590.44 277.07,-594.77"/> +<polygon fill="cornflowerblue" stroke="cornflowerblue" points="276.92,-591.27 267,-595 277.08,-598.27 276.92,-591.27"/> +</g> +<!-- Scope1_1 --> +<g id="node24" class="node"> +<title>Scope1_1</title> +<polygon fill="cyan" stroke="transparent" points="586,-95 586,-116 602,-116 602,-95 586,-95"/> +<polygon fill="none" stroke="black" points="586,-95 586,-116 602,-116 602,-95 586,-95"/> +<text text-anchor="start" x="589" y="-101.8" font-family="Times,serif" font-size="14.00">1</text> +<polygon fill="none" stroke="black" points="602,-95 602,-116 617,-116 617,-95 602,-95"/> +<text text-anchor="start" x="605" y="-101.8" font-family="Times,serif" font-size="14.00">a</text> +</g> +<!-- Scope1_1->Phi_a34 --> +<g id="edge32" class="edge"> +<title>Scope1_1:Scope1_1_a->Phi_a34</title> +<path fill="none" stroke="cornflowerblue" stroke-dasharray="5,2" d="M610,-117C610,-172.18 418.84,-177.72 336.26,-177.53"/> +<polygon fill="cornflowerblue" stroke="cornflowerblue" points="336.07,-174.03 326.06,-177.48 336.04,-181.03 336.07,-174.03"/> +</g> +</g> +</svg> diff --git a/chapter05/src/main/java/com/seaofnodes/simple/GraphVisualizer.java b/chapter05/src/main/java/com/seaofnodes/simple/GraphVisualizer.java index f3942edb..01b5aeeb 100644 --- a/chapter05/src/main/java/com/seaofnodes/simple/GraphVisualizer.java +++ b/chapter05/src/main/java/com/seaofnodes/simple/GraphVisualizer.java @@ -146,7 +146,7 @@ public class GraphVisualizer { // Walk the node edges private void nodeEdges(StringBuilder sb, Collection<Node> all) { // All them edge labels - sb.append("\tedge [ fontname=Helvetica, fontsize=8 ];\n"); + sb.append("\tedge [ fontname=Helvetica, fontsize=8 ];\n"); for( Node n : all ) { // Do not display the Constant->Start edge; // ProjNodes handled by Multi; @@ -155,16 +155,12 @@ public class GraphVisualizer { continue; int i=0; for( Node def : n._inputs ) { - // Do not draw the Phi->Region edge (in red); instead Phis are - // on a line with their Region, and we draw an invisible line - // from the Region to the Phi, to force all the Phis to the - // right of the Region. if( n instanceof PhiNode && def instanceof RegionNode ) { - sb.append('\t').append(def.uniqueName()); + // Draw a dotted use->def edge from Phi to Region. + sb.append('\t').append(n.uniqueName()); sb.append(" -> "); - sb.append(n.uniqueName()); - sb.append(" [style=invis]\n"); - + sb.append(def.uniqueName()); + sb.append(" [style=dotted taillabel=").append(i).append("];\n"); } else if( def != null ) { // Most edges land here use->def sb.append('\t').append(n.uniqueName()).append(" -> "); @@ -176,7 +172,7 @@ public class GraphVisualizer { sb.append("[taillabel=").append(i); // control edges are colored red if( def.isCFG() ) - sb.append("; color=red"); + sb.append(" color=red"); sb.append("];\n"); } i++; diff --git a/chapter05/src/main/java/com/seaofnodes/simple/Parser.java b/chapter05/src/main/java/com/seaofnodes/simple/Parser.java index 8bf343b3..a132fce0 100644 --- a/chapter05/src/main/java/com/seaofnodes/simple/Parser.java +++ b/chapter05/src/main/java/com/seaofnodes/simple/Parser.java @@ -94,6 +94,7 @@ public class Parser { _scope.define(CTRL , new ProjNode(START, 0, CTRL ).peephole()); _scope.define("arg", new ProjNode(START, 1, "arg").peephole()); parseBlock(); + if (!_lexer.isEOF()) throw error("Syntax error, unexpected " + _lexer.getAnyNextToken()); return STOP; } finally { @@ -129,7 +130,7 @@ public class Parser { * Parses a statement * * <pre> - * returnStatement | declStatement | blockStatement | expressionStatement + * returnStatement | declStatement | blockStatement | ifStatement | expressionStatement * </pre> * @return a {@link Node} or {@code null} */ diff --git a/chapter05/src/main/java/com/seaofnodes/simple/node/MinusNode.java b/chapter05/src/main/java/com/seaofnodes/simple/node/MinusNode.java index 834f4c11..533155d9 100644 --- a/chapter05/src/main/java/com/seaofnodes/simple/node/MinusNode.java +++ b/chapter05/src/main/java/com/seaofnodes/simple/node/MinusNode.java @@ -20,7 +20,7 @@ public class MinusNode extends Node { @Override public Type compute() { if (in(1)._type instanceof TypeInteger i0) - return TypeInteger.constant(-i0.value()); + return i0.isConstant() ? TypeInteger.constant(-i0.value()) : i0; return TypeBot.BOTTOM; } diff --git a/chapter05/src/main/java/com/seaofnodes/simple/node/ScopeNode.java b/chapter05/src/main/java/com/seaofnodes/simple/node/ScopeNode.java index 64061030..61fac118 100644 --- a/chapter05/src/main/java/com/seaofnodes/simple/node/ScopeNode.java +++ b/chapter05/src/main/java/com/seaofnodes/simple/node/ScopeNode.java @@ -105,6 +105,10 @@ public class ScopeNode extends Node { * The new Scope is a full-fledged Node with proper use<->def edges. */ public ScopeNode dup() { + // Our goals are: + // 1) duplicate the name bindings of the ScopeNode across all stack levels + // 2) Make the new ScopeNode a user of all the nodes bound + // 3) Ensure that the order of defs is the same to allow easy merging ScopeNode dup = new ScopeNode(); for( HashMap<String, Integer> tab : _scopes ) dup._scopes.push(new HashMap<>(tab)); @@ -114,6 +118,14 @@ public class ScopeNode extends Node { return dup; } + /** + * Merges the names whose node bindings differ, by creating Phi node for such names + * The names could occur at all stack levels, but a given name can only differ in the + * innermost stack level where the name is bound. + * + * @param that The ScopeNode to be merged into this + * @return A new Region node representing the merge point + */ public RegionNode mergeScopes(ScopeNode that) { RegionNode r = (RegionNode)ctrl(new RegionNode(null,ctrl(), that.ctrl()).peephole()); for( int i=1; i<nIns(); i++ ) diff --git a/chapter05/src/test/java/com/seaofnodes/simple/Chapter05Test.java b/chapter05/src/test/java/com/seaofnodes/simple/Chapter05Test.java index 0516fb73..e40136bd 100644 --- a/chapter05/src/test/java/com/seaofnodes/simple/Chapter05Test.java +++ b/chapter05/src/test/java/com/seaofnodes/simple/Chapter05Test.java @@ -21,8 +21,7 @@ else { #showGraph; } #showGraph; -return a; -"""); +return a;"""); StopNode ret = parser.parse(true); assertEquals("return Phi(Region17,(arg+2),(arg-3));", ret.toString()); } @@ -36,50 +35,94 @@ if (arg == 1) { b = 3; c = 4; } -return c; - """, TypeInteger.BOT); - StopNode ret = parser.parse(); +return c;""", TypeInteger.BOT); + StopNode ret = parser.parse(true); assertEquals("return Phi(Region16,4,3);", ret.toString()); } @Test public void testChapter5Return2() { - Parser parser = new Parser("if( arg==1 ) return 3; else return 4; #showGraph;", TypeInteger.BOT); + Parser parser = new Parser(""" +if( arg==1 ) + return 3; +else + return 4; +#showGraph;""", TypeInteger.BOT); StopNode stop = parser.parse(); assertEquals("Stop[ return 3; return 4; ]", stop.toString()); } @Test public void testChapter5IfMergeB() { - Parser parser = new Parser("int a=arg+1; int b=0; if( arg==1 ) b=a; else b=a+1; return a+b;"); + Parser parser = new Parser(""" +int a=arg+1; +int b=0; +if( arg==1 ) + b=a; +else + b=a+1; +return a+b;"""); StopNode ret = parser.parse(true); assertEquals("return ((arg*2)+Phi(Region20,2,3));", ret.toString()); } @Test public void testChapter5IfMerge2() { - Parser parser = new Parser("int a=arg+1; int b=arg+2; if( arg==1 ) b=b+a; else a=b+1; return a+b;"); + Parser parser = new Parser(""" +int a=arg+1; +int b=arg+2; +if( arg==1 ) + b=b+a; +else + a=b+1; +return a+b;"""); StopNode ret = parser.parse(true); assertEquals("return ((Phi(Region31,(arg*2),arg)+arg)+Phi(Region31,4,5));", ret.toString()); } @Test public void testChapter5Merge3() { - Parser parser = new Parser("int a=1; if( arg==1 ) if( arg==2 ) a=2; else a=3; else if( arg==3 ) a=4; else a=5; return a; #showGraph;", TypeInteger.BOT); + Parser parser = new Parser(""" +int a=1; +if( arg==1 ) + if( arg==2 ) + a=2; + else + a=3; +else if( arg==3 ) + a=4; +else + a=5; +return a; +#showGraph;""", TypeInteger.BOT); StopNode stop = parser.parse(); assertEquals("return Phi(Region33,Phi(Region21,2,3),Phi(Region31,4,5));", stop.toString()); } @Test public void testChapter5Merge4() { - Parser parser = new Parser("int a=0;int b=0;if(arg)a=1;if(arg==0)b=2;return arg+a+b;#showGraph;", TypeInteger.BOT); + Parser parser = new Parser(""" +int a=0; +int b=0; +if( arg ) + a=1; +if( arg==0 ) + b=2; +return arg+a+b; +#showGraph;""", TypeInteger.BOT); StopNode stop = parser.parse(); assertEquals("return ((arg+Phi(Region13,1,0))+Phi(Region22,2,0));", stop.toString()); } @Test public void testChapter5Merge5() { - Parser parser = new Parser("int a=arg==2;if(arg==1)a=arg==3;return a;"); + Parser parser = new Parser(""" +int a=arg==2; +if( arg==1 ) +{ + a=arg==3; +} +return a;"""); StopNode ret = parser.parse(true); assertEquals("return (arg==Phi(Region16,3,2));", ret.toString()); } @@ -259,6 +302,13 @@ return c; assertEquals("Undefined name 'inta'",e.getMessage()); } } + + @Test + public void testChapter4Bug4() { + Parser parser = new Parser("return -arg;"); + StopNode ret = parser.parse(); + assertEquals("return (-arg);", ret.print()); + } @Test public void testVarDecl() { @@ -440,4 +490,15 @@ return c; assertEquals("Syntax error, expected }: ",e.getMessage()); } } + + @Test + public void testBad7() { + try { + new Parser("return 1;}").parse(); + fail(); + } catch( RuntimeException e ) { + assertEquals("Syntax error, unexpected }",e.getMessage()); + } + } + } |
