{"id":20418872,"url":"https://github.com/sehugg/vintagebasic","last_synced_at":"2026-02-06T16:33:01.816Z","repository":{"id":139692247,"uuid":"387554462","full_name":"sehugg/vintagebasic","owner":"sehugg","description":"Multi-dialect vintage BASIC interpreter (from 8bitworkshop.com)","archived":false,"fork":false,"pushed_at":"2025-08-07T22:16:25.000Z","size":600,"stargazers_count":3,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-08-08T00:18:26.770Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"BASIC","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sehugg.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}},"created_at":"2021-07-19T18:08:47.000Z","updated_at":"2025-08-07T22:16:29.000Z","dependencies_parsed_at":null,"dependency_job_id":"e4fe6f28-059d-40cc-aed0-b91a952d7c8d","html_url":"https://github.com/sehugg/vintagebasic","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/sehugg/vintagebasic","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sehugg%2Fvintagebasic","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sehugg%2Fvintagebasic/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sehugg%2Fvintagebasic/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sehugg%2Fvintagebasic/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sehugg","download_url":"https://codeload.github.com/sehugg/vintagebasic/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sehugg%2Fvintagebasic/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29168507,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-06T15:38:29.831Z","status":"ssl_error","status_checked_at":"2026-02-06T15:37:48.592Z","response_time":59,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":[],"created_at":"2024-11-15T06:35:07.006Z","updated_at":"2026-02-06T16:33:01.783Z","avatar_url":"https://github.com/sehugg.png","language":"BASIC","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Vintage BASIC\n\n[Try it online at 8bitworkshop.com](https://8bitworkshop.com/redir.html?platform=basic)\n\n## Usage\n\n~~~sh\nnpm run build\nnode gen/basic/run.js test/presets/hello.bas \n~~~\n\n## Test Suite, Fuzzer\n\n~~~sh\nnpm run test\nnpm run fuzzbasic\n~~~\n\n## Example\n\n~~~basic\nOPTION DIALECT DARTMOUTH\n10 PRINT \"HELLO! LET'S PROGRAM IN BASIC.\"\n20 INPUT \"WOULD YOU MIND TYPING IN YOUR NAME\";A$\n30 PRINT \"THANKS, \";A$;\"! THIS WILL BE FUN!\"\n40 INPUT \"NOW TELL ME YOUR FAVORITE NUMBER\";N\n50 LET B=N^2\n60 PRINT \"THAT'S A GOOD ONE! I LIKE\";B;\"MYSELF.\"\n70 PRINT \"NICE MEETING YOU, \";A$;\".\"\n999 END\n~~~\n\nNote the OPTION DIALECT line at the beginning of the file.  This is a\nnon-standard BASIC construct that tells the compiler to recognize a specific\nvariant of BASIC.  This affects syntax, allowable keywords and functions,\nand print formatting.  Older dialects will limit the editor to uppercase\ncharacters.\n\n# BASIC Interpreter\n\n## Dialects\n\nThe 8bitworkshop IDE supports several flavors of BASIC.\nThe BASIC dialect can be selected with the `OPTION DIALECT` statement,\nwhich should be the first line in your program.\nThere are several dialects supported:\n\nDARTMOUTH, DARTMOUTH4\n: BASIC 4th Edition or \"the Fourth\" (1968) ran on the\n  [Dartmouth BASIC Time Sharing System](https://en.wikipedia.org/wiki/Dartmouth_Time_Sharing_System).\n  It's the ancestor of most of the other BASICs in this list.\n  We support everything except the `MAT` (matrix math) statements and multiline function definitions.\n\nDECPLUS, BASICPLUS\n: DEC BASIC-PLUS (1972).\n  This was an extended riff on Dartmouth BASIC written for PDP-11 systems running RSTS/E.\n  We support the `GOTO` *expr* `OF` *line, line...* syntax, but not the other extended flow control directives like `PRINT I IF I \u003e 10`.\n  There are some other quirks not supported, like the \"`\u0026`\" symbol substituted for a `PRINT` statement,\n  and the `PRINT USING` statement (used for numeric formatting).\n\nTINY\n: Tiny BASIC (1975) was a stripped-down integer-only interpreted BASIC (though we allow floats in our interpretation).\n  It was designed as a [freely-available implementation](https://en.wikipedia.org/wiki/Tiny_BASIC)\n  in response to Bill Gates' \"[Open Letter To Hobbyists](https://en.wikipedia.org/wiki/Open_Letter_to_Hobbyists),\" and led to the coining of the term \"copyleft\".\n  The first version was published in the [PCC (People's Computer Company) newsletter](https://archive.computerhistory.org/resources/access/text/2017/09/102661095/102661095-05-v4-n2-acc.pdf),\n  which spun off a new periodical to publish source code -- Dr. Dobb's Journal.\n  To make reimplementation easier, the parser was written in a bytecode language called [IL](https://en.wikipedia.org/wiki/Tiny_BASIC#Implementation_in_a_virtual_machine).\n\nHP, HPTSB, HP2000\n: HP Time-Shared BASIC (1976).\n  The games in *[What To Do After You Hit Return](https://archive.org/details/Whattodoafteryouhitreturn)*\n  were written in this dialect, which supports a unique array-slice syntax for strings.\n  Many BASIC games were ported to this dialect, including a popular\n  [cross-country pioneer simulation](https://www.filfre.net/2011/04/on-the-trail-of-the-oregon-trail-part-4/).\n\nALTAIR41, ALTAIR\n: MITS Altair 8800 BASIC 4.1 (1977), Microsoft's first product.\n  [David Ahl](http://www.vintage-basic.net/games.html) liked this one, so many classic games should work with it.\n\nBASIC80\n: Microsoft's BASIC-80 (1977) for Z80 and 8080 CPUs.\n  It ran on CP/M and later became TRS-80 Level III BASIC.\n  This introduced the `WHILE ... WEND` syntax which persisted all the way to Visual BASIC.\n\nECMA55, MINIMAL\n: Minimal BASIC (1978) was an attempt to define an interoperable BASIC standard.\n  Microsoft BASICs were becoming the de-facto standard, so it was ultimately withdrawn,\n  although the ANSI standard remains.\n  It is very similar to Dartmouth BASIC 4th edition, except without the CHANGE command,\n  assignment chaining, and tick (') comments.\n  \nMODERN\n: A fictional BASIC which pulls out all of the stops, which is to say it doesn't explicitly disallow anything without a good reason.\n  Some things are disallowed, like using a variable before assignment, or using an array before dimensioning.\n  Labels are supported, and line numbers are optional.\n  Block IF/THEN/ELSE is supported, as are subroutines with SUB/CALL.\n\n\n## Examples\n\nThe [8bitworkshop IDE](https://8bitworkshop.com/redir.html?platform=basic)\nincludes many examples of classic BASIC programs.\nSome of these are historically relevant and reproduced from the original source code.\n\n[Hello World](https://8bitworkshop.com/redir.html?platform=basic\u0026file=hello.bas)\n: This is a simple \"conversational program\" which simulates a short dialogue\n  between human and computer.\n  At the time, this type of program was a disarming introduction to computers for those who have never seen one.\n  It demonstrates the `PRINT` and `INPUT` commands, string variables, and the `^` exponentiation operator.\n\n[Lander](https://8bitworkshop.com/redir.html?platform=basic\u0026file=lander.bas)\n: A lunar (or Earth) powered descent simulator, originally written in DEC's FOCAL language by a high-school student in 1969.\n  He submitted it to DEC's newsletter where the editor David H. Ahl translated it into BASIC.\n  (Benj Edwards wrote up a [great article](https://www.technologizer.com/2009/07/19/lunar-lander/) about it.)\n  At each time step, the player enters a quantity of fuel to burn, and downward velocity slows proportionally.\n  The goal is to reach near-zero velocity at the surface without running out of fuel.\n \n[Hammurabi](https://8bitworkshop.com/redir.html?platform=basic\u0026file=hamurabi.bas)\n: Another early David Ahl conversion, from FOCAL program to the EduSystem 70 (PDP-8)\n  and later to Microsoft BASIC.\n  This version was found at [Pete Turnbull's web site](http://www.dunnington.info/public/basicgames/).\n\n[23 Matches](https://8bitworkshop.com/redir.html?platform=basic\u0026file=23match.bas)\n: A simple [Nim-like](https://en.wikipedia.org/wiki/Nim) game, where the last player to take an object loses, and the computer plays perfectly.\n  David Ahl's version added computer trash-talking, with insults like \"meatball-nose\" and \"floppy ears.\"\n  Our version from the 1973 DEC EduSystem Handbook is more polite.\n\n[Hunt the Wumpus](https://8bitworkshop.com/redir.html?platform=basic\u0026file=wumpus.bas)\n: The classic (only?) dodecahedronal hunting game, written by Gregory Yob in 1973\n  as a response to the many two-dimensional games like Mugwump.\n  This is a version from [HP library tapes](http://www.dunnington.info/public/basicgames/).\n  It implores: `IF YOU DON'T KNOW WHAT A DODECAHEDRON IS, ASK SOMEONE`.\n\n[Craps](https://8bitworkshop.com/redir.html?platform=basic\u0026file=craps.bas)\n: A gambling simulator adapted for \"GTE Sylvania 1974 Family Day\" found on a [tape backup](http://www.bitsavers.org/bits/HP/paperTapes/JeffM/).\n  This must have been part of a demonstration where families were present, since `NO PROFANITY!` is requested.\n  One wonders what the non-censored version of the program was like.\n  \n[Star Trader](https://8bitworkshop.com/redir.html?platform=basic\u0026file=startrader.bas)\n: Dave Kaufman's 1974 multiplayer space trading game, which (along with [another text-based space game](http://www.dunnington.info/public/startrek/index.html))\n  inspired a genre that now includes *Elite*, *Trade Wars* and *Eve Online*.\n  The game was so big that it had to be split into multiple files, linked with the `CHAIN` command.\n  Our BASIC interpreter doesn't support that, so we renumbered and combined everything into a single file,\n  and made a few other changes since we don't support `PRINT USING` either.\n  This game was published in the People's Computing Company's newsletter and in their 1975 compendium\n  *[What To Do After You Hit Return](https://archive.org/details/Whattodoafteryouhitreturn)*.\n\n[Interest Calculator](https://8bitworkshop.com/redir.html?platform=basic\u0026file=mortgage.bas)\n: A simple HP BASIC program from 1977 that computes interest payments.\n  Soon, VisiCalc and other spreadsheet software would largely replace BASIC programming for these kinds of tasks.\n  \n[Haunted House](https://8bitworkshop.com/redir.html?platform=basic\u0026file=haunted.bas)\n: A silly and spooky adventure game from 1979, found on an old DEC tape backup.\n\n[Sieve Benchmark](https://8bitworkshop.com/redir.html?platform=basic\u0026file=sieve.bas)\n: This is an implementation of the [Byte Sieve](https://en.wikipedia.org/wiki/Byte_Sieve),\n  a popular Sieve of Eratosthenes benchmark published in a 1981 issue of BYTE magazine.\n  Our implementation uses the `OPTION CPUSPEED MAX` command to run much faster than the\n  interpreter's default of 1,000 statements per second.\n  Initial cocktail napkin simulations show that we run at about 30% the speed of [John Ham's Minimal BASIC to x86 Compiler](https://buraphakit.sourceforge.io/BASIC.shtml).\n\n\n\n\n\n## Statements\n\n`CHANGE`\n: Convert a string to an array of character codes, or vice-versa.\n  Not available in all dialects.\n\n`CLEAR`\n: Clears all variables, arrays, and function definitions.\n\n`DATA` datum, datum...\n: Creates data elements to be read back serially by READ.\n  Elements are separated by commas, and can be numeric, or quoted or unquoted strings.\n  (Compatibility issue: Whitespace is not trimmed on unquoted strings.)\n\n`DEF FN`a`(`arg, arg...`)` = definition\n: Defines a function with zero or more arguments.\n  The function name must start with `FN`.\n  The function body cannot call itself, although the compiler doesn't check to see if functions call each other recursively.\n\n`DIM` varname `(` dim1, dim2... `)`\n:  Reserves space for arrays.\n   Unless declared otherwise, all array subscripts shall have a\n   lower bound of zero and an upper bound of ten. Thus the default\n   space allocation reserves space for 11 elements in one-dimensional arrays and 121 elements in two-dimensional arrays.\n   In HP dialect, strings are allocated using the `DIM` statement.\n\n`END`\n:  Terminates the program.\n   In MINIMAL and HP dialects, an `END` must be the final statement in the program.\n\n`FOR` varname `=` initial `TO` final `STEP` step\n: Declares a FOR loop, terminated by a NEXT statement.\n  The numeric variable *varname* is set to *initial* before the first loop iteration. \n  After each iteration, the variable is incremented by *step* (which can be negative) and then checked against *final*.\n  The loop is repeated until the value is equal to or goes beyond the final value.\n  In some dialects, this check is done before the first iteration, and so zero iterations are possible.\n\n`NEXT` varname, varname...\n: Ends a FOR loop. In some dialects, *varname* is optional, and multiple variables can be specified.\n\n`GOTO` label\n: Transfers control of the program to a specified line number or label.\n  In some dialects, this can be a computed value.\n\n`GOSUB` label ... `RETURN`\n: Like `GOTO`, but pushes the program counter onto a return stack.\n  `RETURN` pops the topmost value off this stack and resumes execution.\n\n`IF` condition [ `THEN` statement | `GOTO` label ] `ELSE` statement\n: If *condition* is non-zero, execute the statements after THEN,\n  or transfer control to the label after the GOTO.\n  In some dialects, ELSE can be specified, which binds to the rightmost THEN.\n\n`INPUT` prompt? `,` ref `,` ref ...\n: Pauses and accepts input from the keyboard.\n  A quoted string *prompt* can be present.\n  In any case, a \"?\" is printed before pausing for input.\n  Each *ref* can be a simple variable or array element, numeric or string.\n  If multiple values are specified, they are separated by commas before being accepted.\n\n`LET` ref `=` expression\n: Assigns a computed expression to a variable, which can be a simple variable or array reference.\n  The `LET` can be ommitted in most dialects.\n  In HP dialect, the left side can be an array slice for strings.\n\n`ON` index [ `GOTO` | `GOSUB` ] label1, label2 ...\n: Computes *index* and uses it to select one or more labels to GOTO or GOSUB.\n  The value 1 specifies the first label, 2 the second, etc.\n  Some dialects silently ignore out-of-bounds values.\n\n`OPTION BASE` [ 0 | 1 ]\n: Selects whether arrays start at 0 or 1.\n  The DIM statement specifies the highest valid index regardless of this setting.\n\n`OPTION DIALECT` identifier\n: Selects a BASIC dialect to use for parsing and running the program.\n\n`OPTION CPUSPEED` [ number | `MAX` ]\n: Sets the simulated BASIC interpreter speed in statements per second, or MAX for maximum speed.\n\n`OPTION` name value\n: Set other dialect options -- see the [table](#dialectfeaturematrix) below.\n  For example, `OPTION UPPERCASEONLY 0` enables lowercase on mainframe dialects.\n\n`PRINT` expression [ `,` | `;` ] [ expression ... ]\n: Prints to the output.\n  Each expression can be numeric or string.\n  If numeric, most dialects put whitespace before and after the value, or a minus sign before.\n  A comma separates expressions by tab groups, defined by the dialect, and usually 14-16 characters long.\n  A semicolon places no extra whitespace between expressions.\n  A new line is generated after the PRINT statement unless it ends with a comma or semicolon.\n\n`RANDOMIZE`\n: Initialize the `RANDOM` number generator with a random seed.\n  The `RND` function returns a predictable sequence of numbers until this statement is executed.\n  This is consistent with the ECMA-55 standard.\n\n`READ` ref `,` ref ...\n: Reads data serially from DATA statements in the program.\n\n`RESTORE` label\n: Resets the data pointer used by READ to the first DATA statement.\n  Some dialects allow a label to be specified.\n\n`STOP`\n: Halts the program.\n\n`WHILE` condition ... `WEND`\n: Executes a loop as long as *condition* is non-zero.\n  Only in BASIC80 and MODERN dialects.\n\n\n## Numeric Functions\n\n`ABS(X)`\n: The absolute value of X, i.e., if X \u003c 0 then return -X.\n\n`ATN(X)`\n:                The arctangent of X in radians, i.e., the angle\n                 whose tangent is X. The range of the function\n                 is\n                        `-(pi/2) \u003c ATN(X) \u003c (pi/2)`\n\n`COS(X)`\n:                 The cosine of X, where X is in radians.\n\n`EXP(X)`\n:                 The exponential of X, i.e., the value of the\n                  base of natural logarithms (e = 2,71828...)\n                  raised to the power X.\n\n`INT(X)`\n:                 The largest integer not greater than X; e.g.\n                  `INT(1.3)` = 1 and `INT(-1.3)` = -2.\n\n`LOG(X)`\n:                 The natural logarithm of X; X must be greater\n                  than zero.\n\n`RND`\n:                 The next pseudo-random  number in an\n                  implementation-supplied sequence of pseudo-random\n                  numbers uniformly distributed in the range \n                  0 \u003c= `RND` \u003c 1.\n\n`SGN(X)`\n:                 The sign of X: -1 if X \u003c 0, 0 if X = 0 and\n                  +1 if X \u003e 0.\n\n`SIN(X)`\n:                 The sine of X, where X is in radians.\n\n`SQR(X)`\n:                 The nonnegative square root of X; X must be\n                  nonnegative.\n\n`TAN(X)`\n:                 The tangent of X, where X  is in radians.\n\n`FIX(` num `)`\n: Returns the integer part of the *num* argument, rounding up to zero if negative or down to zero if positive.\n\n`INT(` num `)`\n: Rounds down to an integer (floor).\n\n`RND`\n: Returns a random number.\n  The sequence is repeatable unless RANDOMIZE has been executed.\n\n`ROUND(` num `)`\n: Rounds to the nearest integer.\n\n\n## String Functions\n\n`ASC(` string `)`\n: Returns the character code of the leftmost character of *string*.\n\n`CHR$(` num `)`\n: Converts a character code to a single-character string.\n  Try 9 (tab), 10 (line feed), 12 (form feed) and 7 (bell).\n\n`HEX$(` num `)`\n: Converts a number to its hexidecimal notation.\n\n`INSTR(` needle `,` haystack `)`\n: Returns the position of substring *needle* in the string *haystack*, or 0 if not found.\n\n`INSTR(` index `,` needle `,` haystack `)`\n: Returns the position of substring *needle* in the string *haystack* starting at *index*, or 0 if not found.\n\n`LEFT$(` string `,` count `)`\n: Returns the leftmost *count* characters of a string.\n\n`LEN(` string `)`\n: Returns the length of a string.\n\n`LIN(` count `)`\n: Returns *count* line feeds for use in PRINT statements.\n\n`MID$(` string `,` index `,` count `)`\n: Returns *count* characters from *string*, starting at character *index* (1 is the leftmost character).\n\n`OCT$(` num `)`\n: Converts a number to its octal representation.\n\n`POS`\n: Returns the current column position of the printed output.\n\n`RIGHT$(` string `,` count `)`\n: Returns the rightmost *count* characters of a string.\n\n`SPC(` count `)`\n: Returns a string of *count* space characters, for use in PRINT statements.\n\n`SPACE$(` count `)`\n: Returns a string of *count* space characters.\n\n`STR$(` num `)`\n: Converts *num* to its string representation.\n\n`STRING$(` count `,` char `)`\n: Returns a string of *count* repetitions of *char*, which can be either a numeric character code or another string.\n\n`TAB(` column `)`\n: Returns the number of spaces neccessary to advance to a given column, or an empty string if already past the desired column.\n  For use in PRINT statements.\n\n`TIMER`\n: Returns the number of seconds since a reference time.\n\n`UPS$(` string `)`\n: Converts *string* to uppercase.\n\n`VAL(` string `)`\n: Converts a string value to a numeric.\n\n\n## Compatibility\n\nThe IDE's BASIC compiler doesn't emulate each dialect exactly.\nHowever, there is a rich tradition in BASIC of porting programs from one dialect to another,\nso for maximum verisimilitude you should try it yourself.\nHere are some of the issues that might pop up:\n\n`MAT` keyword and matrix operations\n: Not supported.\n  A lot of games only use this feature to read in arrays of data, which can be easily done with loops.\n\n`CHAIN`\n: For BASIC programs too big to fit into memory, this was a primitive way to pass variables between them (with the `COM` declaration).\n  Instead, you can renumber and merge the files by hand.\n\n`PRINT USING` and `IMAGE`\n: Dartmouth BASIC Sixth Edition introduced powerful numeric formatting features similar to that of FORTRAN.\n  However, this is not implemented.\n  You can use the `NFORMAT$` and string functions as a substitute.\n\n`ENTER`\n: On HP BASIC, the `ENTER` statement doesn't time out, or allow a `#` port variable.\n  But it does return how fast it took for you to type.\n\n`CONVERT`\n: The HP BASIC `CONVERT` command can't assign to array slices.\n\n`ON ERROR GOTO`\n: Error trapping is not supported.\n\n`THEN` clauses\n: All BASICs support the `IF` *condition* `THEN` *statement* syntax,\n  even though early BASICs only supported a `GOTO` line number.\n\n`PRINT` separators\n: If there is no delimiter between items, \";\" is assumed.\n  \nNo integer types\n: Only floating point and string types (`A$`) are supported, just like in JavaScript.\n  Integer (`I%`) types are not supported.\n\nRelational operators anywhere\n: Many BASICs only let you use relational operators in an IF statement.\n  We allow them anywhere, and return a logical value of 0 for false and 1 for true --\n  or -1 for true when bitwise logic operators are supported.\n\nNo file support\n: Can't open, read, write files.\n\nError messages\n: Our error messages may be at times better or worse than actual vintage BASIC systems.\n  They are certainly more verbose overall.\n\nOut-of-order line numbers\n: If line 200 comes before line 100 in the file, line 200 will be executed first.\n  No error will be given for out-of-order line numbers.\n  You also can't jump to a line number that doesn't exist, like in some interpreted BASICs.\n\nMultiple-line function definitions\n: Dartmouth BASIC 4th Edition supported complex multiline functions with a `DEF ... FNEND` block.\n  We only support simple mathematical functions.\n\nEmbedded character codes\n: Strings in HP BASIC do not support embedded character codes like `\"RING\"'7\"RING\"`.\n\n\n## Dialect Feature Matrix\n\ndialectName                   |TINY     |ECMA55   |DARTMOUTH|HP2000   |DECPLUS  |ALTAIR41 |BASIC80  |MODERN   \n------------------------------|---------|---------|---------|---------|---------|---------|---------|--------\nasciiOnly                     |Y        |Y        |Y        |Y        |Y        |Y        |Y        |-        \nuppercaseOnly                 |Y        |Y        |Y        |Y        |-        |Y        |-        |-        \noptionalLabels                |-        |-        |-        |-        |-        |-        |-        |Y        \noptionalWhitespace            |-        |-        |-        |-        |-        |Y        |Y        |-        \nmultipleStmtsPerLine          |-        |-        |-        |Y        |Y        |Y        |Y        |Y        \nvarNaming                     |A        |A1       |A1       |A1       |A1       |*        |*        |*        \nstaticArrays                  |-        |Y        |Y        |Y        |Y        |-        |-        |-        \nsharedArrayNamespace          |Y        |Y        |-        |-        |-        |Y        |Y        |-        \ndefaultArrayBase              |0        |0        |0        |1        |0        |0        |0        |0        \ndefaultArraySize              |0        |11       |11       |11       |11       |11       |11       |0        \ndefaultValues                 |Y        |-        |-        |-        |Y        |Y        |Y        |-        \nstringConcat                  |-        |-        |-        |-        |Y        |Y        |Y        |Y        \nmaxDimensions                 |0        |2        |2        |2        |2        |128      |255      |255      \nmaxDefArgs                    |255      |255      |255      |255      |255      |255      |255      |255      \nmaxStringLength               |255      |255      |255      |255      |255      |255      |255      |2048     \ntickComments                  |-        |-        |Y        |-        |Y        |-        |Y        |Y        \nhexOctalConsts                |-        |-        |-        |-        |-        |-        |Y        |Y        \nvalidKeywords                 |11       |26       |31       |31       |39       |44       |51       |all      \nvalidFunctions                |0        |12       |17       |23       |39       |37       |46       |all      \nvalidOperators                |11       |11       |11       |18       |19       |19       |19       |all      \nprintZoneLength               |1        |15       |15       |15       |14       |15       |14       |16       \nnumericPadding                |-        |Y        |Y        |Y        |Y        |Y        |Y        |-        \ncheckOverflow                 |-        |Y        |Y        |-        |Y        |Y        |-        |Y        \ntestInitialFor                |-        |Y        |Y        |Y        |Y        |-        |Y        |Y        \noptionalNextVar               |-        |-        |-        |-        |-        |Y        |Y        |Y        \nmultipleNextVars              |-        |-        |-        |-        |-        |Y        |Y        |Y        \nbitwiseLogic                  |-        |-        |-        |-        |-        |Y        |Y        |Y        \ncheckOnGotoIndex              |-        |Y        |Y        |-        |Y        |-        |-        |Y        \ncomputedGoto                  |Y        |-        |-        |Y        |-        |-        |-        |-        \nrestoreWithLabel              |-        |-        |-        |Y        |-        |-        |Y        |Y        \nsquareBrackets                |-        |-        |-        |Y        |-        |-        |-        |Y        \narraysContainChars            |-        |-        |-        |Y        |-        |-        |-        |-        \nendStmtRequired               |-        |Y        |Y        |Y        |-        |-        |-        |-        \nchainAssignments              |-        |-        |Y        |Y        |-        |-        |-        |Y        \noptionalLet                   |-        |-        |-        |Y        |Y        |Y        |Y        |Y        \ncompiledBlocks                |-        |Y        |Y        |Y        |Y        |-        |-        |Y        \n`OPTION`                      |Y        |Y        |Y        |Y        |Y        |Y        |Y        |Y        \n`PRINT`                       |Y        |Y        |Y        |Y        |Y        |Y        |Y        |Y        \n`IF`                          |Y        |Y        |Y        |Y        |Y        |Y        |Y        |Y        \n`GOTO`                        |Y        |Y        |Y        |Y        |Y        |Y        |Y        |Y        \n`INPUT`                       |Y        |Y        |Y        |Y        |Y        |Y        |Y        |Y        \n`LET`                         |Y        |Y        |Y        |Y        |Y        |Y        |Y        |Y        \n`GOSUB`                       |Y        |Y        |Y        |Y        |Y        |Y        |Y        |Y        \n`RETURN`                      |Y        |Y        |Y        |Y        |Y        |Y        |Y        |Y        \n`CLEAR`                       |Y        |-        |-        |-        |-        |-        |-        |Y        \n`END`                         |Y        |Y        |Y        |Y        |Y        |Y        |Y        |Y        \n`DATA`                        |-        |Y        |Y        |Y        |Y        |Y        |Y        |Y        \n`DEF`                         |-        |Y        |Y        |Y        |Y        |Y        |Y        |Y        \n`DIM`                         |-        |Y        |Y        |Y        |Y        |Y        |Y        |Y        \n`FOR`                         |-        |Y        |Y        |Y        |Y        |Y        |Y        |Y        \n`NEXT`                        |-        |Y        |Y        |Y        |Y        |Y        |Y        |Y        \n`ON`                          |-        |Y        |Y        |-        |Y        |Y        |Y        |Y        \n`RANDOMIZE`                   |-        |Y        |Y        |Y        |Y        |Y        |Y        |Y        \n`READ`                        |-        |Y        |Y        |Y        |Y        |Y        |Y        |Y        \n`RESTORE`                     |-        |Y        |Y        |Y        |Y        |Y        |Y        |Y        \n`STOP`                        |-        |Y        |Y        |Y        |Y        |Y        |Y        |Y        \n`CHANGE`                      |-        |-        |Y        |-        |Y        |-        |-        |Y        \n`ENTER`                       |-        |-        |-        |Y        |-        |-        |-        |Y        \n`ELSE`                        |-        |-        |-        |-        |Y        |Y        |Y        |Y        \n`WHILE`                       |-        |-        |-        |-        |Y        |-        |Y        |Y        \n`WEND`                        |-        |-        |-        |-        |-        |-        |Y        |Y        \n*a* = *b*                     |Y        |Y        |Y        |Y        |Y        |Y        |Y        |Y        \n*a* \u003c\u003e *b*                    |Y        |Y        |Y        |Y        |Y        |Y        |Y        |Y        \n*a* \u003e\u003c *b*                    |Y        |-        |-        |-        |-        |-        |-        |Y        \n*a* \u003c *b*                     |Y        |Y        |Y        |Y        |Y        |Y        |Y        |Y        \n*a* \u003e *b*                     |Y        |Y        |Y        |Y        |Y        |Y        |Y        |Y        \n*a* \u003c= *b*                    |Y        |Y        |Y        |Y        |Y        |Y        |Y        |Y        \n*a* \u003e= *b*                    |Y        |Y        |Y        |Y        |Y        |Y        |Y        |Y        \n*a* + *b*                     |Y        |Y        |Y        |Y        |Y        |Y        |Y        |Y        \n*a* - *b*                     |Y        |Y        |Y        |Y        |Y        |Y        |Y        |Y        \n*a* * *b*                     |Y        |Y        |Y        |Y        |Y        |Y        |Y        |Y        \n*a* / *b*                     |Y        |Y        |Y        |Y        |Y        |Y        |Y        |Y        \n*a* ^ *b*                     |-        |Y        |Y        |Y        |Y        |Y        |Y        |Y        \n*a* ** *b*                    |-        |-        |-        |Y        |Y        |-        |-        |Y        \n*a* *#* *b*                   |-        |-        |-        |Y        |-        |-        |-        |Y        \n*a* NOT *b*                   |-        |-        |-        |Y        |Y        |Y        |Y        |Y        \n*a* AND *b*                   |-        |-        |-        |Y        |Y        |Y        |Y        |Y        \n*a* OR *b*                    |-        |-        |-        |Y        |Y        |Y        |Y        |Y        \n*a* MIN *b*                   |-        |-        |-        |Y        |-        |-        |-        |Y        \n*a* MAX *b*                   |-        |-        |-        |Y        |-        |-        |-        |Y        \n*a* == *b*                    |-        |-        |-        |-        |Y        |-        |-        |Y        \n*a* XOR *b*                   |-        |-        |-        |-        |Y        |Y        |Y        |Y        \n*a* IMP *b*                   |-        |-        |-        |-        |Y        |Y        |Y        |Y        \n*a* EQV *b*                   |-        |-        |-        |-        |Y        |Y        |Y        |Y        \n*a* \\ *b*                     |-        |-        |-        |-        |-        |Y        |Y        |Y        \n*a* MOD *b*                   |-        |-        |-        |-        |-        |Y        |Y        |Y        \n`ABS()`                       |-        |Y        |Y        |Y        |Y        |Y        |Y        |Y        \n`ATN()`                       |-        |Y        |Y        |Y        |Y        |Y        |Y        |Y        \n`COS()`                       |-        |Y        |Y        |Y        |Y        |Y        |Y        |Y        \n`EXP()`                       |-        |Y        |Y        |Y        |Y        |Y        |Y        |Y        \n`INT()`                       |-        |Y        |Y        |Y        |Y        |Y        |Y        |Y        \n`LOG()`                       |-        |Y        |Y        |Y        |Y        |Y        |Y        |Y        \n`RND()`                       |-        |Y        |Y        |Y        |Y        |Y        |Y        |Y        \n`SGN()`                       |-        |Y        |Y        |Y        |Y        |Y        |Y        |Y        \n`SIN()`                       |-        |Y        |Y        |Y        |Y        |Y        |Y        |Y        \n`SQR()`                       |-        |Y        |Y        |Y        |Y        |Y        |Y        |Y        \n`TAB()`                       |-        |Y        |Y        |Y        |Y        |Y        |Y        |Y        \n`TAN()`                       |-        |Y        |Y        |Y        |Y        |Y        |Y        |Y        \n`CTL()`                       |-        |-        |-        |Y        |-        |-        |-        |Y        \n`LEN()`                       |-        |-        |-        |Y        |Y        |Y        |Y        |Y        \n`LIN()`                       |-        |-        |-        |Y        |-        |-        |-        |Y        \n`POS()`                       |-        |-        |-        |Y        |Y        |Y        |Y        |Y        \n`TIM()`                       |-        |-        |-        |Y        |-        |-        |-        |Y        \n`UPS$()`                      |-        |-        |-        |Y        |-        |-        |-        |Y        \n`NFORMAT$()`                  |-        |-        |-        |Y        |Y        |-        |-        |Y        \n`LOG10()`                     |-        |-        |-        |-        |Y        |-        |-        |Y        \n`PI()`                        |-        |-        |-        |-        |Y        |-        |-        |Y        \n`CHR$()`                      |-        |-        |-        |-        |Y        |Y        |Y        |Y        \n`LEFT$()`                     |-        |-        |-        |-        |Y        |Y        |Y        |Y        \n`RIGHT$()`                    |-        |-        |-        |-        |Y        |Y        |Y        |Y        \n`MID$()`                      |-        |-        |-        |-        |Y        |Y        |Y        |Y        \n`INSTR()`                     |-        |-        |-        |-        |Y        |Y        |Y        |Y        \n`SPACE$()`                    |-        |-        |-        |-        |Y        |Y        |Y        |Y        \n`VAL()`                       |-        |-        |-        |-        |Y        |Y        |Y        |Y        \n`ASC()`                       |-        |-        |-        |-        |-        |Y        |Y        |Y        \n`CINT()`                      |-        |-        |-        |-        |-        |Y        |Y        |Y        \n`FIX()`                       |-        |-        |-        |-        |-        |Y        |Y        |Y        \n`HEX$()`                      |-        |-        |-        |-        |-        |Y        |Y        |Y        \n`OCT$()`                      |-        |-        |-        |-        |-        |Y        |Y        |Y        \n`SPC()`                       |-        |-        |-        |-        |-        |Y        |Y        |Y        \n`STR$()`                      |-        |-        |-        |-        |-        |Y        |Y        |Y        \n`STRING$()`                   |-        |-        |-        |-        |-        |Y        |Y        |Y    \n\n\n\n# BASIC Compiler Internals\n\nIf you want to know more about the internals of a BASIC compiler written in TypeScript, then read on.\n\n## Tokenizer\n\nThe tokenizer is powered by one huge gnarly regular expression.\nEach token type is a separate capture group, and we just look for the first one that matched.\nHere's a sample of the regex:\n\n~~~\n    comment      identifier      string\n... (['].*) | ([A-Z_]\\w*[$]?) | (\".*?\") ...\n~~~\n\nIn some tokenizers, like Microsoft BASIC, each keyword supported by the language is matched individually,\nso whitespace is not required around keywords.\nFor example, `FORI=ATOB` would be matched `FOR I = A TO B`.\nThis was sometimes called \"crunching.\"\nWe have a special case in the tokenizer to enable this for these dialects.\n\nThe tokenizer also has special cases for `REM`, `DATA`, and `OPTION` which require tokens be untouched\n-- and in the case of `DATA`, whitespace preserved.\n\nSince BASIC is a line-oriented language, the tokenizer operates on one line at a time,\nand each line is then fed to the parser.\nFor block-oriented languages, we'd probably want to tokenize the entire file before the parsing stage.\n\n\n## Parser\n\nThe parser is a hand-coded recursive descent parser.\nWhy?\nThere was no `yacc` nor `bison` when BASIC was invented, so the language was not designed for these tools.\nIn fact, BASIC is a little gnarly when you get into the details, so having a bit of control is nice,\nand error messages can be more informative.\nBoth clang and gcc use recursive descent parsers, so it can't be that bad, right?\n\nThe program is parsed one line at a time.\nAfter line tokenization, the tokens go into an array.\nWe can consume tokens (remove from the list), peek at tokens (check the next token without removing), and pushback (return them to the list).\nWe don't have to check for `null`; we will always get the EOL (end-of-line) empty-string token if we run out.\n\nExpressions are parsed with an [operator-precedence parser](https://en.wikipedia.org/wiki/Operator-precedence_parser#Pseudocode), which isn't really that complicated.\nWe also infer types at this type (number or string).\nWe have a list of function signatures, and we know that \"$\" means a string variable, so we can check types.\nThe tricky part is that `FNA(X)` is a user-defined function, while `INT(X)` is a function, and `I1(X)` could be a dimensioned array.\n\nTokens carry their source code location with them, so we can assign a precise source code location to each statement.\nThis is used for error messages and for debugging.\n\nThe compiler generates an AST (Abstract Syntax Tree) and not any kind of VM bytecode.\nThe top-level of the AST is a list of statements, and an associated mapping of labels (line numbers) to statements.\nAST nodes must refer to other nodes by index, not by reference, as the worker transfers it to the main thread using `JSON.stringify()`.\n\n\n## Runtime\n\nThe runtime interprets the AST generated by the compiler.\nIt compiles each statement (PRINT, LET, etc.) into JavaScript.\nThe methods `expr2js()` converts expression trees to JavaScript, and `assign2js()` handles assignments like `LET`, `READ` and `INPUT`.\n\nOne statement is executed every time step.\nThere's a \"program counter\", which is the index of the next-to-run Statement node in the list.\n\nEarly BASICs were compiled languages, but the most popular BASICs for microcomputers were tokenized and interpreted.\nThere are subtle differences between the two.\nFor example, interpreted BASIC supports NEXT statements without a variable,\nwhich always jump back to the most recent FOR even if you GOTO a different NEXT.\nThis requires the runtime maintain a stack of FOR loops.\nCompiled BASIC dialects will verify loop structures at compile time.\n\nFor INPUT commands, the runtime calls the `input()` method, which returns a Promise.\nThe IDE overriddes this method to show a text field to the user, and resolve the Promise when data is entered.\nThe runtime might call multiple times until valid data is entered.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsehugg%2Fvintagebasic","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsehugg%2Fvintagebasic","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsehugg%2Fvintagebasic/lists"}