Language syntax and expressions
Exact MBC-16 grammar, integer arithmetic and source limits.
Source files and line numbers
A source is a regular file whose suffix is .bas, ignoring case. Use single-byte ASCII syntax with LF or CRLF line endings. CR and tab are skipped as lexical whitespace; CR-only files do not provide statement-line boundaries. An embedded NUL is an error.
A non-empty line may begin with a decimal number from 1 to 65535. Numbers must be strictly increasing in physical source order; the compiler does not sort them. An unnumbered non-empty line receives the preceding number plus one, starting at 1. Empty lines do not consume a line-table entry.
At most 64 non-empty lines, including comment-only lines, can be compiled. Several statements can share a physical line using colons. Branches still target the start of a numbered line.
Core grammar
program = { source-line LF } [ source-line ]
source-line = [ line-number ] [ statement { ":" statement } ]
assignment = [ "LET" ] variable "=" expression
variable = "A" | "B" | ... | "Z"
line-number = decimal-integer ; 1..65535
string = DQUOTE { literal-byte } DQUOTE
DQUOTE = ASCII character 34
primary = decimal-integer | variable | "(" expression ")"
| "ABS(" expression ")" | "RND(" expression ")"
| TICKS | INKEY | HOUR | MINUTE | SECOND | EOF
unary = primary | ( "+" | "-" | "NOT" ) unary
expression = unary { binary-operator unary }This grammar summarizes the common forms; the precedence table and individual statement pages provide the remaining rules. Keywords and A–Z are case-insensitive. Literal strings and pathnames retain their case. No implicit keyword concatenation or multi-letter variable names.
Numeric representation
Variables hold signed 16-bit values, −32768 through 32767, and initialize to zero on every run. Decimal literals may encode 0 through 65535; values with bit 15 set are interpreted as negative when used or printed. A leading sign is a unary operator.
Addition, subtraction and multiplication wrap modulo 65536. Division truncates toward zero. MOD has the dividend’s sign. For example -17/5 is −3 and -17 MOD 5 is −2. Division by zero is status 37.
Comparisons return −1 for true and 0 for false. IF tests any nonzero value as true. AND, OR and NOT are bitwise operators, without short-circuit evaluation. There is no floating point, exponent notation, hexadecimal-literal notation or string arithmetic.
Operator precedence
| Binding, high to low | Operators | Notes |
|---|---|---|
| Primary | (expression), ABS(expression), RND(expression), values | Parentheses control grouping. |
| 6 | Unary +, unary -, NOT | NOT binds tightly in this dialect; parenthesize a comparison when negating its result. |
| 5 | * / MOD | Left-associative. |
| 4 | + - | Left-associative. |
| 3 | = <> < <= > >= | Same precedence; evaluated left-associatively. |
| 2 | AND | Bitwise. |
| 1 | OR | Bitwise. |
Use NOT (A=0) to negate a comparison. NOT A=0 means (NOT A)=0. Chained comparisons are arithmetic combinations of −1/0 results, not mathematical chained inequalities.
Literal strings
Only double-quoted literal strings are available, up to 95 bytes per literal. Empty literals are accepted. There is no escape convention for an embedded quote, no string variable and no concatenation operator; PRINT can place several literals or numeric expressions next to one another.
OPEN requires a literal pathname. The physical-key map in 0.6 also has limitations for entering some operator characters; see keyboard punctuation before attempting to type a new listing from scratch.
Control flow details
- IF supports only THEN followed by a literal line number, without ELSE or inline statements.
- Statements after a colon following IF are independent: on a false condition, execution proceeds to them.
- GOTO/GOSUB targets must exist; destination offsets are resolved at compile time.
- FOR/NEXT and GOSUB/RETURN share eight LIFO control frames. GOTO does not clean them up.
- END and STOP both terminate; no resumable stop state exists.
- A bare PRINT followed immediately by a colon is not accepted; use PRINT "" instead.
Compiler and runtime limits
| Resource | Bound |
|---|---|
| Variables | 26, A–Z. |
| Non-empty source lines | 64. |
| Line-number literals | 1–65535, strictly increasing. |
| Literal integer | 0–65535 before unary sign. |
| Literal string | 95 bytes. |
| Expression parser depth | 12; operators and nesting both contribute. |
| Operand stack | 16 values. |
| FOR/GOSUB stack | Eight shared frames. |
| Source editor | 1,280 bytes; the streaming compiler has a separate line limit. |
| Data files | One open in addition to the executable. |
Reserved and unsupported forms
Recognized language words are: LET, PRINT, IF, THEN, GOTO, GOSUB, RETURN, FOR, TO, STEP, NEXT, INPUT, END, STOP, REM, CLS, BEEP, WAIT, LOCATE, PSET, PRESET, LINE, SOUND, TICKS, INKEY, ABS, RND, MOD, AND, OR, NOT, OPEN, AS, LEN, GET, PUT, CLOSE, EOF, HOUR, MINUTE, SECOND, PATH, OUTPUT. Recognition in the scanner does not make every word a usable statement. AS, LEN and PATH are reserved/internal tokens without a supported source form in 0.6.
Unimplemented features include DIM/arrays, string variables, real numbers, DATA/READ/RESTORE, DEF FN, SIN/COS/LOG and other transcendental functions, RUN/LIST/SAVE/LOAD/PLAY as BASIC statements, file-number syntax, append/seek and inline IF/ELSE.