first working CSV export, see #631

This commit is contained in:
hneemann 2021-02-12 10:56:23 +01:00
parent 96a2858d85
commit 1a25ac7279
9 changed files with 251 additions and 136 deletions

View File

@ -61,45 +61,6 @@ public class TruthTable implements Copyable<TruthTable> {
}
}
/**
* Save the table as hex file to be loaded in a ROM or LUT element.
*
* @param filename filename
* @throws IOException IOException
*/
public void saveHex(File filename) throws IOException {
if (results.size() > 63)
throw new IOException(Lang.get("err_tableHasToManyResultColumns"));
try (Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(filename), StandardCharsets.UTF_8))) {
saveHex(out);
}
}
/**
* Save the table as hex file to be loaded in a ROM or LUT element.
*
* @param writer the filename to use
* @throws IOException IOException
*/
public void saveHex(Writer writer) throws IOException {
writer.write("v2.0 raw\n");
int count = results.get(0).getValues().size();
for (int i = 0; i < count; i++) {
long val = 0;
long mask = 1;
for (Result r : results) {
ThreeStateValue v = r.getValues().get(i);
if (v == ThreeStateValue.one)
val |= mask;
mask *= 2;
}
writer.write(Long.toHexString(val));
writer.write('\n');
}
}
private static XStream getxStream() {
XStream xStream = new XStreamValid();
xStream.alias("truthTable", TruthTable.class);

View File

@ -13,7 +13,7 @@ import de.neemann.digital.core.Bits;
/**
* Exports a table in LogicFriday format
*/
public class TruthTableFormatterLogicFriday implements TruthTableFormatter {
public class TruthTableFormatterCSV implements TruthTableFormatter {
@Override
public String format(TruthTable truthTable) throws ExpressionException {

View File

@ -0,0 +1,37 @@
/*
* Copyright (c) 2016 Helmut Neemann
* Use of this source code is governed by the GPL v3 license
* that can be found in the LICENSE file.
*/
package de.neemann.digital.analyse.format;
import de.neemann.digital.analyse.TruthTable;
import de.neemann.digital.analyse.expression.ExpressionException;
import de.neemann.digital.analyse.quinemc.ThreeStateValue;
/**
* Formats a truth table
*/
public class TruthTableFormatterHex implements TruthTableFormatter {
@Override
public String format(TruthTable truthTable) throws ExpressionException {
StringBuilder sb = new StringBuilder();
sb.append("v2.0 raw\n");
int count = truthTable.getResult(0).size();
for (int i = 0; i < count; i++) {
long val = 0;
long mask = 1;
for (int j = 0; j < truthTable.getResultCount(); j++) {
ThreeStateValue v = truthTable.getResult(j).get(i);
if (v == ThreeStateValue.one)
val |= mask;
mask *= 2;
}
sb.append(Long.toHexString(val));
sb.append('\n');
}
return sb.toString();
}
}

View File

@ -12,13 +12,13 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
public class ExpressionListenerLogicFriday implements ExpressionListener {
public class ExpressionListenerCSVCondensed implements ExpressionListener {
private final ArrayList<Result> results;
private final HashSet<String> names;
private VariableVisitor variables;
private final VariableVisitor variables;
private StringBuilder str;
public ExpressionListenerLogicFriday() {
public ExpressionListenerCSVCondensed() {
results = new ArrayList<>();
names = new HashSet<>();
variables = new VariableVisitor();
@ -42,7 +42,6 @@ public class ExpressionListenerLogicFriday implements ExpressionListener {
str.append(",").append(r.name);
str.append("\n");
for (Result r : results)
r.createString(str, variables.getVariables(), results.size());
}
@ -67,18 +66,43 @@ public class ExpressionListenerLogicFriday implements ExpressionListener {
if (expression instanceof Operation.Or) {
ArrayList<Expression> o = ((Operation.Or) expression).getExpressions();
for (Expression e : o)
add(sb, e, variables, results);
} else if (expression instanceof Operation.And)
add(sb, expression, variables, results);
else if (expression instanceof Variable)
add(sb, Operation.and(expression), variables, results);
else if (expression instanceof Not)
add(sb, Operation.and(expression), variables, results);
addPrime(sb, e, variables, results);
} else
addPrime(sb, expression, variables, results);
}
private void addPrime(StringBuilder sb, Expression and, Collection<Variable> variables, int results) throws ExpressionException {
if (and instanceof Operation.And)
addAnd(sb, and, variables, results);
else if (and instanceof Variable)
addVar(sb, ((Variable) and).getIdentifier(), variables, results, false);
else if (and instanceof Not && ((Not) and).getExpression() instanceof Variable)
addVar(sb, ((Variable) (((Not) and).getExpression())).getIdentifier(), variables, results, true);
else
throw new ExpressionException("invalid expression");
}
private void add(StringBuilder sb, Expression and, Collection<Variable> variables, int results) throws ExpressionException {
private void addVar(StringBuilder sb, String identifier, Collection<Variable> variables, int results, boolean invert) {
for (Variable var : variables) {
if (var.getIdentifier().endsWith(identifier)) {
if (invert)
sb.append("0,");
else
sb.append("1,");
} else
sb.append("X,");
}
for (int i = 0; i < results; i++) {
if (i == number)
sb.append(",1");
else
sb.append(",0");
}
sb.append('\n');
}
private void addAnd(StringBuilder sb, Expression and, Collection<Variable> variables, int results) throws ExpressionException {
HashSet<String> v = new HashSet<>();
HashSet<String> nv = new HashSet<>();
if (and instanceof Operation.And) {
@ -114,6 +138,5 @@ public class ExpressionListenerLogicFriday implements ExpressionListener {
}
sb.append('\n');
}
}
}

View File

@ -16,6 +16,8 @@ import de.neemann.digital.analyse.expression.Variable;
import de.neemann.digital.analyse.expression.format.FormatterException;
import de.neemann.digital.analyse.expression.modify.*;
import de.neemann.digital.analyse.format.TruthTableFormatter;
import de.neemann.digital.analyse.format.TruthTableFormatterCSV;
import de.neemann.digital.analyse.format.TruthTableFormatterHex;
import de.neemann.digital.analyse.format.TruthTableFormatterTestCase;
import de.neemann.digital.analyse.quinemc.BoolTableByteArray;
import de.neemann.digital.builder.ATF150x.ATFDevice;
@ -439,43 +441,29 @@ public class TableDialog extends JDialog {
}
}.setToolTip(Lang.get("menu_table_createFunctionFixture_tt")).createJMenuItem());
fileMenu.add(new ToolTipAction(Lang.get("menu_table_exportHex")) {
JMenu export = new JMenu(Lang.get("menu_export"));
fileMenu.add(export);
export.add(new FileExportAction(Lang.get("menu_table_exportHex"), "hex") {
@Override
public void actionPerformed(ActionEvent e) {
int res = JOptionPane.OK_OPTION;
if (undoManager.getActual().getVars().size() > 20)
res = JOptionPane.showConfirmDialog(TableDialog.this, Lang.get("msg_tableHasManyRowsConfirm"));
if (res == JOptionPane.OK_OPTION) {
JFileChooser fc = new MyFileChooser();
if (TableDialog.this.filename != null)
fc.setSelectedFile(SaveAsHelper.checkSuffix(TableDialog.this.filename, "hex"));
new SaveAsHelper(TableDialog.this, fc, "hex")
.checkOverwrite(file -> undoManager.getActual().saveHex(file));
}
protected String getString() throws FormatterException, ExpressionException {
return new TruthTableFormatterHex().format(undoManager.getActual());
}
}.setToolTip(Lang.get("menu_table_exportHex_tt")).createJMenuItem());
fileMenu.add(new ToolTipAction(Lang.get("menu_table_exportTableLogicFriday")) {
export.add(new FileExportAction(Lang.get("menu_table_exportTableCSVCondensed"), "csv") {
@Override
public void actionPerformed(ActionEvent e) {
JFileChooser fc = new MyFileChooser();
if (TableDialog.this.filename != null)
fc.setSelectedFile(SaveAsHelper.checkSuffix(TableDialog.this.filename, "csv"));
new SaveAsHelper(TableDialog.this, fc, "csv")
.checkOverwrite(file -> {
ExpressionListenerLogicFriday expressionListener = new ExpressionListenerLogicFriday();
try {
lastGeneratedExpressions.replayTo(expressionListener);
expressionListener.close();
try (Writer w = new FileWriter(file)) {
w.write(expressionListener.toString());
}
} catch (FormatterException | ExpressionException ex) {
throw new IOException(ex);
}
});
protected String getString() throws FormatterException, ExpressionException {
ExpressionListenerCSVCondensed expressionListener = new ExpressionListenerCSVCondensed();
lastGeneratedExpressions.replayTo(expressionListener);
expressionListener.close();
return expressionListener.toString();
}
}.setToolTip(Lang.get("menu_table_exportTableLogicFriday_tt")).createJMenuItem());
}.setToolTip(Lang.get("menu_table_exportTableCSVCondensed")).createJMenuItem());
export.add(new FileExportAction(Lang.get("menu_table_exportTableCSV"), "csv") {
@Override
protected String getString() throws FormatterException, ExpressionException {
return new TruthTableFormatterCSV().format(undoManager.getActual());
}
}.setToolTip(Lang.get("menu_table_exportTableCSV")).createJMenuItem());
createJK = new JCheckBoxMenuItem(Lang.get("menu_table_JK"));
createJK.addActionListener(e -> calculateExpressions());
@ -1021,4 +1009,33 @@ public class TableDialog extends JDialog {
abstract ExpressionListener createExpressionListener() throws ExpressionException;
}
}
private abstract class FileExportAction extends ToolTipAction {
private final String suffix;
private FileExportAction(String name, String suffix) {
super(name);
this.suffix = suffix;
}
@Override
public void actionPerformed(ActionEvent e) {
JFileChooser fc = new MyFileChooser();
if (TableDialog.this.filename != null)
fc.setSelectedFile(SaveAsHelper.checkSuffix(TableDialog.this.filename, suffix));
new SaveAsHelper(TableDialog.this, fc, suffix)
.checkOverwrite(file -> {
try {
try (Writer w = new FileWriter(file)) {
w.write(getString());
}
} catch (FormatterException | ExpressionException ex) {
throw new IOException(ex);
}
});
}
protected abstract String getString() throws FormatterException, ExpressionException;
}
}

View File

@ -38,52 +38,4 @@ public class TruthTableTest extends TestCase {
}
}
public void testHexExportSingle() throws Exception {
ArrayList<Variable> vars = Variable.vars(3);
TruthTable t = new TruthTable(vars).addResult();
BoolTableByteArray result = (BoolTableByteArray) t.getResult(0);
for (int i = 0; i < t.getRows(); i++) {
result.set(i, i % 2);
}
StringWriter w = new StringWriter();
t.saveHex(w);
w.close();
assertEquals("v2.0 raw\n" +
"0\n" +
"1\n" +
"0\n" +
"1\n" +
"0\n" +
"1\n" +
"0\n" +
"1\n", w.toString());
}
public void testHexExportTwo() throws Exception {
ArrayList<Variable> vars = Variable.vars(3);
TruthTable t = new TruthTable(vars).addResult();
BoolTableByteArray result = (BoolTableByteArray) t.getResult(0);
for (int i = 0; i < t.getRows(); i++) {
result.set(i, i % 2);
}
t.addResult();
result = (BoolTableByteArray) t.getResult(1);
for (int i = 0; i < t.getRows(); i++) {
result.set(i, (i + 1) % 2);
}
StringWriter w = new StringWriter();
t.saveHex(w);
w.close();
assertEquals("v2.0 raw\n" +
"2\n" +
"1\n" +
"2\n" +
"1\n" +
"2\n" +
"1\n" +
"2\n" +
"1\n", w.toString());
}
}

View File

@ -0,0 +1,59 @@
package de.neemann.digital.analyse.format;
import de.neemann.digital.analyse.TruthTable;
import de.neemann.digital.analyse.expression.Variable;
import de.neemann.digital.analyse.quinemc.BoolTableByteArray;
import junit.framework.TestCase;
import java.io.StringWriter;
import java.util.ArrayList;
public class TruthTableFormatterHexTest extends TestCase {
public void testHexExportSingle() throws Exception {
ArrayList<Variable> vars = Variable.vars(3);
TruthTable t = new TruthTable(vars).addResult();
BoolTableByteArray result = (BoolTableByteArray) t.getResult(0);
for (int i = 0; i < t.getRows(); i++) {
result.set(i, i % 2);
}
String hex = new TruthTableFormatterHex().format(t);
assertEquals("v2.0 raw\n" +
"0\n" +
"1\n" +
"0\n" +
"1\n" +
"0\n" +
"1\n" +
"0\n" +
"1\n", hex);
}
public void testHexExportTwo() throws Exception {
ArrayList<Variable> vars = Variable.vars(3);
TruthTable t = new TruthTable(vars).addResult();
BoolTableByteArray result = (BoolTableByteArray) t.getResult(0);
for (int i = 0; i < t.getRows(); i++) {
result.set(i, i % 2);
}
t.addResult();
result = (BoolTableByteArray) t.getResult(1);
for (int i = 0; i < t.getRows(); i++) {
result.set(i, (i + 1) % 2);
}
String hex = new TruthTableFormatterHex().format(t);
assertEquals("v2.0 raw\n" +
"2\n" +
"1\n" +
"2\n" +
"1\n" +
"2\n" +
"1\n" +
"2\n" +
"1\n", hex);
}
}

View File

@ -5,13 +5,13 @@ import de.neemann.digital.analyse.expression.ExpressionException;
import de.neemann.digital.analyse.quinemc.BoolTableByteArray;
import junit.framework.TestCase;
public class TruthTableFormatterLogicFridayTest extends TestCase {
public class TruthTableFormatterLogicCSV extends TestCase {
public void testSimple() throws ExpressionException {
TruthTable tt = new TruthTable(2);
tt.addResult("X", new BoolTableByteArray(new byte[]{0, 1, 1, 1}));
tt.addResult("Y", new BoolTableByteArray(new byte[]{0, 0, 0, 1}));
String res = new TruthTableFormatterLogicFriday().format(tt);
String res = new TruthTableFormatterCSV().format(tt);
assertEquals("A,B,,X,Y\n" +
"0,0,,0,0\n" +

View File

@ -0,0 +1,66 @@
package de.neemann.digital.gui.components.table;
import de.neemann.digital.analyse.expression.Expression;
import de.neemann.digital.analyse.expression.ExpressionException;
import de.neemann.digital.analyse.expression.NamedExpression;
import de.neemann.digital.analyse.expression.Variable;
import de.neemann.digital.analyse.expression.format.FormatterException;
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;
public class ExpressionListenerCSVCondensedTest extends TestCase {
Variable a = new Variable("A");
Variable b = new Variable("B");
Variable c = new Variable("C");
public void testSimple() throws FormatterException, ExpressionException {
Expression expression = or(and(a, b), c);
ExpressionListenerCSVCondensed el = create(expression);
assertEquals("A,B,C,,Y\n" +
"1,1,X,,1\n" +
"X,X,1,,1\n", el.toString());
}
public void testNot() throws FormatterException, ExpressionException {
Expression expression = or(and(a, not(b)), not(c));
ExpressionListenerCSVCondensed el = create(expression);
assertEquals("A,B,C,,Y\n" +
"1,0,X,,1\n" +
"X,X,0,,1\n", el.toString());
}
public void testTwo() throws FormatterException, ExpressionException {
Expression e1 = new NamedExpression("Y", or(and(a, b), c));
Expression e2 = new NamedExpression("X", a);
ExpressionListenerCSVCondensed el = create(e1, e2);
assertEquals("A,B,C,,Y,X\n" +
"1,1,X,,1,0\n" +
"X,X,1,,1,0\n" +
"1,X,X,,0,1\n", el.toString());
}
private ExpressionListenerCSVCondensed create(Expression... expressions) throws FormatterException, ExpressionException {
ExpressionListenerCSVCondensed el = new ExpressionListenerCSVCondensed();
for (Expression e : expressions) {
String name = "Y";
if (e instanceof NamedExpression) {
NamedExpression ne = (NamedExpression) e;
name = ne.getName();
e = ne.getExpression();
}
el.resultFound(name, e);
}
el.close();
return el;
}
}