{"id":18497340,"url":"https://github.com/kbilsted/commodorebasicreformatter","last_synced_at":"2025-07-19T08:09:09.231Z","repository":{"id":69160123,"uuid":"197565291","full_name":"kbilsted/CommodoreBasicReformatter","owner":"kbilsted","description":"Reformat and enhance with explanations, Commodore BASIC programs to make them more readable","archived":false,"fork":false,"pushed_at":"2019-08-08T20:05:13.000Z","size":124,"stargazers_count":4,"open_issues_count":1,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-05-14T05:20:32.395Z","etag":null,"topics":["basic","c64","commodore-64","commodore-basic","dotnet"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kbilsted.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2019-07-18T10:25:42.000Z","updated_at":"2022-10-03T21:07:05.000Z","dependencies_parsed_at":"2023-03-11T05:24:07.776Z","dependency_job_id":null,"html_url":"https://github.com/kbilsted/CommodoreBasicReformatter","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/kbilsted/CommodoreBasicReformatter","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kbilsted%2FCommodoreBasicReformatter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kbilsted%2FCommodoreBasicReformatter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kbilsted%2FCommodoreBasicReformatter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kbilsted%2FCommodoreBasicReformatter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kbilsted","download_url":"https://codeload.github.com/kbilsted/CommodoreBasicReformatter/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kbilsted%2FCommodoreBasicReformatter/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265904329,"owners_count":23846675,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["basic","c64","commodore-64","commodore-basic","dotnet"],"created_at":"2024-11-06T13:34:14.708Z","updated_at":"2025-07-19T08:09:09.223Z","avatar_url":"https://github.com/kbilsted.png","language":"C#","readme":"﻿# Reformat and augment BASIC for improved readability\r\n\r\nThis tool makes Commodore BASIC programs more readable! It supports a variety of strategies for achieving this. It adds whitespace, it breaks multiple statements into several lines and finally, it\r\nexplains character codes and memory locations used in the code. The later is of particular importance. Unlike modern programming, accesing specific memory addresses in Commodore BASIC is used \r\nfor playing sounds, controlling the keyboard buffer size or perhaps most famously, changing the background and border colors. \r\n\r\n![c64 basic](c64.png)\r\n\r\n\r\n\r\n\r\n## 1. Usage\r\n\r\n    CommodoreBasicReformatter [--split-lines] [--add-explanations] \u003cinfile\u003e \u003coutfile\u003e\r\n\r\n\r\n## 2. Example\r\n\r\nAn example code from the fun game \"Raging robots\" found at http://www.gb64.com/game.php?id=21265\r\n\r\n```\r\n250 vl=54296:ad=54277:p1=54273:p3=54287:wf=54276\r\n260 qa=198:qb=214:sc=1024:cs=55296:pokeqa,0:z$=\"\"\"\"\r\n270 rt=ti:wait qa,1:getz$:pokeqa,0:rq=ti-rt\r\n280 rr=rq*rnd(0):dim r(nr),p(nr):r=nr\r\n290 print\"\".\"\":fori=1to80:pokevl,5:pokevl,0\r\n```\r\n\r\nThe code is so dense. If we reformat it with our tool, it becomes\r\n\r\n```\r\n250 vl = 54296 : ad = 54277 : p1 = 54273 : p3 = 54287 : wf = 54276\r\n260 qa = 198 : qb = 214 : sc = 1024 : cs = 55296 : poke qa,0 : z$ = \"\"\"\"\r\n270 rt = ti : wait qa,1 : get z$ : poke qa,0 : rq = ti-rt\r\n280 rr = rq*rnd(0) : dim r(nr),p(nr) : r = nr\r\n290 print \"\".\"\" : for i = 1 to 80 : poke vl,5 : poke vl,0\r\n```\r\n\r\nwhich is much nicer to the eye.\r\n\r\n\r\n### 2.1. The `--split-lines` argument \r\n But we can improve readability even more by using the `--split-lines` flag. Then the code becomes\r\n\r\n```\r\n250 vl = 54296\r\n251 ad = 54277\r\n252 p1 = 54273\r\n253 p3 = 54287\r\n254 wf = 54276\r\n260 qa = 198\r\n261 qb = 214\r\n262 sc = 1024\r\n263 cs = 55296\r\n264 poke qa,0\r\n265 z$ = \"\"\"\"\r\n270 rt = ti\r\n271 wait qa,1\r\n272 get z$\r\n273 poke qa,0\r\n274 rq = ti-rt\r\n280 rr = rq*rnd(0)\r\n281 dim r(nr),p(nr)\r\n282 r = nr\r\n290 print \"\".\"\"\r\n291 for i = 1 to 80\r\n292 poke vl,5\r\n293 poke vl,0\r\n```\r\n\r\nNot all lines are split, however. Then-blocks are excluded as it would change the semantics if the code. For example, the line:\r\n\r\n```\r\n390 da=asc(d$) :ifda=145thendp=-40:goto480\r\n```\r\nbecomes\r\n\r\n```\r\n390 da = asc(d$)\r\n391 if da = 145 then dp =-40 : goto 480\r\n```\r\n\r\n### 2.2. The `--add-explanations` argument\r\n\r\nThe tool makes semantic analysis of the code and suggest explanations as comments. The analysis covers\r\n\r\n  * Known memory location usage\r\n  * Known `chr$` codes.\r\n\r\nWe explain variables and constants that we can conclude are used as memory locations through a simple analysis.\r\nLet's try adding explainations to this very nice 6-line smooth screen scroller written in basic.\r\n\r\n```\r\n10 print chr$(147) : poke53280,6:poke53281,0\r\n20 for l=1024 to 2023:poke l,219:next l\r\n30 for l=0 to 7\r\n40 poke 53265, (peek(53265) and 240) or 7-l : poke 53270,l\r\n50 next l\r\n60 goto 30\r\n```\r\n\r\nYou can see it in execution on https://youtu.be/JzPEfHufyfg?t=93 The original code is a bit cryptic and the author of the video goes into some details as to explaining each line:\r\nBut our tool can do some explaning of its own! \r\n\r\nTake a look at the code when we enhance it with explanations:\r\n\r\n```\r\n10 rem 53280=Border color\r\n10 rem 53281=Background color\r\n10 rem 147=Clears screen of any text, and causes the next character to be printed at the upper left-hand corner of the text screen.\r\n10 print chr$(147) : poke 53280,6 : poke 53281,0\r\n20 rem 1024=Default first area of screen memory (upper left corner)\r\n20 rem 2023=Default last area of screen memory(lower right corner)\r\n20 for l = 1024 to 2023 : poke l,219 : next l\r\n30 for l = 0 to 7\r\n40 rem 53265=Screen control register #1 (e.g. for YSCROLL or setting gfx mode)\r\n40 rem 53270=Screen control register #2 (e.g. for XSCROLL or setting gfx mode))\r\n40 poke 53265,(peek(53265)and 240)or 7-l : poke 53270,l\r\n50 next l\r\n60 goto 30\r\n```\r\n\r\nThe line duplication is intentional. It allows you to keep the explanations you like simply by changing their line numbers. Otherwise\r\nthey get overwritten by the actual code that produced the explanation.\r\n\r\n\r\n## 3. How it works\r\n\r\nWe do light-weigh tokenization of the following sets of characters\r\n\r\n\r\nWe've made a simple parser using the following grammar\r\n    \r\n\r\n     KEYWORD ::= 'to' | 'then' | 'end' | 'for' | 'next' | 'data' | 'dim' | 'read' | 'let' | 'goto' | ...\r\n     SYMBOL  ::= ',' | '+' | '-' | '*' | '/' | '(' | ')' | '=' | '\u003c' | '\u003e' | '\u003c\u003e' | ';' | '#'\r\n     STRING  ::= 'a'..'z' ( 'a'..'z' | '0'..'9' | '%' | '$' )*\r\n     DIGIT   ::= ( '0'..'9' )+\r\n     NEWLINE ::= '\\n'\r\n     COLON   ::= ':'\r\n\r\n\r\nWe then parse a file as a stream of tokens. The tokens has to obey the following simple grammar\r\n\r\n     PROGRAM ::= ( NEWLINE | LINE )*\r\n     LINE    ::= DIGIT STMTS NEWLINE\r\n     STMTS   ::= STMT ( COLON STMT )* \r\n     STMT    ::= ( KEYWORD | DIGIT | STRING | SYMBOL )+\r\n\r\nOn top of this we apply the various analysis and content modification before outputting the result.\r\n\r\n\r\n\r\n\r\n## 4. Working with tape and disc files\r\n\r\nC64 BASIC listings are easy to get hold of from the internet. Usually they come in the form of tape or disc images - thus not being readily readable. \r\nThe VICE emulator (http://vice-emu.sourceforge.net/) comes with two essential tools `c1541.exe` and `petcat.exe` which are needed in order to read the BASIC code listings on\r\nmore modern operating systems.\r\n\r\n\r\n### 4.1. How to extract and reformat T64 files \r\n\r\nBefore reformatting tape files, you need to convert the tape file to a disc image, then extract to the local file system, and then run `petcat` on it.\r\n\r\nAn example with a T64 file named `RAGINGRO.T64` containing the BASIC file `raging robots`\r\n\r\n    .\\c1541.exe -format diskname,id d64 my_diskimage.d64 -attach my_diskimage.d64\r\n    .\\c1541.exe -attach my_diskimage.d64 -tape RAGINGRO.T64\r\n    .\\c1541.exe -attach my_diskimage.d64 -extract\r\n    .\\petcat.exe -o rr.ascii \"raging robots\"\r\n    dotnet CommodoreBasicReformatter.dll \".\\rr.ascii\" rr2.ascii\r\n\r\nto make an executable of the re-formatted program run\r\n\r\n    .\\petcat.exe -w2 -l 0x0801 -o rr2.prg rr2.ascii\r\n\r\nthen watch it run in VICE \r\n\r\n\tx64.exe rr2.prg\r\n\r\n\r\n### 4.2. How to extract and reformat D64 files \r\n\r\nBefore reformatting disc files, you need to extract to the local file system, and then run `petcat` on it.\r\n\r\nAn example with a D64 file named `YADA.D64` containing the BASIC file `DD.PRG`\r\n\r\n    .\\c1541.exe -attach YADA.D64 -extract\r\n    .\\petcat.exe -o dd.ascii \"dd\"\r\n    dotnet CommodoreBasicReformatter.dll \".\\dd.ascii\" dd2.ascii\r\n\r\nto make an executable of the re-formatted program run\r\n\r\n    .\\petcat.exe -w2 -l 0x0801 -o dd.prg dd2.ascii\r\n\r\nthen watch it run in VICE \r\n\r\n\tx64.exe dd2.prg\r\n\r\n\r\n## 5. Supported platforms\r\n\r\nThe code is written in .Net core so it should run on Windows, Linux, MAC OS\r\n\r\nDownload a binary release from https://github.com/kbilsted/CommodoreBasicReformatter/releases/ or build the source code.\r\n\r\nIf you cannot find a runtime for your Linux distribution, the tool works fine through Wine.\r\n\r\n\r\n## 6. Have fun\r\n\r\nKasper Graversern\r\n\r\nhttp://firstclassthoughts.co.uk/\r\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkbilsted%2Fcommodorebasicreformatter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkbilsted%2Fcommodorebasicreformatter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkbilsted%2Fcommodorebasicreformatter/lists"}