Skip to content

QBasic Language Support v0.10.0

boxgaming edited this page Aug 8, 2025 · 5 revisions

QBJS supports a large subset of the QBasic and QB64|PE syntax as well as native support for the GX API.
The following standard keywords are currently implemented: Supported Keywords.

QBasic Compatibility

Much effort has been made to allow QBJS to be as compatible as possible with applications built with classic QBasic and QB64. At the same time, another aspiration of this project is to allow access to powerful features of the browser's javascript engine. In an effort to balance these goals the following differences exist between QBJS and QBasic/QB64.

Differences from QBasic/QB64

  • Subs and function parameters are pass by value instead of pass by reference
  • Goto and GoSub are not supported. Labels are supported only in the context of Data/Read/Restore.
  • Limited support of metacommands

Functionality New to QBJS

Known Issues

Outstanding issues and requested features are tracked here:
https://github.com/boxgaming/qbjs/issues

Data Types

All data types from QBasic and QB64 (including custom types) are supported with the exception of the following:

  • Fixed length strings (String*n)
  • _BIT type with specific length (_BIT*n)
  • _MEM data type

Flexible typing

QBJS takes advantage of the fact that the underlying Javascript runtime is not strongly typed. This allows for a more flexible variable assignment than would have been allowed in traditional QBasic. For example, the following is valid in QBJS, but would cause an error in traditional QBasic:

Dim a As Integer
a = 3
Print a

a = "test"
Print a

Pass by Value

With traditional QBasic, values passed as arguments to functions and subs are passed by reference by default. Any changes made to those values in the method will be reflected in the variable which was passed after the method execution has completed. In QBJS, however, all values are passed by value. Consider the following example:

Dim x As Integer
x = 3
Print "result: "; Increment(x)
Print "x:      "; x

Function Increment (n As Integer)
    n = n + 1
    Increment = n
End Function

In QBasic/QB64 this would output:

result: 4
x:      4

However, in QBJS the result would be:

result: 4
x:      3

To be more precise, what is passed by value in QBJS is the pointer to the original value. This means that while assigning the variable to a new value will not affect the value of the original variable (as shown above), if the value passed as the method argument is a complex variable (i.e. a custom type or array) and an element of that variable is modified, the change will be also reflected in the original variable. For example:

Type Position
    x As Integer
    y As Integer
End Type

Dim testPos As Position
testPos.x = 35
testPos.y = 45

UpdatePosition testPos

Print "x: "; testPos.x
Print "y: "; testPos.y

Sub UpdatePosition (p As Position)
    p.x = p.x * 2
    p.y = p.y + 10
End Sub

If executed in QBasic/QB64 or QBJS, the result will be the same:

x: 70
y: 55

However, if we alter this example slightly to assign a new value to the p variable like so:

Type Position
    x As Integer
    y As Integer
End Type

Dim testPos As Position
testPos.x = 35
testPos.y = 45

UpdatePosition testPos

Print "x: "; testPos.x
Print "y: "; testPos.y

Sub UpdatePosition (p As Position)
    Dim p1 As Position
    p1.x = p.x * 2
    p1.y = p.y + 10
    p = p1
End Sub

We will see the same result as above when executed with QBasic/QB64. However, in QBJS, because we reassigned what p was pointing to in the UpdatePosition function, this results in the original values being printed in the program output:

x: 35
y: 45

Associative Arrays

In addition to support for standard QBasic arrays, QBJS also provides the ability to create associative arrays, also called hashtable, map, or dictionary.

Dim stnames() As String
stnames("CA") = "California"
stnames("NY") = "New York"
stnames("KY") = "Kentucky" 

Print "Name: "; stnames("KY")

Method Pointers

QBJS adds the ability to define Functions and Subs as variable types. Additionally, pointers to existing subs or functions can be referenced with the '@' operator. One of the primary use cases for this feature is to support passing "callback" methods for event-based programming. In the example below we can define a method to handle button click events and then pass a reference to that method to register it with the Dom.Event method so that it can be called by the framework each time the button is clicked.

Import Dom From "lib/web/dom.bas"

Dim btn As Object
Dom.Create "br"
btn = Dom.Create("button", , "Push Me")
Dom.Event btn, "click", @OnButtonClick


Sub OnButtonClick (event As Object)
    Print "You pushed it!"
End Sub

Function and Sub variable types can be used for creating custom callback functions as well as enabling dynamic method assignment:

Randomize Timer

' Dynamically assign a function reference and call it
Dim fn As Function
fn = @Emphasize
Print fn("This is working")
Print "---------------------------------------"

' Pass a callback function to another method
Delegate "Is this a question", @Question
Delegate "Yes it is", @Emphasize
Print "---------------------------------------"

' Initialize a list of function references as objects
Dim As Object funcRefs(15)
For i = 1 To UBound(funcRefs)
    If Rnd*2 > 1 Then
        funcRefs(i) = @Emphasize
    Else
        funcRefs(i) = @Question
    End If
Next i

For i = 1 To UBound(funcRefs)
    fn = funcRefs(i)
    Print i; fn("This is a function")
Next i


Function Emphasize (s As String)
    Emphasize = s + "!!"
End Function

Function Question (s As String)
    Question = s + "?"
End Function

Sub Delegate (s As String, fnCallback As Function)
    Print fnCallback(s)
End Sub

Metacommands

QBasic and QB64 support a number of metacommands prefixed with '$' (e.g. $Include, $Dynamic). All metacommands are currently ignored by QBJS with two exceptions. Any content included between the $If Javascript Then ... $End If will be evaluated as native javascript.

Dim n as Integer
Input "Enter a number: ", n
If n > 8 Then
    $If Javascript Then
        alert("That number is too large");
    $End If
End If

Any content included within a "$If WEB Then" block will be evaluated by QBJS but ignored by QB64. This allows for web-only code blocks to be defined.

Sub FCirc (CX As Long, CY As Long, R As Long, C As _Unsigned Long)
$If WEB Then
    G2D.FillCircle CX, CY, R, C
$Else
    Dim Radius As Long, RadiusError As Long
    Dim X As Long, Y As Long
    Radius = Abs(R): RadiusError = -Radius: X = Radius: Y = 0
    If Radius = 0 Then PSet (CX, CY), C: Exit Sub
    Line (CX - X, CY)-(CX + X, CY), C, BF
    While X > Y
        RadiusError = RadiusError + Y * 2 + 1
        If RadiusError >= 0 Then
            If X <> Y + 1 Then
                Line (CX - Y, CY - X)-(CX + Y, CY - X), C, BF
                Line (CX - Y, CY + X)-(CX + Y, CY + X), C, BF
            End If
            X = X - 1
            RadiusError = RadiusError - X * 2
        End If
        Y = Y + 1
        Line (CX - X, CY - Y)-(CX + X, CY - Y), C, BF
        Line (CX - X, CY + Y)-(CX + X, CY + Y), C, BF
    Wend
$End If
End Sub

Full support of the $If, $ElseIf, $Else and $Include metacommands is planned for future inclusion.

Clone this wiki locally