mirror of
https://github.com/AppleCommander/bastools.git
synced 2026-04-21 14:17:46 +00:00
Adding Nibble Checkit binary proofreader. Juggled interface names a bit.
This commit is contained in:
+36
@@ -0,0 +1,36 @@
|
||||
package org.applecommander.bastools.api.proofreaders;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
|
||||
/**
|
||||
* Standard interface for proofreaders that evaluate a binary program.
|
||||
*/
|
||||
public interface BinaryDataProofReader {
|
||||
/** Parses each line into a byte stream and then uses addBytes to roll into checksum. */
|
||||
default void addProgram(String text) {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
int address = 0;
|
||||
for (var line : text.lines().toList()) {
|
||||
var info = parseLine(line);
|
||||
if (address == 0) address = info.address;
|
||||
outputStream.writeBytes(info.code);
|
||||
};
|
||||
addBytes(address, outputStream.toByteArray());
|
||||
}
|
||||
/** Parses the line and adds to the current checksums. */
|
||||
void addBytes(int address, byte... binary);
|
||||
/** Handy method to parse a line from text into address + bytes. */
|
||||
static LineInfo parseLine(final String line) {
|
||||
String[] parts = line.split(":");
|
||||
assert parts.length != 0;
|
||||
int address = Integer.parseInt(parts[0], 16);
|
||||
String[] bytes = parts[1].split(" ");
|
||||
assert bytes.length > 0;
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
for (String value : bytes) {
|
||||
outputStream.write(Integer.parseInt(value, 16));
|
||||
}
|
||||
return new LineInfo(address, outputStream.toByteArray(), line);
|
||||
}
|
||||
record LineInfo(int address, byte[] code, String line) {}
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
package org.applecommander.bastools.api.proofreaders;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
/**
|
||||
* Standard interface for proofreaders that evaluate a binary program.
|
||||
*/
|
||||
public interface BinaryInputBufferProofReader {
|
||||
default void addProgram(String code) {
|
||||
code.lines().forEach(this::addLine);
|
||||
}
|
||||
/** Parses the line and adds to the current checksums. */
|
||||
void addLine(String line);
|
||||
/** Converts to standard lines adds to the current checksums. */
|
||||
default void addBytes(int address, byte... binary) {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
PrintWriter pw = new PrintWriter(outputStream);
|
||||
for (int i=0; i<binary.length; i++) {
|
||||
if (i % 16 == 0) {
|
||||
if (i > 0) pw.println();
|
||||
pw.printf("%04X:", address+i);
|
||||
}
|
||||
else {
|
||||
pw.print(' ');
|
||||
}
|
||||
pw.printf("%02X", binary[i]);
|
||||
}
|
||||
addProgram(outputStream.toString());
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
package org.applecommander.bastools.api.proofreaders;
|
||||
|
||||
/**
|
||||
* Standard interface for proofreaders that evaluate a binary program.
|
||||
*/
|
||||
public interface BinaryProofReader {
|
||||
default void addProgram(String text) {
|
||||
// TODO
|
||||
}
|
||||
/** Parses the line and adds to the current checksums. */
|
||||
void addBytes(int address, byte... binary);
|
||||
}
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
package org.applecommander.bastools.api.proofreaders;
|
||||
|
||||
public class NibbleAppleCheckerBinary implements BinaryProofReader {
|
||||
public class NibbleAppleCheckerBinary implements BinaryDataProofReader {
|
||||
private final String filename;
|
||||
private int length;
|
||||
private final NibbleAppleCheckerChecksum checksum = new NibbleAppleCheckerChecksum();
|
||||
|
||||
@@ -1,142 +0,0 @@
|
||||
/*
|
||||
* bastools
|
||||
* Copyright (C) 2026 Robert Greene
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.applecommander.bastools.api.proofreaders;
|
||||
|
||||
import org.applecommander.bastools.api.Configuration;
|
||||
|
||||
public class NibbleCheckit implements ApplesoftInputBufferProofReader {
|
||||
private final Configuration config;
|
||||
private final Checksum totalChecksum = new Checksum();
|
||||
private final Checksum lineChecksum = new Checksum();
|
||||
|
||||
public NibbleCheckit(Configuration config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Configuration getConfiguration() {
|
||||
return config;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public void addProgramText(String code) {
|
||||
System.out.println("Nibble Checkit, Copyright 1988, Microsparc Inc.");
|
||||
ApplesoftInputBufferProofReader.super.addProgramText(code);
|
||||
System.out.printf("TOTAL: %02X%02X\n", totalChecksum.checksum & 0xff, totalChecksum.checksum >> 8);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public void addLine(final String originalLine) {
|
||||
// Calculate and output line value
|
||||
lineChecksum.reset();
|
||||
|
||||
// The ? => PRINT replacement always occurs, including in strings!
|
||||
String line = originalLine.replace("?", "PRINT");
|
||||
|
||||
boolean inQuote = false;
|
||||
StringBuilder remLettersSeen = new StringBuilder();
|
||||
for (char ch : line.toCharArray()) {
|
||||
if (ch == '"') inQuote = !inQuote;
|
||||
if (!inQuote && ch == ' ') continue;
|
||||
lineChecksum.add(ch|0x80);
|
||||
|
||||
// we only allow R E M from a comment; skip rest of the comment
|
||||
remLettersSeen.append(ch);
|
||||
if ("REM".contentEquals(remLettersSeen)) {
|
||||
break;
|
||||
}
|
||||
else if ("R".contentEquals(remLettersSeen) || "RE".contentEquals(remLettersSeen)) {
|
||||
// Keep them, this may be a comment
|
||||
}
|
||||
else {
|
||||
remLettersSeen = new StringBuilder();
|
||||
}
|
||||
}
|
||||
|
||||
int cs = ( (lineChecksum.checksum & 0xff) - (lineChecksum.checksum >> 8) ) & 0xff;
|
||||
System.out.printf("%02X | %s\n", cs, originalLine);
|
||||
|
||||
// Update program values
|
||||
int lineNumber = Integer.parseInt(line.split(" ")[0].trim());
|
||||
totalChecksum.add(lineNumber & 0xff);
|
||||
totalChecksum.add(lineNumber >> 8);
|
||||
}
|
||||
|
||||
public int getLineChecksumValue() {
|
||||
return lineChecksum.value();
|
||||
}
|
||||
public int getTotalChecksumValue() {
|
||||
return totalChecksum.value();
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform Nibble Checkit algorithm. Note that a large part of the assembly is shifting the
|
||||
* new value byte into the checksum; if the checksum itself causes a carry in the high byte,
|
||||
* an exclusive-or is done with (maybe?) the CCITT CRC polynomial.
|
||||
* <pre>
|
||||
* 864F- A2 08 L864F LDX #$08 ; 8 bits
|
||||
* 8651- 0A L8651 ASL ; Acc. is value
|
||||
* 8652- 26 08 ROL $08 ; $08/$09 is low/high byte of checksum
|
||||
* 8654- 26 09 ROL $09
|
||||
* 8656- 90 0E BCC L8666 ; no carry, continue loop
|
||||
* 8658- 48 PHA ; save current value
|
||||
* 8659- A5 08 LDA $08
|
||||
* 865B- 49 21 EOR #$21 ; low byte of $1021
|
||||
* 865D- 85 08 STA $08
|
||||
* 865F- A5 09 LDA $09
|
||||
* 8661- 49 10 EOR #$10 ; high byte of $1021
|
||||
* 8663- 85 09 STA $09
|
||||
* 8665- 68 PLA ; restore current value
|
||||
* 8666- CA L8666 DEX
|
||||
* 8667- D0 E8 BNE L8651 ; loop through all 8 bits
|
||||
* 8669- 60 RTS
|
||||
* </pre>
|
||||
* In this implementation, we just mash the value and the checksum together, so the
|
||||
* resulting number is <code>0x00CCCCVV</code>. Then the intermediate carry bits aren't
|
||||
* a concern, and we simply need to detect when we overflow three bytes and then do the
|
||||
* XOR. The result is the middle two bytes where the checksum resides. (Note that the
|
||||
* <code>0x1021</code> was shifted by a byte as well.)
|
||||
*/
|
||||
public static class Checksum implements ProofReaderChecksum {
|
||||
private int checksum = 0;
|
||||
@Override
|
||||
public void reset() {
|
||||
this.checksum = 0;
|
||||
}
|
||||
@Override
|
||||
public void add(int value) {
|
||||
assert value >= 0 && value <= 0xff;
|
||||
int work = (checksum << 8) | value;
|
||||
for (int i=0; i<8; i++) {
|
||||
work <<= 1;
|
||||
// Note: If we run into negative issues somehow, this could also be "((work & 0xff000000) != 0)".
|
||||
if (work > 0xffffff) {
|
||||
work &= 0xffffff;
|
||||
work ^= 0x102100;
|
||||
}
|
||||
}
|
||||
checksum = work >> 8;
|
||||
}
|
||||
@Override
|
||||
public int value() {
|
||||
return checksum;
|
||||
}
|
||||
}
|
||||
}
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* bastools
|
||||
* Copyright (C) 2026 Robert Greene
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.applecommander.bastools.api.proofreaders;
|
||||
|
||||
import org.applecommander.bastools.api.Configuration;
|
||||
|
||||
public class NibbleCheckitApplesoft implements ApplesoftInputBufferProofReader {
|
||||
private final Configuration config;
|
||||
private final NibbleCheckitChecksum totalChecksum = new NibbleCheckitChecksum();
|
||||
private final NibbleCheckitChecksum lineChecksum = new NibbleCheckitChecksum();
|
||||
|
||||
public NibbleCheckitApplesoft(Configuration config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Configuration getConfiguration() {
|
||||
return config;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public void addProgramText(String code) {
|
||||
System.out.println("Nibble Checkit, Copyright 1988, Microsparc Inc.");
|
||||
ApplesoftInputBufferProofReader.super.addProgramText(code);
|
||||
System.out.printf("TOTAL: %04X\n", getTotalChecksumValue());
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public void addLine(final String originalLine) {
|
||||
// Calculate and output line value
|
||||
lineChecksum.reset();
|
||||
|
||||
// The ? => PRINT replacement always occurs, including in strings!
|
||||
String line = originalLine.replace("?", "PRINT");
|
||||
|
||||
boolean inQuote = false;
|
||||
StringBuilder remLettersSeen = new StringBuilder();
|
||||
for (char ch : line.toCharArray()) {
|
||||
if (ch == '"') inQuote = !inQuote;
|
||||
if (!inQuote && ch == ' ') continue;
|
||||
lineChecksum.add(ch|0x80);
|
||||
|
||||
// we only allow R E M from a comment; skip rest of the comment
|
||||
remLettersSeen.append(ch);
|
||||
if ("REM".contentEquals(remLettersSeen)) {
|
||||
break;
|
||||
}
|
||||
else if ("R".contentEquals(remLettersSeen) || "RE".contentEquals(remLettersSeen)) {
|
||||
// Keep them, this may be a comment
|
||||
}
|
||||
else {
|
||||
remLettersSeen = new StringBuilder();
|
||||
}
|
||||
}
|
||||
|
||||
System.out.printf("%02X | %s\n", getLineChecksumValue(), originalLine);
|
||||
|
||||
// Update program values
|
||||
int lineNumber = Integer.parseInt(line.split(" ")[0].trim());
|
||||
totalChecksum.add(lineNumber & 0xff);
|
||||
totalChecksum.add(lineNumber >> 8);
|
||||
}
|
||||
|
||||
public int getLineChecksumValue() {
|
||||
return ( (lineChecksum.value() & 0xff) - (lineChecksum.value() >> 8) ) & 0xff;
|
||||
}
|
||||
public int getTotalChecksumValue() {
|
||||
int high = totalChecksum.value() & 0xff;
|
||||
int low = (totalChecksum.value() >> 8) & 0xff;
|
||||
return high << 8 | low;
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package org.applecommander.bastools.api.proofreaders;
|
||||
|
||||
public class NibbleCheckitBinary implements BinaryInputBufferProofReader {
|
||||
private final NibbleCheckitChecksum lineChecksum = new NibbleCheckitChecksum();
|
||||
private final NibbleCheckitChecksum totalChecksum = new NibbleCheckitChecksum();
|
||||
|
||||
@Override
|
||||
public void addProgram(final String code) {
|
||||
System.out.println("Nibble Checkit, Copyright 1988, Microsparc Inc.");
|
||||
BinaryInputBufferProofReader.super.addProgram(code);
|
||||
System.out.printf("TOTAL: %04X\n", getTotalChecksumValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addLine(final String line) {
|
||||
lineChecksum.reset();
|
||||
for (char ch : line.toCharArray()) {
|
||||
lineChecksum.add(ch|0x80);
|
||||
}
|
||||
System.out.printf("%02X | %s\n", getLineChecksumValue(), line);
|
||||
|
||||
var info = BinaryDataProofReader.parseLine(line);
|
||||
for (byte b : info.code()) {
|
||||
totalChecksum.add(Byte.toUnsignedInt(b));
|
||||
}
|
||||
}
|
||||
|
||||
public int getLineChecksumValue() {
|
||||
return ( (lineChecksum.value() & 0xff) - (lineChecksum.value() >> 8) ) & 0xff;
|
||||
}
|
||||
public int getTotalChecksumValue() {
|
||||
int high = totalChecksum.value() & 0xff;
|
||||
int low = (totalChecksum.value() >> 8) & 0xff;
|
||||
return high << 8 | low;
|
||||
}
|
||||
}
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
package org.applecommander.bastools.api.proofreaders;
|
||||
|
||||
/**
|
||||
* Perform Nibble Checkit algorithm. Note that a large part of the assembly is shifting the
|
||||
* new value byte into the checksum; if the checksum itself causes a carry in the high byte,
|
||||
* an exclusive-or is done with (maybe?) the CCITT CRC polynomial.
|
||||
* <pre>
|
||||
* 864F- A2 08 L864F LDX #$08 ; 8 bits
|
||||
* 8651- 0A L8651 ASL ; Acc. is value
|
||||
* 8652- 26 08 ROL $08 ; $08/$09 is low/high byte of checksum
|
||||
* 8654- 26 09 ROL $09
|
||||
* 8656- 90 0E BCC L8666 ; no carry, continue loop
|
||||
* 8658- 48 PHA ; save current value
|
||||
* 8659- A5 08 LDA $08
|
||||
* 865B- 49 21 EOR #$21 ; low byte of $1021
|
||||
* 865D- 85 08 STA $08
|
||||
* 865F- A5 09 LDA $09
|
||||
* 8661- 49 10 EOR #$10 ; high byte of $1021
|
||||
* 8663- 85 09 STA $09
|
||||
* 8665- 68 PLA ; restore current value
|
||||
* 8666- CA L8666 DEX
|
||||
* 8667- D0 E8 BNE L8651 ; loop through all 8 bits
|
||||
* 8669- 60 RTS
|
||||
* </pre>
|
||||
* In this implementation, we just mash the value and the checksum together, so the
|
||||
* resulting number is <code>0x00CCCCVV</code>. Then the intermediate carry bits aren't
|
||||
* a concern, and we simply need to detect when we overflow three bytes and then do the
|
||||
* XOR. The result is the middle two bytes where the checksum resides. (Note that the
|
||||
* <code>0x1021</code> was shifted by a byte as well.)
|
||||
*/
|
||||
public class NibbleCheckitChecksum implements ProofReaderChecksum {
|
||||
private int checksum = 0;
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
this.checksum = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(int value) {
|
||||
assert value >= 0 && value <= 0xff;
|
||||
int work = (checksum << 8) | value;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
work <<= 1;
|
||||
// Note: If we run into negative issues somehow, this could also be "((work & 0xff000000) != 0)".
|
||||
if (work > 0xffffff) {
|
||||
work &= 0xffffff;
|
||||
work ^= 0x102100;
|
||||
}
|
||||
}
|
||||
checksum = work >> 8;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int value() {
|
||||
return checksum;
|
||||
}
|
||||
}
|
||||
+5
-6
@@ -28,7 +28,7 @@ import static org.junit.Assert.assertEquals;
|
||||
* Perform some rudimentary testing of the Nibble Checkit algorithm.
|
||||
* Note that some of the algorithm is replicated in the "perform" methods.
|
||||
*/
|
||||
public class NibbleCheckitTest {
|
||||
public class NibbleCheckitApplesoftTest {
|
||||
@Test
|
||||
public void testLineChecksums() {
|
||||
assertEquals(0x37, performLineCalc("10 REM"));
|
||||
@@ -44,8 +44,7 @@ public class NibbleCheckitTest {
|
||||
|
||||
@Test
|
||||
public void testProgramChecksum() {
|
||||
// Note: The value displayed is 1CB9, but the code prints low byte first...
|
||||
assertEquals(0xb91c, performProgramCalc(10, 20, 30));
|
||||
assertEquals(0x1cb9, performProgramCalc(10, 20, 30));
|
||||
}
|
||||
|
||||
protected int performLineCalc(String text) {
|
||||
@@ -53,9 +52,9 @@ public class NibbleCheckitTest {
|
||||
.preserveNumbers(true)
|
||||
.sourceFile(new File("test.bas"))
|
||||
.build();
|
||||
NibbleCheckit proofreader = new NibbleCheckit(config);
|
||||
NibbleCheckitApplesoft proofreader = new NibbleCheckitApplesoft(config);
|
||||
proofreader.addLine(text);
|
||||
return ( (proofreader.getLineChecksumValue() & 0xff) - (proofreader.getLineChecksumValue() >> 8) ) & 0xff;
|
||||
return proofreader.getLineChecksumValue();
|
||||
}
|
||||
|
||||
protected int performProgramCalc(int... lineNumbers) {
|
||||
@@ -63,7 +62,7 @@ public class NibbleCheckitTest {
|
||||
.preserveNumbers(true)
|
||||
.sourceFile(new File("test.bas"))
|
||||
.build();
|
||||
NibbleCheckit proofreader = new NibbleCheckit(config);
|
||||
NibbleCheckitApplesoft proofreader = new NibbleCheckitApplesoft(config);
|
||||
for (int lineNumber : lineNumbers) {
|
||||
// We ignore the line, but line also computes the program checksum
|
||||
proofreader.addLine(Integer.toString(lineNumber));
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
package org.applecommander.bastools.api.proofreaders;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class NibbleCheckitBinaryTest {
|
||||
@Test
|
||||
public void testExtermShapes() {
|
||||
// Nibble, June 1989, page 53
|
||||
final String code = """
|
||||
6100:04 00 0a 00 29 00 4d 00
|
||||
6108:73 00 49 29 15 3e 3c 37
|
||||
6110:35 3e 3f 3e 2e 4d 2c 24
|
||||
6118:15 2d 2e 3e 96 3a 3c fe
|
||||
6120:3b 67 25 2c 25 15 3e 3f
|
||||
6128:00 92 32 2e 24 24 25 2d
|
||||
6130:c1 2d 15 35 35 15 36 27
|
||||
6138:3c 3c c1 3f 5f f7 2e 2d
|
||||
6140:ac f5 3f 2e 35 3f 17 2d
|
||||
6148:2d 3e 3f 3f 00 49 09 ad
|
||||
6150:3f bf 6d 29 ad ff 3b 3f
|
||||
6158:3f 17 6d 29 4d 6d 3a df
|
||||
6160:3f df bf 2d 2d 6d 29 f5
|
||||
6168:1b ff 1b bf 6d 29 f5 3b
|
||||
6170:3f 3f 00 35 35 35 35 35
|
||||
6178:35 35 35 35 35 25 c1 c1
|
||||
6180:c1 c1 c1 c1 c1 c1 c1 37
|
||||
6188:37 37 37 f7 3a 3e 3e 3e
|
||||
6190:3e 06 00
|
||||
""".toUpperCase(); // yes, being lazy
|
||||
final int[] expectedLine = {
|
||||
0x59, 0x5c, 0xa5, 0x24, 0xa6, 0x8a, 0xf9, 0x52,
|
||||
0x32, 0x6c, 0xa5, 0x2c, 0x35, 0xf4, 0xb0, 0x03,
|
||||
0xb0, 0xdf, 0x11
|
||||
};
|
||||
final int expectedTotal = 0x1dd8;
|
||||
|
||||
check(code, expectedLine, expectedTotal);
|
||||
}
|
||||
|
||||
public void check(final String code, final int[] expectedLine, final int expectedTotal) {
|
||||
NibbleCheckitBinary proofreader = new NibbleCheckitBinary();
|
||||
List<String> lines = code.lines().toList();
|
||||
assertEquals("lines are expected length", expectedLine.length, lines.size());
|
||||
for (int i=0; i< lines.size(); i++) {
|
||||
String line = lines.get(i);
|
||||
proofreader.addLine(line);
|
||||
int expectedChecksum = expectedLine[i];
|
||||
assertEquals("line checksum", expectedChecksum, proofreader.getLineChecksumValue());
|
||||
}
|
||||
assertEquals("total checksum", expectedTotal, proofreader.getTotalChecksumValue());
|
||||
}
|
||||
}
|
||||
@@ -352,7 +352,7 @@ public class Main implements Callable<Integer> {
|
||||
@Option(names = "--checkit", description = "Apply Nibble Checkit (ca 1988) to code")
|
||||
public void selectNibbleCheckit(boolean flag) {
|
||||
this.proofReaderFn = (c,p) -> {
|
||||
NibbleCheckit proofreader = new NibbleCheckit(c);
|
||||
NibbleCheckitApplesoft proofreader = new NibbleCheckitApplesoft(c);
|
||||
proofreader.addProgram(p);
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user