diff --git a/src/main/java/de/neemann/digital/analyse/format/TruthTableFormatterLogicFriday.java b/src/main/java/de/neemann/digital/analyse/format/TruthTableFormatterLogicFriday.java new file mode 100644 index 000000000..ba9c4124a --- /dev/null +++ b/src/main/java/de/neemann/digital/analyse/format/TruthTableFormatterLogicFriday.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2021 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; +import de.neemann.digital.core.Bits; + +/** + * Exports a table in LogicFriday format + */ +public class TruthTableFormatterLogicFriday implements TruthTableFormatter { + + @Override + public String format(TruthTable truthTable) throws ExpressionException { + StringBuilder sb = new StringBuilder(); + for (String n : truthTable.getVarNames()) + sb.append(n).append(","); + for (String n : truthTable.getResultNames()) + sb.append(',').append(n); + sb.append('\n'); + + export(sb, truthTable); + + return sb.toString(); + } + + private void export(StringBuilder sb, TruthTable truthTable) { + int vars = truthTable.getVars().size(); + for (int r = 0; r < truthTable.getRows(); r++) { + long m = Bits.up(1, vars - 1); + for (int c = 0; c < vars; c++) { + if ((r & m) == 0) + sb.append('0'); + else + sb.append('1'); + sb.append(','); + m = m >> 1; + } + for (int c = 0; c < truthTable.getResultCount(); c++) { + ThreeStateValue v = truthTable.getResult(c).get(r); + sb.append(',').append(v.toString()); + } + sb.append('\n'); + } + } +} diff --git a/src/main/java/de/neemann/digital/gui/components/table/ExpressionListenerLogicFriday.java b/src/main/java/de/neemann/digital/gui/components/table/ExpressionListenerLogicFriday.java new file mode 100644 index 000000000..a123d4ae1 --- /dev/null +++ b/src/main/java/de/neemann/digital/gui/components/table/ExpressionListenerLogicFriday.java @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2021 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.gui.components.table; + +import de.neemann.digital.analyse.expression.*; +import de.neemann.digital.analyse.expression.format.FormatterException; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; + +public class ExpressionListenerLogicFriday implements ExpressionListener { + private final ArrayList results; + private final HashSet names; + private VariableVisitor variables; + private StringBuilder str; + + public ExpressionListenerLogicFriday() { + results = new ArrayList<>(); + names = new HashSet<>(); + variables = new VariableVisitor(); + } + + @Override + public void resultFound(String name, Expression expression) throws FormatterException, ExpressionException { + if (!names.contains(name)) { + names.add(name); + results.add(new Result(name, expression, results.size())); + expression.traverse(variables); + } + } + + @Override + public void close() throws FormatterException, ExpressionException { + str = new StringBuilder(); + for (Variable var : variables.getVariables()) + str.append(var.getIdentifier()).append(","); + for (Result r : results) + str.append(",").append(r.name); + str.append("\n"); + + + for (Result r : results) + r.createString(str, variables.getVariables(), results.size()); + } + + @Override + public String toString() { + return str.toString(); + } + + private static class Result { + private final String name; + private final Expression expression; + private final int number; + + public Result(String name, Expression expression, int number) { + this.name = name; + this.expression = expression; + this.number = number; + } + + public void createString(StringBuilder sb, Collection variables, int results) throws ExpressionException { + if (expression instanceof Operation.Or) { + ArrayList 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); + else + throw new ExpressionException("invalid expression"); + } + + private void add(StringBuilder sb, Expression and, Collection variables, int results) throws ExpressionException { + HashSet v = new HashSet<>(); + HashSet nv = new HashSet<>(); + if (and instanceof Operation.And) { + Operation.And a = (Operation.And) and; + for (Expression var : a.getExpressions()) { + HashSet map = v; + if (var instanceof Not) { + map = nv; + var = ((Not) var).getExpression(); + } + if (var instanceof Variable) + map.add(((Variable) var).getIdentifier()); + else + throw new ExpressionException("invalid expression"); + } + } else + throw new ExpressionException("invalid expression"); + + for (Variable var : variables) { + if (v.contains(var.getIdentifier())) + sb.append("1,"); + else if (nv.contains(var.getIdentifier())) + sb.append("0,"); + else + sb.append("X,"); + } + + for (int i = 0; i < results; i++) { + if (i == number) + sb.append(",1"); + else + sb.append(",0"); + } + sb.append('\n'); + } + + } +} diff --git a/src/main/java/de/neemann/digital/gui/components/table/TableDialog.java b/src/main/java/de/neemann/digital/gui/components/table/TableDialog.java index bbeb58f97..03eb7921b 100644 --- a/src/main/java/de/neemann/digital/gui/components/table/TableDialog.java +++ b/src/main/java/de/neemann/digital/gui/components/table/TableDialog.java @@ -60,7 +60,9 @@ import java.awt.event.ActionEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.io.File; +import java.io.FileWriter; import java.io.IOException; +import java.io.Writer; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -453,6 +455,27 @@ public class TableDialog extends JDialog { } }.setToolTip(Lang.get("menu_table_exportHex_tt")).createJMenuItem()); + fileMenu.add(new ToolTipAction(Lang.get("menu_table_exportTableLogicFriday")) { + @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); + } + }); + } + }.setToolTip(Lang.get("menu_table_exportTableLogicFriday_tt")).createJMenuItem()); createJK = new JCheckBoxMenuItem(Lang.get("menu_table_JK")); createJK.addActionListener(e -> calculateExpressions()); diff --git a/src/test/java/de/neemann/digital/analyse/format/TruthTableFormatterLogicFridayTest.java b/src/test/java/de/neemann/digital/analyse/format/TruthTableFormatterLogicFridayTest.java new file mode 100644 index 000000000..51a532bec --- /dev/null +++ b/src/test/java/de/neemann/digital/analyse/format/TruthTableFormatterLogicFridayTest.java @@ -0,0 +1,22 @@ +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.BoolTableByteArray; +import junit.framework.TestCase; + +public class TruthTableFormatterLogicFridayTest 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); + + assertEquals("A,B,,X,Y\n" + + "0,0,,0,0\n" + + "0,1,,1,0\n" + + "1,0,,1,0\n" + + "1,1,,1,1\n", res); + } +} \ No newline at end of file