PILOT is a lightweight educational language embedded within PowerBASIC via #PCODE/#END PCODE blocks. Each PILOT command is lowered to PowerBASIC statements and then compiled to native x64 machine code. PILOT provides a simple command set for text-based interactive programs: type output (T:), accept input (A:), pattern matching (M:), conditional branching (Y:/N:, J:, U:), computation (C:), and flow control (J:, E:).
#PCODE ... #END PCODEprogram.pilot — top-level PILOT source fileT: A: M: Y: N: C: J: U: E: R: S:
In V11, a .pilot file can be compiled directly without wrapping in #PCODE/#END PCODE blocks. The compiler auto-generates the necessary PBMAIN wrapper. This makes PILOT a first-class compile target.
Every command that produces a match result (T:, Y:, N:, J:, U:) now supports conditional suffixes that test the match flag before executing:
| Suffix | Meaning | Example |
|---|---|---|
TY: | Execute if match is TRUE | TY: Correct! — print only if last M: matched |
TN: | Execute if match is FALSE | TN: Wrong, try again — print only if last M: failed |
JY: | Jump if match is TRUE | JY: *CORRECT — jump to CORRECT if matched |
JN: | Jump if match is FALSE | JN: *WRONG — jump to WRONG if not matched |
UY: | Conditional use if match TRUE | UY: score>=3: *WIN — test condition only if matched |
UN: | Conditional use if match FALSE | UN: score>=10: *QUIT — test condition only if not matched |
The T: (Type) command now supports parenthesized conditional expressions. If the expression evaluates to FALSE, the text output is suppressed:
T(#x>=0): Score is non-negative ' only prints if #x >= 0 T(#count=1): There is 1 item ' only prints if #count = 1
The M: command now accepts multiple patterns separated by commas. The match result is TRUE if any pattern matches. Each matched group is captured:
M: YES, Y, OK, SURE ' matches any of these four responses
After a successful M: with wildcards, three special variables contain the matched portions:
| Variable | Content |
|---|---|
$MATCH | The full substring that matched the pattern |
$LEFT | The text to the left of the first wildcard match |
$RIGHT | The text to the right of the first wildcard match |
M: *IS* A: Enter something with IS: T: Matched: $MATCH, Left: $LEFT, Right: $RIGHT
The U: (Use) command with a label target (*LABEL) now performs a GOSUB (call with return) instead of a GOTO:
U: score>=3: *BONUS ' calls subroutine BONUS, returns here T: Back from bonus round
The A: (Accept) command now accepts multiple comma-separated variables in a single command:
A: $NAME, #AGE, $CITY ' reads three values on one line
| PILOT | Generated PowerBASIC | Generated ASM Pattern |
|---|---|---|
T: text $var #num |
PRINT "text "; var$; " "; num# |
See PRINT (WriteFile) |
A: |
INPUT a$ |
See Console INPUT (ReadFile) |
A: $NAME |
INPUT name$ |
ReadFile + assign to named string variable |
A: #COUNT |
INPUT tmp$ : count# = VAL(tmp$) |
ReadFile + string-to-number conversion |
A: $NAME, #AGE, $CITY |
INPUT name$ : INPUT age# : INPUT city$ |
V11 Sequential ReadFile for multiple targets |
M: YES |
match = (TRIM$(UCASE$(a$)) = "YES") |
String comparison via memcmp |
M: Y* |
match = (LEFT$(TRIM$(UCASE$(a$)), 1) = "Y") |
Prefix check after case normalization |
M: *ING |
match = (RIGHT$(TRIM$(UCASE$(a$)), 3) = "ING") |
Suffix check |
M: *ORL* |
match = (INSTR(TRIM$(UCASE$(a$)), "ORL") > 0) |
Substring search |
M: * |
match = 1 |
Always true |
M: 42 |
match = (#A = 42) |
CMP + SETcc for numeric equality |
M: #EXPECTED |
match = (#A = #EXPECTED) |
CMP with numeric variables |
M: $EXPECTED |
match = (TRIM$(UCASE$(a$)) = TRIM$(UCASE$(expected$))) |
String comparison |
M: PAT1, PAT2, PAT3 |
match = (match1 OR match2 OR match3) |
V11 Multi-pattern OR combination |
Y: text $var #num |
IF match THEN PRINT "text "; var$; " "; num# |
Conditional jump around PRINT code |
Y: *LABEL |
IF match THEN GOTO LABEL |
Conditional JMP |
TY: text |
IF match THEN PRINT "text" |
V11 Y: alias (match-true type) |
TN: text |
IF NOT match THEN PRINT "text" |
V11 N: alias (match-false type) |
JY: *LABEL |
IF match THEN GOTO LABEL |
V11 Conditional JMP on match TRUE |
JN: *LABEL |
IF NOT match THEN GOTO LABEL |
V11 Conditional JMP on match FALSE |
N: text $var #num |
IF NOT match THEN PRINT "text ... |
Inverted conditional jump |
N: *LABEL |
IF NOT match THEN GOTO LABEL |
Inverted conditional JMP |
C: score = score + 1 |
score# = score# + 1 |
Standard assignment + arithmetic |
C: name = $A |
name$ = a$ |
String assignment |
J: *LABEL |
GOTO LABEL |
jmp __pb_label_xxx_LABEL |
U: score>=3: *WIN |
IF score# >= 3 THEN GOTO WIN |
CMP + conditional JMP |
U: score>=3: You win! |
IF score# >= 3 THEN PRINT "You win!" |
CMP + conditional around PRINT |
U: score>=3: *BONUS |
IF score# >= 3 THEN GOSUB BONUS |
V11 CMP + CALL (not JMP) |
UY: score>=3: *WIN |
IF match AND score# >= 3 THEN GOTO WIN |
V11 Match AND condition |
UN: score>=10: *QUIT |
IF NOT match AND score# >= 10 THEN GOTO QUIT |
V11 NOT match AND condition |
E: |
GOTO EndOfPilotBlock_N |
jmp __pb_pilot_end_N |
R: comment |
PB comment | No ASM generated |
S: DRAW 50 |
PB comment | No ASM generated (no-op) |
*LABEL |
__pb_pilot_blockN_LABEL: |
ASM label definition |
; PILOT variables are prefixed internally to prevent collisions: $A -> a$ (string variable) #A -> a# (numeric variable from VAL) $NAME -> pilot_block1_NAME$ (block-scoped string) #SCORE -> pilot_block1_SCORE# (block-scoped numeric) *LOOP -> __pb_pilot_block1_LOOP (block-scoped label) ; V11 match capture variables: $MATCH -> pilot_block1_MATCH$ (matched substring) $LEFT -> pilot_block1_LEFT$ (text left of wildcard) $RIGHT -> pilot_block1_RIGHT$ (text right of wildcard)
; Each #PCODE block generates: ; 1. LOCAL declarations for all PILOT variables ; 2. Lowered PB statements for each PILOT command ; 3. An end-of-block label for E: command target ; 4. Unique prefix ensures no name clashes between blocks ; ; V11: Standalone .pilot files auto-generate the #PCODE wrapper ; and PBMAIN entry point. Variables are scoped per file. ; ; V11: T(#expr): conditions emit CMP/TEST before the PRINT code ; with a conditional jump to skip output if the expression is FALSE. ; ; V11: U:*LABEL emits CALL instead of JMP for subroutine semantics. ; V13: PILOT restoration brings back D:, GR:, SO: (no-op comments ; for Atari-style display/graphic/sound commands) and #POS state ; variable tracking. All V10/V11 features retained. ; ; V13: Standalone .pilot/.pil/.plt/.pcode files compile via ; auto-generated PB wrapper with PBMAIN entry point.
V13 restores the full PILOT layer that was introduced in V10/V11, including newly covered commands and state variables:
D: x, y, "text" | D: CLEARAtari-style display positioning command. Accepted as a no-op comment for compatibility. Future graphics runtime will render text at screen coordinates.
GR: mode | GR: DRAW x1,y1 TO x2,y2Atari-style graphics mode and drawing commands. Accepted as no-op comments. Turtle graphics and screen rendering are deferred to a future runtime.
SO: freq, duration | SO: NOTE "C4", 100Atari-style sound/music command. Accepted as a no-op comment. Audio output is deferred to a future runtime.
#POS (read-only numeric variable)After a successful M: pattern match, #POS contains the 1-based character position where the match was found in the input string. Returns 0 if no match.
M: *HELLO* Y: Found at position #POS!
| Command | V10 | V11 | V13 | Description |
|---|---|---|---|---|
| T: | Yes | Yes | Yes | Type (print) |
| A: | Yes | Yes | Yes | Accept (input) |
| M: | Yes | Yes | Yes | Match pattern |
| Y: | Yes | Yes | Yes | Yes (match success) |
| N: | Yes | Yes | Yes | No (match failure) |
| C: | Yes | Yes | Yes | Compute (assign) |
| J: | Yes | Yes | Yes | Jump (goto) |
| U: | Yes | Yes | Yes | Use (conditional) |
| E: | Yes | Yes | Yes | End block |
| R: | Yes | Yes | Yes | Remark (comment) |
| S: | Yes | Yes | Yes | Screen (no-op) |
| D: | -- | -- | Yes | Display (no-op) |
| GR: | -- | -- | Yes | Graphic (no-op) |
| SO: | -- | -- | Yes | Sound (no-op) |
| TY:/TN: | -- | Yes | Yes | Conditional type |
| JY:/JN: | -- | Yes | Yes | Conditional jump |
| UY:/UN: | -- | Yes | Yes | Conditional use |
| T(#expr): | -- | Yes | Yes | Parenthesized condition |
| $MATCH | -- | Yes | Yes | Matched text variable |
| $LEFT | -- | Yes | Yes | Left of match |
| $RIGHT | -- | Yes | Yes | Right of match |
| #POS | -- | -- | Yes | Match position |