summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/Parser.java64
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java2
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/CallEndNode.java5
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallARM.java4
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallRRARM.java2
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRISC.java3
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRRISC.java2
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallX86.java2
-rw-r--r--chapter23/src/test/java/com/seaofnodes/simple/Chapter22Test.java4
-rw-r--r--chapter23/src/test/java/com/seaofnodes/simple/Chapter23Test.java125
-rw-r--r--chapter23/src/test/java/com/seaofnodes/simple/EvalArm64.java11
-rw-r--r--chapter23/src/test/java/com/seaofnodes/simple/TestC.java22
-rw-r--r--chapter23/src/test/java/com/seaofnodes/simple/progs/and1.smp10
-rw-r--r--chapter23/src/test/java/com/seaofnodes/simple/progs/and2.smp16
-rw-r--r--chapter23/src/test/java/com/seaofnodes/simple/progs/and3.smp14
-rw-r--r--chapter23/src/test/java/com/seaofnodes/simple/progs/or1.smp12
-rw-r--r--chapter23/src/test/java/com/seaofnodes/simple/progs/or2.smp23
-rw-r--r--chapter23/src/test/java/com/seaofnodes/simple/progs/ptrand.smp10
18 files changed, 301 insertions, 30 deletions
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/Parser.java b/chapter23/src/main/java/com/seaofnodes/simple/Parser.java
index 1db873e0..ffd4bfe9 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/Parser.java
+++ b/chapter23/src/main/java/com/seaofnodes/simple/Parser.java
@@ -530,11 +530,11 @@ public class Parser {
// Parse predicate
require("(");
var pred = require(parseAsgn(), ")");
- return parseTrinary(pred,true,"else");
+ return parseTrinary(pred,"else");
}
// Parse a conditional expression, merging results.
- private Node parseTrinary( Node pred, boolean stmt, String fside ) {
+ private Node parseTrinary( Node pred, String fside ) {
pred.keep();
// IfNode takes current control and predicate
@@ -550,7 +550,15 @@ public class Parser {
// Parse the true side
ctrl(ifT.unkeep()); // set ctrl token to ifTrue projection
_scope.addGuards(ifT,pred,false); // Up-cast predicate
- Node lhs = (stmt ? parseStatement() : parseAsgn()).keep(); // Parse true-side
+ // Parse true-side flavor
+ Node lhs = switch( fside ) {
+ case "else" -> parseStatement(); // if( pred ) stmts;
+ case ":" -> parseAsgn(); // pred ? asgn;
+ case "&&" -> parseLogical(); // pred && expr
+ case "||" -> pred; // pred || expr_is_ignored
+ default -> throw Utils.TODO();
+ };
+ lhs.keep();
_scope.removeGuards(ifT);
// See if a one-sided def was made: "if(pred) int x = 1;" and throw.
@@ -566,17 +574,23 @@ public class Parser {
// Up-cast predicate, even if not else clause, because predicate can
// remain true if the true clause exits: `if( !ptr ) return 0; return ptr.fld;`
_scope.addGuards(ifF,pred,true);
- boolean doRHS = match(fside);
- Node rhs = (doRHS
- ? (stmt ? parseStatement() : parseAsgn())
- : con(lhs._type.makeZero())).keep();
+ // Parse false-side flavor
+ boolean doRHS = false; // RHS is optional for if/else and trinary
+ Node rhs = switch( fside ) {
+ case "else" -> (doRHS=match(fside)) ? parseStatement() : con(lhs._type.makeZero());
+ case ":" -> (doRHS=match(fside)) ? parseAsgn() : con(lhs._type.makeZero());
+ case "&&" -> rhs = pred;
+ case "||" -> rhs = parseLogical();
+ default -> throw Utils.TODO();
+ };
+ rhs.keep();
_scope.removeGuards(ifF);
if( doRHS )
fScope = _scope;
pred.unkeep();
// Check the trinary widening int/flt
- if( !stmt ) {
+ if( !fside.equals("else") ) {
rhs = widenInt( rhs.unkeep(), lhs._type ).keep();
lhs = widenInt( lhs.unkeep(), rhs._type ).keep();
}
@@ -593,7 +607,7 @@ public class Parser {
Node ret = peep(new PhiNode("",lhs._type.meet(rhs._type).glb(false),r,lhs.unkeep(),rhs.unkeep()));
// Immediately fail e.g. `arg ? 7 : ptr`
ParseException err;
- if( !stmt && (err=ret.err()) !=null ) throw err;
+ if( !fside.equals("else") && (err=ret.err()) !=null ) throw err;
r.peephole();
return ret;
}
@@ -993,8 +1007,8 @@ public class Parser {
* @return an expression {@link Node}, never {@code null}
*/
private Node parseExpression() {
- Node expr = parseBitwise();
- return match("?") ? parseTrinary(expr,false,":") : expr;
+ Node expr = parseLogical();
+ return match("?") ? parseTrinary(expr,":") : expr;
}
/**
@@ -1005,13 +1019,25 @@ public class Parser {
* </pre>
* @return a bitwise expression {@link Node}, never {@code null}
*/
+
+ private Node parseLogical() {
+ Node lhs = parseBitwise();
+ while (true) {
+ if( false ) ;
+ else if( match("&&") ) lhs = parseTrinary(lhs, "&&");
+ else if( match("||") ) lhs = parseTrinary(lhs, "||");
+ else break;
+ }
+ return lhs;
+ }
+
private Node parseBitwise() {
Node lhs = parseComparison();
while( true ) {
if( false ) ;
- else if( match("&") ) lhs = new AndNode(loc(),lhs,null);
- else if( match("|") ) lhs = new OrNode(loc(),lhs,null);
- else if( match("^") ) lhs = new XorNode(loc(),lhs,null);
+ else if( matchOp('&') ) lhs = new AndNode(loc(),lhs,null);
+ else if( matchOp('|') ) lhs = new OrNode(loc(),lhs,null);
+ else if( match ("^") ) lhs = new XorNode(loc(),lhs,null);
else break;
lhs.setDef(2,parseComparison());
lhs = peep(lhs);
@@ -1701,6 +1727,7 @@ public class Parser {
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); }
+ private boolean matchOp(char c0 ) { return _lexer.matchOp(c0); }
private boolean matchOpx(char c0, char c1) { return _lexer.matchOpx(c0,c1); }
// Return true and do NOT skip if 'ch' is next
private boolean peek(char ch) { return _lexer.peek(ch); }
@@ -1876,6 +1903,15 @@ public class Parser {
_position -= syntax.length();
return false;
}
+ // Match this char, and the next char must be different.
+ // Handles '&&' vs '&'
+ boolean matchOp( char c0 ) {
+ skipWhiteSpace();
+ if( _position+1 >= _input.length || _input[_position]!=c0 || _input[_position+1]==c0 )
+ return false;
+ inc();
+ return true;
+ }
// Match these two characters in a row
boolean matchOpx(char c0, char c1) {
skipWhiteSpace();
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java b/chapter23/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java
index caa7ff44..6c958f32 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java
+++ b/chapter23/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java
@@ -39,6 +39,8 @@ public class CodeGen {
// ---------------------------
public CodeGen( String src ) { this(src, TypeInteger.BOT, 123L, true ); }
+ public CodeGen( String src, TypeInteger arg) { this(src, arg==null ? TypeInteger.BOT : arg, 123L, true ); }
+
public CodeGen( String src, TypeInteger arg, long workListSeed, boolean reset ) {
CODE = this;
if( reset ) Type.reset();
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/node/CallEndNode.java b/chapter23/src/main/java/com/seaofnodes/simple/node/CallEndNode.java
index b75852a4..d95af697 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/node/CallEndNode.java
+++ b/chapter23/src/main/java/com/seaofnodes/simple/node/CallEndNode.java
@@ -86,6 +86,11 @@ public class CallEndNode extends CFGNode implements MultiNode {
fun.setDef(2,call.ctrl()); // Bypass the Call;
fun.ret().setDef(3,null); // Return is folding also
CodeGen.CODE.addAll(fun._outputs);
+ // Repeat defs 1 layer down, for users of Parm (Phis)
+ for( Node parm : fun._outputs )
+ if( parm instanceof ParmNode )
+ CodeGen.CODE.addAll(parm._outputs);
+
// Inlining immediately blows all cache idepth fields past the inline point.
// Bump the global version number invalidating them en-masse.
CodeGen.CODE.invalidateIDepthCaches();
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallARM.java b/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallARM.java
index a2cb9bba..427cf2e2 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallARM.java
+++ b/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallARM.java
@@ -42,9 +42,9 @@ public class CallARM extends CallNode implements MachNode, RIPRelSize {
}
@Override public void asm(CodeGen code, SB sb) {
- sb.p(_name);
+ sb.p(_name).p(" ");
for( int i=0; i<nargs(); i++ )
- sb.p(code.reg(arg(i+2))).p(" ");
+ sb.p(code.reg(arg(i+2))).p(", ");
sb.unchar(2);
}
}
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallRRARM.java b/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallRRARM.java
index a3e1cf19..c84aa9e5 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallRRARM.java
+++ b/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallRRARM.java
@@ -25,7 +25,7 @@ public class CallRRARM extends CallNode implements MachNode {
@Override public void asm(CodeGen code, SB sb) {
sb.p(code.reg(fptr())).p(" ");
for( int i=0; i<nargs(); i++ )
- sb.p(code.reg(arg(i))).p(" ");
+ sb.p(code.reg(arg(i))).p(", ");
sb.unchar(2);
}
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRISC.java b/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRISC.java
index a676ba60..bd5dabe5 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRISC.java
+++ b/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRISC.java
@@ -57,7 +57,6 @@ public class CallRISC extends CallNode implements MachNode, RIPRelSize {
sb.p(_name).p(" ");
for( int i=0; i<nargs(); i++ )
sb.p(code.reg(arg(i+2))).p(", ");
- sb.unchar(2).p(" ").p(code.reg(fptr()));
-
+ sb.unchar(2);
}
}
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRRISC.java b/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRRISC.java
index ac36ed12..298789e8 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRRISC.java
+++ b/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRRISC.java
@@ -25,7 +25,7 @@ public class CallRRISC extends CallNode implements MachNode {
@Override public void asm(CodeGen code, SB sb) {
sb.p(code.reg(fptr())).p(" ");
for( int i=0; i<nargs(); i++ )
- sb.p(code.reg(arg(i))).p(" ");
+ sb.p(code.reg(arg(i))).p(", ");
sb.unchar(2);
}
}
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallX86.java b/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallX86.java
index ffdce7df..d74e3833 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallX86.java
+++ b/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallX86.java
@@ -42,7 +42,7 @@ public class CallX86 extends CallNode implements MachNode, RIPRelSize {
@Override public void asm(CodeGen code, SB sb) {
sb.p(_name).p(" ");
for( int i=0; i<nargs(); i++ )
- sb.p(code.reg(in(i+2))).p(" ");
+ sb.p(code.reg(in(i+2))).p(", ");
sb.unchar(2);
}
}
diff --git a/chapter23/src/test/java/com/seaofnodes/simple/Chapter22Test.java b/chapter23/src/test/java/com/seaofnodes/simple/Chapter22Test.java
index 394ba336..13322d3d 100644
--- a/chapter23/src/test/java/com/seaofnodes/simple/Chapter22Test.java
+++ b/chapter23/src/test/java/com/seaofnodes/simple/Chapter22Test.java
@@ -180,7 +180,7 @@ return cc.cz;
@Test
public void testHelloWorld() throws IOException {
String src = Files.readString(Path.of("src/test/java/com/seaofnodes/simple/progs/helloWorld.smp"));
- TestC.run(src,TestC.CALL_CONVENTION,null,null,"build/objs/helloWorld","","Hello, World!",0);
+ TestC.run(src,TestC.CALL_CONVENTION,null, null,null,"build/objs/helloWorld","","Hello, World!",0);
// Evaluate on RISC5 emulator
EvalRisc5 R5 = TestRisc5.build("helloWorld", 0, 2, false);
@@ -221,7 +221,7 @@ return sum(is);
@Test @Ignore
public void testEcho() throws IOException {
String src = Files.readString(Path.of("src/test/java/com/seaofnodes/simple/progs/echo.smp"));
- TestC.run(src,TestC.CALL_CONVENTION,null,null,"build/objs/echo","","",0);
+ TestC.run(src,TestC.CALL_CONVENTION,null, null,null,"build/objs/echo","","",0);
// Evaluate on RISC5 emulator
EvalRisc5 R5 = TestRisc5.build("echo", 0, 2, false);
diff --git a/chapter23/src/test/java/com/seaofnodes/simple/Chapter23Test.java b/chapter23/src/test/java/com/seaofnodes/simple/Chapter23Test.java
index 20a506fb..12e089fc 100644
--- a/chapter23/src/test/java/com/seaofnodes/simple/Chapter23Test.java
+++ b/chapter23/src/test/java/com/seaofnodes/simple/Chapter23Test.java
@@ -1,6 +1,7 @@
package com.seaofnodes.simple;
import com.seaofnodes.simple.codegen.CodeGen;
+import com.seaofnodes.simple.node.cpus.riscv.riscv;
import com.seaofnodes.simple.type.TypeInteger;
import java.io.IOException;
import java.nio.file.Files;
@@ -32,6 +33,130 @@ public class Chapter23Test {
}
@Test
+ public void testOr() throws IOException {
+ TestC.runS("or1","Or",0);
+
+ // Evaluate on RISC5 emulator
+ EvalRisc5 R5 = TestRisc5.build("or1", 0, 2, false);
+ int trap = R5.step(100);
+ assertEquals(0,trap);
+ assertEquals(0,R5.regs[riscv.A0]);
+ assertEquals("Or",R5._stdout.toString());
+
+ // Evaluate on ARM emulator
+ EvalArm64 arm = TestArm64.build("or1", 0, 2, false);
+ trap = arm.step(100);
+ assertEquals(0,trap);
+ assertEquals(0,arm.regs[0]);
+ assertEquals("Or",arm._stdout.toString());
+ }
+
+ @Test
+ public void testAnd() throws IOException {
+ TestC.runS("and1","And",0);
+
+ // Evaluate on RISC5 emulator
+ EvalRisc5 R5 = TestRisc5.build("and1", 0, 2, false);
+ int trap = R5.step(100);
+ assertEquals(0,trap);
+ assertEquals(0,R5.regs[riscv.A0]);
+ assertEquals("And",R5._stdout.toString());
+
+ // Evaluate on ARM emulator
+ EvalArm64 arm = TestArm64.build("and1", 0, 2, false);
+ trap = arm.step(100);
+ assertEquals(0,trap);
+ assertEquals(0,arm.regs[0]);
+ assertEquals("And",arm._stdout.toString());
+ }
+
+ @Test
+ public void testAndPtr() throws IOException {
+ String src =
+"""
+struct S { S? fld; };
+val ptr = arg == 1 ? null : new S{fld = arg==1 ? null : new S{fld = null;};};
+return ptr && ptr.fld ? "true" : "false";
+ """;
+ CodeGen code = new CodeGen(src).parse().opto().typeCheck();
+ assertEquals("[97-117][ 116,114,117,101]", Eval2.eval(code, 0));
+
+ // Evaluate on RISC5 emulator
+ EvalRisc5 R5 = TestRisc5.build("ptrand", 1, 8, false);
+ int trap = R5.step(100);
+ assertEquals(0,trap);
+ assertEquals(0,R5.regs[riscv.A0]);
+ assertEquals("false",R5._stdout.toString());
+
+ // Evaluate on ARM emulator
+ EvalArm64 arm = TestArm64.build("ptrand", 1, 8, false);
+ trap = arm.step(100);
+ assertEquals(0,trap);
+ assertEquals(0,arm.regs[0]);
+ assertEquals("false",arm._stdout.toString());
+ }
+
+ // conditional side effect
+ @Test
+ public void testCondSideEffAnd() throws IOException {
+ TestC.runS("and2","Effected",0);
+
+ // Evaluate on RISC5 emulator
+ EvalRisc5 R5 = TestRisc5.build("and2", 0, 2, false);
+ int trap = R5.step(100);
+ assertEquals(0,trap);
+ assertEquals(0,R5.regs[riscv.A0]);
+ assertEquals("Effected",R5._stdout.toString());
+
+ // Evaluate on ARM emulator
+ EvalArm64 arm = TestArm64.build("and2", 0, 2, false);
+ trap = arm.step(100);
+ assertEquals(0,trap);
+ assertEquals(0,arm.regs[0]);
+ assertEquals("Effected",arm._stdout.toString());
+ }
+
+
+ @Test
+ public void testCondSideEffOr() throws IOException {
+ TestC.runS("or2","Effected",0);
+
+ // Evaluate on RISC5 emulator
+ EvalRisc5 R5 = TestRisc5.build("or2", 0, 2, false);
+ int trap = R5.step(100);
+ assertEquals(0,trap);
+ assertEquals(0,R5.regs[riscv.A0]);
+ assertEquals("Effected",R5._stdout.toString());
+
+ // Evaluate on ARM emulator
+ EvalArm64 arm = TestArm64.build("or2", 0, 2, false);
+ trap = arm.step(100);
+ assertEquals(0,trap);
+ assertEquals(0,arm.regs[0]);
+ assertEquals("Effected",arm._stdout.toString());
+ }
+
+ // test it with function calls
+ @Test
+ public void testFuncCall() throws IOException {
+ TestC.runS("and3","Or",0);
+
+ // Evaluate on RISC5 emulator
+ EvalRisc5 R5 = TestRisc5.build("and3", 0, 2, false);
+ int trap = R5.step(100);
+ assertEquals(0,trap);
+ assertEquals(0,R5.regs[riscv.A0]);
+ assertEquals("Or",R5._stdout.toString());
+
+ // Evaluate on ARM emulator
+ EvalArm64 arm = TestArm64.build("and3", 0, 2, false);
+ trap = arm.step(100);
+ assertEquals(0,trap);
+ assertEquals(0,arm.regs[0]);
+ assertEquals("Or",arm._stdout.toString());
+ }
+
+ @Test
public void testFRefFields() {
String src =
"""
diff --git a/chapter23/src/test/java/com/seaofnodes/simple/EvalArm64.java b/chapter23/src/test/java/com/seaofnodes/simple/EvalArm64.java
index ec97eab0..c719b8e8 100644
--- a/chapter23/src/test/java/com/seaofnodes/simple/EvalArm64.java
+++ b/chapter23/src/test/java/com/seaofnodes/simple/EvalArm64.java
@@ -573,11 +573,16 @@ public class EvalArm64 {
break;
}
case 0xD6: {
+ if( (ir & 0xFFFF) != 0 ) throw Utils.TODO();
+ if( ((ir>>16) & 0xFF) != 0x5F ) throw Utils.TODO(); // 0x3F is register call
rdid = -1;
+ int rn = ir << 22 >> 27;
+ assert rn == 0;
+ pc = (int)regs[30];
// Return to zero breaks simulation
- if(regs[30] == 0)
- break outer;
- throw Utils.TODO();
+ if( pc==0 ) break outer;
+ pc -= 4; // Undo post-increment
+ break;
}
case 0xF1: {
diff --git a/chapter23/src/test/java/com/seaofnodes/simple/TestC.java b/chapter23/src/test/java/com/seaofnodes/simple/TestC.java
index 9df3dc68..dbe9f02f 100644
--- a/chapter23/src/test/java/com/seaofnodes/simple/TestC.java
+++ b/chapter23/src/test/java/com/seaofnodes/simple/TestC.java
@@ -1,6 +1,7 @@
package com.seaofnodes.simple;
import com.seaofnodes.simple.codegen.CodeGen;
+import com.seaofnodes.simple.type.TypeInteger;
import com.seaofnodes.simple.util.Ary;
import com.seaofnodes.simple.util.Utils;
import java.io.IOException;
@@ -29,7 +30,7 @@ public abstract class TestC {
}
// Compile and run a simple program
- public static void run( String dir, String file, String expected, int spills ) throws IOException {
+ public static void run( String dir, String file, TypeInteger arg, String expected, int spills, boolean standalone) throws IOException {
// Files
String cfile = dir+"/"+file+".c" ;
String sfile = dir+"/"+file+".smp";
@@ -37,15 +38,28 @@ public abstract class TestC {
// Compile and export Simple
String src = Files.readString(Path.of(sfile));
- run(src,CALL_CONVENTION,"",cfile,efile,"S",expected,spills);
+ run(src,CALL_CONVENTION,arg, "",standalone? null: cfile,efile,"S",expected,spills);
+ }
+ public static void run(String dir, String file, String expected, int spills ) throws IOException {
+ run(dir, file,null, expected, spills, false);
+ }
+
+ public static void runS(String file, String expected, int spills ) throws IOException {
+ run("src/test/java/com/seaofnodes/simple/progs", file, null, expected, spills, true);
}
- public static void run( String src, String simple_conv, String c_conv, String cfile, String efile, String xtn, String expected, int spills ) throws IOException {
+ public static void runS(String file, TypeInteger arg, String expected, int spills ) throws IOException {
+ run("src/test/java/com/seaofnodes/simple/progs", file, arg, expected, spills, true);
+ }
+
+
+ public static void run( String src, String simple_conv, TypeInteger arg, String c_conv, String cfile, String efile, String xtn, String expected, int spills ) throws IOException {
String bin = efile+xtn;
String obj = bin+".o";
String exe = OS.startsWith("Windows") ? bin+".exe" : bin;
// Compile simple, emit ELF
- CodeGen code = new CodeGen(src).driver( CPU_PORT, simple_conv, obj);
+ CodeGen code = new CodeGen(src, arg).driver( CPU_PORT, simple_conv, obj);
+
String result = gcc(obj, c_conv, cfile, false, exe );
assertEquals(expected,result);
diff --git a/chapter23/src/test/java/com/seaofnodes/simple/progs/and1.smp b/chapter23/src/test/java/com/seaofnodes/simple/progs/and1.smp
new file mode 100644
index 00000000..ef4c904f
--- /dev/null
+++ b/chapter23/src/test/java/com/seaofnodes/simple/progs/and1.smp
@@ -0,0 +1,10 @@
+// -*- mode: java; -*-
+int a = 1;
+int b = 1;
+
+if(a && b) {
+ sys.io.p("And");
+} else {
+ sys.io.p("Or");
+}
+return 0;
diff --git a/chapter23/src/test/java/com/seaofnodes/simple/progs/and2.smp b/chapter23/src/test/java/com/seaofnodes/simple/progs/and2.smp
new file mode 100644
index 00000000..2a463c94
--- /dev/null
+++ b/chapter23/src/test/java/com/seaofnodes/simple/progs/and2.smp
@@ -0,0 +1,16 @@
+// -*- mode: java; -*-
+int a = 1;
+int b = 1;
+
+int x=1;
+int y=1;
+int z=0;
+
+int g = x++ && y++ && z++;
+
+if(x == 2 && y == 2 && z == 1 && g == 0) {
+ sys.io.p("Effected");
+} else {
+ sys.io.p("Not effected");
+}
+return 0;
diff --git a/chapter23/src/test/java/com/seaofnodes/simple/progs/and3.smp b/chapter23/src/test/java/com/seaofnodes/simple/progs/and3.smp
new file mode 100644
index 00000000..aadbdfed
--- /dev/null
+++ b/chapter23/src/test/java/com/seaofnodes/simple/progs/and3.smp
@@ -0,0 +1,14 @@
+// -*- mode: java; -*-
+int a = 1;
+int b = 1;
+
+var sq = { int x ->
+ x*x;
+};
+
+if(a && sq(0)) {
+ sys.io.p("And");
+} else {
+ sys.io.p("Or");
+}
+return 0;
diff --git a/chapter23/src/test/java/com/seaofnodes/simple/progs/or1.smp b/chapter23/src/test/java/com/seaofnodes/simple/progs/or1.smp
new file mode 100644
index 00000000..f5f526c3
--- /dev/null
+++ b/chapter23/src/test/java/com/seaofnodes/simple/progs/or1.smp
@@ -0,0 +1,12 @@
+// -*- mode: java; -*-
+int a = 1;
+int b = 0;
+
+if(a++ || b++ ) {
+ if(b == 0 && a == 2) {
+ sys.io.p("Or");
+ }
+} else{
+ sys.io.p("And");
+}
+return 0;
diff --git a/chapter23/src/test/java/com/seaofnodes/simple/progs/or2.smp b/chapter23/src/test/java/com/seaofnodes/simple/progs/or2.smp
new file mode 100644
index 00000000..ac688b5a
--- /dev/null
+++ b/chapter23/src/test/java/com/seaofnodes/simple/progs/or2.smp
@@ -0,0 +1,23 @@
+// -*- mode: java; -*-
+int a = 1;
+int b = 1;
+
+int x = -1;
+int y=1;
+int z= -1;
+
+int g = x++ || y++ || z++;
+
+int switch = 0;
+if(x == 4 || y == 4 || z == 4) {
+ switch = -1;
+} else {
+ switch = 1;
+}
+int cd = 1;
+if((x == 0 && y == 1 && z==-1) && switch && g) {
+ sys.io.p("Effected");
+} else {
+ sys.io.p("Not effected");
+}
+return 0;
diff --git a/chapter23/src/test/java/com/seaofnodes/simple/progs/ptrand.smp b/chapter23/src/test/java/com/seaofnodes/simple/progs/ptrand.smp
new file mode 100644
index 00000000..9d7bce88
--- /dev/null
+++ b/chapter23/src/test/java/com/seaofnodes/simple/progs/ptrand.smp
@@ -0,0 +1,10 @@
+struct S { S? fld; };
+
+val ptr = arg == 1 ? null : new S{fld = arg==1 ? null : new S{fld = null;};};
+if( ptr && ptr.fld ) {
+ sys.io.p("true");
+} else {
+ sys.io.p("false");
+}
+
+return 0;