cleaning infocom code

This commit is contained in:
Denis Molony 2019-12-29 12:52:06 +10:00
parent 504d8f467e
commit 01a62e5918
8 changed files with 223 additions and 120 deletions

View File

@ -623,6 +623,7 @@ public class AppleDisk implements Disk
private int getBufferOffset (DiskAddress da)
{
assert sectorSize == SECTOR_SIZE;
return da.getTrack () * trackSize
+ interleaveSector[interleave][da.getSector ()] * SECTOR_SIZE;
}
@ -630,6 +631,7 @@ public class AppleDisk implements Disk
private int getBufferOffset (DiskAddress da, int seq)
{
assert sectorSize == BLOCK_SIZE;
assert seq == 0 || seq == 1;
return da.getTrack () * trackSize

View File

@ -60,10 +60,33 @@ class CodeManager extends AbstractFile
return blocks;
}
void addMissingRoutines ()
void addRoutines (int programCounter)
{
addRoutine (programCounter - 1, 0); //
addActionRoutines (); // obtained from Grammar
addCodeRoutines (); // obtained from Object properties
addMissingRoutines (); // requires stringPtr to be set
if (false)
{
int ptr = header.highMemory;
for (int key : routines.keySet ())
{
if (ptr % 2 == 1)
++ptr;
Routine routine = routines.get (key);
if (routine.startPtr > ptr)
System.out.printf ("skipped %d bytes%n", routine.startPtr - ptr);
System.out.println (routine);
ptr = routine.startPtr + routine.length;
}
}
}
private void addMissingRoutines ()
{
System.out.printf ("%nWalking the code block%n%n");
int total = 0;
int total = routines.size ();
int ptr = header.highMemory;
while (ptr < header.stringPointer)
@ -71,7 +94,7 @@ class CodeManager extends AbstractFile
if (ptr >= 0 && ptr % 2 == 1) // routine must start on a word boundary
ptr++;
if (containsRoutineAt (ptr))
if (routines.containsKey (ptr))
{
ptr += getRoutine (ptr).length;
continue;
@ -81,18 +104,20 @@ class CodeManager extends AbstractFile
if (routine == null)
{
System.out.printf ("Invalid routine found : %05X%n", ptr);
ptr = findNextRoutine (ptr + 1);
int nextRoutinePtr = findNextRoutine (ptr + 1);
// System.out.println (Utility.getHex (buffer, ptr, nextRoutinePtr - ptr));
ptr = nextRoutinePtr;
System.out.printf ("skipping to %05X%n", ptr);
if (ptr == 0)
break;
}
else
{
total++;
ptr += routine.length;
}
}
System.out.printf ("%n%d new routines found by walking the code block%n%n", total);
System.out.printf ("%n%d new routines found by walking the code block%n%n",
routines.size () - total);
}
private int findNextRoutine (int address)
@ -125,12 +150,7 @@ class CodeManager extends AbstractFile
return text.toString ();
}
boolean containsRoutineAt (int address)
{
return (routines.containsKey (address));
}
void addCodeRoutines ()
private void addCodeRoutines ()
{
List<Integer> routines = header.objectManager.getCodeRoutines ();
System.out.println ("Adding " + routines.size () + " code routines");
@ -138,8 +158,9 @@ class CodeManager extends AbstractFile
addRoutine (address, 0);
}
void addActionRoutines ()
private void addActionRoutines ()
{
// process actionRoutines and preActionRoutines
List<Integer> routines = header.grammar.getActionRoutines ();
System.out.println ("Adding " + routines.size () + " action routines");
for (Integer address : routines)
@ -150,6 +171,7 @@ class CodeManager extends AbstractFile
{
if (address == 0) // stack-based call
return null;
if (address > header.fileLength)
return null;
@ -163,7 +185,7 @@ class CodeManager extends AbstractFile
// try to create a new Routine
Routine r = new Routine (address, header, caller);
if (r.length == 0) // invalid routine
if (!r.isValid ())
return null;
// recursively add all routines called by this one

View File

@ -1,6 +1,11 @@
package com.bytezone.diskbrowser.infocom;
import java.util.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import com.bytezone.diskbrowser.utilities.HexFormatter;
@ -70,6 +75,7 @@ class Grammar extends InfocomAbstractFile
hexBlocks.add (new HexBlock (actionPtr, actionSize, "Action routines:"));
hexBlocks.add (new HexBlock (preActionPtr, preActionSize, "Pre-action routines:"));
hexBlocks.add (new HexBlock (prepositionPtr, prepositionSize, "Preposition table:"));
// System.out.println (getHexDump ());
// create SentenceGroup and Sentence objects and action lists
int count = 255;

View File

@ -73,10 +73,7 @@ class Header extends InfocomAbstractFile
// add all the ZStrings
stringManager = new StringManager ("Strings", buffer, this);
codeManager.addRoutine (programCounter - 1, 0);
codeManager.addActionRoutines (); // obtained from Grammar
codeManager.addCodeRoutines (); // obtained from Object properties
codeManager.addMissingRoutines (); // requires stringPtr to be set
codeManager.addRoutines (programCounter);
// add entries for AbstractFile.getHexDump ()
hexBlocks.add (new HexBlock (0, 64, "Header data:"));
@ -139,6 +136,41 @@ class Header extends InfocomAbstractFile
text.append (String.format ("Total objects %d%n",
objectManager.getObjects ().size ()));
text.append (getAlternate ());
return text.toString ();
}
private String getAlternate ()
{
StringBuilder text = new StringBuilder ("\n\n");
text.append (getLine (0, 1, "version"));
text.append (getLine (1, 3, "flags 1"));
text.append (getLine (4, 2, "high memory"));
text.append (getLine (6, 2, "program counter"));
text.append (getLine (8, 2, "dictionary"));
text.append (getLine (10, 2, "object table"));
text.append (getLine (12, 2, "global variables"));
text.append (getLine (14, 2, "static memory"));
text.append (getLine (16, 2, "flags 2"));
text.append (getLine (24, 2, "abbreviations table"));
text.append (getLine (26, 2, "length of file (x2 = " + fileLength + ")"));
text.append (getLine (28, 2, "checksum"));
text.append (getLine (50, 1, "revision number"));
return text.toString ();
}
private String getLine (int offset, int size, String description)
{
StringBuilder text = new StringBuilder ();
text.append (String.format ("%04X - %04X ", offset, offset + size - 1));
for (int i = 0; i < size; i++)
text.append (String.format ("%02X ", buffer[offset + i]));
while (text.length () < 24)
text.append (" ");
text.append (description);
text.append ("\n");
return text.toString ();
}

View File

@ -11,7 +11,12 @@ import javax.swing.JOptionPane;
import javax.swing.tree.DefaultMutableTreeNode;
import com.bytezone.diskbrowser.applefile.AppleFileSource;
import com.bytezone.diskbrowser.disk.*;
import com.bytezone.diskbrowser.disk.AbstractFormattedDisk;
import com.bytezone.diskbrowser.disk.AppleDisk;
import com.bytezone.diskbrowser.disk.DefaultAppleFileSource;
import com.bytezone.diskbrowser.disk.Disk;
import com.bytezone.diskbrowser.disk.DiskAddress;
import com.bytezone.diskbrowser.disk.SectorType;
import com.bytezone.diskbrowser.gui.DataSource;
import com.bytezone.diskbrowser.utilities.HexFormatter;
@ -25,12 +30,11 @@ public class InfocomDisk extends AbstractFormattedDisk
private static final boolean TYPE_NODE = true;
private static final boolean TYPE_LEAF = false;
private byte[] data;
// private int version;
private final Header header;
Color green = new Color (0, 200, 0);
SectorType bootSector = new SectorType ("Boot code", Color.lightGray);
SectorType bootSector = new SectorType ("ZIP code", Color.lightGray);
SectorType stringsSector = new SectorType ("Strings", Color.magenta);
SectorType objectsSector = new SectorType ("Objects", green);
SectorType dictionarySector = new SectorType ("Dictionary", Color.blue);

View File

@ -7,15 +7,15 @@ import com.bytezone.diskbrowser.utilities.HexFormatter;
class Instruction
{
Opcode opcode;
int startPtr;
byte[] buffer;
final Opcode opcode;
private int startPtr;
private byte[] buffer;
// List<ZString> abbreviations;
Header header;
private Header header;
enum OperandType
{
VAR_STACK, VAR_LOCAL, VAR_GLOBAL, BYTE, WORD, ARG_BRANCH, ARG_STRING
VAR_SP, VAR_LOCAL, VAR_GLOBAL, BYTE, WORD, ARG_BRANCH, ARG_STRING
}
static final String[] name2OP =
@ -38,26 +38,23 @@ class Instruction
"scan_table", "not", "call_vn", "call_vn2", "tokenise", "encode_text",
"copy_table", "print_table", "check_arg" };
public Instruction (byte[] buffer, int ptr, Header header)
Instruction (byte[] buffer, int ptr, Header header)
{
this.buffer = buffer;
this.startPtr = ptr;
this.header = header;
byte b1 = buffer[ptr];
// long
if ((b1 & 0x80) == 0)
if ((b1 & 0x80) == 0) // long
opcode = new Opcode2OPLong (buffer, ptr);
// short
else if ((b1 & 0x40) == 0)
else if ((b1 & 0x40) == 0) // short
{
if ((b1 & 0x30) == 0x30)
opcode = new Opcode0OP (buffer, ptr);
else
opcode = new Opcode1OP (buffer, ptr);
}
// variable
else
else // variable
{
if ((b1 & 0x20) == 0)
opcode = new Opcode2OPVar (buffer, ptr);
@ -66,43 +63,43 @@ class Instruction
}
}
public int length ()
int length ()
{
return opcode.length ();
}
public boolean isReturn ()
boolean isReturn ()
{
return opcode.isReturn;
}
public boolean isPrint ()
boolean isPrint ()
{
return opcode.string != null;
}
public boolean isCall ()
boolean isCall ()
{
return opcode.isCall;
}
public boolean isJump ()
boolean isJump ()
{
// could use jumpTarget != 0
return (opcode instanceof Opcode1OP && opcode.opcodeNumber == 12);
}
public boolean isBranch ()
boolean isBranch ()
{
return opcode.branch != null;
}
public boolean isStore ()
boolean isStore ()
{
return opcode.store != null;
}
public int target ()
int target ()
{
return isBranch () ? opcode.branch.target : 0;
}
@ -117,8 +114,10 @@ class Instruction
max = 9;
extra = "..";
}
String hex = HexFormatter.getHexString (buffer, startPtr, max);
return String.format ("%-26s%2s %s", hex, extra, opcode.toString ());
return String.format ("%05X : %-26s%2s %s", startPtr, hex, extra, opcode.toString ());
}
abstract class Opcode
@ -134,7 +133,7 @@ class Instruction
int jumpTarget;
int callTarget;
public Opcode ()
Opcode ()
{
operands = new ArrayList<Operand> ();
}
@ -143,9 +142,9 @@ class Instruction
public String toString ()
{
StringBuilder text = new StringBuilder ();
if (false)
text.append (HexFormatter.formatNoHeader (buffer, startPtr, length ()) + "\n");
text.append (String.format ("%05X : %-12s", startPtr, opcodeName ()));
text.append (String.format ("%-12s", opcodeName ()));
if (jumpTarget != 0)
text.append (String.format (" L:%05X", jumpTarget));
else if (isCall)
@ -173,7 +172,7 @@ class Instruction
return text.toString ();
}
public int length ()
int length ()
{
int length = totalOperandLength + opcodeLength;
if (branch != null)
@ -185,7 +184,7 @@ class Instruction
return length;
}
public abstract String opcodeName ();
abstract String opcodeName ();
private void addOperand (Operand operand)
{
@ -193,7 +192,7 @@ class Instruction
totalOperandLength += operand.length;
}
protected void addOperand (byte[] buffer, int ptr, boolean bit1, boolean bit2)
void addOperand (byte[] buffer, int ptr, boolean bit1, boolean bit2)
{
int offset = ptr + totalOperandLength;
if (bit1)
@ -207,7 +206,7 @@ class Instruction
addOperand (new OperandWord (header.getWord (offset))); // %00
}
protected void addOperand (byte[] buffer, int ptr, boolean bit)
void addOperand (byte[] buffer, int ptr, boolean bit)
{
int address = ptr + totalOperandLength;
if (address >= buffer.length)
@ -221,7 +220,7 @@ class Instruction
addOperand (new OperandByte (buffer[address]));
}
protected void setVariableOperands (int ptr)
void setVariableOperands (int ptr)
{
int value = buffer[ptr + 1] & 0xFF;
for (int i = 0; i < 4; i++)
@ -235,21 +234,21 @@ class Instruction
}
}
protected void setStore (byte[] buffer)
void setStore (byte[] buffer)
{
store = new OperandVariable (buffer[startPtr + totalOperandLength + opcodeLength]);
}
protected void setBranch (byte[] buffer)
void setBranch (byte[] buffer)
{
int offset = startPtr + totalOperandLength + (store == null ? 0 : 1) + opcodeLength;
if ((buffer[offset] & 0x40) == 0x40)
if ((buffer[offset] & 0x40) != 0)
branch = new ArgumentBranch (buffer[offset], offset);
else
branch = new ArgumentBranch (header.getWord (offset), offset);
}
protected void setZString (byte[] buffer)
void setZString (byte[] buffer)
{
int offset = startPtr + totalOperandLength + opcodeLength;
string = new ArgumentString (buffer, offset);
@ -258,7 +257,7 @@ class Instruction
class Opcode0OP extends Opcode
{
public Opcode0OP (byte[] buffer, int ptr)
Opcode0OP (byte[] buffer, int ptr)
{
opcodeNumber = buffer[ptr] & 0x0F;
opcodeLength = 1;
@ -286,7 +285,7 @@ class Instruction
class Opcode1OP extends Opcode
{
public Opcode1OP (byte[] buffer, int ptr)
Opcode1OP (byte[] buffer, int ptr)
{
opcodeNumber = buffer[ptr] & 0x0F;
opcodeLength = 1;
@ -315,12 +314,12 @@ class Instruction
abstract class Opcode2OP extends Opcode
{
public Opcode2OP ()
Opcode2OP ()
{
opcodeLength = 1;
}
public void setArguments (byte[] buffer)
void setArguments (byte[] buffer)
{
if ((opcodeNumber >= 1 && opcodeNumber <= 7) || opcodeNumber == 10)
setBranch (buffer);
@ -338,7 +337,7 @@ class Instruction
class Opcode2OPLong extends Opcode2OP
{
public Opcode2OPLong (byte[] buffer, int ptr)
Opcode2OPLong (byte[] buffer, int ptr)
{
opcodeNumber = buffer[ptr] & 0x1F;
boolean bit1 = ((buffer[ptr] & 0x40) == 0x40);
@ -352,7 +351,7 @@ class Instruction
class Opcode2OPVar extends Opcode2OP
{
public Opcode2OPVar (byte[] buffer, int ptr)
Opcode2OPVar (byte[] buffer, int ptr)
{
opcodeNumber = buffer[ptr] & 0x1F;
opcodeLength = 2;
@ -363,7 +362,7 @@ class Instruction
class OpcodeVar extends Opcode
{
public OpcodeVar (byte[] buffer, int ptr)
OpcodeVar (byte[] buffer, int ptr)
{
opcodeNumber = buffer[ptr] & 0x1F;
opcodeLength = 2;
@ -394,7 +393,7 @@ class Instruction
class OperandWord extends Operand
{
public OperandWord (int value)
OperandWord (int value)
{
this.value = value;
length = 2;
@ -410,7 +409,7 @@ class Instruction
class OperandByte extends Operand
{
public OperandByte (byte value)
OperandByte (byte value)
{
this.value = value & 0xFF;
length = 1;
@ -426,13 +425,13 @@ class Instruction
class OperandVariable extends Operand
{
public OperandVariable (byte value)
OperandVariable (byte value)
{
this.value = value & 0xFF;
length = 1;
if (value == 0)
operandType = OperandType.VAR_STACK;
operandType = OperandType.VAR_SP;
else if (value <= 15)
operandType = OperandType.VAR_LOCAL;
else
@ -442,8 +441,8 @@ class Instruction
@Override
public String toString ()
{
if (operandType == OperandType.VAR_STACK)
return ("ToS");
if (operandType == OperandType.VAR_SP)
return ("SP");
if (operandType == OperandType.VAR_LOCAL)
return (String.format ("L%02d", value));
return String.format ("G%03d", (value - 15));
@ -452,13 +451,13 @@ class Instruction
class ArgumentBranch extends Operand
{
int target;
boolean branchOnTrue;
private int target;
private boolean branchOnTrue;
public ArgumentBranch (byte value, int offset)
ArgumentBranch (byte value, int offset)
{
branchOnTrue = (value & 0x80) == 0x80;
int val = value & 0x3F; // unsigned
branchOnTrue = (value & 0x80) != 0;
int val = value & 0x3F; // 0 - 63
if (val <= 1)
target = val;
else
@ -467,12 +466,19 @@ class Instruction
operandType = OperandType.ARG_BRANCH;
}
public ArgumentBranch (int value, int offset)
ArgumentBranch (int value, int offset)
{
branchOnTrue = (value & 0x8000) == 0x8000;
int val = value & 0x3FFF; // signed
if (val > 8191)
val -= 16384;
branchOnTrue = (value & 0x8000) != 0;
int val = ((value & 0x3FFF) << 18) >> 18; // signed 14-bit number
// int val = value & 0x3FFF; // signed
// if (val >= 0x2000)
// {
// System.out.printf ("%04X -> %d%n", val, (val - 0x4000));
// val -= 0x4000;
// }
// else
// System.out.printf ("%04X%n", val);
target = val + offset;
length = 2;
operandType = OperandType.ARG_BRANCH;
@ -493,11 +499,11 @@ class Instruction
class ArgumentString extends Operand
{
ZString text;
int startPtr;
byte[] buffer;
private ZString text;
private int startPtr;
private byte[] buffer;
public ArgumentString (byte[] buffer, int offset)
ArgumentString (byte[] buffer, int offset)
{
this.buffer = buffer;
text = new ZString (header, offset);

View File

@ -39,10 +39,7 @@ class ObjectAnalyser
pt.addTest (hmc);
pt.doTests ();
// System.out.println ("\nSetting the string pointer\n");
for (Integer propertyNo : pt)
// list of all properties that passed all tests
for (Integer propertyNo : pt) // list of all properties that passed all tests
list.add (hmc.statistics[propertyNo]);
Collections.sort (list);
@ -88,22 +85,22 @@ class ObjectAnalyser
System.out.println ("Routines found : " + totRoutines);
}
public void checkThreeByteProperties ()
{
for (ZObject object : parent.getObjects ())
{
for (Property property : object.properties)
{
if (header.getPropertyName (property.propertyNumber).charAt (0) < 'a'
&& property.length == 3)
{
int address = header.getWord (property.ptr + 1) * 2;
System.out.println ("checking " + address);
header.codeManager.addRoutine (address, 0);
}
}
}
}
// private void checkThreeByteProperties ()
// {
// for (ZObject object : parent.getObjects ())
// {
// for (Property property : object.properties)
// {
// if (header.getPropertyName (property.propertyNumber).charAt (0) < 'a'
// && property.length == 3)
// {
// int address = header.getWord (property.ptr + 1) * 2;
// System.out.println ("checking " + address);
// header.codeManager.addRoutine (address, 0);
// }
// }
// }
// }
// find the property with only dictionary entries
public void setDictionary ()

View File

@ -10,8 +10,6 @@ import com.bytezone.diskbrowser.infocom.Instruction.OperandType;
class Routine extends InfocomAbstractFile
implements Iterable<Instruction>, Comparable<Routine>
{
private static final String padding = " ";
int startPtr, length, strings, locals;
List<Parameter> parameters = new ArrayList<Parameter> ();
@ -28,7 +26,7 @@ class Routine extends InfocomAbstractFile
if (locals > 15)
{
System.out.println ("Too many locals: " + locals);
return;
return; // startPtr will be zero
}
startPtr = ptr++; // also used to flag a valid routine
@ -61,16 +59,19 @@ class Routine extends InfocomAbstractFile
if (operand.operandType == OperandType.VAR_GLOBAL)
header.globals.addRoutine (this, operand);
ptr += instruction.length ();
ptr += instruction.length (); // point to next instruction
if (isTarget (ptr))
continue;
// is it a backwards jump?
if (instruction.isJump () && instruction.target () < ptr && !moreCode (ptr))
if (instruction.isJump () && instruction.target () < ptr)
break;
// is it an unconditional return?
if (instruction.isReturn () && !moreCode (ptr))
if (instruction.isReturn ())
break;
}
length = ptr - startPtr;
hexBlocks.add (new HexBlock (startPtr, length, null));
@ -79,22 +80,27 @@ class Routine extends InfocomAbstractFile
if (true)
{
int endPtr = startPtr + length;
for (Instruction ins : instructions)
for (Instruction instruction : instructions)
{
int target = ins.target () > 256 ? ins.target ()
: ins.opcode.jumpTarget > 256 ? ins.opcode.jumpTarget : 0;
int target = instruction.target () > 256 ? instruction.target ()
: instruction.opcode.jumpTarget > 256 ? instruction.opcode.jumpTarget : 0;
if (target == 0)
continue;
if (ins.isBranch () && (target > endPtr || target < startPtr))
System.out.println (ins);
if (ins.isJump () && (target > endPtr || target < startPtr))
System.out.println (ins);
if (instruction.isBranch () && (target > endPtr || target < startPtr))
System.out.println (instruction);
if (instruction.isJump () && (target > endPtr || target < startPtr))
System.out.println (instruction);
}
}
}
boolean isValid ()
{
return startPtr > 0;
}
// test whether the routine contains any instructions pointing to this address
private boolean moreCode (int ptr)
private boolean isTarget (int ptr)
{
for (Instruction ins : instructions)
{
@ -116,17 +122,45 @@ class Routine extends InfocomAbstractFile
public String getText ()
{
StringBuilder text = new StringBuilder ();
text.append (String.format ("Called by : %3d%n", calledBy.size ()));
text.append (String.format ("Calls : %3d%n%n", calls.size ()));
text.append (String.format ("%s%05X : %d%n", padding, startPtr, locals));
text.append (String.format ("Calls : %3d%n", calls.size ()));
text.append (String.format ("Length : %3d%n%n", length));
text.append (String.format ("%05X : %d%n", startPtr, locals));
for (Parameter parameter : parameters)
text.append (padding + parameter.toString () + "\n");
text.append (parameter.toString () + "\n");
text.append ("\n");
for (Instruction instruction : instructions)
text.append (instruction + "\n");
if (calledBy.size () > 0)
{
text.append ("\n\nCalled by\n\n");
for (int i : calledBy)
text.append (String.format ("%05X%n", i));
}
if (calls.size () > 0)
{
text.append ("\n\nCalls\n\n");
for (int i : calls)
text.append (String.format ("%05X%n", i));
}
return text.toString ();
}
@Override
public String toString ()
{
return String.format ("[Start: %05X, Len: %4d, Strings: %2d, Locals: %2d]", startPtr,
length, strings, locals);
}
class Parameter
{
int value;