From 15714ba7fdb3d4480ab67a3b22f8e7e85e10e9e2 Mon Sep 17 00:00:00 2001 From: hneemann Date: Mon, 4 Jul 2016 12:10:57 +0200 Subject: [PATCH] Added support for xor in expressions --- .../digital/analyse/expression/Operation.java | 38 +++++++++++++++ .../digital/analyse/parser/Parser.java | 8 ++-- .../digital/analyse/parser/Tokenizer.java | 9 ++-- .../builder/circuit/CircuitBuilder.java | 46 +++---------------- .../analyse/expression/OperationTest.java | 18 +++++++- .../digital/analyse/parser/ParserTest.java | 11 +++-- 6 files changed, 79 insertions(+), 51 deletions(-) diff --git a/src/main/java/de/neemann/digital/analyse/expression/Operation.java b/src/main/java/de/neemann/digital/analyse/expression/Operation.java index 99fdfe480..c21595a77 100644 --- a/src/main/java/de/neemann/digital/analyse/expression/Operation.java +++ b/src/main/java/de/neemann/digital/analyse/expression/Operation.java @@ -39,6 +39,18 @@ public abstract class Operation implements Expression { return simplify(new Or(Arrays.asList(exp), true)); } + /** + * Creates a new XOR expression + * + * @param a the expression to XOR + * @param b the expression to XOR + * @return the created expression + */ + public static Expression xor(Expression a, Expression b) { + return simplify(new XOr(a, b)); + } + + /** * Creates a new OR expression * @@ -222,4 +234,30 @@ public abstract class Operation implements Expression { return "or" + super.toString(); } } + + /** + * The XOR expression + */ + public static final class XOr extends Operation { + + private XOr(Expression a, Expression b) { + super(Arrays.asList(a, b), false); + } + + @Override + protected boolean getNeutral() { + return false; + } + + @Override + protected boolean calc(boolean a, boolean b) { + return (a || b) && (!a || !b); + } + + @Override + public String toString() { + return "xor" + super.toString(); + } + } + } diff --git a/src/main/java/de/neemann/digital/analyse/parser/Parser.java b/src/main/java/de/neemann/digital/analyse/parser/Parser.java index 60ac4f686..13df202a3 100644 --- a/src/main/java/de/neemann/digital/analyse/parser/Parser.java +++ b/src/main/java/de/neemann/digital/analyse/parser/Parser.java @@ -52,9 +52,11 @@ public class Parser { private Expression parseOr() throws IOException, ParseException { Expression ex = parseAnd(); - while (tokenizer.peek() == OR) { - tokenizer.consume(); - ex = Operation.or(ex, parseAnd()); + while (tokenizer.peek() == OR || tokenizer.peek() == XOR) { + if (tokenizer.next() == OR) + ex = Operation.or(ex, parseAnd()); + else + ex = Operation.xor(ex, parseAnd()); } return ex; } diff --git a/src/main/java/de/neemann/digital/analyse/parser/Tokenizer.java b/src/main/java/de/neemann/digital/analyse/parser/Tokenizer.java index 33f883869..ccb39b6b6 100644 --- a/src/main/java/de/neemann/digital/analyse/parser/Tokenizer.java +++ b/src/main/java/de/neemann/digital/analyse/parser/Tokenizer.java @@ -11,7 +11,7 @@ import java.io.Reader; public class Tokenizer { - enum Token {UNKNOWN, IDENT, AND, OR, NOT, OPEN, CLOSE, ONE, ZERO, EOF} + enum Token {UNKNOWN, IDENT, AND, OR, NOT, XOR, OPEN, CLOSE, ONE, ZERO, EOF} private final Reader in; private Token token; @@ -83,6 +83,9 @@ public class Tokenizer { case ')': token = Token.CLOSE; break; + case '^': + token = Token.XOR; + break; case '&': c = readChar(); if (c != '&') unreadChar(c); @@ -98,6 +101,7 @@ public class Tokenizer { token = Token.OR; break; case '¬': + case '~': case '!': token = Token.NOT; break; @@ -150,8 +154,7 @@ public class Tokenizer { private boolean isIdentChar(int c) { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') - || (c == '_') - || (c == '^'); + || (c == '_'); } private boolean isNumberChar(int c) { diff --git a/src/main/java/de/neemann/digital/builder/circuit/CircuitBuilder.java b/src/main/java/de/neemann/digital/builder/circuit/CircuitBuilder.java index 7f1ba4959..5ce7cefb0 100644 --- a/src/main/java/de/neemann/digital/builder/circuit/CircuitBuilder.java +++ b/src/main/java/de/neemann/digital/builder/circuit/CircuitBuilder.java @@ -1,12 +1,10 @@ package de.neemann.digital.builder.circuit; import de.neemann.digital.analyse.expression.*; +import de.neemann.digital.analyse.expression.Not; import de.neemann.digital.builder.BuilderException; import de.neemann.digital.builder.BuilderInterface; -import de.neemann.digital.core.basic.And; -import de.neemann.digital.core.basic.NAnd; -import de.neemann.digital.core.basic.NOr; -import de.neemann.digital.core.basic.Or; +import de.neemann.digital.core.basic.*; import de.neemann.digital.core.element.Keys; import de.neemann.digital.core.element.Rotation; import de.neemann.digital.core.flipflops.FlipflopD; @@ -19,20 +17,14 @@ import de.neemann.digital.draw.elements.Tunnel; import de.neemann.digital.draw.elements.VisualElement; import de.neemann.digital.draw.elements.Wire; import de.neemann.digital.draw.graphics.Vector; -import de.neemann.digital.draw.library.ElementLibrary; import de.neemann.digital.draw.shapes.ShapeFactory; -import de.neemann.digital.gui.Main; import de.neemann.digital.lang.Lang; -import javax.swing.*; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; -import static de.neemann.digital.analyse.expression.Not.not; -import static de.neemann.digital.analyse.expression.Operation.and; -import static de.neemann.digital.analyse.expression.Operation.or; import static de.neemann.digital.draw.shapes.GenericShape.SIZE; /** @@ -107,6 +99,8 @@ public class CircuitBuilder implements BuilderInterface { return new FragmentExpression(frags, new FragmentVisualElement(And.DESCRIPTION, frags.size(), shapeFactory)); else if (op instanceof Operation.Or) return new FragmentExpression(frags, new FragmentVisualElement(Or.DESCRIPTION, frags.size(), shapeFactory)); + else if (op instanceof Operation.XOr) + return new FragmentExpression(frags, new FragmentVisualElement(XOr.DESCRIPTION, frags.size(), shapeFactory)); else throw new BuilderException(Lang.get("err_builder_operationNotSupported", op.getClass().getSimpleName())); } else if (expression instanceof Not) { @@ -121,6 +115,9 @@ public class CircuitBuilder implements BuilderInterface { } else if (n.getExpression() instanceof Operation.Or) { ArrayList frags = getOperationFragments((Operation) n.getExpression()); return new FragmentExpression(frags, new FragmentVisualElement(NOr.DESCRIPTION, frags.size(), shapeFactory)); + } else if (n.getExpression() instanceof Operation.XOr) { + ArrayList frags = getOperationFragments((Operation) n.getExpression()); + return new FragmentExpression(frags, new FragmentVisualElement(XNOr.DESCRIPTION, frags.size(), shapeFactory)); } return new FragmentExpression(createFragment(n.getExpression()), new FragmentVisualElement(de.neemann.digital.core.basic.Not.DESCRIPTION, shapeFactory)); } else if (expression instanceof Variable) { @@ -288,33 +285,4 @@ public class CircuitBuilder implements BuilderInterface { circuit.add(clock); } - /** - * Only used for manual tests - * - * @param args args - * @throws BuilderException BuilderException - */ - public static void main(String[] args) throws BuilderException { - - Variable y0 = new Variable("Y_0"); - Variable y1 = new Variable("Y_1"); - Variable y2 = new Variable("Y_2"); - Variable z = new Variable("A"); - - Expression y0s = and(not(y0), z); - Expression y1s = or(and(y0, not(y1)), and(y1, not(y0))); - Expression y2s = not(y2); - Expression p0 = and(y0, y1, z); - - Circuit circuit = new CircuitBuilder(new ShapeFactory(new ElementLibrary())) - .addSequential("Y_0", y0s) - .addSequential("Y_1", y1s) - .addSequential("Y_2", y2s) - .addCombinatorial("P_0", p0) - .createCircuit(); - - SwingUtilities.invokeLater(() -> new Main(null, circuit).setVisible(true)); - } - - } diff --git a/src/test/java/de/neemann/digital/analyse/expression/OperationTest.java b/src/test/java/de/neemann/digital/analyse/expression/OperationTest.java index 4b3ec0a31..00bf15397 100644 --- a/src/test/java/de/neemann/digital/analyse/expression/OperationTest.java +++ b/src/test/java/de/neemann/digital/analyse/expression/OperationTest.java @@ -3,8 +3,7 @@ package de.neemann.digital.analyse.expression; import junit.framework.TestCase; import static de.neemann.digital.analyse.expression.Not.not; -import static de.neemann.digital.analyse.expression.Operation.and; -import static de.neemann.digital.analyse.expression.Operation.or; +import static de.neemann.digital.analyse.expression.Operation.*; import static de.neemann.digital.analyse.expression.Variable.v; /** @@ -52,4 +51,19 @@ public class OperationTest extends TestCase { i = and(not(a)); assertTrue(i instanceof Not); } + + public void testXOr() throws Exception { + Variable a = v("a"); + Variable b = v("b"); + + Expression i = xor(a,b); + assertTrue(i instanceof Operation.XOr); + assertEquals(2, ((Operation.XOr) i).getExpressions().size()); + + assertEquals(false, ((Operation)i).calc(false,false)); + assertEquals(true, ((Operation)i).calc(true,false)); + assertEquals(true, ((Operation)i).calc(false,true)); + assertEquals(false, ((Operation)i).calc(true,true)); + } + } \ No newline at end of file diff --git a/src/test/java/de/neemann/digital/analyse/parser/ParserTest.java b/src/test/java/de/neemann/digital/analyse/parser/ParserTest.java index c0918e02b..ca1d85752 100644 --- a/src/test/java/de/neemann/digital/analyse/parser/ParserTest.java +++ b/src/test/java/de/neemann/digital/analyse/parser/ParserTest.java @@ -14,7 +14,6 @@ public class ParserTest extends TestCase { public void testIdent() throws Exception { assertEquals(new Variable("C"), new Parser("C").parse()); assertEquals(new Variable("A_1"), new Parser("A_1").parse()); - assertEquals(new Variable("A^1"), new Parser("A^1").parse()); } public void testConst() throws Exception { @@ -29,6 +28,10 @@ public class ParserTest extends TestCase { assertTrue(new Parser("a||b").parse() instanceof Operation.Or); } + public void testParseXOr() throws Exception { + assertTrue(new Parser("a^b").parse() instanceof Operation.XOr); + } + public void testParseAnd() throws Exception { assertTrue(new Parser("a*b").parse() instanceof Operation.And); assertTrue(new Parser("a∧b").parse() instanceof Operation.And); @@ -51,10 +54,11 @@ public class ParserTest extends TestCase { } public void testParseNot() throws Exception { - Parser p = new Parser("!a"); - Expression exp = p.parse(); + Expression exp = new Parser("!a").parse(); assertTrue(exp instanceof Not); assertTrue(((Not)exp).getExpression() instanceof Variable); + assertTrue(new Parser("~a").parse() instanceof Not); + assertTrue(new Parser("¬a").parse() instanceof Not); } public void testParseRegression() throws Exception { @@ -125,5 +129,4 @@ public class ParserTest extends TestCase { } } - } \ No newline at end of file