-
Notifications
You must be signed in to change notification settings - Fork 10
QBasic Language Support
QBJS supports a large subset of the QBasic and QB64 syntax as well as native support for the GX API.
The following standard keywords are currently implemented: Supported Keywords.
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.
- All variables must be declared
- 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
- Functions can return arrays and custom types
- Functions do not require type suffix to return non-single values
- QBJS takes advantage of flexible typing
- Support for associative arrays (i.e. hashtable, dictionary)
- Inline javascript
- Support for HTML DOM manipulation, event handling and standard web dialogs
- Support for browser local and session storage
- Support for Import of external modules. See Import / Export.
Outstanding issues and requested features are tracked here:
https://github.com/boxgaming/qbjs/issues
All variables must be declared with a DIM or REDIM statement. Errors may occur if a variable is referenced before it is declared.
Static variables are not currently supported but this is planned.
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
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
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
- All mathematical operators are supported with the exception of the integer division operator ( \ ). At present integer division operators are just evaluated as a normal division ( / ) operation.
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")
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.