/*******************************************************************************
* This file is part of logisim-evolution.
*
* logisim-evolution is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* logisim-evolution is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with logisim-evolution. If not, see <http://www.gnu.org/licenses/>.
*
* Original code by Carl Burch (http://www.cburch.com), 2011.
* Subsequent modifications by :
* + Haute École Spécialisée Bernoise
* http://www.bfh.ch
* + Haute École du paysage, d'ingénierie et d'architecture de Genève
* http://hepia.hesge.ch/
* + Haute École d'Ingénierie et de Gestion du Canton de Vaud
* http://www.heig-vd.ch/
* The project is currently maintained by :
* + REDS Institute - HEIG-VD
* Yverdon-les-Bains, Switzerland
* http://reds.heig-vd.ch
*******************************************************************************/
package com.cburch.logisim.analyze.model;
import java.util.HashSet;
public abstract class Expression {
static interface IntVisitor {
public int visitAnd(Expression a, Expression b);
public int visitConstant(int value);
public int visitNot(Expression a);
public int visitOr(Expression a, Expression b);
public int visitVariable(String name);
public int visitXor(Expression a, Expression b);
}
static interface Visitor {
public void visitAnd(Expression a, Expression b);
public void visitConstant(int value);
public void visitNot(Expression a);
public void visitOr(Expression a, Expression b);
public void visitVariable(String name);
public void visitXor(Expression a, Expression b);
}
public static final int OR_LEVEL = 0;
public static final int XOR_LEVEL = 1;
public static final int AND_LEVEL = 2;
public static final int NOT_LEVEL = 3;
public boolean containsXor() {
return 1 == visit(new IntVisitor() {
public int visitAnd(Expression a, Expression b) {
return a.visit(this) == 1 || b.visit(this) == 1 ? 1 : 0;
}
public int visitConstant(int value) {
return 0;
}
public int visitNot(Expression a) {
return a.visit(this);
}
public int visitOr(Expression a, Expression b) {
return a.visit(this) == 1 || b.visit(this) == 1 ? 1 : 0;
}
public int visitVariable(String name) {
return 0;
}
public int visitXor(Expression a, Expression b) {
return 1;
}
});
}
public boolean evaluate(final Assignments assignments) {
int ret = visit(new IntVisitor() {
public int visitAnd(Expression a, Expression b) {
return a.visit(this) & b.visit(this);
}
public int visitConstant(int value) {
return value;
}
public int visitNot(Expression a) {
return ~a.visit(this);
}
public int visitOr(Expression a, Expression b) {
return a.visit(this) | b.visit(this);
}
public int visitVariable(String name) {
return assignments.get(name) ? 1 : 0;
}
public int visitXor(Expression a, Expression b) {
return a.visit(this) ^ b.visit(this);
}
});
return (ret & 1) != 0;
}
public abstract int getPrecedence();
public boolean isCircular() {
final HashSet<Expression> visited = new HashSet<Expression>();
visited.add(this);
return 1 == visit(new IntVisitor() {
private int binary(Expression a, Expression b) {
if (!visited.add(a))
return 1;
if (a.visit(this) == 1)
return 1;
visited.remove(a);
if (!visited.add(b))
return 1;
if (b.visit(this) == 1)
return 1;
visited.remove(b);
return 0;
}
public int visitAnd(Expression a, Expression b) {
return binary(a, b);
}
public int visitConstant(int value) {
return 0;
}
public int visitNot(Expression a) {
if (!visited.add(a))
return 1;
if (a.visit(this) == 1)
return 1;
visited.remove(a);
return 0;
}
public int visitOr(Expression a, Expression b) {
return binary(a, b);
}
public int visitVariable(String name) {
return 0;
}
public int visitXor(Expression a, Expression b) {
return binary(a, b);
}
});
}
public boolean isCnf() {
return 1 == visit(new IntVisitor() {
int level = 0;
public int visitAnd(Expression a, Expression b) {
if (level > 1)
return 0;
int oldLevel = level;
level = 1;
int ret = a.visit(this) == 1 && b.visit(this) == 1 ? 1 : 0;
level = oldLevel;
return ret;
}
public int visitConstant(int value) {
return 1;
}
public int visitNot(Expression a) {
if (level == 2)
return 0;
int oldLevel = level;
level = 2;
int ret = a.visit(this);
level = oldLevel;
return ret;
}
public int visitOr(Expression a, Expression b) {
if (level > 0)
return 0;
return a.visit(this) == 1 && b.visit(this) == 1 ? 1 : 0;
}
public int visitVariable(String name) {
return 1;
}
public int visitXor(Expression a, Expression b) {
return 0;
}
});
}
Expression removeVariable(final String input) {
return visit(new ExpressionVisitor<Expression>() {
public Expression visitAnd(Expression a, Expression b) {
Expression l = a.visit(this);
Expression r = b.visit(this);
if (l == null)
return r;
if (r == null)
return l;
return Expressions.and(l, r);
}
public Expression visitConstant(int value) {
return Expressions.constant(value);
}
public Expression visitNot(Expression a) {
Expression l = a.visit(this);
if (l == null)
return null;
return Expressions.not(l);
}
public Expression visitOr(Expression a, Expression b) {
Expression l = a.visit(this);
Expression r = b.visit(this);
if (l == null)
return r;
if (r == null)
return l;
return Expressions.or(l, r);
}
public Expression visitVariable(String name) {
return name.equals(input) ? null : Expressions.variable(name);
}
public Expression visitXor(Expression a, Expression b) {
Expression l = a.visit(this);
Expression r = b.visit(this);
if (l == null)
return r;
if (r == null)
return l;
return Expressions.xor(l, r);
}
});
}
Expression replaceVariable(final String oldName, final String newName) {
return visit(new ExpressionVisitor<Expression>() {
public Expression visitAnd(Expression a, Expression b) {
Expression l = a.visit(this);
Expression r = b.visit(this);
return Expressions.and(l, r);
}
public Expression visitConstant(int value) {
return Expressions.constant(value);
}
public Expression visitNot(Expression a) {
Expression l = a.visit(this);
return Expressions.not(l);
}
public Expression visitOr(Expression a, Expression b) {
Expression l = a.visit(this);
Expression r = b.visit(this);
return Expressions.or(l, r);
}
public Expression visitVariable(String name) {
return Expressions.variable(name.equals(oldName) ? newName
: name);
}
public Expression visitXor(Expression a, Expression b) {
Expression l = a.visit(this);
Expression r = b.visit(this);
return Expressions.xor(l, r);
}
});
}
@Override
public String toString() {
final StringBuilder text = new StringBuilder();
visit(new Visitor() {
private void binary(Expression a, Expression b, int level, String op) {
if (a.getPrecedence() < level) {
text.append("(");
a.visit(this);
text.append(")");
} else {
a.visit(this);
}
text.append(op);
if (b.getPrecedence() < level) {
text.append("(");
b.visit(this);
text.append(")");
} else {
b.visit(this);
}
}
public void visitAnd(Expression a, Expression b) {
binary(a, b, AND_LEVEL, " ");
}
public void visitConstant(int value) {
text.append("" + Integer.toString(value, 16));
}
public void visitNot(Expression a) {
text.append("~");
if (a.getPrecedence() < NOT_LEVEL) {
text.append("(");
a.visit(this);
text.append(")");
} else {
a.visit(this);
}
}
public void visitOr(Expression a, Expression b) {
binary(a, b, OR_LEVEL, " + ");
}
public void visitVariable(String name) {
text.append(name);
}
public void visitXor(Expression a, Expression b) {
binary(a, b, XOR_LEVEL, " ^ ");
}
});
return text.toString();
}
public abstract <T> T visit(ExpressionVisitor<T> visitor);
abstract int visit(IntVisitor visitor);
abstract void visit(Visitor visitor);
}