Skip to content

Language Reference

github-actions[bot] edited this page Jun 20, 2026 · 5 revisions

Language Reference

Getting Started | Next: Graphics and Multimedia


Contents


Variables and Types

Variables in nuBASIC can be declared explicitly with Dim or created implicitly on first assignment. The type suffix appended to the variable name determines its storage type.

Suffix Type Range / Notes Example
% Integer 32-bit signed, −2 147 483 648 .. +2 147 483 647 count% = 10
& Long64 64-bit signed integer big& = 10000000000
# Boolean True or False flag# = True
$ String Variable-length UTF-8 text name$ = "nuBASIC"
@ Byte 0..255; used in byte arrays buf@(255)
(none) Double 64-bit IEEE 754 floating-point pi = 3.14159

The Any type is inferred automatically from the assigned value and is useful in hash tables and generic functions.

Explicit declaration with optional type annotation:

Dim counter As Integer
Dim name    As String
Dim ratio   As Double
Dim items(99) As Integer   ' array of 100 integers (indices 0..99)
Dim flag    As Boolean

Constants are declared with Const and cannot be reassigned:

Const MAX_SIZE As Integer = 100
Const APP_NAME$ = "nuBASIC Demo"
Const PI_APPROX = 3.14159265

Operators

Arithmetic

a = 10 + 3     ' 13      — addition
a = 10 - 3     ' 7       — subtraction
a = 10 * 3     ' 30      — multiplication
a = 10 / 3     ' 3.333…  — floating-point division
a = 10 \ 3     ' 3       — integer division (truncates)
a = 10 Div 3   ' 3       — same as backslash
a = 10 Mod 3   ' 1       — remainder
a = 2 ^ 8      ' 256     — exponentiation

Increment and decrement prefixes:

++counter%     ' equivalent to: counter% = counter% + 1
--counter%     ' equivalent to: counter% = counter% - 1

Comparison

If a = b  Then ...   ' equal to
If a <> b Then ...   ' not equal to
If a < b  Then ...   ' less than
If a > b  Then ...   ' greater than
If a <= b Then ...   ' less than or equal to
If a >= b Then ...   ' greater than or equal to

Logical

If x > 0 And y > 0  Then Print "both positive"
If x = 0 Or  y = 0  Then Print "at least one zero"
If Not(flag#)        Then Print "flag is false"
result# = (a > b) Xor (c > d)

Bitwise

result = a bAnd b    ' bitwise AND
result = a bOr  b    ' bitwise OR
result = a bXor b    ' bitwise XOR
result = bNot(a)     ' bitwise NOT
result = a bShl 2    ' shift left 2 positions
result = a bShr 2    ' shift right 2 positions

Hexadecimal literals use the BASIC &h / &H prefix. 0x / 0X is also accepted as a convenience for C-style constants:

mask%   = &hFF000000
red%    = &h0000FF
white%  = &hFFFFFF
same%   = 0xFFFFFF

Control Flow

If / ElIf / Else

Single-line form:

If score% > 100 Then Print "High score!" Else Print "Keep trying"

Multi-line form:

If score% >= 90 Then
   Print "Excellent"
   grade$ = "A"
ElIf score% >= 75 Then
   Print "Good"
   grade$ = "B"
ElIf score% >= 60 Then
   Print "Passed"
   grade$ = "C"
Else
   Print "Failed"
   grade$ = "F"
End If

ElseIf is accepted as an alias for ElIf.

For / Next

' Count from 1 to 10
For i% = 1 To 10
   Print i%
Next i%

' Custom step
For x = 0.0 To 1.0 Step 0.25
   Print x
Next x

' Count down
For i% = 10 To 1 Step -1
   Print i%
Next i%

' Exit early
For i% = 1 To 1000
   If i% Mod 7 = 0 And i% Mod 11 = 0 Then
      Print "First multiple of both 7 and 11: "; i%
      Exit For
   End If
Next i%

While / Wend

While Not(EOF(filenum%))
   Input# filenum%, line$
   Print line$
Wend

While 1
   key$ = InKey$()
   If key$ = "q" Or key$ = "Q" Then Exit While
   MDelay 10
Wend

Do / Loop While

' Wait for any key press — body runs at least once
Do
   key$ = InKey$()
Loop While Len(key$) = 0

' Retry up to 10 times
Do
   ++attempts%
   result% = TryOperation()
   If result% = 0 Then Exit Do
Loop While attempts% < 10

GoTo / GoSub / Return

GoTo gameLoop

init:
   score% = 0
   lives% = 3

gameLoop:
   If lives% = 0 Then GoTo gameOver
   GoTo gameLoop

gameOver:
   Print "Game over! Score: "; score%
   End

GoSub calls a subroutine; Return jumps back to the statement after the GoSub call:

GoSub DrawScreen
GoTo mainLoop

DrawScreen:
   Cls
   FillRect 0, 0, 640, 480, &h000000
   Return

On / GoTo (Computed Branch)

On game_mode% GoTo beginner, intermediate, expert

beginner:
   mines% = 10 : GoTo setup_done
intermediate:
   mines% = 20 : GoTo setup_done
expert:
   mines% = 40
setup_done:

Select Case

Select Case dispatches on a scalar expression. Each Case arm is tested in order; the first match wins and execution continues after End Select. Case Else (optional) matches when no earlier arm does.

Select Case score%
   Case Is >= 90
      grade$ = "A"
   Case Is >= 75
      grade$ = "B"
   Case Is >= 60
      grade$ = "C"
   Case Else
      grade$ = "F"
End Select

Supported arm forms:

Form Example Matches when…
Single value Case 1 expression = 1
Value list Case 1, 3, 5 expression is any listed value
Range Case 1 To 10 1 ≤ expression ≤ 10
Comparison Case Is > 100 expression > 100
Fallback Case Else no previous arm matched

Works with integers, doubles, and strings. Select Case blocks may be nested.

' String matching
Select Case cmd$
   Case "quit", "exit", "q"
      Print "Goodbye"
      End
   Case "help", "?"
      Print "Type a command"
   Case Else
      Print "Unknown: "; cmd$
End Select

Subroutines and Functions

Sub — No Return Value

Sub ClearArea(x1%, y1%, x2%, y2%)
   FillRect x1%, y1%, x2%, y2%, &h000000
   Rect     x1%, y1%, x2%, y2%, &h404040
End Sub

Sub PrintCentered(msg$, row%, color%)
   col% = (80 - Len(msg$)) \ 2
   Locate row%, col%
   Print msg$
End Sub

ClearArea 0, 0, 640, 480
PrintCentered "Welcome to nuBASIC", 12, &hffffff

Function — Returns a Value

Function Factorial%(n%)
   If n% <= 1 Then
      Factorial% = 1
   Else
      Factorial% = n% * Factorial%(n% - 1)
   End If
End Function

Function Clamp(value, minVal, maxVal)
   If value < minVal Then
      Clamp = minVal
   ElIf value > maxVal Then
      Clamp = maxVal
   Else
      Clamp = value
   End If
End Function

Function Greeting$(name$)
   Greeting$ = "Hello, " + name$ + "! Welcome to nuBASIC."
End Function

Print Factorial%(12)
Print Clamp(1.5, 0.0, 1.0)
Print Greeting$("World")

ByRef and ByVal

Parameters are by value (ByVal) by default — the procedure receives a copy and changes do not affect the caller. Prefix a parameter with ByRef to pass by reference: mutations inside the procedure propagate back to the caller's variable.

Sub Swap(ByRef a% As Integer, ByRef b% As Integer)
   Dim tmp% As Integer
   tmp% = a% : a% = b% : b% = tmp%
End Sub

Dim x% As Integer, y% As Integer
x% = 7 : y% = 42
Call Swap(x%, y%)
Print x%, y%   ' 42   7

Struct variables can also be passed ByRef:

Sub Translate(ByRef p As Point, dx As Double, dy As Double)
   p.x = p.x + dx
   p.y = p.y + dy
End Sub

Call keyword

Call is an optional keyword before any Sub/Function invocation. When used, arguments must be enclosed in parentheses:

Call ClearArea(0, 0, 640, 480)   ' same as: ClearArea 0, 0, 640, 480

Open-ended Array Parameters

A Sub or Function may declare a parameter with empty parentheses (param() As Type) to accept an array of any size. This lets you write generic procedures without fixing the dimension in the signature:

Sub PrintAll(items() As String)
   Dim i% As Integer
   For i% = 0 To SizeOf(items) - 1
      Print items(i%)
   Next i%
End Sub

Dim names$(2)
names$(0) = "Alice" : names$(1) = "Bob" : names$(2) = "Carol"
Call PrintAll(names$())

Include directive

Include "filename.bas" (also #Include) loads and executes another source file at the point of the directive — useful for splitting programs across multiple files:

Include "utils.bas"
Call DrawBorder(0, 0, 639, 479)

Classes and Objects

Object-oriented programming is new in nuBASIC 2.0 — earlier versions had only Struct value types. Classes are available in Modern syntax mode only: a program that defines a Class must begin with Syntax Modern, otherwise the parser reports 'Class' requires Syntax Modern.

Classes group related data (fields) and behaviour (methods) into a single type. Declare a class with Class/End Class; create instances with Dim:

Syntax Modern

Class Counter
   Public count As Integer

   Sub Reset()
      Me.count = 0
   End Sub

   Sub Increment()
      Me.count = Me.count + 1
   End Sub

   Function Value() As Integer
      Value = Me.count
   End Function
End Class

Dim c As Counter      ' default-constructed instance
Call c.Reset()
Call c.Increment()
Call c.Increment()
Print c.Value()       ' 2

Me refers to the current instance inside an instance method.

Constructors and New

A Sub New(...) member is the constructor — it runs when an instance is created. Pass constructor arguments either with the Dim … As New declaration form or with a New expression:

Syntax Modern

Class Point
   Public x As Double
   Public y As Double
   Sub New(px As Double, py As Double)
      Me.x = px
      Me.y = py
   End Sub
   Function Length() As Double
      Length = Sqr(Me.x * Me.x + Me.y * Me.y)
   End Function
End Class

Dim p As New Point(3.0, 4.0)     ' construct with arguments
Print p.Length()                 ' 5

' New is also a first-class expression: it can be assigned, passed as an
' argument, returned from a function, or used inline.
Dim q As Point
q = New Point(1.0, 2.0)
Print New Point(6.0, 8.0).Length()   ' 10

A class without a Sub New is default-constructed (Dim c As Counter above). A class may also define Sub Delete() — see Destructors.

Object reference semantics and Nothing

Class instances are reference types, unlike Struct values (which are copied). Assigning one object variable to another makes both refer to the same instance, so a mutation through one is visible through the other:

Syntax Modern

Dim a As New Counter
Dim b As Counter
b = a              ' a and b now reference the same object
Call a.Increment()
Print b.Value()    ' 1  — same instance

If b = a Then Print "same object"   ' reference comparison

Dim empty As Counter
empty = Nothing    ' a null object reference
If empty = Nothing Then Print "no object"

Calling a method on a Nothing reference raises a null-reference runtime error.

Static Methods

Static Function and Static Sub inside a Class body define class-level procedures. They do not receive an implicit instance and cannot access Me. Call them with ClassName.Method(args) — no instance required:

Class MathHelper
   Static Function Add(a As Integer, b As Integer) As Integer
      Add = a + b
   End Function

   Static Sub PrintSum(a As Integer, b As Integer)
      Print "Sum ="; a + b
   End Sub
End Class

Dim result% As Integer
result% = MathHelper.Add(3, 7)   ' 10
MathHelper.PrintSum 2, 3          ' Sum = 5

Static and instance methods may coexist in the same class.

Destructors

A class may define Sub Delete() as a destructor. nuBASIC calls it automatically on owned local class instances when the procedure scope exits, in reverse declaration order; in a derived class the derived destructor runs before the base destructor.

Class Resource
   Public name$ As String
   Sub New(n$ As String)
      Me.name$ = n$
   End Sub
   Sub Delete()
      Print "closing "; Me.name$
   End Sub
End Class

Access modifiers

Modifier Where the member is reachable
Public Everywhere (default)
Protected Inside the declaring class and any derived class
Private Only inside the declaring class

Visibility is enforced at compile time.

Inheritance, Overrides, and MyBase

Class Shape
   Overridable Function Describe$() As String
      Describe$ = "a shape"
   End Function
End Class

Class Circle
   Inherits Shape

   Public radius As Double

   Overrides Function Describe$() As String
      Describe$ = MyBase.Describe$() + " (radius " + Str$(Me.radius) + ")"
   End Function
End Class

A call through a base-class reference dispatches dynamically to the most-derived Overrides implementation (virtual dispatch); MyBase.Member(...) is the way to reach the base version explicitly.

Rules: Overrides must match the base Overridable method's full signature (Sub vs Function, return type, parameter count, parameter types, ByRef/ByVal); MyBase.Member(...) is allowed only inside an instance method and dispatches explicitly to the immediate base class.


main() Entry Point

If a Function named main is defined in the program, the interpreter calls it as the entry point instead of executing from the first statement. The function must return an Integer (used as the process exit code). Three signatures are supported:

' No arguments
Function main() As Integer
   Print "Hello from main"
   main = 0
End Function

' Argument count only
Function main(argc As Integer) As Integer
   Print "argc ="; argc
   main = 0
End Function

' Full argc / argv
Function main(argc As Integer, argv() As String) As Integer
   Dim i% As Integer
   Print "Script: "; argv(0)
   For i% = 1 To argc - 1
      Print "  arg "; i%; " = "; argv(i%)
   Next i%
   main = 0
End Function

argc equals 1 plus the number of extra command-line arguments. argv(0) is the script filename; argv(1) through argv(argc-1) are the additional arguments supplied on the command line after the script name:

nubasic -t -e myprog.bas hello world
' → argc = 3, argv(0)="myprog.bas", argv(1)="hello", argv(2)="world"

When main is defined inside an Included file, the entry-point behaviour is suppressed in that file — only the top-level program's main is used.


Namespaced Modules

In Modern syntax mode (Syntax Modern), built-in functions are organised into named modules and can be called with a qualified name (module::function). Legacy programs continue to work with Syntax Legacy (the default).

Syntax Modern

' Qualified calls
Dim s As Double
s = math::sin(0.0)
Dim h$ As String
h$ = string::left$("Hello", 2)   ' "He"
Dim n% As Integer
n% = runtime::sizeof(myArray)

Using — Import a Module

Using ModuleName imports all names from a module into the current scope so they can be called without qualification:

Syntax Modern
Using math
Using string

Dim v As Double
v = Sin(0.785398)          ' math::sin without prefix
Dim s$ As String
s$ = Left$("World", 3)     ' string::left$ without prefix

Switching Modes

Syntax Legacy restores the classic single-namespace mode. The directive can appear anywhere in a file; each Included file honours the mode active at its include site.

Syntax Legacy
' All classic global names work as before
Print Len("abc")    ' 3
Print Sin(0)        ' 0

Structures

Struct Vector2D
   x As Double
   y As Double
End Struct

Struct Sprite
   pos    As Vector2D
   width% As Integer
   height% As Integer
   name$  As String
End Struct

Dim hero As Sprite
hero.pos.x   = 100.0
hero.pos.y   = 200.0
hero.width%  = 32
hero.height% = 48
hero.name$   = "Hero"

Print "Sprite "; hero.name$; " at ("; hero.pos.x; ", "; hero.pos.y; ")"

Arrays of structures:

Dim enemies(10) As Sprite
enemies(0).name$ = "Goblin"
enemies(0).pos.x = 50

Built-in Struct Types

The interpreter pre-registers two struct types that are available without any Struct definition in your program:

DateTime — returned by GetDateTime(), holds all date/time fields:

Field Type Description
year Integer Full year (e.g. 2026)
month Integer Month 1–12
day Integer Day of month 1–31
hour Integer Hour 0–23
minute Integer Minute 0–59
second Integer Second 0–59
wday Integer Day of week: 0=Sunday … 6=Saturday
yday Integer Day of year 0–365
Dim dt As DateTime
dt = GetDateTime()
Print dt.year; "/"; dt.month; "/"; dt.day; "  "; dt.hour; ":"; dt.minute

Mouse — returned by GetMouse(), holds all pointer state (full build only):

Field Type Description
x Integer Cursor X in pixels from left edge
y Integer Cursor Y in pixels from top edge
btn Integer Button mask: 0=none, 1=left, 2=middle, 4=right
Dim m As Mouse
m = GetMouse()
If m.btn = 1 Then Print "Left click at "; m.x; ", "; m.y

Arrays

Dim scores%(9)      ' 10 integers, indices 0..9
Dim names$(4)       ' 5 strings, indices 0..4
Dim data(99)        ' 100 doubles, indices 0..99

Access and assignment:

scores%(0) = 95
scores%(1) = 87

total% = 0
For i% = 0 To 9
   total% = total% + scores%(i%)
Next i%
Print "Average: "; total% / 10

ReDim resizes an existing array (clears content):

size% = 100
ReDim scores%(size% - 1)

Byte arrays for binary data:

Dim buf@(1023)
buf@(0) = 65
Print Chr$(buf@(0))   ' A

Multi-dimensional data (manual row-major indexing):

Const W% = 10
Dim grid%(W% * W% - 1)
grid%(2 * W% + 3) = 42   ' element at row=2, col=3

Hash Tables

' Insert or update entries
HSet "config", "width",     800
HSet "config", "height",    600
HSet "config", "title$",    "My Game"
HSet "config", "fullscreen#", False

' Retrieve values
w% = HGet%("config", "width")
t$ = HGet$("config", "title$")
Print t$; " — "; w%

' Check whether a key exists
If HChk("config", "fullscreen#") Then
   fs# = HGet#("config", "fullscreen#")
End If

' Count entries
Print "Config entries: "; HCnt("config")

' Delete a single key
HDel "config", "fullscreen#"

' Delete the entire table
HDel "config"

File I/O

Sequential Text Files

' Write
Open "notes.txt" For Output As #1
Print# 1, "First line"
Print# 1, "Second line"
Close #1

' Read line by line
Open "notes.txt" For Input As #2
While Not(EOF(2))
   Input# 2, line$
   Print line$
Wend
Close #2

' Append
Open "notes.txt" For Append As #1
Print# 1, "New entry at " + SysTime$()
Close #1

Binary and Random Access

' Write raw bytes
FOpen "data.bin", "wb", 1
Dim buf@(3)
buf@(0) = &hDE : buf@(1) = &hAD : buf@(2) = &hBE : buf@(3) = &hEF
Print# 1, buf@
Close #1

' Seek and read
FOpen "data.bin", "rb", 2
Seek 2, 2, 2
Read# 2, b@, 1
Print "Byte at offset 2: "; Hex$(b@)
Close #2

Diagnostic functions:

pos%  = FTell(1)    ' current byte offset
size% = FSize(1)    ' total file size in bytes
err%  = FError(1)   ' non-zero if error occurred
at_end% = EOF(1)    ' 1 if at end of file

File System Operations

MkDir("saves")
RmDir("saves/old")
Erase("temp.txt")
Print Pwd$()
ChDir ".."

DATA, READ, RESTORE

' Embed a color palette
Data "red",    &hFF0000
Data "green",  &h00FF00
Data "blue",   &h0000FF
Data "yellow", &hFFFF00
Data "white",  &hFFFFFF

' Read sequentially
For i% = 0 To 4
   Read name$, color%
   FillRect i%*60, 10, i%*60+50, 60, color%
   TextOut  i%*60+5, 70, name$, &hFFFFFF
Next i%

' Rewind to start
Restore
Read first_name$, first_color%

' Jump to specific position (0-based)
Restore 2
Read name$, color%

' Clear the data store
Restore -1

String Handling

Measuring and Slicing

s$ = "Hello, World!"

Print Len(s$)           ' 13
Print Left$(s$, 5)      ' "Hello"
Print Right$(s$, 6)     ' "World!"
Print Mid$(s$, 8, 5)    ' "World"   (1-based)
Print SubStr$(s$, 7, 5) ' "World"   (0-based)

Searching

Print InStr("Hello World", "world")     ' 7  (case-insensitive)
Print InStr("Hello World", "xyz")       ' -1 (not found)
Print InStrCS("Hello World", "World")   ' 7  (case-sensitive)
Print InStrCS("Hello World", "world")   ' -1

Modifying and Building

board$ = ".........."
board$ = PStr$(board$, 3, "*")   ' "..*......."
board$ = PStr$(board$, 7, "F")   ' "..*.....F."

Case and Character Conversion

Print UCase$("hello")    ' "HELLO"
Print LCase$("WORLD")    ' "world"
Print Asc("A")           ' 65
Print Chr$(65)           ' "A"
Print Spc(4)             ' "    "

Numeric Conversions

n% = Val%("42")
x  = Val("3.14")
Print Str$(3.14)          ' "3.14"
Print Hex$(255)           ' "FF"
Print StrP$(3.14159, 4)   ' "3.142"

Escape Sequences and Unicode

Standard escape sequences:

Print "Column1\tColumn2\tColumn3"
Print "Line 1\nLine 2"

Unicode characters with $u prefix:

Print $u, "Caf\u00e9 — \u00e0 \u00e8 \u00ec"   ' Café — à è ì
Print $u, "\u03b1 \u03b2 \u03b3"               ' α β γ  (Greek)
Print $u, "\u4e2d\u6587"                        ' 中文

Dynamic Evaluation

x = 5
expr$ = "x * x + 2 * x + 1"
Print Eval(expr$)       ' 36

Native Library Calls

On Windows, Linux, and macOS nuBASIC can declare and call exported functions from native shared libraries. Loading uses LoadLibraryW on Windows and dlopen(RTLD_LAZY|RTLD_LOCAL) on Linux/macOS; invocation is backed by libffi on every platform.

Syntax Modern

' Windows
Declare Function GetCurrentProcessId Lib "kernel32.dll" () As DWORD
Print GetCurrentProcessId()
Syntax Modern

' Linux (glibc)
Declare Function strlen Lib "libc.so.6" (text As String) As Integer
Print strlen("hello")    ' prints 5
Syntax Modern

' macOS
Declare Function strlen Lib "libSystem.B.dylib" (text As String) As Integer
Print strlen("hello")    ' prints 5

The declaration form is:

Declare Function name Lib "library" _
    [Alias "export"] _
    [CallConv "default" | "cdecl" | "stdcall"] _
    (param As NativeType, ...) As NativeType

Supported native types: Integer, DWORD, Long64, ULong64, Double, Bool, Pointer, String, and Void. String maps to a narrow const char*; use Pointer for mutable buffers and manually laid-out structures, together with the runtime module helpers (NativeAlloc, NativeFree, NativePoke*, NativePeekStr$).

Native calls are enabled by default on trusted local hosts and can be disabled with --disable-native-calls. See the full guide in docs/native-dll-calls.md and the worked example examples/native_open_file_dialog.bas.


Getting Started | Next: Graphics and Multimedia

Clone this wiki locally