Skip to content

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: rem followed by space, then comment text
  • rem foo → removed from output
  • rem ** → 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
    yvar           rem ← is PETSCII
    z=23           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 sed pipelines
  • 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 to print:print#5 (statement separator with colon)
  • - Expands to print;: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


  1. Examples of modification via a Bash build script.