mirror of
https://github.com/AppleCommander/bastools.git
synced 2024-05-28 02:48:38 +00:00
Adding a "wrapper" capability to help with DOS rewriting application. #24
This commit is contained in:
parent
089356a3a2
commit
5e72a68c42
|
@ -8,14 +8,6 @@ Generally, the usage pattern is:
|
||||||
|
|
||||||
## Code snippets
|
## Code snippets
|
||||||
|
|
||||||
```java
|
|
||||||
Configuration config = Configuration.builder()
|
|
||||||
.sourceFile(this.sourceFile)
|
|
||||||
.build();
|
|
||||||
```
|
|
||||||
|
|
||||||
The `Configuration` class also allows the BASIC start address to be set (defaults to `0x801`), set the maximum line length (this is in bytes, and defaults to `255`, but feel free to experiment). Some of the classes report output via the debug stream, which defaults to a simple null stream (no output) - replace with `System.out` or another `PrintStream`.
|
|
||||||
|
|
||||||
```java
|
```java
|
||||||
Queue<Token> tokens = TokenReader.tokenize(config.sourceFile);
|
Queue<Token> tokens = TokenReader.tokenize(config.sourceFile);
|
||||||
```
|
```
|
||||||
|
@ -29,6 +21,21 @@ Program program = parser.parse();
|
||||||
|
|
||||||
The `Program` is now the parsed version of the BASIC program. Various `Visitor`s may be used to report, gather information, or manipulate the tree in various ways.
|
The `Program` is now the parsed version of the BASIC program. Various `Visitor`s may be used to report, gather information, or manipulate the tree in various ways.
|
||||||
|
|
||||||
|
```java
|
||||||
|
Configuration config = Configuration.builder()
|
||||||
|
.sourceFile(this.sourceFile)
|
||||||
|
.build();
|
||||||
|
```
|
||||||
|
|
||||||
|
The `Configuration` class also allows the BASIC start address to be set (defaults to `0x801`), set the maximum line length (this is in bytes, and defaults to `255`, but feel free to experiment). Some of the classes report output via the debug stream, which defaults to a simple null stream (no output) - replace with `System.out` or another `PrintStream`.
|
||||||
|
|
||||||
|
```java
|
||||||
|
ByteVisitor byteVisitor = Visitors.byteVisitor(config);
|
||||||
|
byte[] programData = byteVisitor.dump(program);
|
||||||
|
```
|
||||||
|
|
||||||
|
Finally, the ByteVisitor will transform the program into the tokenized form.
|
||||||
|
|
||||||
## Directives
|
## Directives
|
||||||
|
|
||||||
The framework allows embedding of directives.
|
The framework allows embedding of directives.
|
||||||
|
|
|
@ -63,6 +63,7 @@ public class ByteVisitor implements Visitor {
|
||||||
ByteArrayOutputStream os = stack.peek();
|
ByteArrayOutputStream os = stack.peek();
|
||||||
os.write(0x00);
|
os.write(0x00);
|
||||||
os.write(0x00);
|
os.write(0x00);
|
||||||
|
this.address += 2;
|
||||||
return program;
|
return program;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,47 +1,47 @@
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
$ bt
|
$ bt --help
|
||||||
Missing required parameter: <sourceFile>
|
|
||||||
Usage: bt [-chOVx] [--addresses] [--applesingle] [--debug] [--list] [--pretty]
|
Usage: bt [-chOVx] [--addresses] [--applesingle] [--debug] [--list] [--pretty]
|
||||||
[--stdout] [--tokens] [--variables]
|
[--stdout] [--tokens] [--variables] [--wrapper] [-a=<address>]
|
||||||
[--max-line-length=<maxLineLength>] [-a=<address>] [-o=<outputFile>]
|
[--max-line-length=<maxLineLength>] [-o=<outputFile>]
|
||||||
[-f=<optimizations>[,<optimizations>...]]... <sourceFile>
|
[-f=<optimizations>[,<optimizations>...]]... <sourceFile>
|
||||||
|
|
||||||
Transforms an AppleSoft program from text back to its tokenized state.
|
Transforms an AppleSoft program from text back to its tokenized state.
|
||||||
<sourceFile> AppleSoft BASIC program to process.
|
<sourceFile> AppleSoft BASIC program to process.
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
--addresses Dump line number addresses out.
|
|
||||||
--applesingle Write output in AppleSingle format
|
|
||||||
--debug Print debug output.
|
|
||||||
--list List structure as bastools understands it.
|
|
||||||
--max-line-length=<maxLineLength>
|
|
||||||
Maximum line length for generated lines.
|
|
||||||
Default: 255
|
|
||||||
--pretty Pretty print structure as bastools understands it.
|
|
||||||
--stdout Send binary output to stdout.
|
|
||||||
--tokens Dump token list to stdout for debugging.
|
|
||||||
--variables Generate a variable report
|
|
||||||
-a, --address=<address> Base address for program
|
-a, --address=<address> Base address for program
|
||||||
Default: 2049
|
Default: 2049
|
||||||
-c, --copy Generate a copy/paste form of output for testing in an
|
--addresses Dump line number addresses out.
|
||||||
emulator.
|
--applesingle Write output in AppleSingle format
|
||||||
-f= <optimizations>[,<optimizations>...]
|
-c, --copy Generate a copy/paste form of output for testing in
|
||||||
|
an emulator.
|
||||||
|
--debug Print debug output.
|
||||||
|
-f=<optimizations>[,<optimizations>...]
|
||||||
Enable specific optimizations.
|
Enable specific optimizations.
|
||||||
* remove-empty-statements - Strip out all '::'-like
|
* remove-empty-statements - Strip out all '::'-like
|
||||||
statements.
|
statements.
|
||||||
* remove-rem-statements - Remove all REM statements.
|
* remove-rem-statements - Remove all REM statements.
|
||||||
* shorten-variable-names - Ensure all variables are 1 or
|
* shorten-variable-names - Ensure all variables are
|
||||||
2 characters long.
|
1 or 2 characters long.
|
||||||
* extract-constant-values - Assign all constant values
|
* extract-constant-values - Assign all constant
|
||||||
first.
|
values first.
|
||||||
* merge-lines - Merge lines.
|
* merge-lines - Merge lines.
|
||||||
* renumber - Renumber program.
|
* renumber - Renumber program.
|
||||||
-h, --help Show this help message and exit.
|
-h, --help Show this help message and exit.
|
||||||
|
--list List structure as bastools understands it.
|
||||||
|
--max-line-length=<maxLineLength>
|
||||||
|
Maximum line length for generated lines.
|
||||||
|
Default: 255
|
||||||
-o, --output=<outputFile> Write binary output to file.
|
-o, --output=<outputFile> Write binary output to file.
|
||||||
-O, --optimize Apply all optimizations.
|
-O, --optimize Apply all optimizations.
|
||||||
|
--pretty Pretty print structure as bastools understands it.
|
||||||
|
--stdout Send binary output to stdout.
|
||||||
|
--tokens Dump token list to stdout for debugging.
|
||||||
-V, --version Print version information and exit.
|
-V, --version Print version information and exit.
|
||||||
|
--variables Generate a variable report
|
||||||
|
--wrapper Wrap the Applesoft program (DOS 3.3).
|
||||||
-x, --hex Generate a binary hex dump for debugging.
|
-x, --hex Generate a binary hex dump for debugging.
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -153,3 +153,13 @@ demo.dsk /DEMO/
|
||||||
ProDOS format; 139,264 bytes free; 4,096 bytes used.
|
ProDOS format; 139,264 bytes free; 4,096 bytes used.
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Wrapping the application
|
||||||
|
|
||||||
|
DOS 3.3 (but not ProDOS) seems to rewrite the application linked list when an Applesoft program is loaded; this rewrites the pointers and impacts any embedded (via `$embed`) machine code. With the wrapper, the application is "wrapped" with a startup Applesoft program that prevents the rewrite. The wrapper is just a simple program:
|
||||||
|
|
||||||
|
```basic
|
||||||
|
10 POKE 103,24:POKE 104,8:RUN
|
||||||
|
```
|
||||||
|
|
||||||
|
This is a valid program that resets to Applesoft pointer to just after the current program and runs that other program.
|
||||||
|
|
|
@ -1,10 +1,6 @@
|
||||||
package io.github.applecommander.bastools.tools.bt;
|
package io.github.applecommander.bastools.tools.bt;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.*;
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.io.PrintStream;
|
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
@ -74,6 +70,9 @@ public class Main implements Callable<Void> {
|
||||||
|
|
||||||
@Option(names = "--max-line-length", description = "Maximum line length for generated lines.", showDefaultValue = Visibility.ALWAYS)
|
@Option(names = "--max-line-length", description = "Maximum line length for generated lines.", showDefaultValue = Visibility.ALWAYS)
|
||||||
private int maxLineLength = 255;
|
private int maxLineLength = 255;
|
||||||
|
|
||||||
|
@Option(names = "--wrapper", description = "Wrap the Applesoft program (DOS 3.3).")
|
||||||
|
private boolean wrapProgram;
|
||||||
|
|
||||||
@Option(names = "-f", converter = OptimizationTypeConverter.class, split = ",", description = {
|
@Option(names = "-f", converter = OptimizationTypeConverter.class, split = ",", description = {
|
||||||
"Enable specific optimizations.",
|
"Enable specific optimizations.",
|
||||||
|
@ -174,17 +173,34 @@ public class Main implements Callable<Void> {
|
||||||
}
|
}
|
||||||
|
|
||||||
ByteVisitor byteVisitor = Visitors.byteVisitor(config);
|
ByteVisitor byteVisitor = Visitors.byteVisitor(config);
|
||||||
byte[] data = byteVisitor.dump(program);
|
byte[] wrapperData = new byte[0];
|
||||||
|
if (wrapProgram) {
|
||||||
|
Queue<Token> wrapperTokens = TokenReader.tokenize(new ByteArrayInputStream(
|
||||||
|
"10 POKE 103,24:POKE 104,8:RUN".getBytes()));
|
||||||
|
Parser wrapperParser = new Parser(wrapperTokens);
|
||||||
|
Program wrapperProgram = wrapperParser.parse();
|
||||||
|
wrapperData = byteVisitor.dump(wrapperProgram);
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] programData = byteVisitor.dump(program);
|
||||||
if (showLineAddresses) {
|
if (showLineAddresses) {
|
||||||
byteVisitor.getLineAddresses().forEach((l,a) -> System.out.printf("%5d ... $%04x\n", l, a));
|
byteVisitor.getLineAddresses().forEach((l,a) -> System.out.printf("%5d ... $%04x\n", l, a));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Merge both programs together. Note that wrapperData may be a 0 byte array.
|
||||||
|
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||||
|
output.write(wrapperData);
|
||||||
|
output.write(programData);
|
||||||
|
output.flush();
|
||||||
|
byte[] data = output.toByteArray();
|
||||||
|
|
||||||
if (hexFormat) {
|
if (hexFormat) {
|
||||||
HexDumper.standard().dump(address, data);
|
HexDumper.standard().dump(address, data);
|
||||||
}
|
}
|
||||||
if (copyFormat) {
|
if (copyFormat) {
|
||||||
HexDumper.apple2().dump(address, data);
|
HexDumper.apple2().dump(address, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
saveResults(data);
|
saveResults(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user