mirror of
https://github.com/AppleCommander/bastools.git
synced 2025-02-09 00:30:32 +00:00
Adding command-line. Closes #6.
This commit is contained in:
parent
f008a950c3
commit
19f3fe56bf
2
.gitignore
vendored
2
.gitignore
vendored
@ -2,3 +2,5 @@
|
||||
/.settings/
|
||||
/.classpath
|
||||
/.project
|
||||
pom.xml.versionsBackup
|
||||
*.bin
|
||||
|
52
pom.xml
52
pom.xml
@ -1,16 +1,62 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>net.sf.applecommander</groupId>
|
||||
<artifactId>bastokenizer</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<version>0.1.0-SNAPSHOT</version>
|
||||
<name>AppleSoft BASIC Tokenizer</name>
|
||||
<description>Experiments with generating an AppleSoft B/BAS tokenized "binary".</description>
|
||||
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.build.timestamp.format>yyyy-MM-dd HH:mm</maven.build.timestamp.format>
|
||||
<timestamp>${maven.build.timestamp}</timestamp>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>info.picocli</groupId>
|
||||
<artifactId>picocli</artifactId>
|
||||
<version>[3.0,3.1)</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>3.0.2</version>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifest>
|
||||
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
|
||||
<addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
|
||||
<useUniqueVersions>false</useUniqueVersions>
|
||||
</manifest>
|
||||
<manifestEntries>
|
||||
<Implementation-Version>${project.version} (${timestamp})</Implementation-Version>
|
||||
</manifestEntries>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<version>2.0.0.RELEASE</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>repackage</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
@ -1,5 +1,6 @@
|
||||
package com.webcodepro.applecommander.util.applesoft;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
@ -24,12 +25,18 @@ public class TokenReader {
|
||||
private Reader reader;
|
||||
private StreamTokenizer tokenizer;
|
||||
|
||||
/** A handy method to generate a list of Tokens from a file. */
|
||||
/** A handy method to generate a list of Tokens from a file name. */
|
||||
public static Queue<Token> tokenize(String filename) throws FileNotFoundException, IOException {
|
||||
try (FileReader fileReader = new FileReader(filename)) {
|
||||
return tokenize(fileReader);
|
||||
}
|
||||
}
|
||||
/** A handy method to generate a list of Tokens from a file. */
|
||||
public static Queue<Token> tokenize(File file) throws FileNotFoundException, IOException {
|
||||
try (FileReader fileReader = new FileReader(file)) {
|
||||
return tokenize(fileReader);
|
||||
}
|
||||
}
|
||||
/** A handy method to generate a list of Tokens from an InputStream. */
|
||||
public static Queue<Token> tokenize(InputStream inputStream) throws IOException {
|
||||
try (InputStreamReader streamReader = new InputStreamReader(inputStream)) {
|
||||
|
@ -1,37 +1,115 @@
|
||||
package io.github.applecommander.bastokenizer;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import com.webcodepro.applecommander.util.applesoft.Parser;
|
||||
import com.webcodepro.applecommander.util.applesoft.Program;
|
||||
import com.webcodepro.applecommander.util.applesoft.Token;
|
||||
import com.webcodepro.applecommander.util.applesoft.TokenReader;
|
||||
|
||||
/** A simple driver for the tokenizer for a sample and rudimentary test. */
|
||||
public class Main {
|
||||
public static void main(String[] args) throws FileNotFoundException, IOException {
|
||||
if (args.length != 1) {
|
||||
System.err.println("Please include a file to work on.");
|
||||
System.exit(1);
|
||||
}
|
||||
import picocli.CommandLine;
|
||||
import picocli.CommandLine.Command;
|
||||
import picocli.CommandLine.Help.Visibility;
|
||||
import picocli.CommandLine.ITypeConverter;
|
||||
import picocli.CommandLine.IVersionProvider;
|
||||
import picocli.CommandLine.Option;
|
||||
import picocli.CommandLine.Parameters;
|
||||
|
||||
Queue<Token> tokens = TokenReader.tokenize(args[0]);
|
||||
System.out.println(tokens.toString());
|
||||
Parser parser = new Parser(tokens);
|
||||
Program program = parser.parse();
|
||||
program.prettyPrint(System.out);
|
||||
|
||||
int address = 0x801;
|
||||
byte[] data = program.toBytes(address);
|
||||
print(address, data, false);
|
||||
print(address, data, true);
|
||||
/** A command-line interface to the AppleSoft BAS tokenizer libraries. */
|
||||
@Command(description = "Transforms an AppleSoft program from text back to it's tokenized state.",
|
||||
name = "bt", mixinStandardHelpOptions = true,
|
||||
versionProvider = Main.VersionProvider.class)
|
||||
public class Main implements Callable<Void> {
|
||||
@Option(names = { "-o", "--output" }, description = "Write binary output to file.")
|
||||
private File outputFile;
|
||||
|
||||
@Option(names = { "-x", "--hex"}, description = "Generate a binary hex dump for debugging.")
|
||||
private boolean hexFormat;
|
||||
|
||||
@Option(names = { "-c", "--copy"}, description = "Generate a copy/paste form of output for testing in an emulator.")
|
||||
private boolean copyFormat;
|
||||
|
||||
@Option(names = { "-a", "--address" }, description = "Base address for program", showDefaultValue = Visibility.ALWAYS, converter = IntegerTypeConverter.class)
|
||||
private int address = 0x801;
|
||||
|
||||
@Option(names = { "-p", "--pipe" }, description = "Pipe binary output to stdout.")
|
||||
private boolean pipeOutput;
|
||||
|
||||
@Option(names = "--pretty", description = "Pretty print structure as bastokenizer understands it.")
|
||||
private boolean prettyPrint;
|
||||
|
||||
@Option(names = "--tokens", description = "Dump token list to stdout for debugging.")
|
||||
private boolean showTokens;
|
||||
|
||||
@Parameters(index = "0", description = "AppleSoft BASIC program to process.")
|
||||
private File sourceFile;
|
||||
|
||||
public static void main(String[] args) throws FileNotFoundException, IOException {
|
||||
CommandLine.call(new Main(), args);
|
||||
}
|
||||
|
||||
public static void print(int address, byte[] data, boolean forApple) {
|
||||
@Override
|
||||
public Void call() throws FileNotFoundException, IOException {
|
||||
if (checkParameters()) {
|
||||
process();
|
||||
}
|
||||
|
||||
return null; // To satisfy object "Void"
|
||||
}
|
||||
|
||||
/** A basic test to ensure parameters are somewhat sane. */
|
||||
public boolean checkParameters() {
|
||||
if (pipeOutput && (hexFormat || copyFormat || prettyPrint || showTokens)) {
|
||||
System.err.println("The pipe option blocks any other stdout options.");
|
||||
return false;
|
||||
} else if (!(pipeOutput || hexFormat || copyFormat || prettyPrint || showTokens || outputFile != null)) {
|
||||
System.err.println("What do you want to do?");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/** General CLI processing. */
|
||||
public void process() throws FileNotFoundException, IOException {
|
||||
Queue<Token> tokens = TokenReader.tokenize(sourceFile);
|
||||
if (showTokens) {
|
||||
System.out.println(tokens.toString());
|
||||
}
|
||||
Parser parser = new Parser(tokens);
|
||||
Program program = parser.parse();
|
||||
if (prettyPrint) {
|
||||
program.prettyPrint(System.out);
|
||||
}
|
||||
|
||||
byte[] data = program.toBytes(address);
|
||||
if (hexFormat) {
|
||||
hexDump(address, data, false);
|
||||
}
|
||||
if (copyFormat) {
|
||||
hexDump(address, data, true);
|
||||
}
|
||||
if (outputFile != null) {
|
||||
Files.write(outputFile.toPath(), data);
|
||||
}
|
||||
if (pipeOutput) {
|
||||
System.out.write(data);
|
||||
}
|
||||
}
|
||||
|
||||
/** Dump data to stdout in various formats. */
|
||||
public void hexDump(int address, byte[] data, boolean forApple) {
|
||||
final int line = 16;
|
||||
int offset = 0;
|
||||
if (forApple) {
|
||||
int end = address + data.length;
|
||||
System.out.printf("0067: %02x %02x %02x %02x\n", address&0xff, address>>8, end&0xff, end>>8);
|
||||
System.out.printf("%04x: 00\n", address-1);
|
||||
}
|
||||
while (offset < data.length) {
|
||||
System.out.printf("%04x: ", address);
|
||||
for (int i=0; i<line; i++) {
|
||||
@ -58,6 +136,27 @@ public class Main {
|
||||
System.out.printf("\n");
|
||||
address += line;
|
||||
}
|
||||
}
|
||||
|
||||
/** Display version information. Note that this is dependent on Maven configuration. */
|
||||
public static class VersionProvider implements IVersionProvider {
|
||||
public String[] getVersion() {
|
||||
return new String[] { Main.class.getPackage().getImplementationVersion() };
|
||||
}
|
||||
}
|
||||
/** Add support for "$801" and "0x801" instead of just decimal like 2049. */
|
||||
public static class IntegerTypeConverter implements ITypeConverter<Integer> {
|
||||
@Override
|
||||
public Integer convert(String value) throws Exception {
|
||||
if (value == null) {
|
||||
return null;
|
||||
} else if (value.startsWith("$")) {
|
||||
return Integer.valueOf(value.substring(1), 16);
|
||||
} else if (value.startsWith("0x") || value.startsWith("0X")) {
|
||||
return Integer.valueOf(value.substring(2), 16);
|
||||
} else {
|
||||
return Integer.valueOf(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user