Lexical structure¶
Tokens¶
BPP+ recognizes the following token types:
- Label definitions:
<identifier>: - Label references:
<identifier>or<scope-path>.<identifier> - Scope delimiters:
{} - Statement separator:
: - Line continuation:
\ - Comments:
rem <text>or; <text> - Directives:
!include <type> "<path>"or!blitz <directive> - Extension marker:
::(Blitz! runtime interpretation) - Build tokens:
{builddate},{buildtime},{buildstamp} - String literals: Quoted text including empty strings
"" - BASIC keywords: All standard BASIC v2 keywords (preserved as-is)
Identifier syntax¶
identifier := [a-zA-Z_][a-zA-Z0-9_]*
Constraints¶
- Must start with alphabetic character or underscore
- May contain alphanumeric characters and underscores
- Case-insensitive (normalized to lowercase internally)
- Cannot be BASIC v2 reserved keywords
- No hyphens or special characters permitted
Valid identifiers¶
main
loop_1
_private
playerX
INIT_SCREEN
Invalid identifiers¶
1main rem starts with digit
player-x rem contains hyphen
init$ rem contains special character
for rem BASIC keyword
@label rem starts with special character
Comments¶
Two comment syntaxes supported:
rem This is a BASIC comment (stripped from output)
; This is a BPP+ comment (stripped during preprocessing)
Comment syntax rules¶
REM comments¶
- Must match pattern:
remfollowed by space, then comment text rem foo→ removed from outputrem **→ preserved (Blitz! directive, requires space before**)rem **→ preserved (multiple spaces OK)rem**→ removed (no space before**)
Semicolon comments¶
- Start with
;character - Always removed during preprocessing
- No exceptions (cannot be preserved like Blitz! directives)
Comment placement¶
Important¶
Both REM and ; comments can only appear as separate statements, not inline after code:
rem CORRECT: Comment as separate statement
poke 53280,0
gosub main
rem CORRECT: Comment on its own line with colon separator
poke 53280,0: rem set border color
rem WRONG: This causes a SYNTAX ERROR in BASIC v2!
poke 53280,0 rem this will fail
rem WRONG: Semicolon also cannot be inline
poke 53280,0 ; this will also fail
Why the colon works¶
In BASIC v2, the colon (:) is a statement separator. So poke 53280,0: rem comment is actually two statements: poke 53280,0 and rem comment.
BPP+ preprocessing¶
BPP+ removes both rem and ; comments during preprocessing (except Blitz! rem ** directives), so they never appear in the final .bas output.
Comments and Line Continuation
Do NOT use REM or ; comments with line continuation (\). This causes unexpected behavior. See Comments and line continuation for details.
Exception¶
Special rem ** directives for Blitz! compiler are preserved in output (see Blitz! BASIC Compiler). Both standard comment types are removed during compilation to minimize output size.
Build tokens¶
BPP+ replaces three build token types during preprocessing:
{builddate}- Current date in YYYY-MM-DD format{buildtime}- Current time in HH:MM format (24-hour){buildstamp}- Full timestamp in YYYY-MM-DD HH:MM format:
BPP+ replaces these tokens at preprocessing time with the actual build date and time. Your build script can optionally add mode-specific prefixes (like "Release:", "Beta:" or "Dev:") based on the build configuration.
Token format¶
- Case-insensitive:
{builddate},{BUILDDATE},{BuildDate}all work - 24-hour time format without seconds
- BPP+ replaces these before BASIC parsing, so they work anywhere in your code
Usage in source¶
main:
print "{clr}BPP+ Program v1.0"
print "Build: {builddate}"
end
BPP+ output¶
1 print"{clr}BPP+ Program v1.0"
2 print"Build: 2025-10-31"
3 end
Build script processing (optional) 1¶
# For Release builds: Add "Release:" prefix and remove time
sed -i 's/\([0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}\) [0-9]\{2\}:[0-9]\{2\}/\1/g' output.bas
sed -i "s/\([^a-zA-Z:]\)\([0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}\)/\1Release: \2/g" output.bas
# For Dev builds: Add "Dev:" prefix, keep time
sed -i "s/\([^a-zA-Z:]\)\([0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}[^0-9]*[0-9]\{2\}:[0-9]\{2\}\)/\1Dev: \2/g" output.bas
Reserved keywords¶
The following BASIC v2 keywords cannot be used as label identifiers:
end for next data input# input dim read
let goto run if restore gosub return rem
stop on wait load save verify def poke
print# print cont list clr cmd sys open
close get get# new tab( to fn spc(
then not step + - * / ^
and or > = < sgn int abs
usr fre pos sqr rnd log exp cos
sin tan atn peek len str$ val asc
chr$ left$ right$ mid$ ti$ ti st go
π
If you use a keyword as a label, BPP+ will not recognize it as a label. It will pass it through as BASIC code, which causes a syntax error in Petcat.
Example of what NOT to do¶
for:
print "hello" rem ERROR: 'for' is a keyword
goto:
return rem ERROR: 'goto' is a keyword
BPP+ will generate:
1 for:print"hello"
2 goto:return
Petcat will then reject this with a syntax error because for: and goto: are invalid BASIC statements.
String literals¶
String literals are enclosed in double quotes:
print "hello world"
a$ = "test"
print "" rem Empty string is valid
Empty strings are supported¶
if a$="" then print "empty"
PETSCII character conversion¶
BPP+ automatically converts certain PETSCII characters to their ASCII equivalents during preprocessing. This eliminates the need for external sed pipelines in build systems and handles files created with C64 character sets transparently.
Automatic conversions¶
| PETSCII Character | Byte Value | ASCII Equivalent |
|---|---|---|
£ (pound sign) |
0x5C | \ (backslash) |
← (left arrow) |
0x5F | _ (underscore) |
↑ (up arrow) |
0x5E | ^ (caret) |
Why this is needed¶
C64 editors and some modern PETSCII editors use different character codes for these symbols. Files created on a C64 or with PETSCII-aware editors may contain the PETSCII variants, which need conversion to standard ASCII for proper processing.
Example¶
Source file created with PETSCII editor:
main:
x£5 rem £ is PETSCII
y←var rem ← is PETSCII
z=2↑3 rem ↑ is PETSCII
After BPP+ preprocessing (automatic conversion):
main:
x\5 rem Converted to ASCII
y_var rem Converted to ASCII
z=2^3 rem Converted to ASCII
No configuration required¶
This conversion happens automatically during preprocessing. You don't need to:
- Add command-line flags
- Use external
sedpipelines - Modify your source files manually
- Configure character set mappings
BPP+ handles this transparently, allowing you to work with files from various sources without worrying about character encoding differences.
Not a C*Base extension¶
↑ (up arrow) is NOT a C*Base command or extension. It only provides PETSCII-to-ASCII conversion for the exponentiation operator (^).
C*Base extension symbols¶
The characters @, £, and ← have additional meanings in C*Base BBS context beyond their PETSCII conversion purposes.
MCI commands and Prof. Plum extensions¶
| Symbol | MCI Command | Prof. Plum Extension | BASIC Extension |
|---|---|---|---|
@ |
Yes | print:print#5 |
No |
← |
Yes | print;:print#5; |
Yes |
£ |
Yes | No | Yes |
Prof. Plum print shorthand¶
These symbols send output to both screen and modem simultaneously in C*Base BBS source code:
@- Expands toprint:print#5(statement separator with colon)←- Expands toprint;:print#5;(statement separator with semicolon)
Both shortcuts eliminate the need to manually type the dual-output pattern.
Example:
@ "text"
← "text"
£ MCI Command
Statement separator: Single vs Double Colon¶
Single colon (:)¶
Used as a statement separator in BASIC:
poke 53280,0:poke 53281,0:print "done"
BPP+ recognizes : as a delimiter between statements.
Double colon (::)¶
Reserved for Blitz! compiler extension marker (see Blitz! BASIC Compiler):
:: sys 49152 rem Interpreted at runtime, not compiled
The parser treats :: specially to avoid conflicts with single colon parsing.
See also¶
- Symbol resolution - Label definition and reference syntax
- Statement chaining - Line continuation with backslash
- Blitz! BASIC Compiler - Special comment preservation and extension marker
- Control flow - Using labels in GOTO/GOSUB statements
- PETSCII control codes - Screen control and color codes
-
Examples of modification via a Bash build script. ↩