Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
8fb9f27
Take every statement after THEN in a single-line IF
jgarzik Aug 16, 2026
d01b915
Accept a line number after THEN and ELSE as an implied GOTO
jgarzik Aug 16, 2026
5374bdc
Refuse a DO loop that tests its condition at both ends
jgarzik Aug 16, 2026
4e25a3c
Stop guessing at a bad line number, and drop three lexer oddities
jgarzik Aug 16, 2026
606c1c1
Bound recursion depth instead of overflowing the stack
jgarzik Aug 16, 2026
ae4aad4
Carry block terminators in the return type, not the error channel
jgarzik Aug 16, 2026
75303bd
Quote BASIC in diagnostics, not Rust variant names
jgarzik Aug 16, 2026
c3790b6
Report every syntax error, not just the first
jgarzik Aug 16, 2026
0b87d2c
Resolve array-versus-call in sema, not by guessing in the parser
jgarzik Aug 16, 2026
b27ac31
State the identifier uppercase invariant once, and check it
jgarzik Aug 16, 2026
801471c
Build assembly text in place: 17% faster, 20% less memory
jgarzik Aug 16, 2026
bcec60a
Hoist the duplicated field-path loop, and fuzz the front end
jgarzik Aug 16, 2026
cea534d
Make the bitwise operators actually bitwise
jgarzik Aug 16, 2026
a2d1aef
Make operator precedence match LANGREF's own table
jgarzik Aug 16, 2026
1a9e89c
Check the NEXT control variable, and let one NEXT close several loops
jgarzik Aug 16, 2026
6176bde
Take DATA items as written, not as tokens
jgarzik Aug 16, 2026
3474922
Convert a numeric DATA item when it is READ into a string
jgarzik Aug 16, 2026
4269a39
Print the question mark INPUT was always documented to print
jgarzik Aug 16, 2026
e991aa8
Four front-end fixes: overflow, continuation, THEN-colon, cascades
jgarzik Aug 16, 2026
0afba49
Diagnose RETURN without GOSUB, and accept CALL
jgarzik Aug 16, 2026
4800a34
Guard the file helpers that hand a NULL handle to libc
jgarzik Aug 16, 2026
acf4d76
Report the file errors that were being swallowed
jgarzik Aug 16, 2026
1ba3d69
Fix the Windows job, and stop the tests littering the repo root
jgarzik Aug 16, 2026
537dcf6
Narrow the value when READ, INPUT or SWAP stores it
jgarzik Aug 16, 2026
f16aa0f
Make STRING * n actually fixed-length
jgarzik Aug 16, 2026
34ea3e5
Reject arguments the string and power builtins cannot answer
jgarzik Aug 16, 2026
b2007d3
Range-check CHR$, SPACE$ and STRING$, and make DIM's suffix agree wit…
jgarzik Aug 16, 2026
1566b42
Align the stack in the MID$ and INSTR call sequences
jgarzik Aug 16, 2026
9677865
Widen the generated-code alignment check
jgarzik Aug 16, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 90 additions & 5 deletions LANGREF.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,16 @@ Multiple statements can appear on one line separated by colons:
A = 1 : B = 2 : PRINT A + B
```

### Line Continuation

A trailing underscore joins a statement to the next line. Nothing may follow it
on the line it ends:

```basic
Total = Price * Quantity + _
Shipping
```

### Block Terminators

Each multi-line block may be closed with either the two-word form or a single
Expand Down Expand Up @@ -260,13 +270,21 @@ case-sensitive and a prefix sorts before the longer string (`"ab" < "abc"`).
| `XOR` | Bitwise/logical XOR |
| `NOT` | Bitwise/logical NOT |

These operate bitwise on integers, allowing both logical tests and bit manipulation:
These operate bitwise on integers, allowing both logical tests and bit
manipulation. Their operands are converted to integers first, and the result is
an integer:

```basic
IF A > 0 AND B > 0 THEN PRINT "Both positive"
Flags% = Flags% OR &H01 ' Set bit 0
Mask% = NOT &H00FF ' -256: every bit flipped
```

`NOT` complements every bit, so `NOT 1` is `-2`, which is non-zero and therefore
*true*. This matters only when testing a value that is not already a truth
value: comparisons yield -1 or 0, and `NOT` maps those to each other, so
`IF NOT (A > 0)` behaves as expected while `IF NOT 1` does not.

### String Concatenation

```basic
Expand All @@ -287,6 +305,9 @@ From highest to lowest:

Because `^` binds tighter than unary negation, `-2 ^ 2` is `-(2 ^ 2)` = -4.

Operators of equal precedence associate left to right, `^` included: `2 ^ 3 ^ 2`
is `(2 ^ 3) ^ 2` = 64, and `100 - 10 - 5` is 85.

Use parentheses to override precedence:
```basic
Result = (A + B) * C
Expand Down Expand Up @@ -382,10 +403,24 @@ Read user input:

```basic
INPUT X ' Prompt with "? "
INPUT "Enter name: ", N$ ' Custom prompt
INPUT "Enter name: "; N$ ' Prints: Enter name: ?
INPUT "Enter name: ", N$ ' Prints: Enter name:
INPUT "X, Y: ", X, Y ' Multiple values
```

The separator decides the question mark: a `;` after the prompt adds `? `, a
`,` suppresses it, and a prompt-less `INPUT` prints `? ` on its own.

A `;` *before* the prompt is accepted and ignored:

```basic
INPUT ; "Enter name: "; N$
```

In GW-BASIC it suppressed the newline echoed when the operator pressed Return.
That newline comes from the terminal here rather than from the program, so
there is nothing for it to suppress.

### LINE INPUT

Read entire line as string (no parsing):
Expand All @@ -394,6 +429,9 @@ Read entire line as string (no parsing):
LINE INPUT "Enter text: ", Text$
```

`LINE INPUT` never adds a question mark; write one into the prompt if you want
one.

### IF...THEN...ELSE

**Single-line form:**
Expand All @@ -402,6 +440,23 @@ IF X > 0 THEN PRINT "Positive"
IF X > 0 THEN Y = 1 ELSE Y = 0
```

Both branches take a list of statements separated by colons. Everything after
`THEN` up to `ELSE` or the end of the line is conditional, and everything after
`ELSE` is too:

```basic
IF X > 0 THEN Y = 1 : PRINT "Positive" ELSE Y = 0 : PRINT "Not positive"
```

A bare line number after `THEN` or `ELSE` is an implied `GOTO`:

```basic
10 IF X < 0 THEN 90
20 IF X = 0 THEN 90 ELSE 80
80 PRINT "Positive"
90 PRINT "Done"
```

**Block form:**
```basic
IF X > 0 THEN
Expand Down Expand Up @@ -454,13 +509,24 @@ FOR K = 0 TO 1 STEP 0.1
NEXT K
```

The loop variable name after `NEXT` is optional:
The loop variable name after `NEXT` is optional, and a bare `NEXT` closes the
innermost open loop:
```basic
FOR I = 1 TO 10
PRINT I
NEXT
```

If the name *is* given it must be the one that loop counts, so `FOR I ... NEXT J`
is an error rather than a loop closed by surprise. One `NEXT` may close several
nested loops, innermost first:
```basic
FOR I = 1 TO 3
FOR J = 1 TO 3
PRINT I * J
NEXT J, I
```

### WHILE...WEND

Pre-test loop:
Expand Down Expand Up @@ -577,6 +643,18 @@ RESTORE ' Reset data pointer to beginning
RESTORE 100 ' Resume at the DATA on line 100
```

A DATA item needs quotes only if it contains a comma, a colon, or spaces that
matter. Otherwise write it plainly; surrounding spaces are trimmed and the text
is taken exactly as written, case included. An omitted item reads as 0 or `""`:

```basic
DATA hello, World, "a,b", " padded "
DATA 1,,3
```

A colon ends a DATA statement, so another statement may follow it on the same
line.

### CLS

Clear screen:
Expand Down Expand Up @@ -925,7 +1003,10 @@ blanks and line breaks, so several fields may come from one line and one
field may span several. A field wrapped in quotes may contain commas.
`LINE INPUT #` takes a whole line, commas and all.

`EOF()` gives the usual read-until-the-end loop:
Reading past the end of a file is an error (`Input past end of file`), as is
opening a file that is not there (`File not found`) or re-using a file number
that is still open (`File already open`). `EOF()` gives the usual
read-until-the-end loop:

```basic
OPEN "data.txt" FOR INPUT AS #1
Expand Down Expand Up @@ -1080,9 +1161,13 @@ END SUB

' Call the subroutine
PrintGreeting "World"
PrintGreeting("World") ' Parentheses optional
PrintGreeting("World") ' Parentheses optional
CALL PrintGreeting("World") ' CALL is accepted too
```

`CALL` is recognised only before a name at the start of a statement, so a
program may still use it as a variable.

### FUNCTION

Procedures that return a value:
Expand Down
Loading
Loading