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:

Launch interpreter

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:

1 | INPUT "What's your name"; name$
2 | PRINT "Hello,"; name$
3 |
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 LOAD command:

SAVE "hello.bas"
Saved as LOCAL:hello.bas

    Directory of LOCAL:/

    Modified              Size    Name
    2022-06-03 13:08        55    hello.bas

    1 file(s), 55 bytes

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.

Getting help

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:


    EndBASIC 0.7.0
    Copyright 2020-2021 Julio Merino

    Project page at <>
    License Apache Version 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:


    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 LBOUND% function:


    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.

Language basics

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.

Case sensitivity

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 CamelCase.

Primitive types

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:

Type Annotation Default Values
Boolean ? FALSE TRUE and FALSE
Double floating point # 0.0 Numbers with a period
32-bit signed integers % 0 Numbers from -2,147,483,648 to 2,147,483,647
Strings $ "" 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 command:

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)

Arithmetic operators

EndBASIC supports the following arithmetic operators:

Expression Meaning
a + b Addition
a - b Subtraction
a * b Multiplication
a / b Division (integer or floating point depending on variable types)
a MOD b Modulo operation (integer division remainder)
-a Sign flip

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 ITOD and DTOI functions to cast between these two types.

Comparison operators

EndBASIC supports the following comparison operators:

Expression Meaning
a = b Equality comparison
a <> b Inequality comparison
a < b Less-than comparison
a <= b Less-than or equal to comparison
a > b Greater-than comparison
a >= b 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 ITOD and DTOI functions to cast between these two types.

Logical operators

EndBASIC supports the following logical operators:

Expression Meaning
a AND b Logical and
a OR b Logical or
a XOR b Logical exclusive or
NOT a Logical negation

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:

  1. Function calls and array references.
  2. Parenthetical sub-expressions.
  3. Arithmetical sign flip and logical negation.
  4. Arithmetical multiplication, division and modulo.
  5. Arithmetical addition and subtration.
  6. Comparisons.
  7. 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:

PRINT DTOI(RND() * 100.0) + 500 < 550


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.

Conditional statements

EndBASIC supports conditional statements (IF) with zero or more alternate branches (ELSE IF and ELSE).

Here is how the most simple construct looks like:

IF 3 < 5 THEN
    PRINT "Three is less than five"

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!"
    PRINT "Wow, an amazing discount!"

While loops

EndBASIC supports while loops via the WHILE and 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%

For loops

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%

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%

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.

Text manipulation

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 PRINT invocation.

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

Interactive interfaces

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

Rendering graphics

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 or GFX_RECT commands:

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 HELP GRAPHICS.

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.

' Loop until any key is pressed.
x% = 0
c% = 0
    ' Clear the screen and render the current frame.
    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.

    ' Pause until the next frame.
    SLEEP 0.01

' Enable automatic video syncing.

File system

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:


    Working directory: LOCAL:/
    System location: /home/jmmv/Documents/endbasic/

CD "memory:"

    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.

Drive providers

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:

Target scheme Availability Description
cloud://user All Exposes the cloud drive of the user. More on this in the Cloud service section.
demos:// All Read-only collection of built-in demo programs.
file:///path Desktop Exposes the /path directory of the local file system. Any subdirectories are ignored.
local:// Web Provides a file system backed by the browser’s local storage. Files saved in this provider never leave your machine.
memory:// 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:

MOUNT "jmmv", "cloud://jmmv"

    Name      Target
    DEMOS     demos://
    JMMV      cloud://jmmv
    LOCAL     file:///home/jmmv/Documents/endbasic
    MEMORY    memory://

    4 drive(s)

Side-loading files

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:

MOUNT "X", "file:///home/jmmv/bas"
CD "X:"

    Directory of X:/

    Modified              Size    Name
    2022-06-03 23:37        23    example.bas

    1 file(s), 23 bytes

Cloud service

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:

Replace 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 endbasic/welcome.bas demo!

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:

MOUNT "e", "cloud://endbasic"
CD "e:"

    Directory of E:/

    Modified              Size    Name
    2022-05-27 16:25        40    welcome.bas

    1 file(s), 40 bytes

LOAD "welcome.bas"
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.

Signing up

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:


    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:
Receive promotional email (y/N)? n

    We are ready to go.  Please review your answers before proceeding.

Username: demo10
Email address:
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

    If you encounter any problems, please contact

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.

Logging in

Once you have created and activated your account, all you have to do is type LOGIN "username" to log into your account:

LOGIN "demo"
Password: ********

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 SHARE command.


    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 LOCAL:/upload.bas to CLOUD:/upload.bas. We can do so by loading the file into memory and then saving it again, like this:

LOAD "LOCAL:/upload.bas"
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 public pseudo-user.

Suppose we have saved a awesome.bas file in our cloud drive. We can share it with the public like this:

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:

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.

More specifically:

  1. 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.

  2. 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.

  3. 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.

  4. 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.

  5. 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.

  6. 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.

Hardware access

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 HELP HARDWARE.

As an example, here is how to wait for a physical button press attached to pin number 8:

pressed? = FALSE
WHILE NOT pressed?
    pressed? = GPIO_READ(8)
    SLEEP 0.01

And here is how to flash an LED attached to pin number 18:

state? = TRUE
FOR i = 1 to 10
    GPIO_WRITE 18, state?
    SLEEP 1
    state? = NOT state?



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.