LocoBasic is a streamlined adaptation of Locomotive BASIC, designed primarily for calculations. It is lightweight and can run either in a browser or on the command line using Node.js. It has NO GOTO but supports a subroutine style with GOSUB. Line numbers are optional and only needed to start a subroutine or a DATA line for RESTORE
LocoBasic Links: LocoBasic, Source code, HTML Readme
- Open LocoBasic in any modern web browser.
- Select an example with the select box or input your own BASIC code. The code is automatically compiled to JavaScript and executed unless you switch off the "auto" checkbox.
-
Install Node.js if you don’t already have it.
-
Clone this repository and navigate to its directory.
-
Run the following commands to install:
npm i npm run build
-
Run some of the following command to execute:
node dist/locobasic.js example=euler node dist/locobasic.js input='print "Hello!"' node dist/locobasic.js input="?3 + 5 * (2 - 8)"
- Supported:
IF...ELSE
- Loops:
FOR
andWHILE
- These structures are directly converted to JavaScript for execution.
-
Use
GOSUB
andON GOSUB
GOTO
andON GOTO
are not supported
-
Subroutine Style:
- A line starting with
GOSUB <line>
marks the beginning of a subroutine - Subroutines must end with a single
RETURN
on its own line - Important: Subroutines cannot be nested
- A line starting with
- Usually number
- Use
$
to denote a string variable- Variable markers like
!
and%
are not supported
- Variable markers like
- No automatic rounding:
- Integer parameters are not automatically rounded
- Computations follow JavaScript precision
- Operator arity and precedence match those of Locomotive BASIC
- Endless Loops:
- Not trapped automatically. Restarting the browser window may be required to recover.
- STOP and END:
- These halt execution only at the top level. Within subroutines, they simply return.
AND
,NOT
,OR
,XOR
number MOD number
compute the modulus- Comparisons: =, <>, <, <=, >, >=
- +, -, *, /, \ (integer div), (...)
- &hexValue, &xBinaryValue
- String concatenation: +
ABS(number)
Returns the absolute value of numberASC(character)
Returns the ASCII number of characterÀTN(number)
Returns the arcustangens of number in radiansBIN$(number [, padding])
Converts a number to its binary representationCHR$(number)
Returns the character for the ASCII code numberCINT(number)
Returns the integer part of number- same as INT
CLS
Clears the output windowCOS(number)
Returns the cosine of number given in radiansDATA ["string", number,...]
Defines string or numerical data to be read by READ- Separated by commas ","
- Strings must be quoted
- Numbers (including hex and binary) are unquoted and can only be read numerically
DEC$(number, format)
Returns the number as a string formatted according to the specified pattern.- Only "#" and "." are supported in the format. Example: "##.###"
DEF FNname[(arg1, ...)] = expression
Defines a function FNname- Can be used as
FNname()
- No space between FN and name is allowed
- If there are no arguments, do not use parentheses
- Can be used as
DIM arrayVariable(dim1 [, dim2, ...])
Initializes an array- Can be multi-dimensional
- Will be initialized to 0 or "" depending on the variable type
END
Ends execution- currently the same as
STOP
- currently the same as
ERASE variable, [variable,...]
Erases array variables- Specify variable name without indices
ERROR number
Throws error with numberEXP(number)
Returns e function raised to the power of numberFIX(number)
Truncates numberFOR variable = start to end [STEP increment]
Control structure- increment can also be negative,, in which case start must be greater than end
- Endless Loops: Not trapped
FRAME
Pauses execution for ~50ms intervals for synchronization.GOSUB line
Calls subroutine starting at line- Subroutines must end with a single
RETURN
on its own line
- Subroutines must end with a single
HEX$(number [, padding])
Converts a number to its hexadecimal representationIF expression THEN statements [ELSE statements]
control structure (in one line)INPUT [message;] variable
Prompts the user for input (string or numeric)INSTR(string1, string2)
Returns the first positon of string2 in string1- Limitations: No support for start position as first argument
INT(number)
Returns the integer part of numberLEFT$(string, number)
Returns number characters from the left in stringLEN(string)
Returns rthe length of the string- LocoBasic has no limitaton on the length
LOG(number)
Returns natural logarithm for number (based on e)LOG10(number)
Returns logarithm for number based on 10LOWER$(string)
Returns string in lowercaseMAX(number [,number,...])
Returns the maximum of the given numbersMID$(string, first [, length])
Returns a substring starting at positon first with lengthMIN(number [,number,...])
Returns the minimum of the given numbersMODE number
Sets screen mode- Currently the same as CLS with the mode number ignored
NEXT
Closes a FOR loopON index GOSUB line1 [,line2...]
Calls subroutine at position index in the list- Check
GOSUB
for how to define a subroutine - Limitations: There must be a subroutine at position index in the list
- Check
PI
Returns the value of 'pi'PRINT argument1 [; argument2; ...]
Outputs text and numbers- Arguments must be separated by
;
- Numbers are padded with trailinng space, and leading space for positive numbers
- Limitations: No support for
TAB()
,SPC()
, orUSING
formatting. Use DEC$() to format numbers
- Arguments must be separated by
READ variable
Reads the next value from aDATA
statement into variableREM
A comment until end of line, same as `RESTORE [line]
Resets theDATA
pointer to a specified line numberRETURN
Returns from a subroutine.- See GOSUB, ON... GOSUB
RIGHT$(string, number)
Returns number characters from the right in stringRND(number)
Returns the next pseudo-random number- Parameter number is ignored
ROUND(number [, decimalPlaces])
Rounds a number to a specified number of decimal places- Rounding not exactly the same as with Locomotive BASIC
SGN(number)
Returns the signum of a number (-1, 0 or 1)SIN(number)
Returns the sine of number given in radiansSPACE$(number)
Returns number spacesSQR(number)
Returns the square root of numberSTOP
Halts the execution- Within subroutines, it functions as a RETURN
- Similar to END
STR$(number)
Converts a number to its string representation- A positive number is passed with a space
STRING$(number, character)
Returns character repeated number times- requires the second parameter to be a character
TAN(number)
Returns the tangens of number given in radiansTIME
Returns the current system time in 1/300 secUPPER$(string)
Returns string in uppercaseVAL(string)
Converts a string to a number- supports hexadecimal and binary formats
WEND
Ends a WHILE loopWHILE expression
Control structure: repeat until expression is falsenumber XOR number
In Expresions: exclusive-OR
- LocoBasic is mainly used for calculations. It runs in a Browser or on the command line with node.js
- Control structures like IF...ELSE, and FOR and WHILE loops are directly converted to JaveScript
- GOTO or ON GOTO are not suppoered. Use GOSUB, ON GOSUB instead. The GOSUB line is interpreted as subroutine start.
- Subroutine style: Line from GOSUB <line> starts a subroutine which is ended be a single RETURN in a line. Do not nest subroutines.
- Variable types: No type checking: "$" to mark a string variable is optional; "!", "%" are not supported
- No automatic rounding to integer for integer parameters
- Computations are done with JavaScript precision; arity and precedence of operators follows Locomotive BASIC
- Endless loops are not trapped, ypou may need to restart the browser window.
- PRINT: output in the output window. Args can be separated by ";" or "," which behave the same. (No TAB(), SPC(), USING)
- STOP, END: stop only on top level, not in subroutines (where they just return)
- STRING$(): second parameter must be a character
- DATA: strings must be quoted; numbers (including hex, bin) are unquoted and can only be read numerical
MID$
as assign?a$="abcde": MID$(a$,3,2)="w": ?a$
- command line tool should output a stand alone running JS file for node
- Do we want keywords all uppercase? And variables all lowercase? And maybe new features with capital letter? E.g. If...Then...Else...Endif on multiple lines?
- Create syntax highlighting for BASIC for CodeMirror, maybe similar to theamstradbasic-vscode or CPCReady extension
- numbers with exponential notation
- dim and other more complex commands are included on-demand in the compiled JavaScript
- TIME: *300/1000
- DIM, NEXT with multiple arguments
- DATA, READ, RESTORE
- comments in IF: 107 IF zoom<3 THEN zoom=3: 'zoom=12
- No JS reserved word as variables: arguments, await, [break], case, catch, class, const, continue, debugger, default, delete, do, [else], enum, eval, export, extends, false, finally, [for], function, [if], implements, import, in, instanceof, interface, [let], [new], null, package, private, protected, public, [return], static, super, switch, this, throw, true, try, typeof, var, void, [while], with, yield https://www.w3schools.com/js/js_reserved.asp
- ?hex$("3") => array hex$["3"]
- load examples.js separately (not as examples.ts in the package)
- separate UI from core (UI not needed for node), maybe two packages
ERASE var | strVar
setsvar=0; strVar=""
, not really needed, just to run such programs
after auto border break call cat chain clear cog closein closeout cont copychr creal cursor dec defint defreal defstr deg delete derr di draw drawr edit ei eof erl err every fill fre goto graphics himem ink inkey-$ inp joy key let line list load locate mask memory merge move mover new on openin openout origin out paper peek pen plot plotr poke pos rad randomize release remain renum resume run save sound spc speed sq swap symbol tab tag tagoff test testr troff tron unt using vpos wait width window write xpos ypos zone
-
Ohm JavaScript parsing toolkit - Source code - Paper: Modular Semantic Actions
-
CodeMirror code editor used for the Locobasic UI - Source code - Libraries
-
CPCBasicTS CPCBasicTS Unchained - Run CPC BASIC in a Browser - Source code
-
CPCBasic CPCBasic Unchained - Run CPC BASIC in a Browser - Source code
-
CPCemu - CPC Emulator, since version 2.0 with very accurate emulation
-
Amstrad CPC 6128 User Instructions, or: Schneider CPC 6128 Benutzerhandbuch
-
Locomotive BASIC - Description of the CPC Basic Dialect
-
Another BASIC compiler: ugBASIC