This page provides an overview of the EndBASIC programming language and environment. Most of this text is written in a tutorial-like style, guiding you to accomplish certain tasks. The text is not meant to teach you programming from the ground up, although that would be desirable considering what EndBASIC’s goals are.
Launching the interpreter
EndBASIC is multi-platform and runs on the web and on almost all desktop operating systems, including macOS, Windows, and any Unix derivative such as FreeBSD or Linux. Most features exist in all builds, although there are a few exceptions.
The easiest way to get started is via the web-based interpreter, which you can start by clicking on this button:
If you prefer the desktop version, visit the Download page to fetch the right build for your system and follow the instructions provided there.
As a teaser, note that if you end up trying out different versions of the interpreter, the easiest way to move files between them is to use the file-sharing cloud service.
Writing your first program
To create your first program, open up the interpreter, type
EDIT and press
Enter. This will open up a full-screen text editor where you can start typing your first program. Within it, type the text below and press
Esc to return to the command line:
INPUT "What's your name"; name$ PRINT "Hello,"; name$
Once you are back in the command line, try using the
LIST command to visualize that the program you typed is stored in the interpreter’s memory, and then use the
RUN command to launch your program:
Ready LIST 1 | INPUT "What's your name"; name$ 2 | PRINT "Hello,"; name$ 3 | Ready RUN What's your name? Julio Hello, Julio
That’s it! You have written and executed your first program!
When the interpreter stops, all state changes made by the program are left untouched. This is useful to illustrate that the program and the interpreter are tightly coupled and helps troubleshoot problems in the program. In other words: any variables defined up to the point where the program stopped are still in memory, so if you type
PRINT name$ from the command line, you’ll get back the name that you previously entered.
Because of the side-effects that an executed program leaves behind, the
CLEAR exists and lets you reset the interpreter to a clean slate while maintaining your program in memory. (Essentially,
RUN does a
CLEAR first to ensure that your program isn’t impacted by previous state.) There is also a command called
NEW which does the same as
CLEAR and also clears the program stored in memory.
To iterate on the program, you can go back to the editor by typing
EDIT again, modifying your previous code.
Loading and saving
In the previous section, you wrote your first program—and I suppose you don’t want to lose such a precious creation! To avoid that, you can save your program to disk with the
SAVE command, verify that it was saved via the
DIR command, and load it back into memory via the
SAVE "hello.bas" Saved as LOCAL:hello.bas Ready DIR Directory of LOCAL:/ Modified Size Name 2022-06-03 13:08 55 hello.bas 1 file(s), 55 bytes Ready LOAD "hello.bas"
Once you have given the program a name, the interpreter will keep track of it until you exit or discard the currently-loaded program via the
NEW command. This means that any subsequent
SAVE operation can be done without re-entering the program name: simply typing
SAVE will update the previously-created file with the new contents.
EndBASIC will try to prevent you from losing your program. For example, if you try to drop the current program with
NEW or exit the interpreter before saving your program, EndBASIC will prompt you to confirm your actions.
That said, get in the habit of saving your program frequently. If your program gets stuck, you may need to reboot the interpreter and there is no protection against that.
EndBASIC is designed to be self-documenting, and this document does not intend to provide a full reference manual to EndBASIC because this information is already built into the interpreter.
To access the built-in reference documentation, type
HELP within the interpreter, which will greet you with a message like this:
Ready HELP EndBASIC 0.7.0 Copyright 2020-2021 Julio Merino Project page at <https://github.com/endbasic/endbasic> License Apache Version 2.0 <http://www.apache.org/licenses/LICENSE-2.0> Top-level help topics: >> Array functions >> Cloud access >> Console >> File system >> Hardware interface >> Interpreter >> Language reference >> Numerical functions >> Stored program >> String functions Type HELP followed by the name of a topic for details. Type HELP HELP for details on how to specify topic names.
This main help page shows you the available help topics. To get extra help, you need to provide one of those topics to the
HELP command. Topic matching is done on a prefix basis, so you can type only part of the topic name. For example, to access the Array functions topic:
Ready HELP ARR Array functions >> LBOUND% Returns the lower bound for the given dimension of the array. >> UBOUND% Returns the upper bound for the given dimension of the array. Type HELP followed by the name of a symbol for details.
And from there, you can also obtain extra information on the subtopics. For example, to get details on the
Ready HELP LB LBOUND%(array[, dimension%]) Returns the lower bound for the given dimension of the array. The lower bound is the smallest available subscript that can be provided to array indexing operations. For one-dimensional arrays, the dimension% is optional. For multi-dimensional arrays, the dimension% is a 1-indexed integer.
In lieu of a full on-line reference manual, you can check out the full dump of all help messages as checked into the repository.
EndBASIC is an interpreter for a BASIC-like language and is inspired by Amstrad’s Locomotive BASIC 1.1 and Microsoft’s QuickBASIC 4.5. That said, be warned that the language itself is still quite rudimentary: most effort so far has gone into building the EndBASIC environment (graphical shell, cloud service, etc.) rather than improving the language. This should get much better in the upcoming version 0.10.
EndBASIC is case-insensitive. It is common to write BASIC code all in uppercase, but this is not a requirement. The convention in the EndBASIC interpreter, the documentation, and example code is to write all keywords in uppercase and all identifiers (variable names) in lowercase.
As a tip, note that uppercase keywords make the code look dated because all modern programming languages use
lower_snake_case (Rust, C++),
camelCase (Java, Python, Go) or
PascalCase (C#, Go). Writing your EndBASIC code in lowercase will make it look more modern.
For extra trivia, note that the convention in Visual Basic is to use
EndBASIC is a strongly typed language. Variables are assigned a type at definition time and their type remains immutable throughout their existence. This type is represented as a single-character type annotation appended to the variable names. The type annotation is optional, in which case EndBASIC will infer types, but it must match the type of the variable if present.
The following types are supported:
|Double floating point||
||Numbers with a period|
|32-bit signed integers||
||Numbers from -2,147,483,648 to 2,147,483,647|
||Any text enclosed in double-quotes|
New variables can be defined and declared at assignment time, like in these examples:
bool_var? = TRUE double_var# = 5.0 integer_var% = 5 string_var$ = "Hello, world!"
Or they can be declared and set to their default values with the
DIM b AS BOOLEAN ' b? is set to FALSE. DIM d AS DOUBLE ' d# is set to 0.0. DIM i AS INTEGER ' i% is set to 0. DIM s AS STRING ' s$ is set to "".
EndBASIC supports multidimensional arrays. Arrays are represented as contiguous blocks of memory in row-wise order and all values in the array must be of the same type.
Arrays are 1-indexed which means that an array’s indexes go from 1 to the size of the array as specified during its declaration. This is unlike most common languages which use 0-indexing. Certain variants of BASIC offer a mechanism to switch to 0-indexing (via the
OPTION BASE command), but this is currently not supported.
Arrays must be defined with the
DIM command and are later accessed using parenthesis (which is unlike most common languages today, which use square brackets for indexing):
' Define a 2-dimensional array (aka matrix) with 5 rows and 3 columns. DIM arr(5, 3) AS INTEGER ` Assign and access two different positions. arr(3, 2) = 12345 PRINT arr(1, 1)
EndBASIC supports the following arithmetic operators:
||Division (integer or floating point depending on variable types)|
||Modulo operation (integer division remainder)|
Note that there is no automatic type promotion in the language right now. Operands to binary operators must be of the same type. In particular, this means that something like
3 + 4.0 will fail because integers and doubles are not compatible. Use the
DTOI functions to cast between these two types.
EndBASIC supports the following comparison operators:
||Less-than or equal to comparison|
||Greater-than or equal to comparison|
Note that there is no automatic type promotion in the language right now. Operands to binary operators must be of the same type. In particular, this means that something like
3 < 4.0 will fail because integers and doubles are not compatible. Use the
DTOI functions to cast between these two types.
EndBASIC supports the following logical operators:
||Logical exclusive or|
Operands to logical operators must be of boolean type. There is no automatic coercing of other types into booleans, and there will not be. In particular, this means that something like
NOT a is invalid unless
a is a boolean.
All of the previously-described operators can be combined in complex expressions. The following ordering applies when evaluating expressions:
- Function calls and array references.
- Parenthetical sub-expressions.
- Arithmetical sign flip and logical negation.
- Arithmetical multiplication, division and modulo.
- Arithmetical addition and subtration.
- Logical and, or and exclusive or.
Operators of the same priority are applied left-to-right. For example, in
3 - 4 + 5, where both addition and subtraction have the same priority ordering, the subtraction will be done before the addition (as you would expect).
As an example, here is an expression to compute a random number between 500 and 600 and check whether the resulting number is within 500 to 550:
Ready PRINT DTOI(RND() * 100.0) + 500 < 550 FALSE
GOTO is probably the most salient feature of a retro-looking BASIC interpreter… but unfortunately this is currently not supported due to the way the execution engine works. I have plans to add this and maybe even line numbers in a subsequent release, but for now you’ll have to stick to structured programming.
EndBASIC supports conditional statements (
IF) with zero or more alternate branches (
ELSE IF and
Here is how the most simple construct looks like:
IF 3 < 5 THEN PRINT "Three is less than five" END IF
Here is a more advanced construct with multiple alternate branches:
discount# = RND() IF discount# < 0.2 THEN PRINT "Meh, a small discount." ELSEIF discount# < 0.7 THEN PRINT "Nice, a good discount!" ELSE PRINT "Wow, an amazing discount!" END IF
EndBASIC supports while loops via the
WEND keyword. Here is how they look like:
n% = 0 WHILE n% < 1 OR n% > 10 INPUT "Enter a number between 1 and 10: ", n% WEND
EndBASIC supports for loops via the
FOR keyword. For loops iterate over an inclusive range of integers with a default step of 1. For example, the following loop will print numbers 1, 2, 3, 4 and 5:
FOR i% = 1 TO 5 PRINT i% NEXT
The stepping through the range is configurable via the
STEP keyword, and this can be both positive and negative. For example, the following loop will print the numbers 10, 8, 6, 4 and 2:
FOR i% = 10 TO 1 STEP -2 PRINT i% NEXT
Both the beginning and end of the range can be arbitrary integer expressions. However, the
STEP argument must be an integer literal.
The EndBASIC console is a hybrid console that offers overlapping textl and graphics. As such, the console exposes two coordinate systems: commands that deal with text use character-based coordinates, and commands that deal with graphics use pixel-based coordinates. Both coordinate systems are 0-indexed and start at the top-left corner of the console.
The graphical console is available by default in the web version of EndBASIC.
Desktop builds have support for the graphical console as well, but they must be built with SDL support. All prebuilt binaries in the Download section have SDL support. Note, however, that to launch the desktop version of EndBASIC with graphics support, you will have to use a command like these:
endbasic --console=graphics # Default settings. endbasic --console=graphics:1024x768 # Specific resolution. endbasic --console=graphics:1920x1080fs # Specific resolution, full screen.
The EndBASIC text console provides sufficient features to build simple text-based interactive interfaces. These include changing colors, moving the cursor around, and waiting for key presses.
To get started, you can play with the
CLS command to clear the screen, the
COLOR command to set the foreground and/or background colors of the text, and the
LOCATE command to move the cursor to a new position. Note that
LOCATE on its own is useless unless it is immediately followed by a
To experience these features, type the following string of commands in the console and press Enter:
COLOR 15, 12: CLS: LOCATE 10, 10: PRINT "Hello": LOCATE 0, 15
To build any kind of interactive interface, be it textual or graphical, you will need to wait for key presses. The
INPUT command is insufficient for this because it waits for a full line of input. But we can use the
INKEY function to poll the keyboard for an input.
For example, see this code to build a loop that waits for a key press and then reacts to it:
PRINT "Press keys to get feedback, or ESC to exit" k$ = "" WHILE k$ <> "ESC" k$ = INKEY() IF k$ <> "" THEN PRINT "You pressed"; k$ END IF SLEEP 0.01 WEND
A distinctive feature of EndBASIC is its support for graphics and text in the same console. You can start rendering graphics right from the command line, without having to understand how two separate windows interact with each other or without changing modes.
To get started, play with the
GFX_LINE 0, 0, 100, 100 GFX_RECT 100, 100, 300, 300
Remember that you can access detailed reference information for all available commands within the graphics category by typing
Efficient graphics rendering
Drawing occasional graphics from the console by typing individual commands is a great way of exploring what’s available and understanding how the computer reacts to code, but rendering graphics in this manner is not very efficient: every drawing operation will be flushed to the video card as soon as it is executed, and this is a slow process.
To draw animations in an efficient manner, you must explicitly control when the console’s contents are sent to the screen: in other words, you need to control when every video sync operation happens.
The general idea is that your program needs to render everything first “in memory” and then tell the video driver to paint the results. This can be accomplished via the
GFX_SYNC command, which allows us to enable or disable automatic video flushing, and to explicitly flush the video.
Here is a sample program that renders an animation. Pay attention to the way the calls to the
GFX_SYNC are done:
' Disable automatic video syncing. GFX_SYNC FALSE ' Loop until any key is pressed. x% = 0 c% = 0 WHILE INKEY$() = "" ' Clear the screen and render the current frame. CLS COLOR c% GFX_RECTF x%, 100, x% + 10, 110 ' Update positions and colors for the next frame. c% = (c% + 1) MOD 15 x% = (x% + 5) MOD 500 ' Flush the rendered frame to the screen. GFX_SYNC ' Pause until the next frame. SLEEP 0.01 WEND CLS COLOR ' Enable automatic video syncing. GFX_SYNC TRUE
EndBASIC offers a DOS-like interface to access and manipulate files.
Due to the fact that the EndBASIC command line is BASIC, there are a few oddities you will have to get used to when typing commands. The first one is that paths and file names are strings, and as such must be double-quoted. The second one is that arguments to commands must be separated by commas, not just spaces.
Drives and paths
The EndBASIC virtual file system is composed of a bunch of drives, each containing its own collection of files. Drives are mapped to targets, and these targets expose a variety of backend storage services.
Paths in EndBASIC have the general form
[DRIVE:][/]FILENAME. Both the drive name and the slash are optional. When all components are present, such as in
LOCAL:/FILE.BAS, we have an absolute path that unique identifies a file; when the drive component is missing, such as in
FILE.BAS, we have a relative path to the current working directory.
The current working directory can be queried with the
CWD command and can be changed via the
CD command. For example:
Ready PWD Working directory: LOCAL:/ System location: /home/jmmv/Documents/endbasic/ Ready CD "memory:" Ready PWD Working directory: MEMORY:/ No system location available
Directories are not currently supported. This is why the slash in the paths above is optional, but it’s good to get in the habit of specifying it because support for directories will come later.
Drives are mapped to targets, and these targets are backed by virtual file system providers that expose a variety of backend storage services.
The following providers are currently supported:
||All||Exposes the cloud drive of the
||All||Read-only collection of built-in demo programs.|
||Web||Provides a file system backed by the browser’s local storage. Files saved in this provider never leave your machine.|
||All||Memory-backed file system. Different instances of this provider offer disjoint file systems.|
The list of currently-mounted file systems can be queried and modified via the
MOUNT command. For example:
Ready MOUNT "jmmv", "cloud://jmmv" Ready MOUNT Name Target DEMOS demos:// JMMV cloud://jmmv LOCAL file:///home/jmmv/Documents/endbasic MEMORY memory:// 4 drive(s)
While EndBASIC provides a built-in editor, the editor is currently quite simplistic. If you find that the editor limits your development speed, you can side-load files into the interpreter. This feature is only available in the desktop version of EndBASIC.
To do this, you can either save files under the default projects location, which typically is
~/Documents/endbasic/, or you can save them under a directory of your choice and then mount that directory inside EndBASIC using the
file:// mount target.
For example, say that you create a program outside of EndBASIC:
$ mkdir ~/bas $ vim ~/bas/example.bas ... edit edit edit ...
Once the file is saved, you can access it like this:
Ready MOUNT "X", "file:///home/jmmv/bas" Ready CD "X:" Ready DIR Directory of X:/ Modified Size Name 2022-06-03 23:37 23 example.bas 1 file(s), 23 bytes
The EndBASIC service is a simple cloud-based file system that lets you maintain and share your creations with the world, right from the EndBASIC command line.
You can always consume public content without creating an account but, to share your own content, you will need an account first.
Accessing public content
To access a file that was shared publicly by you or someone else, you have two options.
The first option is to tell the web UI to automatically run the program based on a URL of the form:
user with the name of the user that has shared the file and
file.bas with the name of the file that was shared. With that, the interpreter will launch, mount the user’s public drive, and run the given file. Try it now: run the
The second option is to mount the user’s drive interactively and then investigate its contents. You can do so providing a target of the form
cloud://user to the
MOUNT command, where
user is the name of the user that shared the file. Then, inspect the drive contents with the
DIR command and load a file with the
LOAD command. Here is a sample session:
Ready MOUNT "e", "cloud://endbasic" Ready CD "e:" Ready DIR Directory of E:/ Modified Size Name 2022-05-27 16:25 40 welcome.bas 1 file(s), 40 bytes Ready LOAD "welcome.bas" Ready LIST 1 | PRINT "Welcome to the EndBASIC service!"
When mounting a cloud drive, the contents you see will depend on your credentials. If you are not logged in, all you will see are the user’s public files (if any). If you are logged in, whoever, you will also see any files that the user may have shared directly with you.
To create an account, use the
SIGNUP command from within the interpreter. You will have to provide basic information for the account, such as a username and a password, and you will also have to provide an email address for account activation (see privacy notes). Here is what you can expect during account creation:
Ready SIGNUP Let's gather some information to create your cloud account. You can abort this process at any time by hitting Ctrl+C and you will be given a chance to review your inputs before creating the account. Username: demo Password: ********* Retype password: ********* We also need your email address to activate your account. Your email address will be kept on file in case we have to notify you of important service issues and will never be made public. You will be asked if you want to receive promotional email messages (like new release announcements) or not, and your selection here will have no adverse impact in the service you receive. Email address: email@example.com Receive promotional email (y/N)? n We are ready to go. Please review your answers before proceeding. Username: demo10 Email address: firstname.lastname@example.org Promotional email: no Continue (y/N)? y Your account has been created and is pending activation. Check your email now and look for a message from the EndBASIC Service. Follow the instructions in it to activate your account. Make sure to check your spam folder. Once your account is activated, come back here and use LOGIN to get started! If you encounter any problems, please contact email@example.com.
After you complete this process, check your email and look out for a message from the EndBASIC service. You’ll have to click on the link provided within to activate your account, and you must do that before proceeding.
Note the question above to receive promotional emails. If you consent to that, you will receive notifications of new EndBASIC releases and new blog posts via email. I’d appreciate it if you said yes as a mechanism to keep a certain level of engagement in EndBASIC over time. Expect about one email a month at most.
Once you have created and activated your account, all you have to do is type
LOGIN "username" to log into your account:
Ready LOGIN "demo" Password: ******** ----- BEGIN SERVER MOTD ----- Welcome back, demo! It's good to see you again. ----- END SERVER MOTD -----
After a successful log in, the EndBASIC client will mount the
CLOUD: drive, which is your personal space to hold files in the cloud. Any files stored in this drive are private to you by default, but they can be shared with others with ease using the
Ready CD "CLOUD:" Ready DIR Directory of CLOUD:/ Modified Size Name 2021-06-25 13:51 116 thanks.bas 2021-06-25 13:50 103 welcome.bas 2 file(s), 219 bytes 65317 of 65536 bytes free
Uploading a program
Sometimes, it is simpler to develop a program outside of the EndBASIC environment and then side-load it into the interpreter. This is easy to do in the desktop build of EndBASIC because it has direct access to the local file system, but it is hard to do for any file in the cloud.
The way around this is to develop your program locally and then upload it to the cloud. To do this, you will have to do a manual file copy. For example, suppose we want to upload
CLOUD:/upload.bas. We can do so by loading the file into memory and then saving it again, like this:
Ready LOAD "LOCAL:/upload.bas" Ready SAVE "CLOUD:/upload.bas" Saved as CLOUD:/upload.bas
Publishing a program
The primary purpose of the EndBASIC cloud service is to let you share your magical creations with the public.
Files saved in cloud drives have reader ACLs that control who can read them. You can give read permissions to individual users, or you can give read permissions to everyone by means of the
Suppose we have saved a
awesome.bas file in our cloud drive. We can share it with the public like this:
Ready SHARE "CLOUD:/awesome.bas", "public+r" You have made the file publicly readable. As a result, other people can now auto-run your public file by visiting: https://repl.endbasic.dev/?run=jmmv/awesome.bas
Note how the
SHARE command detects that you have made the file public and will print the URL that users can open to automatically launch your program.
Privacy and security notes
EndBASIC is, right now, a toy project. While I have tried my best to keep the service secure and private, I ask that you do not store any sensitive information in this service.
Your user account and files are stored in a PostgreSQL database managed by Azure. Read the Azure Encryption documentation for more details on what this entails.
I collect high-level metadata on all requests to the cloud service for troubleshooting purposes and basic usage analytics. Details include the contacted API endpoint, the client IP address, and the originating browser agent. The logs do not include the request payloads, but obviously the database does.
The email address collected during the sign-up process will only be used for critical service-related communications by default. These can include notifications of data loss due to the evolving nature of the service. There has only been the need to send one such notification so far, and I expect the volume of these emails to be near zero.
Your email address will never be sold nor given to third-parties. However, as part of giving you service, your email must flow through SendGrid and has is in theory visible to the operators of the PostgreSQL database managed by Azure.
You can opt in to receiving “promotional emails”, and I would appreciate it if you did so. These emails will include notifications of new EndBASIC releases as well as notifications of new blog posts. You can expect about one such message per month on average.
You can always update your account’s information or permanently delete your account and all information associated with it. Contact support and I’ll be happy to assist you; I haven’t had a chance to build those features within the interface yet.
EndBASIC supports limited direct hardware access as a way to play with real-world hardware. Toying with LEDs, buttons, and the like can be a great way of learning how computers work, and is the reason why this support was builtin EndBASIC.
Hardware support is currently limited to the desktop builds for the Raspberry Pi, which you can get from the Download page.
EndBASIC has support to manipulate the GPIO pins of the Raspberry Pi via the family of commands described in
As an example, here is how to wait for a physical button press attached to pin number 8:
GPIO_SETUP 8, "IN-PULL-DOWN" pressed? = FALSE WHILE NOT pressed? pressed? = GPIO_READ(8) SLEEP 0.01 WEND
And here is how to flash an LED attached to pin number 18:
GPIO_SETUP 18, "OUT" state? = TRUE FOR i = 1 to 10 GPIO_WRITE 18, state? SLEEP 1 state? = NOT state? NEXT GPIO_CLEAR
The EndBASIC interpreter looks for a file named
AUTOEXEC.BAS (all uppercase) in the
LOCAL:/ drive at startup time and, if found, will run it before dropping you into the command prompt.
You can create this file from within the interpreter and make it run any commands you like. A common use may be to run
LOGIN to automatically log into your cloud account. Or you could use it to customize the appearance of the console by changing its colors.