mirror of
https://github.com/hneemann/Digital.git
synced 2025-09-16 08:25:09 -04:00
Added support for xor in expressions
This commit is contained in:
parent
10d53aab8f
commit
15714ba7fd
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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<CircuitBuilder> {
|
||||
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<CircuitBuilder> {
|
||||
} else if (n.getExpression() instanceof Operation.Or) {
|
||||
ArrayList<Fragment> frags = getOperationFragments((Operation) n.getExpression());
|
||||
return new FragmentExpression(frags, new FragmentVisualElement(NOr.DESCRIPTION, frags.size(), shapeFactory));
|
||||
} else if (n.getExpression() instanceof Operation.XOr) {
|
||||
ArrayList<Fragment> 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<CircuitBuilder> {
|
||||
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));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
@ -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 {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user