bastok: tool to convert a BASIC tokenized file to ASCII.
git-svn-id: svn://localhost/thomson@63 85ae3b6b-dc8f-4344-a89d-598714f2e4e5
diff --git a/tools/bastok/bastok.cpp b/tools/bastok/bastok.cpp
new file mode 100644
index 0000000..166efbd
--- /dev/null
+++ b/tools/bastok/bastok.cpp
@@ -0,0 +1,168 @@
+#include <map>
+#include <vector>
+#include <stdint.h>
+
+#include <arpa/inet.h>
+
+struct __attribute__((packed)) BAS_Data {
+ uint8_t type;
+ uint16_t length;
+ std::vector<uint8_t> data;
+};
+
+bool BAS_ReadChunk(FILE* in, BAS_Data& out) {
+ // Read the chunk header
+ int value = fread(&out, 3, 1, in);
+ if (value == 0)
+ return false;
+
+ // 6809 is little endian, take that into account...
+ out.length = ntohs(out.length);
+
+ // Resize the data member to the proper size and read the data to it.
+ out.data.reserve(out.length);
+ fread(&out.data[0], out.length, 1, in);
+
+ return true;
+};
+
+struct __attribute__((packed)) BAS_Line {
+ uint16_t offset;
+ uint16_t number;
+ uint8_t data[];
+};
+
+void BAStoASCII(BAS_Data& data)
+{
+ std::map<uint8_t, const char*> Opcodes;
+ std::map<uint8_t, const char*> Functions;
+
+ // FLOW CONTROL
+ Opcodes[0x80] = "END";
+ Opcodes[0x81] = "FOR";
+ Opcodes[0x82] = "NEXT";
+ Opcodes[0x83] = "DATA";
+ Opcodes[0x84] = "DIM";
+ Opcodes[0x85] = "READ";
+ //
+ Opcodes[0x87] = "GO";
+ //
+ Opcodes[0x89] = "IF";
+ Opcodes[0x8A] = "RESTORE";
+ Opcodes[0x8B] = "RETURN";
+ //
+ Opcodes[0x93] = "DEFINT";
+ // CURSOR
+ Opcodes[0x9C] = "LOCATE";
+ Opcodes[0x9D] = "CLS";
+ // MACHINE
+ Opcodes[0xA2] = "EXEC";
+ // DISPLAY
+ Opcodes[0xA4] = "COLOR";
+ Opcodes[0xA5] = "LINE";
+ Opcodes[0xA6] = "BOX";
+ //
+ Opcodes[0xA8] = "ATTRB";
+ Opcodes[0xA9] = "DEF"; // FIXME DEFGR$
+ Opcodes[0xAA] = "POKE";
+ Opcodes[0xAB] = "PRINT";
+ //
+ Opcodes[0xAE] = "CLEAR";
+
+ // SOUND
+ Opcodes[0xB9] = "PLAY";
+
+ // SUB-CODES
+ Opcodes[0xBB] = "TO";
+ Opcodes[0xBC] = "SUB";
+ //
+ Opcodes[0xBF] = "USING";
+ //
+ Opcodes[0xC4] = "THEN";
+ //
+ Opcodes[0xC6] = "STEP";
+
+ // OPERATORS
+ Opcodes[0xC7] = "+";
+ Opcodes[0xC8] = "-";
+ Opcodes[0xC9] = "*";
+ Opcodes[0xCA] = "/";
+ //
+ Opcodes[0xCC] = "AND";
+ Opcodes[0xCD] = "OR";
+ //
+ Opcodes[0xD3] = ">";
+ Opcodes[0xD4] = "=";
+ Opcodes[0xD5] = "<";
+
+
+ Functions[0x81] = "INT";
+ Functions[0x82] = "ABS";
+ Functions[0x8B] = "LEN";
+ Functions[0x8E] = "ASC";
+ Functions[0x8F] = "CHR$";
+ Functions[0x99] = "GR$";
+ Functions[0x9A] = "LEFT$";
+ Functions[0x9C] = "MID$";
+ Functions[0x9F] = "RND";
+ Functions[0xA0] = "INKEY$";
+ Functions[0xA1] = "INPUT$";
+ Functions[0xA4] = "SCREEN";
+
+ /* ################################ */
+
+ BAS_Line* currentLine;
+ currentLine = (BAS_Line*)&data.data[0];
+
+ bool func = false;
+ while(currentLine->offset) {
+ // Endianness fixup
+ currentLine->offset = ntohs(currentLine->offset);
+ currentLine->number = ntohs(currentLine->number);
+
+ printf("%d ", currentLine->number);
+
+ for (int i = 0; currentLine->data[i]; i++) {
+ uint8_t c = currentLine->data[i];
+ if (c < 128 && isprint(c))
+ putchar(c);
+ else if (c == 0xFF) {
+ func = true;
+ continue;
+ } else if ((!func) && (Opcodes.find(c) != Opcodes.end()))
+ printf("\x1B[31m%s\x1B[0m", Opcodes[c]);
+ else if (func && (Functions.find(c) != Functions.end()))
+ printf("\x1B[32m%s\x1B[0m", Functions[c]);
+ else {
+ printf("\n*** UNKNOWN %s %x ***\n", func?"FUNCTION":"OPCODE", c);
+ for (int k = 0; currentLine->data[k]; k++)
+ printf("%02X ", currentLine->data[k]);
+ puts("");
+ exit(EXIT_FAILURE);
+ }
+ func = false;
+ }
+ currentLine = (BAS_Line*)&data.data[currentLine->offset - 0x25A4];
+ puts("");
+ }
+}
+
+int main(int argc, char* argv[])
+{
+ if (argc < 2)
+ {
+ fprintf(stderr, "%s file.bas\n", argv[0]);
+ return 1;
+ }
+
+ FILE* in;
+ BAS_Data h;
+
+ in = fopen(argv[1], "rb");
+
+ while(BAS_ReadChunk(in, h))
+ {
+ BAStoASCII(h);
+ };
+
+}