From 9207282bcff35e31dd57bbfecf0acccdc2448d8c Mon Sep 17 00:00:00 2001 From: Stephen Hewitt Date: Sun, 3 Aug 2025 04:13:35 +1000 Subject: [PATCH] patterns: Added Commodore BASIC (#428) * Commodore BASIC * Update desc * I made it * Implemented suggestion * Implemented suggestion * Test file * Rename file --------- Co-authored-by: Nik --- README.md | 1 + patterns/commodore_basic.hexpat | 158 ++++++++++++++++++ .../test_data/commodore_basic.hexpat.prg | Bin 0 -> 6702 bytes 3 files changed, 159 insertions(+) create mode 100644 patterns/commodore_basic.hexpat create mode 100644 tests/patterns/test_data/commodore_basic.hexpat.prg diff --git a/README.md b/README.md index 6b6b821..695e312 100644 --- a/README.md +++ b/README.md @@ -198,6 +198,7 @@ Everything will immediately show up in ImHex's Content Store and gets bundled wi | ZLIB | `application/zlib` | [`patterns/zlib.hexpat`](patterns/zlib.hexpat) | ZLIB compressed data format | | ZSTD | `application/zstd` | [`patterns/zstd.hexpat`](patterns/zstd.hexpat) | Zstandard compressed data format | | MOD | `3d-model/mod` | [`patterns/DMC3HD-Mod.hexpat`](patterns/dmc3_hd_mod.hexpat) | 3D Model files used in Devil May Cry 3 HD Collection | +| CBM BASIC | | [`commodore_basic.hexpat`](patterns/commodore_basic.hexpat) | Commodore BASIC | ### Scripts diff --git a/patterns/commodore_basic.hexpat b/patterns/commodore_basic.hexpat new file mode 100644 index 0000000..5f4cf02 --- /dev/null +++ b/patterns/commodore_basic.hexpat @@ -0,0 +1,158 @@ +#pragma description Commodore BASIC +#pragma author Stephen Hewitt + +import std.io; +import std.mem; + +bool in_quotes = false; + +le u16 LoadAddress @0 [[color("ff0000")]]; + +fn formatll(u16 offset) { + if (offset&0xff00 == 0) + return "No next line"; + u16 fo = offset-LoadAddress+2; + return std::format("Next line: ${:04X} (offset ${:04X})", offset, fo); +}; + +enum Token : u8 { + END = 0x80, + FOR = 0x81, + NEXT = 0x82, + DATA = 0x83, + INPUT_ = 0x84, + INPUT = 0x85, + DIM = 0x86, + READ = 0x87, + LET = 0x88, + GOTO = 0x89, + RUN = 0x8a, + IF = 0x8b, + RESTORE = 0x8c, + GOSUB = 0x8d, + RETURN = 0x8e, + REM = 0x8f, + STOP = 0x90, + ON = 0x91, + WAIT = 0x92, + LOAD = 0x93, + SAVE = 0x94, + VERIFY = 0x95, + DEF = 0x96, + POKE = 0x97, + PRINT_ = 0x98, + PRINT = 0x99, + CONT = 0x9a, + LIST = 0x9b, + CLR = 0x9c, + CMD = 0x9d, + SYS = 0x9e, + OPEN = 0x9f, + CLOSE = 0xa0, + GET = 0xa1, + NEW = 0xa2, + TAB_ = 0xa3, + TO = 0xa4, + FN = 0xa5, + SPC_ = 0xa6, + THEN = 0xa7, + NOT = 0xa8, + STEP = 0xa9, + PLUS_ = 0xaa, + MINUS_ = 0xab, + TIMES_ = 0xac, + DIVIDE_ = 0xad, + POW_ = 0xae, + AND = 0xaf, + OR = 0xb0, + GT_ = 0xb1, + EQ_ = 0xb2, + LT_ = 0xb3, + SGN = 0xb4, + INT = 0xb5, + ABS = 0xb6, + USR = 0xb7, + FRE = 0xb7, + POS = 0xb9, + SQR = 0xba, + RND = 0xbb, + LOG = 0xbc, + EXP = 0xbd, + COS = 0xbe, + SIN = 0xbf, + TAN = 0xc0, + ATN = 0xc1, + PEEK = 0xc2, + LEN = 0xc3, + STR_ = 0xc4, + VAL = 0xc5, + ASC = 0xc6, + CHR_ = 0xc7, + LEFT_ = 0xc8, + RIGHT_ = 0xc9, + MID_ = 0xca, + PI_ = 0xff +} [[format("formate")]]; + +// Can't seem to put attributes on enum members. Hack around it. +fn formate(Token t) { + match (t) { + (Token::INPUT_): return "INPUT#"; // $84 + (Token::PRINT_): return "PRINT#"; // $98 + (Token::TAB_): return "TAB("; // $a3 + (Token::SPC_): return "SPC("; // $a6 + (Token::PLUS_): return "+"; // $aa + (Token::MINUS_): return "-"; // $ab + (Token::TIMES_): return "*"; // $ac + (Token::DIVIDE_): return "/"; // $ad + //(Token::POW_): return "↑"; // $ae + (Token::GT_): return ">"; // $b1 + (Token::EQ_): return "="; // $b2 + (Token::LT_): return "<"; // $b3 + (Token::STR_): return "STR$"; // $c4 + (Token::CHR_): return "CHR$"; // $c7 + (Token::LEFT_): return "LEFT$"; // $c8 + (Token::RIGHT_): return "RIGHT$"; // $c9 + (Token::MID_): return "MID$"; // $ca + //(Token::PI_): return "π"; // $ff + } + + return t; +}; + +fn NotZero() { + u8 b = std::mem::read_unsigned($, 1); + return b!=0; +}; + +fn IsToken() { + u8 b = std::mem::read_unsigned($, 1); + return b&0x80!=0; +}; + +fn IsPETSCII() { + u8 b = std::mem::read_unsigned($, 1); + if (b == '"') + in_quotes = !in_quotes; + return (b!=0) && (in_quotes || (b&0x80)==0); +}; + +struct LineSegment +{ + Token tokens[while(IsToken())] [[color("a040a0")]]; + char petscii[while(IsPETSCII())] [[color("a0a0a0")]]; +}; + +struct Line +{ + in_quotes = false; + + u16 next [[color("8080ff"), format("formatll")]]; + if (next&0xff00 == 0) + break; + le u16 line_number [[color("00FF00")]]; + LineSegment contents[while(NotZero())]; + u8 eol [[color("00ffff")]]; +}; + +Line Lines[while(!std::mem::eof())] @ 2; \ No newline at end of file diff --git a/tests/patterns/test_data/commodore_basic.hexpat.prg b/tests/patterns/test_data/commodore_basic.hexpat.prg new file mode 100644 index 0000000000000000000000000000000000000000..9ad2826a250274c935eaef197f30c30dbdb4395d GIT binary patch literal 6702 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 literal 0 HcmV?d00001