Created
March 5, 2026 18:10
-
-
Save leiradel/dfa70ca201db7119ba891f6d7a97b2e5 to your computer and use it in GitHub Desktop.
A small function that creates a listing of a ZX Spectrum BASIC program
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // Original code by Mike Daley | |
| // License: MIT | |
| std::string listbasic(const Memory& mem, uint64_t offset) { | |
| uint64_t size = mem.size(); | |
| std::string listing; | |
| while (offset + 4 <= size) { | |
| uint16_t const lineNumber = mem.peekU16BE(offset); | |
| uint16_t const lineLength = mem.peekU16LE(offset + 2); | |
| if (lineNumber > 9999 || lineLength == 0) { | |
| break; | |
| } | |
| uint64_t const bodyStart = offset + 4; | |
| uint64_t const lineEnd = bodyStart + lineLength; | |
| if (lineEnd > size) { | |
| break; | |
| } | |
| std::string text; | |
| uint64_t pos = bodyStart; | |
| while (pos < lineEnd) { | |
| uint8_t const byte = mem.peek(pos); | |
| if (byte == 0x0d) { | |
| break; | |
| } | |
| // Number marker: skip 0x0e + 5-byte floating point | |
| if (byte == 0x0e) { | |
| pos += 6; | |
| continue; | |
| } | |
| // Colour control codes (INK..OVER): 1 param byte | |
| if (byte >= 0x10 && byte <= 0x15) { | |
| pos += 2; | |
| continue; | |
| } | |
| // AT/TAB control: 2 param bytes | |
| if (byte >= 0x16 && byte <= 0x17) { | |
| pos += 3; | |
| continue; | |
| } | |
| // Token (0xa5-0xff) | |
| if (byte >= 0xa5) { | |
| const char* keyword = tokenToKeyword(byte); | |
| if (keyword != nullptr) { | |
| if (!text.empty() && text.back() != ' ') { | |
| text += ' '; | |
| } | |
| text += keyword; | |
| size_t const kwLen = std::strlen(keyword); | |
| char last = keyword[kwLen - 1]; | |
| if ((last >= 'A' && last <= 'Z') || last == '$' || last == '#') { | |
| text += ' '; | |
| } | |
| } | |
| pos++; | |
| continue; | |
| } | |
| // Printable ASCII | |
| if (byte >= 0x20 && byte < 0x80) { | |
| text += (char)byte; | |
| pos++; | |
| continue; | |
| } | |
| // Skip other control codes | |
| pos++; | |
| } | |
| // Trim leading/trailing spaces | |
| size_t start = text.find_first_not_of(' '); | |
| size_t end = text.find_last_not_of(' '); | |
| listing += std::to_string(lineNumber); | |
| listing += ' '; | |
| if (start != std::string::npos) { | |
| listing.append(text, start, end - start + 1); | |
| } | |
| listing += '\n'; | |
| offset = lineEnd; | |
| } | |
| return listing; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment