Introduction
Welcome to SLP-BASIC
Welcome to SLP-BASIC v1.2, a faithful implementation of Commodore BASIC V2 for the Emulator.ca modem network. Whether you're returning to 1980s computing or encountering it for the first time, you're about to enter a world where programming is direct, immediate, and rewarding.
This manual is your comprehensive guide to the BASIC language—line-numbered programming, immediate mode execution, and the distinctive experience of Commodore computing. Everything you need to write programs, from your first PRINT statement to sophisticated applications, is covered in these pages.
SLP-BASIC v1.2 brings authentic Commodore BASIC V2 to your terminal, exactly as it appeared on the VIC-20 and Commodore 64. Every command, every function, every quirk has been faithfully recreated. When you type RUN and watch your program execute, you are experiencing computing as millions have come to know and love it.
Press ESC at any time to interrupt program execution. Your programs are automatically saved and persist across sessions, so you can pick up right where you left off.
What is BASIC?
BASIC stands for Beginner's All-purpose Symbolic Instruction Code. Created in 1964 by John Kemeny and Thomas Kurtz at Dartmouth College, BASIC was designed with a revolutionary goal: to make programming accessible to everyone, not just mathematicians and engineers.
Before BASIC, programming required intimate knowledge of machine architecture, complex syntax, and often, stacks of punched cards. BASIC changed everything. Its commands were English-like (PRINT, INPUT, GOTO), its syntax was forgiving, and its feedback was immediate. You could type a command and instantly see the result. For the first time, programming became conversational.
The BASIC Revolution
When microcomputers arrived in the late 1970s, BASIC came with them. The Apple II, the TRS-80, the Commodore PET—every home computer booted directly into BASIC. Turn on the power, and within seconds you saw a READY prompt waiting for your commands. No operating system to load, no applications to launch. The computer was ready to be programmed, and BASIC was the language it spoke.
BASIC became the lingua franca of a generation. Millions learned to program by typing in listings from magazines like COMPUTE! and Creative Computing. Classrooms taught BASIC. Users' groups exchanged BASIC programs on cassette tapes and floppy disks. If you wanted your computer to do something new, you wrote it in BASIC.
Why Commodore BASIC?
Among the many dialects of BASIC, Commodore BASIC V2 holds a special place. Derived from Microsoft's 6502 BASIC, it powered some of the most beloved computers of the 1980s:
- VIC-20 (1980): The first computer to sell over one million units, bringing computing to families worldwide
- Commodore 64 (1982): The best-selling single computer model of all time, with over 17 million units sold
Commodore BASIC V2 struck a perfect balance: powerful enough for serious programming, yet simple enough for beginners. It lacked some features found in other BASICs (no ELSE clause initially, no WHILE loops), but this simplicity was its strength. You learned the core concepts of programming without distraction.
In BASIC, you're never more than one RUN command away from seeing your program in action. This immediate feedback loop—type, run, see results, modify—creates a programming experience that's both educational and addictive.
BASIC Today
While BASIC is no longer the dominant language it once was, its influence remains profound. Many concepts that seem obvious today—interactive programming environments, immediate mode execution, English-like syntax—were pioneered by BASIC. Modern languages like Python, with their emphasis on readability and interactivity, are spiritual descendants of BASIC's philosophy.
SLP-BASIC preserves this heritage while taking advantage of modern technology. You get the authentic experience—right down to the character set and memory limits—but with benefits like instant saving, reliable execution, and the ability to run your programs anywhere you have a web browser.
Ready to Begin
You're about to embark on a journey into computing history—but this isn't just nostalgia.
In 1982, a 12-year-old could save up lawn-mowing money, buy a Commodore 64, plug it into the family television, and immediately—within seconds of power-on—have access to a complete programming environment. No installation, no configuration, no operating system to learn. Just READY and a blinking cursor. That child could type 10 PRINT "HELLO" and press RUN, and the computer would obey. The sense of power was intoxicating.
That directness, that immediate feedback, that focus on solving problems rather than managing complexity—these qualities made BASIC revolutionary, and they make it an excellent environment for learning programming concepts that remain relevant today.
The next chapter guides you through connecting to the SLP-BASIC system. Once you see that READY prompt, you'll have access to a complete programming environment—38,911 bytes free, just like the original—waiting for your commands. Let's begin!
Take your time with each chapter. Type the examples yourself rather than copying and pasting. The act of typing helps build muscle memory and understanding. Make mistakes—they're part of learning, and BASIC's error messages are designed to help you understand what went wrong.
Getting Connected
This chapter covers remote computing via modem connection. You'll learn how to establish a connection to the SLP-BASIC v1.2 system, understand the technical details of the RS-232 communication protocol, and master the procedures for maintaining and terminating your session.
The SLP-BASIC system runs on a dedicated server accessible through the public switched telephone network. Whether you're calling from your home computer lab or a remote terminal, the connection process is straightforward and reliable.
What You'll Need
Before dialing in, ensure you have the following:
Hardware Requirements:
- A computer with RS-232 serial port (DB-25 or DB-9 connector)
- Hayes-compatible modem (300, 1200, or 2400 baud)
- Telephone line with dial tone
- Properly configured terminal program
Software Configuration:
- Terminal emulation: VT100 or ANSI
- Data bits: 8
- Parity: None
- Stop bits: 1
- Flow control: RTS/CTS (hardware)
Most Commodore 64 and VIC-20 users will access SLP-BASIC through the modem simulator provided at emulator.ca. The following procedures apply whether you're using authentic vintage hardware or the web-based emulator.
Dialing In
Once your modem is properly configured and connected, you're ready to dial. The SLP-BASIC system is accessible at:
Phone Number: 555-0300
To initiate the connection, enter the following command at your terminal:
ATDT555-0300
Let's break down this command:
- AT - Attention prefix (all Hayes commands start with AT)
- D - Dial command
- T - Tone dialing (use "P" for pulse dialing if necessary)
- 555-0300 - The SLP-BASIC system phone number
CODE_FENCE_0
After pressing RETURN, your modem will begin dialing. You'll hear the familiar tones as it establishes the connection.
If your local telephone exchange requires a "9" or other prefix for outside lines, include it before the number: ATDT9,555-0300 (the comma adds a 2-second pause for dial tone).
The Connection Sequence
Once your modem begins dialing, several events occur in rapid succession. Understanding this sequence helps you diagnose connection problems and appreciate the engineering behind reliable data communication.
Phase 1: Call Establishment Your modem sends dual-tone multi-frequency (DTMF) signals corresponding to each digit. The telephone system routes your call to the SLP-BASIC server.
Phase 2: Answer and Handshake The remote modem answers and both modems negotiate communication parameters—baud rate, modulation type, and error correction. You'll hear a characteristic screech and warble during this negotiation.
Phase 3: Carrier Detection Once negotiation succeeds, both modems establish a carrier signal. Your modem asserts the DCD (Data Carrier Detect) line, informing your computer that a valid connection exists.
Phase 4: Connection Confirmation Your modem displays the connection status:
CONNECT 1200
The number indicates your connection speed in bits per second. Common speeds include:
- 300 baud - 30 characters per second
- 1200 baud - 120 characters per second
- 2400 baud - 240 characters per second
"Baud" technically refers to symbol rate, not bits per second, but at these speeds the terms are used interchangeably. Modern modems use advanced modulation schemes where the distinction becomes significant.
Immediately after connection, the SLP-BASIC system sends its welcome banner.
The Welcome Banner
Upon successful connection, the SLP-BASIC interpreter identifies itself with a welcome banner. The banner you see depends on which computer model the system is emulating.
Commodore 64 Banner (Default):
**** COMMODORE 64 BASIC V2 ****
64K RAM SYSTEM 38911 BASIC BYTES FREE
READY.
VIC-20 Banner (Alternate Configuration):
**** COMMODORE VIC-20 ****
3583 BYTES FREE
READY.
The banner provides essential information:
- System Identification - Which computer is being emulated
- BASIC Version - V2 is Commodore BASIC Version 2
- Available Memory - How many bytes are free for your programs
- Ready Status - The "READY." prompt indicates the interpreter awaits input
The difference in free memory reflects authentic hardware limitations. The VIC-20's modest 5KB RAM (with 1.5KB for BASIC) contrasts sharply with the C64's generous 64KB (with 38KB available to BASIC after system overhead). Both systems provide identical BASIC V2 functionality—the VIC-20 simply requires more compact programs!
The SLP-BASIC system defaults to Commodore 64 emulation. The banner you receive confirms your session parameters and available resources.
The READY Prompt
After the banner displays, you'll see:
READY.
█
The READY. prompt is your signal that the interpreter is waiting for input. The blinking cursor (shown here as █) marks where your next character will appear.
This prompt has special significance in Commodore BASIC:
What "READY" Means:
- The interpreter has finished executing (or has no program running)
- All commands and statements are now accepted
- You can enter immediate mode commands or program lines
- The system is idle and waiting for you
The Period Matters: The period (full stop) after "READY" is part of Commodore's distinctive style. It differentiates this prompt from the similar but period-less prompts of other BASIC implementations.
Cursor Behavior: The cursor blinks at approximately 1 Hz (once per second), indicating the system is responsive and ready. If the cursor stops blinking or disappears, the connection may have been interrupted.
CODE_FENCE_0
Notice how after executing your command, the system immediately returns to the READY prompt, awaiting your next instruction.
If you don't see the READY prompt within 5 seconds of connection, try pressing RETURN once. The banner may have transmitted before your terminal was fully synchronized.
RS-232 Signal Protocol
The SLP-BASIC interpreter participates fully in RS-232 hardware handshaking. Understanding these signals helps you diagnose connection issues and appreciate how reliable communication is maintained.
RS-232 defines several control signals beyond the transmit (TX) and receive (RX) data lines. The most important for modem communication are:
| Signal | Name | Direction | Function |
|---|---|---|---|
| DTR | Data Terminal Ready | DTE→DCE | Terminal asserts when ready to communicate |
| DSR | Data Set Ready | DCE→DTE | Modem asserts when ready to communicate |
| RTS | Request To Send | DTE→DCE | Terminal requests permission to send data |
| CTS | Clear To Send | DCE→DTE | Modem grants permission to send data |
| DCD | Data Carrier Detect | DCE→DTE | Modem asserts when carrier signal present |
Terminology:
- DTE (Data Terminal Equipment) - Your computer
- DCE (Data Communications Equipment) - Your modem
RS-232C, the 1969 standard most commonly implemented, specifies voltage levels for these signals: +3V to +15V for logical 0 (SPACE, asserted) and -3V to -15V for logical 1 (MARK, deasserted). This unusual polarity reflects telegraph heritage and provides excellent noise immunity over short cable runs.
How SLP-BASIC Uses These Signals:
DTR (Data Terminal Ready): The interpreter asserts DTR immediately upon connection, signaling to the modem that it's ready for communication. When you disconnect properly, the interpreter drops DTR, instructing the modem to hang up. This is the primary method for terminating the connection.
RTS (Request To Send): The interpreter asserts RTS when initialized and maintains it throughout the session. This signal, combined with CTS, implements hardware flow control. When the interpreter's input buffer approaches capacity, it could (in theory) deassert RTS to pause incoming data. In practice, at these speeds, buffer overflow is rare.
CTS (Clear To Send): The modem asserts CTS in response to RTS when ready to accept data. If your modem needs to throttle input (because its own buffers are full or the phone line quality degrades), it will deassert CTS. The interpreter monitors this signal and pauses output when CTS is low.
DCD (Data Carrier Detect): The modem asserts DCD when it detects a valid carrier signal from the remote modem. If DCD drops during your session, it indicates carrier loss—usually meaning the remote system hung up or the phone line was interrupted. The interpreter monitors DCD and can initiate cleanup if carrier is lost unexpectedly.
DSR (Data Set Ready): The modem asserts DSR when powered on and ready to operate. This signal confirms your modem is functional before attempting to dial.
Signal Flow During Operation
Here's how these signals interact during a typical session:
INITIAL CONNECTION SEQUENCE
═══════════════════════════
COMPUTER (DTE) MODEM (DCE)
│ │
┌────┤ │
│ │ DTR ───────────────────> │ (Terminal ready)
│ │ ├────┐
│ │ <────────────────── DSR │ │ (Modem ready)
│ │ │ │
│ │ RTS ───────────────────> │ │ (Request to send)
│ │ │ │
│ │ <────────────────── CTS │ │ (Clear to send)
│ │ │ │
│ │ ┌────┘ │
│ │ [DIALING...] │ │
│ │ └────┐ │
│ │ │ │
│ │ <────────────────── DCD │ │ (Carrier detected)
│ │ ├────┘
│ │ │
└───>│ TX ←──────────────→ RX │ (Data exchange)
│ RX ←──────────────→ TX │
│ │
ACTIVE SESSION (ALL SIGNALS ASSERTED)
══════════════════════════════════════
DTR: HIGH (Interpreter ready)
RTS: HIGH (Ready to send)
CTS: HIGH (Modem ready to receive)
DCD: HIGH (Carrier present)
DSR: HIGH (Modem operational)
NORMAL DISCONNECTION SEQUENCE
══════════════════════════════
│ │
│ DTR drop ──────────────> │ (Hangup request)
│ │
│ [HANGUP]
│ │
│ <────────────── DCD drop │ (Carrier lost)
│ │
∅ ∅
Flow Control in Action:
If the modem's transmit buffer fills (perhaps due to a noisy line requiring retransmissions), it will deassert CTS. The interpreter detects this condition and suspends output until CTS returns high. This prevents data loss and maintains reliable communication even under adverse conditions.
Interrupting Execution
Sometimes you'll need to stop a running program—perhaps it's stuck in an infinite loop, generating too much output, or you've simply changed your mind. The SLP-BASIC interpreter provides a clean interrupt mechanism.
The ESC Key:
Press the ESC (Escape) key at any time to interrupt program execution. The interpreter will:
- Immediately halt the current statement
- Display
^Cto acknowledge the interrupt - Return to the READY prompt
- Preserve all variables and program code in memory
CODE_FENCE_0
The program stops immediately, but remains in memory. You can LIST it, modify it, or RUN it again.
The ESC key sends character code 27 (0x1B in hexadecimal). The interpreter's input handler recognises this code and sets an internal interrupt flag. The execution loop checks this flag before each statement, providing rapid response to user interrupts. Maximum interrupt latency is typically under 100 milliseconds.
What ESC Does NOT Do:
- Does not disconnect your session
- Does not clear program memory (use NEW for that)
- Does not reset variables (use CLR for that)
- Does not hang up the modem (see next section)
If a program is waiting for INPUT and you want to cancel it without providing data, press ESC. The program will halt, and you can modify it to handle unexpected conditions more gracefully.
Disconnecting Properly
When you've finished your session, it's important to disconnect properly. This ensures the modem releases the phone line, prevents phantom connections, and maintains clean system logs.
Method 1: The Proper Way (Drop DTR)
The cleanest disconnection method is to instruct your modem to hang up by dropping DTR:
+++
OK
ATH
OK
NO CARRIER
Let's break this down:
Step 1: Enter Command Mode
Type three plus signs with one-second pauses before and after: +++
This is the Hayes "escape sequence" that returns the modem to command mode without disconnecting. After a brief pause, the modem responds with OK.
Step 2: Hang Up
Type ATH (AT Hang-up) and press RETURN.
The modem drops DTR, terminates the connection, and responds with OK followed by NO CARRIER.
The three plus signs must be preceded by one second of silence, typed without pauses between them, and followed by one second of silence. If you type too quickly or too slowly, the modem won't recognise the escape sequence. This timing requirement prevents accidental escape sequences in your data.
Method 2: Direct Hangup (Most Terminal Programs)
Most terminal programs provide a hangup command:
- Kermit: Press Ctrl-\ C, then type
HANGUP - ProComm: Press Alt-H
- Telix: Press Alt-H
- Commodore 64: Depends on your terminal program
Consult your terminal software documentation for the specific key combination.
Method 3: Modem Power Cycle (Emergency Only)
If the modem becomes unresponsive, you can disconnect by cycling power:
- Turn off the modem
- Wait 10 seconds
- Turn on the modem
- Wait for DSR to assert (modem ready light)
This method should be reserved for emergencies, as it terminates the connection abruptly without notifying the remote system.
What Happens During Disconnection:
When DTR drops, the following sequence occurs:
- The interpreter detects DTR deassertion
- The interpreter halts execution and clears its state
- The modem terminates the carrier signal
- The remote modem detects carrier loss
- Both modems return to idle state
- The phone line is released
Never disconnect by simply unplugging the phone line or turning off your computer while connected. This leaves the remote modem in an ambiguous state and may hold the phone line open unnecessarily. Always disconnect through proper DTR signaling.
Verifying Disconnection:
You know you've successfully disconnected when:
- Your modem's "CD" (Carrier Detect) light goes off
- Your terminal displays "NO CARRIER"
- Your modem returns to idle state (ready to accept AT commands)
- Dial tone returns on your phone line
Troubleshooting Connection Issues
Even with proper configuration, you may occasionally encounter connection problems. This section covers common issues and their solutions.
Problem: NO DIALTONE Error
Symptoms: After entering ATDT555-0300, your modem immediately responds:
NO DIALTONE
Cause: The modem cannot detect dial tone on the phone line.
Solutions:
- Verify phone cable is securely connected to both modem and wall jack
- Test phone line by connecting a telephone and listening for dial tone
- Check if another device (fax, answering machine) is off-hook on the same line
- Try:
ATX3before dialing (disables dial tone detection) - Verify phone line type (some modems don't work with VoIP or PBX systems)
Problem: NO ANSWER Error
Symptoms: Modem dials successfully but eventually responds:
NO ANSWER
Cause: The remote system didn't answer within the timeout period (typically 30-60 seconds).
Solutions:
- Verify you're dialing the correct number (555-0300)
- Check if you need a dialing prefix (9 for outside line, 1 for long distance)
- Increase answer timeout:
ATS7=60(wait 60 seconds for answer) - Try again during off-peak hours (the system may be busy)
- Verify the remote system is operational (try calling the voice line to confirm)
Problem: CONNECT Followed by Garbage
Symptoms: Modem reports successful connection, but the banner is garbled or you see random characters:
CONNECT 1200
��*@��CO#�MM%�DO��@��@4 B����
Cause: Communication parameters mismatch between your terminal and the remote system.
Solutions:
- Verify your terminal settings match the requirements:
- Data bits: 8
- Parity: None
- Stop bits: 1
- Check baud rate—try forcing a specific speed:
AT&N6(lock at 1200 baud) - Disable software flow control (XON/XOFF) in your terminal program
- Enable hardware flow control (RTS/CTS)
- Reset modem to factory defaults:
AT&Fthen reconfigure
Problem: Connection Drops Randomly
Symptoms: You successfully connect and use SLP-BASIC, but the connection terminates unexpectedly with:
NO CARRIER
Cause: Poor line quality causing excessive errors, or modem timeout.
Solutions:
- Check for sources of electrical interference:
- Don't run modem cable parallel to power cables
- Keep modem away from fluorescent lights, motors
- Avoid wireless devices near modem cable
- Try a shorter phone cable (RJ-11) to modem
- Increase carrier loss timeout:
ATS10=20(wait 2 seconds before declaring carrier lost) - Enable error correction:
AT&M4orAT&M5 - Try a lower baud rate:
AT&N5(lock at 300 baud) - Test with a different phone jack (line quality varies)
Problem: Can't Enter Command Mode with +++
Symptoms:
Typing +++ doesn't return modem to command mode; it may appear in your SLP-BASIC session instead.
Cause: Incorrect timing on the escape sequence, or the characters are being interpreted as data.
Solutions:
- Remember the timing: one second pause, three plus signs, one second pause
- Verify escape character:
ATS2?(should return 43, the ASCII code for +) - Some modems use different escape sequences—check your modem manual
- If using a terminal program, use its built-in hangup command instead
- As last resort, power cycle the modem
Problem: Banner Appears Slowly or Character-by-Character
Symptoms: Each character of the banner appears with a noticeable delay.
Cause: This is actually normal behavior for some configurations—the system may be implementing character-by-character transmission for authentic terminal emulation.
Solutions:
- This is not necessarily a problem—wait for the complete banner
- If unacceptably slow, try a higher baud rate:
- Set modem to 2400:
AT&N8 - Or negotiate highest common speed:
AT&N0
- Set modem to 2400:
- Verify your modem doesn't have excessive guard time:
ATS12?(should be 50 or less)
Problem: Modem Doesn't Respond to AT Commands
Symptoms:
You type AT and press RETURN, but see no response.
Cause: Communication problem between computer and modem, or modem not in command mode.
Solutions:
- Verify serial cable is properly connected
- Check your terminal program's COM port setting matches physical port
- Try different baud rates in terminal program (2400, 1200, 300)
- Enable local echo in terminal program to see what you're typing
- Reset modem by power cycling
- Try sending:
ATE1(enable echo) followed by RETURN several times - Check if modem has a physical DIP switch configuration—may need to match software settings
- Consult modem manual for factory reset procedure
Problem: SLP-BASIC Not Responding
Symptoms: Connection successful, banner appears, but keyboard input doesn't produce output:
READY.
PRINT "TEST"[no response]
Cause: Flow control issue, or interpreter has frozen.
Solutions:
- Check if CTS is deasserted (flow control blocking)—try disabling hardware flow control temporarily
- Press ESC to attempt interrupt
- Check Scroll Lock key on your keyboard—it may be pausing output
- Verify local echo is OFF in your terminal program (or you'll see double characters)
- Try sending a carriage return (ENTER) alone—may resynchronize
- As last resort, disconnect and reconnect
Problem: Cursor Not Visible
Symptoms: You can type and see output, but there's no visible cursor.
Cause: Terminal emulation mismatch—the cursor control codes aren't supported by your terminal.
Solutions:
- This doesn't affect functionality—the cursor position is tracked internally
- Try different terminal emulation: VT100, ANSI, or TTY
- Some terminals have a cursor enable/disable setting—check your terminal program
- Not all emulation modes support blinking cursors—steady cursor or no cursor may be normal
When experiencing connection issues, start with the simplest solutions:
- Power cycle the modem
- Try a different phone jack
- Verify configuration with
AT&V(view settings) - Reset to factory defaults with
AT&F - Reduce baud rate to 300 for maximum compatibility
Most problems have simple solutions—methodical testing usually reveals the issue quickly.
Connection Best Practices
Follow these guidelines for reliable, pleasant SLP-BASIC sessions:
Before Connecting:
- Test your modem with
ATcommand before dialing - Verify phone line quality (no static on voice calls)
- Close other programs that might use the serial port
- Ensure adequate lighting to read your screen comfortably
During Connection:
- Don't touch the phone cable while connected (may introduce noise)
- If the connection seems slow, wait—don't repeatedly press keys
- Save your programs frequently using SAVE (covered in Chapter 12)
- Use ESC to interrupt runaway programs rather than disconnecting
- Keep a written log of your session time for phone billing purposes
After Disconnecting:
- Always use proper hangup procedure (drop DTR via ATH or terminal command)
- Verify "NO CARRIER" message before walking away
- Reset modem to clear settings:
ATZ - Log your session (programs created, problems encountered, solutions)
Etiquette and Usage:
- During peak hours, limit sessions to reasonable duration to share system access
- Don't leave your terminal connected but idle for extended periods
- If you encounter system problems, note exact error messages for reporting
- Be patient with connection times—analog modems are inherently slower than modern internet
Understanding Connection Costs
In the 1980s, telephone charges for modem connections were a significant consideration. Local calls might be free or metered, while long-distance calls accrued charges per minute. The SLP-BASIC simulator at emulator.ca is free to use with no connection charges, but understanding the historical context enriches your appreciation of remote computing's evolution.
If you were connecting to a real remote system in 1983, you'd consider:
Telephone Charges:
- Local calls: Often included in monthly service fee (flat rate)
- Long distance: Significant per-minute charges, especially during business hours
- Timing: Evenings and weekends usually had lower rates
System Access Fees: Many timesharing systems charged for connect time:
- $5-$20 per hour was typical for personal systems
- Commercial services (CompuServe, The Source) charged $5-$25 per hour
- Premium rates for high-speed connections (1200/2400 baud)
- Storage fees for saved programs
Cost Management Strategies:
- Compose programs offline in a text editor
- Upload quickly using protocol transfers (XMODEM, Kermit)
- Download results and disconnect promptly
- Use off-peak hours for development work
- Keep detailed logs of connect time for budgeting
The SLP-BASIC emulator frees you from these concerns—connect as long as you like, experiment freely, and learn without watching the clock!
What's Next
Now that you've successfully connected to SLP-BASIC and understand the communication protocols involved, you're ready to start programming!
In Chapter 3, you'll learn about Immediate Mode, where you can use BASIC as an interactive calculator and test commands before adding them to programs. You'll discover that the READY prompt isn't just waiting for programs—it's your gateway to instant computation and experimentation.
Before continuing, practice the connection procedure several times:
- Dial in to SLP-BASIC
- Verify you see the proper banner
- Type
PRINT "HELLO"and press RETURN to confirm communication - Disconnect properly using the ATH command
- Verify successful disconnection
Comfort with these procedures ensures smooth sailing throughout your SLP-BASIC journey!
Key Points to Remember:
- Phone number: 555-0300 (ATDT555-0300 to dial)
- Connection speed: 300-2400 baud (typically 1200)
- Welcome banner: Confirms system type and available memory
- READY prompt: Indicates interpreter is waiting for input
- RS-232 signals: DTR, RTS, CTS, DCD, DSR maintain reliable communication
- ESC key: Interrupts program execution without disconnecting
- Proper disconnect: Use ATH command to drop DTR and hang up
- Troubleshooting: Start simple—check cables, power cycle, verify settings
With solid connection fundamentals under your belt, you're prepared to explore the full power of SLP-BASIC v1.2!
Immediate Mode
What is Immediate Mode?
One of BASIC's most powerful features is something so simple you might overlook it: immediate mode. It's the ability to type a command and see the result instantly, without writing a program at all.
The secret is the line number—or rather, the lack of one. Any command you type without a line number executes immediately:
PRINT "HELLO, WORLD!"
That's it. No RUN command needed, no program to save. Just type and press Enter. BASIC executes the command and shows you the result right away.
Compare this to program mode, where commands are stored for later execution:
10 PRINT "HELLO, WORLD!"
20 PRINT "THIS IS A PROGRAM"
RUN
See the difference? The line with "10" doesn't execute when you type it—it's stored. Only when you type RUN does BASIC execute line 10, then line 20, in order.
Immediate mode is what happens when you skip the line number. The command executes immediately, as soon as you press Enter. This simple feature transforms BASIC from a programming language into an interactive environment where you can explore, experiment, and test ideas without ceremony.
When you see "READY." BASIC is waiting in immediate mode. Any command you type will execute instantly. This is your playground—use it freely.
Why Immediate Mode Matters
In most programming languages, testing a simple idea requires creating a file, writing a function, compiling or running the program, and checking the output. In BASIC, you just type the command. Want to know what 125 times 37 equals? Type it:
PRINT 125 * 37
Instant answer. No ceremony, no overhead, no waiting. This immediacy makes BASIC uniquely suited for exploration and learning. You're never more than one command away from discovering something new.
BASIC as a Calculator
The simplest use of immediate mode is as a calculator. BASIC handles arithmetic with precision and power that would have seemed miraculous in the 1980s—and it's still remarkably handy today.
Simple Arithmetic
PRINT 2 + 2
PRINT 100 - 37
PRINT 15 * 8
PRINT 100 / 3
Notice that division produces a decimal result. BASIC uses floating-point arithmetic, so you get precise fractional answers.
Complex Expressions
BASIC follows standard mathematical operator precedence: multiplication and division before addition and subtraction. Parentheses override this order:
PRINT 5 * 7 + 3
PRINT 5 * (7 + 3)
Same numbers, different results. The parentheses make BASIC add first, then multiply. Without them, BASIC multiplies first (5 × 7 = 35), then adds 3.
Exponentiation
The ^ operator raises numbers to powers:
PRINT 2 ^ 8
PRINT 10 ^ 6
PRINT 1.5 ^ 3
This works for fractional exponents too—useful for roots:
PRINT 16 ^ 0.5
That's the square root of 16! Raising a number to the 0.5 power is equivalent to taking its square root.
BASIC's calculator mode handles scientific notation, large numbers, and complex expressions. It's more powerful than most pocket calculators of the 1980s—and it's always available at the READY prompt.
Practical Calculations
Immediate mode shines for quick real-world calculations:
PRINT 19.99 * 1.13
That's a $19.99 item with 13% tax. Or:
PRINT 127 / 2.54
Converting 127 centimeters to inches. You don't need to write a program, save it, and run it. Just type the calculation and get your answer.
Instant Feedback with PRINT
The PRINT command is your window into what BASIC is thinking. In immediate mode, it shows you the result of any expression:
PRINT 123 * 456
PRINT "THE ANSWER IS 42"
PRINT 7 > 5
Wait—what's that last one? BASIC uses -1 to represent "true" and 0 to represent "false." The expression 7 > 5 is true, so BASIC prints -1. This becomes important when you write programs with conditions.
The ? Shorthand
Here's a secret that will save you countless keystrokes: ? is shorthand for PRINT. They're completely identical:
? 2 + 2
? "HELLO"
? 100 / 3
Most experienced BASIC programmers use ? in immediate mode because it's faster to type. PRINT and ? work identically in programs too, though PRINT is more readable in program listings.
The ? shorthand comes from early BASIC interpreters where every byte of memory mattered. Using ? instead of PRINT saved four precious bytes per line. The convention stuck, even when memory became abundant.
Multiple Values
PRINT can display multiple values separated by commas or semicolons:
PRINT 10; 20; 30
PRINT "VALUE:"; 123
Semicolons pack values tightly together. Commas create wider spacing (tab zones). We'll explore formatting in detail in Chapter 8, but for now, know that you can print multiple things with one PRINT command.
Variables in Immediate Mode
Variables work in immediate mode just as they do in programs. You can create them, assign values, and check their contents—all without writing a program.
Creating and Using Variables
A = 42
PRINT A
NAME$ = "ALICE"
PRINT NAME$
X = 10
Y = 20
PRINT X + Y
Notice the $ suffix on NAME$—that makes it a string variable (text). Variables without suffixes hold numbers. This distinction is crucial in BASIC.
Variables Persist
Here's something important: variables you create in immediate mode persist until you clear them. They don't disappear when the command finishes:
SCORE = 100
PRINT SCORE
SCORE = SCORE + 50
PRINT SCORE
The variable SCORE remembers its value between commands. You can use it again and again:
SCORE = 1000
PRINT SCORE
PRINT SCORE * 2
PRINT SCORE + 500
This persistence makes immediate mode perfect for testing and debugging. You can set up variables, try operations, check results, and refine your logic—all interactively.
Before using a variable in a program, test it in immediate mode. Assign values, perform operations, check results. Once you're confident it works, add the line numbers to make it a program.
String Operations
String variables hold text and can be manipulated:
FIRST$ = "HELLO"
LAST$ = "WORLD"
PRINT FIRST$ + " " + LAST$
The + operator concatenates (joins) strings. You can build complex text from simple pieces:
MSG$ = "THE ANSWER IS "
NUM = 42
PRINT MSG$ + STR$(NUM)
Notice STR$(NUM)—that converts the number to a string so it can be concatenated. We'll cover string functions in Chapter 10, but immediate mode is perfect for experimenting with them.
Integer Variables
Variables ending with % hold integers (whole numbers from -32768 to 32767):
COUNT% = 100
PRINT COUNT%
PRINT COUNT% * 2
Integer arithmetic is faster than floating-point, though you rarely notice on modern hardware. Use integers when you know values will always be whole numbers.
Testing Commands Before Programming
Immediate mode's greatest strength is risk-free experimentation. You can test any command, try any function, check any expression—without affecting your program.
Try It First
Suppose you're writing a program that needs to find the square root of a number. You remember there's a function, but you're not sure of the exact syntax. Try it in immediate mode:
PRINT SQR(16)
PRINT SQR(2)
PRINT SQR(144)
Perfect—SQR() takes a number and returns its square root. Now you're confident adding it to your program:
10 INPUT "ENTER A NUMBER"; N
20 PRINT "SQUARE ROOT IS"; SQR(N)
RUN
Testing String Functions
String functions can be tricky. Test them before committing:
TEXT$ = "HELLO WORLD"
PRINT LEFT$(TEXT$, 5)
PRINT RIGHT$(TEXT$, 5)
PRINT MID$(TEXT$, 7, 5)
LEFT$ extracts characters from the left, RIGHT$ from the right, and MID$ from the middle. Playing with them in immediate mode clarifies exactly how they work.
Testing Conditions
When writing IF statements, test the conditions first:
A = 10
B = 20
PRINT A > B
PRINT A < B
PRINT A = B
Remember: -1 means true, 0 means false. Once you understand how the comparison works, write the IF statement with confidence.
In immediate mode, mistakes cost nothing. A syntax error? You get an error message and try again. A wrong result? Adjust and re-test. There's no program to corrupt, no file to lose. Immediate mode is your safe space for learning.
Building Complex Expressions
Test parts of complex expressions separately:
PRICE = 19.99
TAX = 0.13
PRINT PRICE * TAX
PRINT PRICE + (PRICE * TAX)
PRINT INT(PRICE + (PRICE * TAX) + 0.5)
That last one rounds to the nearest whole number. By testing each step, you build confidence that the final expression does what you intend.
Practical Debugging Uses
When your program doesn't work as expected, immediate mode becomes your debugging workshop. You can inspect variables, test logic, and identify problems without modifying your program.
Checking Variable Values
After a program runs (or stops with an error), variables retain their values. You can examine them:
10 FOR I = 1 TO 10
20 TOTAL = TOTAL + I
30 NEXT I
40 PRINT "TOTAL:"; TOTAL
RUN
Now check the variables:
PRINT I
PRINT TOTAL
The loop ran completely (I is 11, past the limit of 10), and TOTAL holds the sum. If these values seem wrong, you've found your bug.
Testing Logic Interactively
Suppose a program's IF statement isn't working. Set up the conditions manually and test:
SCORE = 85
GRADE$ = ""
IF SCORE >= 90 THEN GRADE$ = "A"
IF SCORE >= 80 AND SCORE < 90 THEN GRADE$ = "B"
PRINT GRADE$
Does it assign the right grade? Try different scores:
SCORE = 92
IF SCORE >= 90 THEN GRADE$ = "A"
PRINT GRADE$
This interactive testing helps you understand exactly when conditions trigger and what values result.
- Run the program (RUN)
- Note unexpected behavior
- Use immediate mode to check variables
- Test suspected logic interactively
- Fix the program
- Run again
This cycle—run, inspect, test, fix—is the heart of debugging in BASIC.
Simulating Program Lines
You can execute any program line in immediate mode by typing it without the line number:
10 LET X = 10
20 PRINT X * 2
LIST
Now execute line 20 directly:
PRINT X * 2
This helps you test individual lines without running the entire program. Set up the conditions (assign variables), then execute the line to see what happens.
Quick Calculations During Development
Often while programming you need quick answers. How many elements in a 10×10 array? Check immediately:
PRINT 10 * 10
What's the midpoint of a 640-pixel screen?
PRINT 640 / 2
These micro-calculations happen constantly during development. Immediate mode means you never leave BASIC to find a calculator.
The INPUT Command in Immediate Mode
INPUT works in immediate mode, prompting you for values just as it would in a program:
INPUT "ENTER YOUR NAME"; NAME$
Type a name and press Enter. Then:
PRINT "HELLO, "; NAME$
The variable NAME$ persists, holding the value you entered. This is handy for setting up test data:
INPUT "AGE"; AGE
PRINT AGE * 365
That estimates days lived (simplified—no leap years). You can test INPUT prompts to ensure they're clear and that the resulting variables work correctly.
Testing INPUT Validation
Suppose your program needs to ensure users enter valid data. Test the validation logic:
INPUT "ENTER A NUMBER (1-10)"; N
IF N < 1 OR N > 10 THEN PRINT "INVALID!"
IF N >= 1 AND N <= 10 THEN PRINT "VALID!"
Try various inputs to confirm the validation works. Once satisfied, add line numbers and incorporate it into your program.
Advanced Immediate Mode Techniques
As you become comfortable with immediate mode, you'll discover advanced techniques that experienced BASIC programmers use daily.
Multi-Statement Lines
You can combine multiple statements on one line with colons:
A = 5 : B = 10 : PRINT A + B
This works in both immediate mode and programs. It's handy for quick setup:
NAME$ = "BOB" : SCORE = 100 : PRINT NAME$; " SCORED"; SCORE
Use this judiciously—too many statements on one line becomes hard to read.
Function Testing
Test built-in functions with different inputs:
PRINT INT(7.8)
PRINT INT(-7.8)
PRINT ABS(-42)
PRINT SGN(-5)
PRINT SGN(5)
Understanding exactly how functions behave prevents surprises in programs. INT() truncates toward zero, ABS() returns absolute value, SGN() returns the sign (-1, 0, or 1).
Random Number Testing
The RND function generates random numbers. Test it interactively:
PRINT RND(1)
PRINT INT(RND(1) * 6) + 1
That second line simulates a six-sided die (1-6). Run it several times to see different results:
PRINT INT(RND(1) * 6) + 1
PRINT INT(RND(1) * 6) + 1
PRINT INT(RND(1) * 6) + 1
The RND function returns a value from 0 (inclusive) to 1 (exclusive). To get integers in a range, multiply by the range size, use INT() to truncate, then add the minimum value. The formula INT(RND(1) * N) + MIN gives integers from MIN to MIN+N-1.
Clearing Variables
The CLR command erases all variables without affecting your program:
A = 100
B$ = "TEST"
PRINT A; B$
CLR
PRINT A; B$
After CLR, numeric variables become 0 and string variables become empty. This is useful when you want fresh variables without clearing your program (NEW clears both).
Immediate Mode Best Practices
To make the most of immediate mode, follow these practices developed by generations of BASIC programmers.
Use It Constantly
Don't save immediate mode for special occasions. Use it constantly:
- Quick calculations while programming
- Testing new functions before using them
- Checking variable values during debugging
- Experimenting with syntax you're unsure about
- Verifying expressions before adding to programs
The READY prompt isn't just waiting for programs—it's waiting for questions. Ask them freely.
Build Understanding Incrementally
When learning new commands, start simple and add complexity:
PRINT "HELLO"
PRINT "HELLO"; " "; "WORLD"
A$ = "HELLO"
B$ = "WORLD"
PRINT A$; " "; B$
Each step adds one concept. By building incrementally, you isolate exactly what each piece does.
Document Your Discoveries
When you discover something useful in immediate mode, immediately turn it into a program line before you forget:
PRINT INT(RND(1) * 100) + 1
That generates random numbers 1-100. Make it permanent:
100 REM GENERATE RANDOM NUMBER 1-100
110 R = INT(RND(1) * 100) + 1
LIST 100-110
Now it's saved in your program for future use.
Combine with LIST
Use immediate mode to test changes before making them permanent. Suppose line 50 isn't working:
10 A = 10
20 B = 20
50 PRINT A + B * 2
LIST
Test the fix in immediate mode first:
PRINT (A + B) * 2
That's what you wanted. Now update the program:
50 PRINT (A + B) * 2
LIST
Testing before modifying prevents replacing one bug with another.
The Immediate Mode Mindset
Learning BASIC is learning to think interactively. Every question has an immediate answer. Every hypothesis can be tested instantly. This creates a unique programming experience—one where the line between learning and doing dissolves.
In most languages, you write code, then test it. In BASIC, testing is writing. Every experiment in immediate mode teaches you something. Every successful test becomes part of your program. The process is fluid, conversational, and deeply satisfying.
When you sit down to program in BASIC, you're not just writing code that will run later. You're having a conversation with the computer right now. You ask questions (PRINT 2+2), get answers (4), refine your questions (PRINT (2+2)*5), and build understanding incrementally.
This is what made BASIC revolutionary in the 1980s and what makes SLP-BASIC special today: it removes the barriers between thought and execution. You think of something, you type it, you see the result. No compilation, no setup, no ceremony. Just pure, immediate feedback.
The best BASIC programmers aren't the ones who memorize every command—they're the ones who experiment fearlessly. Try things. Break things. See what happens. Immediate mode makes exploration cost-free and learning inevitable.
Immediate mode isn't just a feature of BASIC. It's the heart of the BASIC experience. Master it, use it constantly, and you'll find programming in BASIC more intuitive and enjoyable than you imagined possible.
End of Chapter 3
Proceed to Chapter 4: Your First Program to learn how to transform immediate mode experiments into structured programs.
Your First Program
You've mastered immediate mode—entering commands and seeing instant results. Now it's time to take the next step: writing programs that you can save, edit, and run again and again. This is where BASIC transforms from a powerful calculator into a true programming language.
In this chapter, you'll write your first complete program, learn how BASIC organises code, and discover the tools for editing and managing your programs. By the end, you'll be a programmer—not just someone who types commands, but someone who creates software.
Take your time with each section. Every concept builds on the previous one, and mastering these fundamentals will make everything that follows much easier.
Understanding Line Numbers
Unlike modern programming languages where code runs from top to bottom in the order you type it, BASIC programs are organised by line numbers. Every line of your program begins with a number, and BASIC uses these numbers to determine the order of execution.
CODE_FENCE_0
When you run this program, BASIC executes line 10 first, then line 20, then line 30.
Line numbers in SLP-BASIC can range from 0 to 65535. That's a lot of lines! In practice, you'll rarely need more than a few hundred lines for most programs.
The Convention: Counting by Tens
While you could number your lines 1, 2, 3, 4, 5..., experienced BASIC programmers use a different convention: increment by 10.
10 First line
20 Second line
30 Third line
40 Fourth line
Why skip numbers? Because later, when you're improving your program, you might need to add a line between two existing lines. If you have:
10 PRINT "HELLO"
20 PRINT "GOODBYE"
And you want to add a line between them, you can use any number from 11 to 19:
10 PRINT "HELLO"
15 PRINT "HOW ARE YOU?"
20 PRINT "GOODBYE"
Start your programs at line 10 and increment by 10. This gives you 9 "slots" (11-19, 21-29, etc.) for future additions between any two lines. Most programmers never need more than this!
Why Line Numbers Matter
Line numbers serve three critical purposes:
- Execution Order: BASIC runs lines from lowest to highest number
- Jump Targets: Commands like GOTO and GOSUB use line numbers to direct program flow
- Editing: You reference lines by number when making changes
Here's something magical: you can enter lines in any order, and BASIC will automatically sort them by line number. Enter line 30, then line 10, then line 20—when you LIST your program, they'll appear in numerical order: 10, 20, 30.
Your First Program: Hello World
Every programmer's journey begins with the same program: "Hello World." This simple program does one thing—displays a greeting on the screen. Let's write it together, step by step.
Step 1: Clear Your Workspace
First, make sure you're starting fresh. Type:
NEW
Press ENTER.
The NEW command clears any program currently in memory. You should see the READY. prompt again, indicating BASIC is ready for your first line.
NEW deletes your program permanently! There is no undo. Only use NEW when you're certain you want to start over. Later, we'll learn how to SAVE programs so you never lose your work.
Step 2: Enter Your First Line
Now type this exactly as shown:
10 PRINT "HELLO, WORLD!"
Press ENTER.
Let's break down what you just typed:
- 10 — The line number (we started at 10, following convention)
- PRINT — A BASIC command that displays text
- "HELLO, WORLD!" — The text to display (must be in quotes)
You should see the READY. prompt again. BASIC accepted your line and stored it in memory.
Step 3: Enter Your Second Line
Type:
20 END
Press ENTER.
The END command tells BASIC your program is finished. It's good practice to end every program with END.
Step 4: View Your Program
Type:
LIST
Press ENTER.
CODE_FENCE_0
Congratulations! You just entered your first complete program. The LIST command displays all the lines in memory, sorted by line number.
Step 5: Run Your Program
Now execute your program. Type:
RUN
Press ENTER.
CODE_FENCE_0
You did it! Your first program executed successfully. You told the computer to print a message, and it obeyed. This might seem simple, but you've just learned the fundamental cycle of programming:
- Write code (enter lines)
- Review code (LIST)
- Execute code (RUN)
- See results (output appears)
Try It Yourself
Here's an interactive version where you can experiment:
10 PRINT "HELLO, WORLD!"
20 END
The program is already loaded. Type RUN and press Enter to execute it. Then try LIST to see the program code.
Want to experiment? Type NEW to clear memory, then enter your own program line by line!
Try changing the message! Type 10 PRINT "YOUR NAME HERE" to replace line 10, then RUN again. You can modify programs as many times as you want.
How BASIC Sorts Your Program
One of BASIC's most helpful features is automatic line sorting. You don't have to enter lines in order—BASIC will organise them for you.
Let's prove it. Try this experiment:
Entering Lines Out of Order
Type these lines (yes, in this "backwards" order):
NEW
50 PRINT "LINE FIVE"
30 PRINT "LINE THREE"
10 PRINT "LINE ONE"
40 PRINT "LINE FOUR"
20 PRINT "LINE TWO"
Now type:
LIST
CODE_FENCE_0
Look at that! Even though you entered lines 50, 30, 10, 40, 20, BASIC displays them as 10, 20, 30, 40, 50.
Now type RUN:
CODE_FENCE_0
BASIC executed the lines in numerical order, not the order you typed them. This is incredibly useful—you can add lines anywhere in your program without worrying about reorganizing everything.
BASIC always:
- Stores lines sorted by line number
- Displays lines in numerical order (with LIST)
- Executes lines from lowest to highest number
Your typing order doesn't matter—only the line numbers matter!
Why This Matters
Imagine you've written a 50-line program and realize you need to add something near the beginning. Without automatic sorting, you'd have to retype everything. With BASIC, just insert a new line number between existing ones:
10 PRINT "FIRST"
15 PRINT "INSERTED LATER"
20 PRINT "SECOND"
50 PRINT "LINE FIVE"
30 PRINT "LINE THREE"
10 PRINT "LINE ONE"
40 PRINT "LINE FOUR"
20 PRINT "LINE TWO"
60 END
Type LIST to see how BASIC sorted these lines. Then type RUN to see execution order match line number order.
The LIST Command
The LIST command is your window into program memory. It shows you what BASIC has stored, formatted and organised. You've already used the basic form, but LIST has several powerful variations.
LIST (Display Everything)
The simplest form displays your entire program:
LIST
This shows every line from lowest to highest line number.
LIST n (Display One Line)
To see a single line, type LIST followed by the line number:
LIST 20
CODE_FENCE_0
This is useful when you want to check the contents of a specific line without scrolling through your entire program.
LIST n-m (Display a Range)
To see several consecutive lines, specify a range:
LIST 10-30
CODE_FENCE_0
The format is starting_line-ending_line. BASIC displays all lines from the start through the end, inclusive.
LIST -n (Display From Beginning)
To see everything from the start of your program up to a specific line:
LIST -30
CODE_FENCE_0
This shows line 30 and everything before it.
LIST n- (Display to End)
To see everything from a specific line to the end:
LIST 20-
CODE_FENCE_0
This shows line 20 and everything after it.
- LIST — See your entire program (most common)
- LIST 50 — Check what line 50 contains
- LIST 10-30 — Review a specific section
- LIST -30 — See the beginning of a long program
- LIST 100- — See the end of a long program
10 PRINT "LINE TEN"
20 PRINT "LINE TWENTY"
30 PRINT "LINE THIRTY"
40 PRINT "LINE FORTY"
50 PRINT "LINE FIFTY"
60 END
Try all the LIST variations:
LIST(shows everything)LIST 30(shows just line 30)LIST 20-40(shows lines 20, 30, 40)LIST -30(shows lines 10, 20, 30)LIST 40-(shows lines 40, 50, 60)
Running Your Program
You've learned to enter programs and view them with LIST. Now let's explore how to execute them with RUN.
The RUN Command
Type RUN and press ENTER to execute your program:
RUN
BASIC immediately:
- Jumps to the lowest line number
- Executes that line
- Moves to the next higher line number
- Continues until it reaches
ENDor runs out of lines
CODE_FENCE_0
RUN From Immediate Mode
RUN always works in immediate mode (when you see the READY. prompt). You can run your program as many times as you want:
RUN
(output appears)
READY.
RUN
(output appears again)
READY.
Each time you type RUN, BASIC starts fresh from the beginning.
What Happens During RUN
Let's trace execution step by step for this program:
10 PRINT "ONE"
20 PRINT "TWO"
30 PRINT "THREE"
40 END
- START: BASIC finds the lowest line (10)
- LINE 10: Executes
PRINT "ONE", displaysONE - LINE 20: Executes
PRINT "TWO", displaysTWO - LINE 30: Executes
PRINT "THREE", displaysTHREE - LINE 40: Executes
END, stops program - FINISH: Returns to
READY.prompt
Programs run continuously from start to finish without pausing (unless you use special commands like INPUT, which we'll learn later). BASIC executes each line as fast as possible.
The Importance of END
While not strictly required, ending your programs with END is good practice:
10 PRINT "HELLO"
20 END
END tells BASIC "stop here." Without it, BASIC stops when it runs out of lines—but using END makes your intent clear and prevents errors if you add lines later.
Get in the habit of ending every program with END. It prevents confusion and makes your code cleaner. Most experienced programmers use the highest line number (like 9999) for END so there's always room to add more lines before it.
10 PRINT "COUNTING..."
20 PRINT "1"
30 PRINT "2"
40 PRINT "3"
50 PRINT "DONE!"
60 END
Type RUN to execute this counting program. Try running it multiple times—each execution is independent and starts fresh.
Editing Lines
You'll frequently want to change parts of your program. BASIC makes editing simple: just re-enter the line number with new content.
How Editing Works
When you type a line number that already exists, BASIC replaces the old line with your new one.
Let's say you have:
10 PRINT "HELLO"
20 END
To change line 10, type:
10 PRINT "GOODBYE"
Now LIST shows:
CODE_FENCE_0
The old PRINT "HELLO" is gone, replaced by PRINT "GOODBYE".
Complete Replacement
Important: BASIC replaces the entire line, not just part of it. You must retype the complete new line:
CODE_FENCE_0
Editing Step by Step
Let's practice editing with a complete example:
Step 1: Enter this program:
NEW
10 PRINT "MY NAME IS BOB"
20 PRINT "I AM 25 YEARS OLD"
30 END
Step 2: Run it:
RUN
MY NAME IS BOB
I AM 25 YEARS OLD
READY.
Step 3: Change line 10:
10 PRINT "MY NAME IS ALICE"
Step 4: Change line 20:
20 PRINT "I AM 30 YEARS OLD"
Step 5: Check your changes:
LIST
10 PRINT "MY NAME IS ALICE"
20 PRINT "I AM 30 YEARS OLD"
30 END
READY.
Step 6: Run the edited program:
RUN
MY NAME IS ALICE
I AM 30 YEARS OLD
READY.
A common workflow:
RUNyour program- See something you want to change
- Retype that line number with new content
RUNagain to test your change
You can edit and run as many times as needed until your program works perfectly!
10 PRINT "THE SKY IS RED"
20 PRINT "GRASS IS PURPLE"
30 PRINT "WATER IS YELLOW"
40 END
This program has wrong colors! Edit it to fix them:
- Type
10 PRINT "THE SKY IS BLUE" - Type
20 PRINT "GRASS IS GREEN" - Type
30 PRINT "WATER IS BLUE" - Type
RUNto see your corrected program
Deleting Lines
Sometimes you need to remove a line entirely from your program. BASIC makes this easy: type the line number by itself, with nothing after it.
How to Delete a Line
To delete line 20:
20
Just the number, then ENTER. That's it!
CODE_FENCE_0
Line 20 is gone. Notice that line numbering doesn't change—line 10 is still 10, line 30 is still 30. You now have a gap where line 20 used to be.
Deleting Multiple Lines
Delete lines one at a time:
10
20
30
CODE_FENCE_0
Why Delete Lines?
Common reasons to delete lines:
- Removing debug code: You added
PRINTstatements to find a problem; delete them when done - Simplifying logic: You found a better way and don't need old code
- Fixing mistakes: You added a line you don't want
Delete vs. Edit
Remember the difference:
- Edit a line: Type the line number + new content
- Delete a line: Type the line number only
CODE_FENCE_0
Deleted lines are gone forever! There's no undo command. If you delete something by mistake, you must retype it. This is why experienced programmers LIST their programs frequently—to make sure everything looks correct.
10 PRINT "KEEP THIS"
20 PRINT "DELETE ME"
30 PRINT "KEEP THIS"
40 PRINT "DELETE ME TOO"
50 PRINT "KEEP THIS"
60 END
Practice deleting lines:
- Type
20to delete line 20 - Type
40to delete line 40 - Type
LISTto see what remains - Type
RUNto execute the cleaned-up program
Starting Fresh with NEW
The NEW command clears everything from memory—your entire program and all variables disappear. It's like wiping a chalkboard clean so you can start over.
When to Use NEW
Use NEW when you want to:
- Start writing a completely different program
- Clear out old code before typing in a new program
- Get a fresh start after experimenting
How NEW Works
Simply type:
NEW
Press ENTER. BASIC immediately:
- Deletes all program lines
- Clears all variables
- Resets to a clean state
- Shows the
READY.prompt
CODE_FENCE_0
Notice that LIST shows nothing—the program is completely gone.
NEW Is Permanent
NEW is PERMANENT and IMMEDIATE! There is:
- No "Are you sure?" prompt
- No undo
- No way to recover your program
- No confirmation
Once you type NEW and press ENTER, your program is gone forever.
Protecting Your Work
Before using NEW, make sure:
- You don't need your current program anymore
- You've saved anything important (we'll learn
SAVEin Chapter 12) - You're ready to start completely fresh
CODE_FENCE_0
NEW vs. Delete
Compare these approaches:
Delete individual lines:
10
20
30
(Specific lines removed)
Clear everything:
NEW
(All lines removed)
Use individual deletion when editing. Use NEW when starting completely fresh.
Type NEW at the start of each programming session if you're following along with examples. This ensures you're starting with a clean slate and won't have old code interfering with new programs.
10 PRINT "OLD PROGRAM"
20 PRINT "ABOUT TO BE CLEARED"
30 END
See NEW in action:
- Type
LISTto see the current program - Type
NEWto clear everything - Type
LISTagain (nothing will appear) - Enter a new program:
10 PRINT "NEW PROGRAM" - Type
LISTto see your fresh start
Your Second Program: Name Greeter
Now that you know the basics of program management, let's write a more interactive program. This one will ask for your name and then greet you personally.
Introducing INPUT
We need a new command: INPUT. This tells BASIC to pause and wait for you to type something:
INPUT A$
The A$ is a string variable—a place to store text. The $ means "text" (we'll learn more about variables in Chapter 5).
The Program
Let's build this program together:
Step 1: Start fresh:
NEW
Step 2: Enter the program:
10 PRINT "HELLO! WHAT IS YOUR NAME?"
20 INPUT A$
30 PRINT "NICE TO MEET YOU, "; A$
40 PRINT "WELCOME TO BASIC PROGRAMMING!"
50 END
Step 3: Check your work:
LIST
Make sure all five lines appear correctly.
Step 4: Run the program:
RUN
CODE_FENCE_0
When you see the ? prompt, type your name and press ENTER. The program uses your input!
How It Works
Let's examine each line:
Line 10: PRINT "HELLO! WHAT IS YOUR NAME?"
- Displays a question to the user
Line 20: INPUT A$
- Pauses and waits for input
- Shows a
?prompt - Stores whatever you type in the variable
A$
Line 30: PRINT "NICE TO MEET YOU, "; A$
- Prints text followed by the contents of
A$ - The semicolon (
;) combines text and variable without adding extra spaces
Line 40: PRINT "WELCOME TO BASIC PROGRAMMING!"
- Prints another message
Line 50: END
- Ends the program
Notice the semicolon in line 30: PRINT "TEXT"; A$
The semicolon tells BASIC to print things right next to each other. Without it, BASIC would print on separate lines. We'll learn more about formatting in Chapter 8.
Try It Yourself
10 PRINT "HELLO! WHAT IS YOUR NAME?"
20 INPUT A$
30 PRINT "NICE TO MEET YOU, "; A$
40 PRINT "WELCOME TO BASIC PROGRAMMING!"
50 END
Type RUN and enter your name when prompted. Run it multiple times with different names!
Challenge: Can you edit line 30 to say "HI" instead of "NICE TO MEET YOU"?
A$ is like a labeled box where BASIC stores text. When you type your name, BASIC puts it in the A$ box. Later, when you PRINT A$, BASIC looks in the box and displays what's inside.
You can use any variable name: NAME$, USERNAME$, X$—we'll learn the rules in Chapter 5.
Progressive Practice
Let's write a few more programs, each slightly more complex than the last. This will reinforce what you've learned and introduce new concepts gradually.
Program 3: Simple Calculator
This program asks for two numbers and adds them:
NEW
10 PRINT "SIMPLE CALCULATOR"
20 PRINT "ENTER FIRST NUMBER:"
30 INPUT A
40 PRINT "ENTER SECOND NUMBER:"
50 INPUT B
60 PRINT "THE SUM IS:"; A + B
70 END
CODE_FENCE_0
New Concepts:
AandBare numeric variables (no$because they hold numbers, not text)- You can do math directly in a
PRINTstatement:PRINT A + B - Multiple
INPUTstatements let you gather several pieces of information
10 PRINT "SIMPLE CALCULATOR"
20 PRINT "ENTER FIRST NUMBER:"
30 INPUT A
40 PRINT "ENTER SECOND NUMBER:"
50 INPUT B
60 PRINT "THE SUM IS:"; A + B
70 END
Try the calculator. Then challenge yourself: Can you add a line that multiplies the numbers too? (Hint: PRINT "THE PRODUCT IS:"; A * B)
Program 4: Multiple Greetings
This program shows how spacing and formatting affect output:
NEW
10 PRINT "================================"
20 PRINT " WELCOME TO MY PROGRAM"
30 PRINT "================================"
40 PRINT
50 PRINT "WHAT IS YOUR NAME?"
60 INPUT N$
70 PRINT
80 PRINT "HELLO, "; N$; "!"
90 PRINT "IT'S GREAT TO MEET YOU!"
100 PRINT
110 PRINT "HAVE A WONDERFUL DAY!"
120 END
CODE_FENCE_0
New Concepts:
PRINTwith no text prints a blank line (lines 40, 70, 100)- Multiple semicolons let you combine several pieces:
"HELLO, "; N$; "!" - Spaces in quotes create visual structure (line 20)
- Drawing with characters creates borders (lines 10, 30)
Blank lines (PRINT with nothing after it) make output easier to read. Compare:
Without blank lines: CODE_FENCE_0
With blank lines: CODE_FENCE_1
Much clearer!
10 PRINT "================================"
20 PRINT " WELCOME TO MY PROGRAM"
30 PRINT "================================"
40 PRINT
50 PRINT "WHAT IS YOUR NAME?"
60 INPUT N$
70 PRINT
80 PRINT "HELLO, "; N$; "!"
90 PRINT "IT'S GREAT TO MEET YOU!"
100 PRINT
110 PRINT "HAVE A WONDERFUL DAY!"
120 END
Run this program and notice the spacing. Try editing it to add more blank lines or change the border characters.
Program 5: Age Calculator
This program does simple math with your input:
NEW
10 PRINT "AGE CALCULATOR"
20 PRINT
30 PRINT "WHAT YEAR WERE YOU BORN?"
40 INPUT Y
50 PRINT "IN 1985, YOU WILL BE:"; 1985 - Y; "YEARS OLD"
60 PRINT "IN 2030, YOU WILL BE:"; 2030 - Y; "YEARS OLD"
70 PRINT "IN 2050, YOU WILL BE:"; 2050 - Y; "YEARS OLD"
80 END
CODE_FENCE_0
New Concepts:
- You can perform calculations with input:
1985 - Y - The same variable can be used multiple times (lines 50, 60, 70)
- BASIC does the math before printing the result
Notice how line 50, 60, and 70 are similar—only the year changes. Later, you'll learn about loops (Chapter 7) that let you repeat similar actions without repeating code. For now, repetition is fine!
10 PRINT "AGE CALCULATOR"
20 PRINT
30 PRINT "WHAT YEAR WERE YOU BORN?"
40 INPUT Y
50 PRINT "IN 1985, YOU WILL BE:"; 1985 - Y; "YEARS OLD"
60 PRINT "IN 2030, YOU WILL BE:"; 2030 - Y; "YEARS OLD"
70 PRINT "IN 2050, YOU WILL BE:"; 2050 - Y; "YEARS OLD"
80 END
Try the age calculator with different birth years. Notice how BASIC automatically performs the subtraction.
Common Beginner Mistakes
Every programmer makes mistakes—it's a normal part of learning! Here are the most common errors beginners encounter, and how to fix them.
Mistake 1: Forgetting Line Numbers
CODE_FENCE_0
Problem: You typed a command without a line number.
What BASIC thinks: "Is this immediate mode or program mode? No line number, so it must be immediate mode. But PRINT "HELLO" by itself is fine in immediate mode..."
Actually, this works! But if you meant to add it to your program, you need:
10 PRINT "HELLO"
Fix: Always start program lines with a number.
Mistake 2: Typos in Keywords
CODE_FENCE_0
Problem: You typed PRNT instead of PRINT.
Fix: BASIC keywords must be spelled exactly right. Double-check spelling!
Common typos:
PRNT→ Should bePRINTINPT→ Should beINPUTGOTO→ (This one is correct, but people often writeGO TO)
Mistake 3: Missing Quotes
CODE_FENCE_0
Problem: Text must be in quotes.
Fix:
10 PRINT "HELLO WORLD"
Rule: When printing literal text, surround it with quote marks. When printing variables, don't use quotes:
10 A$ = "BOB"
20 PRINT A$ (Correct: prints BOB)
30 PRINT "A$" (Wrong: prints A$)
Mistake 4: Reusing Line Numbers Accidentally
CODE_FENCE_0
Problem: You accidentally reused line 10, erasing your original line 10.
Fix: Be careful with line numbers! Check with LIST frequently to make sure you haven't overwritten something important.
Prevention: Use increments of 10 and always check what line number you're typing.
Mistake 5: Forgetting END
This isn't technically an error—BASIC will run programs without END—but it's a best practice:
10 PRINT "HELLO"
(Where's the END?)
Better:
10 PRINT "HELLO"
20 END
Why it matters: Without END, if you add more lines later, they might execute when you don't expect them to.
Mistake 6: Wrong Variable Type
CODE_FENCE_0
Problem: A$ stores text, but you're trying to add a number to it.
Fix: Use A (without $) for numbers:
10 INPUT A
20 PRINT A + 5
Rule:
- Variables ending in
$are for text (strings) - Variables without
$are for numbers
When you see an error:
- Read the error message — BASIC usually tells you what's wrong
- Check the line number — The error message often includes which line failed
- LIST that line — Use
LIST 20to see line 20 by itself - Look for common mistakes — Missing quotes, typos, wrong variable type
- Fix and try again — Retype the line correctly and
RUNagain
One More Thing: The LIST-RUN-FIX Cycle
Experienced programmers use this rhythm:
- WRITE some lines
- LIST to check what you entered
- RUN to test your program
- FIX any errors
- Repeat until it works
This cycle is the heart of programming. You won't get everything perfect the first time—nobody does! The key is catching and fixing errors quickly.
Chapter Summary: You're a Programmer Now!
Congratulations! You've reached the end of Chapter 4, and you've accomplished something remarkable: you've become a programmer.
Let's review what you now know:
Line Numbers and Program Organization
- Programs consist of numbered lines (0-65535)
- Convention: start at 10, increment by 10
- BASIC automatically sorts lines by number
- Execution flows from lowest to highest line number
Essential Commands
- NEW — Clear memory and start fresh
- LIST — Display program (with range options: LIST 10-30, LIST -30, LIST 30-)
- RUN — Execute your program from start to finish
- END — Mark the end of a program
Editing Techniques
- Re-enter a line — Type line number + new content (replaces old)
- Delete a line — Type line number only
- Insert a line — Use a number between existing lines (e.g., 15 between 10 and 20)
Programming Concepts
- PRINT — Display text and numbers
- INPUT — Ask the user for information
- Variables — Store data (
A$for text,Afor numbers) - Semicolons — Combine output without extra spaces
- Blank lines — Use
PRINTalone to add spacing
What You've Built
You've written five working programs:
- Hello World — Your first program
- Name Greeter — Interactive input and personalized output
- Simple Calculator — Math with user input
- Multiple Greetings — Formatted output with spacing
- Age Calculator — Using variables in calculations
Each program taught you new skills, building on the previous one.
The Programming Mindset
Most importantly, you've learned the fundamental programming workflow:
Write code → Review code → Run code → Fix errors → Repeat
This cycle is the same whether you're writing a 10-line BASIC program or a million-line application. You've mastered the essentials!
What's Next
You're ready to explore BASIC more deeply. The remaining chapters will teach you:
- Chapter 5 — Variables and data types in detail
- Chapter 6 — Operators for calculations and comparisons
- Chapter 7 — Program flow control (loops, conditions, jumps)
- Chapter 8 — Advanced input and output formatting
- Chapter 9 — Arrays for handling collections of data
- Chapter 10 — Built-in functions for math and strings
But you already have everything you need to experiment and create. Don't wait—start writing programs now! The best way to learn programming is by doing.
Before moving to Chapter 5, spend time writing your own programs:
- Make a program that asks for your favorite color
- Create a quiz with multiple questions
- Build a simple story generator
- Make a program that counts to 10
- Try anything that sounds interesting!
The more you practice, the more confident you'll become. Programming is a skill—and like any skill, it improves with practice.
One Final Interactive Challenge
Here's a blank slate. Write a program from scratch that:
- Asks for two pieces of information (name and favorite number)
- Displays a personalized message using both
- Performs a calculation with the number (multiply by 2, add 10, etc.)
Start with NEW, then build your program line by line. Use everything you learned in this chapter. There's no "right" answer—be creative!
You've completed Chapter 4. You're no longer just learning about programming—you're a programmer.
Welcome to the community. Keep exploring, keep building, and keep learning.
Variables and Data Types
Introduction to Variables
Variables are the foundation of programming. They're named storage locations where your program keeps data—numbers, text, results of calculations—for later use. Think of variables as labeled boxes: you put values into them, retrieve those values when needed, and update them as your program runs.
In BASIC, variables are created automatically the moment you use them. No declaration is needed (except for arrays, which we'll cover in Chapter 9). Simply assign a value to a name, and that variable exists:
A = 10
NAME$ = "ALICE"
COUNT% = 0
Three variables now exist: A holds the number 10, NAME$ holds the text "ALICE", and COUNT% holds the integer 0.
SLP-BASIC supports three fundamental data types, each optimized for different kinds of data:
- Numeric variables (floating-point): For general-purpose numbers with decimal precision
- Integer variables (% suffix): For whole numbers requiring faster arithmetic
- String variables ($ suffix): For text and character data
The type suffix—or lack thereof—determines how BASIC treats your variable. A, A%, and A$ are three completely different variables. The suffix is part of the name, indicating the type of data the variable holds.
Understanding when to use each type is crucial for writing efficient, bug-free programs. This chapter covers everything you need to know about variables: naming rules, type characteristics, assignment syntax, and type mixing behavior.
Variables persist across immediate mode commands and program execution. Once created, a variable retains its value until you assign a new value, run CLR, or run NEW. This persistence is useful for debugging but can cause confusion if you forget to initialize variables.
Variable Naming Rules
BASIC variable names follow straightforward rules, but there's one critical quirk inherited from Commodore BASIC V2 that surprises programmers: only the first two characters are significant.
Basic Naming Rules
Variable names must:
- Start with a letter (A-Z, case-insensitive)
- Contain letters and numbers after the first character
- End with a type suffix (% for integer, $ for string, nothing for numeric)
Valid variable names:
A ' Single-letter numeric variable
COUNT ' Multi-character numeric variable
INDEX% ' Integer variable
NAME$ ' String variable
X1 ' Variable with number
TOTAL99 ' Variable with multiple numbers
Invalid variable names:
9LIVES ' Cannot start with number
FIRST-NAME$ ' Hyphens not allowed
COUNT TOTAL ' Spaces not allowed
MY.VALUE ' Periods not allowed
The Two-Character Significance Rule
Here's the crucial detail: BASIC only looks at the first two characters of a variable name. Everything after the first two characters is ignored. This means:
COUNT = 10
COUNTER = 20
COUNTRY = 30
PRINT COUNT ' Prints 30!
All three variable names start with "CO", so BASIC treats them as the same variable. The last assignment (COUNTRY = 30) overwrites the previous values. Only COUNT (or COUNTER, or COUNTRY—they're identical to BASIC) exists, and it holds 30.
This behavior is authentic to Commodore BASIC V2 and was a memory-saving measure in the 1980s. Modern programmers find it surprising, but it's preserved in SLP-BASIC for compatibility.
Always ensure variable names have unique first two characters. Use a naming convention that makes this natural: A, B, C, D for simple variables; AA, AB, AC, AD for related groups; or use a spreadsheet to track your two-character prefixes in large programs.
Practical Naming Strategies
Given the two-character limitation, effective variable naming requires planning:
Single-letter names for simple programs:
A = 5
B = 10
C = A + B
Two-letter names for clarity:
SC = 0 ' SCore
HP = 100 ' Hit Points
LV = 1 ' LeVel
Longer names for readability (remembering only first two matter):
NAME$ = "ALICE" ' NA is the key
ADDRESS$ = "123" ' AD is the key
NOTES$ = "HELLO" ' NO is the key
The long names make your code more readable, but you must ensure the first two letters are unique across all variables of the same type.
Type Suffix Separation
The type suffix (%, $) creates separate namespaces. These are three different variables:
COUNT = 42 ' Numeric variable CO
COUNT% = 100 ' Integer variable CO%
COUNT$ = "MANY" ' String variable CO$
Even though all three start with "CO", the suffix makes them distinct. You can have a numeric A, an integer A%, and a string A$ simultaneously without conflict.
Case Insensitivity
BASIC doesn't distinguish between uppercase and lowercase letters:
Name$ = "ALICE"
name$ = "BOB"
NAME$ = "CHARLIE"
PRINT name$ ' Prints CHARLIE
All four references are to the same variable. BASIC internally treats everything as uppercase, so Name$, name$, NAME$, and nAmE$ all refer to the same string variable.
This manual shows variable names in lowercase or mixed case for readability, but you can type them in any case you prefer.
Reserved Words
You cannot use BASIC keywords as variable names, but you can embed them:
FOR = 10 ' Error: FOR is a keyword
FORGET = 10 ' OK: Starts with FO
IFFY = 20 ' OK: Starts with IF
Since only the first two characters matter, FORGET and FOR would conflict anyway (both start with FO). Choose names that don't begin with keyword prefixes: avoid FO, NE, IF, GO, etc.
Adopt a systematic naming convention. For example: use A-Z for loop counters, AA-AZ for array indices, BA-BZ for user input, CA-CZ for calculated results, DA-DZ for temporary values, etc. Document your convention at the top of your program with REM statements.
Numeric Variables
Numeric variables are BASIC's default variable type. When you use a variable name without a type suffix, you get a numeric variable. Numeric variables store floating-point numbers—numbers with decimal points and wide range.
Declaration and Assignment
Numeric variables are created automatically on first use:
X = 5 ' Create X, assign 5
PI = 3.14159 ' Create PI, assign π
TEMP = -40 ' Negative numbers work
HUGE = 1.7E38 ' Scientific notation
No declaration is needed. The moment you assign to a previously unused name, that variable exists and holds the assigned value.
IEEE 754 Single-Precision Format
SLP-BASIC uses IEEE 754 single-precision floating-point format for numeric variables. This is the same format used by most modern programming languages for their "float" type. The format provides:
Range: Approximately ±1.7 × 10^±38
- Smallest positive: ~1.2 × 10^-38
- Largest positive: ~3.4 × 10^38
- Symmetric negative range
Precision: Approximately 7 decimal digits
- 6-7 significant figures in most cases
- Precision decreases for very large or very small numbers
- Not suitable for financial calculations requiring exact decimal representation
This means you can represent huge numbers (1000000000) and tiny numbers (0.0000001), but you can't rely on exact representation beyond about 7 digits:
A = 1234567 ' Stored exactly
B = 12345678 ' Some precision lost
C = 123456789 ' More precision lost
PRINT C ' May not print exactly 123456789
For most BASIC programs—games, educational software, scientific calculations—this precision is more than adequate. The Commodore 64 used a slightly different floating-point format with similar characteristics, so this behavior is authentic to the BASIC experience.
When to Use Numeric Variables
Use numeric variables when you need:
- Decimal values: 3.14, 0.5, -2.718
- Large numbers: Beyond ±32767 (integer range)
- Scientific notation: 1.23E-5, 6.022E23
- Division results: 10 / 3 = 3.333... (not an integer)
- Trigonometric functions: SIN, COS, TAN return floating-point
- Default behavior: When you're not sure, numeric works
Numeric variables are versatile but slower than integer variables for whole-number arithmetic. If you're only using whole numbers in a performance-critical loop, consider integer variables instead.
Numeric Variable Examples
<BasicCode>
PRINT "CALCULATING CIRCLE AREA"
RADIUS = 5
PI = 3.14159
AREA = PI * RADIUS * RADIUS
PRINT "RADIUS: "; RADIUS
PRINT "AREA: "; AREA
</BasicCode>
Common uses:
PRICE = 19.95 ' Money (note precision limits)
ANGLE = 45 ' Degrees (convert to radians for trig)
AVERAGE = 87.3 ' Statistical result
RATIO = 0.618 ' Proportions
DISTANCE = 1.5E8 ' Scientific: 150,000,000 km
Initialization Values
Newly created numeric variables automatically initialize to 0:
PRINT X ' Prints 0 (X didn't exist before)
X = 10
PRINT X ' Prints 10
This differs from some languages where uninitialized variables contain garbage. In BASIC, all variables start with a sensible default: 0 for numeric, 0 for integer, empty string for string.
Avoid comparing floating-point numbers for exact equality. Due to precision limitations, calculations that should be equal may differ slightly. Instead of IF A = B THEN, use IF ABS(A - B) < 0.0001 THEN to test approximate equality.
Integer Variables
Integer variables, indicated by the % suffix, store whole numbers in a restricted range but offer significantly faster arithmetic. For programs with intensive calculations using only whole numbers, integers can noticeably improve performance.
Declaration and Assignment
Add % to the variable name to create an integer variable:
COUNT% = 0 ' Integer counter
INDEX% = 1 ' Array index
SCORE% = 1000 ' Game score
LIVES% = 3 ' Remaining lives
The % is part of the variable name. COUNT and COUNT% are completely different variables—one numeric (floating-point), one integer.
16-Bit Signed Integer Format
Integer variables use 16-bit signed integer format:
Range: -32768 to 32767
- Exactly 65536 possible values
- Stored as two bytes in memory
- Fixed range with no precision loss
Attempting to store values outside this range causes overflow:
BIG% = 40000 ' Error: overflow
SMALL% = -40000 ' Error: overflow
MAX% = 32767 ' OK: maximum value
MIN% = -32768 ' OK: minimum value
Unlike numeric variables that can represent huge numbers, integers have a hard limit. Know your data range before choosing integer variables.
Arithmetic Behavior
Integer arithmetic is exact for results within range:
A% = 100
B% = 200
C% = A% + B% ' C% = 300 (exact)
D% = 10 / 3 ' D% = 3 (truncated, not rounded)
Division truncates toward zero (fractional parts are discarded):
X% = 10 / 3 ' X% = 3
Y% = 10 / 4 ' Y% = 2
Z% = -10 / 3 ' Z% = -3
This truncation can surprise beginners. If you need the remainder, use modulo arithmetic:
QUOTIENT% = 10 / 3 ' 3
REMAINDER% = 10 - (QUOTIENT% * 3) ' 1
Performance Advantage
Integer arithmetic is faster than floating-point arithmetic—often 2-3 times faster on modern processors, and even more significant on the original 6502 hardware. For loops and counters, this adds up:
FOR I% = 1 TO 10000 ' Faster with I%
TOTAL% = TOTAL% + 1
NEXT I%
Versus:
FOR I = 1 TO 10000 ' Slower with floating-point I
TOTAL = TOTAL + 1
NEXT I
On a 1MHz Commodore 64, this difference was dramatic. In SLP-BASIC's WebAssembly implementation, it's less noticeable but still measurable in tight loops.
When to Use Integer Variables
Use integer variables when:
- Counting: Loop counters, iteration indices
- Whole numbers only: No decimals needed
- Range fits: Values guaranteed within ±32767
- Performance matters: Tight loops, intensive calculations
- Array indices: DIM A(100): FOR I%=0 TO 100: A(I%)=0: NEXT
Don't use integer variables when:
- Division produces fractions: 10 / 3 = 3.333... (lost in integer)
- Range uncertain: User input might exceed ±32767
- Decimal precision required: Money, measurements, scientific data
- Mixed with floating-point: Type conversions slow down performance
Use integer variables for loop counters and array indices. This is the single most effective optimization you can make in BASIC programs. The speed difference in a 10,000-iteration loop is measurable and worthwhile.
Integer Variable Examples
<BasicCode>
PRINT "INTEGER ARITHMETIC DEMO"
A% = 10
B% = 3
PRINT "A% = "; A%
PRINT "B% = "; B%
PRINT "A% + B% = "; A% + B%
PRINT "A% - B% = "; A% - B%
PRINT "A% * B% = "; A% * B%
PRINT "A% / B% = "; A% / B%
PRINT "(TRUNCATED, NOT ROUNDED)"
</BasicCode>
Common integer uses:
SCORE% = 0 ' Game score
LIVES% = 3 ' Player lives
LEVEL% = 1 ' Current level
COUNT% = 0 ' Items counted
INDEX% = 0 ' Array position
YEAR% = 1985 ' Year (within range)
DAY% = 15 ' Day of month
TRIES% = 10 ' Attempts remaining
String Variables
String variables, indicated by the $ suffix, store text data—characters, words, sentences, or any sequence of characters up to 255 bytes in length. Strings are fundamental to interactive programs that display text and accept user input.
Declaration and Assignment
Add $ to the variable name to create a string variable:
NAME$ = "ALICE"
MESSAGE$ = "HELLO, WORLD!"
EMPTY$ = ""
LETTER$ = "X"
Strings are enclosed in double quotes. The quotes delimit the string but aren't part of the stored value—NAME$ contains ALICE, not "ALICE".
String Length Limit
SLP-BASIC strings can hold up to 255 characters:
SHORT$ = "HI" ' 2 characters
LONG$ = STRING$(255, "X") ' 255 X's
TOOLONG$ = STRING$(300, "X") ' Error: string too long
This limit is generous for most purposes. A full screen of C64 text (40×25 = 1000 characters) exceeds it, but typical strings—names, messages, input—fit easily.
The 255-character limit comes from using a single byte to store string length internally, a common design in 1980s BASIC implementations.
UTF-8 Encoding (Modern Enhancement)
Unlike original Commodore BASIC (which used PETSCII encoding), SLP-BASIC uses UTF-8 encoding for strings. This means you can use Unicode characters:
SMILE$ = "😊" ' Emoji (if your terminal supports it)
ACCENT$ = "café" ' Accented characters
GREEK$ = "π ≈ 3.14" ' Mathematical symbols
This is a modern enhancement for international text support. Be aware that multi-byte UTF-8 characters count toward the 255-byte limit based on their encoded size, not their visual character count.
String Operations
Strings can be concatenated (joined) with the + operator:
FIRST$ = "HELLO"
LAST$ = "WORLD"
FULL$ = FIRST$ + " " + LAST$
PRINT FULL$ ' Prints: HELLO WORLD
Strings can be compared with relational operators:
A$ = "APPLE"
B$ = "BANANA"
IF A$ < B$ THEN PRINT "A COMES FIRST" ' True: alphabetically earlier
String comparison is case-sensitive and follows ASCII/UTF-8 ordering. Chapter 10 covers string functions (LEFT$, RIGHT$, MID$, LEN, etc.) in detail.
When to Use String Variables
Use string variables for:
- User input: Names, messages, commands
- Text display: Labels, prompts, output
- Character data: Single letters, codes
- Formatting: Building formatted output
- Parsing: Breaking down input into components
Essentially, if your data is text rather than numbers, use a string variable.
Empty Strings
The empty string ("") is a string containing zero characters:
EMPTY$ = ""
IF EMPTY$ = "" THEN PRINT "NOTHING HERE" ' True
IF LEN(EMPTY$) = 0 THEN PRINT "LENGTH ZERO" ' True
Empty strings are useful for initializing string variables, testing for input, and building strings character by character.
Initialization Values
Newly created string variables automatically initialize to the empty string:
PRINT LEN(NEWVAR$) ' Prints 0 (NEWVAR$ didn't exist, now empty)
NEWVAR$ = "HELLO"
PRINT LEN(NEWVAR$) ' Prints 5
Like numeric variables initializing to 0, string variables initialize to "", ensuring predictable behavior.
To include a double quote inside a string, you must use CHR$(34): MESSAGE$ = "HE SAID " + CHR$(34) + "HELLO" + CHR$(34). There's no escape sequence like " in modern languages. ASCII 34 is the double-quote character.
String Variable Examples
<BasicCode>
PRINT "STRING OPERATIONS"
FIRST$ = "HELLO"
LAST$ = "WORLD"
FULL$ = FIRST$ + " " + LAST$
PRINT FULL$
PRINT "LENGTH: "; LEN(FULL$)
PRINT "FIRST 5 CHARS: "; LEFT$(FULL$, 5)
</BasicCode>
Common string uses:
NAME$ = "ALICE" ' User name
PROMPT$ = "ENTER NAME" ' Input prompt
ANSWER$ = "YES" ' User response
LINE$ = "" ' Build string dynamically
MENU$ = "1) PLAY" ' Menu option
ERROR$ = "INVALID" ' Error message
CODE$ = "X1B2" ' Alphanumeric code
Variable Assignment
Variable assignment stores a value in a variable. BASIC provides two syntaxes for assignment: with the optional LET keyword and without it. Both forms are equivalent; LET is a historical artifact preserved for compatibility.
Assignment Without LET
The modern, preferred syntax omits LET:
X = 10 ' Assign 10 to X
NAME$ = "ALICE" ' Assign "ALICE" to NAME$
COUNT% = 0 ' Assign 0 to COUNT%
This is clear, concise, and matches most modern programming languages. The equals sign (=) is the assignment operator: the variable on the left receives the value on the right.
Assignment With LET
The traditional BASIC syntax includes the LET keyword:
LET X = 10
LET NAME$ = "ALICE"
LET COUNT% = 0
LET explicitly indicates assignment and was required in early BASIC dialects. By the time of Commodore BASIC V2, LET was optional. Most programmers omit it, but you'll see it in vintage program listings and old books.
SLP-BASIC accepts both forms. Choose whichever you prefer, but be consistent within your programs.
LET was inspired by mathematical notation: "Let x = 10" is how mathematicians introduce variable assignments. Early BASIC designers wanted the language to feel familiar to math students. As programming evolved, the redundant keyword was dropped.
Assignment Expressions
The right side of an assignment can be any expression—literal values, variables, calculations, function calls:
A = 5 ' Literal number
B = A ' Copy another variable
C = A + B ' Arithmetic expression
D = SQR(C) ' Function result
E = (A + B) * 2 ' Complex expression
The expression is evaluated first, then the result is stored in the variable:
X = 10
X = X + 1 ' Read X (10), add 1, store result (11) back in X
PRINT X ' Prints 11
This pattern—reading a variable, modifying its value, storing the result back—is fundamental to programming. It looks strange mathematically (x = x + 1 has no solution!), but it makes perfect sense in programming: "take the current value of X, add 1, and make that the new value of X."
Multiple Assignments
BASIC doesn't support multiple assignment in one statement. You must assign variables one at a time:
A = 5 ' OK
B = 10 ' OK
A = B = 5 ' Not supported: syntax error
However, you can use multiple statements on one line with the colon separator:
10 A = 5: B = 10: C = 15
This is purely a space-saving technique. It doesn't execute faster or change program behavior.
Assignment vs. Comparison
The equals sign (=) serves two purposes in BASIC:
- Assignment (in statements): X = 10 stores 10 in X
- Comparison (in expressions): IF X = 10 tests whether X equals 10
Context determines which meaning applies:
X = 10 ' Assignment: store 10 in X
IF X = 10 THEN ... ' Comparison: test if X equals 10
Y = (X = 10) ' Comparison: Y gets -1 (true) or 0 (false)
This dual use can be confusing initially, but you'll quickly learn to recognise assignment (on its own) versus comparison (inside IF, WHILE, or an expression).
Omit LET unless you're maintaining vintage code that uses it consistently. Modern BASIC style prefers the shorter syntax: X = 10 rather than LET X = 10. Save the four characters and visual clutter.
Assignment Examples
<BasicCode>
PRINT "ASSIGNMENT DEMONSTRATION"
X = 5
PRINT "X = "; X
X = X + 10
PRINT "X = X + 10"
PRINT "X NOW = "; X
Y = X * 2
PRINT "Y = X * 2"
PRINT "Y = "; Y
</BasicCode>
The CLR Command
The CLR command (short for "clear") erases all variables from memory while preserving your program. It's useful for resetting your program's state without retyping the entire program.
Syntax
CLR
CLR takes no parameters and returns nothing. It's a command, not a statement—you typically execute it in immediate mode or at the beginning of a program.
What CLR Does
CLR performs these actions:
- Erases all variables: Numeric, integer, and string variables are removed
- Erases all arrays: Arrays declared with DIM are removed
- Resets DATA pointer: RESTORE to the first DATA statement
- Clears user-defined functions: DEF FN definitions are erased
- Preserves program: Your program lines remain intact
After CLR, it's as if you just loaded the program—no variables exist, but the program is ready to run.
When to Use CLR
Use CLR when:
- Testing a program repeatedly: Run, see results, CLR, modify, run again
- Program initialization: Some programs start with CLR to ensure clean state
- Debugging: Clear variables to test with fresh values
- After errors: If variables are in an inconsistent state, CLR resets everything
Don't use CLR if:
- You need variable values: CLR is destructive—variables are gone
- Program is running: CLR during execution may cause unpredictable behavior
CLR vs. NEW
Understand the difference:
- CLR: Erases variables, preserves program
- NEW: Erases variables AND program—total memory wipe
NEW is for starting fresh with a new program. CLR is for resetting variable state while keeping your program.
NEW ' Everything gone: program + variables
CLR ' Only variables gone: program remains
CLR in Programs
You can include CLR in a program line, typically at the beginning:
10 CLR
20 PRINT "VARIABLES CLEARED"
30 REM ... rest of program
This ensures a clean state every time the program runs. However, most programs don't need this—variables initialize to sensible defaults (0, 0%, "", or empty array) automatically.
Example: Using CLR
<BasicCode>
X = 10
NAME$ = "ALICE"
COUNT% = 5
PRINT "X = "; X
PRINT "NAME$ = "; NAME$
PRINT "COUNT% = "; COUNT%
CLR
PRINT "AFTER CLR:"
PRINT "X = "; X
PRINT "NAME$ = "; NAME$
PRINT "COUNT% = "; COUNT%
</BasicCode>
After CLR, all variables revert to their initial values: 0 for numeric, 0 for integer, empty string for string.
CLR cannot be undone. If you had important values in variables, they're gone. Use CLR deliberately, not carelessly. For testing, consider using a test program that sets known values rather than relying on CLR to erase unknown values.
Type Mixing and Conversion
BASIC's three variable types—numeric, integer, and string—are distinct and incompatible in direct operations. Understanding how BASIC handles (or refuses to handle) type mixing is crucial for avoiding errors and writing correct programs.
Type Strictness
Each variable type is separate:
A = 10 ' Numeric variable
A% = 20 ' Integer variable (different from A)
A$ = "30" ' String variable (different from both)
These three variables coexist independently. Changing one doesn't affect the others. The type suffix creates separate namespaces.
Automatic Type Conversion
BASIC automatically converts between numeric and integer types in expressions:
X = 10 ' Numeric
Y% = 20 ' Integer
Z = X + Y% ' Z = 30 (numeric result)
W% = X + Y% ' W% = 30 (integer result, X converted to integer)
Numeric and integer values mix freely in arithmetic. The result type depends on the receiving variable:
- Assigning to numeric variable: Result is floating-point
- Assigning to integer variable: Result is truncated to integer
Truncation happens automatically:
X = 10.7
Y% = X ' Y% = 10 (truncated, not rounded)
This conversion is usually what you want, but be aware of truncation in integer assignments.
String Conversions Are Explicit
Strings do not automatically convert to or from numbers. You must use conversion functions:
- STR$(n): Convert number to string
- VAL(s$): Convert string to number
Attempting to mix types without conversion causes an error:
X = 10
NAME$ = "ALICE"
RESULT = X + NAME$ ' ERROR: TYPE MISMATCH
This error protects you from nonsensical operations. What would it mean to add 10 to "ALICE"? BASIC refuses to guess.
Explicit Conversion Examples
Convert number to string:
SCORE = 1000
MESSAGE$ = "YOUR SCORE: " + STR$(SCORE)
PRINT MESSAGE$ ' Prints: YOUR SCORE: 1000
Note: STR$ adds a leading space for positive numbers (for alignment with negative numbers, which have a - sign). This is authentic BASIC behavior.
Convert string to number:
INPUT "ENTER AGE"; A$
AGE = VAL(A$) ' Convert string input to number
IF AGE < 18 THEN PRINT "TOO YOUNG"
VAL converts a string to its numeric value. If the string isn't a valid number, VAL returns 0:
X = VAL("123") ' X = 123
Y = VAL("12.5") ' Y = 12.5
Z = VAL("HELLO") ' Z = 0 (not a number)
Type Mismatch Errors
The most common type-related error is ?TYPE MISMATCH ERROR, which occurs when:
- Assigning wrong type: Numeric to string variable
- Mixing incompatible types: String arithmetic
- Wrong argument type: Function expecting number receives string
Examples:
X = "HELLO" ' Error: string assigned to numeric variable
NAME$ = 100 ' Error: number assigned to string variable
Y = 10 + "5" ' Error: can't add number and string
Always match types: numeric/integer to numeric/integer variables, strings to string variables. Use conversion functions when crossing type boundaries.
Type Checking Best Practices
To avoid type errors:
- Use clear naming conventions: Suffix string variables with $ and integer variables with %
- Convert explicitly: Never rely on implicit string conversion (there isn't any)
- Check input types: After INPUT to string variable, use VAL if you need a number
- Test boundary cases: Try invalid input to see how your program handles it
INPUT always reads to a string variable first, then convert to number if needed: INPUT "AGE"; A$: AGE = VAL(A$). This gives you control over invalid input (VAL returns 0 for non-numeric input, which you can detect and handle).
Mixed-Type Expression Example
<BasicCode>
PRINT "TYPE CONVERSION DEMO"
X = 10
Y% = 3
PRINT "X (NUMERIC) = "; X
PRINT "Y% (INTEGER) = "; Y%
PRINT "X + Y% = "; X + Y%
PRINT "X / Y% = "; X / Y%
PRINT ""
S$ = "100"
PRINT "S$ (STRING) = "; S$
N = VAL(S$)
PRINT "VAL(S$) = "; N
PRINT "N + X = "; N + X
</BasicCode>
Summary Table of Variable Types
| Type | Suffix | Range/Length | Precision | Example | Use Case |
|---|---|---|---|---|---|
| Numeric | (none) | ±1.7E±38 | ~7 digits | PI = 3.14159 | General math, decimals |
| Integer | % | -32768 to 32767 | Exact | COUNT% = 100 | Loops, counters, whole numbers |
| String | $ | 0-255 chars | N/A | NAME$ = "ALICE" | Text, user input, messages |
Common Mistakes and Gotchas
Learning BASIC's variable system involves avoiding several common pitfalls. This section documents the mistakes beginners (and experienced programmers new to BASIC) frequently make.
Mistake 1: Forgetting Two-Character Significance
The most surprising rule: only the first two characters of a variable name matter.
COUNTER = 10
COUNT = 20
PRINT COUNTER ' Prints 20, not 10!
Solution: Plan variable names carefully. Use a prefix system (AA, AB, AC...) or check the first two characters of every variable in your program.
Mistake 2: Case Confusion
BASIC is case-insensitive. Name$ and NAME$ are the same variable.
Name$ = "ALICE"
PRINT name$ ' Prints ALICE (same variable)
This isn't usually a problem, but it surprises programmers from case-sensitive languages.
Solution: Pick one case style and stick with it. This manual uses lowercase or PascalCase for readability.
Mistake 3: Type Mismatch in Assignment
Assigning the wrong type to a variable causes errors:
X = "HELLO" ' Error: string to numeric variable
NAME$ = 100 ' Error: number to string variable
Solution: Match types or use conversion functions (STR$, VAL). INPUT to string first, then convert to number if needed.
Mistake 4: String Arithmetic
You can't do arithmetic on strings without converting first:
A$ = "10"
B$ = "20"
C = A$ + B$ ' Error: TYPE MISMATCH
Solution: Convert with VAL:
C = VAL(A$) + VAL(B$) ' C = 30
Mistake 5: Integer Overflow
Integer variables have a limited range (-32768 to 32767):
BIG% = 40000 ' Error: overflow
Solution: Use numeric variables for large numbers, or ensure your data fits the integer range.
Mistake 6: Integer Division Truncation
Integer division truncates, which can surprise:
X% = 10
Y% = 3
Z% = X% / Y% ' Z% = 3, not 3.333...
The fractional part is discarded, not rounded.
Solution: Use numeric variables if you need decimal results:
Z = X% / Y% ' Z = 3.333... (floating-point)
Mistake 7: Uninitialized Variable Assumptions
Assuming a variable has a specific value without initializing it:
10 TOTAL = TOTAL + 10
20 PRINT TOTAL
RUN
This works (TOTAL starts at 0, becomes 10), but if TOTAL already existed from a previous run, it starts with that value instead.
Solution: Always initialize variables explicitly:
10 TOTAL = 0
20 TOTAL = TOTAL + 10
30 PRINT TOTAL
Or use CLR at the program start to ensure clean state.
Mistake 8: Confusing A, A%, and A$
These are three completely different variables:
A = 10
A% = 20
A$ = "30"
PRINT A ' Prints 10
PRINT A% ' Prints 20
PRINT A$ ' Prints 30
Solution: Use distinct base names for different purposes. Don't rely on type suffixes to differentiate logically unrelated variables.
Mistake 9: Forgetting String Length Limit
Strings are limited to 255 characters:
LONG$ = STRING$(300, "X") ' Error: string too long
Solution: Check string length with LEN before operations that might exceed 255 characters. Split long text into multiple variables if needed.
Mistake 10: Assuming String = Empty Means False
In BASIC, comparisons return -1 (true) or 0 (false), not boolean types:
A$ = ""
IF A$ = "" THEN PRINT "EMPTY" ' Correct
IF A$ THEN PRINT "NOT EMPTY" ' Wrong: doesn't work as expected
BASIC doesn't treat empty string as false in boolean context.
Solution: Always use explicit comparisons: IF A$ = "" or IF LEN(A$) = 0.
Summary
Variables are the foundation of BASIC programming. This chapter covered:
- Variable naming rules: Start with letter, first two characters significant, case-insensitive
- Numeric variables: IEEE 754 single-precision, ±1.7E±38 range, ~7 digits precision
- Integer variables: % suffix, -32768 to 32767, faster arithmetic, exact for whole numbers
- String variables: $ suffix, up to 255 characters, UTF-8 encoded
- Assignment syntax: With or without LET (LET is optional and typically omitted)
- CLR command: Erases variables, preserves program
- Type conversion: Automatic between numeric/integer, explicit (STR$/VAL) for strings
- Common mistakes: Two-character significance, type mismatches, integer overflow
Key takeaways:
- Plan variable names carefully: The two-character significance rule requires thoughtful naming
- Choose the right type: Numeric for decimals and large numbers, integer for fast whole-number math, string for text
- Convert explicitly: Always use STR$ and VAL when crossing the number/string boundary
- Initialize variables: Don't assume initial values (even though they're predictable)
- Match types: Keep numeric with numeric, string with string, to avoid TYPE MISMATCH errors
With solid understanding of variables and data types, you're ready to explore operators (Chapter 6) and program flow control (Chapter 7)—the tools that turn static data into dynamic programs that calculate, decide, and respond to user input.
End of Chapter 5
Proceed to Chapter 6: Operators to learn how to manipulate variables with arithmetic, comparison, and logical operators.
Operators
Understanding Operators
Operators are the symbols that tell BASIC how to combine, compare, and manipulate values. They're the mathematical and logical machinery that transforms static data into dynamic computation. Whether you're adding two numbers, comparing values for equality, or combining logical conditions, operators are your tools.
BASIC provides five categories of operators:
Arithmetic Operators: Perform mathematical calculations (+, -, *, /, ^)
Comparison Operators: Compare values and return true or false (=, <>, <, >, <=, >=)
Logical Operators: Combine and invert logical conditions (AND, OR, NOT)
String Operator: Concatenate strings together (+)
Parentheses: Group operations and override default precedence
Understanding operator precedence—the order in which operations execute—is essential for writing correct programs. BASIC follows mathematical conventions but adds logical operators that require attention. This chapter provides the comprehensive reference you need to master operators and write clear, correct expressions.
Arithmetic Operators
Arithmetic operators perform mathematical calculations. BASIC supports the five fundamental operations: addition, subtraction, multiplication, division, and exponentiation.
Addition (+)
The addition operator adds two numeric values:
PRINT 5 + 3
8
Addition works with any numeric type—floating-point, integer, or combinations:
A = 10
B% = 5
PRINT A + B%
15
Subtraction (-)
The subtraction operator subtracts the right value from the left value:
PRINT 10 - 3
7
Subtraction can produce negative results:
PRINT 5 - 10
-5
Multiplication (*)
The multiplication operator multiplies two values:
PRINT 6 * 7
42
Use multiplication for repeated addition, area calculations, and scaling:
PRICE = 19.95
QUANTITY = 3
TOTAL = PRICE * QUANTITY
PRINT TOTAL
59.85
Division (/)
The division operator divides the left value by the right value:
PRINT 20 / 4
5
Division always produces a floating-point result, even when dividing integers evenly:
PRINT 10 / 2
5
Dividing by zero produces a ?DIVISION BY ZERO ERROR and halts program execution. Always validate divisors when user input or calculations might produce zero.
Example of safe division:
10 INPUT "ENTER DIVISOR"; D
20 IF D = 0 THEN PRINT "CANNOT DIVIDE BY ZERO": GOTO 10
30 PRINT "RESULT: "; 100 / D
Exponentiation (^)
The exponentiation operator raises the left value to the power of the right value:
PRINT 2 ^ 3
8
This is equivalent to 2 × 2 × 2. Exponentiation is useful for squares, cubes, and exponential growth:
PRINT 5 ^ 2
25
PRINT 10 ^ 3
1000
PRINT 2 ^ 10
1024
Exponentiation supports fractional exponents for roots:
PRINT 16 ^ 0.5
4
This calculates the square root (16^0.5 = √16 = 4).
Negative exponents produce reciprocals:
PRINT 2 ^ -3
0.125
This is equivalent to 1/(2^3) = 1/8 = 0.125.
Unlike most operators, exponentiation associates right-to-left. This means 2^3^2 is evaluated as 2^(3^2) = 2^9 = 512, not (2^3)^2 = 8^2 = 64. Use parentheses for clarity when chaining exponentiation.
Unary Minus
The minus sign can also be used as a unary operator to negate a value:
A = 10
PRINT -A
-10
Unary minus has higher precedence than binary operators (except exponentiation), so:
PRINT -2 ^ 2
-4
This calculates -(2^2) = -4, not (-2)^2 = 4. Use parentheses for the latter:
PRINT (-2) ^ 2
4
Operator Precedence
When an expression contains multiple operators, BASIC evaluates them in a specific order called precedence. Understanding precedence ensures your expressions calculate correctly.
Precedence Table
From highest precedence (evaluated first) to lowest (evaluated last):
| Precedence | Operator(s) | Description | Example |
|---|---|---|---|
| 1 (highest) | () |
Parentheses | (2 + 3) * 4 |
| 2 | ^ |
Exponentiation | 2 ^ 3 |
| 3 | - (unary) |
Negation | -5 |
| 4 | * / |
Multiplication, Division | 6 * 4 / 2 |
| 5 | + - |
Addition, Subtraction | 5 + 3 - 2 |
| 6 | = <> < > <= >= |
Comparison | A > B |
| 7 | NOT |
Logical NOT | NOT (A=B) |
| 8 | AND |
Logical AND | A>5 AND B<10 |
| 9 (lowest) | OR |
Logical OR | A=1 OR B=2 |
Operators with equal precedence are evaluated left-to-right (except exponentiation, which is right-to-left).
Precedence Examples
Multiplication before addition:
PRINT 2 + 3 * 4
14
Calculation: 3 * 4 = 12, then 2 + 12 = 14, not (2 + 3) * 4 = 20.
Exponentiation before multiplication:
PRINT 2 * 3 ^ 2
18
Calculation: 3 ^ 2 = 9, then 2 * 9 = 18, not (2 * 3) ^ 2 = 36.
Division and multiplication left-to-right:
PRINT 20 / 4 * 2
10
Calculation: 20 / 4 = 5, then 5 * 2 = 10, not 20 / (4 * 2) = 2.5.
Unary minus before exponentiation:
PRINT -2 ^ 2
-4
Calculation: 2 ^ 2 = 4, then -(4) = -4, not (-2) ^ 2 = 4.
Parentheses override precedence:
PRINT (2 + 3) * 4
20
Calculation: (2 + 3) = 5, then 5 * 4 = 20.
When Precedence Matters
Precedence errors are common sources of bugs. Consider calculating a temperature conversion:
Incorrect (precedence error):
10 INPUT "CELSIUS"; C
20 F = C * 9 / 5 + 32
30 PRINT "FAHRENHEIT: "; F
This works correctly because multiplication and division happen before addition (left-to-right). But if written differently:
Also correct:
20 F = 9 / 5 * C + 32
This also works: 9 / 5 = 1.8, then 1.8 * C, then + 32.
Incorrect (if you forget precedence):
20 F = 9 * C / 5 + 32
This looks different but is actually correct due to left-to-right evaluation. The key is understanding what's happening:
- 9 * C is calculated first
- Result / 5 is calculated next
- Result + 32 is calculated last
When in doubt, use parentheses for clarity:
20 F = (C * 9 / 5) + 32
Or even more explicit:
20 F = ((C * 9) / 5) + 32
Extra parentheses don't hurt performance, and they make your intention crystal clear.
When precedence is unclear or complex, use parentheses even if they're technically unnecessary. Code is read more often than written. Make your intention obvious to future readers (including yourself).
Comparison Operators
Comparison operators compare two values and return a logical result. In BASIC, these operators return numeric values: -1 for true and 0 for false. This is different from many modern languages but consistent with Commodore BASIC V2.
The Six Comparison Operators
Equal (=): Returns true if both values are equal:
PRINT 5 = 5
-1
PRINT 5 = 6
0
Not Equal (<>): Returns true if values are different:
PRINT 5 <> 6
-1
PRINT 5 <> 5
0
Less Than (<): Returns true if left value is less than right value:
PRINT 3 < 5
-1
PRINT 5 < 3
0
Greater Than (>): Returns true if left value is greater than right value:
PRINT 5 > 3
-1
PRINT 3 > 5
0
Less Than or Equal (<=): Returns true if left value is less than or equal to right value:
PRINT 3 <= 5
-1
PRINT 5 <= 5
-1
PRINT 6 <= 5
0
Greater Than or Equal (>=): Returns true if left value is greater than or equal to right value:
PRINT 5 >= 3
-1
PRINT 5 >= 5
-1
PRINT 3 >= 5
0
Using Comparisons in IF Statements
Comparisons are most commonly used in conditional statements:
10 INPUT "ENTER AGE"; AGE
20 IF AGE >= 18 THEN PRINT "ADULT"
30 IF AGE < 18 THEN PRINT "MINOR"
The IF statement evaluates the comparison. If the result is non-zero (true), the THEN clause executes.
Comparing Strings
Comparison operators work with strings, using alphabetical (lexicographic) order:
PRINT "APPLE" < "BANANA"
-1
PRINT "ZEBRA" > "AARDVARK"
-1
PRINT "CAT" = "CAT"
-1
PRINT "cat" = "CAT"
-1
String comparisons are case-insensitive in BASIC. "CAT" and "cat" are considered equal.
String comparison compares character by character:
PRINT "ABC" < "ABD"
-1
The first two characters match, but "C" < "D", so "ABC" < "ABD".
True and False Values
Because true is -1 and false is 0, you can use comparison results in arithmetic:
A = 5
B = 10
RESULT = (A < B) * 100
PRINT RESULT
100
Since A < B is true (-1), the result is -1 * 100 = -100. Wait, that's not right! Let's reconsider:
Actually, the result is indeed -100 due to -1 representing true. To get 100, use:
RESULT = -(A < B) * 100
The negation converts -1 to 1, yielding 100.
More commonly, comparisons are used in logical contexts where the -1/0 distinction doesn't matter:
10 IF SCORE >= 90 THEN GRADE$ = "A"
20 IF SCORE >= 80 AND SCORE < 90 THEN GRADE$ = "B"
id="basic-comparison-examples"
title="Comparison Operator Examples"
language="basic"
preload="PRINT \"5 = 5: \"; 5 = 5
PRINT \"5 <> 6: \"; 5 <> 6
PRINT \"3 < 5: \"; 3 < 5
PRINT \"5 > 3: \"; 5 > 3
PRINT \"5 <= 5: \"; 5 <= 5
PRINT \"5 >= 5: \"; 5 >= 5
PRINT
PRINT \"String comparisons:\"
PRINT \"APPLE < BANANA: \"; \"APPLE\" < \"BANANA\"
PRINT \"cat = CAT: \"; \"cat\" = \"CAT\""
Most modern languages use 1 for true. BASIC uses -1. This is because -1 in binary is all bits set (11111111...), making bitwise operations more intuitive. The distinction rarely matters in practice, but be aware of it when using comparison results arithmetically.
Logical Operators
Logical operators combine or invert logical conditions. BASIC provides three logical operators: AND, OR, and NOT. These operators work on numeric values, treating 0 as false and any non-zero value (particularly -1) as true.
AND Operator
The AND operator returns true only if both operands are true:
PRINT -1 AND -1
-1
PRINT -1 AND 0
0
PRINT 0 AND -1
0
PRINT 0 AND 0
0
AND Truth Table
| Left | Right | Result |
|---|---|---|
| 0 (false) | 0 (false) | 0 (false) |
| 0 (false) | -1 (true) | 0 (false) |
| -1 (true) | 0 (false) | 0 (false) |
| -1 (true) | -1 (true) | -1 (true) |
Practical use: Combining conditions that must all be true:
10 INPUT "ENTER AGE"; AGE
20 INPUT "HAVE LICENSE (1=YES, 0=NO)"; LIC
30 IF AGE >= 16 AND LIC = 1 THEN PRINT "CAN DRIVE"
40 IF AGE < 16 OR LIC = 0 THEN PRINT "CANNOT DRIVE"
OR Operator
The OR operator returns true if either or both operands are true:
PRINT -1 OR -1
-1
PRINT -1 OR 0
-1
PRINT 0 OR -1
-1
PRINT 0 OR 0
0
OR Truth Table
| Left | Right | Result |
|---|---|---|
| 0 (false) | 0 (false) | 0 (false) |
| 0 (false) | -1 (true) | -1 (true) |
| -1 (true) | 0 (false) | -1 (true) |
| -1 (true) | -1 (true) | -1 (true) |
Practical use: Allowing multiple conditions where any can satisfy:
10 INPUT "ENTER DAY"; DAY$
20 IF DAY$ = "SATURDAY" OR DAY$ = "SUNDAY" THEN PRINT "WEEKEND"
30 IF DAY$ <> "SATURDAY" AND DAY$ <> "SUNDAY" THEN PRINT "WEEKDAY"
NOT Operator
The NOT operator inverts a logical value—true becomes false, false becomes true:
PRINT NOT -1
0
PRINT NOT 0
-1
NOT Truth Table
| Value | NOT Value |
|---|---|
| 0 (false) | -1 (true) |
| -1 (true) | 0 (false) |
Practical use: Inverting conditions:
10 INPUT "CONTINUE (1=YES, 0=NO)"; CONT
20 IF NOT CONT THEN END
30 PRINT "CONTINUING..."
Combining Logical Operators
Logical operators can be combined for complex conditions:
10 INPUT "AGE"; AGE
20 INPUT "INCOME"; INC
30 INPUT "CITIZEN (1/0)"; CIT
40 IF (AGE >= 18 AND AGE <= 65) AND (INC > 20000 OR CIT = 1) THEN PRINT "ELIGIBLE"
Remember precedence: NOT is evaluated before AND, which is evaluated before OR. Use parentheses generously:
' Without parentheses (may be ambiguous)
IF A = 1 OR B = 2 AND C = 3 THEN PRINT "YES"
' With parentheses (clear intention)
IF A = 1 OR (B = 2 AND C = 3) THEN PRINT "YES"
Bitwise Behavior
AND and OR are actually bitwise operators in BASIC. They operate on the binary representation of integers:
PRINT 5 AND 3
1
Why? In binary:
- 5 = 0101
- 3 = 0011
- AND = 0001 = 1
PRINT 5 OR 3
7
In binary:
- 5 = 0101
- 3 = 0011
- OR = 0111 = 7
For logical conditions using comparisons (which return -1 or 0), bitwise behavior doesn't matter. But if you're working with numeric flags or bit manipulation, understand that AND/OR operate on bits.
When AND/OR are applied to floating-point numbers, BASIC converts them to 16-bit signed integers first. This can produce unexpected results with large numbers or fractions. Stick to comparison results (-1, 0) or small integers for logical operations.
String Concatenation
While most operators work with numbers, the addition operator (+) also concatenates (joins) strings when both operands are strings:
FIRST$ = "HELLO"
LAST$ = "WORLD"
RESULT$ = FIRST$ + LAST$
PRINT RESULT$
HELLOWORLD
Notice there's no space between the words. To add a space:
RESULT$ = FIRST$ + " " + LAST$
PRINT RESULT$
HELLO WORLD
Building Strings Incrementally
String concatenation is useful for building output:
10 INPUT "FIRST NAME"; F$
20 INPUT "LAST NAME"; L$
30 FULL$ = F$ + " " + L$
40 GREETING$ = "HELLO, " + FULL$ + "!"
50 PRINT GREETING$
If you enter "JOHN" and "DOE":
HELLO, JOHN DOE!
Concatenating Multiple Strings
You can chain multiple concatenations:
A$ = "THE "
B$ = "QUICK "
C$ = "BROWN "
D$ = "FOX"
RESULT$ = A$ + B$ + C$ + D$
PRINT RESULT$
THE QUICK BROWN FOX
Concatenation Limits
Strings in BASIC are limited to 255 characters. If concatenation exceeds this limit, the result is truncated:
A$ = STRING$(200, "A") ' 200 A's
B$ = STRING$(100, "B") ' 100 B's
C$ = A$ + B$ ' Would be 300 chars
PRINT LEN(C$)
255
Wait—STRING$ isn't a standard BASIC V2 function. Let me correct that example:
' Building a long string
A$ = ""
FOR I = 1 TO 200
A$ = A$ + "A"
NEXT I
PRINT LEN(A$)
200
' Adding more would be truncated at 255 total
You cannot concatenate strings and numbers directly. The expression "SCORE: " + 95 produces a ?TYPE MISMATCH ERROR. Use STR$ to convert numbers to strings first: RESULT$ = "SCORE: " + STR$(95)
Practical String Concatenation
10 SCORE% = 95
20 MSG$ = "YOUR SCORE: " + STR$(SCORE%) + " POINTS"
30 PRINT MSG$
YOUR SCORE: 95 POINTS
Notice STR$ adds a leading space for positive numbers. To remove it:
20 MSG$ = "YOUR SCORE: " + MID$(STR$(SCORE%), 2) + " POINTS"
Using MID$ to skip the first character (the space).
Using Parentheses
Parentheses override operator precedence, allowing you to control the order of evaluation. When an expression contains parentheses, BASIC evaluates the innermost parentheses first, working outward.
Basic Grouping
Force addition before multiplication:
PRINT 2 + 3 * 4
14
PRINT (2 + 3) * 4
20
Without parentheses: 3 * 4 = 12, then 2 + 12 = 14 With parentheses: 2 + 3 = 5, then 5 * 4 = 20
Nested Parentheses
Parentheses can be nested to any depth:
PRINT ((2 + 3) * (4 + 5)) / 3
15
Evaluation order:
- (2 + 3) = 5
- (4 + 5) = 9
- 5 * 9 = 45
- 45 / 3 = 15
Clarifying Complex Expressions
Even when parentheses aren't strictly necessary, they improve readability:
Unclear:
10 RESULT = A * B + C / D - E ^ F
Clear:
10 RESULT = (A * B) + (C / D) - (E ^ F)
Both calculate the same value, but the second makes the order obvious.
Logical Grouping
Parentheses are essential for complex logical conditions:
10 INPUT "AGE"; AGE
20 INPUT "STUDENT (1/0)"; STU
30 INPUT "SENIOR (1/0)"; SEN
40 IF (AGE < 18 OR STU = 1) AND NOT SEN THEN PRINT "DISCOUNT"
Without parentheses around "AGE < 18 OR STU = 1", precedence would evaluate differently:
' Wrong: IF AGE < 18 OR (STU = 1 AND NOT SEN)
Mathematical Formulas
Complex formulas often require careful parenthesization:
Quadratic formula: x = (-b ± √(b² - 4ac)) / 2a
10 INPUT "A, B, C"; A, B, C
20 DISC = B ^ 2 - 4 * A * C
30 IF DISC < 0 THEN PRINT "NO REAL ROOTS": END
40 X1 = (-B + SQR(DISC)) / (2 * A)
50 X2 = (-B - SQR(DISC)) / (2 * A)
60 PRINT "X1 = "; X1
70 PRINT "X2 = "; X2
Note the parentheses around (2 * A) to ensure the entire numerator is divided by 2A, not just divided by 2 then multiplied by A.
Comparison Grouping
When using comparisons with logical operators, parentheses clarify intention:
' Check if value is in range 10-20 or 30-40
IF (X >= 10 AND X <= 20) OR (X >= 30 AND X <= 40) THEN PRINT "IN RANGE"
Without the outer parentheses, this still works due to AND having higher precedence than OR. But the parentheses make it obvious.
Parentheses never hurt (except readability if overused). If you're uncertain about precedence, add parentheses. The small visual clutter is worth the guaranteed correctness and clarity.
Practical Examples
Let's apply operators to real-world programming scenarios, demonstrating how arithmetic, comparison, logical, and string operators work together.
Example 1: Loan Payment Calculator
Calculate monthly loan payment using the formula: Payment = P × (r(1+r)^n) / ((1+r)^n - 1)
10 PRINT "LOAN PAYMENT CALCULATOR"
20 PRINT
30 INPUT "LOAN AMOUNT"; P
40 INPUT "ANNUAL INTEREST RATE (%)"; R
50 INPUT "LOAN TERM (YEARS)"; Y
60 R = R / 100 / 12 ' Convert to monthly decimal rate
70 N = Y * 12 ' Convert years to months
80 IF R = 0 THEN PMT = P / N: GOTO 110
90 T = (1 + R) ^ N
100 PMT = P * (R * T) / (T - 1)
110 PRINT
120 PRINT "MONTHLY PAYMENT: $"; INT(PMT * 100 + 0.5) / 100
What's happening:
- Line 60: Multiple divisions for rate conversion
- Line 70: Multiplication for term conversion
- Line 80: Comparison and division for zero-interest case
- Line 90: Exponentiation for compound interest factor
- Line 100: Complex arithmetic expression with proper parentheses
- Line 120: Multiplication, addition, division for rounding
Example 2: Grade Calculator
Determine letter grade based on numeric score with complex conditions:
10 INPUT "ENTER SCORE (0-100)"; S
20 IF S < 0 OR S > 100 THEN PRINT "INVALID": GOTO 10
30 IF S >= 90 THEN G$ = "A": GOTO 100
40 IF S >= 80 THEN G$ = "B": GOTO 100
50 IF S >= 70 THEN G$ = "C": GOTO 100
60 IF S >= 60 THEN G$ = "D": GOTO 100
70 G$ = "F"
100 PRINT "GRADE: "; G$
110 IF G$ = "A" OR G$ = "B" THEN PRINT "EXCELLENT WORK!"
120 IF G$ = "C" THEN PRINT "SATISFACTORY"
130 IF G$ = "D" OR G$ = "F" THEN PRINT "NEEDS IMPROVEMENT"
What's happening:
- Line 20: OR operator with comparisons for validation
- Lines 30-70: Sequential comparisons for grade determination
- Lines 110-130: OR operators for grouped feedback
Example 3: Tax Calculator
Calculate tax with progressive brackets:
10 INPUT "TAXABLE INCOME"; INC
20 TAX = 0
30 IF INC <= 10000 THEN TAX = INC * 0.1: GOTO 100
40 TAX = 10000 * 0.1
50 IF INC <= 40000 THEN TAX = TAX + (INC - 10000) * 0.2: GOTO 100
60 TAX = TAX + 30000 * 0.2
70 TAX = TAX + (INC - 40000) * 0.3
100 PRINT "TAX: $"; INT(TAX * 100 + 0.5) / 100
110 PRINT "EFFECTIVE RATE: "; INT(TAX / INC * 10000 + 0.5) / 100; "%"
What's happening:
- Comparisons determine which bracket applies
- Subtraction calculates amount in each bracket
- Multiplication applies bracket rate
- Accumulation through addition
- Division for percentage calculation
Example 4: Distance Calculator
Calculate distance between two points: d = √((x₂-x₁)² + (y₂-y₁)²)
10 PRINT "DISTANCE CALCULATOR"
20 INPUT "X1, Y1"; X1, Y1
30 INPUT "X2, Y2"; X2, Y2
40 DX = X2 - X1
50 DY = Y2 - Y1
60 DIST = SQR(DX ^ 2 + DY ^ 2)
70 PRINT "DISTANCE: "; DIST
What's happening:
- Line 40-50: Subtraction for delta values
- Line 60: Exponentiation for squares, addition, then SQR
- Parentheses not needed due to precedence (^ before +, SQR operates on entire result)
But for clarity, could write:
60 DIST = SQR((DX ^ 2) + (DY ^ 2))
Example 5: Leap Year Detector
A year is a leap year if divisible by 4, except centuries (divisible by 100) unless also divisible by 400:
10 INPUT "ENTER YEAR"; Y
20 IF Y MOD 400 = 0 THEN PRINT "LEAP YEAR": GOTO 100
30 IF Y MOD 100 = 0 THEN PRINT "NOT LEAP YEAR": GOTO 100
40 IF Y MOD 4 = 0 THEN PRINT "LEAP YEAR": GOTO 100
50 PRINT "NOT LEAP YEAR"
100 END
Wait—MOD isn't available in Commodore BASIC V2. Let me rewrite using subtraction:
10 INPUT "ENTER YEAR"; Y
20 ' Check if divisible by 400
30 IF Y / 400 = INT(Y / 400) THEN PRINT "LEAP YEAR": GOTO 200
40 ' Check if divisible by 100
50 IF Y / 100 = INT(Y / 100) THEN PRINT "NOT LEAP YEAR": GOTO 200
60 ' Check if divisible by 4
70 IF Y / 4 = INT(Y / 4) THEN PRINT "LEAP YEAR": GOTO 200
80 PRINT "NOT LEAP YEAR"
200 END
What's happening:
- Division and INT comparison checks divisibility
- Comparison operators test equality
- Sequential IF statements implement logical priority
Example 6: String Formatter
Build formatted output with string concatenation:
10 INPUT "FIRST NAME"; F$
20 INPUT "LAST NAME"; L$
30 INPUT "AGE"; A
40 INPUT "CITY"; C$
50 FULL$ = F$ + " " + L$
60 INFO$ = FULL$ + ", AGE " + STR$(A) + ", FROM " + C$
70 PRINT
80 PRINT "PROFILE:"
90 PRINT INFO$
100 PRINT
110 BORDER$ = ""
120 FOR I = 1 TO LEN(INFO$)
130 BORDER$ = BORDER$ + "="
140 NEXT I
150 PRINT BORDER$
What's happening:
- String concatenation builds full name and info string
- STR$ converts numeric age to string for concatenation
- Loop with concatenation builds border of equal signs
id="basic-practical-operators"
title="Practical Operator Examples"
language="basic"
preload="10 REM DISTANCE CALCULATOR
20 X1=0: Y1=0: X2=3: Y2=4
30 DX = X2 - X1
40 DY = Y2 - Y1
50 DIST = SQR(DX^2 + DY^2)
60 PRINT \"DISTANCE: \"; DIST
70 PRINT
80 REM GRADE CALCULATOR
90 S = 85
100 IF S >= 90 THEN G$ = \"A\"
110 IF S >= 80 AND S < 90 THEN G$ = \"B\"
120 IF S >= 70 AND S < 80 THEN G$ = \"C\"
130 PRINT \"SCORE \"; S; \" = GRADE \"; G$
RUN"
Common Mistakes and How to Avoid Them
Operators seem simple, but certain patterns consistently cause problems. Here are the most common mistakes and how to avoid them.
Mistake 1: Forgetting Operator Precedence
Problem:
10 PRINT "TOTAL: $"; PRICE + TAX * 1.08
If PRICE = 100 and TAX = 10, this prints 110.8, not 118.8, because TAX * 1.08 is calculated first (10.8), then added to PRICE (100 + 10.8 = 110.8).
Solution: Use parentheses to make intent clear:
10 PRINT "TOTAL: $"; (PRICE + TAX) * 1.08
Mistake 2: Confusing = in Comparisons
Problem:
10 IF A = B = C THEN PRINT "ALL EQUAL"
This doesn't check if A, B, and C are all equal. It evaluates as:
- A = B produces -1 or 0
- That result is compared to C
Solution: Use AND to combine comparisons:
10 IF A = B AND B = C THEN PRINT "ALL EQUAL"
Mistake 3: Division by Zero
Problem:
10 INPUT "DIVISOR"; D
20 PRINT 100 / D
If user enters 0, you get ?DIVISION BY ZERO ERROR and program halts.
Solution: Always validate divisors:
10 INPUT "DIVISOR"; D
20 IF D = 0 THEN PRINT "CANNOT DIVIDE BY ZERO": GOTO 10
30 PRINT 100 / D
Mistake 4: Mixing Strings and Numbers
Problem:
10 NAME$ = "SCORE: " + 95
This produces ?TYPE MISMATCH ERROR because + can't concatenate string and number directly.
Solution: Convert number to string:
10 NAME$ = "SCORE: " + STR$(95)
Mistake 5: Incorrect Exponentiation Order
Problem:
10 PRINT 2 ^ 3 ^ 2
Expecting (2^3)^2 = 8^2 = 64, but getting 512 because exponentiation is right-associative: 2^(3^2) = 2^9 = 512.
Solution: Use parentheses for left-to-right evaluation:
10 PRINT (2 ^ 3) ^ 2
Mistake 6: Unary Minus with Exponentiation
Problem:
10 PRINT -2 ^ 2
Expecting 4 (negative two squared), but getting -4 because it calculates -(2^2).
Solution: Parenthesize the negative number:
10 PRINT (-2) ^ 2
Mistake 7: Assuming Boolean Short-Circuit
Problem:
10 IF D <> 0 AND 100 / D > 5 THEN PRINT "VALID"
In some languages, if D = 0, the second condition isn't evaluated (short-circuit). But BASIC evaluates both sides, causing ?DIVISION BY ZERO ERROR.
Solution: Use nested IF statements:
10 IF D <> 0 THEN IF 100 / D > 5 THEN PRINT "VALID"
Or separate lines:
10 IF D = 0 THEN GOTO 100
20 IF 100 / D > 5 THEN PRINT "VALID"
100 REM Continue
Mistake 8: Confusing -1 and 1 for True
Problem:
10 A = 5 > 3 ' A = -1 (true)
20 PRINT A * 10 ' Expecting 10, get -10
Solution: If using comparison results arithmetically, negate or adjust:
10 A = -(5 > 3) ' A = 1
20 PRINT A * 10 ' Prints 10
Or better, avoid arithmetic on boolean results:
10 IF 5 > 3 THEN A = 1 ELSE A = 0
Wait, ELSE isn't in Commodore BASIC V2:
10 A = 0
20 IF 5 > 3 THEN A = 1
30 PRINT A * 10
BASIC always evaluates both sides of AND and OR operators. If one side has a division or function call that might fail, protect it with a separate IF statement first. Do not rely on the first condition preventing evaluation of the second.
Summary
Operators are the computational heart of BASIC, transforming static values into dynamic calculations and logical decisions. This chapter covered all operator categories:
Arithmetic Operators (+, -, *, /, ^) perform mathematical calculations following standard mathematical conventions, with exponentiation as the highest-precedence arithmetic operator and right-associative behavior.
Operator Precedence determines evaluation order: parentheses first, then exponentiation, then multiplication/division, then addition/subtraction, then comparison, then logical operators (NOT, AND, OR). When in doubt, use parentheses to clarify.
Comparison Operators (=, <>, <, >, <=, >=) compare values and return -1 for true, 0 for false—a Commodore BASIC convention that differs from modern languages but enables consistent logical operations.
Logical Operators (AND, OR, NOT) combine and invert logical conditions. They're bitwise operators working on integer representations, but for comparisons returning -1/0, they behave as expected logical operators.
String Concatenation (+) joins strings together, building formatted output and dynamic text. Remember to convert numbers to strings with STR$ before concatenation.
Parentheses override precedence and clarify intention. Use them liberally—clarity is more valuable than brevity.
Understanding operators is essential for writing correct BASIC programs. The precedence rules, while straightforward, require attention in complex expressions. When combined with variables (Chapter 5) and flow control (Chapter 7), operators enable sophisticated programs that process data, make decisions, and solve real problems.
Practice with operators in immediate mode before using them in programs. Test expressions, verify precedence, and confirm your understanding. The InteractiveREPL examples throughout this chapter provide hands-on practice—use them to experiment and learn.
End of Chapter 6
Proceed to Chapter 7: Program Flow Control to learn how to make decisions and create loops using the operators you've mastered.
Program Flow Control
The heart of BASIC programming isn't data or variables—it's control. The ability to make decisions, repeat actions, and jump to different parts of your program transforms a simple list of statements into an intelligent system that responds, adapts, and solves problems.
In this chapter, you'll master the commands that control program execution flow. You'll start with the simplest form—unconditional jumps—and progress to sophisticated structures like nested loops and computed branching. By the end, you'll understand how flow control turns linear code into programs that think.
Why Flow Control Matters
Without flow control, programs execute one line at a time, from lowest to highest line number, always in the same order. That's useful for simple calculations, but real programs need to:
- Make decisions — Different actions based on conditions (IF statements)
- Repeat actions — Perform the same operation multiple times (loops)
- Organise code — Break complex tasks into reusable subroutines (GOSUB)
- Handle choices — Select from multiple options (ON...GOTO menus)
Every non-trivial program uses flow control. Games loop until the player wins or loses. Data entry programs validate input with IF statements. Scientific calculations repeat formulas across datasets with FOR loops. Mastering these commands is mastering programming itself.
Every example in this chapter uses interactive demonstrations. Type them yourself, experiment with variations, and watch how small changes affect program behavior. Flow control is best learned by doing.
The Simplest Jump: GOTO
The most basic flow control command is GOTO. It does exactly what its name suggests: go to a specific line number.
10 PRINT "START"
20 GOTO 50
30 PRINT "YOU'LL NEVER SEE THIS"
40 PRINT "OR THIS"
50 PRINT "END"
RUN
When line 20 executes, BASIC immediately jumps to line 50, skipping lines 30 and 40 entirely. The program prints:
START
END
GOTO is unconditional—it always jumps, no questions asked. This makes it powerful but also dangerous. Used carelessly, GOTO creates "spaghetti code" where execution jumps all over the place, making programs nearly impossible to understand or debug.
Infinite Loops with GOTO
10 PRINT "HELLO"
20 GOTO 10
RUN
This program prints "HELLO" forever. Line 20 jumps back to line 10, which prints "HELLO" again, then jumps back again, endlessly. Press ESC to stop it.
Infinite loops aren't always mistakes—game main loops, animation systems, and server programs all use controlled infinite loops. But accidentally creating one is a common beginner error.
If your program seems stuck, press ESC to interrupt execution. SLP-BASIC's interpreter yields control between statements, so ESC always works—even in tight infinite loops.
Forward and Backward Jumps
GOTO can jump forward (to a higher line number) or backward (to a lower one):
10 X = 0
20 X = X + 1
30 PRINT X
40 IF X < 5 THEN GOTO 20
50 PRINT "DONE"
RUN
This prints numbers 1 through 5. Line 40 creates a loop by jumping backward to line 20—but only while X < 5. When X reaches 5, the IF condition becomes false, the GOTO doesn't execute, and the program continues to line 50.
This pattern—a counter, a print statement, and a conditional backward GOTO—is how BASIC programmers created loops before FOR...NEXT existed. It works, but FOR...NEXT (covered later) is cleaner and less error-prone.
Making Decisions: IF...THEN
GOTO always jumps. IF...THEN jumps conditionally—only when a condition is true.
The basic syntax is:
IF condition THEN line_number
10 INPUT "ENTER YOUR AGE"; A
20 IF A >= 18 THEN GOTO 50
30 PRINT "YOU ARE A MINOR"
40 GOTO 60
50 PRINT "YOU ARE AN ADULT"
60 PRINT "THANK YOU"
RUN
If the user enters 25, the program jumps to line 50 and prints "YOU ARE AN ADULT". If they enter 12, line 20's condition is false, so execution continues to line 30, printing "YOU ARE A MINOR".
Notice line 40: after printing the minor message, we GOTO 60 to skip the adult message. Without this jump, both messages would print—clearly wrong. Managing these jumps is tedious, which is why ELSE (covered next) is so valuable.
IF...THEN with Statements
Instead of jumping to a line number, IF...THEN can execute a single statement directly:
10 INPUT "TEMPERATURE (F)"; T
20 IF T > 100 THEN PRINT "TOO HOT!"
30 IF T < 32 THEN PRINT "FREEZING!"
40 PRINT "TEMPERATURE: "; T
RUN
This is cleaner for simple one-line responses. Each IF checks a condition and prints a warning if true. Line 40 always executes—it's not part of either IF statement.
You can use any statement after THEN: PRINT, assignment, GOSUB, even END to immediately terminate the program:
10 INPUT "ENTER PASSWORD"; P$
20 IF P$ <> "SECRET" THEN END
30 PRINT "ACCESS GRANTED"
RUN
If the password is wrong, line 20 ends the program immediately—no error message, no further execution. This pattern is common in vintage BASIC programs for simple security checks.
Use IF...THEN statement_form for simple, one-line responses. Use IF...THEN line_number when you need to execute multiple statements or have complex branching logic.
Binary Choice: IF...THEN...ELSE
Original Commodore BASIC V2 lacked ELSE—you had to manage skips manually with GOTO. SLP-BASIC includes ELSE for cleaner, more readable code:
IF condition THEN true_action ELSE false_action
10 INPUT "GUESS A NUMBER (1-10)"; G
20 IF G = 7 THEN PRINT "CORRECT!" ELSE PRINT "WRONG!"
RUN
When G equals 7, BASIC executes the PRINT after THEN. When G is anything else, it executes the PRINT after ELSE. No manual GOTO needed—BASIC handles the branching automatically.
ELSE with Line Numbers
ELSE works with GOTO too:
10 INPUT "CONTINUE (Y/N)"; A$
20 IF A$ = "Y" THEN GOTO 50
30 PRINT "GOODBYE"
40 END
50 PRINT "CONTINUING..."
RUN
Can be written more cleanly as:
10 INPUT "CONTINUE (Y/N)"; A$
20 IF A$ = "Y" THEN PRINT "CONTINUING..." ELSE PRINT "GOODBYE"
RUN
The second version is shorter and clearer. ELSE eliminates the need for manual jump management, reducing bugs and improving readability.
Commodore BASIC V2 didn't have ELSE—it was added in BASIC 3.5 and 7.0. SLP-BASIC includes it because modern programmers expect it, and it makes programs more readable. Purists can avoid ELSE to maintain VIC-20/C64 compatibility.
Compound Conditions
Use AND, OR, and NOT to build complex conditions:
10 INPUT "TEMPERATURE (F)"; T
20 IF T >= 60 AND T <= 75 THEN PRINT "COMFORTABLE" ELSE PRINT "UNCOMFORTABLE"
RUN
10 INPUT "DAY (1-7)"; D
20 IF D = 1 OR D = 7 THEN PRINT "WEEKEND" ELSE PRINT "WEEKDAY"
RUN
10 INPUT "READY (Y/N)"; R$
20 IF NOT (R$ = "Y") THEN PRINT "NOT READY" ELSE PRINT "READY"
RUN
Parentheses control evaluation order. NOT (R$ = "Y") is clearer than R$ <> "Y" for some programmers, though both work identically.
Repeating Actions: FOR...NEXT
The most powerful and commonly used flow control structure in BASIC is the FOR...NEXT loop. It repeats a block of code a specific number of times, automatically managing a counter variable.
Basic FOR...NEXT Syntax
FOR variable = start TO end
statements
NEXT variable
10 FOR I = 1 TO 5
20 PRINT "LOOP "; I
30 NEXT I
40 PRINT "DONE"
RUN
This prints:
LOOP 1
LOOP 2
LOOP 3
LOOP 4
LOOP 5
DONE
Here's what happens:
- Line 10 sets I = 1 (start value)
- Lines 20 executes (prints "LOOP 1")
- Line 30 (NEXT) increments I to 2
- BASIC checks: is I ≤ 5? Yes → jump back to line 20
- Repeat steps 2-4 until I > 5
- When I exceeds 5, exit loop and continue to line 40
The loop variable (I) is just a regular variable—you can use it in calculations, print it, even modify it (though that's usually a bad idea).
Counting Down with STEP
By default, FOR increments the counter by 1. The STEP keyword lets you specify a different increment—including negative values for countdown loops:
10 FOR I = 10 TO 1 STEP -1
20 PRINT I
30 NEXT I
40 PRINT "BLASTOFF!"
RUN
This counts down from 10 to 1, then prints "BLASTOFF!". STEP -1 decrements I by 1 each iteration.
You can use any STEP value:
10 FOR I = 0 TO 100 STEP 25
20 PRINT I
30 NEXT I
RUN
This prints 0, 25, 50, 75, 100—every 25th number from 0 to 100.
10 FOR X = 0 TO 3.14 STEP 0.5
20 PRINT X
30 NEXT X
RUN
STEP works with floating-point values too. This prints values from 0 to π in 0.5 increments.
Practical FOR...NEXT Examples
Multiplication Table:
10 INPUT "WHICH TABLE"; N
20 FOR I = 1 TO 10
30 PRINT N; " X "; I; " = "; N * I
40 NEXT I
RUN
Sum of Numbers:
10 S = 0
20 FOR I = 1 TO 100
30 S = S + I
40 NEXT I
50 PRINT "SUM 1-100: "; S
RUN
This calculates 1+2+3+...+100 = 5050 (Gauss would be proud).
Drawing Patterns:
10 FOR I = 1 TO 10
20 FOR J = 1 TO I
30 PRINT "*";
40 NEXT J
50 PRINT
60 NEXT I
RUN
This draws a triangle of asterisks, demonstrating nested loops (covered next).
Use simple names for loop counters: I, J, K for generic loops. Use descriptive names like ROW, COL, or INDEX when the meaning matters. After NEXT, the variable name is optional but recommended for readability, especially in nested loops.
Nested Loops
You can place one FOR...NEXT loop inside another. The inner loop completes all its iterations for each iteration of the outer loop.
10 FOR I = 1 TO 3
20 FOR J = 1 TO 4
30 PRINT I; ","; J; " ";
40 NEXT J
50 PRINT
60 NEXT I
RUN
This prints:
1,1 1,2 1,3 1,4
2,1 2,2 2,3 2,4
3,1 3,2 3,3 3,4
The outer loop (I) runs 3 times. For each I value, the inner loop (J) runs 4 times completely. Total iterations: 3 × 4 = 12.
Multiplication Table Grid
10 FOR I = 1 TO 10
20 FOR J = 1 TO 10
30 PRINT I * J;
40 IF I * J < 10 THEN PRINT " ";
50 PRINT " ";
60 NEXT J
70 PRINT
80 NEXT I
RUN
This creates a complete 10×10 multiplication table. Lines 40-50 handle spacing so single-digit products align properly with double-digit ones.
Important Nesting Rules
Inner loop must complete inside outer loop — You can't start a FOR in one loop and NEXT it in another.
NEXT in reverse order — The innermost loop NEXTs first:
10 FOR I = 1 TO 5
20 FOR J = 1 TO 3
30 PRINT I; J
40 NEXT J ← Inner NEXT first
50 NEXT I ← Outer NEXT second
- Don't cross loop boundaries — This is wrong:
10 FOR I = 1 TO 5
20 FOR J = 1 TO 3
30 NEXT I ← ERROR: Crossing boundaries!
40 NEXT J
BASIC will generate a "NEXT WITHOUT FOR" error.
Forgetting which loop is outer and which is inner leads to NEXT mismatches. Use indentation (if your editor supports it) or comments to track nesting levels.
Nested Loop Performance
Nested loops multiply iteration counts. Three levels deep can execute thousands of times:
10 C = 0
20 FOR I = 1 TO 10
30 FOR J = 1 TO 10
40 FOR K = 1 TO 10
50 C = C + 1
60 NEXT K
70 NEXT J
80 NEXT I
90 PRINT "ITERATIONS: "; C
RUN
This runs 10 × 10 × 10 = 1,000 iterations. At 4 loops deep, you'd hit 10,000 iterations—enough to slow down even modern computers if the loop body is complex.
Breaking Out Early
Sometimes you want to exit a FOR loop before it completes naturally. Commodore BASIC doesn't have a BREAK or EXIT command, but you can use GOTO:
10 FOR I = 1 TO 100
20 PRINT "CHECKING "; I
30 IF I * I = 144 THEN GOTO 60
40 NEXT I
50 PRINT "NOT FOUND"
60 PRINT "FOUND: "; I
RUN
This searches for a number whose square is 144. When found (I=12), line 30 jumps to 60, exiting the loop early. Without the match, the loop completes and line 50 prints "NOT FOUND".
When you GOTO out of a FOR loop, BASIC leaves the loop's internal state on the stack. This wastes a small amount of memory. For occasional early exits it's fine, but exiting thousands of loops can cause problems. Using a FLAG variable and checking it is cleaner but slower.
Subroutines: GOSUB and RETURN
Before structured programming and functions, BASIC had subroutines—blocks of code you could call from multiple places. GOSUB (GO to SUBroutine) jumps to a line number, executes code there, then RETURN jumps back to the line after the GOSUB.
10 PRINT "START"
20 GOSUB 100
30 PRINT "MIDDLE"
40 GOSUB 100
50 PRINT "END"
60 END
100 PRINT "*** SUBROUTINE ***"
110 RETURN
RUN
This prints:
START
*** SUBROUTINE ***
MIDDLE
*** SUBROUTINE ***
END
Line 20 calls the subroutine at 100, which prints its message then RETURNs to line 30. Line 40 calls the same subroutine again, demonstrating code reuse—the subroutine is written once but executed twice.
How GOSUB Works Internally
GOSUB is smarter than GOTO. It remembers where it came from:
- GOSUB saves the current line number on a return stack
- Jumps to the target line
- RETURN pops the saved line from the stack and jumps back
This means subroutines can call other subroutines (nesting):
10 GOSUB 100
20 END
100 PRINT "SUB A START"
110 GOSUB 200
120 PRINT "SUB A END"
130 RETURN
200 PRINT "SUB B"
210 RETURN
RUN
Execution flow:
- Line 10 → GOSUB 100 (save return address: line 20)
- Line 100-110 → GOSUB 200 (save return address: line 120)
- Line 200-210 → RETURN (go back to line 120)
- Line 120-130 → RETURN (go back to line 20)
- Line 20 → END
The stack allows arbitrary nesting depths—limited only by memory.
Passing Information to Subroutines
BASIC has no formal parameter passing, so subroutines use global variables:
10 N = 5: GOSUB 100: PRINT "RESULT: "; R
20 N = 8: GOSUB 100: PRINT "RESULT: "; R
30 END
100 REM SQUARE SUBROUTINE
110 R = N * N
120 RETURN
RUN
This subroutine squares N and stores the result in R. The caller sets N before GOSUB, then reads R after RETURN.
Use consistent naming conventions to track which variables are inputs, outputs, or internal to subroutines. Many vintage BASIC programmers used comments like:
100 REM SQUARE SUBROUTINE
110 REM INPUT: N OUTPUT: R
Common Subroutine Patterns
Initialization:
10 GOSUB 1000: REM INITIALIZE
20 REM ... MAIN PROGRAM ...
1000 REM INITIALIZATION
1010 DIM A(100), B$(50)
1020 PI = 3.14159
1030 RETURN
Input Validation:
10 INPUT "AGE"; A
20 GOSUB 2000: REM VALIDATE
30 IF V = 0 THEN PRINT "INVALID": GOTO 10
2000 REM VALIDATE AGE
2010 V = 1
2020 IF A < 0 OR A > 120 THEN V = 0
2030 RETURN
Drawing/Display:
100 GOSUB 3000: REM DRAW BORDER
3000 REM DRAW BORDER
3010 FOR I = 1 TO 40: PRINT "*";: NEXT I
3020 PRINT
3030 RETURN
Place subroutines at the end of your program (starting at line 1000 or higher). This keeps the main logic at the top, making programs easier to read. Always end your main program with END before subroutines start.
RETURN Without GOSUB
RETURN without a matching GOSUB generates an error:
10 PRINT "HELLO"
20 RETURN
RUN
This produces "RETURN WITHOUT GOSUB ERROR"—there's no saved return address on the stack.
This error also occurs if you GOTO into a subroutine:
10 GOTO 100
100 PRINT "SUB"
110 RETURN ← ERROR! No GOSUB called us
The correct pattern is GOSUB to enter, RETURN to exit. GOTO bypasses the return address setup.
Computed Branching: ON...GOTO
When you need to jump to different line numbers based on a numeric value, ON...GOTO provides cleaner code than multiple IF statements.
Basic ON...GOTO Syntax
ON variable GOTO line1, line2, line3, ...
10 PRINT "MENU:"
20 PRINT "1. HELLO"
30 PRINT "2. GOODBYE"
40 PRINT "3. STATUS"
50 INPUT "CHOICE"; C
60 ON C GOTO 100, 200, 300
70 PRINT "INVALID CHOICE"
80 END
100 PRINT "HELLO!": GOTO 80
200 PRINT "GOODBYE!": GOTO 80
300 PRINT "STATUS: OK": GOTO 80
RUN
If C=1, jump to line 100. If C=2, jump to 200. If C=3, jump to 300. If C is 0, negative, or greater than 3, execution continues to line 70 (no jump).
This is equivalent to:
60 IF C = 1 THEN GOTO 100
70 IF C = 2 THEN GOTO 200
80 IF C = 3 THEN GOTO 300
90 PRINT "INVALID CHOICE"
ON...GOTO is much shorter and clearer for multiple choices.
ON...GOSUB for Subroutine Dispatch
ON...GOSUB works identically but calls subroutines instead of jumping:
10 PRINT "CALCULATOR:"
20 PRINT "1. ADD"
30 PRINT "2. SUBTRACT"
40 PRINT "3. MULTIPLY"
50 INPUT "OPERATION"; OP
60 INPUT "FIRST NUMBER"; A
70 INPUT "SECOND NUMBER"; B
80 ON OP GOSUB 100, 200, 300
90 PRINT "RESULT: "; R
95 END
100 R = A + B: RETURN
200 R = A - B: RETURN
300 R = A * B: RETURN
RUN
Each operation is a subroutine. After RETURN, execution continues at line 90 to print the result. This pattern is perfect for menu-driven programs.
Boundary Behavior
If the ON variable is fractional, BASIC truncates to an integer:
10 X = 2.7
20 ON X GOTO 100, 200, 300
100 PRINT "JUMPED TO 100": END
200 PRINT "JUMPED TO 200": END
300 PRINT "JUMPED TO 300": END
RUN
X=2.7 truncates to 2, so this jumps to line 200.
If the value is out of range (≤0 or greater than the number of targets), no jump occurs:
10 X = 5
20 ON X GOTO 100, 200
30 PRINT "NO JUMP - CONTINUED HERE"
100 PRINT "FIRST": END
200 PRINT "SECOND": END
RUN
X=5 but there are only 2 targets, so execution continues to line 30.
ON...GOTO indexes start at 1, not 0. If your variable can be 0, you'll need an IF check before ON...GOTO, or add a dummy first target.
Program Termination: END, STOP, CONT
BASIC provides several ways to halt execution, each with different behavior.
END - Clean Termination
END stops program execution and closes files:
10 PRINT "RUNNING..."
20 END
30 PRINT "NEVER EXECUTED"
RUN
After END, you cannot CONT (continue). The program has cleanly terminated. You must RUN again to restart.
Best practice: place END at the end of your main program, before subroutines:
10 REM MAIN PROGRAM
20 GOSUB 1000
30 GOSUB 2000
40 END
1000 REM SUBROUTINE 1
1010 RETURN
2000 REM SUBROUTINE 2
2010 RETURN
Without END, execution would "fall through" into subroutine 1000, then hit RETURN without GOSUB—error!
STOP - Suspended Execution
STOP also halts execution, but leaves the program in a suspended state:
10 FOR I = 1 TO 10
20 PRINT I
30 IF I = 5 THEN STOP
40 NEXT I
RUN
This prints 1-5 then stops. The program shows "BREAK IN LINE 30" (or similar).
After STOP, you can:
- Type CONT to resume execution from the next line
- Type LIST to review your code
- Type PRINT to check variable values
- Type RUN to restart from the beginning
CONT
This continues from line 40, printing 6-10.
STOP is invaluable for debugging. Place STOP at suspicious locations, run the program, then examine variables to understand what's happening.
CONT - Continue After STOP
CONT (continue) resumes execution after a STOP. It picks up at the line after the STOP:
10 PRINT "BEFORE"
20 STOP
30 PRINT "AFTER"
RUN
BEFORE
BREAK IN 20
CONT
AFTER
CONT only works after STOP. After END or an error, CONT fails with "CAN'T CONTINUE ERROR".
Place multiple STOPs in your program to examine execution at different points. Run, check variables, CONT, run more, check again. This step-through debugging is slower than modern debuggers but remarkably effective for finding logic errors.
When Programs Stop Automatically
Besides END and STOP, programs halt on:
- Syntax Errors - Invalid code generates an error and stops
- Runtime Errors - Division by zero, array bounds, type mismatch, etc.
- User Interrupt - Pressing ESC (in SLP-BASIC) or STOP key (on hardware)
After runtime errors, you usually cannot CONT—the error condition must be fixed first.
Putting It All Together
Let's build a complete program using every flow control structure from this chapter:
10 REM NUMBER GUESSING GAME
20 REM USES: IF/THEN/ELSE, FOR/NEXT, GOSUB/RETURN, END
30 GOSUB 1000: REM INITIALIZE
40 GOSUB 2000: REM PLAY GAME
50 INPUT "PLAY AGAIN (Y/N)"; A$
60 IF A$ = "Y" THEN GOTO 30
70 PRINT "THANKS FOR PLAYING!"
80 END
1000 REM INITIALIZE
1010 S = INT(RND(1) * 100) + 1
1020 T = 0
1030 RETURN
2000 REM PLAY GAME
2010 FOR I = 1 TO 10
2020 INPUT "GUESS (1-100)"; G
2030 T = T + 1
2040 IF G = S THEN GOSUB 3000: RETURN
2050 IF G < S THEN PRINT "TOO LOW!"
2060 IF G > S THEN PRINT "TOO HIGH!"
2070 NEXT I
2080 PRINT "OUT OF TRIES! IT WAS "; S
2090 RETURN
3000 REM WIN
3010 PRINT "CORRECT IN "; T; " TRIES!"
3020 RETURN
RUN
This program demonstrates:
- GOSUB/RETURN - Organised into subroutines (init, play, win)
- FOR/NEXT - 10-attempt loop
- IF/THEN - Checking guess against secret number
- IF/THEN with GOSUB - Calling win subroutine when correct
- IF with statement - Simple prints for too-high/too-low
- GOTO - Play-again loop (line 60)
- END - Clean termination
The program structure is clean: main logic (lines 10-80), subroutines (1000+), clear separation with END.
Flow Control Best Practices
After working through all these commands, here are key principles for writing maintainable BASIC code:
1. Minimize GOTO Usage
GOTO is powerful but makes code hard to follow. Prefer:
- FOR...NEXT for loops
- IF...THEN...ELSE for decisions
- GOSUB/RETURN for code reuse
- ON...GOTO only for multi-way branching (menus)
Use GOTO only when necessary (play-again loops, early exits, state machines).
2. Structure with Subroutines
Break programs into logical sections:
10-90: Main program logic
100-999: Main program helpers
1000-1999: Subroutine 1 (e.g., input validation)
2000-2999: Subroutine 2 (e.g., calculations)
3000-3999: Subroutine 3 (e.g., display)
9000-9999: Utility subroutines used everywhere
This organization makes programs scannable at a glance.
3. Always END Before Subroutines
This prevents accidental fall-through:
40 END
100 REM SUBROUTINE 1
110 ...
120 RETURN
Without line 40, the program runs into subroutine 100, executes it, hits RETURN without GOSUB—error!
4. Use STOP for Debugging
Temporarily insert STOP to examine state:
50 STOP: REM DEBUG - CHECK VARIABLES HERE
Run, examine variables, CONT, repeat. Remove STOPs once bugs are fixed.
5. Comment Complex Flow
Use REM to explain non-obvious logic:
100 REM MAIN MENU DISPATCH
110 ON C GOSUB 1000, 2000, 3000, 4000
120 REM 1=NEW 2=LOAD 3=SAVE 4=QUIT
Future-you (or other programmers) will appreciate the clarity.
6. Validate Before Branching
Check user input before ON...GOTO:
10 INPUT "CHOICE"; C
20 IF C < 1 OR C > 5 THEN PRINT "INVALID": GOTO 10
30 ON C GOSUB 100, 200, 300, 400, 500
This prevents weird behavior from out-of-range values.
7. Watch FOR Loop Variables
Don't modify loop variables inside the loop—it creates confusing, hard-to-debug code:
10 FOR I = 1 TO 10
20 PRINT I
30 I = I + 1: REM DON'T DO THIS!
40 NEXT I
Let FOR...NEXT manage the counter automatically.
Code is read more often than written. Choose clarity over cleverness. A simple IF statement beats a clever GOTO every time—even if the GOTO saves a line or two.
Common Pitfalls
NEXT Without FOR
10 FOR I = 1 TO 5
20 FOR J = 1 TO 3
30 NEXT I ← ERROR: Wrong order!
40 NEXT J
Fix: NEXT the innermost loop first: 30 NEXT J then 40 NEXT I.
RETURN Without GOSUB
10 GOTO 100
100 PRINT "HELLO"
110 RETURN ← ERROR: No GOSUB called us!
Fix: Use GOSUB instead of GOTO, or remove RETURN.
Infinite Loop Without Exit
10 X = 1
20 PRINT X
30 GOTO 20
This runs forever. If intentional (game loop), ensure there's a way out (IF condition, user input, etc.).
FOR Loop Boundary Errors
10 DIM A(10)
20 FOR I = 1 TO 11
30 A(I) = I ← ERROR: A(11) doesn't exist!
40 NEXT I
Arrays dimensioned with DIM A(10) have indices 0-10 (11 elements). Loop from 0 TO 10, not 1 TO 11.
Falling Through Into Subroutines
10 PRINT "MAIN"
20 PRINT "DONE"
100 PRINT "SUB"
110 RETURN ← ERROR when main falls through!
Fix: Add END before line 100 to stop main program execution.
When you get "RETURN WITHOUT GOSUB," check if your main program ENDs before subroutines. This is the most common cause.
Advanced Pattern: State Machine
Complex programs often need to track "states"—different modes of operation. A state machine uses a variable to remember the current state and ON...GOSUB to dispatch to state-specific code.
10 REM SIMPLE STATE MACHINE
20 REM STATE: 1=MENU, 2=PLAYING, 3=GAMEOVER
30 S = 1: REM START IN MENU STATE
40 REM MAIN LOOP
50 ON S GOSUB 100, 200, 300
60 GOTO 50
70 REM MENU STATE
100 PRINT "1. START GAME"
110 PRINT "2. QUIT"
120 INPUT C
130 IF C = 1 THEN S = 2: RETURN
140 IF C = 2 THEN END
150 PRINT "INVALID": RETURN
200 REM PLAYING STATE
210 PRINT "PLAYING... (PRESS 1 TO WIN, 2 TO LOSE)"
220 INPUT C
230 IF C = 1 THEN PRINT "YOU WIN!": S = 3
240 IF C = 2 THEN PRINT "YOU LOSE!": S = 3
250 RETURN
300 REM GAMEOVER STATE
310 PRINT "GAME OVER"
320 INPUT "PLAY AGAIN (Y/N)"; A$
330 IF A$ = "Y" THEN S = 2: RETURN
340 S = 1: RETURN
RUN
The state variable S controls program flow:
- S=1 → Menu (subroutine 100)
- S=2 → Playing (subroutine 200)
- S=3 → Game Over (subroutine 300)
Each subroutine can change S to transition to a new state. The main loop (lines 50-60) continuously dispatches based on S. This pattern scales to complex programs with many states and transitions.
Chapter Summary
You've mastered the commands that control program execution flow:
Unconditional Jumps:
- GOTO line_number - Jump to a specific line
Conditional Execution:
- IF condition THEN action - Execute if condition is true
- IF condition THEN action ELSE action - Binary choice
Loops:
- FOR var = start TO end ... NEXT var - Counted loops
- FOR var = start TO end STEP increment - Custom increment loops
- Nested FOR...NEXT - Loops within loops
Subroutines:
- GOSUB line_number - Call a subroutine
- RETURN - Return from subroutine
- ON variable GOSUB list - Computed subroutine dispatch
Computed Branching:
- ON variable GOTO list - Jump based on numeric value
Program Control:
- END - Terminate program cleanly
- STOP - Suspend execution (allows CONT)
- CONT - Continue after STOP
These commands form the foundation of structured BASIC programming. Combined with variables (Chapter 5) and operators (Chapter 6), you can now write sophisticated programs that make decisions, repeat actions, and organise code logically.
The next chapter covers Input and Output—how to interact with users, format displays, and create professional-looking programs. With flow control mastered, you're ready to build interactive applications that respond intelligently to user input.
Write a program that asks the user for two numbers and an operation (+, -, *, /), then displays the result. Use GOSUB for each operation, IF...THEN for operation selection, and INPUT for user interaction. This exercise combines flow control with I/O—a preview of Chapter 8.
Input and Output
Professional programs don't just compute—they communicate. They present information clearly, organise data logically, and interact gracefully with users. In this chapter, you'll master BASIC's input and output tools: the commands that transform raw calculations into polished, readable programs.
You already know the basics of PRINT and INPUT from earlier chapters. Now we'll go deeper, exploring formatting techniques that make your output look professional. By the end of this chapter, you'll be able to create aligned tables, formatted reports, interactive menus, and visually appealing displays.
The PRINT Statement
You've been using PRINT since Chapter 4, but let's formalize what you know and extend it.
PRINT Basics
The PRINT statement displays text, numbers, and variables:
10 PRINT "HELLO WORLD"
20 PRINT 42
30 A = 100
40 PRINT A
CODE_FENCE_0
Each PRINT statement outputs its content, then moves to a new line. This is the default behavior—unless you change it with formatting characters.
The ? Shorthand
Typing PRINT repeatedly gets tedious. BASIC provides a shortcut: the question mark (?) means exactly the same thing as PRINT.
10 ? "HELLO"
20 ? 42
This is identical to:
10 PRINT "HELLO"
20 PRINT 42
In the 1980s, every character counted when typing on a Commodore keyboard. The ? shorthand saved time and reduced typing errors. Many experienced BASIC programmers used ? exclusively.
Modern convention in printed code uses PRINT for clarity, but ? in interactive sessions for speed. Use whichever you prefer!
PRINT with Nothing
A PRINT statement with no content prints a blank line:
10 PRINT "FIRST LINE"
20 PRINT
30 PRINT "THIRD LINE"
CODE_FENCE_0
This is essential for visual spacing. Use blank lines liberally to organise output and make it easier to read.
Multiple Items
You can print several things in one statement using commas or semicolons (we'll explore these in detail soon):
10 PRINT "VALUE:", 42
20 PRINT "NAME:"; "ALICE"
The comma and semicolon control spacing differently—this is where BASIC's formatting power begins.
10 PRINT "HELLO WORLD"
20 PRINT 42
30 PRINT
40 ? "SHORTHAND WORKS TOO!"
50 END
Try both PRINT and ? to see they're identical. Add a blank line with PRINT alone.
Formatting with Commas
The comma (,) is BASIC's primary tool for creating columns. When you separate items with commas, BASIC divides the screen into zones and places each item in the next zone.
Understanding Zones
BASIC divides each line into zones of 14 characters. On a Commodore 64's 40-column screen, this gives you:
- Zone 1: Columns 0-13
- Zone 2: Columns 14-27
- Zone 3: Columns 28-41 (wraps to next line at column 40)
CODE_FENCE_0
Output: CODE_FENCE_1
Each word is in its own 14-character zone.
The 14-Character Rule
Each zone is exactly 14 characters wide. If your text is shorter than 14 characters, BASIC pads with spaces. If longer, it still occupies only one zone (but may look odd).
CODE_FENCE_0
Output: CODE_FENCE_1
Notice how everything aligns perfectly in columns.
Creating Simple Tables
Commas are perfect for tabular data:
CODE_FENCE_0
Output: CODE_FENCE_1
The columns align automatically because commas tab to the next 14-character boundary.
Multiple Zones Per Line
You can use up to 5 zones on a 40-column screen (though zone 3 starts to wrap):
10 PRINT "A", "B", "C", "D", "E"
CODE_FENCE_0
Notice how zone 3 ("C") wraps, and zones 4-5 continue on the next line.
In practice, use 2-3 zones per line for best readability. More than that causes wrapping and looks messy.
Numbers and Commas
Numbers work the same way:
10 PRINT "NAME", "AGE", "SCORE"
20 PRINT "ALICE", 25, 95
30 PRINT "BOB", 30, 87
CODE_FENCE_0
BASIC right-aligns numbers within their zones (though this isn't always obvious with the 14-character spacing).
Practical Example: Multiplication Table
CODE_FENCE_0
Output: CODE_FENCE_1
10 PRINT "PRODUCT", "PRICE", "STOCK"
20 PRINT "-------", "-----", "-----"
30 PRINT "WIDGET", "$5.00", 150
40 PRINT "GADGET", "$8.50", 75
50 PRINT "DOOHICKEY", "$12.00", 42
60 END
Run this inventory report. Try adding more products or changing the column headers.
Formatting with Semicolons
While commas create spacious columns, semicolons do the opposite: they eliminate spacing entirely, placing items directly adjacent to each other.
Semicolon: Tight Spacing
The semicolon (;) tells BASIC: "print the next item right here, with no extra space."
10 PRINT "HELLO"; "WORLD"
CODE_FENCE_0
Notice there's no space between the words—they're smashed together.
Adding Your Own Spaces
Since semicolons add no space, you control spacing explicitly:
10 PRINT "HELLO"; " "; "WORLD"
CODE_FENCE_0
The " " (a string containing one space) adds the space between words.
Building Output Piece by Piece
Semicolons let you construct output from multiple pieces:
10 NAME$ = "ALICE"
20 AGE = 25
30 PRINT "NAME: "; NAME$; " AGE: "; AGE
CODE_FENCE_0
This is incredibly useful for mixing text and variables in natural-looking sentences.
Suppressing the Newline
Here's a powerful trick: a semicolon at the end of a PRINT statement suppresses the automatic newline:
10 PRINT "PART 1";
20 PRINT " PART 2";
30 PRINT " PART 3"
CODE_FENCE_0
All three PRINT statements output to the same line because lines 10 and 20 end with semicolons.
Progress Indicators
Semicolons at line endings enable progress bars and animations:
10 PRINT "LOADING";
20 FOR I = 1 TO 10
30 PRINT ".";
40 NEXT I
50 PRINT " DONE!"
CODE_FENCE_0
The dots appear one at a time (though instantly in this example—we'd need delays for true animation).
Combining Commas and Semicolons
You can mix both in a single statement:
10 PRINT "NAME:"; "ALICE", "AGE:"; 25
CODE_FENCE_0
The semicolon keeps NAME: and ALICE together, then the comma tabs to the next zone, then the semicolon keeps AGE: and 25 together.
This gives you fine control over spacing.
Practical Example: Formatted Receipt
CODE_FENCE_0
Output: CODE_FENCE_1
10 PRINT "BUILDING";
20 PRINT " A";
30 PRINT " SENTENCE";
40 PRINT " PIECE";
50 PRINT " BY";
60 PRINT " PIECE"
70 END
See how semicolons connect multiple PRINT statements into one line. Try removing semicolons to see the difference.
TAB() for Absolute Positioning
Commas and semicolons control relative spacing—but what if you want to place text at an exact column position? That's where TAB() comes in.
TAB(n) Syntax
TAB(n) moves the cursor to column n:
10 PRINT TAB(10); "HELLO"
CODE_FENCE_0
"HELLO" starts at column 10 (with 10 spaces before it, since columns start at 0).
Absolute Column Control
Unlike commas (which tab to 14, 28, etc.), TAB() lets you specify any column from 0 to 39 (on a 40-column screen):
10 PRINT TAB(5); "FIVE"
20 PRINT TAB(15); "FIFTEEN"
30 PRINT TAB(25); "TWENTY-FIVE"
CODE_FENCE_0
Each line positions its text at exactly the specified column.
Creating Precise Tables
TAB() excels at creating professionally aligned tables:
10 PRINT TAB(0); "ITEM"; TAB(20); "PRICE"; TAB(30); "QTY"
20 PRINT TAB(0); "----"; TAB(20); "-----"; TAB(30); "---"
30 PRINT TAB(0); "APPLE"; TAB(20); "$1.50"; TAB(30); "12"
40 PRINT TAB(0); "ORANGE"; TAB(20); "$2.00"; TAB(30); "8"
50 PRINT TAB(0); "BANANA"; TAB(20); "$0.75"; TAB(30); "20"
CODE_FENCE_0
Perfect alignment, regardless of item name length.
TAB() vs. Commas
Compare these approaches:
With commas (14-char zones):
10 PRINT "NAME", "SCORE"
20 PRINT "ALICE", 95
Output:
NAME SCORE
ALICE 95
With TAB() (exact columns):
10 PRINT "NAME"; TAB(20); "SCORE"
20 PRINT "ALICE"; TAB(20); 95
Output:
NAME SCORE
ALICE 95
TAB() gives you pixel-perfect control.
TAB() with Variables
You can calculate TAB positions dynamically:
10 FOR I = 0 TO 30 STEP 10
20 PRINT TAB(I); "*"
30 NEXT I
CODE_FENCE_0
Stars appear at columns 0, 10, 20, and 30.
Practical Example: Formatted Report
CODE_FENCE_0
Output: CODE_FENCE_1
If the cursor is already past the specified column, TAB() does nothing—it won't move backward. For example, if you're at column 20 and use TAB(10), the cursor stays at column 20.
10 PRINT TAB(5); "MENU"
20 PRINT TAB(5); "===="
30 PRINT
40 PRINT TAB(0); "1."; TAB(5); "NEW GAME"
50 PRINT TAB(0); "2."; TAB(5); "LOAD GAME"
60 PRINT TAB(0); "3."; TAB(5); "OPTIONS"
70 PRINT TAB(0); "4."; TAB(5); "QUIT"
80 END
A professionally formatted menu using TAB(). Try changing the column numbers to see how alignment changes.
SPC() for Relative Spacing
While TAB() positions absolutely, SPC() adds spacing relative to the current cursor position. It prints a specified number of spaces.
SPC(n) Syntax
SPC(n) prints n spaces:
10 PRINT "HELLO"; SPC(5); "WORLD"
CODE_FENCE_0
Five spaces appear between HELLO and WORLD.
Adding Spacing
SPC() is useful when you want gaps without calculating exact positions:
10 PRINT "NAME:"; SPC(3); "ALICE"
20 PRINT "AGE:"; SPC(4); "25"
30 PRINT "CITY:"; SPC(3); "NYC"
CODE_FENCE_0
Notice how the spacing is consistent, even though the labels are different lengths. (Though in this example, they'd align better with TAB().)
SPC() in Loops
SPC() shines in loops where you need increasing or decreasing spacing:
10 FOR I = 0 TO 5
20 PRINT SPC(I); "*"
30 NEXT I
CODE_FENCE_0
Each star is one space further right than the previous.
SPC() vs. TAB()
When should you use each?
Use TAB() when:
- You need exact column positions
- You're creating aligned tables
- Multiple lines need to align precisely
Use SPC() when:
- You need a fixed number of spaces
- You're adding gaps in a line
- You're creating patterns or animations
CODE_FENCE_0
Both produce similar output, but TAB() is absolute (column 10, column 20), while SPC() is relative (8 spaces, then 9 spaces).
Creating Patterns
SPC() is excellent for ASCII art and patterns:
10 FOR I = 1 TO 5
20 PRINT SPC(5-I); "*"; SPC(2*I-2); "*"
30 NEXT I
CODE_FENCE_0
The spacing creates a diamond shape.
Practical Example: Progress Bar
CODE_FENCE_0
Output: CODE_FENCE_1
10 FOR I = 0 TO 10
20 PRINT SPC(I); "*"; SPC(20-2*I); "*"
30 NEXT I
40 END
Watch stars move in opposite directions using SPC(). Try changing the spacing formula.
POS() for Cursor Position
Sometimes you need to know where you are on the screen. POS(0) returns the current cursor column position.
POS(0) Syntax
POS(0) is a function that returns the column number (0-39 on a 40-column screen):
10 PRINT "HELLO";
20 P = POS(0)
30 PRINT " CURSOR AT:"; P
CODE_FENCE_0
After printing "HELLO" (5 characters), the cursor is at column 5.
The parameter is always 0—it's a quirk of Commodore BASIC's syntax. The original design allowed for multiple devices (0 for screen), but only screen position was implemented.
Always use POS(0), not POS() or POS(1).
Checking Position Before Formatting
POS(0) helps you decide whether to add spacing:
10 PRINT "NAME:";
20 IF POS(0) < 10 THEN PRINT SPC(10 - POS(0));
30 PRINT "ALICE"
This ensures "ALICE" always starts at column 10, regardless of how wide "NAME:" is.
Dynamic TAB Calculation
Use POS(0) to tab to the next available zone:
10 PRINT "SHORT";
20 NEXTTAB = (INT(POS(0)/14) + 1) * 14
30 PRINT TAB(NEXTTAB); "NEXT COLUMN"
This calculates the next 14-character zone boundary.
Detecting Line Wrapping
Check if you're approaching the edge of the screen:
10 PRINT "THIS IS A LONG LINE OF TEXT";
20 IF POS(0) > 30 THEN PRINT "(NEAR EDGE)"
If the cursor is past column 30, you're getting close to the 40-column limit.
Practical Example: Right-Aligned Text
CODE_FENCE_0
Output: CODE_FENCE_1
The text is right-aligned by calculating its position based on length.
Centering Text
10 WIDTH = 40
20 TEXT$ = "CENTERED TEXT"
30 CENTERPOS = (WIDTH - LEN(TEXT$)) / 2
40 PRINT TAB(CENTERPOS); TEXT$
CODE_FENCE_0
POS() Limitations
POS(0) only tracks the column—not the row. BASIC V2 has no equivalent for checking the vertical cursor position.
10 PRINT "HELLO";
20 P = POS(0)
30 PRINT
40 PRINT "CURSOR WAS AT COLUMN:"; P
50 PRINT
60 PRINT "NOW TRY THIS:"
70 PRINT "12345678901234567890";
80 PRINT " POSITION:"; POS(0)
90 END
See POS(0) in action. Try changing the text lengths to see how position changes.
Getting Input with INPUT
You've used INPUT to read user data, but there's more to learn about its behavior and formatting options.
Basic INPUT
The simplest form waits for the user to type something:
10 INPUT A$
When this line executes:
- BASIC prints
?(the input prompt) - Waits for user to type
- User presses ENTER
- BASIC stores the input in
A$
CODE_FENCE_0
INPUT with Prompts
Add a message before the ?:
10 INPUT "WHAT IS YOUR NAME"; A$
CODE_FENCE_0
Notice the ? appears automatically after your prompt.
Multiple Variables
You can input several values at once:
10 INPUT "ENTER THREE NUMBERS"; A, B, C
CODE_FENCE_0
Users separate values with commas.
Mixing String and Numeric Variables
10 INPUT "NAME, AGE, CITY"; N$, A, C$
CODE_FENCE_0
INPUT Behavior
Important details:
- Numeric variables: If user enters non-numeric text, BASIC shows
?REDO FROM START - String variables: Accept any text
- Leading spaces: Trimmed from input
- Quotes: Required if input contains commas (e.g.,
"SMITH, JOHN")
CODE_FENCE_0
BASIC rejects non-numeric input for numeric variables.
Complete Example
CODE_FENCE_0
10 PRINT "CALCULATOR"
20 INPUT "FIRST NUMBER"; A
30 INPUT "SECOND NUMBER"; B
40 PRINT
50 PRINT "SUM:"; A + B
60 PRINT "PRODUCT:"; A * B
70 END
Run this calculator and enter two numbers when prompted. Try entering invalid input to see ?REDO FROM START.
Input Prompts
The way you format prompts significantly affects user experience. Let's master prompt customization.
Default Prompt (with ?)
By default, INPUT adds a ?:
10 INPUT "NAME"; N$
Output: NAME? _
Custom Prompt (semicolon suppresses ?)
Use a semicolon instead of a comma to suppress the automatic ?:
10 INPUT "NAME: "; N$
Output: NAME: _
No question mark! This looks more professional.
CODE_FENCE_0
When to Use Each Style
Use comma (with ?):
- Questions:
INPUT "CONTINUE"; A$ - Simple prompts:
INPUT "NAME", N$ - Authentic retro feel
Use semicolon (no ?):
- Labels:
INPUT "USERNAME: "; U$ - Professional forms:
INPUT "ENTER PASSWORD: "; P$ - Modern appearance
Formatting Multi-Line Prompts
For complex input, split the prompt:
10 PRINT "PLEASE ENTER YOUR FULL NAME"
20 PRINT "(FIRST AND LAST)"
30 INPUT "NAME: "; N$
CODE_FENCE_0
Clearer than cramming everything into one line.
Empty Prompts
For minimal interface, use an empty prompt:
10 PRINT "NAME:"
20 INPUT ""; N$
CODE_FENCE_0
Still shows ? but no text before it.
Arrow Prompts
Create custom prompt characters:
10 INPUT "> "; CMD$
CODE_FENCE_0
Looks like a command-line interface.
Practical Example: Form
CODE_FENCE_0
Output: CODE_FENCE_1
Notice the dots in the form labels (CUSTOMER NAME.....:). These are called "dot leaders" and help the eye connect labels to input fields. They're a classic formatting technique from the days of printed forms.
10 PRINT "LOGIN SYSTEM"
20 PRINT "============"
30 PRINT
40 INPUT "USERNAME: "; U$
50 INPUT "PASSWORD: "; P$
60 PRINT
70 IF U$ = "ADMIN" AND P$ = "1234" THEN PRINT "ACCESS GRANTED" ELSE PRINT "ACCESS DENIED"
80 END
A simple login system using semicolon-style prompts. Try entering the username "ADMIN" and password "1234".
Single Keystroke with GET
INPUT waits for the user to type and press ENTER. But what if you want immediate response to a single keystroke? That's where GET comes in.
GET Syntax
GET reads a single character without waiting for ENTER:
10 GET A$
This sets A$ to:
- The character if a key is pressed
- Empty string (
"") if no key is pressed
GET vs INPUT
Compare:
INPUT:
10 INPUT "PRESS ENTER"; A$
User types HELLO and presses ENTER → A$ = "HELLO"
GET:
10 GET A$
User presses H → A$ = "H" (immediately, no ENTER needed)
WASM Context Limitation
In SLP-BASIC's WASM environment, GET behaves differently than on real Commodore hardware:
- Real Commodore:
GETwaits for a keypress (blocking) - SLP-BASIC:
GETreturns immediately with empty string if no key waiting (non-blocking)
This is due to the cooperative execution model—BASIC can't pause indefinitely waiting for input without freezing the browser.
Checking for Empty String
Because GET might return empty, always check:
10 GET A$
20 IF A$ = "" THEN GOTO 10
30 PRINT "YOU PRESSED: "; A$
This loops until a key is pressed.
Menu Systems
GET is perfect for menu choices:
10 PRINT "MENU: [A] ADD [B] DELETE [Q] QUIT"
20 GET K$
30 IF K$ = "" THEN GOTO 20
40 IF K$ = "A" THEN PRINT "ADDING..."
50 IF K$ = "B" THEN PRINT "DELETING..."
60 IF K$ = "Q" THEN END
70 GOTO 20
CODE_FENCE_0
Detecting Specific Keys
10 PRINT "PRESS SPACE TO CONTINUE"
20 GET K$
30 IF K$ <> " " THEN GOTO 20
40 PRINT "CONTINUING..."
Waits specifically for the spacebar.
Yes/No Prompts
10 PRINT "DELETE ALL FILES? (Y/N)"
20 GET A$
30 IF A$ = "" THEN GOTO 20
40 IF A$ = "Y" THEN PRINT "DELETED!": GOTO 60
50 IF A$ = "N" THEN PRINT "CANCELLED": GOTO 60
60 END
CODE_FENCE_0
Case Sensitivity
GET is case-sensitive. "A" and "a" are different. Handle both:
10 GET K$
20 IF K$ = "Y" OR K$ = "y" THEN PRINT "YES"
Or convert to uppercase:
10 GET K$
20 IF K$ >= "a" AND K$ <= "z" THEN K$ = CHR$(ASC(K$) - 32)
30 IF K$ = "Y" THEN PRINT "YES"
Practical Example: Press Any Key
CODE_FENCE_0
GET in SLP-BASIC:
- Returns immediately (non-blocking)
- Requires a loop to wait for input
- Can't detect special keys (F1, arrows) in WASM context
- Always use
IF A$ = "" THEN GOTOpattern
10 PRINT "SIMPLE MENU"
20 PRINT "==========="
30 PRINT
40 PRINT "[N] NEW GAME"
50 PRINT "[L] LOAD GAME"
60 PRINT "[Q] QUIT"
70 PRINT
80 PRINT "CHOICE: ";
90 GET C$
100 IF C$ = "" THEN GOTO 90
110 PRINT C$
120 IF C$ = "N" THEN PRINT "STARTING NEW GAME..."
130 IF C$ = "L" THEN PRINT "LOADING GAME..."
140 IF C$ = "Q" THEN PRINT "GOODBYE!": END
150 END
Try pressing N, L, or Q. Notice how GET responds immediately to a single keystroke.
Formatted Output Examples
Let's put everything together with complete, practical examples that demonstrate professional formatting techniques.
Example 1: Multiplication Table
CODE_FENCE_0
Output: CODE_FENCE_1
Example 2: Invoice
CODE_FENCE_0
Example 3: Restaurant Menu
CODE_FENCE_0
Output: CODE_FENCE_1
Example 4: Progress Bar
CODE_FENCE_0
(The delay loop in line 60 would slow down the progress bar on real hardware.)
Example 5: Data Entry Form
CODE_FENCE_0
Example 6: ASCII Art Border
CODE_FENCE_0
Output: CODE_FENCE_1
10 PRINT "GRADE REPORT"
20 PRINT "============"
30 PRINT
40 INPUT "STUDENT NAME: "; N$
50 INPUT "MATH SCORE: "; M
60 INPUT "ENGLISH SCORE: "; E
70 INPUT "SCIENCE SCORE: "; S
80 AVG = (M + E + S) / 3
90 PRINT
100 PRINT "STUDENT: "; N$
110 PRINT STRING$(30, "-")
120 PRINT "MATH"; TAB(20); M
130 PRINT "ENGLISH"; TAB(20); E
140 PRINT "SCIENCE"; TAB(20); S
150 PRINT STRING$(30, "-")
160 PRINT "AVERAGE"; TAB(20); AVG
170 END
A complete grade calculator with formatted output. Enter three scores and see a professional report.
Common Formatting Mistakes
Even experienced programmers make formatting errors. Here are the most common pitfalls and how to avoid them.
Mistake 1: Mixing Comma and Semicolon Accidentally
CODE_FENCE_0
Output: CODE_FENCE_1
The comma tabs to column 14, but the semicolon smashes AGE and CITY together.
Fix: Be consistent. Use all commas OR all semicolons:
10 PRINT "NAME:", "AGE:", "CITY:"
or
10 PRINT "NAME: "; "AGE: "; "CITY: "
Mistake 2: Forgetting Semicolon for Continuation
CODE_FENCE_0
Output: CODE_FENCE_1
You wanted them on the same line! Fix:
10 PRINT "LOADING";
20 PRINT "..."
Mistake 3: TAB() Past Current Position
CODE_FENCE_0
If line 10 leaves the cursor at column 20, TAB(5) does nothing—the cursor can't move backward. "HERE" prints at column 20, not column 5.
Fix: Use TAB() at the start of a line, or ensure you're tabbing forward:
10 PRINT "LONG LINE"
20 PRINT TAB(5); "HERE"
Mistake 4: Not Accounting for Variable Length
CODE_FENCE_0
If N$ is "CHRISTOPHER" (11 chars), the cursor might already be past column 20 when you use TAB(20), misaligning the output.
Fix: Always start fresh lines for alignment, or use fixed-width fields:
10 PRINT "NAME: "; LEFT$(N$, 10); TAB(20); "AGE:"; A
Mistake 5: Forgetting Spaces in Semicolon Output
CODE_FENCE_0
Output: HELLOWORLD
Fix: Add explicit spaces:
30 PRINT A$; " "; B$
Output: HELLO WORLD
Mistake 6: Wrong Variable Type in INPUT
CODE_FENCE_0
A$ is a string, can't add numbers to it.
Fix: Use numeric variable:
10 INPUT "AGE"; A
20 PRINT "IN 10 YEARS:"; A + 10
Mistake 7: Not Checking for Empty GET
CODE_FENCE_0
This might miss the keypress if GET returns empty string.
Fix: Loop until you get input:
10 GET K$
20 IF K$ = "" THEN GOTO 10
30 IF K$ = "Q" THEN END
Before finalizing output:
- ✓ Check alignment with different length inputs
- ✓ Verify commas and semicolons are used consistently
- ✓ Test TAB() positions with actual data
- ✓ Ensure spaces appear where expected
- ✓ Test GET loops with empty input
- ✓ Verify numeric vs string variable types
Chapter Summary: Professional Output
You've mastered BASIC's complete I/O toolkit. Let's review what you can now do:
Output Control
PRINT Statement:
- Display text, numbers, and variables
?shorthand for fast typing- Blank lines with
PRINTalone
Comma Formatting:
- Tabs to 14-character zones (14, 28, 42...)
- Perfect for simple tables and columns
- Automatic spacing
Semicolon Formatting:
- Tight spacing, no gaps
- Continue lines (semicolon at end)
- Build output piece by piece
TAB(n):
- Absolute positioning to column n
- Precise alignment for professional tables
- Calculate positions dynamically
SPC(n):
- Relative spacing (n spaces)
- Pattern creation
- Variable spacing in loops
POS(0):
- Query current cursor column
- Dynamic positioning calculations
- Right-align and center text
Input Control
INPUT Statement:
- Basic user input
- Custom prompts with comma or semicolon
- Multiple variables at once
- Type validation (numeric vs string)
Prompt Styles:
- Comma: Adds automatic
? - Semicolon: Suppresses
?for custom prompts - Multi-line prompts for clarity
GET Statement:
- Single keystroke input
- Menu systems
- "Press any key" prompts
- Non-blocking in WASM (requires loop)
Practical Skills
You can now create:
- ✓ Aligned tables and reports
- ✓ Professional invoices and forms
- ✓ Restaurant menus and price lists
- ✓ Progress indicators
- ✓ Interactive menus
- ✓ ASCII art borders
- ✓ Data entry systems
- ✓ Formatted calculations
Key Principles
Formatting is communication:
- Good formatting makes programs easier to use
- Alignment helps users scan data quickly
- Spacing creates visual hierarchy
- Professional output builds user confidence
Choose the right tool:
- Commas for quick, simple columns
- TAB() for precise alignment
- Semicolons for tight control
- SPC() for patterns and spacing
Test with real data:
- Variable-length inputs affect alignment
- Always verify formatting with actual values
- Plan for the longest expected data
What's Next
You now have all the tools for user interaction and output formatting. The next chapters will teach you:
- Chapter 9 — Arrays for handling collections of data
- Chapter 10 — Built-in functions for text and math
- Chapter 11 — Program management commands
- Chapter 12 — Saving and loading programs
But with what you know now, you can create sophisticated, professional-looking programs. Don't wait—start building!
Before moving on, create a complete program that:
- Displays a formatted menu (using TAB or commas)
- Gets user choice (using GET or INPUT)
- Collects multiple pieces of data (using INPUT)
- Displays a formatted report (using TAB, SPC, and formatting)
This will solidify everything you've learned in this chapter.
One Final Challenge
Create a grade book program from scratch:
Requirements:
- Ask for student name
- Input 3 test scores
- Calculate average
- Display formatted report with:
- Student name
- Each test score (aligned)
- Average (highlighted)
- Letter grade (A/B/C/D/F based on average)
Use everything from this chapter: INPUT prompts, TAB positioning, formatted output, and calculations.
Congratulations! You've completed Chapter 8. You're no longer just printing basic output—you're creating professional user interfaces.
Master formatting, and your programs will look polished and professional, even if they're simple underneath. First impressions matter, and well-formatted output makes all the difference.
Arrays and Data
What Are Arrays?
Variables store single values—one number, one text string. But what if you need to store fifty test scores? Or a hundred temperatures? Or a tic-tac-toe board with nine positions? Creating SCORE1, SCORE2, SCORE3... SCORE50 is tedious, error-prone, and impossible to process in loops.
Arrays solve this problem. An array is a collection of storage locations—numbered boxes—all sharing a single name. Instead of fifty separate variables, you have one array with fifty numbered elements:
SCORE(0) = 85
SCORE(1) = 92
SCORE(2) = 78
...
SCORE(49) = 95
Each element (numbered box) holds a value, accessed by its index (position number). The array name (SCORE) identifies the collection; the index in parentheses (0, 1, 2...) identifies the specific element.
Think of an array as a numbered list:
- Array: A vertical filing cabinet with numbered drawers
- Index: The drawer number (0, 1, 2, 3...)
- Element: The contents of one drawer
- Array name: The label on the cabinet
Arrays organise related data logically. All test scores go in the SCORE array. All daily temperatures go in the TEMP array. All game board positions go in the BOARD array. This organization makes programs clearer and enables powerful patterns like processing every element with a FOR loop.
BASIC supports:
- One-dimensional arrays: Lists indexed by a single number (like a column of data)
- Two-dimensional arrays: Tables indexed by two numbers (like a spreadsheet with rows and columns)
Both types use the same fundamental concept: numbered storage boxes accessed by index.
BASIC arrays start at index 0, not 1. An array with 10 elements has indices 0 through 9. This surprises beginners but quickly becomes natural. Remember: the index is a position offset from the start, so the first element is at offset 0.
Declaring Arrays with DIM
Unlike simple variables (which spring into existence on first use), arrays must be declared before use with the DIM statement. DIM stands for "dimension"—you're defining the size and shape of the array.
Basic DIM Syntax
DIM arrayname(size)
Examples:
DIM SCORE(10) ' Numeric array, 11 elements (0-10)
DIM NAME$(20) ' String array, 21 elements (0-20)
DIM COUNT%(50) ' Integer array, 51 elements (0-50)
The number in parentheses is the maximum index, not the number of elements. DIM A(10) creates an array with 11 elements: A(0), A(1), A(2)... A(10). This is the zero-based indexing at work—index runs from 0 to the declared size, inclusive.
Size Calculation
To calculate the number of elements:
Number of elements = declared size + 1
Examples:
- DIM A(10): 11 elements (0-10)
- DIM A(99): 100 elements (0-99)
- DIM A(0): 1 element (just element 0)
This off-by-one calculation confuses beginners. Remember: the DIM parameter is the highest index you can use, not a count of elements.
If you need exactly 50 elements:
DIM SCORE(49) ' Elements 0-49 = 50 elements
If you need 100 elements:
DIM TEMPS(99) ' Elements 0-99 = 100 elements
Default Array Size
If you use an array without DIM, BASIC automatically creates it with 11 elements (0-10). This is convenient for small arrays but dangerous for larger ones:
A(5) = 100 ' OK: auto-created with default size
A(15) = 200 ' Error: SUBSCRIPT OUT OF RANGE
Best practice: always use DIM explicitly. It documents your array size and prevents subscript range errors from exceeding the default limit.
Array Types
Arrays have types just like variables:
- Numeric arrays (no suffix): DIM A(10)
- Integer arrays (% suffix): DIM A%(10)
- String arrays ($ suffix): DIM A$(10)
The type suffix applies to every element:
DIM NAME$(10) ' 11 string elements
NAME$(0) = "ALICE"
NAME$(1) = "BOB"
NAME$(2) = "CHARLIE"
You can't mix types within an array. Each element holds the same type of data.
DIM Restrictions
Important restrictions on DIM:
- DIM before use: Must declare array before accessing elements
- DIM once only: Can't re-DIM an array after it's created
- DIM in program or immediate: Works in both modes, but program-mode DIM is more common
Attempting to DIM an array twice causes an error:
DIM A(10)
DIM A(20) ' Error: REDIM'D ARRAY
Once dimensioned, an array's size is fixed for that program run. To change size, use NEW (erases program) or CLR (erases variables including arrays), then DIM again with the new size.
Memory Considerations
Arrays consume memory proportional to their size:
- Numeric array: 5 bytes per element (1-byte overhead + 4-byte float)
- Integer array: 3 bytes per element (1-byte overhead + 2-byte int)
- String array: ~20 bytes per element (varies with string length)
Large arrays can exhaust memory:
DIM BIG(10000) ' ~50KB for numeric array
The C64 has 38911 bytes free; VIC-20 has only 3583 bytes. Plan array sizes carefully. Use integer arrays for whole numbers to save memory (3 bytes vs 5 bytes per element).
DIM A(10) creates 11 elements, not 10. The size parameter is the maximum index, not the count. Always add 1 when calculating memory usage or loop limits.
DIM Examples
<BasicCode>
10 PRINT "ARRAY DECLARATION DEMO"
20 DIM SCORES(4)
30 SCORES(0) = 85
40 SCORES(1) = 92
50 SCORES(2) = 78
60 SCORES(3) = 88
70 SCORES(4) = 95
80 PRINT "TEST SCORES:"
90 FOR I = 0 TO 4
100 PRINT "SCORE"; I; "= "; SCORES(I)
110 NEXT I
</BasicCode>
Zero-Based Indexing
BASIC arrays start counting at 0, not 1. This zero-based indexing is fundamental to understanding arrays and avoiding off-by-one errors.
Index Range
An array declared with DIM A(N) has indices from 0 to N:
DIM A(10)
Valid indices: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 (that's 11 elements)
Invalid indices: -1, 11, 12, 100 (out of range)
The first element is A(0), not A(1). The last element is A(10), equal to the DIM parameter.
Why Zero-Based?
Zero-based indexing has historical and mathematical reasons:
- Memory offset: Index represents offset from array start (0 bytes = first element)
- Mathematical elegance: Modulo arithmetic and array wrap-around work naturally
- Common practice: Most programming languages (C, Java, Python) use zero-based arrays
- Commodore heritage: Original BASIC implementations chose this convention
It feels unnatural initially ("first element should be #1!"), but you'll adapt quickly. The key insight: index is a distance from the start, not a position number.
Loop Patterns
Zero-based indexing affects loop patterns. To process every element:
DIM A(10)
FOR I = 0 TO 10 ' Include 0 and 10
PRINT A(I)
NEXT I
Not:
FOR I = 1 TO 10 ' Wrong: skips A(0)
And not:
FOR I = 0 TO 9 ' Wrong: skips A(10)
The loop must run from 0 to the DIM size, inclusive: FOR I = 0 TO N.
Common Pitfall: One-Based Thinking
Beginners often think in one-based terms:
DIM SCORES(10) ' "I want 10 scores"
FOR I = 1 TO 10 ' "Process scores 1 through 10"
SCORES(I) = I * 10
NEXT I
This works but wastes SCORES(0)—you've allocated 11 elements but only use 10. Either:
- Use all elements (embrace zero-based):
DIM SCORES(10) ' 11 elements
FOR I = 0 TO 10 ' Use all 11
SCORES(I) = I * 10
NEXT I
- Dimension correctly (if you insist on one-based):
DIM SCORES(10) ' 11 elements (waste SCORES(0))
FOR I = 1 TO 10 ' Use elements 1-10
SCORES(I) = I * 10
NEXT I
Option 1 is preferred—don't waste memory on unused elements.
Subscript Out of Range Error
Accessing an index outside the declared range causes ?SUBSCRIPT OUT OF RANGE ERROR:
DIM A(10)
A(11) = 100 ' Error: 11 > 10 (max index)
A(-1) = 50 ' Error: negative index
PRINT A(20) ' Error: 20 > 10
This error is your friend—it catches array bugs before they corrupt memory. Always ensure loop bounds match array dimensions.
Zero-Based Example
<BasicCode>
10 PRINT "ZERO-BASED INDEXING DEMO"
20 DIM DAYS$(6)
30 DAYS$(0) = "SUNDAY"
40 DAYS$(1) = "MONDAY"
50 DAYS$(2) = "TUESDAY"
60 DAYS$(3) = "WEDNESDAY"
70 DAYS$(4) = "THURSDAY"
80 DAYS$(5) = "FRIDAY"
90 DAYS$(6) = "SATURDAY"
100 PRINT "DAYS OF THE WEEK:"
110 FOR I = 0 TO 6
120 PRINT I; ": "; DAYS$(I)
130 NEXT I
</BasicCode>
Notice: 7 days fit in DAYS$(6) because arrays include index 0 through 6 (that's 0,1,2,3,4,5,6 = 7 elements).
Think of the index as "how many steps from the start." The first element is 0 steps away. The second element is 1 step away. This perspective makes zero-based indexing intuitive.
One-Dimensional Arrays
One-dimensional arrays are lists: sequences of values indexed by a single number. They're the most common array type and perfect for storing any linear collection of data.
Concept: Lists
A one-dimensional array models:
- List of test scores
- Temperatures for each day of the week
- High scores in a game
- Student names in a class
- Inventory counts for different items
Any data that forms a natural sequence fits a one-dimensional array.
Declaration
DIM arrayname(size)
Examples:
DIM SCORES(9) ' 10 test scores (0-9)
DIM TEMPS(6) ' 7 daily temperatures (0-6)
DIM NAMES$(19) ' 20 student names (0-19)
DIM INVENTORY%(99) ' 100 inventory items (0-99)
Accessing Elements
Access individual elements with subscript notation:
DIM A(10)
A(0) = 100 ' Assign to first element
A(5) = 200 ' Assign to sixth element
X = A(5) ' Read from sixth element
PRINT A(0) ' Print first element
The subscript can be:
- Literal: A(5)
- Variable: A(I)
- Expression: A(I * 2 + 1)
Variable indices enable powerful loop patterns:
FOR I = 0 TO 10
A(I) = I * I ' Store squares
NEXT I
Processing All Elements
The standard pattern for processing every element:
DIM A(N)
FOR I = 0 TO N
' Process A(I)
NEXT I
Example: Sum all elements
DIM SCORES(9)
' ... fill array ...
TOTAL = 0
FOR I = 0 TO 9
TOTAL = TOTAL + SCORES(I)
NEXT I
AVERAGE = TOTAL / 10
PRINT "AVERAGE: "; AVERAGE
Student Grades Example
Complete program: Track student grades, calculate average
<BasicCode>
10 PRINT "STUDENT GRADE TRACKER"
20 DIM GRADES(4)
30 PRINT "ENTER 5 GRADES:"
40 FOR I = 0 TO 4
50 PRINT "GRADE "; I + 1; ": ";
60 INPUT GRADES(I)
70 NEXT I
80 TOTAL = 0
90 FOR I = 0 TO 4
100 TOTAL = TOTAL + GRADES(I)
110 NEXT I
120 AVERAGE = TOTAL / 5
130 PRINT ""
140 PRINT "GRADES: ";
150 FOR I = 0 TO 4
160 PRINT GRADES(I); " ";
170 NEXT I
180 PRINT ""
190 PRINT "AVERAGE: "; AVERAGE
</BasicCode>
Temperature Tracker Example
Track daily temperatures, find maximum:
<BasicCode>
10 PRINT "WEEKLY TEMPERATURE TRACKER"
20 DIM TEMPS(6)
30 DATA 68, 72, 75, 71, 69, 73, 70
40 FOR I = 0 TO 6
50 READ TEMPS(I)
60 NEXT I
70 MAXTEMP = TEMPS(0)
80 MAXDAY = 0
90 FOR I = 1 TO 6
100 IF TEMPS(I) > MAXTEMP THEN MAXTEMP = TEMPS(I): MAXDAY = I
110 NEXT I
120 PRINT "TEMPERATURES: ";
130 FOR I = 0 TO 6
140 PRINT TEMPS(I); " ";
150 NEXT I
160 PRINT ""
170 PRINT "HIGHEST: "; MAXTEMP; " ON DAY "; MAXDAY
</BasicCode>
Common One-Dimensional Patterns
Filling an array with calculated values:
DIM SQUARES(10)
FOR I = 0 TO 10
SQUARES(I) = I * I
NEXT I
Searching an array:
FOUND = 0
FOR I = 0 TO N
IF A(I) = TARGET THEN FOUND = I: I = N
NEXT I
IF FOUND > 0 THEN PRINT "FOUND AT INDEX "; FOUND
Reversing an array:
FOR I = 0 TO N / 2
TEMP = A(I)
A(I) = A(N - I)
A(N - I) = TEMP
NEXT I
Finding minimum/maximum:
MIN = A(0)
MAX = A(0)
FOR I = 1 TO N
IF A(I) < MIN THEN MIN = A(I)
IF A(I) > MAX THEN MAX = A(I)
NEXT I
Two-Dimensional Arrays
Two-dimensional arrays are tables: grids of values indexed by two numbers (row and column). They model spreadsheets, game boards, matrices, or any data naturally organised in rows and columns.
Concept: Tables
A two-dimensional array models:
- Tic-tac-toe board (3×3 grid)
- Chess board (8×8 grid)
- Multiplication table (rows × columns)
- Spreadsheet (rows × columns)
- Pixel display (x × y coordinates)
Any data arranged in a rectangular grid fits a two-dimensional array.
Declaration
DIM arrayname(rows, columns)
Examples:
DIM BOARD(2, 2) ' 3×3 tic-tac-toe board (0-2, 0-2)
DIM MATRIX(9, 9) ' 10×10 matrix (0-9, 0-9)
DIM MAP(19, 19) ' 20×20 game map (0-19, 0-19)
Both dimensions follow zero-based indexing. DIM A(2, 3) creates a 3×4 array:
- Rows: 0, 1, 2 (3 rows)
- Columns: 0, 1, 2, 3 (4 columns)
- Total elements: 3 × 4 = 12
Accessing Elements
Access elements with two indices: arrayname(row, column)
DIM BOARD(2, 2)
BOARD(0, 0) = 1 ' Top-left corner
BOARD(1, 1) = 2 ' Center
BOARD(2, 2) = 3 ' Bottom-right corner
Visualize it as a grid:
Col 0 Col 1 Col 2
Row 0: 1 ? ?
Row 1: ? 2 ?
Row 2: ? ? 3
Processing All Elements
Nested loops process every element—outer loop for rows, inner loop for columns:
DIM A(ROWS, COLS)
FOR R = 0 TO ROWS
FOR C = 0 TO COLS
' Process A(R, C)
NEXT C
NEXT R
This traverses row-by-row (all columns in row 0, then all columns in row 1, etc.).
Multiplication Table Example
Classic 2D array application:
<BasicCode>
10 PRINT "MULTIPLICATION TABLE"
20 DIM TABLE(10, 10)
30 FOR R = 0 TO 10
40 FOR C = 0 TO 10
50 TABLE(R, C) = R * C
60 NEXT C
70 NEXT R
80 PRINT " ";
90 FOR C = 0 TO 10
100 PRINT C; TAB(4 * (C + 1));
110 NEXT C
120 PRINT ""
130 FOR R = 0 TO 10
140 PRINT R; TAB(3);
150 FOR C = 0 TO 10
160 PRINT TABLE(R, C); TAB(4 * (C + 1));
170 NEXT C
180 PRINT ""
190 NEXT R
</BasicCode>
Tic-Tac-Toe Board Example
Model a game board with 2D array:
<BasicCode>
10 PRINT "TIC-TAC-TOE BOARD"
20 DIM BOARD(2, 2)
30 REM INITIALIZE EMPTY BOARD
40 FOR R = 0 TO 2
50 FOR C = 0 TO 2
60 BOARD(R, C) = 0
70 NEXT C
80 NEXT R
90 REM MAKE SOME MOVES
100 BOARD(0, 0) = 1: REM X
110 BOARD(1, 1) = 1: REM X
120 BOARD(2, 2) = 1: REM X
130 BOARD(0, 2) = 2: REM O
140 BOARD(2, 0) = 2: REM O
150 REM DISPLAY BOARD
160 FOR R = 0 TO 2
170 FOR C = 0 TO 2
180 IF BOARD(R, C) = 0 THEN PRINT "-";
190 IF BOARD(R, C) = 1 THEN PRINT "X";
200 IF BOARD(R, C) = 2 THEN PRINT "O";
210 IF C < 2 THEN PRINT " ";
220 NEXT C
230 PRINT ""
240 NEXT R
</BasicCode>
Matrix Operations Example
Simple matrix addition:
DIM A(2, 2)
DIM B(2, 2)
DIM C(2, 2)
REM Fill A and B with values
FOR R = 0 TO 2
FOR C = 0 TO 2
READ A(R, C)
NEXT C
NEXT R
FOR R = 0 TO 2
FOR C = 0 TO 2
READ B(R, C)
NEXT C
NEXT R
REM Add matrices: C = A + B
FOR R = 0 TO 2
FOR C = 0 TO 2
C(R, C) = A(R, C) + B(R, C)
NEXT C
NEXT R
DATA 1,2,3,4,5,6,7,8,9
DATA 9,8,7,6,5,4,3,2,1
Memory Considerations
Two-dimensional arrays consume rows × columns elements:
DIM A(99, 99) ' 100 × 100 = 10,000 elements
At 5 bytes per element (numeric), that's 50KB—exceeds C64 memory! Be cautious with large 2D arrays.
Use integer arrays for smaller size:
DIM A%(99, 99) ' 30KB (3 bytes/element)
Or reduce dimensions:
DIM A(49, 49) ' 50 × 50 = 2,500 elements (12.5KB)
Two-dimensional arrays grow quadratically. A 100×100 array has 10,000 elements. A 200×200 array has 40,000 elements. Plan sizes carefully to avoid OUT OF MEMORY errors.
The DATA Statement
The DATA statement embeds constant values directly in your program. It's a convenient way to initialize arrays, create lookup tables, or store configuration data without prompting the user for input.
Basic Syntax
DATA value1, value2, value3, ...
Examples:
DATA 10, 20, 30, 40, 50
DATA "ALICE", "BOB", "CHARLIE"
DATA 3.14159, 2.71828, 1.41421
DATA statements store values in a program-wide list. You access these values sequentially with the READ statement (covered next).
Multiple DATA Statements
You can have multiple DATA statements anywhere in your program:
10 DATA 1, 2, 3
20 DATA 4, 5, 6
100 DATA 7, 8, 9
BASIC treats all DATA statements as a single continuous list: 1, 2, 3, 4, 5, 6, 7, 8, 9. The line numbers don't matter—DATA is read in program order (lowest line number to highest).
Data Types in DATA
DATA can contain:
- Numeric values: 10, -5, 3.14, 1.5E-3
- String values: "HELLO", "ALICE", "123"
- Mixed types: DATA 10, "HELLO", 3.14
When using mixed types, ensure your READ statements match the data type order.
DATA Placement
DATA statements can appear anywhere in your program:
10 PRINT "SETUP"
20 DATA 1, 2, 3
30 PRINT "PROCESSING"
40 DATA 4, 5, 6
Common conventions:
- Beginning: DATA statements before main program logic
- End: DATA statements after program end (after line 9999 or at high line numbers)
- Grouped: Related DATA statements together
Most programmers put DATA at the end for clarity—it separates data from logic.
String Data Gotcha
String data in DATA statements doesn't require quotes unless the string contains commas or leading/trailing spaces:
DATA HELLO, WORLD ' Two strings: "HELLO" and "WORLD"
DATA "HELLO, WORLD" ' One string: "HELLO, WORLD"
DATA HELLO WORLD ' One string: "HELLO WORLD" (no comma)
If your string contains:
- Commas: Use quotes
- Leading/trailing spaces: Use quotes
- Just letters/numbers: Quotes optional
Best practice: always quote strings in DATA for consistency.
Example: Embedding Configuration
<BasicCode>
10 PRINT "GAME CONFIGURATION"
20 READ MAXLIVES, STARTLEVEL, DIFFICULTY$
30 PRINT "MAX LIVES: "; MAXLIVES
40 PRINT "START LEVEL: "; STARTLEVEL
50 PRINT "DIFFICULTY: "; DIFFICULTY$
60 DATA 3, 1, "HARD"
</BasicCode>
Example: Color Names
10 DIM COLORS$(7)
20 FOR I = 0 TO 7
30 READ COLORS$(I)
40 NEXT I
50 PRINT "COLORS: ";
60 FOR I = 0 TO 7
70 PRINT COLORS$(I); " ";
80 NEXT I
90 DATA "RED", "ORANGE", "YELLOW", "GREEN"
100 DATA "BLUE", "INDIGO", "VIOLET", "WHITE"
Notice: DATA split across two lines (lines 90-100) but accessed as one continuous list.
Reading Data with READ
The READ statement extracts values from DATA statements and stores them in variables. READ works sequentially—each READ gets the next value from the DATA list.
Basic Syntax
READ variable
Examples:
READ A ' Read next value into A
READ NAME$ ' Read next value into NAME$
READ X, Y, Z ' Read three values
READ advances an internal data pointer that tracks the current position in the DATA list. First READ gets the first DATA value, second READ gets the second value, and so on.
Sequential Access
READ processes DATA values in order:
10 READ A
20 READ B
30 READ C
40 PRINT A, B, C
50 DATA 10, 20, 30
Output: 10 20 30
Each READ consumes one value from the DATA list. The pointer advances automatically.
Multiple Variables in READ
Read multiple values in one statement:
10 READ A, B, C
20 PRINT A, B, C
30 DATA 10, 20, 30
This is equivalent to three separate READ statements but more concise. Useful for related values.
Type Matching
READ variables must match DATA types:
10 READ A, B$
20 PRINT A, B$
30 DATA 10, "HELLO" ' OK: number then string
Mismatched types cause errors:
10 READ A$
20 DATA 10 ' Error: reading string, got number
BASIC attempts type conversion but not always successfully. Best practice: match READ variable types to DATA values.
Loop Pattern for Arrays
The standard pattern for filling an array from DATA:
DIM A(N)
FOR I = 0 TO N
READ A(I)
NEXT I
DATA ...
Example:
<BasicCode>
10 PRINT "ARRAY FROM DATA"
20 DIM SCORES(4)
30 FOR I = 0 TO 4
40 READ SCORES(I)
50 NEXT I
60 PRINT "SCORES: ";
70 FOR I = 0 TO 4
80 PRINT SCORES(I); " ";
90 NEXT I
100 DATA 85, 92, 78, 88, 95
</BasicCode>
OUT OF DATA Error
Reading beyond available DATA causes ?OUT OF DATA ERROR:
10 READ A, B, C
20 DATA 10, 20 ' Only 2 values, need 3
RUN
?OUT OF DATA ERROR
Ensure DATA contains enough values for all READ statements. Count carefully!
Example: Menu Options
<BasicCode>
10 PRINT "MAIN MENU"
20 FOR I = 1 TO 4
30 READ OPTION$
40 PRINT I; ") "; OPTION$
50 NEXT I
60 DATA "PLAY GAME", "HIGH SCORES"
70 DATA "SETTINGS", "QUIT"
</BasicCode>
Resetting with RESTORE
The RESTORE statement resets the DATA pointer to the beginning of the DATA list, allowing you to re-read DATA values. This is useful for multiple passes through the same data or restarting a data sequence.
Basic RESTORE
RESTORE
RESTORE (without parameters) resets the pointer to the first DATA statement in your program:
10 READ A
20 PRINT "FIRST READ: "; A
30 RESTORE
40 READ B
50 PRINT "AFTER RESTORE: "; B
60 DATA 10, 20, 30
Output:
FIRST READ: 10
AFTER RESTORE: 10
Both READ statements get the value 10 because RESTORE reset the pointer to the start.
RESTORE with Line Number
You can RESTORE to a specific DATA statement:
RESTORE linenumber
The pointer jumps to the DATA statement at the specified line:
10 RESTORE 100
20 READ A
30 PRINT A
40 DATA 10, 20, 30
100 DATA 40, 50, 60
Output: 40 (first value from line 100's DATA)
This enables multiple data sets in one program—RESTORE to different line numbers to switch between data sets.
Multiple Data Sets Example
<BasicCode>
10 PRINT "RESTORE DEMO: MULTIPLE DATA SETS"
20 PRINT "SET 1:"
30 RESTORE 100
40 FOR I = 1 TO 3
50 READ A
60 PRINT A; " ";
70 NEXT I
80 PRINT ""
90 PRINT "SET 2:"
95 RESTORE 200
100 FOR I = 1 TO 3
110 READ A
120 PRINT A; " ";
130 NEXT I
140 PRINT ""
150 DATA 10, 20, 30
200 DATA 40, 50, 60
</BasicCode>
Note: Line 150 is ignored because we explicitly RESTORE to lines 100 and 200.
Re-Reading Data
RESTORE enables multiple passes through the same data:
10 DIM A(4)
20 PRINT "FIRST PASS:"
30 FOR I = 0 TO 4
40 READ A(I)
50 PRINT A(I); " ";
60 NEXT I
70 PRINT ""
80 RESTORE
90 PRINT "SECOND PASS:"
100 FOR I = 0 TO 4
110 READ A(I)
120 A(I) = A(I) * 2
130 PRINT A(I); " ";
140 NEXT I
150 DATA 1, 2, 3, 4, 5
Output:
FIRST PASS: 1 2 3 4 5
SECOND PASS: 2 4 6 8 10
When to Use RESTORE
Use RESTORE when:
- Multiple passes: Process same data repeatedly
- Data sets: Switch between different data groups
- Reset after partial read: Start over mid-program
- User-driven re-read: Let user repeat operations
Common pattern: Menu system with multiple DATA sets for different menu levels, RESTORE to jump between them.
RESTORE with an invalid line number (no DATA at that line) doesn't cause an immediate error—it restores to the start. But the next READ may produce unexpected results. Always RESTORE to lines containing DATA statements.
Practical Array Applications
Arrays enable powerful programming patterns. This section demonstrates practical applications: sorting, searching, and statistics.
Bubble Sort
Sort an array from smallest to largest using the bubble sort algorithm:
<BasicCode>
10 PRINT "BUBBLE SORT DEMO"
20 DIM A(9)
30 PRINT "UNSORTED:"
40 FOR I = 0 TO 9
50 A(I) = INT(RND(1) * 100)
60 PRINT A(I); " ";
70 NEXT I
80 PRINT ""
90 REM BUBBLE SORT
100 FOR I = 0 TO 8
110 FOR J = 0 TO 8 - I
120 IF A(J) > A(J + 1) THEN TEMP = A(J): A(J) = A(J + 1): A(J + 1) = TEMP
130 NEXT J
140 NEXT I
150 PRINT "SORTED:"
160 FOR I = 0 TO 9
170 PRINT A(I); " ";
180 NEXT I
</BasicCode>
The algorithm: Compare adjacent elements, swap if out of order, repeat until sorted.
Linear Search
Find an element in an array:
<BasicCode>
10 PRINT "LINEAR SEARCH DEMO"
20 DIM A(9)
30 FOR I = 0 TO 9
40 A(I) = I * 10
50 NEXT I
60 PRINT "ARRAY: ";
70 FOR I = 0 TO 9
80 PRINT A(I); " ";
90 NEXT I
100 PRINT ""
110 INPUT "SEARCH FOR"; TARGET
120 FOUND = -1
130 FOR I = 0 TO 9
140 IF A(I) = TARGET THEN FOUND = I: I = 9
150 NEXT I
160 IF FOUND >= 0 THEN PRINT "FOUND AT INDEX "; FOUND ELSE PRINT "NOT FOUND"
</BasicCode>
Statistics: Mean, Max, Min
Calculate statistics from array data:
<BasicCode>
10 PRINT "STATISTICS CALCULATOR"
20 DIM DATA(9)
30 PRINT "DATA:"
40 TOTAL = 0
50 FOR I = 0 TO 9
60 READ DATA(I)
70 PRINT DATA(I); " ";
80 TOTAL = TOTAL + DATA(I)
90 NEXT I
100 MEAN = TOTAL / 10
110 PRINT ""
120 MINVAL = DATA(0)
130 MAXVAL = DATA(0)
140 FOR I = 1 TO 9
150 IF DATA(I) < MINVAL THEN MINVAL = DATA(I)
160 IF DATA(I) > MAXVAL THEN MAXVAL = DATA(I)
170 NEXT I
180 PRINT "MEAN: "; MEAN
190 PRINT "MIN: "; MINVAL
200 PRINT "MAX: "; MAXVAL
210 DATA 23, 45, 12, 67, 89, 34, 56, 78, 90, 11
</BasicCode>
Histogram
Count occurrences of values:
10 DIM COUNTS(9)
20 REM Initialize counts to 0
30 FOR I = 0 TO 9
40 COUNTS(I) = 0
50 NEXT I
60 REM Count random digits
70 FOR I = 1 TO 100
80 DIGIT = INT(RND(1) * 10)
90 COUNTS(DIGIT) = COUNTS(DIGIT) + 1
100 NEXT I
110 REM Display histogram
120 PRINT "DIGIT COUNT"
130 FOR I = 0 TO 9
140 PRINT I; TAB(6); COUNTS(I)
150 NEXT I
Lookup Table
Use arrays for fast lookups (e.g., month names):
10 DIM MONTHS$(11)
20 FOR I = 0 TO 11
30 READ MONTHS$(I)
40 NEXT I
50 INPUT "ENTER MONTH (0-11)"; M
60 IF M < 0 OR M > 11 THEN PRINT "INVALID": END
70 PRINT "MONTH: "; MONTHS$(M)
80 DATA "JAN", "FEB", "MAR", "APR", "MAY", "JUN"
90 DATA "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"
Common Array Mistakes
Arrays introduce new error patterns. Avoid these common pitfalls:
Mistake 1: Forgetting Zero-Based Index
DIM A(10)
FOR I = 1 TO 10 ' Skips A(0)
A(I) = I
NEXT I
Solution: Loop from 0 to N: FOR I = 0 TO 10
Mistake 2: Off-By-One in Loop
DIM A(10)
FOR I = 0 TO 11 ' Error: 11 > 10
A(I) = I
NEXT I
Solution: Loop to DIM size exactly: FOR I = 0 TO 10
Mistake 3: Forgetting DIM
A(50) = 100 ' Error if A not DIMmed (default is 0-10)
Solution: Always DIM before use, even if size ≤ 11
Mistake 4: Re-DIMming
DIM A(10)
DIM A(20) ' Error: REDIM'D ARRAY
Solution: DIM once only; use CLR to clear and re-DIM
Mistake 5: Type Mismatch in Arrays
DIM A$(10)
A$(0) = 100 ' Error: number to string array
Solution: Match types (use A$(0) = "100" or DIM A(10))
Mistake 6: Subscript Out of Range
DIM A(10)
A(15) = 100 ' Error: 15 > 10
Solution: Check loop bounds; ensure indices ≤ DIM size
Mistake 7: Mixing 1D and 2D Syntax
DIM A(10, 10)
PRINT A(5) ' Error: need two indices
Solution: Use A(5, 5) for 2D arrays
Mistake 8: OUT OF DATA Error
FOR I = 0 TO 10
READ A(I) ' Reads 11 values
NEXT I
DATA 1, 2, 3 ' Only 3 values!
Solution: Count DATA values; ensure enough for all READs
?SUBSCRIPT OUT OF RANGE ERROR is the most common array error. Always verify loop bounds match array dimensions. Use DIM size as loop limit: FOR I = 0 TO N where DIM A(N).
Summary
Arrays organise related data into numbered collections, enabling powerful programming patterns. This chapter covered:
- What arrays are: Numbered storage boxes, indexed by position
- DIM statement: Declares array size (DIM A(N) = N+1 elements)
- Zero-based indexing: Arrays start at index 0, run to DIM size
- One-dimensional arrays: Lists indexed by single number
- Two-dimensional arrays: Tables indexed by row and column
- DATA statement: Embeds constant values in program
- READ statement: Extracts values from DATA sequentially
- RESTORE statement: Resets DATA pointer (with optional line number)
- Practical applications: Sorting, searching, statistics, lookup tables
Key takeaways:
- Always DIM arrays explicitly: Prevents subscript errors, documents size
- Remember zero-based indexing: Loop from 0 to N, not 1 to N
- Match types: Array type (%, $) must match element type
- Count DATA carefully: Ensure enough values for all READs
- Use arrays for collections: Whenever you have related data, use an array instead of separate variables
- Loop patterns are standard: FOR I = 0 TO N processes every element
- 2D arrays for grids: Natural model for tables, boards, matrices
Arrays transform BASIC from a calculator into a data processing powerhouse. Combined with loops (Chapter 7) and functions (Chapter 10), arrays enable sophisticated programs: games with state, data analysis, simulations, and more.
Master arrays to unlock BASIC's full potential. Practice with the examples, modify them, create your own. Arrays are fundamental—every significant BASIC program uses them.
End of Chapter 9
Proceed to Chapter 10: Built-in Functions to learn mathematical, string, and system functions that operate on variables and array elements.
Built-in Functions
Introduction to Functions
Functions are pre-written pieces of code that perform specific calculations and return a result. Unlike statements that perform actions (PRINT, GOTO), functions compute values that you use in expressions.
Functions always appear on the right side of assignments or inside other expressions:
X = SQR(16) ← Function call
PRINT ABS(-5) ← Function inside PRINT
IF LEN(N$) > 10 THEN ← Function in condition
Functions take parameters (inputs) in parentheses and return a single value. Some functions work with numbers (INT, SQR), others with strings (LEFT$, LEN), and some query system state (FRE, POS).
Function naming convention: String functions end with $ (LEFT$, CHR$), numeric functions don't (ABS, SIN). This matches the type of value they return.
All functions are read-only—they calculate results without changing your program's state (except RND, which advances the random number generator).
Mathematical Functions
ABS(x) - Absolute Value
Returns the absolute value of a number (distance from zero, always positive).
Syntax: ABS(expression)
Parameters:
expression- Any numeric value (integer or floating-point)
Returns: Non-negative number of same type as input
Examples:
PRINT ABS(5)
5
PRINT ABS(-5)
5
PRINT ABS(-3.14159)
3.14159
PRINT ABS(0)
0
X = -100
PRINT ABS(X)
100
PRINT ABS(10-20)
10
READY.
Common uses:
- Distance calculations
- Error magnitude (ignoring sign)
- Checking if values are close:
IF ABS(A-B) < 0.001 THEN
INT(x) - Integer Part
Returns the largest integer less than or equal to x (floor function). This rounds down toward negative infinity.
Syntax: INT(expression)
Parameters:
expression- Any numeric value
Returns: Integer value (technically still floating-point type, but whole number)
Examples:
PRINT INT(3.7)
3
PRINT INT(3.2)
3
PRINT INT(-2.3)
-3
PRINT INT(-2.9)
-3
PRINT INT(5)
5
X = 7.9999
PRINT INT(X)
7
READY.
Important: INT rounds toward negative infinity, not toward zero:
INT(2.9) = 2(correct)INT(-2.9) = -3(not -2!)
Rounding to nearest integer:
REM ROUND TO NEAREST INTEGER
X = 3.7
PRINT INT(X + 0.5)
4
X = 3.2
PRINT INT(X + 0.5)
3
X = -2.7
PRINT INT(X + 0.5)
-2
READY.
Common uses:
- Extracting whole numbers from calculations
- Rounding (with offset)
- Generating random integers:
INT(RND(1)*10)
SGN(x) - Sign
Returns the sign of a number: -1 for negative, 0 for zero, +1 for positive.
Syntax: SGN(expression)
Parameters:
expression- Any numeric value
Returns: -1, 0, or 1
Examples:
PRINT SGN(100)
1
PRINT SGN(-50)
-1
PRINT SGN(0)
0
PRINT SGN(0.001)
1
PRINT SGN(-0.001)
-1
X = 10-20
PRINT SGN(X)
-1
READY.
Common uses:
- Direction indicators
- Normalizing values to unit sign
- Checking positive/negative in conditional logic
Practical example:
10 REM TEMPERATURE CHANGE INDICATOR
20 INPUT "YESTERDAY TEMP"; Y
30 INPUT "TODAY TEMP"; T
40 D = SGN(T-Y)
50 IF D=1 THEN PRINT "WARMER"
60 IF D=-1 THEN PRINT "COOLER"
70 IF D=0 THEN PRINT "SAME"
LIST
RUN
YESTERDAY TEMP? 72
TODAY TEMP? 68
COOLER
READY.
SQR(x) - Square Root
Returns the square root of a non-negative number.
Syntax: SQR(expression)
Parameters:
expression- Non-negative numeric value
Returns: Square root (floating-point)
Error: ?ILLEGAL QUANTITY ERROR if x < 0
Examples:
PRINT SQR(16)
4
PRINT SQR(2)
1.41421356
PRINT SQR(100)
10
PRINT SQR(0)
0
PRINT SQR(0.25)
0.5
X = 49
PRINT SQR(X)
7
READY.
Distance formula (Pythagorean theorem):
10 REM DISTANCE BETWEEN TWO POINTS
20 INPUT "X1,Y1"; X1,Y1
30 INPUT "X2,Y2"; X2,Y2
40 DX = X2-X1
50 DY = Y2-Y1
60 D = SQR(DX*DX + DY*DY)
70 PRINT "DISTANCE ="; D
LIST
RUN
X1,Y1? 0,0
X2,Y2? 3,4
DISTANCE = 5
READY.
Common uses:
- Geometry calculations
- Physics equations
- Standard deviation and statistics
- Normalizing vectors
LOG(x) - Natural Logarithm
Returns the natural logarithm (base e) of a positive number.
Syntax: LOG(expression)
Parameters:
expression- Positive numeric value (x > 0)
Returns: Natural log (floating-point)
Error: ?ILLEGAL QUANTITY ERROR if x ≤ 0
Examples:
PRINT LOG(1)
0
PRINT LOG(2.71828)
1
PRINT LOG(10)
2.30258509
PRINT LOG(100)
4.60517019
X = 7.389
PRINT LOG(X)
2.00001629
READY.
Converting to other bases:
10 REM LOG BASE 10 CONVERTER
20 X = 1000
30 LOG10 = LOG(X)/LOG(10)
40 PRINT "LOG10("; X; ") ="; LOG10
RUN
LOG10( 1000 ) = 3
READY.
Common uses:
- Scientific calculations
- Exponential decay/growth
- Converting between logarithm bases:
LOGB(X) = LOG(X)/LOG(B) - Sound intensity (decibels)
EXP(x) - Exponential
Returns e raised to the power of x (e^x where e ≈ 2.71828).
Syntax: EXP(expression)
Parameters:
expression- Any numeric value
Returns: e^x (floating-point)
Note: Result can overflow for large values (x > 88)
Examples:
PRINT EXP(0)
1
PRINT EXP(1)
2.71828183
PRINT EXP(2)
7.3890561
PRINT EXP(-1)
0.367879441
X = 3
PRINT EXP(X)
20.0855369
READY.
Relationship with LOG:
X = 5
PRINT EXP(LOG(X))
5
Y = EXP(2)
PRINT LOG(Y)
2
READY.
Exponential growth model:
10 REM COMPOUND INTEREST
20 P = 1000: REM PRINCIPAL
30 R = 0.05: REM 5% RATE
40 T = 10: REM YEARS
50 A = P * EXP(R*T)
60 PRINT "AMOUNT: $"; INT(A*100+0.5)/100
RUN
AMOUNT: $ 1648.72
READY.
Common uses:
- Exponential growth/decay
- Continuous compounding
- Normal distribution calculations
- Physics (radioactive decay)
RND(x) - Random Number
Returns a pseudo-random number between 0 (inclusive) and 1 (exclusive).
Syntax: RND(expression)
Parameters:
x > 0- Generate next random number (most common: useRND(1))x = 0- Repeat last random number generatedx < 0- Seed generator with x (same seed = same sequence)
Returns: Random value in range [0, 1)
Examples:
PRINT RND(1)
0.737927713
PRINT RND(1)
0.293746442
PRINT RND(1)
0.629374802
PRINT RND(0)
0.629374802
PRINT RND(0)
0.629374802
READY.
Seeding the generator:
REM SEED WITH -1
X = RND(-1)
PRINT RND(1)
0.185032621
PRINT RND(1)
0.842648298
REM SEED AGAIN WITH -1
X = RND(-1)
PRINT RND(1)
0.185032621
PRINT RND(1)
0.842648298
READY.
Generating random integers (dice, cards, etc.):
10 REM ROLL A 6-SIDED DIE
20 FOR I=1 TO 10
30 ROLL = INT(RND(1)*6)+1
40 PRINT ROLL;
50 NEXT I
RUN
3 1 6 2 5 4 6 1 2 3
READY.
Random number in range [MIN, MAX]:
10 REM RANDOM NUMBER BETWEEN 10 AND 20
20 MIN=10: MAX=20
30 FOR I=1 TO 5
40 R = INT(RND(1)*(MAX-MIN+1))+MIN
50 PRINT R;
60 NEXT I
RUN
17 12 19 14 16
READY.
Practical dice roller:
10 REM DICE ROLLER
20 INPUT "HOW MANY DICE"; N
30 T=0
40 FOR I=1 TO N
50 D=INT(RND(1)*6)+1
60 PRINT "DIE"; I; ":"; D
70 T=T+D
80 NEXT I
90 PRINT "TOTAL:"; T
LIST
RUN
HOW MANY DICE? 3
DIE 1 : 4
DIE 2 : 2
DIE 3 : 6
TOTAL: 12
READY.
Common uses:
- Games (dice, card shuffling)
- Simulations
- Random sampling
- Procedural generation
Trigonometric Functions
All trigonometric functions work in radians, not degrees.
Degree/Radian conversion:
- Radians to degrees:
DEGREES = RADIANS * 180 / PI - Degrees to radians:
RADIANS = DEGREES * PI / 180 - Pi constant:
PI = 3.14159265
SIN(x) - Sine
Returns the sine of an angle (in radians).
Syntax: SIN(expression)
Parameters:
expression- Angle in radians
Returns: Sine value in range [-1, 1]
Examples:
PRINT SIN(0)
0
PI = 3.14159265
PRINT SIN(PI/2)
1
PRINT SIN(PI)
-8.74227766E-08
PRINT SIN(PI*2)
-1.74845553E-07
PRINT SIN(-PI/2)
-1
READY.
Working with degrees:
10 REM SINE IN DEGREES
20 PI = 3.14159265
30 DEF FN RAD(D) = D*PI/180
40 INPUT "ANGLE IN DEGREES"; A
50 PRINT "SIN("; A; ") ="; SIN(FN RAD(A))
LIST
RUN
ANGLE IN DEGREES? 30
SIN( 30 ) = 0.5
RUN
ANGLE IN DEGREES? 90
SIN( 90 ) = 1
READY.
COS(x) - Cosine
Returns the cosine of an angle (in radians).
Syntax: COS(expression)
Parameters:
expression- Angle in radians
Returns: Cosine value in range [-1, 1]
Examples:
PRINT COS(0)
1
PI = 3.14159265
PRINT COS(PI/2)
-4.37113883E-08
PRINT COS(PI)
-1
PRINT COS(PI*2)
1
READY.
TAN(x) - Tangent
Returns the tangent of an angle (in radians).
Syntax: TAN(expression)
Parameters:
expression- Angle in radians
Returns: Tangent value (can be very large near π/2)
Examples:
PRINT TAN(0)
0
PI = 3.14159265
PRINT TAN(PI/4)
1
PRINT TAN(PI/6)
0.577350269
PRINT TAN(-PI/4)
-1
READY.
ATN(x) - Arctangent
Returns the arctangent (inverse tangent) of a number, in radians.
Syntax: ATN(expression)
Parameters:
expression- Any numeric value
Returns: Angle in radians, range (-π/2, π/2)
Examples:
PRINT ATN(0)
0
PRINT ATN(1)
0.785398163
PI = 3.14159265
PRINT ATN(1)*4
3.14159265
PRINT ATN(1000000)
1.5707953
READY.
Calculating Pi:
10 REM CALCULATE PI USING ATN
20 PI = ATN(1)*4
30 PRINT "PI ="; PI
RUN
PI = 3.14159265
READY.
Complete trigonometry example (right triangle solver):
10 REM RIGHT TRIANGLE SOLVER
20 PI = 3.14159265
30 INPUT "ADJACENT SIDE"; A
40 INPUT "OPPOSITE SIDE"; O
50 H = SQR(A*A + O*O)
60 ANG = ATN(O/A) * 180/PI
70 PRINT "HYPOTENUSE ="; H
80 PRINT "ANGLE ="; INT(ANG*100+0.5)/100; "DEG"
LIST
RUN
ADJACENT SIDE? 3
OPPOSITE SIDE? 4
HYPOTENUSE = 5
ANGLE = 53.13 DEG
READY.
Polar to Cartesian conversion:
10 REM POLAR TO CARTESIAN
20 PI = 3.14159265
30 INPUT "RADIUS"; R
40 INPUT "ANGLE (DEGREES)"; D
50 A = D * PI/180
60 X = R * COS(A)
70 Y = R * SIN(A)
80 PRINT "X ="; X
90 PRINT "Y ="; Y
LIST
RUN
RADIUS? 10
ANGLE (DEGREES)? 45
X = 7.07106781
Y = 7.07106781
READY.
String Functions
String functions manipulate text. String variables end with $ suffix (N$, A$), and string functions return strings (LEFT$, CHR$) or numbers (LEN, ASC).
LEN(s$) - String Length
Returns the number of characters in a string.
Syntax: LEN(string$)
Parameters:
string$- Any string expression
Returns: Integer count of characters (0 to 255)
Examples:
PRINT LEN("HELLO")
5
PRINT LEN("")
0
A$ = "COMMODORE 64"
PRINT LEN(A$)
12
PRINT LEN(" SPACES ")
10
X$ = "ABC" + "DEF"
PRINT LEN(X$)
6
READY.
Validation example:
10 REM PASSWORD LENGTH CHECK
20 INPUT "ENTER PASSWORD"; P$
30 IF LEN(P$)<6 THEN PRINT "TOO SHORT": GOTO 20
40 IF LEN(P$)>20 THEN PRINT "TOO LONG": GOTO 20
50 PRINT "PASSWORD ACCEPTED"
LIST
RUN
ENTER PASSWORD? ABC
TOO SHORT
ENTER PASSWORD? MYPASSWORD
PASSWORD ACCEPTED
READY.
LEFT$(s$,n) - Left Substring
Returns the leftmost n characters of a string.
Syntax: LEFT$(string$, count)
Parameters:
string$- Source stringcount- Number of characters (0 to length)
Returns: Substring of leftmost characters
Examples:
PRINT LEFT$("HELLO",3)
HEL
PRINT LEFT$("BASIC",1)
B
A$ = "COMMODORE"
PRINT LEFT$(A$,4)
COMM
PRINT LEFT$("TEST",10)
TEST
PRINT LEFT$("WORD",0)
READY.
Truncation example:
10 REM TRUNCATE TO 10 CHARS
20 INPUT "NAME"; N$
30 IF LEN(N$)>10 THEN N$=LEFT$(N$,10)
40 PRINT "HELLO "; N$
LIST
RUN
NAME? CHRISTOPHER
HELLO CHRISTOPH
READY.
RIGHT$(s$,n) - Right Substring
Returns the rightmost n characters of a string.
Syntax: RIGHT$(string$, count)
Parameters:
string$- Source stringcount- Number of characters (0 to length)
Returns: Substring of rightmost characters
Examples:
PRINT RIGHT$("HELLO",3)
LLO
PRINT RIGHT$("BASIC",2)
IC
A$ = "FILENAME.BAS"
PRINT RIGHT$(A$,3)
BAS
PRINT RIGHT$("TEST",10)
TEST
READY.
File extension parser:
10 REM EXTRACT FILE EXTENSION
20 INPUT "FILENAME"; F$
30 E$ = RIGHT$(F$,3)
40 IF E$="BAS" THEN PRINT "BASIC PROGRAM"
50 IF E$="TXT" THEN PRINT "TEXT FILE"
60 IF E$="DAT" THEN PRINT "DATA FILE"
LIST
RUN
FILENAME? GAME.BAS
BASIC PROGRAM
READY.
MID$(s$,start[,length]) - Middle Substring
Returns a substring starting at a specified position.
Syntax:
MID$(string$, start)- From start to endMID$(string$, start, length)- Specific length
Parameters:
string$- Source stringstart- Starting position (1-based, first char is 1)length- Optional, number of characters to extract
Returns: Substring from specified position
Examples:
PRINT MID$("HELLO",2,3)
ELL
PRINT MID$("COMMODORE",4,3)
MOD
PRINT MID$("BASIC",2)
ASIC
A$ = "123-456-7890"
PRINT MID$(A$,5,3)
456
PRINT MID$("TEST",1,1)
T
READY.
String parsing example:
10 REM PARSE DATE MM/DD/YYYY
20 INPUT "DATE (MM/DD/YYYY)"; D$
30 M$ = MID$(D$,1,2)
40 D$ = MID$(D$,4,2)
50 Y$ = MID$(D$,7,4)
60 PRINT "MONTH:"; M$
70 PRINT "DAY:"; D$
80 PRINT "YEAR:"; Y$
LIST
RUN
DATE (MM/DD/YYYY)? 03/15/1982
MONTH: 03
DAY: 15
YEAR: 1982
READY.
CHR$(n) - ASCII to Character
Converts an ASCII code number to its character.
Syntax: CHR$(code)
Parameters:
code- ASCII value (0 to 255)
Returns: Single-character string
Examples:
PRINT CHR$(65)
A
PRINT CHR$(97)
a
PRINT CHR$(48)
0
PRINT CHR$(32)
PRINT CHR$(72);CHR$(73);
HI
A = 65
PRINT CHR$(A); CHR$(A+1); CHR$(A+2)
ABC
READY.
Building strings from codes:
10 REM GENERATE ALPHABET
20 FOR I=65 TO 90
30 PRINT CHR$(I);
40 NEXT I
RUN
ABCDEFGHIJKLMNOPQRSTUVWXYZ
READY.
ASCII table reference (common characters):
32: Space 48-57: 0-9 65-90: A-Z 97-122: a-z
13: Return 10: Linefeed 8: Backspace 27: Escape
ASC(s$) - Character to ASCII
Returns the ASCII code of the first character in a string.
Syntax: ASC(string$)
Parameters:
string$- Non-empty string
Returns: ASCII value (0-255) of first character
Error: ?ILLEGAL QUANTITY ERROR if string is empty
Examples:
PRINT ASC("A")
65
PRINT ASC("HELLO")
72
PRINT ASC("a")
97
PRINT ASC("0")
48
PRINT ASC(" ")
32
READY.
Character classification:
10 REM CHARACTER TYPE CHECKER
20 INPUT "ENTER CHARACTER"; C$
30 IF C$="" THEN PRINT "EMPTY": GOTO 20
40 A = ASC(C$)
50 IF A>=48 AND A<=57 THEN PRINT "DIGIT"
60 IF A>=65 AND A<=90 THEN PRINT "UPPERCASE"
70 IF A>=97 AND A<=122 THEN PRINT "LOWERCASE"
LIST
RUN
ENTER CHARACTER? 5
DIGIT
RUN
ENTER CHARACTER? Z
UPPERCASE
READY.
Case conversion:
10 REM UPPERCASE CONVERTER
20 INPUT "TEXT"; T$
30 U$ = ""
40 FOR I=1 TO LEN(T$)
50 C$ = MID$(T$,I,1)
60 A = ASC(C$)
70 IF A>=97 AND A<=122 THEN A=A-32
80 U$ = U$ + CHR$(A)
90 NEXT I
100 PRINT U$
LIST
RUN
TEXT? Hello World
HELLO WORLD
READY.
STR$(n) - Number to String
Converts a number to its string representation.
Syntax: STR$(number)
Parameters:
number- Any numeric value
Returns: String representation (includes leading space for positive)
Examples:
PRINT STR$(123)
123
PRINT STR$(-456)
-456
X = 3.14159
PRINT STR$(X)
3.14159
PRINT "VALUE:" + STR$(100)
VALUE: 100
READY.
Note: Positive numbers have a leading space where the minus sign would go.
Removing leading space:
X = 42
S$ = STR$(X)
IF LEFT$(S$,1)=" " THEN S$=MID$(S$,2)
PRINT ">" + S$ + "<"
>42<
READY.
Concatenating numbers and strings:
10 REM SCORE DISPLAY
20 S=1000
30 L=3
40 M$ = "SCORE:" + STR$(S) + " LIVES:" + STR$(L)
50 PRINT M$
RUN
SCORE: 1000 LIVES: 3
READY.
VAL(s$) - String to Number
Converts a string to a numeric value. Parsing stops at first non-numeric character.
Syntax: VAL(string$)
Parameters:
string$- String containing numeric representation
Returns: Numeric value (0 if no valid number found)
Examples:
PRINT VAL("123")
123
PRINT VAL("-456")
-456
PRINT VAL("3.14159")
3.14159
PRINT VAL(" 42")
42
PRINT VAL("10ABC")
10
PRINT VAL("ABC")
0
READY.
Parsing user input:
10 REM CALCULATOR
20 INPUT "ENTER EXPRESSION (A+B)"; E$
30 FOR I=1 TO LEN(E$)
40 C$=MID$(E$,I,1)
50 IF C$="+" OR C$="-" OR C$="*" THEN 70
60 NEXT I
70 A=VAL(LEFT$(E$,I-1))
80 OP$=C$
90 B=VAL(MID$(E$,I+1))
100 IF OP$="+" THEN PRINT A+B
110 IF OP$="-" THEN PRINT A-B
120 IF OP$="*" THEN PRINT A*B
LIST
RUN
ENTER EXPRESSION (A+B)? 15+27
42
RUN
ENTER EXPRESSION (A+B)? 100-25
75
READY.
System Functions
System functions query the interpreter's state and environment.
FRE(0) - Free Memory
Returns the number of bytes of free memory available for program and variables.
Syntax: FRE(0) or FRE(dummy)
Parameters:
- Dummy parameter (by convention 0, value ignored)
Returns: Free memory in bytes
Examples:
PRINT FRE(0)
38911
10 DIM A(1000)
PRINT FRE(0)
34815
READY.
Memory monitoring:
10 REM MEMORY MONITOR
20 PRINT "FREE:"; FRE(0); "BYTES"
30 INPUT "ARRAY SIZE"; N
40 DIM A(N)
50 PRINT "USED:"; FRE(0); "BYTES"
LIST
RUN
FREE: 38911 BYTES
ARRAY SIZE? 500
USED: 36863 BYTES
READY.
Note: Values differ between C64 mode (38911 bytes) and VIC-20 mode (3583 bytes).
POS(0) - Cursor Position
Returns the current cursor column position (0-39 on C64, 0-21 on VIC-20).
Syntax: POS(0) or POS(dummy)
Parameters:
- Dummy parameter (by convention 0, value ignored)
Returns: Column position (0-based)
Examples:
PRINT POS(0)
0
PRINT "HELLO";
PRINT POS(0)
5
PRINT TAB(20); "X";
PRINT POS(0)
21
READY.
Formatted table with alignment:
10 REM ALIGNED TABLE
20 FOR I=1 TO 5
30 PRINT "ITEM"; I;
40 PRINT TAB(15); "VALUE"; I*10
50 NEXT I
LIST
RUN
ITEM 1 VALUE 10
ITEM 2 VALUE 20
ITEM 3 VALUE 30
ITEM 4 VALUE 40
ITEM 5 VALUE 50
READY.
PEEK(addr) - Read Memory
Reads a byte from a memory address in the 64KB simulated memory space.
Syntax: PEEK(address)
Parameters:
address- Memory address (0-65535)
Returns: Byte value at address (0-255)
Examples:
POKE 1024,65
PRINT PEEK(1024)
65
POKE 2000,123
X = PEEK(2000)
PRINT X
123
READY.
Memory inspection:
10 REM MEMORY HEX DUMP
20 INPUT "START ADDRESS"; A
30 FOR I=0 TO 15
40 V=PEEK(A+I)
50 PRINT V;
60 NEXT I
LIST
RUN
START ADDRESS? 1024
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
READY.
Note: SLP-BASIC uses simulated memory, not real hardware. PEEK/POKE are useful for data storage but don't access actual hardware registers.
User-Defined Functions with DEF FN
DEF FN allows you to create your own custom functions.
Syntax: DEF FN name(parameter) = expression
Naming rules:
- Function name must start with FN
- Followed by letter (FNA, FNX, FNCALC)
- Parameter name is a variable
Limitations:
- Single-line only - Expression must fit on one line
- Single parameter only
- Cannot call other DEF FN functions
- Cannot use IF, FOR, GOTO, etc. (expression only)
Examples:
DEF FN DOUBLE(X) = X*2
PRINT FN DOUBLE(5)
10
PRINT FN DOUBLE(3.5)
7
READY.
DEF FN SQU(X) = X*X
FOR I=1 TO 5
PRINT I; "SQUARED ="; FN SQU(I)
NEXT I
1 SQUARED = 1
2 SQUARED = 4
3 SQUARED = 9
4 SQUARED = 16
5 SQUARED = 25
READY.
Mathematical formulas:
10 REM TEMPERATURE CONVERTER
20 DEF FN C2F(C) = C*9/5+32
30 DEF FN F2C(F) = (F-32)*5/9
40 INPUT "CELSIUS"; C
50 PRINT C; "C ="; FN C2F(C); "F"
60 INPUT "FAHRENHEIT"; F
70 PRINT F; "F ="; FN F2C(F); "C"
LIST
RUN
CELSIUS? 0
0 C = 32 F
FAHRENHEIT? 212
212 F = 100 C
READY.
Complex expressions:
10 REM CIRCLE CALCULATIONS
20 PI = 3.14159265
30 DEF FN AREA(R) = PI*R*R
40 DEF FN CIRC(R) = 2*PI*R
50 INPUT "RADIUS"; R
60 PRINT "AREA:"; FN AREA(R)
70 PRINT "CIRCUMFERENCE:"; FN CIRC(R)
LIST
RUN
RADIUS? 5
AREA: 78.5398163
CIRCUMFERENCE: 31.4159265
READY.
Using with trigonometry:
10 REM DEGREE/RADIAN CONVERTERS
20 PI = 3.14159265
30 DEF FN RAD(D) = D*PI/180
40 DEF FN DEG(R) = R*180/PI
50 INPUT "DEGREES"; D
60 PRINT "SIN("; D; ") ="; SIN(FN RAD(D))
70 PRINT "COS("; D; ") ="; COS(FN RAD(D))
LIST
RUN
DEGREES? 45
SIN( 45 ) = 0.707106781
COS( 45 ) = 0.707106781
READY.
Common uses:
- Unit conversions (temperature, distance, weight)
- Mathematical formulas (area, volume)
- Physics equations
- Financial calculations
What you CANNOT do with DEF FN:
DEF FN BAD(X) = IF X>0 THEN X ELSE -X ← NO! Can't use IF
DEF FN BAD(X) = FN OTHER(X) ← NO! Can't call other FN
DEF FN BAD(X,Y) = X+Y ← NO! Single parameter only
For complex functions requiring multiple statements, use GOSUB subroutines instead.
Function Examples
Example 1: Scientific Calculator
10 REM SCIENTIFIC CALCULATOR
20 PI = 3.14159265
30 DEF FN RAD(D) = D*PI/180
40 PRINT "SCIENTIFIC CALCULATOR"
50 PRINT "1) SQUARE ROOT"
60 PRINT "2) SINE (DEGREES)"
70 PRINT "3) LOGARITHM"
80 PRINT "4) POWER"
90 INPUT "CHOICE"; C
100 IF C=1 THEN GOSUB 200
110 IF C=2 THEN GOSUB 300
120 IF C=3 THEN GOSUB 400
130 IF C=4 THEN GOSUB 500
140 GOTO 50
200 INPUT "NUMBER"; X
210 PRINT "SQRT("; X; ") ="; SQR(X)
220 RETURN
300 INPUT "ANGLE"; A
310 PRINT "SIN("; A; ") ="; SIN(FN RAD(A))
320 RETURN
400 INPUT "NUMBER"; X
410 IF X<=0 THEN PRINT "MUST BE >0": RETURN
420 PRINT "LOG("; X; ") ="; LOG(X)
430 RETURN
500 INPUT "BASE,EXPONENT"; B,E
510 PRINT B; "^"; E; "="; B^E
520 RETURN
LIST
RUN
SCIENTIFIC CALCULATOR
1) SQUARE ROOT
2) SINE (DEGREES)
3) LOGARITHM
4) POWER
CHOICE? 1
NUMBER? 144
SQRT( 144 ) = 12
1) SQUARE ROOT
2) SINE (DEGREES)
3) LOGARITHM
4) POWER
CHOICE? 2
ANGLE? 30
SIN( 30 ) = 0.5
READY.
Example 2: String Analyzer
10 REM STRING ANALYZER
20 INPUT "ENTER TEXT"; T$
30 PRINT "LENGTH:"; LEN(T$)
40 U=0: L=0: D=0: S=0
50 FOR I=1 TO LEN(T$)
60 C$=MID$(T$,I,1)
70 A=ASC(C$)
80 IF A>=65 AND A<=90 THEN U=U+1
90 IF A>=97 AND A<=122 THEN L=L+1
100 IF A>=48 AND A<=57 THEN D=D+1
110 IF A=32 THEN S=S+1
120 NEXT I
130 PRINT "UPPERCASE:"; U
140 PRINT "LOWERCASE:"; L
150 PRINT "DIGITS:"; D
160 PRINT "SPACES:"; S
LIST
RUN
ENTER TEXT? Hello World 123
LENGTH: 15
UPPERCASE: 1
LOWERCASE: 9
DIGITS: 3
SPACES: 2
READY.
Example 3: Random Statistics
10 REM RANDOM STATISTICS
20 INPUT "HOW MANY SAMPLES"; N
30 DIM R(N)
40 T=0
50 FOR I=1 TO N
60 R(I)=RND(1)
70 T=T+R(I)
80 NEXT I
90 M=T/N
100 PRINT "MEAN:"; M
110 V=0
120 FOR I=1 TO N
130 V=V+(R(I)-M)^2
140 NEXT I
150 V=V/N
160 SD=SQR(V)
170 PRINT "STD DEV:"; SD
180 PRINT
190 PRINT "FIRST 10 VALUES:"
200 FOR I=1 TO 10
210 PRINT R(I)
220 NEXT I
LIST
RUN
HOW MANY SAMPLES? 100
MEAN: 0.493846279
STD DEV: 0.289471236
FIRST 10 VALUES:
0.737927713
0.293746442
0.629374802
0.851930174
0.142756847
0.287461925
0.763847294
0.539281764
0.914738562
0.391847562
READY.
Example 4: Distance Calculator (Haversine Formula)
10 REM DISTANCE BETWEEN CITIES
20 REM HAVERSINE FORMULA
30 PI=3.14159265
40 DEF FN RAD(D)=D*PI/180
50 INPUT "LAT1,LON1"; LAT1,LON1
60 INPUT "LAT2,LON2"; LAT2,LON2
70 A1=FN RAD(LAT1)
80 A2=FN RAD(LAT2)
90 DA=FN RAD(LAT2-LAT1)
100 DO=FN RAD(LON2-LON1)
110 A=SIN(DA/2)^2
120 A=A+COS(A1)*COS(A2)*SIN(DO/2)^2
130 C=2*ATN(SQR(A)/SQR(1-A))
140 D=6371*C
150 PRINT "DISTANCE:"; INT(D); "KM"
LIST
RUN
LAT1,LON1? 40.7128,-74.0060
LAT2,LON2? 51.5074,-0.1278
DISTANCE: 5570 KM
READY.
Example 5: Number Guessing with Hints
10 REM NUMBER GUESSING GAME
20 N=INT(RND(1)*100)+1
30 T=0
40 PRINT "GUESS NUMBER 1-100"
50 INPUT G
60 T=T+1
70 D=ABS(N-G)
80 IF D=0 THEN 150
90 IF D<5 THEN PRINT "VERY HOT!": GOTO 50
100 IF D<10 THEN PRINT "HOT": GOTO 50
110 IF D<20 THEN PRINT "WARM": GOTO 50
120 IF D<30 THEN PRINT "COOL": GOTO 50
130 PRINT "COLD"
140 GOTO 50
150 PRINT "CORRECT IN"; T; "TRIES!"
LIST
RUN
GUESS NUMBER 1-100
? 50
WARM
? 60
COOL
? 55
HOT
? 57
VERY HOT!
? 58
CORRECT IN 5 TRIES!
READY.
Summary
Built-in functions are essential tools for computation:
Mathematical: ABS, INT, SGN, SQR, LOG, EXP, RND Trigonometric: SIN, COS, TAN, ATN (remember: radians!) String manipulation: LEN, LEFT$, RIGHT$, MID$ String conversion: CHR$, ASC, STR$, VAL System queries: FRE, POS, PEEK User-defined: DEF FN for custom formulas
Key concepts:
- Functions return values, statements perform actions
- Trigonometry uses radians (use DEF FN for degree conversion)
- INT rounds down, not toward zero
- RND(1) generates random, RND(-x) seeds generator
- String functions simplify text processing
- DEF FN limited to single-line expressions
Next chapter: Program Management - organizing and debugging your code.
End of Chapter 10
Program Management
You've written programs, entered lines, and seen your code execute. Now it's time to master the tools that every BASIC programmer uses dozens of times each session: commands for managing, viewing, running, and controlling programs.
This chapter covers the essential program management commands that transform BASIC from a simple calculator into a complete development environment. You'll learn how to clear memory safely, list program sections efficiently, run code from specific points, and control program flow. These tools are your constant companions throughout your programming journey.
By the end of this chapter, you'll work efficiently—navigating programs quickly, testing sections independently, and debugging with confidence. These aren't flashy features, but they're absolutely fundamental to productive programming.
Clearing Programs with NEW
The NEW command is both the simplest and the most dangerous command in BASIC. Type three letters, press ENTER, and everything disappears—your entire program and all variables vanish instantly.
What NEW Does
NEW completely resets BASIC to a clean slate:
NEW
In one atomic operation:
- Deletes all program lines — Every line, from first to last
- Clears all variables — Numeric, integer, and string variables all gone
- Resets program state — No execution history remains
- Returns to ready state — The
READY.prompt appears
CODE_FENCE_0
The program is gone. Completely. Forever.
When to Use NEW
Use NEW at the start of each new programming project:
- Beginning a new session — Clear out old experiments
- Starting a different program — When you're completely done with current code
- After loading a program — Actually,
LOADdoesNEWautomatically (see Chapter 12) - When everything is broken — Nuclear option: start completely fresh
CRITICAL: NEW is permanent and immediate. There is:
- No "Are you sure?" prompt
- No undo command
- No recovery mechanism
- No way to retrieve your program
Once you press ENTER after typing NEW, your program is gone forever—unless you saved it first.
Safe NEW Workflow
Experienced programmers follow this pattern:
LIST (Review what you have)
(Is this program important?)
(If yes: SAVE "MYPROGRAM" — See Chapter 12)
(If no: continue)
NEW (Clear memory)
LIST (Verify clean slate)
(Start entering new program)
Get in the habit: if you spent more than a few minutes on a program, SAVE it before using NEW. You'll learn SAVE in Chapter 12, but remember this now: good programmers save frequently and never trust NEW around unsaved work.
NEW vs. Other Commands
Compare NEW to similar operations:
| Command | Program Lines | Variables | Use Case |
|---|---|---|---|
NEW |
Deleted | Cleared | Start completely fresh |
CLR |
Preserved | Cleared | Reset variables only |
RUN |
Preserved | Preserved | Just execute program |
NEW is the most destructive. Use it only when you truly want to discard everything.
10 PRINT "THIS PROGRAM WILL BE DELETED"
20 A = 42
30 PRINT "A ="; A
40 END
Try this sequence:
RUNto see the program executePRINT Ato see the variable (42)NEWto clear everythingLIST(nothing appears)PRINT A(gives 0—variable is gone)
Listing Programs with LIST
The LIST command is your window into program memory. It displays your code, formatted and organised, so you can see what BASIC has stored. Mastering LIST variations makes navigating programs effortless.
LIST (Display Everything)
The simplest form shows your entire program:
LIST
BASIC displays every line from lowest to highest line number, each on its own line.
CODE_FENCE_0
This is the most common form—use it constantly while developing programs.
LIST n (Display One Line)
To examine a single line, specify its number:
LIST 30
CODE_FENCE_0
Perfect for checking the exact contents of a specific line without scrolling through your entire program.
LIST n-m (Display a Range)
To see consecutive lines, specify a range:
LIST 20-40
CODE_FENCE_0
The format is start-end. BASIC displays all lines from start through end, inclusive. Both boundaries must exist as line numbers or be close to existing lines.
LIST -n (From Beginning to Line n)
To see everything up to a specific line:
LIST -30
CODE_FENCE_0
Note the hyphen before the number. This shows line 30 and everything preceding it.
LIST n- (From Line n to End)
To see everything from a specific line onward:
LIST 30-
CODE_FENCE_0
Note the hyphen after the number. This shows line 30 and everything following it.
When to Use Each Form
| Command | Shows | Best For |
|---|---|---|
LIST |
Everything | General review, small programs |
LIST 50 |
Line 50 only | Checking specific line contents |
LIST 10-50 |
Lines 10 through 50 | Reviewing a section or subroutine |
LIST -50 |
Start through line 50 | Seeing initialization code |
LIST 900- |
Line 900 to end | Viewing subroutines at program end |
For long programs (100+ lines):
- Use
LIST -50to see initialization - Use
LIST 100-200to see main loop - Use
LIST 900-to see subroutines - Avoid
LISTalone—too much scrolling!
10 REM PROGRAM START
20 PRINT "INITIALIZING..."
30 A = 0: B = 0
40 REM MAIN LOOP
50 FOR I = 1 TO 10
60 A = A + I
70 B = B + I * 2
80 NEXT I
90 REM DISPLAY RESULTS
100 PRINT "SUM:"; A
110 PRINT "DOUBLE SUM:"; B
120 END
Practice all LIST variations:
LISTshows everythingLIST 50shows just the FOR lineLIST 40-80shows the main loop sectionLIST -40shows initializationLIST 90-shows results section
Running Programs with RUN
The RUN command executes your program. You've used it before, but RUN has capabilities beyond simple execution—you can start from any line number.
RUN (Execute from Beginning)
The basic form starts at the lowest line number:
RUN
BASIC immediately:
- Clears all variables (fresh start)
- Jumps to the lowest line number
- Executes lines sequentially
- Continues until
ENDor program runs out of lines - Returns to
READY.prompt
CODE_FENCE_0
RUN Clears Variables
Important: RUN always clears all variables before execution, even if you've set them in immediate mode:
CODE_FENCE_0
The A = 99 from immediate mode is gone—RUN cleared it. This ensures programs start with a clean variable state every time.
RUN n (Execute from Line n)
You can start execution at any line number:
RUN 50
BASIC:
- Clears all variables (same as
RUN) - Jumps directly to line 50
- Executes from there to the end
CODE_FENCE_0
Notice A = 0 because we skipped line 20 which sets A = 100.
When to Use RUN n
RUN n is invaluable for testing:
Testing specific sections:
(Skip initialization, test main logic)
RUN 100
Testing subroutines in isolation:
(Jump directly to subroutine)
RUN 900
GOSUB 1000
END
Debugging:
(Problem seems to be after line 200)
RUN 200
(Now you can focus on that section)
RUN 50 starts at line 50. Lines before 50 never execute. If those lines initialized variables or set up data, that setup is skipped—variables start at 0 or empty strings.
Only use RUN n when you understand which initialization code you're bypassing!
RUN vs. GOTO
Don't confuse these:
- RUN — Clears variables, starts fresh (use from immediate mode)
- GOTO — Jumps to a line, keeps variables (use within programs)
RUN 100 (From immediate mode: clear vars, start at 100)
10 GOTO 100 (Within program: jump to 100, keep vars)
10 PRINT "SECTION 1: INITIALIZATION"
20 A = 50
30 B$ = "HELLO"
40 PRINT "A ="; A; " B$ ="; B$
50 PRINT
60 PRINT "SECTION 2: MAIN PROGRAM"
70 PRINT "A * 2 ="; A * 2
80 PRINT "MESSAGE:"; B$
90 END
Try these commands:
RUN(executes from line 10, A = 50)RUN 60(executes from line 60, A = 0 because we skipped initialization!)- Notice how
RUN 60showsA * 2 = 0andMESSAGE:is empty
Program Termination: END and STOP
Two commands terminate program execution: END and STOP. They look similar but behave differently—understanding when to use each prevents confusion.
The END Statement
END terminates your program gracefully:
50 END
When BASIC executes END:
- Stops execution immediately — No more lines execute
- Returns to immediate mode — Shows
READY.prompt - Keeps variables — All variables retain their values
- Cannot continue — You can't resume with
CONT
CODE_FENCE_0
Line 50 never executes because END stopped the program at line 40.
Where to Place END
Traditionally, END appears at the end of your program:
10 PRINT "HELLO"
20 PRINT "WORLD"
999 END
Some programmers use a high line number (900, 999, 9999) for END so there's room to add lines before it.
The STOP Statement
STOP suspends your program temporarily:
50 STOP
When BASIC executes STOP:
- Pauses execution — Stops at the
STOPline - Shows BREAK message — Displays
BREAK IN 50 - Returns to immediate mode — Shows
READY.prompt - Allows continuation — You can resume with
CONT
CODE_FENCE_0
The program stopped at line 30. It hasn't ended—it's paused.
When to Use Each
| Statement | Purpose | Can CONT? | Use Case |
|---|---|---|---|
END |
Terminate permanently | No | End of program |
STOP |
Suspend temporarily | Yes | Debugging, inspection |
Use END when:
- Your program completes normally
- You want final, definite termination
- You're structuring program flow (multiple exit points)
Use STOP when:
- Debugging—inspect variables mid-execution
- Testing—pause before a problem section
- Development—check intermediate results
Multiple END Statements
Programs can have multiple END statements:
10 INPUT "CONTINUE"; A$
20 IF A$ = "NO" THEN END
30 PRINT "CONTINUING..."
40 PRINT "MORE PROCESSING..."
50 END
If user types "NO", the program ends at line 20. Otherwise, it continues and ends at line 50.
Insert STOP statements to inspect variables during execution:
CODE_FENCE_0
Run the program. When it hits line 115: CODE_FENCE_1
Remove STOP when debugging is complete.
10 PRINT "CALCULATING..."
20 FOR I = 1 TO 5
30 PRINT "I ="; I
40 NEXT I
50 PRINT "HALF WAY DONE"
60 STOP
70 PRINT "RESUMING..."
80 FOR J = 6 TO 10
90 PRINT "J ="; J
100 NEXT J
110 END
Run this program and observe:
RUNexecutes through line 60, then showsBREAK IN 60- Type
PRINT Ito see I = 5 (loop completed) - Type
CONTto continue from line 70 - Program completes the second loop
Continuing Execution with CONT
The CONT command resumes a program that was suspended by STOP (or by pressing ESC to interrupt execution). Think of it as "unpause."
How CONT Works
When you type:
CONT
BASIC resumes execution at the line after the one that caused the break.
CODE_FENCE_0
After STOP at line 30, CONT resumes at line 40 (the next line).
CONT After ESC Interrupt
If you press ESC during program execution, the program pauses:
10 FOR I = 1 TO 10000
20 PRINT I
30 NEXT I
RUN
1
2
3
(Press ESC)
BREAK IN 20
READY.
CONT
(Continues counting...)
This is useful when a program runs too long or enters an infinite loop.
When CONT Works
CONT works after:
- STOP statement — Program executed
STOP - ESC interrupt — You pressed ESC during execution
When CONT Fails
CONT does not work after:
- END statement — Program terminated completely
- Error — Runtime error occurred
- Program edit — You changed any program line
- RUN command — Starting fresh clears continuation state
CODE_FENCE_0
END terminated the program—there's nothing to continue.
CODE_FENCE_0
You edited the program—BASIC can't safely resume.
Inspecting Variables During STOP
The power of STOP + CONT is examining program state:
10 A = 5
20 B = 10
30 C = A + B
40 STOP
50 PRINT "RESULT:"; C
60 END
RUN
BREAK IN 40
READY.
PRINT A
5
READY.
PRINT B
10
READY.
PRINT C
15
READY.
CONT
RESULT: 15
READY.
You inspected variables A, B, and C in immediate mode, then continued execution.
Never edit program lines while stopped! Editing breaks the continuation state. If you need to change code:
- Note the problem
- Let the program finish (or press ESC)
- Edit the lines
RUNagain from the start
Use STOP for interactive debugging:
- Add
STOPbefore problem section RUNthe program- When it breaks, inspect variables with
PRINT - Type
CONTto continue - Observe results after resume
- Remove
STOPwhen bug is found
10 PRINT "MULTIPLICATION TABLE FOR 7"
20 FOR I = 1 TO 3
30 PRINT "7 x"; I; "="; 7 * I
40 NEXT I
50 STOP
60 FOR I = 4 TO 6
70 PRINT "7 x"; I; "="; 7 * I
80 NEXT I
90 END
Try this sequence:
RUN(stops after 7x1, 7x2, 7x3)PRINT I(shows 3, the loop completed)CONT(continues with 7x4, 7x5, 7x6)
Clearing Variables with CLR
The CLR command clears all variables but preserves your program. It's like NEW but less destructive—your code stays intact.
What CLR Does
Type:
CLR
BASIC:
- Sets all numeric variables to 0 — A, X, COUNT%, etc.
- Sets all string variables to empty — A$, NAME$, etc.
- Clears arrays — All array contents reset
- Keeps your program — Every line remains unchanged
- Stays in immediate mode — Shows
READY.prompt
CODE_FENCE_0
Variables are cleared, but the program remains.
CLR vs. RUN vs. NEW
Compare these commands:
| Command | Program | Variables | Use Case |
|---|---|---|---|
CLR |
Kept | Cleared | Reset variables, keep program |
RUN |
Kept | Cleared, then executes | Run program from start |
NEW |
Deleted | Cleared | Start completely fresh |
When to Use CLR
Testing programs repeatedly:
(After first run, variables have values from execution)
CLR
RUN
(Now you know variables start at 0)
Cleaning up after experiments:
A = 99
B$ = "TEST"
(Experiments done, don't want garbage values)
CLR
Before running manually:
(You're about to run a program with GOTO 10)
CLR
GOTO 10
(Variables start clean)
CLR Is Automatic in RUN
You rarely need CLR because RUN does it automatically:
RUN
(RUN clears variables, then executes)
But CLR is useful when:
- Testing setup before running
- Using
GOTOto enter program withoutRUN - Experimenting in immediate mode and want a clean slate
You can enter a program using GOTO from immediate mode:
CODE_FENCE_0
This keeps variables from immediate mode. Use CLR first if you want clean variables:
CODE_FENCE_1
- NEW — Starting a completely different program
- CLR — Resetting variables, keeping program
- RUN — Normal execution (includes CLR automatically)
Most of the time, just use RUN!
10 PRINT "ENTER A NUMBER:"
20 INPUT A
30 PRINT "YOU ENTERED:"; A
40 PRINT "DOUBLE:"; A * 2
50 END
Try this experiment:
RUNand enter 50- After program ends,
PRINT A(shows 50) CLRto clear variablesPRINT A(now shows 0)LISTto verify program still exists
Commenting with REM
The REM statement adds comments to your programs—notes for yourself (and other programmers) that explain what the code does. BASIC ignores REM lines during execution.
REM Syntax
10 REM THIS IS A COMMENT
Everything after REM on that line is ignored:
10 REM INITIALIZE VARIABLES
20 A = 0
30 B = 0
40 REM START MAIN LOOP
50 FOR I = 1 TO 10
What Makes a Good Comment
Bad comment (obvious):
10 REM SET A TO 5
20 A = 5
The code already says A = 5—the comment adds nothing.
Good comment (explains why):
10 REM A = 5 BECAUSE WE START AT LEVEL 5
20 A = 5
Now we understand the reason behind the value.
Bad comment (too vague):
100 REM DO CALCULATIONS
110 C = (F - 32) * 5 / 9
Good comment (specific):
100 REM CONVERT FAHRENHEIT TO CELSIUS
110 C = (F - 32) * 5 / 9
When to Use Comments
Document sections:
10 REM ============================
20 REM INITIALIZATION SECTION
30 REM ============================
40 A = 0: B = 0: C$ = ""
100 REM ============================
110 REM MAIN PROGRAM LOOP
120 REM ============================
130 FOR I = 1 TO 100
Explain complex logic:
200 REM CHECK IF NUMBER IS PRIME
210 REM TRY DIVIDING BY 2 THROUGH SQRT(N)
220 FOR I = 2 TO SQR(N)
230 IF N/I = INT(N/I) THEN RETURN
240 NEXT I
Document subroutines:
1000 REM ==========================
1010 REM SUBROUTINE: DISPLAY TITLE
1020 REM SHOWS CENTERED TITLE TEXT
1030 REM ==========================
1040 PRINT " PROGRAM TITLE"
1050 RETURN
Mark TODO items:
500 REM TODO: ADD ERROR CHECKING HERE
510 INPUT A
REM Must Be Entire Line
You cannot put REM at the end of a code line:
10 A = 5 REM SET A TO 5 (WRONG!)
This causes a syntax error. Comments must be on their own line:
10 REM SET A TO 5 (CORRECT)
20 A = 5
REM and Multi-Statement Lines
However, after a colon separator, REM works:
10 A = 5: REM THIS WORKS
Everything after REM is ignored, even on multi-statement lines.
Performance Note
REM lines slow down execution very slightly—BASIC must skip them. In practice, this is negligible. Always prioritize clarity over micro-optimization. Well-commented programs are worth the tiny performance cost.
CODE_FENCE_0
Develop a consistent style:
- Section headers — Use REM with === borders
- Line-by-line explanation — REM before complex lines
- Blank REM lines — Use
REMalone for visual spacing in listings - Indentation — Can't indent code, but can indent comments: CODE_FENCE_0
10 REM ========================
20 REM MULTIPLICATION QUIZ
30 REM ========================
40 REM GENERATE RANDOM PROBLEM
50 A = INT(RND(1) * 10) + 1
60 B = INT(RND(1) * 10) + 1
70 REM ASK USER FOR ANSWER
80 PRINT A; "x"; B; "= ";
90 INPUT ANS
100 REM CHECK IF CORRECT
110 IF ANS = A * B THEN PRINT "CORRECT!"
120 IF ANS <> A * B THEN PRINT "WRONG. ANSWER:"; A * B
999 END
Notice how comments make this program's structure clear. Try LIST to see the organization, then RUN to see how BASIC skips the comments.
Development Workflows
Now that you know all the program management commands, let's see how experienced BASIC programmers use them together in typical workflows.
The Edit-List-Run-Debug Cycle
This is the heartbeat of BASIC programming:
1. EDIT — Enter or modify program lines
10 PRINT "HELLO"
20 END
2. LIST — Review your changes
LIST
10 PRINT "HELLO"
20 END
READY.
3. RUN — Execute the program
RUN
HELLO
READY.
4. DEBUG — Fix any problems, return to step 1
Repeat this cycle continuously. Most programming sessions involve hundreds of iterations through this loop.
Starting a New Program
Clean slate workflow:
NEW (Clear memory)
LIST (Verify empty)
10 REM MY NEW PROGRAM
20 PRINT "STARTING..."
...
(Enter program lines)
...
LIST (Review what you entered)
RUN (Test initial version)
Debugging a Problem
Isolate-and-inspect workflow:
(Program has a bug around line 200)
LIST 180-220 (Review problem area)
(Identify suspect line)
(Add debugging output)
195 PRINT "A ="; A; "B ="; B
RUN
(Check output)
(Or use STOP to inspect)
195 STOP
RUN
BREAK IN 195
READY.
PRINT A
(Inspect variable)
PRINT B
(Inspect another)
CONT
(Continue execution)
(Bug found! Remove debugging code)
195
LIST 180-220 (Verify fix)
RUN (Test again)
Testing a Subroutine
Isolated subroutine test:
(Program has subroutine at line 1000)
LIST 1000-1100 (Review subroutine)
(Add temporary test code before program)
5 GOSUB 1000
6 END
RUN (Test subroutine)
(Subroutine executes)
(Works! Remove test code)
5
6
RUN (Normal execution)
Making Major Changes
Incremental-change workflow:
SAVE "MYPROGRAM" (Backup current version - Ch 12)
LIST (Review before changes)
(Make first change)
50 PRINT "NEW VERSION"
LIST 40-60 (Verify change)
RUN (Test)
(Works!)
(Make second change)
100 A = A * 2
LIST 90-110 (Verify)
RUN (Test)
(Works!)
SAVE "MYPROGRAM" (Save working version)
When Things Go Wrong
Recovery workflow:
(Made a mistake, program broken)
LIST (See what's wrong)
(Try to fix)
50 (Delete bad line)
RUN (Test)
(Still broken)
NEW (Nuclear option)
LOAD "MYPROGRAM" (Restore from save - Ch 12)
(Back to last working version)
Building Programs Incrementally
Progressive-development workflow:
(Start with simplest version)
10 PRINT "HELLO"
20 END
RUN
(Works!)
(Add feature #1)
15 INPUT "NAME"; N$
30 PRINT "HI, "; N$
RUN
(Works!)
(Add feature #2)
35 INPUT "AGE"; A
40 PRINT "YOU ARE"; A; "YEARS OLD"
RUN
(Works!)
LIST (Review complete program)
SAVE "GREETER" (Save final version)
The Line Number Strategy
Organised numbering:
10-90 REM Initialization
100-890 REM Main program
900-990 REM Cleanup/end
1000-1990 REM Subroutines
9000-9999 REM Data statements
Example:
10 REM INITIALIZATION
20 A = 0: B = 0
30 DIM SCORES(10)
100 REM MAIN PROGRAM
110 FOR I = 1 TO 10
120 GOSUB 1000
130 NEXT I
900 REM END
910 PRINT "COMPLETE"
999 END
1000 REM SUBROUTINE: INPUT SCORE
1010 INPUT "SCORE"; SCORES(I)
1020 RETURN
Don't write 100 lines, then run. Instead:
- Write 5-10 lines
LISTto reviewRUNto test- Fix any problems
- Repeat
Small iterations catch errors early when they're easy to fix!
10 REM VERSION 1: BASIC GREETING
20 PRINT "HELLO, WORLD!"
30 END
Practice incremental development:
RUNthis basic version- Add line
15 INPUT "NAME"; N$ - Change line
20 PRINT "HELLO, "; N$ RUNto test- Add line
25 INPUT "AGE"; A - Add line
35 PRINT "IN 10 YEARS YOU'LL BE"; A + 10 LISTto see your evolved programRUNfor final test
Chapter Summary
You've mastered the essential program management tools that every BASIC programmer uses constantly.
Commands Covered
Memory Management:
- NEW — Clear program and variables (permanent!)
- CLR — Clear variables, keep program
Viewing Programs:
- LIST — Show entire program
- LIST n — Show single line
- LIST n-m — Show range
- LIST -n — Show start through line n
- LIST n- — Show line n through end
Execution Control:
- RUN — Execute from beginning (clears variables)
- RUN n — Execute from line n (clears variables)
- END — Terminate program (cannot continue)
- STOP — Suspend program (can continue)
- CONT — Resume after STOP or ESC
Documentation:
- REM — Add comments (entire line only)
Key Insights
NEW is permanent — Always save important programs before using NEW.
LIST has many forms — Master all variations for efficient navigation.
RUN clears variables — Every RUN starts fresh, even RUN n.
END vs STOP — END terminates, STOP suspends. Use STOP for debugging.
CONT requires STOP — Can't continue after END, errors, or edits.
CLR rarely needed — RUN does it automatically.
REM makes code maintainable — Future you will thank present you.
Typical Session
NEW Start fresh
(Enter program lines)
LIST Review code
RUN Test execution
(Error occurs)
LIST 50 Inspect problem line
50 (corrected line) Fix the error
RUN Test again
(Works!)
SAVE "MYPROGRAM" Save it (Chapter 12)
What's Next
You now have complete control over program development. In Chapter 12, you'll learn to save programs permanently with SAVE and LOAD, ensuring your work survives browser restarts.
But first, you have all the tools needed to write, test, and debug BASIC programs effectively. The commands in this chapter are your constant companions—you'll use them thousands of times in your programming journey.
These commands become automatic with practice. Don't try to memorize—just keep programming. After a few sessions, you'll type LIST, RUN, and CONT without thinking.
That's when programming becomes truly fluid and enjoyable!
File Operations
You've written programs, debugged them, perfected them—and then closed your browser. When you return, they're gone. Hours of work, vanished.
This chapter solves that problem permanently.
BASIC's SAVE and LOAD commands preserve your programs in browser storage, making them persistent across sessions. Write a program today, load it next week, share it next month. Your work survives browser restarts, computer reboots, everything.
File operations transform BASIC from a sandbox into a proper development environment. You'll learn to save programs safely, load them reliably, manage multiple projects, handle errors gracefully, and develop backup strategies. Never lose work again.
By the end of this chapter, you'll save programs as naturally as you RUN them. File operations become second nature—automatic protection for everything you create.
Introduction to File Storage
Every program you've written so far exists only in temporary memory. Close the browser tab, and it's gone forever. NEW deletes it. A browser crash erases it. There's no recovery, no undo, no second chance.
The Solution: Persistent Storage
SLP-BASIC uses your browser's localStorage to save programs permanently. Think of localStorage as a virtual filing cabinet—a place where BASIC stores your code safely, independent of the interpreter's memory.
Programs saved to localStorage:
- Survive browser restarts — Close and reopen, programs are still there
- Survive BASIC restarts — Disconnect and reconnect, programs remain
- Survive NEW commands — Clear memory all you want, saved programs are safe
- Persist indefinitely — Browsers preserve localStorage forever (unless you clear browser data)
How Storage Works
When you save a program named "MYGAME", BASIC:
- Converts your program to plain text (one line per program line)
- Writes it to browser localStorage
- Uses a unique key:
emulator.ca/disk/basic/MYGAME - Returns success confirmation
When you load "MYGAME", BASIC:
- Looks up the key in localStorage
- Reads the plain text
- Clears current program (like
NEW) - Parses each line back into memory
- Returns ready to
RUN
The BackendDisk Abstraction
Technically, BASIC uses a component called BackendDisk that provides a file-system-like interface over browser localStorage. This abstraction:
- Handles all storage operations
- Manages the
emulator.ca/disk/basic/namespace - Converts between BASIC program format and storage format
- Reports errors when storage fails
You don't interact with BackendDisk directly—you use SAVE and LOAD, and BackendDisk handles the details.
Storage Limitations
Browser localStorage has limits:
Capacity:
- Most browsers: 5-10 MB total for the entire domain
- Shared with all site data, not just BASIC programs
- Typical BASIC program: 1-50 KB (you can store hundreds of programs)
What happens when full:
SAVEfails with?SAVE ERROR- Delete old programs to free space
- Or clear browser storage (loses everything!)
Per-browser isolation:
- Programs saved in Chrome aren't visible in Firefox
- Programs saved on Computer A aren't on Computer B
- Each browser/device has its own independent storage
Where Are Programs Stored?
The storage namespace is:
emulator.ca/disk/basic/<filename>
So saving "TEST" creates:
emulator.ca/disk/basic/TEST
And saving "GAME.BAS" creates:
emulator.ca/disk/basic/GAME.BAS
You can inspect saved programs in browser Developer Tools:
- Press F12 to open DevTools
- Go to Application tab (Chrome) or Storage tab (Firefox)
- Expand Local Storage
- Click on the site domain
- Look for keys starting with
emulator.ca/disk/basic/ - Click a key to see the stored program text
This is useful for debugging storage issues or recovering programs manually.
Plain Text Format
Unlike some classic BASIC implementations that tokenize programs into binary format, SLP-BASIC saves programs as human-readable plain text:
10 PRINT "HELLO"
20 FOR I = 1 TO 10
30 PRINT I
40 NEXT I
50 END
This format:
- Readable — You can see exactly what's stored
- Debuggable — Easy to inspect in DevTools
- Portable — Copy/paste between systems
- Reliable — No binary corruption issues
The tradeoff: plain text is larger than tokenized binary (real Commodores used binary). But with modern storage sizes, this doesn't matter.
The cardinal rule of programming: save frequently. Don't wait until your program is "done"—save after every significant addition. A program saved is a program you can't lose.
Experienced programmers save constantly:
- After writing a new section
- Before making risky changes
- After fixing a difficult bug
- Every few minutes during active development
Make SAVE a habit, like LIST and RUN.
10 PRINT "TEST PROGRAM"
20 PRINT "THIS WILL BE SAVED"
30 END
Before continuing, save this program:
- Type
SAVE "TEST" - You should see
SAVING TEST - Type
NEWto clear memory - Type
LOAD "TEST"to restore it - Type
LISTto see it's back
Saving Programs with SAVE
The SAVE command writes your current program to persistent storage. Once saved, your program survives anything—browser restarts, memory clears, even computer crashes (assuming browser data is preserved).
SAVE Syntax
SAVE "filename"
The filename must be in quotes. These are all valid:
SAVE "MYPROGRAM"
SAVE "GAME.BAS"
SAVE "MULTIPLICATION-QUIZ"
SAVE "VERSION-2"
CODE_FENCE_0
The program is now permanently stored as "FIBONACCI".
What SAVE Does
When you execute SAVE "filename":
- Validates filename — Checks that it's a non-empty string
- Converts program to text — Each line becomes text (e.g.,
10 PRINT "HELLO") - Writes to storage — Stores in
emulator.ca/disk/basic/filename - Shows confirmation — Prints
SAVING filename - Reports errors — Shows
?SAVE ERRORif storage fails
The program in memory remains unchanged—you can continue editing, running, whatever. SAVE is non-destructive to the active program.
SAVE Overwrites Existing Files
If you save a program with a name that already exists, SAVE overwrites the old version without warning:
CODE_FENCE_0
The original "TEST" is gone—replaced by the new version.
There's no confirmation prompt, no "Are you sure?" message. SAVE immediately overwrites. If you want to preserve the old version, use a different filename (see versioning strategies later).
SAVE Does Not Clear Memory
After saving, your program remains in memory:
SAVE "MYPROGRAM"
SAVING MYPROGRAM
READY.
LIST
(Program still appears)
RUN
(Program still executes)
SAVE is like taking a snapshot—the original stays where it is.
Filename Restrictions
Filenames should:
- Be descriptive —
PRIME-FINDERnotP - Avoid special characters — Stick to letters, numbers, hyphens, underscores
- Use extensions optionally —
.BASis traditional but not required
Filenames are case-sensitive on some systems:
SAVE "MYGAME"andSAVE "mygame"might create different filesLOAD "MYGAME"won't find"mygame"
Best practice: use UPPERCASE for consistency (traditional BASIC style).
When SAVE Fails
SAVE can fail if:
- Storage is full — Browser localStorage limit reached
- Storage is disabled — User disabled storage in browser settings
- Permission denied — Browser security blocks storage access
- Invalid filename — Empty string or invalid characters
When SAVE fails:
SAVE "MYPROGRAM"
?SAVE ERROR
READY.
The error message is generic—BASIC can't tell you why it failed. Check browser storage capacity in DevTools.
At the start of a new session, save a test program immediately:
CODE_FENCE_0
If this fails, you know there's a storage problem. Don't spend hours programming only to discover you can't save!
10 REM PRIME NUMBER FINDER
20 PRINT "PRIME NUMBERS UP TO 50:"
30 FOR N = 2 TO 50
40 P = 1
50 FOR I = 2 TO SQR(N)
60 IF N/I = INT(N/I) THEN P = 0
70 NEXT I
80 IF P THEN PRINT N;
90 NEXT N
100 PRINT
110 END
Practice saving:
LISTto review the programSAVE "PRIMES"to save itNEWto clear memoryLOAD "PRIMES"to restore (we'll learn LOAD next)RUNto verify it still works
Loading Programs with LOAD
The LOAD command restores a saved program from storage back into memory. Think of it as the opposite of SAVE—you take a snapshot off the shelf and put it back in the camera.
LOAD Syntax
LOAD "filename"
The filename must match exactly what you used with SAVE:
SAVE "MYPROGRAM"
(Later...)
LOAD "MYPROGRAM"
CODE_FENCE_0
The saved program is restored to memory and ready to run.
LOAD Clears Current Program First
Important: LOAD does NEW automatically before loading. Your current program is deleted:
CODE_FENCE_0
If you need to save the current program before loading another:
SAVE "CURRENT" (Save what you have)
LOAD "DIFFERENT" (Now load the other one)
What LOAD Does
When you execute LOAD "filename":
- Looks up filename — Searches
emulator.ca/disk/basic/filename - Checks if exists — Returns
?FILE NOT FOUNDif missing - Clears memory — Executes
NEW(deletes current program and variables) - Reads file contents — Retrieves plain text from storage
- Parses lines — Converts text back to program lines
- Loads into memory — Each line is entered (like typing manually)
- Shows confirmation — Prints
LOADING filename - Returns ready — Program is loaded, ready to
LISTorRUN
LOAD Does Not RUN
After LOAD, your program is in memory but not executing:
LOAD "MYPROGRAM"
LOADING MYPROGRAM
READY.
(Program is loaded but not running)
(You must RUN manually)
RUN
(Now it executes)
To load and run in one sequence:
LOAD "MYPROGRAM"
RUN
Or combine with colon separator:
LOAD "MYPROGRAM": RUN
(Loads, then immediately runs)
When LOAD Fails
The most common error is file not found:
LOAD "TYPO"
?FILE NOT FOUND
READY.
This happens when:
- Filename misspelled —
"MYGAME"vs"MYGAMME" - Case mismatch —
"MYGAME"vs"mygame" - File never saved — You thought you saved but didn't
- Wrong browser — Saved in Chrome, trying to load in Firefox
Other errors:
LOAD ""
?MISSING FILE NAME
READY.
LOAD "CORRUPTED"
?LOAD ERROR
INVALID LINE: (details)
READY.
?LOAD ERROR means the file exists but is corrupted or invalid.
LOAD and Variables
LOAD clears all variables (because it does NEW):
A = 100
PRINT A
100
READY.
LOAD "MYPROGRAM"
LOADING MYPROGRAM
READY.
PRINT A
0
READY.
The variable A is reset to 0. This is usually what you want—loading a program should start fresh.
After loading, always check that you got the right program:
CODE_FENCE_0
This catches filename typos and ensures the loaded program is what you expected.
10 PRINT "TEMPORARY PROGRAM"
20 PRINT "ABOUT TO BE REPLACED"
30 END
If you saved "PRIMES" earlier:
LISTto see current programLOAD "PRIMES"to replace itLISTto see the loaded programRUNto execute
If LOAD fails with ?FILE NOT FOUND, you'll need to SAVE "PRIMES" first (see previous section).
Using String Variables for Filenames
Both SAVE and LOAD accept string variables in place of literal filenames. This enables dynamic filename generation—programs that save/load based on user input, numbered versions, or computed names.
Basic String Variable Usage
Instead of:
SAVE "MYPROGRAM"
You can use:
F$ = "MYPROGRAM"
SAVE F$
CODE_FENCE_0
Dynamic Filename Generation
This becomes powerful when combined with user input:
CODE_FENCE_0
Version Numbering
You can automatically generate version numbers:
CODE_FENCE_0
Note: STR$(V) converts the number to a string (see Chapter 10).
Numbered Backups
Create multiple backups with sequential numbers:
CODE_FENCE_0
(Note the space in STR$(I)—we'll handle that in the next example.)
Cleaning Up STR$() Spaces
STR$() adds a leading space for positive numbers. Remove it with MID$():
10 N$ = "PROG"
20 V = 5
30 F$ = N$ + MID$(STR$(V), 2)
40 PRINT F$
RUN
PROG5
READY.
MID$(STR$(V), 2) extracts from character 2 onward, skipping the space.
Loading with String Variables
Same principle applies to LOAD:
10 INPUT "FILENAME TO LOAD"; F$
20 LOAD F$
30 RUN
(Note: Lines after LOAD don't execute—LOAD clears program!)
Wait—that won't work! LOAD clears the program, so line 30 disappears. Instead:
INPUT "FILENAME TO LOAD"; F$
LOAD F$
Do this in immediate mode, not in a program.
Program-Managed Saves
A self-saving program:
CODE_FENCE_0
Wait—same problem! SAVE happens inside the program, but the program is what you're saving. This works fine! SAVE doesn't clear memory—it just writes the current program to storage.
Common filename patterns using string variables:
CODE_FENCE_0
Choose patterns that make filenames clear and organised.
10 PRINT "VERSION SAVER"
20 INPUT "BASE NAME"; N$
30 INPUT "VERSION NUMBER"; V
40 F$ = N$ + "-V" + MID$(STR$(V), 2)
50 PRINT "WILL SAVE AS: "; F$
60 SAVE F$
70 PRINT "SAVED!"
80 END
Try this program:
RUNand enterTESTas base name- Enter
1as version number - It saves as
TEST-V1 NEWto clear memory- Type
LOAD "TEST-V1"to restore LISTto verify
Storage Details
Understanding how storage works helps you avoid problems and use it efficiently. This section covers the technical details of SLP-BASIC's storage system.
The localStorage Namespace
All BASIC programs are stored under the namespace:
emulator.ca/disk/basic/
A file saved as "MYGAME" is stored with key:
emulator.ca/disk/basic/MYGAME
A file saved as "PROJECT.BAS" is stored with key:
emulator.ca/disk/basic/PROJECT.BAS
The namespace ensures BASIC programs don't collide with other site data.
Storage Capacity Limits
Browser localStorage is typically limited to 5-10 MB per origin (domain). This storage is shared by:
- BASIC programs (our files)
- Other site data (telemetry, settings, etc.)
- Anything else the site stores
How much space do programs use?
A typical BASIC program:
- Small program (10-20 lines): ~200-500 bytes
- Medium program (50-100 lines): ~1-3 KB
- Large program (200+ lines): ~5-20 KB
- Very large program (1000+ lines): ~50-200 KB
With 5-10 MB available, you can store:
- Hundreds of small programs
- Dozens of large programs
- Several very large programs
Checking Storage Usage
No built-in command shows storage usage. You must use browser DevTools:
- Open DevTools (F12)
- Go to Application → Local Storage
- Click the site domain
- Look for keys starting with
emulator.ca/disk/basic/ - Each key shows its size in the value column
What Happens When Storage Is Full
When localStorage reaches capacity, SAVE fails:
SAVE "BIGPROGRAM"
?SAVE ERROR
READY.
Solutions:
- Delete old programs (use DevTools to remove keys)
- Clear browser data (loses everything!)
- Use private/incognito mode (fresh storage, but lost on close)
- Export programs (copy text manually, import later)
Data Persistence
localStorage data persists:
- Browser restarts — Yes, survives
- Computer restarts — Yes, survives
- Browser updates — Usually survives
- Clear browsing data — NO, deleted
- Private/incognito mode — NO, cleared on close
Per-Browser Isolation
Each browser maintains separate storage:
- Programs saved in Chrome are invisible to Firefox
- Programs saved on Computer A are invisible on Computer B
- Programs in normal mode are invisible to private mode
To share programs between browsers/computers:
LISTthe program- Copy the output text
- Manually enter lines on the other system
- Or use browser sync features (if available)
Storage Format
Programs are stored as plain text with one line per program line:
10 PRINT "HELLO"
20 FOR I = 1 TO 10
30 PRINT I
40 NEXT I
50 END
Exactly as LIST displays. No compression, no tokenization, no binary encoding.
Advantages:
- Human-readable
- Easy to debug
- Copy/paste friendly
- No corruption from binary issues
Disadvantages:
- Larger file size than tokenized binary
- Slower to parse (negligible for programs <1000 lines)
Comparison to Real Commodore Storage
| Feature | SLP-BASIC | Real Commodore |
|---|---|---|
| Medium | Browser localStorage | Cassette tape / Floppy disk |
| Format | Plain text | Tokenized binary |
| Capacity | 5-10 MB (hundreds of programs) | 64-170 KB per disk |
| Speed | Instant (< 1 second) | 1-5 minutes (tape), 10-30 seconds (disk) |
| Persistence | Forever (unless cleared) | Until tape/disk degrades |
| Sharing | Copy/paste, DevTools export | Physical media transfer |
| Directory | No DIR command (yet) |
LOAD "$",8 |
SLP-BASIC storage is more reliable and faster, but less authentic (no disk drive sounds!).
Planned storage features:
- DIR or CATALOG — List saved programs
- DELETE or SCRATCH — Remove programs from storage
- VERIFY — Check file integrity
- Export/Import — Save programs as downloadable text files
These features will make storage management easier.
Occasionally check storage in DevTools:
- How many programs do you have?
- Any duplicates or old versions to delete?
- Approaching storage limit?
Proactive management prevents ?SAVE ERROR surprises.
10 PRINT "STORAGE TEST"
20 PRINT "THIS PROGRAM IS SAVED IN PLAIN TEXT FORMAT"
30 PRINT "EXACTLY AS LIST DISPLAYS IT"
40 END
Save this program, then inspect storage:
SAVE "FORMAT-TEST"- Open browser DevTools (F12)
- Go to Application → Local Storage
- Find key
emulator.ca/disk/basic/FORMAT-TEST - Look at the value—it's the plain text of your program!
Error Messages
File operations can fail for various reasons. Understanding error messages helps you diagnose and fix problems quickly.
?FILE NOT FOUND
Appears during: LOAD
Means: BASIC searched storage but couldn't find a program with that filename.
CODE_FENCE_0
Common causes:
- Filename misspelled —
"MYGAME"vs"MYGAMME" - Case mismatch —
"MYGAME"vs"mygame" - Program never saved — You intended to save but didn't
- Wrong browser — Saved in Chrome, loading in Firefox
- Browser data cleared — Storage was reset
Solutions:
- Double-check spelling:
LOAD "MYGAME"notLOAD "MYGAMME" - Try alternate case:
LOAD "mygame"ifLOAD "MYGAME"fails - Verify program was saved: Check DevTools → Local Storage
- Re-save the program if you have it in memory
?MISSING FILE NAME
Appears during: SAVE or LOAD
Means: You didn't provide a filename, or the filename is an empty string.
CODE_FENCE_0
Common causes:
- Empty string:
SAVE "" - Empty variable:
F$ = ""thenSAVE F$ - Missing quotes:
SAVE FILENAME(treats as variable, might be empty)
Solutions:
- Always provide a filename:
SAVE "MYPROGRAM" - Check variable before using:
IF F$ = "" THEN INPUT "FILENAME"; F$
?SAVE ERROR
Appears during: SAVE
Means: BASIC attempted to save but storage operation failed.
CODE_FENCE_0
Common causes:
- Storage is full — Browser localStorage capacity reached
- Storage disabled — User disabled storage in browser settings
- Permission denied — Browser security blocks storage access
- Private mode — Some browsers restrict storage in incognito mode
Solutions:
- Delete old programs to free space (DevTools → Local Storage)
- Check browser storage settings (enable storage if disabled)
- Try normal mode instead of private/incognito
- Use a different browser
?LOAD ERROR
Appears during: LOAD
Means: BASIC found the file but couldn't parse it as a valid program.
CODE_FENCE_0
Common causes:
- File corrupted — Storage data damaged
- Manually edited — You edited storage in DevTools incorrectly
- Invalid format — File wasn't created by BASIC
- Line number format — Lines don't start with valid numbers
Solutions:
- If you have the program elsewhere, re-save it
- If manually edited in DevTools, fix the format
- If corruption is severe, delete the file and re-create the program
INVALID LINE: (details)
Appears with: ?LOAD ERROR
Means: A specific line couldn't be parsed.
CODE_FENCE_0
The error shows the problematic line text. Common issues:
- Typo in command:
PRINNTinstead ofPRINT - Missing line number: Line starts with text instead of number
- Malformed syntax: Invalid BASIC syntax
Solutions:
- Note the error details
- Load fails, but you can manually enter corrected line
- Or delete the corrupted file and re-create
Error Handling Workflow
When you encounter an error:
- Read the error message carefully — It usually tells you exactly what's wrong
- Check obvious causes — Spelling, case, quotes
- Inspect storage — Use DevTools to verify file exists and looks correct
- Try alternatives — Different case, different filename
- Re-save if needed — If you have the program in memory, save again
- Delete corrupted files — If file is damaged beyond repair
Most file errors are preventable:
For ?FILE NOT FOUND:
- Use consistent naming (all UPPERCASE)
- Verify with DevTools after saving
- Keep a list of saved programs
For ?SAVE ERROR:
- Test save early in session
- Monitor storage usage
- Delete old programs regularly
For ?LOAD ERROR:
- Don't manually edit files in DevTools
- Save with BASIC commands only
- Keep backups of important programs
10 PRINT "ERROR TEST PROGRAM"
20 END
Test error handling:
SAVE ""(shows ?MISSING FILE NAME)SAVE "TEST-ERROR"(saves successfully)LOAD "WRONG-NAME"(shows ?FILE NOT FOUND)LOAD "TEST-ERROR"(loads successfully)
File Naming Best Practices
Good filenames make programs easy to find, organise, and manage. Poor filenames lead to confusion, overwrites, and lost work. Here's how to name files effectively.
Use Descriptive Names
Bad:
SAVE "P"
SAVE "PROG"
SAVE "TEST"
SAVE "X"
Good:
SAVE "PRIME-FINDER"
SAVE "MULTIPLICATION-QUIZ"
SAVE "TEMPERATURE-CONVERTER"
SAVE "FIBONACCI-SEQUENCE"
Months later, which will you recognise? Descriptive names tell you what the program does at a glance.
Follow Naming Conventions
Recommended style:
- UPPERCASE — Traditional BASIC style, consistent with commands
- Hyphens or underscores — Separate words (PRIME-FINDER or PRIME_FINDER)
- Descriptive but concise — 2-4 words maximum
Examples:
SAVE "GUESS-THE-NUMBER"
SAVE "AREA-CALCULATOR"
SAVE "STUDENT-GRADES"
SAVE "MENU-SYSTEM"
Include Version Numbers
For evolving programs, include version indicators:
Pattern 1: Suffix version
SAVE "MYGAME-V1"
SAVE "MYGAME-V2"
SAVE "MYGAME-V3"
Pattern 2: Date-based
SAVE "MYGAME-JAN23"
SAVE "MYGAME-JAN24"
Pattern 3: Status suffix
SAVE "MYGAME-ALPHA"
SAVE "MYGAME-BETA"
SAVE "MYGAME-FINAL"
Use Extensions Optionally
.BAS is traditional but not required:
SAVE "PROGRAM.BAS" (Traditional style)
SAVE "PROGRAM" (Also fine)
Extensions add clarity but take up space in filenames. Your choice.
Organise by Project
For large projects with multiple programs, use prefixes:
SAVE "GAME-MAIN"
SAVE "GAME-INTRO"
SAVE "GAME-LEVELS"
SAVE "GAME-HISCORE"
Or categories:
SAVE "MATH-PRIMES"
SAVE "MATH-FACTORS"
SAVE "MATH-FIBONACCI"
SAVE "GAMES-GUESS"
SAVE "GAMES-QUIZ"
Avoid Problematic Characters
Safe characters:
- Letters: A-Z, a-z
- Numbers: 0-9
- Hyphen: -
- Underscore: _
- Period: .
Avoid:
- Spaces (use hyphens instead)
- Special characters: !, @, #, $, %, ^, &, *, (, ), etc.
- Quotes within filename (syntax error)
Why: Some characters cause parsing issues or are reserved by browsers.
Keep Names Reasonable Length
Too short:
SAVE "P" (What does P mean?)
Too long:
SAVE "MY-REALLY-AWESOME-PROGRAM-THAT-DOES-CALCULATIONS"
Just right:
SAVE "CALCULATOR"
Aim for 1-3 words, 10-30 characters total.
Backup Naming Strategy
For backups, add identifiers:
SAVE "MYPROGRAM-BACKUP"
SAVE "MYPROGRAM-BACKUP-2"
SAVE "MYPROGRAM-BEFORE-CHANGES"
SAVE "MYPROGRAM-WORKING"
Real-World Examples
Here's how you might organise a collection of programs:
UTILITIES:
SAVE "UTIL-UNIT-CONVERT"
SAVE "UTIL-DATE-CALC"
SAVE "UTIL-BASE-CONVERT"
GAMES:
SAVE "GAME-GUESS-NUMBER"
SAVE "GAME-MATH-QUIZ"
SAVE "GAME-WORD-SCRAMBLE"
LEARNING:
SAVE "LEARN-LOOPS"
SAVE "LEARN-ARRAYS"
SAVE "LEARN-STRINGS"
PROJECTS:
SAVE "PROJECT-GRADEBOOK-V1"
SAVE "PROJECT-GRADEBOOK-V2"
SAVE "PROJECT-GRADEBOOK-BACKUP"
Anti-Patterns to Avoid
Generic names:
SAVE "PROGRAM"
SAVE "TEST"
SAVE "NEW"
SAVE "TEMP"
You'll have dozens of these and won't remember which is which.
Numbered names:
SAVE "PROG1"
SAVE "PROG2"
SAVE "PROG3"
Numbers don't convey meaning. What's the difference between PROG1 and PROG2?
Random names:
SAVE "ASDF"
SAVE "QWERTY"
SAVE "XYZ"
These are impossible to search or remember.
Before saving, ask:
- Descriptive? — Will I know what this is in 6 months?
- Unique? — Does it conflict with existing programs?
- Consistent? — Does it match my naming convention?
- Appropriate length? — Not too short, not too long?
If yes to all four, it's a good filename!
10 REM TEMPERATURE CONVERTER
20 REM CONVERTS FAHRENHEIT TO CELSIUS
30 PRINT "TEMPERATURE CONVERTER"
40 INPUT "FAHRENHEIT"; F
50 C = (F - 32) * 5 / 9
60 PRINT "CELSIUS: "; C
70 END
Practice good naming:
- Bad:
SAVE "TEMP" - Better:
SAVE "TEMPERATURE" - Best:
SAVE "TEMP-CONVERTER"orSAVE "UTIL-TEMP-CONVERT"
Choose a descriptive name and save this program.
Backup Strategies
Hard drives fail. Browsers crash. Accidents happen. The only defense is backups—multiple copies of your important programs. Here's how to protect your work.
The 3-2-1 Backup Rule
In professional computing:
- 3 copies — Original + 2 backups
- 2 different media — Hard drive + cloud, or browser storage + text file
- 1 off-site — Cloud storage or different computer
For BASIC programs:
- Original — Current version in memory / localStorage
- Backup 1 — Saved with
-BACKUPsuffix - Backup 2 — Exported as text file (copy from
LIST)
Strategy 1: Version Suffixes
Save multiple versions as you work:
(Initial version)
SAVE "MYGAME-V1"
(After adding features)
SAVE "MYGAME-V2"
(After major changes)
SAVE "MYGAME-V3"
Benefits:
- Easy to revert to previous version
- Can compare versions (load each, examine changes)
- Protection against destructive edits
Downside:
- Uses more storage
- Older versions become clutter
Strategy 2: Backup Copies
Before risky changes, save a backup:
(Current working version)
SAVE "MYGAME"
(Before major refactoring)
SAVE "MYGAME-BACKUP"
(Make changes to original)
SAVE "MYGAME"
(If changes work: delete backup)
(If changes fail: LOAD "MYGAME-BACKUP")
Strategy 3: Milestone Backups
Save at significant milestones:
SAVE "MYGAME" (Daily working version)
SAVE "MYGAME-ALPHA" (First playable version)
SAVE "MYGAME-BETA" (Feature-complete)
SAVE "MYGAME-FINAL" (Release version)
Strategy 4: Time-Based Backups
Save with timestamps (manual, no DATE$ function yet):
SAVE "MYGAME-JAN23"
SAVE "MYGAME-JAN24"
SAVE "MYGAME-JAN25"
Or session numbers:
SAVE "MYGAME-SESSION1"
SAVE "MYGAME-SESSION2"
Strategy 5: Export to Text
The ultimate backup: copy program as plain text.
Process:
LISTyour program- Select all output text
- Copy to clipboard
- Paste into a text editor (Notepad, TextEdit, etc.)
- Save as
MYGAME.TXTorMYGAME.BAS
Benefits:
- Survives browser data clearing
- Portable to any system
- Can edit outside BASIC
- Can commit to version control (Git)
- True off-site backup
Restoration:
- Open text file
- Copy program lines
- In BASIC, type
NEW - Manually enter each line (or paste if terminal supports it)
Automated Backup Pattern
Build backups into your workflow:
CODE_FENCE_0
Backup Checklist for Important Programs
Before making major changes:
- Save current version —
SAVE "PROGRAM" - Create backup —
SAVE "PROGRAM-BACKUP" - Export to text —
LIST, copy, save to file - Verify backup —
LOAD "PROGRAM-BACKUP"to confirm it works - Proceed with changes — Now it's safe to experiment
When to Delete Backups
Don't let backups accumulate forever:
Keep:
- Current working version
- Last 2-3 versions
- Milestone versions (ALPHA, BETA, FINAL)
Delete:
- Old experimental versions
- Temporary backups after changes succeed
- Duplicate versions
- Versions older than 1 month (unless milestones)
Use DevTools → Local Storage to review and delete old backups.
Recovery Scenarios
Scenario 1: Accidentally overwrote program
LOAD "PROGRAM-BACKUP"
(Restore previous version)
Scenario 2: Browser data cleared
(Load text file)
(Manually re-enter program lines)
Scenario 3: Corrupted file
(Try backup)
LOAD "PROGRAM-BACKUP"
(If backup also corrupted, use text export)
Don't just save backups—verify they work!
CODE_FENCE_0
A backup that doesn't load is worthless.
Adopt this rhythm:
- Before every session: Save current work
- Every 15 minutes: Save during active development
- Before risky changes: Save backup copy
- End of session: Save final version
- After milestones: Save milestone version
This becomes automatic—like checking mirrors while driving.
10 REM IMPORTANT PROGRAM
20 REM DO NOT LOSE THIS
30 PRINT "CRITICAL CALCULATION"
40 A = 1000000
50 PRINT "VALUE: "; A
60 END
Practice backup workflow:
SAVE "IMPORTANT"(main version)SAVE "IMPORTANT-BACKUP"(backup)- Edit line 40:
40 A = 2000000 RUN(test change)SAVE "IMPORTANT"(save if good, or...)LOAD "IMPORTANT-BACKUP"(restore if bad)
Complete Save/Load Workflow
Let's put everything together with a complete development workflow—from starting a new project to saving multiple versions and managing backups.
Workflow: Creating a New Program
Step 1: Start Fresh
NEW
Step 2: Enter Your Program
10 REM MULTIPLICATION QUIZ
20 REM ASKS 5 RANDOM PROBLEMS
30 PRINT "MULTIPLICATION QUIZ"
40 PRINT
50 SCORE = 0
60 FOR Q = 1 TO 5
70 A = INT(RND(1) * 10) + 1
80 B = INT(RND(1) * 10) + 1
90 PRINT Q; ". "; A; " X "; B; " = ";
100 INPUT ANS
110 IF ANS = A * B THEN SCORE = SCORE + 1: PRINT "CORRECT!"
120 IF ANS <> A * B THEN PRINT "WRONG. ANSWER: "; A * B
130 NEXT Q
140 PRINT
150 PRINT "SCORE: "; SCORE; " OUT OF 5"
999 END
Step 3: Test
RUN
(Test the program)
Step 4: Save
SAVE "MULT-QUIZ-V1"
Now your program is safe!
Workflow: Iterative Development
Session 1: Initial Version
(Create basic version)
SAVE "MYGAME-V1"
Session 2: Add Features
LOAD "MYGAME-V1"
(Make changes)
SAVE "MYGAME-V2"
Session 3: Major Refactoring
LOAD "MYGAME-V2"
SAVE "MYGAME-V2-BACKUP" (Backup before risky changes)
(Refactor code)
RUN (Test)
(Works!)
SAVE "MYGAME-V3"
Session 4: Polish and Release
LOAD "MYGAME-V3"
(Final tweaks)
SAVE "MYGAME-FINAL"
Workflow: Bug Fixing
Discover Bug
LOAD "MYPROGRAM"
RUN
(See bug)
Create Debug Version
SAVE "MYPROGRAM-DEBUG"
(Add debug PRINT statements)
150 PRINT "DEBUG: A = "; A
RUN
(Find problem)
Fix Bug
(Remove debug lines)
150
(Fix actual bug)
100 IF A > 0 THEN ...
Test and Save
RUN
(Works!)
SAVE "MYPROGRAM"
Workflow: Backup Before Experiment
Safe Experimentation
LOAD "STABLE-VERSION"
LIST (Review it)
SAVE "STABLE-VERSION-BACKUP" (Backup)
(Try experimental idea)
50 (Delete old approach)
55 (Add new approach)
RUN
(Doesn't work...)
LOAD "STABLE-VERSION-BACKUP" (Restore)
(Back to working version)
Workflow: Multi-Version Management
Maintaining Multiple Versions
Active development:
SAVE "PROJECT-DEV" (Daily working version)
Stable versions:
SAVE "PROJECT-V1" (Released version 1)
SAVE "PROJECT-V2" (Released version 2)
Experimental branches:
SAVE "PROJECT-EXPERIMENT-AI"
SAVE "PROJECT-EXPERIMENT-SOUND"
Backups:
SAVE "PROJECT-BACKUP-JAN23"
Workflow: Collaborative Development
(Well, as collaborative as localStorage allows!)
Developer A:
(Create program)
SAVE "SHARED-PROGRAM"
LIST
(Copy output)
(Send text to Developer B via email/chat)
Developer B:
NEW
(Paste lines from Developer A)
10 PRINT "HELLO"
20 END
...
(Make changes)
SAVE "SHARED-PROGRAM-B"
LIST
(Send changes back)
Workflow: End-of-Session Checklist
Before closing the browser:
1. LIST (Review current work)
2. SAVE "CURRENTPROJECT" (Save main version)
3. SAVE "CURRENTPROJECT-BACKUP" (Save backup)
4. (Optional: Export to text file)
Tomorrow you'll return to a clean slate:
1. LOAD "CURRENTPROJECT"
2. LIST (Review where you left off)
3. RUN (Test that it still works)
4. (Continue development)
CODE_FENCE_0
Good programmers develop automatic habits:
Every 5 minutes: LIST to review
Every 15 minutes: SAVE "PROGRAM" to save
Before risky changes: SAVE "PROGRAM-BACKUP"
End of session: SAVE main and backup versions
After milestones: SAVE "PROGRAM-V1", SAVE "PROGRAM-V2", etc.
These habits prevent data loss and enable fearless experimentation.
10 REM COMPLETE WORKFLOW DEMO
20 PRINT "WORKFLOW EXAMPLE"
30 END
Practice complete workflow:
- Edit this program (add features)
SAVE "WORKFLOW-V1"(save first version)- Edit again (add more features)
SAVE "WORKFLOW-V2"(save second version)NEW(clear memory)LOAD "WORKFLOW-V1"(load old version)LIST(see the old version)LOAD "WORKFLOW-V2"(load new version)LIST(see the new version)
Chapter Summary
You've mastered file operations—the commands that preserve your work permanently. Never lose a program again.
Commands Covered
Saving Programs:
- SAVE "filename" — Save current program to storage
- SAVE variable$ — Save using string variable filename
Loading Programs:
- LOAD "filename" — Load program from storage (clears memory first)
- LOAD variable$ — Load using string variable filename
Key Insights
Storage is persistent — Programs survive browser restarts, computer reboots, and NEW commands (unless browser data is cleared).
SAVE overwrites — No confirmation when overwriting existing files. Use versioning (-V1, -V2) to preserve old versions.
LOAD clears memory — Your current program is deleted before loading. Save first if you need to keep it!
Plain text format — Programs stored as human-readable text, exactly as LIST displays. View in DevTools → Local Storage.
localStorage limits — Typically 5-10 MB total, shared with other site data. Hundreds of programs fit comfortably.
Per-browser isolation — Programs in Chrome don't appear in Firefox. Programs on Computer A don't appear on Computer B.
Backups are essential — Always keep backups of important programs. Multiple versions protect against accidents.
Error Messages
- ?FILE NOT FOUND — Filename doesn't exist (check spelling, case)
- ?MISSING FILE NAME — No filename provided or empty string
- ?SAVE ERROR — Storage full or disabled
- ?LOAD ERROR — File corrupted or invalid format
Best Practices
File naming:
- Descriptive names (PRIME-FINDER, not P)
- Consistent case (UPPERCASE recommended)
- Version numbers (MYGAME-V1, MYGAME-V2)
- Avoid special characters
Backup strategy:
- Save frequently (every 15 minutes)
- Create backups before risky changes
- Keep multiple versions
- Export important programs to text files
Development workflow:
LOADat start of sessionSAVEfrequently during development- Test after loading to verify file integrity
SAVEbackups before major changesSAVEmain version at end of session
Comparison to Commodore BASIC
Similarities:
- SAVE and LOAD syntax identical
- Programs persist between sessions
- Error messages similar
Differences:
- No device numbers (no
,8suffix) - No VERIFY command (yet)
- No directory commands (yet)
- Faster (instant vs. 1-5 minutes on tape)
- More reliable (no tape degradation)
- Plain text instead of tokenized binary
What's Next
You now have complete program persistence. Combined with Chapter 11's program management commands, you have a full development environment—write, test, save, load, debug, and manage programs professionally.
In Chapter 13, you'll explore advanced features—memory access with PEEK and POKE, user-defined functions with DEF FN, and multi-statement lines with colon separators.
But first, practice file operations until they become automatic. The commands in this chapter protect your work—use them constantly!
Every experienced programmer has a horror story about lost work. Here's how to avoid yours:
The Three Rules:
- Save early — Save your first draft immediately
- Save often — Every 15 minutes, minimum
- Save versions — Keep multiple backups
Follow these rules religiously. Your future self will thank you.
Advanced Features
You've mastered the fundamentals: variables, loops, arrays, functions, file operations. You can write complete programs that solve real problems. You're a competent BASIC programmer.
But there's more.
This chapter reveals BASIC's advanced features—the tools that separate casual programmers from system hackers. These are the commands that let you peek behind the curtain, access raw memory, define custom mathematical functions, and write code so compact it borders on cryptic.
Advanced features aren't for every program. Most of your code won't need POKE, won't benefit from DEF FN, won't require WAIT. But when you need them, they're indispensable. They transform BASIC from a beginner's language into a systems programming tool.
We'll explore memory access with POKE and PEEK, system synchronization with WAIT, mathematical abstraction with DEF FN, and code compression with multi-statement lines. Each feature comes with power—and responsibility. Use them wisely.
By the end of this chapter, you'll understand when to reach for advanced features and when simpler solutions suffice. You'll write more elegant, more efficient, more powerful programs. You'll think like a systems programmer.
Memory Access with POKE and PEEK
The 64KB Memory Space
Every Commodore BASIC system has memory—64 kilobytes (65,536 bytes) addressed from 0 to 65,535. On real Commodore hardware, this memory contains:
- The BASIC interpreter itself
- Your program code
- Variable storage
- Screen memory (what you see on the display)
- Color memory (text colors)
- Hardware registers (sound, graphics, I/O ports)
- The operating system (Kernal ROM)
In SLP-BASIC, we simulate this memory space. It's not real hardware, but it behaves identically to authentic Commodore memory. You can read from it, write to it, and use it exactly as 1980s programmers did.
Why Memory Access Matters
Most BASIC commands work at a high level: PRINT displays text, INPUT reads values, FOR loops. They hide the underlying machinery.
POKE and PEEK operate at the lowest level—raw memory bytes. This lets you:
- Manipulate hardware (or simulated hardware)
- Store temporary data in unused memory areas
- Access system information not available through BASIC commands
- Optimize storage by packing data efficiently
- Implement advanced algorithms that need direct memory control
On real Commodore systems, programmers used POKE to change screen colors, activate sprites, play sounds, and control peripherals. They used PEEK to read joystick positions, check keyboard states, and monitor system status.
In SLP-BASIC's simulated environment, these operations work but affect simulated memory, not physical hardware. Still, the techniques are identical.
The POKE Command
Syntax:
POKE address,value
What it does:
Writes a single byte (value, 0-255) to memory location address (0-65535).
Examples:
{
"description": "Basic POKE usage - writing to memory",
"program": "10 POKE 2000,42\n20 PRINT \"WROTE 42 TO ADDRESS 2000\"\n30 PRINT \"READ IT BACK:\"; PEEK(2000)"
}
{
"description": "POKE with calculated addresses",
"program": "10 REM STORE ARRAY IN CUSTOM MEMORY\n20 BASE=5000\n30 FOR I=0 TO 9\n40 POKE BASE+I,I*10\n50 NEXT I\n60 REM READ IT BACK\n70 FOR I=0 TO 9\n80 PRINT \"ADDR\";BASE+I;\"=\";PEEK(BASE+I)\n90 NEXT I"
}
Value Range:
valuemust be 0-255 (one byte)- Values outside this range are truncated (modulo 256)
POKE 1000,256stores 0 (256 MOD 256 = 0)POKE 1000,300stores 44 (300 MOD 256 = 44)POKE 1000,-1stores 255 (wraps around)
Address Range:
addressmust be 0-65535- Addresses outside this range cause
?ILLEGAL QUANTITY ERROR
The PEEK Function
Syntax:
value = PEEK(address)
What it does:
Reads a single byte (0-255) from memory location address and returns it as a numeric value.
Examples:
{
"description": "Reading memory with PEEK",
"program": "10 POKE 3000,123\n20 A=PEEK(3000)\n30 PRINT \"VALUE AT 3000:\";A"
}
{
"description": "PEEK in expressions",
"program": "10 POKE 4000,10\n20 POKE 4001,20\n30 PRINT \"SUM:\";PEEK(4000)+PEEK(4001)\n40 PRINT \"PRODUCT:\";PEEK(4000)*PEEK(4001)"
}
Return value:
- Always returns 0-255 (unsigned byte)
- Reading from uninitialized memory returns 0 (in simulated environment)
- On real Commodore, uninitialized memory contains random values
Practical Example: Custom Data Storage
Arrays use significant memory and have limitations (must be pre-dimensioned, only one or two dimensions). Sometimes you need more control.
{
"description": "Using POKE/PEEK as a custom data structure",
"program": "10 REM HIGH SCORE TABLE IN MEMORY\n20 REM FORMAT: 5 SCORES (0-255)\n30 BASE=8000\n40 REM STORE SCORES\n50 POKE BASE+0,95\n60 POKE BASE+1,87\n70 POKE BASE+2,76\n80 POKE BASE+3,64\n90 POKE BASE+4,52\n100 REM DISPLAY\n110 PRINT \"HIGH SCORES:\"\n120 FOR I=0 TO 4\n130 PRINT \"#\";I+1;\":\";PEEK(BASE+I)\n140 NEXT I"
}
Multi-Byte Values
A single byte stores 0-255. What if you need larger numbers?
Technique: Split into high/low bytes
A 16-bit value (0-65535) uses two bytes:
- Low byte = value MOD 256
- High byte = INT(value/256)
{
"description": "Storing 16-bit values in memory",
"program": "10 REM STORE 16-BIT VALUE 1234\n20 V=1234\n30 LO=V-INT(V/256)*256\n40 HI=INT(V/256)\n50 POKE 6000,LO\n60 POKE 6001,HI\n70 REM READ IT BACK\n80 L=PEEK(6000)\n90 H=PEEK(6001)\n100 RESULT=H*256+L\n110 PRINT \"STORED:\";V\n120 PRINT \"RECOVERED:\";RESULT"
}
Memory Map Reference
On authentic Commodore systems, different memory ranges have different purposes:
VIC-20 Memory Map:
0-1023 Zero page, stack, BASIC workspace
1024-7679 BASIC program area (3KB expansion)
7680-7935 Screen memory (22×23 = 506 bytes)
38400+ Color memory
C64 Memory Map:
0-1023 Zero page, stack, BASIC workspace
2048-40959 BASIC program area
53248-53294 VIC-II chip registers (graphics)
54272-54295 SID chip registers (sound)
55296-56295 Color RAM
In SLP-BASIC's simulated environment, all 65,536 bytes are available for your use. There's no real screen memory or hardware registers (yet), so you can safely POKE anywhere.
Future versions of SLP-BASIC may simulate specific hardware features (screen memory, color RAM, sound registers). When that happens, POKE to those addresses will have visible effects—changing colors, playing sounds, drawing graphics.
For now, memory is just storage—a 64KB scratch space for your data.
Common Uses
- Temporary data storage — Fast, flexible alternative to arrays
- Bit manipulation — Store flags, pack multiple booleans into one byte
- Hardware control — On real Commodore, essential for graphics/sound
- Low-level optimization — Direct memory access is fast
- Educational — Understanding memory builds systems thinking
Cautions
- Don't POKE into BASIC program area — You'll corrupt your code
- Don't assume memory persists —
NEWclears everything - Document your memory layout — Future you will forget what you stored where
- Simulated memory ≠ real memory — Some real Commodore tricks won't work here
The WAIT Statement
Synchronization and Timing
The WAIT statement pauses program execution until a memory location meets specific conditions. On real Commodore hardware, this was used to:
- Synchronize with the raster beam (for flicker-free graphics)
- Wait for hardware events (joystick press, disk drive ready)
- Implement precise timing loops
- Coordinate with interrupts
Syntax:
WAIT address,mask
WAIT address,mask,mask2
How it works:
- Reads byte from
address - Performs bitwise AND with
mask - (Optional) Performs bitwise XOR with
mask2 - If result is non-zero, continues
- Otherwise, loops back to step 1
Mathematical formula:
Continue when: ((PEEK(address) AND mask) XOR mask2) ≠ 0
Without mask2:
Continue when: (PEEK(address) AND mask) ≠ 0
Examples
{
"description": "Basic WAIT usage",
"program": "10 REM WAIT DEMO\n20 POKE 7000,0\n30 PRINT \"WAITING FOR BIT 0...\"\n40 POKE 7000,1: REM SET BIT\n50 WAIT 7000,1\n60 PRINT \"CONDITION MET!\""
}
{
"description": "WAIT with two masks",
"program": "10 REM WAIT FOR SPECIFIC VALUE\n20 POKE 8000,0\n30 PRINT \"WAITING FOR VALUE 255...\"\n40 POKE 8000,255\n50 WAIT 8000,255,0\n60 PRINT \"GOT IT!\""
}
Bit Masks Explained
A mask selects which bits you care about:
Value: 10110101 (binary)
Mask: 00001111 (check low 4 bits only)
Result: 00000101 (AND operation)
Common masks:
1= Bit 0 (value 1)2= Bit 1 (value 2)4= Bit 2 (value 4)8= Bit 3 (value 8)128= Bit 7 (value 128)255= All bits (entire byte)
The XOR Mask
The optional mask2 inverts bits:
WAIT 1000,255,255
This waits until address 1000 becomes zero:
- Read byte, AND with 255 (no change)
- XOR with 255 (inverts all bits)
- Result is non-zero only when original byte was zero
WAIT in WASM Context
Important: SLP-BASIC runs in a WebAssembly environment with cooperative execution. WAIT doesn't actually spin in a tight loop—that would freeze the browser.
Instead, WAIT:
- Checks the condition once
- If not met, yields control back to the event loop
- Continues program when called again
This means WAIT in SLP-BASIC is non-blocking and plays nice with the browser. It behaves correctly but won't provide microsecond timing precision.
Practical Example: Event Coordination
{
"description": "Using WAIT for event flags",
"program": "10 REM SIMPLE EVENT SYSTEM\n20 EVENT=9000\n30 POKE EVENT,0: REM CLEAR FLAG\n40 PRINT \"PROGRAM RUNNING...\"\n50 REM SIMULATE EVENT\n60 POKE EVENT,1\n70 WAIT EVENT,1\n80 PRINT \"EVENT DETECTED!\"\n90 POKE EVENT,0: REM CLEAR\n100 PRINT \"HANDLED.\""
}
When to Use WAIT
Good uses:
- Coordinating with external events
- Implementing state machines
- Polling for conditions
Better alternatives:
- Most timing needs: Use
FORloops or counters - Simple delays: Not supported in WASM (use loops)
- Complex logic: Use
IFstatements
WAIT is a specialized tool. On modern BASIC, you'll rarely need it.
User-Defined Functions with DEF FN
Beyond Built-in Functions
BASIC provides excellent built-in functions: SQR, SIN, ABS, etc. But what if you need a function BASIC doesn't have? What if you're repeatedly calculating the same complex formula?
DEF FN lets you define your own functions.
Syntax
DEF FN name(parameter) = expression
Rules:
- Function name must start with
FN - Parameter is a single variable (can be numeric or string)
- Expression is evaluated when function is called
- Definition must fit on one line
- Function can be used anywhere expressions are allowed
Basic Example
{
"description": "Simple user-defined function",
"program": "10 DEF FN DOUBLE(X) = X*2\n20 PRINT FN DOUBLE(5)\n30 PRINT FN DOUBLE(3.5)\n40 A=10\n50 PRINT FN DOUBLE(A)"
}
Mathematical Functions
{
"description": "Custom mathematical functions",
"program": "10 REM CELSIUS TO FAHRENHEIT\n20 DEF FN C2F(C) = C*9/5+32\n30 PRINT \"0C =\";FN C2F(0);\"F\"\n40 PRINT \"100C =\";FN C2F(100);\"F\"\n50 PRINT \"37C =\";FN C2F(37);\"F\""
}
{
"description": "Area calculation function",
"program": "10 REM CIRCLE AREA\n20 DEF FN AREA(R) = 3.14159*R*R\n30 FOR R=1 TO 5\n40 PRINT \"R=\";R;\"AREA=\";FN AREA(R)\n50 NEXT R"
}
Functions Using Built-in Functions
Your function can call any built-in function:
{
"description": "Combining built-in functions",
"program": "10 REM HYPOTENUSE CALCULATOR\n20 DEF FN HYP(X) = SQR(X*X+X*X)\n30 PRINT FN HYP(3)\n40 PRINT FN HYP(5)\n50 PRINT FN HYP(10)"
}
{
"description": "Rounding function",
"program": "10 REM ROUND TO NEAREST INTEGER\n20 DEF FN ROUND(X) = INT(X+0.5)\n30 PRINT FN ROUND(3.2)\n40 PRINT FN ROUND(3.7)\n50 PRINT FN ROUND(3.5)"
}
String Functions
Functions can return strings too:
{
"description": "String manipulation function",
"program": "10 REM FIRST 3 CHARACTERS\n20 DEF FN FIRST3$(S$) = LEFT$(S$,3)\n30 PRINT FN FIRST3$(\"HELLO\")\n40 PRINT FN FIRST3$(\"BASIC\")\n50 N$=\"PROGRAMMING\"\n60 PRINT FN FIRST3$(N$)"
}
Multiple Functions
You can define as many functions as you need:
{
"description": "Multiple function definitions",
"program": "10 REM GEOMETRY FUNCTIONS\n20 DEF FN CIRC(R) = 2*3.14*R\n30 DEF FN AREA(R) = 3.14*R*R\n40 DEF FN VOL(R) = 4/3*3.14*R*R*R\n50 R=5\n60 PRINT \"RADIUS:\";R\n70 PRINT \"CIRCUMF:\";FN CIRC(R)\n80 PRINT \"AREA:\";FN AREA(R)\n90 PRINT \"VOLUME:\";FN VOL(R)"
}
Limitations
Single line only:
DEF FN COMPLEX(X) = (X*X+X)/2 ✓ Works
DEF FN COMPLEX(X) = ✗ Can't split
X*X+X ✗ across lines
One parameter only:
DEF FN AVG(X) = X/2 ✓ Works
DEF FN AVG(X,Y) = (X+Y)/2 ✗ Can't do this
Workaround: Use global variables for additional inputs
No recursion:
DEF FN FACT(X) = X*FN FACT(X-1) ✗ Don't do this
Function can't call itself (BASIC has no recursion).
Using Functions in Expressions
Once defined, use your function anywhere:
{
"description": "Functions in complex expressions",
"program": "10 DEF FN SQ(X) = X*X\n20 DEF FN DIST(D) = SQR(FN SQ(D)+FN SQ(D))\n30 A=FN SQ(5)+FN SQ(3)\n40 PRINT \"A=\";A\n50 B=FN DIST(10)\n60 PRINT \"B=\";B\n70 IF FN SQ(4)>10 THEN PRINT \"YES\""
}
When to Use DEF FN
Good uses:
- Repeated calculations (conversion formulas, geometry)
- Making code self-documenting (
FN C2F(T)clearer thanT*9/5+32) - Encapsulating complex expressions
- Reducing typing for frequently-used formulas
Alternatives:
- For multi-line logic: Use
GOSUBsubroutines - For simple calculations: Inline expressions may be clearer
- For multiple parameters: Use subroutines with global variables
Multi-Statement Lines
Compact Code with Colons
Every BASIC line you've written so far has contained one statement:
10 A=5
20 B=10
30 PRINT A+B
The colon (:) lets you combine multiple statements on one line:
10 A=5:B=10:PRINT A+B
This is functionally identical—it just saves line numbers and vertical space.
Basic Examples
{
"description": "Multiple statements per line",
"program": "10 A=1:B=2:C=3\n20 PRINT A:PRINT B:PRINT C"
}
{
"description": "Combining different statement types",
"program": "10 X=5:Y=10:PRINT \"X=\";X;\"Y=\";Y\n20 A$=\"HELLO\":B$=\"WORLD\":PRINT A$;\" \";B$"
}
Control Flow with Colons
This is where multi-statement lines get interesting:
{
"description": "IF with multiple consequences",
"program": "10 INPUT \"NUMBER\";N\n20 IF N<0 THEN PRINT \"NEGATIVE\":END\n30 IF N=0 THEN PRINT \"ZERO\":END\n40 IF N>0 THEN PRINT \"POSITIVE\":END"
}
{
"description": "Compact loop initialization",
"program": "10 S=0:C=0\n20 FOR I=1 TO 10:S=S+I:C=C+1:NEXT I\n30 PRINT \"SUM=\";S;\"COUNT=\";C"
}
Initialization Blocks
Group related initialization:
{
"description": "Variable initialization block",
"program": "10 REM GAME SETUP\n20 SC=0:LV=1:HP=100:XP=0\n30 PRINT \"SCORE:\";SC\n40 PRINT \"LEVEL:\";LV\n50 PRINT \"HEALTH:\";HP\n60 PRINT \"XP:\";XP"
}
When to Use Colons
Good uses:
- Related variable assignments:
X=0:Y=0:Z=0 - Short sequences:
PRINT A:PRINT B - Compact IF branches:
IF X<0 THEN PRINT "ERROR":END - Initialization blocks:
SC=0:HI=0:NM$=""
When to avoid:
- Long, complex logic (hard to read)
- Unrelated operations (confusing)
- Debugging (harder to step through)
- When clarity matters more than brevity
Readability vs Compactness
Compare:
Readable version:
10 INPUT "NAME";N$
20 IF N$="" THEN PRINT "EMPTY"
30 IF N$="" THEN END
40 PRINT "HELLO ";N$
Compact version:
10 INPUT "NAME";N$:IF N$="" THEN PRINT "EMPTY":END
20 PRINT "HELLO ";N$
Both work. Choose based on context:
- Short programs: Compact is fine
- Complex logic: Readable is better
- Sharing code: Readable helps others
- Personal projects: Whatever you prefer
Limits
Some statements don't work well with colons:
10 FOR I=1 TO 10:PRINT I:NEXT I ✓ Works
10 DEF FN SQ(X)=X*X:A=5 ✗ DEF must be alone
10 DATA 1,2,3:PRINT "HI" ? Weird, don't do this
Rule of thumb: If it feels awkward, split it into separate lines.
Real-World Example
{
"description": "Practical multi-statement program",
"program": "10 REM TEMPERATURE CONVERTER\n20 PRINT \"1=F TO C 2=C TO F\":INPUT C\n30 IF C=1 THEN INPUT \"F\";F:PRINT (F-32)*5/9;\"C\":END\n40 IF C=2 THEN INPUT \"C\";C:PRINT C*9/5+32;\"F\":END\n50 PRINT \"INVALID\":GOTO 20"
}
This program is dense but functional. For production code, you'd probably expand it.
Philosophy
Multi-statement lines are a tool, not a rule. Use them to make code clearer or more compact, but never at the expense of understanding.
In the 1980s, programmers used colons to save memory (fewer line numbers = less RAM). On SLP-BASIC with 38KB free, memory isn't the issue—clarity is.
Write for humans first, computers second.
Error Messages
Every programmer encounters errors. Not occasionally—constantly. You'll type wrong syntax, forget a closing quote, divide by zero, access non-existent variables, jump to missing line numbers. Errors aren't failures—they're feedback.
This chapter is your debugging companion.
BASIC's error messages are terse but precise. They tell you exactly what went wrong and usually where. A ?SYNTAX ERROR means malformed code. A ?UNDEF'D STATEMENT ERROR means you jumped to a line that doesn't exist. A ?NEXT WITHOUT FOR ERROR means you closed a loop that was never opened.
Understanding error messages transforms frustration into systematic debugging. Instead of randomly changing code and hoping it works, you'll read the error, understand the cause, locate the problem, and fix it correctly. First time.
We'll cover every error message in SLP-BASIC: what causes it, what it means, how to fix it, and how to prevent it. You'll see real examples that trigger each error and learn proven debugging techniques that work for any problem.
By the end of this chapter, you'll welcome error messages. They're not obstacles—they're instructions. Follow them, and your programs work.
Understanding Error Messages
The Error Format
When BASIC encounters an error, it displays:
?ERROR_TYPE ERROR IN LINE
For example:
?SYNTAX ERROR IN 100
Components:
- Question mark (?) — Universal error prefix, signals something's wrong
- ERROR_TYPE — Specific error name (SYNTAX, OVERFLOW, OUT OF DATA, etc.)
- ERROR — The word "ERROR" (always present)
- IN LINE — If error occurred in program mode, shows line number
- No line number — If error occurred in immediate mode
Where Errors Occur
Immediate mode errors:
?SYNTAX ERROR
You typed something invalid directly at the prompt. Fix it and try again.
Program mode errors:
?DIVISION BY ZERO ERROR IN 150
Line 150 caused the error during RUN. Use LIST 150 to see what's wrong.
The Error State
When an error occurs:
- Program execution stops immediately
- Control returns to immediate mode
- Error message displays
- You can inspect variables (still in memory)
- You can
LISTthe program (still intact) - You cannot
CONT(errors break continuity)
To continue, you must:
- Fix the error (edit the problematic line)
RUNagain from the start- Or
GOTOa specific line to resume
Your Debugging Mindset
When you see an error:
- Read it carefully — Error name tells you the category
- Check the line number —
LISTthat line to see the code - Understand the cause — Match error to the situation
- Fix it — Apply the correct solution
- Test again — Verify the fix worked
Don't:
- Panic and randomly change code
- Ignore the error message
- Assume you know what's wrong without checking
- Give up (every error has a solution)
Syntax Errors
Syntax errors are caught when you enter a line or when the parser tries to execute it. These are typing mistakes, malformed commands, or invalid BASIC constructs.
?SYNTAX ERROR
Cause: Code doesn't match BASIC's grammar rules.
Common triggers:
- Misspelled keywords
- Missing operators
- Invalid characters
- Malformed expressions
- Incorrect command structure
{
"description": "Syntax error - misspelled keyword",
"program": "PRNT \"HELLO\""
}
Why it failed: PRNT isn't a BASIC keyword. Should be PRINT.
{
"description": "Syntax error - missing operator",
"program": "10 A=5 6\n20 PRINT A"
}
Why it failed: 5 6 isn't valid. Did you mean 5+6 or 5*6?
{
"description": "Syntax error - invalid expression",
"program": "10 A=5+\n20 PRINT A"
}
Why it failed: Expression ends with operator (+). What comes after?
How to fix:
- Carefully read the line mentioned in the error
- Compare to correct syntax (reference manual)
- Fix typos, add missing parts, correct structure
- Re-enter the line
Prevention:
- Double-check spelling before pressing Enter
- Type slowly and carefully
- Use
LISTto review code beforeRUN - Learn correct syntax patterns through examples
?MISSING FILE NAME
Cause: SAVE or LOAD command without a filename.
{
"description": "Missing filename error",
"program": "10 PRINT \"TESTING\"\nSAVE"
}
Correct usage:
SAVE "MYPROGRAM"
LOAD "MYPROGRAM"
How to fix:
- Add filename in quotes after
SAVE/LOAD - Ensure quotes are present (required)
- Check for typos in command
Prevention:
- Always specify filename:
SAVE "NAME" - Use meaningful names that describe the program
?ILLEGAL QUANTITY ERROR
Cause: Number outside valid range for the operation.
Common triggers:
- Array subscript negative or too large
DIMwith invalid sizeMID$with position < 1- Mathematical operations with invalid inputs
{
"description": "Illegal quantity - negative array subscript",
"program": "10 DIM A(10)\n20 PRINT A(-5)"
}
{
"description": "Illegal quantity - invalid DIM",
"program": "10 DIM A(-10)"
}
{
"description": "Illegal quantity - string position",
"program": "10 A$=\"HELLO\"\n20 PRINT MID$(A$,0,2)"
}
How to fix:
- Check array subscripts: must be ≥ 0 and < DIM size
- Verify numeric parameters are in valid ranges
- Add bounds checking with
IFstatements
Prevention:
10 DIM A(10)
20 INPUT "INDEX";I
30 IF I<0 OR I>10 THEN PRINT "OUT OF RANGE":GOTO 20
40 PRINT A(I)
Always validate user input before using it as an index.
Runtime Errors
Runtime errors occur during program execution. The syntax is correct, but something went wrong at runtime—missing data, invalid math, memory exhausted, etc.
?UNDEF'D STATEMENT ERROR
Cause: GOTO, GOSUB, THEN, or RUN referenced a line number that doesn't exist.
{
"description": "Undefined statement - GOTO",
"program": "10 PRINT \"START\"\n20 GOTO 100\n30 PRINT \"END\""
}
Why it failed: Line 100 doesn't exist. Program can't jump there.
{
"description": "Undefined statement - GOSUB",
"program": "10 GOSUB 500\n20 PRINT \"DONE\"\n30 END"
}
{
"description": "Undefined statement - IF THEN",
"program": "10 A=5\n20 IF A=5 THEN 200\n30 PRINT \"NOT 5\""
}
How to fix:
- Use
LISTto see all line numbers in your program - Either change the
GOTO/GOSUBto a line that exists - Or add the missing line at that number
Prevention:
- Use
LISTto verify line numbers before referencing them - Use consistent line numbering (10, 20, 30...)
- Comment your subroutines so you remember their line numbers
?OUT OF DATA ERROR
Cause: READ statement executed but no more DATA available.
{
"description": "Out of data error",
"program": "10 DATA 1,2,3\n20 FOR I=1 TO 5\n30 READ A\n40 PRINT A\n50 NEXT I"
}
Why it failed: Loop reads 5 times, but DATA only has 3 values.
How to fix:
Option 1: Add more data
10 DATA 1,2,3,4,5
Option 2: Read less
20 FOR I=1 TO 3
Option 3: Check before reading
{
"description": "Preventing out of data error",
"program": "10 DATA 1,2,3,4,5\n20 C=5: REM COUNT OF ITEMS\n30 FOR I=1 TO C\n40 READ A\n50 PRINT A\n60 NEXT I\n70 PRINT \"DONE\""
}
Prevention:
- Count your
DATAitems and loop that many times - Store count in a variable or
DATAitself:
10 DATA 5: REM COUNT
20 READ N
30 FOR I=1 TO N
40 READ A
50 PRINT A
60 NEXT I
70 DATA 10,20,30,40,50
?DIVISION BY ZERO ERROR
Cause: Attempted to divide by zero (mathematically undefined).
{
"description": "Division by zero",
"program": "10 A=10\n20 B=0\n30 C=A/B\n40 PRINT C"
}
{
"description": "Division by zero in loop",
"program": "10 FOR I=5 TO 0 STEP -1\n20 PRINT 100/I\n30 NEXT I"
}
Why it failed: When I reaches 0, 100/I tries to divide by zero.
How to fix:
{
"description": "Preventing division by zero",
"program": "10 INPUT \"DIVIDEND\";A\n20 INPUT \"DIVISOR\";B\n30 IF B=0 THEN PRINT \"CANNOT DIVIDE BY ZERO\":GOTO 20\n40 PRINT A/B"
}
Prevention:
- Always check divisor ≠ 0 before dividing
- Especially important with user input
- In loops, ensure counter never reaches zero if used as divisor
?OVERFLOW ERROR
Cause: Number too large for BASIC to represent.
Limits:
- Floating-point: approximately ±1.7 × 10³⁸
- Integer: -32768 to 32767
{
"description": "Overflow error - exponential growth",
"program": "10 A=1E30\n20 B=A*A\n30 PRINT B"
}
{
"description": "Overflow error - integer multiplication",
"program": "10 A%=30000\n20 B%=2\n30 C%=A%*B%\n40 PRINT C%"
}
Why it failed: 30000 × 2 = 60000, exceeds integer range (32767).
How to fix:
- Use regular floats instead of integers for large numbers
- Break calculations into smaller steps
- Check intermediate results
{
"description": "Preventing overflow with floats",
"program": "10 A=30000: REM FLOAT, NOT INTEGER\n20 B=2\n30 C=A*B\n40 PRINT C"
}
Prevention:
- Be aware of numeric limits
- Use appropriate variable types (float vs integer)
- Validate input ranges
?OUT OF MEMORY ERROR
Cause: Program exhausted available memory.
Triggers:
- Very large arrays
- Too many variables
- Extremely long program
- String accumulation in loops
{
"description": "Out of memory - large array",
"program": "10 DIM A(50000)"
}
How to fix:
- Reduce array sizes
- Delete unused variables with
CLR - Simplify program structure
- Break into smaller programs
- Use
FRE(0)to check available memory
Prevention:
10 PRINT "FREE:";FRE(0);"BYTES"
20 INPUT "ARRAY SIZE";N
30 IF N*2>FRE(0) THEN PRINT "TOO LARGE":GOTO 20
40 DIM A(N)
?SUBSCRIPT OUT OF RANGE ERROR
Cause: Array accessed with index outside declared dimensions.
{
"description": "Subscript out of range",
"program": "10 DIM A(10)\n20 A(15)=100\n30 PRINT A(15)"
}
Why it failed: Array A declared with size 10 (indices 0-10), but line 20 tries to access index 15.
{
"description": "Subscript out of range - negative",
"program": "10 DIM B(5)\n20 PRINT B(-1)"
}
How to fix:
Option 1: Use valid indices
10 DIM A(10)
20 A(10)=100 : REM Valid: 0-10
Option 2: Increase array size
10 DIM A(20) : REM Now 0-20 are valid
20 A(15)=100
Option 3: Add bounds checking
{
"description": "Preventing subscript errors",
"program": "10 DIM A(10)\n20 INPUT \"INDEX\";I\n30 IF I<0 OR I>10 THEN PRINT \"INVALID\":GOTO 20\n40 A(I)=I*10\n50 PRINT \"A(\";I;\")=\";A(I)"
}
Prevention:
- Remember arrays are zero-based:
DIM A(10)gives 0-10 (11 elements) - Always validate indices before use
- Especially important with user input or calculated indices
Logic Errors
Logic errors stem from incorrect program control flow—mismatched loops, unbalanced subroutines, wrong data types.
?NEXT WITHOUT FOR ERROR
Cause: NEXT encountered without matching FOR.
{
"description": "NEXT without FOR",
"program": "10 I=1\n20 PRINT I\n30 NEXT I"
}
Why it failed: Line 30 tries to close a loop, but no FOR opened it.
{
"description": "Mismatched loop variable",
"program": "10 FOR I=1 TO 5\n20 PRINT I\n30 NEXT J"
}
Why it failed: Loop uses I, but NEXT closes J.
How to fix:
Correct form:
{
"description": "Properly matched FOR...NEXT",
"program": "10 FOR I=1 TO 5\n20 PRINT I\n30 NEXT I"
}
Nested loops:
{
"description": "Correctly nested loops",
"program": "10 FOR I=1 TO 3\n20 FOR J=1 TO 3\n30 PRINT I;J\n40 NEXT J\n50 NEXT I"
}
Prevention:
- Every
FORneeds exactly one matchingNEXT - Loop variables must match:
FOR I→NEXT I - Nest loops properly (inner closes before outer)
- Use indentation (mental model) to track nesting
?RETURN WITHOUT GOSUB ERROR
Cause: RETURN executed without preceding GOSUB.
{
"description": "RETURN without GOSUB",
"program": "10 PRINT \"START\"\n20 RETURN\n30 PRINT \"END\""
}
Why it failed: Line 20 tries to return from a subroutine, but none was called.
{
"description": "Incorrect program flow",
"program": "10 GOTO 100\n20 PRINT \"DONE\"\n30 END\n100 PRINT \"SUBROUTINE\"\n110 RETURN"
}
Why it failed: GOTO 100 jumps to the subroutine, but subroutines should be called with GOSUB, not GOTO.
How to fix:
Correct subroutine usage:
{
"description": "Proper GOSUB...RETURN",
"program": "10 GOSUB 100\n20 PRINT \"DONE\"\n30 END\n100 PRINT \"SUBROUTINE\"\n110 RETURN"
}
Multiple calls:
{
"description": "Multiple GOSUB calls",
"program": "10 GOSUB 100\n20 GOSUB 100\n30 GOSUB 100\n40 END\n100 PRINT \"CALLED\"\n110 RETURN"
}
Prevention:
- Use
GOSUBto call subroutines, notGOTO - Every subroutine needs exactly one
RETURN - Don't
GOTOinto the middle of a subroutine - End main program with
ENDbefore subroutines start
Standard structure:
10 REM MAIN PROGRAM
20 GOSUB 1000: REM CALL SUBROUTINE
30 PRINT "BACK IN MAIN"
40 END
1000 REM SUBROUTINE STARTS HERE
1010 PRINT "IN SUBROUTINE"
1020 RETURN
?TYPE MISMATCH ERROR
Cause: Operation expects one type (number or string) but got the other.
{
"description": "Type mismatch - string as number",
"program": "10 A$=\"HELLO\"\n20 B=A$+5\n30 PRINT B"
}
Why it failed: Can't add string to number.
{
"description": "Type mismatch - number as string",
"program": "10 A=123\n20 B$=LEFT$(A,2)\n30 PRINT B$"
}
Why it failed: LEFT$ expects a string, but A is numeric.
{
"description": "Type mismatch - wrong variable type",
"program": "10 INPUT \"NAME\";N\n20 PRINT \"HELLO \";N"
}
Why it failed: N is numeric variable, but user likely entered a string name.
How to fix:
Use correct types:
{
"description": "Correct type usage",
"program": "10 A$=\"HELLO\"\n20 B$=A$+\" WORLD\"\n30 PRINT B$"
}
{
"description": "String variable for name",
"program": "10 INPUT \"NAME\";N$\n20 PRINT \"HELLO \";N$"
}
Convert between types:
{
"description": "Type conversion",
"program": "10 A$=\"123\"\n20 B=VAL(A$)+5\n30 PRINT \"RESULT:\";B\n40 C$=STR$(B)\n50 PRINT \"AS STRING:\";C$"
}
Prevention:
- Use
$suffix for strings:N$,NAME$,TEXT$ - Use
%suffix for integers:COUNT%,INDEX% - No suffix for regular numbers:
X,TOTAL,PRICE - Use
VAL()to convert string → number - Use
STR$()to convert number → string
File Operation Errors
Errors related to SAVE and LOAD commands.
?FILE NOT FOUND ERROR
Cause: LOAD tried to read a file that doesn't exist in storage.
{
"description": "File not found",
"program": "LOAD \"NONEXISTENT\""
}
Common causes:
- Filename misspelled
- File never saved
- File saved in different browser/device
- Browser storage cleared
How to fix:
- Check spelling carefully (case-sensitive on some systems)
- Verify file was saved successfully
- Try alternative filename
- Recreate the program if lost
Prevention:
- Use consistent, memorable filenames
- Save immediately after writing programs
- Save multiple versions:
"GAME-V1","GAME-V2","GAME-V3" - Test
LOADafterSAVEto verify it worked
?SAVE ERROR
Cause: SAVE failed to write file to storage.
Common causes:
- Storage quota exceeded (5-10 MB browser limit)
- Browser denied storage permission
- Private/incognito mode (no persistent storage)
- Storage corruption
{
"description": "Save with valid filename",
"program": "10 PRINT \"TEST PROGRAM\"\nSAVE \"VALIDTEST\""
}
How to fix:
- Check
FRE(0)to ensure program isn't too large - Clear browser storage (Settings → Clear Data)
- Exit private/incognito mode
- Try shorter filename
- Use different browser
Prevention:
- Save frequently during development
- Monitor storage usage
- Use descriptive but short filenames
- Don't develop in incognito mode
- Keep backup exports of important programs
?LOAD ERROR
Cause: File found but couldn't be loaded (corrupted or wrong format).
Common causes:
- File corrupted
- Not a valid BASIC program file
- Storage corruption
- Manual editing broke format
How to fix:
- Try loading different file to test system
- Clear browser cache
- Rewrite program from scratch if unrecoverable
- Check browser console for detailed error
Prevention:
- Don't manually edit files in browser storage
- Save backups before making major changes
- Test
LOADperiodically to catch corruption early
Debugging Techniques
Error messages tell you what went wrong. Debugging techniques help you find why and fix it.
Technique 1: Read the Error Message
Don't skip this step! The error message is precise:
?NEXT WITHOUT FOR ERROR IN 250
Tells you:
- What:
NEXTwithout matchingFOR - Where: Line 250
Use this information:
LIST 250
See the problem immediately.
Technique 2: LIST Around the Error
{
"description": "Using LIST to debug",
"program": "10 FOR I=1 TO 5\n20 PRINT I\n30 NEXT J\n40 PRINT \"DONE\""
}
Error says line 30. Use:
LIST 10-40
See the context: loop starts with I, closes with J. Mismatch found.
Technique 3: PRINT Variable Values
When logic is wrong but no error appears:
{
"description": "Debugging with PRINT",
"program": "10 A=5\n20 B=10\n30 C=A+B\n40 PRINT \"A=\";A;\"B=\";B;\"C=\";C\n50 IF C=20 THEN PRINT \"CORRECT\""
}
Insert PRINT statements to see values at each step. Find where expectations diverge from reality.
Technique 4: REM Out Code Sections
{
"description": "Commenting out code",
"program": "10 PRINT \"SECTION 1\"\n20 REM GOSUB 100\n30 PRINT \"SECTION 2\"\n40 REM GOSUB 200\n50 PRINT \"DONE\"\n60 END\n100 PRINT \"SUB 1\":RETURN\n200 PRINT \"SUB 2\":RETURN"
}
If program crashes, comment out sections with REM to isolate the problem:
- Does it work without subroutine 100?
- Does it work without subroutine 200?
- Narrow down to exact problematic line
Technique 5: Simplify and Test
Break complex lines into simple steps:
Complex (hard to debug):
10 X=(A+B)/(C-D)+SQR(E*F)
Simplified (easy to debug):
10 T1=A+B
15 PRINT "SUM:";T1
20 T2=C-D
25 PRINT "DIFF:";T2
30 T3=T1/T2
35 PRINT "QUOT:";T3
40 T4=E*F
45 PRINT "PROD:";T4
50 T5=SQR(T4)
55 PRINT "ROOT:";T5
60 X=T3+T5
70 PRINT "RESULT:";X
Each step is visible. Find errors immediately.
Technique 6: Test Incrementally
Don't write entire program then test it. Test as you build:
- Write 5-10 lines
RUNto test- Fix any errors
- Add 5-10 more lines
RUNagain- Repeat
Errors caught early are easy to fix. Errors found after writing 200 lines are nightmares.
Technique 7: Use the Immediate Mode
Test code fragments before adding them to programs:
PRINT 100/5
FOR I=1 TO 3:PRINT I:NEXT I
A$="TEST":PRINT LEFT$(A$,2)
If it works in immediate mode, it'll work in a program. If it fails in immediate mode, fix it before adding to your program.
Technique 8: Check Bounds and Ranges
Many errors stem from values outside expected ranges:
{
"description": "Bounds checking",
"program": "10 DIM A(10)\n20 INPUT \"INDEX (0-10)\";I\n30 IF I<0 OR I>10 THEN PRINT \"OUT OF RANGE\":GOTO 20\n40 INPUT \"VALUE\";V\n50 A(I)=V\n60 PRINT \"STORED\";V;\"AT INDEX\";I"
}
Always validate:
- Array indices
- Loop counters
- User input
- Calculated values
Technique 9: Rubber Duck Debugging
Explain your code to someone (or something—a rubber duck works):
"This line reads a number. Then this line divides by it. Oh wait—what if the number is zero? That would cause division by zero!"
Speaking aloud forces you to think through logic step-by-step. You'll often find your own bugs this way.
Technique 10: Start Fresh
If you're stuck:
- Save current program:
SAVE "BROKEN" NEW- Rewrite the problematic section from scratch
- Test it in isolation
- Once working, integrate back into main program
Sometimes a fresh perspective reveals obvious mistakes.
Systematic Debugging Process
When faced with a bug:
- Reproduce reliably — Can you make it happen consistently?
- Isolate — Which line/section causes it?
- Understand — What is the code supposed to do vs what it's doing?
- Hypothesize — What might be wrong?
- Test — Try a fix
- Verify — Does it work now? Try edge cases.
Don't guess randomly. Follow this process methodically.
Common Beginner Mistakes
Mistake 1: Not reading error messages
- Wrong: "It's broken. Let me change random things."
- Right: "?DIVISION BY ZERO ERROR IN 150. Let me LIST 150."
Mistake 2: Testing too late
- Wrong: Write 200 lines, then test
- Right: Test every 5-10 lines
Mistake 3: No variable inspection
- Wrong: "Why isn't this working?"
- Right:
PRINT A,B,C— "Oh, B is zero!"
Mistake 4: Ignoring edge cases
- Wrong: "It works with input 5."
- Right: "Does it work with 0? With -1? With 9999?"
Mistake 5: Complex code without understanding
- Wrong: Copy complex code, hope it works
- Right: Understand every line before using it
Error Prevention Checklist
Before running any program:
✓ Syntax
- All keywords spelled correctly?
- All parentheses matched?
- All quotes closed?
- Variable types consistent ($, %, none)?
✓ Logic
- Every
FORhas matchingNEXT? - Every
GOSUBhas matchingRETURN? - Every
IFhas properTHEN? - Loop counters don't go out of bounds?
✓ Data
- Enough
DATAfor allREADs? - Arrays dimensioned large enough?
- Division denominators never zero?
- String operations on strings, math on numbers?
✓ Flow
- Main program ends with
END? - Can't "fall through" into subroutines?
- All
GOTO/GOSUBtargets exist?
Use this checklist, and 90% of errors disappear before they happen.
When All Else Fails
- Take a break — Fresh eyes see bugs instantly
- Ask for help — Explain code to someone
- Search documentation — Re-read the manual
- Simplify — Make smallest possible program that demonstrates bug
- Start over — Sometimes faster than debugging
Programming is problem-solving. Every error is a puzzle. You have all the tools to solve it.
Errors aren't obstacles. They're instructions. Follow them.
Example Programs
Introduction
The best way to learn programming is by studying working code. This chapter presents ten complete, tested programs that demonstrate the concepts you've learned. Each program is designed to be:
- Complete: Ready to type and run without modification
- Practical: Solves a real problem or creates something useful
- Educational: Demonstrates specific programming techniques
- Extensible: Includes suggestions for improvement and customization
These aren't toy examples—they're real programs that do real things. Study them, type them, run them, modify them, and make them your own. That's how you become a programmer.
Type these programs yourself rather than copying and pasting. The act of typing helps you internalize the patterns and syntax. You'll make mistakes, fix them, and learn from the process. That's programming.
Each program includes:
- Complete source code with line numbers and comments
- Explanation of how it works and why
- Sample output showing what you'll see
- Modifications you can make to learn more
- Interactive demo you can run immediately
Work through these programs in order. They build on each other, starting simple and growing more complex. By program #10, you'll be handling sophisticated algorithms with confidence.
Program 1: Hello World
Every programming journey starts here. This is the traditional first program—simple, but it establishes the fundamental pattern: write code, run it, see results.
The Program
<BasicCode>
10 REM *** HELLO WORLD ***
20 REM DEMONSTRATES: BASIC STRUCTURE, PRINT, END
30 REM
40 PRINT "HELLO, WORLD!"
50 PRINT "WELCOME TO SLP-BASIC V1.2"
60 PRINT
70 PRINT "THIS IS YOUR FIRST PROGRAM."
80 PRINT "GREAT JOB!"
90 END
</BasicCode>
How It Works
Lines 10-30: Comments explaining what the program does. Use REM statements to document your code. Future you (and other programmers) will appreciate it.
Lines 40-80: PRINT statements display text. Each PRINT moves to a new line unless you use a semicolon at the end.
Line 90: END terminates the program gracefully. While optional (the program stops at the last line anyway), it's good practice to explicitly mark where your program ends.
Sample Output
HELLO, WORLD!
WELCOME TO SLP-BASIC V1.2
THIS IS YOUR FIRST PROGRAM.
GREAT JOB!
READY.
What You're Learning
- Program structure: Line numbers, comments, statements
- PRINT statement: Basic output
- END statement: Proper program termination
- Blank lines: Using PRINT alone for spacing
Modifications to Try
- Add your name: Change line 40 to
PRINT "HELLO, [YOUR NAME]!" - More messages: Add line 85:
PRINT "PROGRAMMING IS FUN!" - ASCII art: Create a simple border using dashes or asterisks
- Multiple blanks: Add
PRINTon several lines to create more spacing
Exercise
Create a "About Me" program that displays:
- Your name
- Your age
- Your favorite hobby
- A fun fact about yourself
Use the Hello World program as a template. Add blank lines for readability and end with a friendly message.
Program 2: Number Guessing Game
Now we add interactivity and logic. The computer picks a random number, and you try to guess it. This demonstrates loops, conditionals, input, and random numbers—the building blocks of most games.
The Program
<BasicCode>
10 REM *** NUMBER GUESSING GAME ***
20 REM DEMONSTRATES: RND, INPUT, IF/THEN, FOR LOOP
30 REM
40 PRINT "I'M THINKING OF A NUMBER FROM 1 TO 100"
50 PRINT
60 REM GENERATE RANDOM NUMBER
70 NUMBER = INT(RND(1) * 100) + 1
80 TRIES = 0
90 REM
100 REM MAIN GAME LOOP
110 INPUT "YOUR GUESS"; GUESS
120 TRIES = TRIES + 1
130 REM
140 IF GUESS = NUMBER THEN GOTO 200
150 IF GUESS < NUMBER THEN PRINT "TOO LOW!"
160 IF GUESS > NUMBER THEN PRINT "TOO HIGH!"
170 GOTO 110
180 REM
190 REM PLAYER WON
200 PRINT "CORRECT! YOU GOT IT IN"; TRIES; "TRIES!"
210 PRINT
220 INPUT "PLAY AGAIN? (Y/N)"; A$
230 IF A$ = "Y" OR A$ = "y" THEN GOTO 40
240 PRINT "THANKS FOR PLAYING!"
250 END
</BasicCode>
How It Works
Line 70: INT(RND(1) * 100) + 1 generates a random integer from 1 to 100:
RND(1)returns a decimal from 0 to 0.999...- Multiply by 100: gives 0 to 99.999...
INT()truncates to whole number: 0 to 99- Add 1: shifts range to 1 to 100
Line 80: Initialize tries counter to zero.
Line 110: Get player's guess. INPUT automatically converts text to number.
Line 120: Increment tries counter.
Lines 140-160: Check guess against number:
- Equal? Jump to winning message (line 200)
- Too low? Print hint
- Too high? Print hint
Line 170: Loop back to get another guess (GOTO 110).
Line 200: Victory! Show how many tries it took.
Lines 220-230: Ask to play again. If yes, GOTO 40 to restart (new random number).
Sample Output
I'M THINKING OF A NUMBER FROM 1 TO 100
YOUR GUESS? 50
TOO HIGH!
YOUR GUESS? 25
TOO LOW!
YOUR GUESS? 37
TOO HIGH!
YOUR GUESS? 31
TOO LOW!
YOUR GUESS? 34
CORRECT! YOU GOT IT IN 5 TRIES!
PLAY AGAIN? (Y/N)? N
THANKS FOR PLAYING!
READY.
What You're Learning
- Random numbers:
RND(1)for random values - Input validation: Getting user guesses
- Conditional logic: IF/THEN for game rules
- Loops: GOTO for repeating gameplay
- Counters: Tracking attempts
- String comparison: Checking Y/N answers
Modifications to Try
- Difficulty levels: Ask user for range (1-10, 1-50, 1-1000)
- Guess limit: Give player only 7 tries before game over
- Hints: Add "getting warmer" or "getting colder" messages
- High score: Track and display best (lowest) number of tries
- Better input: Use
GETinstead ofINPUTfor Y/N prompt
Exercise
Add a "quit" option: if player types 0 as guess, end the game immediately without counting it as a try.
Hint: Add after line 120:
125 IF GUESS = 0 THEN PRINT "QUITTER!": GOTO 240
Program 3: Fibonacci Sequence
The Fibonacci sequence (0, 1, 1, 2, 3, 5, 8, 13...) is a classic programming challenge. Each number is the sum of the previous two. This program demonstrates arrays, loops, and mathematical sequences.
The Program
<BasicCode>
10 REM *** FIBONACCI SEQUENCE ***
20 REM DEMONSTRATES: ARRAYS, FOR LOOPS, DIM
30 REM
40 PRINT "FIBONACCI SEQUENCE GENERATOR"
50 PRINT "============================"
60 PRINT
70 INPUT "HOW MANY NUMBERS"; N
80 IF N < 1 OR N > 20 THEN PRINT "ENTER 1-20": GOTO 70
90 REM
100 REM DECLARE ARRAY
110 DIM FIB(20)
120 REM
130 REM INITIALIZE FIRST TWO VALUES
140 FIB(0) = 0
150 FIB(1) = 1
160 REM
170 REM CALCULATE SEQUENCE
180 FOR I = 2 TO N - 1
190 FIB(I) = FIB(I-1) + FIB(I-2)
200 NEXT I
210 REM
220 REM DISPLAY RESULTS
230 PRINT
240 PRINT "FIRST"; N; "FIBONACCI NUMBERS:"
250 PRINT
260 FOR I = 0 TO N - 1
270 PRINT "F("; I; ") ="; FIB(I)
280 NEXT I
290 END
</BasicCode>
How It Works
Line 110: Declare array with DIM. Arrays in BASIC start at index 0, so DIM FIB(20) creates 21 storage locations: FIB(0) through FIB(20).
Lines 140-150: Set the first two Fibonacci numbers manually. By definition, F(0)=0 and F(1)=1.
Lines 180-200: Calculate remaining numbers. Each number is the sum of the previous two:
- F(2) = F(1) + F(0) = 1 + 0 = 1
- F(3) = F(2) + F(1) = 1 + 1 = 2
- F(4) = F(3) + F(2) = 2 + 1 = 3
- And so on...
Lines 260-280: Display all calculated values in a formatted list.
Sample Output
FIBONACCI SEQUENCE GENERATOR
============================
HOW MANY NUMBERS? 10
FIRST 10 FIBONACCI NUMBERS:
F( 0 ) = 0
F( 1 ) = 1
F( 2 ) = 1
F( 3 ) = 2
F( 4 ) = 3
F( 5 ) = 5
F( 6 ) = 8
F( 7 ) = 13
F( 8 ) = 21
F( 9 ) = 34
READY.
What You're Learning
- Arrays: Storing multiple related values
- DIM statement: Declaring array size
- Array indexing: Accessing elements with subscripts
- FOR loops: Iterating through sequences
- Input validation: Checking range (1-20)
- Mathematical sequences: Building values from previous values
Modifications to Try
- Larger sequences: Increase limit to 30 (watch for overflow around F(46))
- Ratios: Calculate and display ratio of consecutive numbers (approaches golden ratio φ ≈ 1.618)
- Sum: Add line to calculate and display sum of all Fibonacci numbers
- Formatted output: Use TAB() to align numbers in columns
- Graph: Display simple bar chart using asterisks proportional to value
Exercise
Modify the program to show only Fibonacci numbers less than 1000. Remove the "how many" input and instead keep generating until the next number would exceed 1000.
Hint: Replace the FOR loop with a WHILE-style loop:
170 I = 2
180 IF FIB(I-1) + FIB(I-2) > 1000 THEN GOTO 220
190 FIB(I) = FIB(I-1) + FIB(I-2)
200 I = I + 1
210 GOTO 180
Program 4: Prime Number Finder
Prime numbers are integers greater than 1 that have no divisors except 1 and themselves. This program finds all primes up to a given limit using nested loops and the classic trial division algorithm.
The Program
<BasicCode>
10 REM *** PRIME NUMBER FINDER ***
20 REM DEMONSTRATES: NESTED LOOPS, INT, SQR, BOOLEAN FLAGS
30 REM
40 PRINT "PRIME NUMBER FINDER"
50 PRINT "==================="
60 PRINT
70 INPUT "FIND PRIMES UP TO WHAT NUMBER"; LIMIT
80 IF LIMIT < 2 THEN PRINT "MUST BE AT LEAST 2": GOTO 70
90 REM
100 PRINT
110 PRINT "PRIME NUMBERS UP TO"; LIMIT; ":"
120 PRINT
130 COUNT = 0
140 REM
150 REM CHECK EACH NUMBER
160 FOR N = 2 TO LIMIT
170 REM ASSUME IT'S PRIME UNTIL PROVEN OTHERWISE
180 ISPRIME = 1
190 REM
200 REM TEST DIVISORS UP TO SQUARE ROOT
210 FOR D = 2 TO INT(SQR(N))
220 IF N / D = INT(N / D) THEN ISPRIME = 0
230 IF ISPRIME = 0 THEN GOTO 260
240 NEXT D
250 REM
260 REM IF STILL PRIME, PRINT IT
270 IF ISPRIME = 1 THEN PRINT N; : COUNT = COUNT + 1
280 NEXT N
290 REM
300 PRINT
310 PRINT
320 PRINT "FOUND"; COUNT; "PRIMES"
330 END
</BasicCode>
How It Works
Line 180: Assume number is prime (ISPRIME = 1 means true). We'll disprove this if we find a divisor.
Line 210: Only need to test divisors up to square root of N. If N has a factor greater than √N, it must also have one less than √N.
Line 220: Check if D divides N evenly. If N / D equals INT(N / D), there's no remainder, so D is a factor.
Line 230: If we found a factor, no need to keep checking—break out of inner loop.
Line 270: If we didn't find any factors (ISPRIME = 1), print the number. Use semicolon to keep output on same line.
Line 320: Display count of primes found.
Sample Output
PRIME NUMBER FINDER
===================
FIND PRIMES UP TO WHAT NUMBER? 50
PRIME NUMBERS UP TO 50 :
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47
FOUND 15 PRIMES
READY.
What You're Learning
- Nested loops: FOR loop inside another FOR loop
- Boolean flags: Using 1/0 as true/false
- Optimization: Testing only up to square root
- Early exit: Breaking out of loop when done
- Trial division: Classic primality test algorithm
- Formatted output: Using semicolon to keep numbers on one line
Modifications to Try
- Formatted columns: Print 10 primes per line using POS(0)
- Time it: Add delay loop to show algorithm in action
- Twin primes: Find prime pairs (p, p+2) like 11,13 or 17,19
- Sieve of Eratosthenes: Implement faster algorithm using arrays
- Factorization: For non-primes, show their prime factors
Exercise
Modify the program to find the first N primes (instead of primes up to N). Ask user "HOW MANY PRIMES?" and keep searching until you've found that many.
Hint: Change line 160 to:
160 N = 2
And add after line 280:
285 IF COUNT >= LIMIT THEN GOTO 300
287 N = N + 1
288 GOTO 170
Program 5: Temperature Converter
A practical utility that converts between Fahrenheit and Celsius. This demonstrates user-defined functions, input validation, and menu-driven programs.
The Program
<BasicCode>
10 REM *** TEMPERATURE CONVERTER ***
20 REM DEMONSTRATES: DEF FN, MENU, ON GOTO, INPUT VALIDATION
30 REM
40 REM DEFINE CONVERSION FUNCTIONS
50 DEF FN F2C(F) = (F - 32) * 5 / 9
60 DEF FN C2F(C) = C * 9 / 5 + 32
70 REM
80 REM MAIN MENU
90 PRINT "TEMPERATURE CONVERTER"
100 PRINT "====================="
110 PRINT
120 PRINT "1. FAHRENHEIT TO CELSIUS"
130 PRINT "2. CELSIUS TO FAHRENHEIT"
140 PRINT "3. QUIT"
150 PRINT
160 INPUT "YOUR CHOICE (1-3)"; CHOICE
170 IF CHOICE < 1 OR CHOICE > 3 THEN GOTO 160
180 ON CHOICE GOTO 200, 300, 900
190 REM
200 REM FAHRENHEIT TO CELSIUS
210 PRINT
220 INPUT "ENTER TEMPERATURE IN F"; TEMP
230 RESULT = FN F2C(TEMP)
240 PRINT TEMP; "F ="; INT(RESULT * 10 + 0.5) / 10; "C"
250 GOTO 400
260 REM
300 REM CELSIUS TO FAHRENHEIT
310 PRINT
320 INPUT "ENTER TEMPERATURE IN C"; TEMP
330 RESULT = FN C2F(TEMP)
340 PRINT TEMP; "C ="; INT(RESULT * 10 + 0.5) / 10; "F"
350 GOTO 400
360 REM
400 REM CONTINUE OR QUIT
410 PRINT
420 INPUT "ANOTHER CONVERSION? (Y/N)"; A$
430 IF A$ = "Y" OR A$ = "y" THEN GOTO 90
440 REM
900 REM QUIT
910 PRINT "GOODBYE!"
920 END
</BasicCode>
How It Works
Lines 50-60: User-defined functions using DEF FN:
FN F2C(F): Fahrenheit to Celsius formula: (F - 32) × 5/9FN C2F(C): Celsius to Fahrenheit formula: C × 9/5 + 32
Line 180: ON CHOICE GOTO is computed branching—jumps to different lines based on value:
- If CHOICE=1, GOTO 200 (F to C)
- If CHOICE=2, GOTO 300 (C to F)
- If CHOICE=3, GOTO 900 (Quit)
Lines 240, 340: Round result to 1 decimal place:
- Multiply by 10, add 0.5 (for rounding), use INT(), divide by 10
- Example: 23.67 → 236.7 → 237.2 → 237 → 23.7
Sample Output
TEMPERATURE CONVERTER
=====================
1. FAHRENHEIT TO CELSIUS
2. CELSIUS TO FAHRENHEIT
3. QUIT
YOUR CHOICE (1-3)? 1
ENTER TEMPERATURE IN F? 98.6
98.6 F = 37 C
ANOTHER CONVERSION? (Y/N)? Y
TEMPERATURE CONVERTER
=====================
1. FAHRENHEIT TO CELSIUS
2. CELSIUS TO FAHRENHEIT
3. QUIT
YOUR CHOICE (1-3)? 2
ENTER TEMPERATURE IN C? 100
100 C = 212 F
ANOTHER CONVERSION? (Y/N)? N
GOODBYE!
READY.
What You're Learning
- DEF FN: Creating custom functions
- Menu systems: Numbered choices
- ON GOTO: Computed branching
- Input validation: Checking choice range
- Rounding: Displaying decimal places
- Program flow: Returning to menu vs exiting
Modifications to Try
- Kelvin: Add third temperature scale (K = C + 273.15)
- Batch mode: Accept multiple temperatures in one session
- Table: Print conversion table (e.g., 0F to 100F in 10-degree steps)
- Reference points: Show water freezing/boiling points
- Input validation: Reject temperatures below absolute zero
Exercise
Add a "common temperatures" reference table:
145 PRINT "4. SHOW REFERENCE TABLE"
And implement it:
500 REM REFERENCE TABLE
510 PRINT
520 PRINT "TEMPERATURE REFERENCE"
530 PRINT "--------------------"
540 PRINT "WATER FREEZES:", "32F", "0C"
550 PRINT "ROOM TEMP:", "68F", "20C"
560 PRINT "BODY TEMP:", "98.6F", "37C"
570 PRINT "WATER BOILS:", "212F", "100C"
580 GOTO 400
Program 6: Simple Calculator
A basic four-function calculator with a menu interface. This demonstrates GOSUB/RETURN for subroutines, making code more organised and reusable.
The Program
<BasicCode>
10 REM *** SIMPLE CALCULATOR ***
20 REM DEMONSTRATES: GOSUB/RETURN, SUBROUTINES, MENUS
30 REM
40 REM MAIN MENU
50 PRINT "CALCULATOR"
60 PRINT "=========="
70 PRINT
80 PRINT "1. ADD"
90 PRINT "2. SUBTRACT"
100 PRINT "3. MULTIPLY"
110 PRINT "4. DIVIDE"
120 PRINT "5. QUIT"
130 PRINT
140 INPUT "OPERATION (1-5)"; OP
150 IF OP < 1 OR OP > 5 THEN GOTO 140
160 IF OP = 5 THEN GOTO 900
170 REM
180 REM GET NUMBERS
190 GOSUB 1000
200 REM
210 REM PERFORM OPERATION
220 ON OP GOSUB 2000, 2100, 2200, 2300
230 REM
240 REM SHOW RESULT
250 GOSUB 3000
260 GOTO 50
270 REM
900 REM QUIT
910 PRINT "GOODBYE!"
920 END
990 REM
1000 REM SUBROUTINE: GET INPUT
1010 PRINT
1020 INPUT "FIRST NUMBER"; A
1030 INPUT "SECOND NUMBER"; B
1040 RETURN
1090 REM
2000 REM SUBROUTINE: ADD
2010 RESULT = A + B
2020 OP$ = "+"
2030 RETURN
2090 REM
2100 REM SUBROUTINE: SUBTRACT
2110 RESULT = A - B
2120 OP$ = "-"
2130 RETURN
2190 REM
2200 REM SUBROUTINE: MULTIPLY
2210 RESULT = A * B
2220 OP$ = "*"
2230 RETURN
2290 REM
2300 REM SUBROUTINE: DIVIDE
2310 IF B = 0 THEN PRINT "ERROR: DIVISION BY ZERO": RETURN
2320 RESULT = A / B
2330 OP$ = "/"
2340 RETURN
2390 REM
3000 REM SUBROUTINE: DISPLAY RESULT
3010 PRINT
3020 PRINT A; OP$; B; "="; RESULT
3030 PRINT
3040 RETURN
</BasicCode>
How It Works
Line 190: GOSUB 1000 calls the input subroutine. Execution jumps to line 1000, runs until RETURN, then comes back to line 200.
Line 220: ON OP GOSUB calls different operation subroutines based on choice:
- OP=1: GOSUB 2000 (Add)
- OP=2: GOSUB 2100 (Subtract)
- OP=3: GOSUB 2200 (Multiply)
- OP=4: GOSUB 2300 (Divide)
Subroutine structure: Each subroutine:
- Performs its specific operation
- Stores result in RESULT variable
- Sets OP$ to operator symbol
- Returns to caller with RETURN
Line 2310: Division by zero check. If B=0, print error and return immediately without calculating.
Sample Output
CALCULATOR
==========
1. ADD
2. SUBTRACT
3. MULTIPLY
4. DIVIDE
5. QUIT
OPERATION (1-5)? 1
FIRST NUMBER? 15
SECOND NUMBER? 27
15 + 27 = 42
CALCULATOR
==========
1. ADD
2. SUBTRACT
3. MULTIPLY
4. DIVIDE
5. QUIT
OPERATION (1-5)? 4
FIRST NUMBER? 100
SECOND NUMBER? 0
ERROR: DIVISION BY ZERO
CALCULATOR
==========
...
What You're Learning
- GOSUB/RETURN: Calling and returning from subroutines
- Code organization: Separating logic into reusable blocks
- ON GOSUB: Computed subroutine calls
- Error handling: Checking for division by zero
- Variable scope: Variables persist across subroutine calls
- Menu loops: Returning to main menu after each operation
Modifications to Try
- More operations: Add power (^), square root, modulo
- Memory: Add M+, M-, MR (memory recall) buttons
- History: Store last 10 calculations in array
- Chain operations: Use previous result as first number of next operation
- Parentheses: Implement expression parsing
Exercise
Add a "percentage" operation: calculate what percent A is of B.
Add to menu:
115 PRINT "6. PERCENT"
Add subroutine:
2400 REM SUBROUTINE: PERCENT
2410 IF B = 0 THEN PRINT "ERROR: DIVISION BY ZERO": RETURN
2420 RESULT = (A / B) * 100
2430 OP$ = "% OF"
2440 RETURN
Update line 220:
220 ON OP GOSUB 2000, 2100, 2200, 2300, 0, 2400
Program 7: Multiplication Tables
Generate formatted multiplication tables with precise alignment using nested FOR loops and TAB positioning.
The Program
<BasicCode>
10 REM *** MULTIPLICATION TABLES ***
20 REM DEMONSTRATES: NESTED FOR LOOPS, TAB, FORMATTING
30 REM
40 PRINT "MULTIPLICATION TABLE GENERATOR"
50 PRINT "=============================="
60 PRINT
70 INPUT "WHICH TABLE (1-12)"; TABLE
80 IF TABLE < 1 OR TABLE > 12 THEN GOTO 70
90 PRINT
100 REM
110 REM PRINT TABLE HEADER
120 PRINT TABLE; "TIMES TABLE"
130 PRINT STRING$(20, "-")
140 REM
150 REM PRINT EACH ROW
160 FOR I = 1 TO 12
170 RESULT = TABLE * I
180 PRINT TAB(2); TABLE; "X"; I; "="; TAB(15); RESULT
190 NEXT I
200 PRINT
210 REM
220 REM OFFER ANOTHER TABLE
230 INPUT "ANOTHER TABLE? (Y/N)"; A$
240 IF A$ = "Y" OR A$ = "y" THEN GOTO 40
250 PRINT
260 REM
270 REM BONUS: SHOW COMPLETE TABLE
280 PRINT "WOULD YOU LIKE TO SEE THE COMPLETE"
290 INPUT "1-12 MULTIPLICATION TABLE? (Y/N)"; A$
300 IF A$ <> "Y" AND A$ <> "y" THEN GOTO 900
310 PRINT
320 GOSUB 1000
330 REM
900 PRINT "GOODBYE!"
910 END
990 REM
1000 REM SUBROUTINE: COMPLETE TABLE
1010 PRINT "COMPLETE MULTIPLICATION TABLE"
1020 PRINT STRING$(40, "=")
1030 PRINT
1040 REM PRINT COLUMN HEADERS
1050 PRINT TAB(4);
1060 FOR C = 1 TO 12
1070 PRINT TAB(4 + C * 4); C;
1080 NEXT C
1090 PRINT
1100 PRINT TAB(4); STRING$(50, "-")
1110 REM
1120 REM PRINT EACH ROW
1130 FOR R = 1 TO 12
1140 PRINT R; "|";
1150 FOR C = 1 TO 12
1160 RESULT = R * C
1170 PRINT TAB(4 + C * 4); RESULT;
1180 NEXT C
1190 PRINT
1200 NEXT R
1210 PRINT
1220 RETURN
</BasicCode>
How It Works
Single Table (lines 160-190):
- Loop from 1 to 12
- Calculate TABLE × I
- Use TAB(2) for left margin, TAB(15) for aligned equals signs
Complete Table (lines 1000-1220):
- Lines 1050-1080: Print column headers (1 through 12)
- Line 1070:
TAB(4 + C * 4)spaces columns 4 characters apart - Lines 1130-1200: Nested loops print grid:
- Outer loop (R): each row
- Inner loop (C): each column
- Calculate R × C and print at precise position
Sample Output
MULTIPLICATION TABLE GENERATOR
==============================
WHICH TABLE (1-12)? 7
7 TIMES TABLE
--------------------
7 X 1 = 7
7 X 2 = 14
7 X 3 = 21
7 X 4 = 28
7 X 5 = 35
7 X 6 = 42
7 X 7 = 49
7 X 8 = 56
7 X 9 = 63
7 X 10 = 70
7 X 11 = 77
7 X 12 = 84
ANOTHER TABLE? (Y/N)? N
WOULD YOU LIKE TO SEE THE COMPLETE
1-12 MULTIPLICATION TABLE? (Y/N)? Y
COMPLETE MULTIPLICATION TABLE
========================================
1 2 3 4 5 6 7 8 9 10 11 12
--------------------------------------------------
1 | 1 2 3 4 5 6 7 8 9 10 11 12
2 | 2 4 6 8 10 12 14 16 18 20 22 24
3 | 3 6 9 12 15 18 21 24 27 30 33 36
...
What You're Learning
- Nested FOR loops: Loop inside loop
- TAB positioning: Precise column alignment
- STRING$ function: Creating separator lines
- Formatted grids: Professional table layout
- Subroutines: Organizing complex display code
Modifications to Try
- Custom range: Ask user for start and end numbers (e.g., 5-15)
- Colored output: Use ASCII codes or special characters for emphasis
- Quiz mode: Ask user to fill in answers, check correctness
- Flash cards: Show random multiplication problems one at a time
- Export: Format as CSV for importing to spreadsheet
Exercise
Add a "search" feature: ask user for a product (e.g., 56) and show all multiplication facts that equal it (7×8, 8×7).
500 REM SEARCH FOR PRODUCT
510 INPUT "FIND PRODUCTS EQUAL TO"; TARGET
520 PRINT "FACTS THAT EQUAL"; TARGET; ":"
530 COUNT = 0
540 FOR A = 1 TO 12
550 FOR B = 1 TO 12
560 IF A * B = TARGET THEN PRINT A; "X"; B; "="; TARGET: COUNT = COUNT + 1
570 NEXT B
580 NEXT A
590 IF COUNT = 0 THEN PRINT "NONE FOUND"
600 RETURN
Program 8: String Reverser
Manipulate strings character by character using string functions. This demonstrates MID$, LEN, and string building techniques.
The Program
<BasicCode>
10 REM *** STRING REVERSER ***
20 REM DEMONSTRATES: LEN, MID$, STRING MANIPULATION
30 REM
40 PRINT "STRING REVERSER"
50 PRINT "==============="
60 PRINT
70 INPUT "ENTER A STRING"; S$
80 IF S$ = "" THEN PRINT "EMPTY STRING!": GOTO 70
90 PRINT
100 REM
110 REM METHOD 1: REVERSE CHARACTER BY CHARACTER
120 PRINT "REVERSING..."
130 REV$ = ""
140 FOR I = LEN(S$) TO 1 STEP -1
150 REV$ = REV$ + MID$(S$, I, 1)
160 NEXT I
170 PRINT
180 PRINT "ORIGINAL: "; S$
190 PRINT "REVERSED: "; REV$
200 PRINT
210 REM
220 REM CHECK IF PALINDROME
230 IF S$ = REV$ THEN PRINT "THIS IS A PALINDROME!"
240 PRINT
250 REM
260 REM SHOW STEP-BY-STEP
270 INPUT "SEE STEP-BY-STEP? (Y/N)"; A$
280 IF A$ <> "Y" AND A$ <> "y" THEN GOTO 400
290 PRINT
300 PRINT "STEP-BY-STEP REVERSAL:"
310 PRINT "---------------------"
320 BUILD$ = ""
330 FOR I = LEN(S$) TO 1 STEP -1
340 CHAR$ = MID$(S$, I, 1)
350 BUILD$ = BUILD$ + CHAR$
360 PRINT "POSITION"; I; ": ADD '"; CHAR$; "' -> "; BUILD$
370 NEXT I
380 PRINT
390 REM
400 REM CONTINUE
410 INPUT "REVERSE ANOTHER? (Y/N)"; A$
420 IF A$ = "Y" OR A$ = "y" THEN GOTO 40
430 PRINT "GOODBYE!"
440 END
</BasicCode>
How It Works
Line 140: FOR I = LEN(S$) TO 1 STEP -1 loops backward through string:
- Start at last character position:
LEN(S$) - End at first character: 1
- Decrement: STEP -1
Line 150: MID$(S$, I, 1) extracts one character at position I:
- MID$(string, start, length)
- Extract from position I, take 1 character
- Concatenate to REV$ to build reversed string
Line 230: Palindrome check—if original equals reversed, it's a palindrome (reads same forward and backward: "RACECAR", "NOON", "A").
Lines 330-370: Step-by-step demonstration shows each character being added to build the reversed string.
Sample Output
STRING REVERSER
===============
ENTER A STRING? HELLO WORLD
REVERSING...
ORIGINAL: HELLO WORLD
REVERSED: DLROW OLLEH
SEE STEP-BY-STEP? (Y/N)? Y
STEP-BY-STEP REVERSAL:
---------------------
POSITION 11 : ADD 'D' -> D
POSITION 10 : ADD 'L' -> DL
POSITION 9 : ADD 'R' -> DLR
POSITION 8 : ADD 'O' -> DLRO
POSITION 7 : ADD 'W' -> DLROW
POSITION 6 : ADD ' ' -> DLROW
POSITION 5 : ADD 'O' -> DLROW O
POSITION 4 : ADD 'L' -> DLROW OL
POSITION 3 : ADD 'L' -> DLROW OLL
POSITION 2 : ADD 'E' -> DLROW OLLE
POSITION 1 : ADD 'H' -> DLROW OLLEH
REVERSE ANOTHER? (Y/N)? Y
STRING REVERSER
===============
ENTER A STRING? RACECAR
REVERSING...
ORIGINAL: RACECAR
REVERSED: RACECAR
THIS IS A PALINDROME!
SEE STEP-BY-STEP? (Y/N)? N
REVERSE ANOTHER? (Y/N)? N
GOODBYE!
READY.
What You're Learning
- LEN function: Getting string length
- MID$ function: Extracting substrings
- String building: Concatenating characters
- Backward loops: STEP -1 for reverse iteration
- Palindrome detection: Comparing original to reversed
- Debugging display: Showing algorithm steps
Modifications to Try
- Case-insensitive palindromes: Ignore capitals (convert to uppercase first)
- Ignore spaces/punctuation: "A man a plan a canal Panama"
- Word reverser: Reverse order of words, not characters
- Encryption: Caesar cipher (shift each letter by N positions)
- Character counter: Count frequency of each letter
Exercise
Add a "pig latin" translator: move first letter to end and add "AY" (HELLO → ELLOHAY).
500 REM PIG LATIN TRANSLATOR
510 IF LEN(S$) < 2 THEN PRINT "TOO SHORT": RETURN
520 FIRST$ = LEFT$(S$, 1)
530 REST$ = MID$(S$, 2, LEN(S$) - 1)
540 PIGLATIN$ = REST$ + FIRST$ + "AY"
550 PRINT "PIG LATIN: "; PIGLATIN$
560 RETURN
Program 9: Array Sorting (Bubble Sort)
Sort a list of numbers using the classic bubble sort algorithm. This demonstrates arrays, nested loops, and swapping values.
The Program
<BasicCode>
10 REM *** BUBBLE SORT DEMONSTRATION ***
20 REM DEMONSTRATES: ARRAYS, SORTING, NESTED LOOPS, SWAP
30 REM
40 DIM A(100)
50 PRINT "BUBBLE SORT"
60 PRINT "==========="
70 PRINT
80 INPUT "HOW MANY NUMBERS (1-100)"; N
90 IF N < 1 OR N > 100 THEN GOTO 80
100 PRINT
110 REM
120 REM GET NUMBERS FROM USER
130 PRINT "ENTER"; N; "NUMBERS:"
140 FOR I = 1 TO N
150 PRINT "NUMBER"; I; ":";
160 INPUT A(I)
170 NEXT I
180 PRINT
190 REM
200 REM SHOW UNSORTED
210 PRINT "UNSORTED:"
220 GOSUB 1000
230 PRINT
240 REM
250 REM BUBBLE SORT ALGORITHM
260 PRINT "SORTING..."
270 FOR PASS = 1 TO N - 1
280 FOR I = 1 TO N - PASS
290 IF A(I) > A(I + 1) THEN GOSUB 2000
300 NEXT I
310 NEXT PASS
320 REM
330 REM SHOW SORTED
340 PRINT "SORTED:"
350 GOSUB 1000
360 PRINT
370 REM
380 REM CONTINUE
390 INPUT "SORT ANOTHER LIST? (Y/N)"; A$
400 IF A$ = "Y" OR A$ = "y" THEN GOTO 50
410 PRINT "GOODBYE!"
420 END
990 REM
1000 REM SUBROUTINE: DISPLAY ARRAY
1010 FOR I = 1 TO N
1020 PRINT A(I);
1030 IF I < N THEN PRINT ",";
1040 NEXT I
1050 PRINT
1060 RETURN
1090 REM
2000 REM SUBROUTINE: SWAP TWO ELEMENTS
2010 TEMP = A(I)
2020 A(I) = A(I + 1)
2030 A(I + 1) = TEMP
2040 RETURN
</BasicCode>
How It Works
Bubble Sort Algorithm (lines 270-310):
- Outer loop (PASS): Number of passes through array (N-1 passes)
- Inner loop (I): Compare adjacent elements
- Line 290: If current element > next element, they're out of order—swap them
Why "Bubble": Large values "bubble" to the end of array on each pass. After pass 1, largest value is in final position. After pass 2, second-largest is in position. And so on.
Swap Subroutine (lines 2000-2040):
- Store A(I) in temporary variable TEMP
- Copy A(I+1) into A(I)
- Copy TEMP into A(I+1)
- Result: values are swapped
Optimization: Inner loop goes to N - PASS because after each pass, one more element is in final position (no need to check it).
Sample Output
BUBBLE SORT
===========
HOW MANY NUMBERS (1-100)? 7
ENTER 7 NUMBERS:
NUMBER 1 : 64
NUMBER 2 : 34
NUMBER 3 : 25
NUMBER 4 : 12
NUMBER 5 : 22
NUMBER 6 : 11
NUMBER 7 : 90
UNSORTED:
64, 34, 25, 12, 22, 11, 90
SORTING...
SORTED:
11, 12, 22, 25, 34, 64, 90
SORT ANOTHER LIST? (Y/N)? N
GOODBYE!
READY.
What You're Learning
- Sorting algorithms: Classic bubble sort
- Nested loops: Multiple passes through data
- Comparison: Testing array elements
- Swapping: Exchanging two values via temporary variable
- Array traversal: Visiting each element
- Algorithm efficiency: Bubble sort is O(n²)—works but slow for large lists
Modifications to Try
- Descending order: Change
>to<in line 290 - Show passes: Print array after each pass to visualize sorting
- Count swaps: Track how many swaps were made
- Early exit: Stop if no swaps made (array already sorted)
- Random fill: Generate random numbers instead of user input
- Selection sort: Implement different sorting algorithm
Exercise
Add swap counter and pass display:
265 SWAPS = 0
295 IF A(I) > A(I + 1) THEN GOSUB 2000: SWAPS = SWAPS + 1
315 PRINT "PASS"; PASS; ": "; : GOSUB 1000
And after sorting:
335 PRINT "TOTAL SWAPS:"; SWAPS
This helps understand algorithm behavior.
Program 10: Random Statistics
Generate random numbers and calculate mean, standard deviation, and display a histogram. This demonstrates arrays, statistical algorithms, and data visualization.
The Program
<BasicCode>
10 REM *** RANDOM STATISTICS ***
20 REM DEMONSTRATES: RND, ARRAYS, STATISTICS, GRAPHING
30 REM
40 DIM VALUES(100), BINS(10)
50 PRINT "RANDOM NUMBER STATISTICS"
60 PRINT "========================"
70 PRINT
80 INPUT "HOW MANY RANDOM NUMBERS (10-100)"; N
90 IF N < 10 OR N > 100 THEN GOTO 80
100 PRINT
110 REM
120 REM GENERATE RANDOM NUMBERS (1-100)
130 PRINT "GENERATING"; N; "RANDOM NUMBERS..."
140 FOR I = 1 TO N
150 VALUES(I) = INT(RND(1) * 100) + 1
160 NEXT I
170 PRINT "DONE!"
180 PRINT
190 REM
200 REM CALCULATE MEAN
210 TOTAL = 0
220 FOR I = 1 TO N
230 TOTAL = TOTAL + VALUES(I)
240 NEXT I
250 MEAN = TOTAL / N
260 REM
270 REM CALCULATE STANDARD DEVIATION
280 SUMDEV = 0
290 FOR I = 1 TO N
300 DEV = VALUES(I) - MEAN
310 SUMDEV = SUMDEV + DEV * DEV
320 NEXT I
330 VARIANCE = SUMDEV / N
340 STDDEV = SQR(VARIANCE)
350 REM
360 REM CREATE HISTOGRAM
370 REM BIN 1: 1-10, BIN 2: 11-20, ETC.
380 FOR I = 1 TO 10
390 BINS(I) = 0
400 NEXT I
410 FOR I = 1 TO N
420 BIN = INT((VALUES(I) - 1) / 10) + 1
430 BINS(BIN) = BINS(BIN) + 1
440 NEXT I
450 REM
460 REM DISPLAY RESULTS
470 PRINT "STATISTICS:"
480 PRINT "-----------"
490 PRINT "MEAN:"; INT(MEAN * 100 + 0.5) / 100
500 PRINT "STD DEV:"; INT(STDDEV * 100 + 0.5) / 100
510 PRINT
520 REM
530 REM DISPLAY HISTOGRAM
540 PRINT "HISTOGRAM (DISTRIBUTION):"
550 PRINT "-------------------------"
560 FOR I = 1 TO 10
570 PRINT I * 10 - 9; "-"; I * 10; ":";
580 PRINT TAB(12);
590 FOR J = 1 TO BINS(I)
600 PRINT "*";
610 NEXT J
620 PRINT " ("; BINS(I); ")"
630 NEXT I
640 PRINT
650 REM
660 REM CONTINUE
670 INPUT "GENERATE MORE? (Y/N)"; A$
680 IF A$ = "Y" OR A$ = "y" THEN GOTO 50
690 PRINT "GOODBYE!"
700 END
</BasicCode>
How It Works
Random Generation (lines 140-160):
INT(RND(1) * 100) + 1generates integers 1-100- Store in VALUES array
Mean Calculation (lines 210-250):
- Sum all values
- Divide by count: MEAN = TOTAL / N
Standard Deviation (lines 280-340):
- For each value, calculate deviation from mean: (VALUE - MEAN)
- Square each deviation
- Sum squared deviations
- Divide by N to get variance
- Square root of variance = standard deviation
Histogram Binning (lines 410-440):
- Divide range 1-100 into 10 bins
- Bin 1: 1-10, Bin 2: 11-20, etc.
BIN = INT((VALUE - 1) / 10) + 1calculates which bin- Increment that bin's counter
Histogram Display (lines 560-630):
- Print range for each bin
- Print asterisks: one per value in bin
- Print count in parentheses
Sample Output
RANDOM NUMBER STATISTICS
========================
HOW MANY RANDOM NUMBERS (10-100)? 50
GENERATING 50 RANDOM NUMBERS...
DONE!
STATISTICS:
-----------
MEAN: 52.34
STD DEV: 28.76
HISTOGRAM (DISTRIBUTION):
-------------------------
1-10 : **** ( 4 )
11-20 : ***** ( 5 )
21-30 : ****** ( 6 )
31-40 : ***** ( 5 )
41-50 : ****** ( 6 )
51-60 : ******* ( 7 )
61-70 : *** ( 3 )
71-80 : ***** ( 5 )
81-90 : ****** ( 6 )
91-100 : *** ( 3 )
GENERATE MORE? (Y/N)? N
GOODBYE!
READY.
What You're Learning
- Random number generation: RND(1) for randomness
- Statistical algorithms: Mean and standard deviation formulas
- Array processing: Multiple passes through data
- Binning: Grouping continuous data into ranges
- Data visualization: ASCII histogram/bar chart
- Scientific computing: Real-world statistical analysis
Modifications to Try
- Different ranges: Generate numbers in different ranges (1-10, 1-1000)
- Show min/max: Find and display smallest and largest values
- Median: Sort array and find middle value
- Normal distribution: Use Box-Muller transform for bell curve
- Export data: Display raw values for analysis
- Multiple runs: Compare statistics across multiple generations
Exercise
Add median calculation. Median is the middle value when sorted.
First, add sort routine after line 440:
445 REM SORT FOR MEDIAN
446 FOR P = 1 TO N - 1
447 FOR I = 1 TO N - P
448 IF VALUES(I) > VALUES(I+1) THEN TEMP = VALUES(I): VALUES(I) = VALUES(I+1): VALUES(I+1) = TEMP
449 NEXT I: NEXT P
Then calculate median after line 340:
345 REM CALCULATE MEDIAN
346 IF N / 2 = INT(N / 2) THEN MEDIAN = (VALUES(N/2) + VALUES(N/2+1)) / 2
347 IF N / 2 <> INT(N / 2) THEN MEDIAN = VALUES(INT(N/2)+1)
Display after line 500:
505 PRINT "MEDIAN:"; INT(MEDIAN * 100 + 0.5) / 100
Chapter Summary
You've now studied ten complete, working programs that demonstrate the full power of BASIC. Let's review what each program taught you:
Programs and Key Concepts
- Hello World: Basic structure, PRINT, END
- Number Guessing: RND, INPUT, IF/THEN, loops, counters
- Fibonacci: Arrays, FOR loops, DIM, mathematical sequences
- Prime Finder: Nested loops, optimization, boolean flags
- Temperature Converter: DEF FN, menus, ON GOTO, formatting
- Calculator: GOSUB/RETURN, subroutines, code organization
- Multiplication Tables: Nested loops, TAB, grid formatting
- String Reverser: LEN, MID$, string building, palindromes
- Bubble Sort: Sorting algorithms, swapping, array manipulation
- Random Statistics: Statistics, histograms, data visualization
Programming Skills Acquired
By working through these examples, you've learned:
Data Structures:
- Variables (numeric, integer, string)
- Arrays for collections
- Using indices effectively
Control Flow:
- FOR loops (including STEP -1)
- Nested loops
- IF/THEN conditionals
- GOTO for program flow
- GOSUB/RETURN for subroutines
Functions:
- Built-in: RND, INT, SQR, LEN, MID$, LEFT$, RIGHT$
- User-defined: DEF FN
Input/Output:
- INPUT for user data
- PRINT with formatting
- TAB for alignment
- String building
Algorithms:
- Random number generation
- Sorting (bubble sort)
- Searching (prime numbers)
- Statistical calculations
- String manipulation
What's Next
These ten programs are starting points, not endpoints. The real learning happens when you:
- Modify them: Change the programs to do something different
- Combine them: Use techniques from multiple programs together
- Debug them: Intentionally break them and fix them
- Extend them: Add features the original doesn't have
- Create your own: Use these as templates for original programs
Don't just read these programs—type them. Don't just type them—modify them. Don't just modify them—break them and fix them. Programming is learned by doing, not by reading.
Challenge Projects
Now that you've studied these examples, try creating:
- Hangman game: Combine string manipulation with game logic
- Grade book: Array of students, calculate class average
- Text adventure: Menu system with branching story
- Math tutor: Random problems, track score, provide feedback
- Contact list: Store names/numbers in arrays, search/sort
- Budget tracker: Income/expenses, calculate balance
- Quiz program: DATA statements with questions/answers
- Pattern generator: ASCII art using loops and spacing
- Number converter: Binary, octal, decimal, hexadecimal
- Simple database: Add/delete/search/display records
Each of these projects uses techniques from the example programs. Start small, get it working, then add features.
Your Programming Journey
You're no longer a beginner. You've seen how real programs work. You understand:
- How to structure code
- How to use variables and arrays
- How to get input and format output
- How to implement algorithms
- How to debug and test
The next chapter (Quick Reference) provides a fast-lookup guide for when you need to remember syntax. But the real reference is the programs you've studied here—come back to them when you need examples of specific techniques.
Keep programming. Keep experimenting. Keep learning.
End of Chapter 15
Proceed to Chapter 16: Quick Reference for fast syntax lookup, or return to these examples whenever you need working code to study and modify.
Quick Reference
Introduction
This chapter is your fast-lookup reference for SLP-BASIC syntax. When you can't remember exact syntax, parameters, or operator precedence, come here for quick answers.
This is not a tutorial. Each previous chapter teaches concepts in depth. This chapter provides terse, rapid-access information for experienced users who know what they need and just want to verify syntax.
Organization: Alphabetical within categories for fast scanning.
Format: Command/statement/function followed by syntax, brief description, and example.
[ ]indicates optional parameters...indicates repeatable parameters|indicates alternatives (OR)- Italics indicate placeholders (replace with actual values)
Command Summary
Commands execute in immediate mode or at program start. They manage programs, not program flow.
CLR
Syntax: CLR
Description: Clear all variables, arrays, and user-defined functions. Program remains.
Example: CLR
CONT
Syntax: CONT
Description: Continue execution after STOP. Doesn't work after END or error.
Example: CONT
END
Syntax: END
Description: Terminate program execution gracefully.
Example: 100 END
LIST
Syntax: LIST [line] | [start-end] | [start-] | [-end]
Description: Display program lines.
Examples:
LIST— all linesLIST 100— single lineLIST 100-200— rangeLIST 100-— from 100 to endLIST -200— from start to 200
LOAD
Syntax: LOAD "filename"
Description: Load program from BackendDisk storage. Clears current program first.
Example: LOAD "MYGAME"
NEW
Syntax: NEW
Description: Clear program and all variables. Total memory reset.
Example: NEW
REM
Syntax: REM comment text
Description: Comment/remark. Entire line is ignored during execution.
Example: 10 REM THIS IS A COMMENT
RUN
Syntax: RUN [line]
Description: Execute program from specified line (or first line if omitted).
Examples:
RUN— start at first lineRUN 100— start at line 100
SAVE
Syntax: SAVE "filename"
Description: Save program to BackendDisk storage. Overwrites existing file.
Example: SAVE "MYGAME"
STOP
Syntax: STOP
Description: Suspend program execution. Can resume with CONT.
Example: 100 STOP
Statement Summary
Statements are used within programs to control flow, manipulate data, and interact with users.
DATA
Syntax: DATA value1, value2, value3, ...
Description: Define data constants for READ statement.
Example: 100 DATA 10, 20, 30, "HELLO"
DEF FN
Syntax: DEF FN name(param) = expression
Description: Define user function. Single-line expression only.
Example: 100 DEF FN DOUBLE(X) = X * 2
DIM
Syntax: DIM array(size) [, array2(size2), ...]
Description: Declare array size. Arrays are 0-indexed: DIM A(10) creates A(0) through A(10).
Examples:
DIM A(100)— 1D array, 101 elementsDIM B(10, 10)— 2D array, 11×11 gridDIM C(50), D(25)— multiple arrays
FOR...NEXT
Syntax: FOR var = start TO end [STEP increment] ... NEXT var
Description: Loop from start to end by increment (default 1).
Example:
100 FOR I = 1 TO 10
110 PRINT I
120 NEXT I
GET
Syntax: GET variable$
Description: Read single keystroke (non-blocking). Returns empty string if no key pressed.
Example: 100 GET K$
GOSUB
Syntax: GOSUB line
Description: Call subroutine at line. Execution returns to next line after RETURN.
Example: 100 GOSUB 1000
GOTO
Syntax: GOTO line
Description: Jump to specified line number unconditionally.
Example: 100 GOTO 50
IF...THEN
Syntax: IF condition THEN statement [ELSE statement]
Description: Execute statement(s) if condition is true. ELSE clause is optional in some contexts (use multiple IFs instead).
Examples:
100 IF X > 10 THEN PRINT "BIG"110 IF A = B THEN GOTO 200120 IF Y < 0 THEN Y = 0: GOTO 150
INPUT
Syntax: INPUT ["prompt"; | "prompt",] variable [, variable2, ...]
Description: Get user input. Semicolon suppresses ?, comma includes it.
Examples:
100 INPUT A— shows?110 INPUT "NAME"; N$— showsNAME?120 INPUT "AGE: "; A— showsAGE:(no ?)130 INPUT "X,Y"; X, Y— two values
LET
Syntax: LET variable = expression or variable = expression
Description: Assign value to variable. LET is optional.
Examples:
100 LET X = 10110 Y = 20— same as LET Y = 20
ON...GOTO
Syntax: ON expression GOTO line1, line2, line3, ...
Description: Computed GOTO. Jump to line based on expression value (1=first, 2=second, etc.).
Example: 100 ON CHOICE GOTO 200, 300, 400
ON...GOSUB
Syntax: ON expression GOSUB line1, line2, line3, ...
Description: Computed GOSUB. Call subroutine based on expression value.
Example: 100 ON OP GOSUB 1000, 2000, 3000
POKE
Syntax: POKE address, value
Description: Write byte to simulated memory address (0-65535). Value must be 0-255.
Example: 100 POKE 1024, 65 — write 'A' to screen memory simulation
PRINT / ?
Syntax: PRINT [expression [; | ,] expression ...]
Description: Display output. ; = tight spacing, , = tab to 14-char zones. ? is shorthand for PRINT.
Examples:
100 PRINT "HELLO"110 ? "WORLD"— same as PRINT120 PRINT A; B; C— tight spacing130 PRINT X, Y, Z— column spacing140 PRINT "HELLO";— suppress newline
READ
Syntax: READ variable [, variable2, ...]
Description: Read values from DATA statements sequentially.
Example: 100 READ A, B, C$
RESTORE
Syntax: RESTORE [line]
Description: Reset DATA pointer to first DATA statement (or specified line).
Examples:
100 RESTORE— reset to first DATA110 RESTORE 500— reset to DATA at line 500
RETURN
Syntax: RETURN
Description: Return from GOSUB subroutine to statement after GOSUB.
Example: 1000 RETURN
WAIT
Syntax: WAIT address, mask [, mask2]
Description: Wait for memory location to match condition. Non-blocking in WASM implementation.
Example: 100 WAIT 53280, 1
Function Summary
Functions return values based on input parameters. Use in expressions and assignments.
Mathematical Functions
ABS(n)
Absolute value. Returns positive magnitude.ABS(-5) → 5ABS(3.7) → 3.7
EXP(n)
e raised to power n (e^n). Natural exponential.EXP(1) → 2.71828... (e)EXP(2) → 7.389... (e²)
INT(n)
Integer part (truncate toward zero). Removes decimal.INT(7.8) → 7INT(-7.8) → -7
LOG(n)
Natural logarithm (base e). n must be > 0.LOG(2.71828) → 1 (approximately)LOG(10) → 2.302...
RND(n)
Random number 0 ≤ r < 1. Argument typically 1.RND(1) → 0.734... (random)INT(RND(1) * 6) + 1 → 1-6 (dice roll)
SGN(n)
Sign of number: -1 (negative), 0 (zero), 1 (positive).SGN(-5) → -1SGN(0) → 0SGN(3.7) → 1
SQR(n)
Square root. n must be ≥ 0.SQR(16) → 4SQR(2) → 1.414...
Trigonometric Functions
All trig functions use radians (not degrees). To convert: radians = degrees × π / 180
ATN(n)
Arctangent (inverse tangent) in radians. Returns -π/2 to π/2.ATN(1) → 0.785... (π/4, which is 45°)ATN(0) → 0
COS(n)
Cosine of n radians.COS(0) → 1COS(3.14159) → -1 (π radians = 180°)
SIN(n)
Sine of n radians.SIN(0) → 0SIN(1.5708) → 1 (π/2 radians = 90°)
TAN(n)
Tangent of n radians.TAN(0) → 0TAN(0.785) → 1 (π/4 radians = 45°)
Note: To get π: PI = 3.14159 or PI = ATN(1) * 4
String Functions
ASC(string$)
ASCII code of first character. Returns 0-255.ASC("A") → 65ASC("HELLO") → 72 (H)
CHR$(n)
Character with ASCII code n (0-255).CHR$(65) → "A"CHR$(32) → " " (space)
LEFT$(string$, n)
First n characters from left.LEFT$("HELLO", 3) → "HEL"LEFT$("BASIC", 1) → "B"
LEN(string$)
Length of string in characters.LEN("HELLO") → 5LEN("") → 0
MID$(string$, start [, length])
Substring starting at position start (1-indexed). Optional length (default: to end).MID$("HELLO", 2, 3) → "ELL"MID$("BASIC", 3) → "SIC"
RIGHT$(string$, n)
Last n characters from right.RIGHT$("HELLO", 2) → "LO"RIGHT$("WORLD", 5) → "WORLD"
STR$(n)
Convert number to string. Adds leading space for positive numbers.STR$(42) → " 42"STR$(-5) → "-5"
VAL(string$)
Convert string to number. Returns 0 if not valid number.VAL("123") → 123VAL("45.6") → 45.6VAL("HELLO") → 0
System Functions
FRE(0)
Free memory in bytes. Always use 0 as parameter.FRE(0) → 38911 (C64 mode)
PEEK(address)
Read byte from simulated memory address (0-65535). Returns 0-255.PEEK(1024) → value at simulated address
POS(0)
Current cursor column position (0-39 on 40-column screen). Always use 0.POS(0) → 15 (cursor at column 15)
SPC(n)
Print n spaces. Use in PRINT statement only.PRINT "A"; SPC(5); "B" → A B
TAB(n)
Move cursor to column n. Use in PRINT statement only.PRINT TAB(10); "HERE" → HERE
Operator Summary
Operators combine values and variables in expressions. Listed by precedence (highest first).
Arithmetic Operators
| Operator | Description | Precedence | Example | Result |
|---|---|---|---|---|
^ |
Exponentiation | 1 (highest) | 2 ^ 3 |
8 |
- |
Negation (unary) | 2 | -5 |
-5 |
* |
Multiplication | 3 | 4 * 3 |
12 |
/ |
Division | 3 | 10 / 4 |
2.5 |
+ |
Addition | 4 | 5 + 3 |
8 |
- |
Subtraction | 4 | 5 - 3 |
2 |
Precedence rules:
- Parentheses override all precedence
- Exponentiation (^) first
- Multiplication and division (*, /) next (left to right)
- Addition and subtraction (+, -) last (left to right)
Examples:
2 + 3 * 4→14(not 20: multiply first)(2 + 3) * 4→20(parentheses force addition first)2 ^ 3 ^ 2→512(2^9: exponentiation right-to-left)10 - 5 - 2→3(left-to-right: 5 then subtract 2)
Comparison Operators
All comparison operators have same precedence (after arithmetic). Return -1 (true) or 0 (false).
| Operator | Description | Example | Result |
|---|---|---|---|
= |
Equal | 5 = 5 |
-1 (true) |
<> |
Not equal | 5 <> 3 |
-1 (true) |
< |
Less than | 3 < 5 |
-1 (true) |
> |
Greater than | 5 > 3 |
-1 (true) |
<= |
Less or equal | 5 <= 5 |
-1 (true) |
>= |
Greater or equal | 5 >= 5 |
-1 (true) |
String comparison: Alphabetical order, case-sensitive.
"APPLE" < "BANANA"→-1(true)"Z" > "A"→-1(true)"ABC" = "abc"→0(false: case matters)
Logical Operators
Perform boolean logic. Operands are numbers: 0 = false, non-zero (typically -1) = true.
| Operator | Description | Example | Result |
|---|---|---|---|
NOT |
Logical NOT (bitwise complement) | NOT 0 |
-1 |
AND |
Logical AND (bitwise) | -1 AND -1 |
-1 |
OR |
Logical OR (bitwise) | -1 OR 0 |
-1 |
Truth tables:
NOT:
NOT 0→-1(not false = true)NOT -1→0(not true = false)
AND: Both must be true
-1 AND -1→-1(true)-1 AND 0→0(false)0 AND 0→0(false)
OR: Either can be true
-1 OR -1→-1(true)-1 OR 0→-1(true)0 OR 0→0(false)
Example:
IF X > 0 AND X < 10 THEN PRINT "IN RANGE"
IF A = 1 OR A = 2 OR A = 3 THEN PRINT "VALID"
IF NOT (X = 0) THEN PRINT "NON-ZERO"
Bitwise behavior: AND, OR, NOT operate on bits, so results with non--1 values differ from pure boolean.
String Concatenation
| Operator | Description | Example | Result |
|---|---|---|---|
+ |
Concatenate strings | "HI" + " " + "THERE" |
"HI THERE" |
Joins strings end-to-end. Cannot mix strings and numbers without conversion.
Error Code Quick Reference
When BASIC encounters an error, it displays an error message with a ? prefix. Most errors indicate the line number where they occurred.
Syntax Errors
?SYNTAX ERROR
Malformed statement, missing keywords, incorrect punctuation.
Cause: Typos, missing operators, invalid syntax
Fix: Check line for correct BASIC syntax
?ILLEGAL QUANTITY ERROR
Number out of valid range or invalid value for context.
Cause: Array subscript negative/too large, invalid parameter
Fix: Check array bounds and function parameters
Runtime Errors
?TYPE MISMATCH ERROR
Wrong data type used (string where number expected or vice versa).
Cause: Assigning number to string variable, string arithmetic
Fix: Use STR$() and VAL() for conversions
?OUT OF DATA ERROR
READ statement but no more DATA available.
Cause: More READs than DATA items
Fix: Add DATA or use RESTORE to reset pointer
?DIVISION BY ZERO ERROR
Attempted division by zero.
Cause: Division or modulo with zero divisor
Fix: Check divisor before division: IF B <> 0 THEN ...
?OVERFLOW ERROR
Number too large to represent.
Cause: Calculation exceeds ±1.7E38 or integer ±32767
Fix: Use smaller numbers or different algorithm
?OUT OF MEMORY ERROR
Insufficient memory for operation.
Cause: Too many variables, arrays too large, program too big
Fix: Reduce array sizes, simplify program, use CLR
Control Flow Errors
?UNDEF'D STATEMENT ERROR
GOTO/GOSUB to non-existent line number.
Cause: Line number doesn't exist, typo in GOTO/GOSUB
Fix: Verify line numbers with LIST
?NEXT WITHOUT FOR ERROR
NEXT without matching FOR.
Cause: Missing FOR, extra NEXT, mismatched variables
Fix: Ensure each FOR has matching NEXT
?RETURN WITHOUT GOSUB ERROR
RETURN without matching GOSUB.
Cause: RETURN outside subroutine, GOSUB/RETURN mismatch
Fix: Remove stray RETURN or add GOSUB
?OUT OF DATA ERROR
READ exhausted all DATA values.
Cause: More READ than DATA
Fix: Add more DATA or RESTORE to reuse
File Errors
?FILE NOT FOUND ERROR
LOAD couldn't find specified file.
Cause: Filename doesn't exist, typo in name
Fix: Check filename spelling, verify file was saved
?SAVE ERROR
SAVE operation failed.
Cause: Storage quota exceeded, browser storage disabled
Fix: Delete old files, check browser settings
Function Errors
?ILLEGAL QUANTITY ERROR
Invalid argument to function.
Cause: SQR(negative), LOG(zero or negative)
Fix: Validate input before function call
?REDIM'D ARRAY ERROR
Array already dimensioned, cannot DIM again.
Cause: Multiple DIM for same array
Fix: Use CLR or NEW to clear array, then DIM once
Debugging Tips
- Note the line number: Error message usually includes line where error occurred
- LIST the line:
LIST 100to see problematic line - Check variable values: Use immediate mode to PRINT variables
- Step through logic: Add PRINT statements to trace execution
- Simplify: Comment out sections to isolate problem
- Validate input: Check user input before using in calculations
ASCII Character Table
ASCII codes for characters 0-127. Use with CHR$() to generate character from code, ASC() to get code from character.
Control Characters (0-31)
| Dec | Hex | Char | Description |
|---|---|---|---|
| 0 | 00 | NUL | Null |
| 7 | 07 | BEL | Bell (beep) |
| 8 | 08 | BS | Backspace |
| 9 | 09 | HT | Tab |
| 10 | 0A | LF | Line feed |
| 13 | 0D | CR | Carriage return |
| 27 | 1B | ESC | Escape |
Printable Characters (32-126)
| Dec | Hex | Char | Dec | Hex | Char | Dec | Hex | Char | Dec | Hex | Char |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 32 | 20 | (space) | 56 | 38 | 8 | 80 | 50 | P | 104 | 68 | h |
| 33 | 21 | ! | 57 | 39 | 9 | 81 | 51 | Q | 105 | 69 | i |
| 34 | 22 | " | 58 | 3A | : | 82 | 52 | R | 106 | 6A | j |
| 35 | 23 | # | 59 | 3B | ; | 83 | 53 | S | 107 | 6B | k |
| 36 | 24 | $ | 60 | 3C | < | 84 | 54 | T | 108 | 6C | l |
| 37 | 25 | % | 61 | 3D | = | 85 | 55 | U | 109 | 6D | m |
| 38 | 26 | & | 62 | 3E | > | 86 | 56 | V | 110 | 6E | n |
| 39 | 27 | ' | 63 | 3F | ? | 87 | 57 | W | 111 | 6F | o |
| 40 | 28 | ( | 64 | 40 | @ | 88 | 58 | X | 112 | 70 | p |
| 41 | 29 | ) | 65 | 41 | A | 89 | 59 | Y | 113 | 71 | q |
| 42 | 2A | * | 66 | 42 | B | 90 | 5A | Z | 114 | 72 | r |
| 43 | 2B | + | 67 | 43 | C | 91 | 5B | [ | 115 | 73 | s |
| 44 | 2C | , | 68 | 44 | D | 92 | 5C | \ | 116 | 74 | t |
| 45 | 2D | - | 69 | 45 | E | 93 | 5D | ] | 117 | 75 | u |
| 46 | 2E | . | 70 | 46 | F | 94 | 5E | ^ | 118 | 76 | v |
| 47 | 2F | / | 71 | 47 | G | 95 | 5F | _ | 119 | 77 | w |
| 48 | 30 | 0 | 72 | 48 | H | 96 | 60 | ` | 120 | 78 | x |
| 49 | 31 | 1 | 73 | 49 | I | 97 | 61 | a | 121 | 79 | y |
| 50 | 32 | 2 | 74 | 4A | J | 98 | 62 | b | 122 | 7A | z |
| 51 | 33 | 3 | 75 | 4B | K | 99 | 63 | c | 123 | 7B | { |
| 52 | 34 | 4 | 76 | 4C | L | 100 | 64 | d | 124 | 7C | | |
| 53 | 35 | 5 | 77 | 4D | M | 101 | 65 | e | 125 | 7D | } |
| 54 | 36 | 6 | 78 | 4E | N | 102 | 66 | f | 126 | 7E | ~ |
| 55 | 37 | 7 | 79 | 4F | O | 103 | 67 | g | 127 | 7F | DEL |
Common Uses
Characters in strings:
10 Q$ = CHR$(34) : REM Quote character
20 T$ = CHR$(9) : REM Tab
30 N$ = CHR$(13) : REM Newline (carriage return)
Special characters:
100 PRINT CHR$(7) : REM Beep (might not work in browser)
110 PRINT CHR$(34); "QUOTED"; CHR$(34) : REM "QUOTED"
Character testing:
200 IF ASC(A$) >= 65 AND ASC(A$) <= 90 THEN PRINT "UPPERCASE"
210 IF ASC(B$) >= 97 AND ASC(B$) <= 122 THEN PRINT "LOWERCASE"
220 IF ASC(C$) >= 48 AND ASC(C$) <= 57 THEN PRINT "DIGIT"
Case conversion:
300 REM UPPERCASE TO LOWERCASE: ADD 32
310 IF ASC(C$) >= 65 AND ASC(C$) <= 90 THEN C$ = CHR$(ASC(C$) + 32)
320 REM LOWERCASE TO UPPERCASE: SUBTRACT 32
330 IF ASC(C$) >= 97 AND ASC(C$) <= 122 THEN C$ = CHR$(ASC(C$) - 32)
Memory Map (Simulated)
SLP-BASIC simulates a 64KB (65536 byte) memory space for PEEK/POKE compatibility with Commodore BASIC. This is not real hardware—it's simulated for authenticity.
Memory Layout
| Address Range | Description |
|---|---|
| 0-255 | Zero page (special fast-access page) |
| 256-511 | System stack |
| 512-1023 | Operating system workspace |
| 1024-2023 | Screen memory (simulated 40×25 character display) |
| 2024-32767 | Available for BASIC program and variables |
| 32768-40959 | Available for BASIC (varies by mode) |
| 40960-49151 | BASIC ROM (simulated) |
| 49152-53247 | Kernal ROM (simulated) |
| 53248-53503 | VIC chip registers (simulated, limited function) |
| 53504-54271 | SID chip registers (simulated, limited function) |
| 54272-55295 | Color RAM (simulated) |
| 55296-65535 | Extended memory (varies by configuration) |
Important Addresses
Screen Memory: 1024-2023 (Commodore 64)
Writing characters here affects simulated screen display (limited in WASM).
Border Color: 53280 (Commodore 64)POKE 53280, value changes border color (0-15, simulated)
Background Color: 53281 (Commodore 64)POKE 53281, value changes background color (0-15, simulated)
Usage Notes
- PEEK/POKE work but simulate Commodore hardware
- Screen memory updates may not be visible (terminal mode)
- Hardware registers (VIC, SID) simulate but don't control real hardware
- Use primarily for authentic Commodore program compatibility
- Modern programs should use PRINT/INPUT rather than direct memory access
Special Topics
Variable Type Suffixes
| Suffix | Type | Range/Size | Example |
|---|---|---|---|
| (none) | Numeric (float) | ±1.7E±38, ~7 digits | X = 3.14 |
% |
Integer | -32768 to 32767 | COUNT% = 100 |
$ |
String | 0-255 characters | NAME$ = "BOB" |
Variable Naming
- First two characters significant: Only first 2 chars matter (COUNTER = COUNT = COUNTRY)
- Case insensitive: Name$, NAME$, name$ are identical
- Reserved words: Cannot start variable with keyword prefix (FOR, IF, GOTO, etc.)
Line Numbering Convention
- Start at 10:
10, 20, 30... - Increment by 10: Leaves room for insertions
- Section ranges: 100-199 init, 200-899 main, 900-999 subroutines, 1000+ data
- Maximum line: 63999
Multi-Statement Lines
Use colon : to separate statements on one line:
100 A = 5: B = 10: PRINT A + B
Equivalent to:
100 A = 5
110 B = 10
120 PRINT A + B
String Operations
Concatenation: Use +
FULL$ = FIRST$ + " " + LAST$
Comparison: Alphabetical (case-sensitive)
IF "APPLE" < "BANANA" THEN PRINT "A COMES FIRST"
Length: Use LEN()
L = LEN("HELLO") : REM L = 5
Random Numbers
Dice roll (1-6):
ROLL = INT(RND(1) * 6) + 1
Range (MIN to MAX):
NUM = INT(RND(1) * (MAX - MIN + 1)) + MIN
Percentage (0-100):
PCT = INT(RND(1) * 101)
Common Patterns
Input validation:
100 INPUT "AGE (1-100)"; A
110 IF A < 1 OR A > 100 THEN GOTO 100
Menu loop:
100 PRINT "1. OPTION A"
110 PRINT "2. OPTION B"
120 INPUT "CHOICE"; C
130 ON C GOTO 200, 300
140 GOTO 100
Array initialization:
100 DIM A(100)
110 FOR I = 0 TO 100
120 A(I) = 0
130 NEXT I
String reversal:
100 REV$ = ""
110 FOR I = LEN(S$) TO 1 STEP -1
120 REV$ = REV$ + MID$(S$, I, 1)
130 NEXT I
Sorting (bubble sort):
100 FOR PASS = 1 TO N - 1
110 FOR I = 1 TO N - PASS
120 IF A(I) > A(I+1) THEN TEMP=A(I): A(I)=A(I+1): A(I+1)=TEMP
130 NEXT I
140 NEXT PASS
Using This Reference
When You Need Quick Syntax
- Commands: Check Command Summary (NEW, LIST, RUN, SAVE, LOAD)
- Statements: Check Statement Summary (IF, FOR, PRINT, INPUT, GOSUB)
- Functions: Check Function Summary by category (Math, String, System)
- Operators: Check Operator Summary with precedence table
- Errors: Check Error Code Quick Reference for debugging
- ASCII: Check ASCII Table for CHR$() and ASC() values
When You Need To Learn
- Return to tutorial chapters: Chapters 1-14 teach concepts in depth
- Study examples: Chapter 15 has complete working programs
- Experiment: Use immediate mode to test syntax
Quick Lookup Strategy
- Know what you need: Function? Statement? Command?
- Find the category: Math? String? Control flow?
- Scan alphabetically: Each section is alphabetized
- Check example: Verify syntax with example
- Test in BASIC: Try it in immediate mode
Common Lookups
Most frequently referenced items:
- FOR loop syntax: Statement Summary → FOR...NEXT
- PRINT formatting: Statement Summary → PRINT
- String functions: Function Summary → String Functions
- Random numbers: Function Summary → RND or Special Topics → Random Numbers
- Operator precedence: Operator Summary → table
- Error messages: Error Code Quick Reference → by error name
- ASCII codes: ASCII Character Table → by character or code
Beyond This Reference
This chapter provides syntax and quick answers. For deeper understanding:
- Chapter 7: Flow control (FOR, IF, GOTO, GOSUB) with extensive examples
- Chapter 8: Input/output (PRINT, INPUT, formatting) with complete formatting guide
- Chapter 9: Arrays and DATA statements with algorithms
- Chapter 10: All functions with detailed explanations and use cases
- Chapter 15: Complete working programs demonstrating techniques
Remember: Quick reference is for recall, not learning. Master the concepts in tutorial chapters, then use this chapter for fast syntax verification.
End of Chapter 16
You now have both tutorial knowledge (Chapters 1-15) and fast-reference syntax (this chapter). You're equipped to program in SLP-BASIC with confidence.
Programming Tips and Best Practices
Introduction
You've learned the syntax. You've mastered the commands. You can write programs that run correctly and produce the right results. But there's a difference between code that works and code that's good.
Good code is readable. Good code is maintainable. Good code follows conventions that make it easier for others (including your future self) to understand what you were trying to accomplish. Good code anticipates problems before they occur and handles edge cases gracefully.
This chapter distills decades of BASIC programming wisdom into practical guidelines. These aren't rigid rules—BASIC is flexible enough to accommodate many styles—but following these patterns will make your programs clearer, more reliable, and easier to debug.
Whether you're writing a quick utility for personal use or developing something to share with others, these tips will help you write better BASIC code.
Line Numbering Strategies
Line numbers are the skeleton of your BASIC program. A well-chosen numbering scheme makes programs easier to read, modify, and maintain. A poorly chosen scheme leads to confusion and makes insertions difficult.
Use Increments of 10
Always number lines in increments of 10: 10, 20, 30, 40, etc. This leaves room for insertions without renumbering your entire program:
10 PRINT "ENTER YOUR NAME"
20 INPUT NAME$
30 PRINT "HELLO, "; NAME$
Now you need validation between lines 20 and 30:
25 IF NAME$ = "" THEN 20
Perfect fit. Had you numbered lines 1, 2, 3, you'd be forced to renumber everything after the insertion point.
Reserve Ranges for Sections
Organise programs by reserving number ranges for logical sections:
0-99: Constants and initialization 100-199: Main program 200-299: Subroutines 300-399: Data statements 400-499: Error handling 500+: Additional modules
This organization makes programs self-documenting:
10 REM *** INITIALIZATION ***
20 DIM SC(10)
30 HI = 0
40 GOSUB 200
100 REM *** MAIN GAME LOOP ***
110 GOSUB 250
120 IF SC(I) > HI THEN HI = SC(I)
130 GOTO 110
200 REM *** SUBROUTINE: INIT DISPLAY ***
210 PRINT CHR$(147)
220 PRINT "SCORE: "; HI
230 RETURN
250 REM *** SUBROUTINE: PLAY TURN ***
260 INPUT "GUESS"; GU
270 GOSUB 350
280 RETURN
350 REM *** SUBROUTINE: CHECK ANSWER ***
360 IF GU = AN THEN PRINT "CORRECT!"
370 RETURN
Anyone reading this code immediately understands the structure. Lines 100-199 are the main program. Lines 200+ are subroutines. The organization is clear at a glance.
Leave Gaps for Expansion
When writing complex sections, leave extra gaps:
100 REM *** MAIN LOOP ***
110 GOSUB 200
120 GOSUB 300
130 GOTO 110
This tight packing looks clean, but what if you need error checking after line 110? You're stuck with line number 115, which breaks the "10s" pattern.
Better:
100 REM *** MAIN LOOP ***
120 GOSUB 200
140 GOSUB 300
160 GOTO 120
Now you have room at 110, 130, 150 for insertions while maintaining consistent spacing.
Start at 10, Not 0
While valid, starting at line 0 is unconventional and can confuse readers who expect line 10 as the program start. Reserve line 0 for special cases if you must use it, but generally start at 10.
10 REM GOOD NUMBERING EXAMPLE
20 REM INITIALIZATION
30 N = 0
40 M = 100
50 REM MAIN LOOP
60 N = N + 1
70 PRINT N
80 IF N < M THEN 60
90 PRINT "DONE!"
LIST
Variable Naming Conventions
BASIC's two-character significance rule makes variable naming challenging but not impossible. With thoughtful naming, you can write readable code despite this limitation.
Understand Two-Character Significance
Only the first two characters matter. BASIC ignores the rest:
COUNTER = 10
COUNTRY = 20
PRINT COUNTER ' Prints 20!
Both names start with "CO", so they're the same variable. This is the single most common source of confusion in BASIC programming.
Make Those Two Characters Count
Choose prefixes carefully to ensure uniqueness:
Good:
SCfor SCOREPLfor PLAYERHPfor HITPOINTSLVfor LEVEL
Bad:
SCfor both SCORE and SCREENPLfor both PLAYER and PLACENAfor both NAME and NATION
Use Descriptive Full Names Anyway
Even though only two characters matter, write full descriptive names. This makes code self-documenting:
SCORE = 0
PLAYER$ = "ALICE"
HITPOINTS = 100
Anyone reading your code understands what these variables represent, even though BASIC only sees SC, PL, and HI.
Consistent Type Suffixes
Always use type suffixes consistently:
- No suffix: Floating-point numeric (SCORE, PRICE, RATIO)
- % suffix: Integer (COUNT%, INDEX%, MAX%)
- $ suffix: String (NAME$, TITLE$, INPUT$)
Don't mix types for the same logical variable:
' Bad - type confusion
NAME = 1
NAME$ = "ALICE"
' Good - clear distinction
USERID = 1
USERNAME$ = "ALICE"
Common Abbreviations
Use standard abbreviations that experienced BASIC programmers recognise:
I,J,K- Loop countersX,Y- CoordinatesN,M- Generic numeric valuesA$,B$,C$- Temporary stringsFL- Flag (boolean state)CT- CountMX- MaximumMN- MinimumSU- SumAV- Average
Example: Before and After
Before (poor naming):
10 A1 = 0
20 A2 = 0
30 B$ = ""
40 INPUT B$
50 A1 = A1 + 1
60 IF A1 > A2 THEN A2 = A1
What does this do? No idea.
After (good naming):
10 COUNT = 0
20 MAXCOUNT = 0
30 INPUT$ = ""
40 INPUT INPUT$
50 COUNT = COUNT + 1
60 IF COUNT > MAXCOUNT THEN MAXCOUNT = COUNT
Crystal clear. Even though BASIC only sees CO, MA, and IN, the full names document intent.
10 REM GOOD NAMING EXAMPLE
20 SCORE = 0
30 PLAYER$ = "ALICE"
40 HITPOINTS = 100
50 PRINT PLAYER$; ": "; HITPOINTS; "HP, SCORE "; SCORE
RUN
Effective Use of REM Statements
Comments are essential for readable code. But not all comments are created equal. Good comments explain why, not what.
Explain Why, Not What
Bad comment (obvious):
10 N = N + 1 ' ADD 1 TO N
We can see what the code does. The comment adds no value.
Good comment (explains intent):
10 N = N + 1 ' SKIP HEADER ROW
Now we understand why we're incrementing N. The comment provides context the code can't.
Use Section Headers
Break programs into logical sections with REM headers:
100 REM *** INITIALIZATION ***
110 DIM SCORES(10)
120 GOSUB 500
200 REM *** MAIN LOOP ***
210 GOSUB 300
220 GOTO 210
300 REM *** SUBROUTINE: GET INPUT ***
310 INPUT "GUESS"; G
320 RETURN
500 REM *** SUBROUTINE: DISPLAY WELCOME ***
510 PRINT CHR$(147)
520 PRINT "WELCOME TO THE GAME!"
530 RETURN
These headers act as bookmarks, making it easy to navigate the program.
Document Complex Logic
When implementing non-obvious algorithms, explain the approach:
100 REM *** BUBBLE SORT ALGORITHM ***
110 REM COMPARE ADJACENT ELEMENTS
120 REM SWAP IF OUT OF ORDER
130 REM REPEAT UNTIL NO SWAPS NEEDED
140 FOR I = 1 TO N-1
150 FOR J = 1 TO N-I
160 IF A(J) > A(J+1) THEN GOSUB 500
170 NEXT J
180 NEXT I
These comments explain the algorithm's logic, helping others (and yourself) understand the code later.
Document Data Structures
Explain what arrays and special variables represent:
10 REM *** DATA STRUCTURES ***
20 REM SC() = PLAYER SCORES (0-10)
30 REM NA$() = PLAYER NAMES
40 REM HI = HIGHEST SCORE SO FAR
50 REM WN$ = WINNING PLAYER NAME
60 DIM SC(10), NA$(10)
Don't Over-Comment
Too many comments clutter code and make it harder to read:
10 N = 0 ' SET N TO ZERO
20 M = 10 ' SET M TO TEN
30 FOR I = 1 TO M ' LOOP FROM 1 TO M
40 N = N + I ' ADD I TO N
50 NEXT I ' END LOOP
60 PRINT N ' PRINT N
This is excessive. Simple, obvious code doesn't need comments.
Comment Modified Algorithms
If you've adapted code from elsewhere, note the source and changes:
100 REM *** RANDOM NUMBER GENERATOR ***
110 REM BASED ON LINEAR CONGRUENTIAL
120 REM MODIFIED FOR SMALLER RANGE
130 SD = (SD * 1103515245 + 12345) AND 2147483647
140 R = INT(SD / 65536) AND 32767
10 REM *** COMMENTED PROGRAM EXAMPLE ***
20 REM CALCULATE AVERAGE OF 5 NUMBERS
30 REM
40 SUM = 0
50 REM GET NUMBERS FROM USER
60 FOR I = 1 TO 5
70 PRINT "NUMBER"; I;
80 INPUT N
90 SUM = SUM + N
100 NEXT I
110 REM CALCULATE AND DISPLAY RESULT
120 AVG = SUM / 5
130 PRINT "AVERAGE: "; AVG
LIST
Modular Design with GOSUB
BASIC lacks modern functions and procedures, but GOSUB provides surprisingly effective modularity. Well-structured subroutines make programs easier to understand, test, and maintain.
One Task Per Subroutine
Each subroutine should do one thing and do it well:
100 REM *** MAIN PROGRAM ***
110 GOSUB 500 ' INITIALIZE
120 GOSUB 600 ' GET INPUT
130 GOSUB 700 ' PROCESS
140 GOSUB 800 ' DISPLAY RESULT
150 END
500 REM *** SUBROUTINE: INITIALIZE ***
510 SCORE = 0
520 LEVEL = 1
530 RETURN
600 REM *** SUBROUTINE: GET INPUT ***
610 INPUT "NAME"; NAME$
620 INPUT "AGE"; AGE
630 RETURN
700 REM *** SUBROUTINE: PROCESS ***
710 SCORE = AGE * 10
720 IF AGE > 18 THEN LEVEL = 2
730 RETURN
800 REM *** SUBROUTINE: DISPLAY RESULT ***
810 PRINT NAME$; ": LEVEL "; LEVEL
820 PRINT "SCORE: "; SCORE
830 RETURN
Each subroutine has a clear purpose. You can test them independently, and the main program reads like English.
Use Standard Subroutine Ranges
Reserve number ranges for subroutines (e.g., 500-999). This makes it obvious when you're calling a subroutine vs. jumping within main code:
GOSUB 150 ' Questionable - main program range
GOSUB 500 ' Clear - subroutine range
Document Subroutine Parameters
BASIC has no formal parameters, so document what variables a subroutine expects and modifies:
500 REM *** SUBROUTINE: CALCULATE DISTANCE ***
510 REM INPUT: X1, Y1, X2, Y2 (COORDINATES)
520 REM OUTPUT: DIST (DISTANCE)
530 DX = X2 - X1
540 DY = Y2 - Y1
550 DIST = SQR(DX*DX + DY*DY)
560 RETURN
Now anyone calling this subroutine knows what to set up before GOSUB and what to expect afterward.
Avoid Deep Nesting
GOSUB from within GOSUB is allowed but can become confusing:
100 GOSUB 500
...
500 GOSUB 600
...
600 GOSUB 700 ' Getting deep
More than 3 levels suggests poor structure. Consider flattening:
100 GOSUB 500 ' INIT
110 GOSUB 600 ' PROCESS PART A
120 GOSUB 700 ' PROCESS PART B
Check Error Conditions Before RETURN
Handle errors within subroutines when possible:
500 REM *** SUBROUTINE: DIVIDE ***
510 REM INPUT: NUMERATOR, DENOMINATOR
520 REM OUTPUT: RESULT
530 IF DENOMINATOR = 0 THEN PRINT "ERROR: DIV BY ZERO": RETURN
540 RESULT = NUMERATOR / DENOMINATOR
550 RETURN
This prevents errors from propagating to the main program.
Example: Before and After
Before (no subroutines):
10 PRINT "MENU:"
20 PRINT "1. ADD"
30 PRINT "2. SUBTRACT"
40 INPUT CH
50 INPUT "FIRST NUMBER"; A
60 INPUT "SECOND NUMBER"; B
70 IF CH = 1 THEN R = A + B
80 IF CH = 2 THEN R = A - B
90 PRINT "RESULT: "; R
100 GOTO 10
All logic in one place, hard to follow.
After (with subroutines):
10 REM *** MAIN LOOP ***
20 GOSUB 500 ' SHOW MENU
30 GOSUB 600 ' GET CHOICE
40 GOSUB 700 ' GET NUMBERS
50 GOSUB 800 ' CALCULATE
60 GOSUB 900 ' DISPLAY RESULT
70 GOTO 20
500 REM *** SUBROUTINE: SHOW MENU ***
510 PRINT "MENU:"
520 PRINT "1. ADD"
530 PRINT "2. SUBTRACT"
540 RETURN
600 REM *** SUBROUTINE: GET CHOICE ***
610 INPUT CH
620 RETURN
700 REM *** SUBROUTINE: GET NUMBERS ***
710 INPUT "FIRST NUMBER"; A
720 INPUT "SECOND NUMBER"; B
730 RETURN
800 REM *** SUBROUTINE: CALCULATE ***
810 IF CH = 1 THEN R = A + B
820 IF CH = 2 THEN R = A - B
830 RETURN
900 REM *** SUBROUTINE: DISPLAY RESULT ***
910 PRINT "RESULT: "; R
920 RETURN
Clear structure, easy to test individual parts, simple to add new operations.
10 REM MODULAR DESIGN EXAMPLE
20 GOSUB 500
30 GOSUB 600
40 END
500 REM *** SUBROUTINE: GREET ***
510 PRINT "HELLO FROM SUBROUTINE!"
520 RETURN
600 REM *** SUBROUTINE: FAREWELL ***
610 PRINT "GOODBYE FROM SUBROUTINE!"
620 RETURN
RUN
Common Pitfalls and How to Avoid Them
Even experienced BASIC programmers make these mistakes. Learn to recognise and avoid them.
Forgetting NEXT in FOR Loops
Problem:
10 FOR I = 1 TO 10
20 PRINT I
30 FOR J = 1 TO 5
40 PRINT J
50 NEXT I ' ERROR: NEXT without FOR
60 NEXT J
You'll get "?NEXT WITHOUT FOR ERROR" because NEXT I appears before NEXT J.
Solution: Match each FOR with its corresponding NEXT in reverse order (LIFO—Last In, First Out):
10 FOR I = 1 TO 10
20 PRINT I
30 FOR J = 1 TO 5
40 PRINT J
50 NEXT J ' Close inner loop first
60 NEXT I ' Then outer loop
GOSUB Without RETURN
Problem:
100 GOSUB 500
...
500 REM SUBROUTINE
510 PRINT "DONE"
520 END ' Wrong! Should be RETURN
Using END instead of RETURN terminates the program rather than returning to the caller. Your program never continues after line 100.
Solution: Always use RETURN to exit subroutines:
500 REM SUBROUTINE
510 PRINT "DONE"
520 RETURN ' Correct
String vs. Numeric Type Confusion
Problem:
10 INPUT "AGE"; AGE$ ' String variable
20 AGE = AGE + 5 ' Numeric operation
AGE$ is a string, AGE is a number—they're different variables! This code doesn't add 5 to the input; it creates a new variable.
Solution: Use consistent types:
10 INPUT "AGE"; AGE ' Numeric variable
20 AGE = AGE + 5 ' Works correctly
Or convert explicitly:
10 INPUT "AGE"; AGE$ ' Get as string
20 AGE = VAL(AGE$) ' Convert to number
30 AGE = AGE + 5 ' Now it works
Off-by-One Errors in Loops
Problem:
10 DIM A(10) ' Creates A(0) through A(10)
20 FOR I = 1 TO 10 ' Skips A(0)!
30 READ A(I)
40 NEXT I
Arrays start at 0, but the loop starts at 1. Element A(0) is never initialized.
Solution: Start at 0 or explicitly document why you're skipping it:
10 DIM A(10)
20 FOR I = 0 TO 10 ' Process all elements
30 READ A(I)
40 NEXT I
Infinite Loops
Problem:
10 X = 1
20 X = X + 1
30 IF X < 100 THEN 20 ' Runs until X reaches 100
What if X never reaches 100? The loop runs forever. Always ensure loop conditions will eventually become false.
Solution: Add safety limits or double-check logic:
10 X = 1
20 X = X + 1
30 IF X >= 100 THEN 50 ' Clear exit condition
40 GOTO 20
50 PRINT "DONE"
Uninitialized Variables
Problem:
10 FOR I = 1 TO 10
20 TOTAL = TOTAL + I
30 NEXT I
40 PRINT TOTAL
What's the initial value of TOTAL? In BASIC, uninitialized numeric variables are 0, but relying on this is poor practice. If TOTAL was used earlier, it retains its old value.
Solution: Explicitly initialize all variables:
10 TOTAL = 0 ' Clear initialization
20 FOR I = 1 TO 10
30 TOTAL = TOTAL + I
40 NEXT I
50 PRINT TOTAL
Variable Name Collisions
Problem:
10 COUNTER = 0
20 COUNT = 10
30 PRINT COUNTER ' Prints 10, not 0!
Both start with "CO"—they're the same variable!
Solution: Ensure unique first two characters:
10 COUNTER = 0 ' CO
20 MAXIMUM = 10 ' MA
30 PRINT COUNTER ' Works correctly
10 REM COMMON PITFALLS EXAMPLE
20 REM INITIALIZE VARIABLES
30 TOTAL = 0
40 REM PROPERLY NESTED LOOPS
50 FOR I = 1 TO 3
60 FOR J = 1 TO 2
70 TOTAL = TOTAL + 1
80 NEXT J
90 NEXT I
100 PRINT "TOTAL: "; TOTAL
RUN
Performance Tips
BASIC is generally fast enough for most tasks, but these optimizations can make computationally intensive programs noticeably faster.
Use Integer Variables for Whole Numbers
Integer arithmetic is significantly faster than floating-point:
Slow:
10 FOR I = 1 TO 10000
20 SUM = SUM + I
30 NEXT I
Fast:
10 FOR I% = 1 TO 10000
20 SUM% = SUM% + I%
30 NEXT I%
The % suffix forces integer arithmetic, which can be 2-3 times faster for whole numbers within the -32768 to 32767 range.
Avoid Repeated Calculations in Loops
Slow:
10 FOR I = 1 TO 1000
20 A = B * 3.14159 + C * 2.71828
30 NEXT I
The constants are multiplied every iteration.
Fast:
10 K1 = B * 3.14159
20 K2 = C * 2.71828
30 FOR I = 1 TO 1000
40 A = K1 + K2
50 NEXT I
Calculate once, reuse many times.
Use Variables for Constants
Slow:
10 FOR I = 1 TO 100
20 AREA = 3.14159 * R * R
30 NEXT I
BASIC parses "3.14159" from text to number every time.
Fast:
10 PI = 3.14159
20 FOR I = 1 TO 100
30 AREA = PI * R * R
40 NEXT I
Parse once at the start, reference the variable thereafter.
Minimize Array Access
Slow:
10 FOR I = 1 TO 1000
20 A(I) = A(I) + B(I)
30 NEXT I
Each array access involves bounds checking and indexing.
Fast:
10 FOR I = 1 TO 1000
20 X = A(I)
30 Y = B(I)
40 A(I) = X + Y
50 NEXT I
This doesn't actually help much in BASIC, but the principle applies: minimize expensive operations inside tight loops.
Use AND/OR Instead of Multiple IFs
Slow:
10 IF X > 0 THEN 30
20 IF X < 100 THEN 40
30 PRINT "X IS POSITIVE"
40 PRINT "X IS LESS THAN 100"
Fast:
10 IF X > 0 AND X < 100 THEN PRINT "X IN RANGE"
Combining conditions reduces branching overhead.
Optimize Inner Loops
The innermost loop in nested structures runs most frequently—optimize it first:
10 REM OUTER LOOP: RUNS 10 TIMES
20 FOR I = 1 TO 10
30 REM MIDDLE LOOP: RUNS 100 TIMES
40 FOR J = 1 TO 10
50 REM INNER LOOP: RUNS 1000 TIMES
60 FOR K = 1 TO 10
70 REM OPTIMIZE THIS SECTION FIRST
80 A = A + 1
90 NEXT K
100 NEXT J
110 NEXT I
A 10% improvement to the inner loop yields far more benefit than a 50% improvement to the outer loop.
Avoid GOTO in Tight Loops
Slow:
10 I = 1
20 PRINT I
30 I = I + 1
40 IF I <= 1000 THEN 20
Fast:
10 FOR I = 1 TO 1000
20 PRINT I
30 NEXT I
FOR...NEXT is optimized; GOTO is not.
Performance Doesn't Always Matter
Don't sacrifice clarity for marginal speed gains:
10 REM THIS IS FAST BUT CRYPTIC
20 FOR I%=0TO 9:A%(I%)=I%*I%:NEXT I%
30 REM THIS IS CLEAR AND BARELY SLOWER
40 FOR INDEX% = 0 TO 9
50 SQUARES%(INDEX%) = INDEX% * INDEX%
60 NEXT INDEX%
Unless you've measured a performance problem, write for clarity first.
10 REM PERFORMANCE COMPARISON
20 REM INTEGER VS FLOATING POINT
30 TI$ = "000000"
40 FOR I% = 1 TO 1000
50 SUM% = SUM% + I%
60 NEXT I%
70 PRINT "INTEGER SUM: "; SUM%
RUN
Program Structure Patterns
Consistent program structure makes code easier to understand and maintain. These patterns have proven effective across thousands of BASIC programs.
The Standard Structure
1. Constants and Configuration (lines 10-90)
2. Initialization (lines 100-190)
3. Main Program Loop (lines 200-890)
4. Subroutines (lines 900-8999)
5. Data Statements (lines 9000-9999)
Example:
10 REM *** CONFIGURATION ***
20 MAXSCORE = 100
30 MAXLEVEL = 10
100 REM *** INITIALIZATION ***
110 GOSUB 9000 ' INIT VARIABLES
120 GOSUB 9100 ' INIT DISPLAY
200 REM *** MAIN LOOP ***
210 GOSUB 1000 ' GET INPUT
220 GOSUB 2000 ' PROCESS
230 GOSUB 3000 ' UPDATE DISPLAY
240 IF GAMEOVER = 0 THEN 210
800 REM *** CLEANUP ***
810 GOSUB 4000 ' SHOW FINAL SCORE
820 END
1000 REM *** SUBROUTINE: GET INPUT ***
1010 GET A$
1020 IF A$ = "" THEN RETURN
1030 INPUT$ = A$
1040 RETURN
2000 REM *** SUBROUTINE: PROCESS ***
2010 REM GAME LOGIC HERE
2020 RETURN
3000 REM *** SUBROUTINE: UPDATE DISPLAY ***
3010 PRINT "SCORE: "; SCORE
3020 RETURN
4000 REM *** SUBROUTINE: SHOW FINAL ***
4010 PRINT "GAME OVER!"
4020 PRINT "FINAL SCORE: "; SCORE
4030 RETURN
9000 REM *** SUBROUTINE: INIT VARIABLES ***
9010 SCORE = 0
9020 LEVEL = 1
9030 GAMEOVER = 0
9040 RETURN
9100 REM *** SUBROUTINE: INIT DISPLAY ***
9110 PRINT CHR$(147)
9120 PRINT "WELCOME TO THE GAME"
9130 RETURN
This structure is immediately recognizable to experienced BASIC programmers.
The Menu-Driven Pattern
For programs with multiple functions:
100 REM *** MAIN MENU LOOP ***
110 GOSUB 9000 ' SHOW MENU
120 GOSUB 9100 ' GET CHOICE
130 ON CHOICE GOSUB 1000, 2000, 3000, 4000
140 IF CHOICE <> 4 THEN 110
150 PRINT "GOODBYE!"
160 END
1000 REM *** FUNCTION: ADD RECORD ***
1010 PRINT "ADD RECORD"
1020 REM Implementation here
1030 RETURN
2000 REM *** FUNCTION: EDIT RECORD ***
2010 PRINT "EDIT RECORD"
2020 REM Implementation here
2030 RETURN
3000 REM *** FUNCTION: DELETE RECORD ***
3010 PRINT "DELETE RECORD"
3020 REM Implementation here
3030 RETURN
4000 REM *** FUNCTION: EXIT ***
4010 RETURN
9000 REM *** SUBROUTINE: SHOW MENU ***
9010 PRINT
9020 PRINT "MENU:"
9030 PRINT "1. ADD"
9040 PRINT "2. EDIT"
9050 PRINT "3. DELETE"
9060 PRINT "4. EXIT"
9070 RETURN
9100 REM *** SUBROUTINE: GET CHOICE ***
9110 INPUT "CHOICE"; CHOICE
9120 IF CHOICE < 1 OR CHOICE > 4 THEN 9110
9130 RETURN
The ON...GOSUB statement routes to the appropriate function based on user choice.
The Game Loop Pattern
For interactive games:
100 REM *** INITIALIZATION ***
110 GOSUB 9000 ' SETUP
120 GOSUB 9100 ' WELCOME SCREEN
200 REM *** GAME LOOP ***
210 GOSUB 1000 ' DISPLAY STATE
220 GOSUB 2000 ' GET PLAYER INPUT
230 GOSUB 3000 ' UPDATE GAME STATE
240 GOSUB 4000 ' CHECK WIN/LOSE
250 IF PLAYING = 1 THEN 210
300 REM *** END GAME ***
310 GOSUB 5000 ' DISPLAY RESULTS
320 GOSUB 6000 ' PLAY AGAIN?
330 IF PLAYAGAIN = 1 THEN 100
340 END
This pattern separates display, input, logic, and win condition checking into distinct phases.
The Data Processing Pattern
For programs that process lists or files:
100 REM *** INITIALIZATION ***
110 GOSUB 9000 ' LOAD DATA
120 N = 0 ' RECORD COUNT
200 REM *** PROCESSING LOOP ***
210 N = N + 1
220 IF N > MAXRECORDS THEN 300
230 GOSUB 1000 ' PROCESS RECORD N
240 GOTO 210
300 REM *** FINALIZATION ***
310 GOSUB 2000 ' SUMMARY STATISTICS
320 GOSUB 3000 ' SAVE RESULTS
330 END
1000 REM *** SUBROUTINE: PROCESS RECORD ***
1010 REM Work with record N
1020 RETURN
9000 REM *** SUBROUTINE: LOAD DATA ***
9010 RESTORE
9020 READ MAXRECORDS
9030 FOR I = 1 TO MAXRECORDS
9040 READ RECORD$(I)
9050 NEXT I
9060 RETURN
9500 DATA 3
9510 DATA "ALICE", "BOB", "CHARLIE"
Clear separation of loading, processing, and saving phases.
Authentic 1980s Style
Part of programming in BASIC is embracing its era. While modern practices emphasize abstraction and indirection, BASIC's strength lies in directness and simplicity.
Embrace Line Numbers
Don't fight them—they're part of BASIC's character. Use them to your advantage for quick navigation and clear structure.
Keep It Simple
BASIC lacks advanced features for a reason. Simple, direct algorithms are easier to understand and debug:
10 REM FIND MAXIMUM IN ARRAY
20 MAX = A(0)
30 FOR I = 1 TO N
40 IF A(I) > MAX THEN MAX = A(I)
50 NEXT I
60 PRINT "MAX: "; MAX
No abstractions, no layers—just clear, straightforward logic.
Use Immediate Mode for Exploration
One of BASIC's greatest strengths is immediate feedback. Use it:
READY.
PRINT 2+2
4
READY.
FOR I=1 TO 5: PRINT I: NEXT I
1
2
3
4
5
READY.
Test ideas immediately, then add working code to your program.
Prioritize Readability
You're not writing assembly language. BASIC programs should read almost like English:
100 IF SCORE > HIGHSCORE THEN HIGHSCORE = SCORE
110 IF LIVES = 0 THEN GAMEOVER = 1
120 IF LEVEL > MAXLEVEL THEN WINNER = 1
Clear and obvious what's happening.
Limit Line Length
Keep lines under 80 characters for readability. Use colon separators sparingly:
Acceptable:
10 X = 0: Y = 0: Z = 0
Too much:
10 X=0:Y=0:Z=0:A=1:B=2:C=3:D=4:E=5:PRINT "VALUES SET"
Accept the Limitations
BASIC doesn't have:
- Local variables
- Recursion (GOSUB stack limited)
- Structured exception handling
- Object-oriented features
Work within these constraints rather than fighting them. The limitations force clarity and simplicity.
Debugging Strategies
Even well-written programs have bugs. These strategies help you find and fix them efficiently.
Use PRINT for Inspection
The simplest debugging tool:
100 GOSUB 500
110 PRINT "AFTER SUBROUTINE, X="; X ' Check value
120 CONTINUE WITH PROGRAM
Insert PRINT statements to verify variable values at critical points.
Comment Out Suspicious Code
Add REM to lines you suspect:
100 GOSUB 500
110 REM GOSUB 600 ' Disable temporarily
120 GOSUB 700
If the problem disappears, you've found the culprit.
Test Subroutines Independently
Create small test programs:
10 REM TEST SUBROUTINE 500
20 X = 10
30 Y = 20
40 GOSUB 500
50 PRINT "RESULT: "; RESULT
60 END
500 REM SUBROUTINE BEING TESTED
510 RESULT = X + Y
520 RETURN
Isolate and verify each piece separately.
Check Boundary Conditions
Test edge cases:
10 DIM A(10)
20 REM TEST WITH I=0 (MIN)
30 I = 0: GOSUB 500
40 REM TEST WITH I=10 (MAX)
50 I = 10: GOSUB 500
60 REM TEST WITH I=5 (MIDDLE)
70 I = 5: GOSUB 500
Many bugs appear only at array bounds or loop extremes.
Use Meaningful Test Data
Don't just test with 1, 2, 3. Use realistic data:
10 NAME$ = "ALICE WONDERLAND"
20 AGE = 42
30 GOSUB 500
Real-world data often reveals edge cases simple test values miss.
Document Fixed Bugs
When you fix a bug, add a comment explaining what was wrong:
100 REM BUG FIX JAN 23: WAS USING CO INSTEAD OF CT
110 REM COUNTER AND COUNT COLLIDED (BOTH START WITH CO)
120 COUNTER = 0
130 MAXIMUM = 100
This prevents reintroducing the same bug later.
Summary
Good BASIC programming comes down to a few key principles:
Structure: Number lines logically, reserve ranges for sections, leave room for expansion.
Naming: Choose descriptive names with unique first two characters, use consistent type suffixes.
Comments: Explain why, not what. Document complex algorithms and data structures.
Modularity: Break programs into subroutines with clear purposes and documented interfaces.
Awareness: Avoid common pitfalls like nested loop errors, type mismatches, and variable collisions.
Performance: Use integers for whole numbers, avoid repeated calculations, optimize inner loops.
Consistency: Follow established patterns for program structure, making code predictable and maintainable.
Simplicity: Embrace BASIC's directness rather than fighting its limitations.
These aren't rigid rules—BASIC is flexible enough for many approaches. But following these guidelines will make your programs clearer, more reliable, and easier to maintain.
Most importantly: write code you'll understand six months from now. Comment generously, name thoughtfully, and structure logically. Your future self will thank you.
Now you have all the tools you need to write excellent BASIC programs. The appendices that follow provide reference material for Commodore compatibility, technical specifications, language differences, and terminology definitions.
Happy programming!
End of Chapter 17
Proceed to Appendix A: Commodore Compatibility for detailed comparison of VIC-20 and C64 implementations.
Appendix A: Commodore Compatibility
Introduction
SLP-BASIC v1.2 faithfully implements Commodore BASIC V2 as found in the VIC-20 and Commodore 64. This appendix details the differences between these platforms, explains how SLP-BASIC accommodates both, and documents memory layouts, screen configurations, and hardware-specific features.
If you're familiar with vintage Commodore computers, this information will help you understand exactly what SLP-BASIC emulates and where it differs. If you're new to Commodore BASIC, this provides historical context for the design decisions behind the language.
VIC-20 vs Commodore 64
Both the VIC-20 (1980) and Commodore 64 (1982) used identical BASIC V2 syntax. Every command, every function, every keyword worked the same way. The differences were in hardware capabilities and available memory, not in the language itself.
VIC-20 (1980)
Memory Configuration:
- Base model: 5KB total RAM
- 3.5KB expansion: 8.5KB total (common configuration)
- BASIC memory: 3583 bytes free (with 3.5KB expansion)
- Program start: $1000 (4096 decimal)
- Program end: $1DFF (7679 decimal)
Display:
- Screen: 22 columns × 23 rows
- Character set: PETSCII (Commodore's ASCII variant)
- Colors: 8 foreground, 8 border, 8 background (16 total)
- Sprites: None
Banner Message:
**** COMMODORE BASIC V2 ****
3583 BYTES FREE
READY.
Sound:
- VIC chip: 3 voices + 1 noise channel
- Addresses: $900A-$900F (POKE for sound)
Target Market:
- Home users and beginners
- Entry-level computing
- Price: $299 (1981)
Commodore 64 (1982)
Memory Configuration:
- 64KB total RAM
- BASIC memory: 38911 bytes free
- Program start: $0801 (2049 decimal)
- Program end: $9FFF (40959 decimal)
Display:
- Screen: 40 columns × 25 rows
- Character set: PETSCII (identical to VIC-20)
- Colors: 16 colors (16 foreground, 16 border, 16 background)
- Sprites: 8 hardware sprites (24×21 pixels)
Banner Message:
**** COMMODORE BASIC V2 ****
64K RAM SYSTEM 38911 BASIC BYTES FREE
READY.
Sound:
- SID chip: 3 independent voices
- Addresses: $D400-$D7FF (POKE for sound)
- Waveforms: Triangle, sawtooth, pulse, noise
- Filters: Low-pass, high-pass, band-pass
Graphics:
- VIC-II chip: Advanced graphics and sprites
- Multiple display modes (text, bitmap, multicolor)
- Hardware scrolling
Target Market:
- Serious home computing
- Gaming and multimedia
- Price: $595 (1982)
Memory Comparison
| Feature | VIC-20 (3.5KB exp) | Commodore 64 |
|---|---|---|
| Total RAM | 8.5KB | 64KB |
| BASIC bytes free | 3,583 | 38,911 |
| Program start | $1000 (4096) | $0801 (2049) |
| Variable storage | After program | After program |
| Array storage | After variables | After variables |
| String storage | Top of memory down | Top of memory down |
| Stack | $0100-$01FF | $0100-$01FF |
Screen Comparison
| Feature | VIC-20 | Commodore 64 |
|---|---|---|
| Columns | 22 | 40 |
| Rows | 23 | 25 |
| Total characters | 506 | 1,000 |
| Character ROM | $8000 | $D000 |
| Screen RAM | $1E00 | $0400 |
| Color RAM | $9600 | $D800 |
BASIC Compatibility
Despite hardware differences, BASIC V2 syntax was 100% identical:
10 PRINT "HELLO, WORLD!"
20 INPUT "YOUR NAME"; N$
30 PRINT "HELLO, "; N$
40 FOR I = 1 TO 10
50 PRINT I
60 NEXT I
70 END
This program runs identically on both machines. The language syntax, command set, functions, operators, and error messages were all the same.
SLP-BASIC Mode Selection
SLP-BASIC can emulate either VIC-20 or C64 memory and display characteristics. The mode is selected when connecting to the BASIC interpreter.
C64 Mode (Default)
Configuration:
- 38911 bytes free
- 40-column display
- Banner: "64K RAM SYSTEM 38911 BASIC BYTES FREE"
Use C64 mode when:
- You want maximum program space
- You're running existing C64 programs
- You need full-width formatted output
- You want the authentic C64 experience
Example:
READY.
PRINT FRE(0)
38911
READY.
VIC-20 Mode
Configuration:
- 3583 bytes free
- 22-column display (narrower formatting)
- Banner: "3583 BYTES FREE"
Use VIC-20 mode when:
- You want authentic VIC-20 constraints
- You're testing programs for VIC-20 compatibility
- You're working with vintage code listings from VIC-20 magazines
- You want to experience the original limitations
Example:
READY.
PRINT FRE(0)
3583
READY.
Selecting Mode
The mode is configured at connection time through the modem interface. Once selected, the mode remains active for the entire session. Reconnecting allows mode switching.
Mode Differences in Practice
Short Programs: No practical difference. Simple programs fit easily in both memory configurations.
Large Programs: C64 mode provides 10× more space for programs, variables, and arrays.
Formatted Output: C64 mode's 40-column screen allows wider tables and reports. VIC-20 mode's 22 columns require more careful formatting.
Array Sizes: C64 mode supports much larger arrays before running out of memory.
Memory Map Comparison
Understanding memory layout helps you use PEEK and POKE effectively (where applicable).
VIC-20 Memory Map (8.5KB configuration)
$0000-$00FF Zero page (system variables, BASIC pointers)
$0100-$01FF 6502 stack
$0200-$03FF BASIC input buffer, system workspace
$0400-$0FFF Expansion RAM (3.5KB)
$1000-$1DFF BASIC program and variable storage (3583 bytes)
$1E00-$1FFF Screen memory (506 bytes, 22×23)
$2000-$7FFF Unmapped (expansion cartridge space)
$8000-$8FFF Character ROM
$9000-$90FF VIC chip registers
$9100-$93FF Color RAM
$9400-$95FF I/O expansion
$9600-$97FF Color RAM (extended)
$9800-$9BFF I/O
$9C00-$9FFF I/O
$A000-$BFFF BASIC ROM (8KB)
$C000-$DFFF Unmapped
$E000-$FFFF Kernal ROM (8KB)
BASIC usage:
- Programs start at $1000 (4096)
- FRE(0) reports bytes from program end to $1E00
- Screen at $1E00 accessible via PEEK/POKE
C64 Memory Map
$0000-$00FF Zero page (system variables, BASIC pointers)
$0100-$01FF 6502 stack
$0200-$03FF BASIC input buffer, system workspace
$0400-$07FF Screen memory (1000 bytes, 40×25)
$0800-$9FFF BASIC program and variable storage (38911 bytes)
$A000-$BFFF BASIC ROM (8KB)
$C000-$CFFF RAM (4KB)
$D000-$DFFF I/O and character ROM (4KB)
$D000-$D3FF VIC-II chip registers
$D400-$D7FF SID chip registers
$D800-$DBFF Color RAM
$DC00-$DCFF CIA #1 (keyboard, joystick)
$DD00-$DDFF CIA #2 (serial, user port)
$DE00-$DFFF I/O expansion
$E000-$FFFF Kernal ROM (8KB)
BASIC usage:
- Programs start at $0801 (2049)
- FRE(0) reports bytes from program end to $A000
- Screen at $0400 accessible via PEEK/POKE
- Color RAM at $D800 (sprite and color control)
SLP-BASIC Simulated Memory
SLP-BASIC maintains a 64KB simulated memory space (0-65535) for PEEK/POKE compatibility. However:
- Memory is initialized but not connected to real hardware
- PEEK reads return 0 or simulated values
- POKE writes are stored but have no hardware effect
- Screen memory ($0400 on C64, $1E00 on VIC-20) is simulated
- I/O registers return simulated values
This allows programs to run without crashing when they PEEK or POKE hardware addresses, but don't expect graphics or sound effects.
PEEK/POKE Address Reference
Common addresses used in Commodore BASIC programs, showing differences between VIC-20 and C64.
System Pointers
| Purpose | VIC-20 | C64 | Description |
|---|---|---|---|
| Program start | $002B-$002C | $002B-$002C | BASIC program beginning |
| Program end | $002D-$002E | $002D-$002E | End of BASIC program |
| Variable start | $002F-$0030 | $002F-$0030 | Simple variables |
| Array start | $0031-$0032 | $0031-$0032 | Array storage |
| String start | $0033-$0034 | $0033-$0034 | String storage |
| Top of memory | $0037-$0038 | $0037-$0038 | Highest address used |
Screen and Color
| Purpose | VIC-20 | C64 | Notes |
|---|---|---|---|
| Screen memory | $1E00-$1FFF | $0400-$07E7 | Character codes |
| Color memory | $9600-$97F5 | $D800-$DBE7 | Character colors |
| Border color | $900F | $D020 | Border color register |
| Background color | $900F | $D021 | Background color |
Example (C64):
10 REM CHANGE BORDER COLOR
20 POKE 53280, 1 ' $D020 = 53280, WHITE = 1
30 REM CHANGE BACKGROUND
40 POKE 53281, 0 ' $D021 = 53281, BLACK = 0
Note: These POKE commands don't affect SLP-BASIC's display (no graphics emulation), but they're documented for reference.
Sound
| Purpose | VIC-20 | C64 | Notes |
|---|---|---|---|
| Voice 1 | $900A | $D400 | Frequency low |
| Voice 2 | $900B | $D407 | Frequency low |
| Voice 3 | $900C | $D40E | Frequency low |
| Volume | $900E | $D418 | Volume register |
Example (VIC-20):
10 POKE 36876, 200 ' $900C, voice 3 frequency
20 POKE 36878, 15 ' $900E, volume max
Note: SLP-BASIC accepts these POKEs but doesn't produce sound (no audio emulation).
Keyboard and I/O
| Purpose | VIC-20 | C64 | Notes |
|---|---|---|---|
| CIA #1 | N/A | $DC00-$DCFF | Keyboard matrix |
| CIA #2 | N/A | $DD00-$DDFF | Serial, user port |
| VIA #1 | $9110-$911F | N/A | VIC-20 I/O |
| VIA #2 | $9120-$912F | N/A | VIC-20 I/O |
Character Set (PETSCII)
Both VIC-20 and C64 used PETSCII (PET Standard Code of Information Interchange), Commodore's variant of ASCII.
Key Differences from ASCII
Control Characters:
- CHR$(147): Clear screen (not standard ASCII)
- CHR$(19): Home cursor
- CHR$(13): Return (standard)
- CHR$(20): Delete character
Graphics Characters:
- Codes 160-223: Block graphics characters
- Codes 224-254: Special symbols
Reverse Video:
- CHR$(18): Reverse video on
- CHR$(146): Reverse video off
Color Control (C64):
- CHR$(5) + color code: Change text color
- Example: CHR$(5)+CHR$(1) = white text
Common PETSCII Examples
10 PRINT CHR$(147) ' Clear screen
20 PRINT CHR$(19) ' Home cursor
30 PRINT CHR$(18) ' Reverse video on
40 PRINT "HELLO"
50 PRINT CHR$(146) ' Reverse video off
SLP-BASIC Support:
- CHR$(147) implemented (clears terminal display)
- CHR$(19) implemented (homes cursor)
- Reverse video codes recognized but may not render
- Color codes recognized but don't change terminal colors
Feature Comparison Table
Complete feature-by-feature comparison of VIC-20, C64, and SLP-BASIC.
| Feature | VIC-20 | C64 | SLP-BASIC |
|---|---|---|---|
| BASIC Version | V2.0 | V2.0 | V2.0 |
| Memory (bytes free) | 3,583 | 38,911 | Configurable |
| Screen size | 22×23 | 40×25 | Configurable |
| All BASIC commands | ✓ | ✓ | ✓ |
| All functions | ✓ | ✓ | ✓ |
| Program save/load | Tape/disk | Tape/disk | localStorage |
| PEEK/POKE | Hardware | Hardware | Simulated |
| Graphics | VIC chip | VIC-II chip | ✗ |
| Sprites | ✗ | ✓ (8 sprites) | ✗ |
| Sound | VIC (3 voices) | SID (3 voices) | ✗ |
| Colors | 8/16 | 16 | ✗ |
| User port | ✓ | ✓ | ✗ |
| Serial I/O | ✓ | ✓ | ✗ |
| Machine language | ✓ (SYS) | ✓ (SYS) | ✗ |
| Execution speed | 1 MHz | 1 MHz | Much faster |
| Interrupt (STOP key) | ✓ | ✓ | ✓ (ESC key) |
Legend:
- ✓ = Fully supported
- ✗ = Not supported (hardware limitations)
- Configurable = User can choose mode
Program Compatibility
Most BASIC V2 programs run in SLP-BASIC without modification, provided they don't depend on hardware features.
Compatible Programs
Computational:
10 REM PRIME NUMBER FINDER
20 INPUT "MAX NUMBER"; M
30 FOR N = 2 TO M
40 GOSUB 100
50 IF PR = 1 THEN PRINT N
60 NEXT N
70 END
100 REM SUBROUTINE: CHECK PRIME
110 PR = 1
120 FOR D = 2 TO SQR(N)
130 IF N / D = INT(N / D) THEN PR = 0
140 NEXT D
150 RETURN
Runs perfectly in SLP-BASIC.
Text Processing:
10 REM STRING REVERSER
20 INPUT "ENTER TEXT"; A$
30 L = LEN(A$)
40 FOR I = L TO 1 STEP -1
50 B$ = B$ + MID$(A$, I, 1)
60 NEXT I
70 PRINT "REVERSED: "; B$
Runs perfectly in SLP-BASIC.
Data Management:
10 REM STUDENT GRADES
20 DIM NA$(10), SC(10)
30 FOR I = 1 TO 5
40 INPUT "NAME"; NA$(I)
50 INPUT "SCORE"; SC(I)
60 NEXT I
70 FOR I = 1 TO 5
80 PRINT NA$(I), SC(I)
90 NEXT I
Runs perfectly in SLP-BASIC.
Incompatible Programs
Graphics:
10 POKE 53280, 1 ' Border color
20 POKE 53281, 0 ' Background color
30 PRINT CHR$(147) ' Clear screen (works)
40 FOR I = 1024 TO 2023
50 POKE I, 160 ' Fill screen (no effect)
60 NEXT I
POKEs to screen memory have no effect (no graphics emulation).
Sound:
10 FOR F = 0 TO 255
20 POKE 54296, 15 ' Volume
30 POKE 54272, F ' Frequency
40 FOR D = 1 TO 100: NEXT D
50 NEXT F
No audio output (no sound emulation).
Hardware I/O:
10 OPEN 1, 8, 15 ' Open disk command channel
20 INPUT#1, E$ ' Read error channel
30 PRINT E$
40 CLOSE 1
OPEN/CLOSE/INPUT# not implemented (no hardware I/O).
Porting Guidelines
To make VIC-20/C64 programs compatible with SLP-BASIC:
- Remove graphics POKEs: Delete or comment out screen, color, and sprite manipulation
- Remove sound POKEs: Delete audio-related POKE statements
- Replace hardware I/O: Use LOAD/SAVE instead of OPEN/INPUT#/PRINT#
- Remove SYS calls: Machine language calls won't work
- Test with FRE(0): Ensure program fits in available memory
- Adjust formatting: Check output formatting for screen width (22 vs 40 columns)
Most computational and text-based programs require minimal or no changes.
Summary
SLP-BASIC provides authentic Commodore BASIC V2 language implementation with configurable hardware emulation. The BASIC language itself—syntax, commands, functions, operators—is 100% compatible with both VIC-20 and C64.
Key Takeaways:
- VIC-20 and C64 used identical BASIC V2 syntax
- Differences were in memory size and hardware capabilities
- SLP-BASIC supports both memory configurations
- PEEK/POKE work but don't affect real hardware
- Graphics and sound commands are recognized but non-functional
- Most computational programs run without modification
- Programs depending on graphics, sound, or I/O need adaptation
For authentic Commodore BASIC programming focused on algorithms, data processing, and text-based interaction, SLP-BASIC delivers the complete experience.
End of Appendix A
Proceed to Appendix B: Technical Specifications for details on the WebAssembly implementation architecture.
Appendix B: Technical Specifications
Introduction
SLP-BASIC v1.2 is a modern implementation of Commodore BASIC V2, built using contemporary web technologies while maintaining authentic vintage behavior. This appendix provides detailed technical specifications for developers, system administrators, and curious users who want to understand the architecture beneath the retro exterior.
Implementation Architecture
Language and Compilation
Core Language: Rust
- Version: 1.70+ (stable channel)
- Target: WebAssembly (wasm32-unknown-unknown)
- Compiler: rustc with wasm-pack build system
- Compilation flags: Optimized for size and speed
Why Rust:
- Memory safety without garbage collection
- Zero-cost abstractions
- Excellent WebAssembly support
- Strong type system prevents common bugs
- Near-native performance
Build Process:
wasm-pack build --target web --release
Produces:
basic_wasm_bg.wasm: Compiled interpreter (~150KB compressed)basic_wasm.js: JavaScript bindings- TypeScript definitions for integration
Module Structure
Core Components:
Lexer (
lexer.rs): Tokenizes BASIC source code- Input: String (program line or immediate command)
- Output: Token stream (keywords, identifiers, numbers, strings, operators)
- Features: Case-insensitive, multi-character operators, string literal handling
Parser (
parser.rs): Converts tokens to AST (Abstract Syntax Tree)- Input: Token stream from lexer
- Output: Structured AST nodes
- Validates syntax, reports errors with line numbers
Runtime (
runtime.rs): Execution environment- Manages program storage (line-numbered program lines)
- Variable storage (numeric, integer, string)
- Array storage (1D and 2D arrays)
- Function definitions (DEF FN)
- GOSUB stack for subroutine calls
- DATA/READ/RESTORE pointers
Executor (
executor.rs): Statement execution engine- Interprets AST nodes
- Implements control flow (IF, FOR, GOSUB, GOTO)
- Handles I/O (PRINT, INPUT, GET)
- Expression evaluation
- Error reporting
Memory (
memory.rs): Simulated 64KB address space- PEEK/POKE support
- Zero-initialized at startup
- No hardware mapping (pure simulation)
Bridge (
lib.rs): JavaScript/WebAssembly interface- Exported functions for JS interaction
- Memory management
- String marshaling between JS and Rust
- Event handling (input, interrupts)
WebAssembly Integration
JavaScript Interface (BasicInterpreter class):
class BasicInterpreter {
constructor(wasmModule)
init(): Promise<void>
executeImmediate(line: string): Promise<Result>
executeProgramLine(lineNumber: number, code: string): Promise<Result>
runProgram(): Promise<void>
resumeProgramOneLine(): Promise<ExecutionState>
interrupt(): void
reset(): void
getVariable(name: string): any
getFreeMemory(): number
}
State Management:
- Interpreter state encapsulated in Rust struct
- No global state (multiple interpreters possible)
- State serialization for save/load
Memory Model:
- Linear memory shared between JS and WASM
- Strings copied across boundary (UTF-8 encoding)
- Numeric values passed by value
- No direct pointer sharing (security)
Execution Model
Cooperative Execution
SLP-BASIC uses a cooperative execution model where programs run one line at a time, yielding control to the JavaScript event loop between lines.
Traditional (blocking) execution:
RUN → Execute line 10 → Execute line 20 → ... → END
[Browser frozen during execution]
Cooperative execution:
RUN → Execute line 10 → Yield → Execute line 20 → Yield → ... → END
[Event loop runs] [Event loop runs]
Implementation:
The resume_program_one_line() method:
- Check if program is running
- Fetch next line to execute
- Parse and execute the line
- Update program counter
- Return execution state (running/stopped/error)
- Yield control to JavaScript
Benefits:
- UI remains responsive during long-running programs
- ESC key interruption processed between lines
- No "unresponsive script" warnings
- Animation frames can be processed
- Network requests don't block
Limitations:
- Very tight loops have visible line-by-line execution
- Timing of original hardware not exactly replicated
- Programs depending on precise timing may behave differently
Performance Impact:
- Minimal for most programs (line overhead ~0.01ms)
- Noticeable only in empty loops executing thousands of times per second
- Mitigated by fast WASM execution (10,000+ lines/sec typical)
Program Flow
Immediate Mode:
User types: PRINT 2+2
↓
JavaScript sends to WASM
↓
Lexer tokenizes
↓
Parser creates AST
↓
Executor evaluates and prints result
↓
Result sent back to JavaScript
↓
Displayed in terminal
Program Mode:
User types: 10 PRINT 2+2
↓
JavaScript sends to WASM
↓
Lexer tokenizes
↓
Parser validates syntax
↓
Line stored in runtime program storage
↓
Acknowledgment sent to JavaScript
RUN Command:
User types: RUN
↓
JavaScript calls runProgram()
↓
WASM sets program counter to first line
↓
JavaScript calls resumeProgramOneLine() repeatedly
↓
Each call executes one line and returns state
↓
Continue until state is "stopped" or error
Error Handling
Error Types:
Syntax Errors: Detected during parsing
- Reported immediately when line is entered
- Line rejected, not stored in program
- Example:
10 PRINT(missing argument)
Runtime Errors: Detected during execution
- Program stops at offending line
- Error message printed with line number
- State preserved for inspection
- Example:
?DIVISION BY ZERO ERROR IN 30
System Errors: WASM or JS-level errors
- Caught and converted to BASIC error messages
- Prevent crashes, maintain stability
Error Recovery:
- Errors return to READY prompt
- Variables retain values (unless NEW/CLR used)
- Program remains in memory
- Can fix error and CONT or RUN again
Data Types and Storage
Numeric Variables
Representation: IEEE 754 single-precision (32-bit) floating-point
Range:
- Minimum: ±1.4 × 10^-45 (subnormal)
- Maximum: ±3.4 × 10^38
- Precision: ~7 decimal digits
Storage: 4 bytes per variable
Operations:
- Addition, subtraction, multiplication, division: Hardware FPU
- Exponentiation: Software implementation
- Transcendental functions (SIN, COS, LOG, EXP): Rust std library
Precision Examples:
PRINT 1/3 ' 0.33333334 (7 digits)
PRINT 1E20 + 1 - 1E20 ' 0 (precision loss)
PRINT 0.1 + 0.2 ' 0.30000001 (floating-point artifact)
Integer Variables (%)
Representation: 16-bit signed two's complement
Range: -32768 to 32767
Storage: 2 bytes per variable
Operations:
- Arithmetic: Integer math (faster than float)
- Overflow: Wraps around (32767 + 1 = -32768)
- Division: Integer division (5% / 2% = 2%)
Performance: ~2-3× faster than floating-point for arithmetic
Use Cases:
- Loop counters
- Array indices
- Counts and tallies
- Flags and states
String Variables ($)
Representation: UTF-8 encoded byte sequence
Maximum Length: 255 characters
Storage:
- String descriptor: 3 bytes (pointer + length)
- String data: Variable (1 byte per ASCII character, 2-4 bytes per Unicode character)
Memory Management:
- Strings stored in separate heap
- Garbage collection when memory runs low
- String concatenation may trigger GC
Unicode Support: Full UTF-8 support (modern enhancement over original PETSCII)
Examples:
A$ = "HELLO" ' 5 bytes
B$ = "CAFÉ" ' 5 characters, 6 bytes (É = 2 bytes)
C$ = "🎮" ' 1 character, 4 bytes (emoji)
Arrays
Declaration: DIM name(size) or DIM name(rows, cols)
Indexing: Zero-based (0 to size inclusive)
DIM A(10)creates elements A(0) through A(10) (11 total)
Storage:
- Numeric arrays: 4 bytes per element
- Integer arrays: 2 bytes per element
- String arrays: 3 bytes per descriptor + string data
Maximum Size: Limited by available memory (FRE(0))
Access Time: O(1) constant time indexing
Multi-dimensional: Maximum 2 dimensions
DIM A(10, 20)creates 11×21 = 231 elements- Stored in row-major order
Memory Layout
Total Simulated Memory: 64KB (0-65535)
BASIC Memory Usage:
Low addresses
↓
Program lines (sorted by line number)
Variable storage (simple variables)
Array storage (array descriptors and data)
↓
[Free memory]
↓
String storage (grows downward from top)
↓
High addresses
FRE(0) Calculation:
Free memory = String storage start - Array storage end
Memory Operations:
- NEW: Clears program and all variables
- CLR: Clears variables but preserves program
- DIM: Allocates array space
- String operations: May trigger garbage collection
Worker Thread Architecture
Threading Model
Main Thread (UI thread):
- Handles user input from terminal
- Manages display updates
- Processes keyboard events
- Controls modem signal simulation
Worker Thread (computation thread):
- Runs WebAssembly interpreter
- Executes BASIC programs
- Performs all computation
- Isolated from DOM for performance
Communication: Message passing via postMessage()
Main Thread Worker Thread
| |
|---- Execute "PRINT 2+2" -->|
| | [Parse]
| | [Execute]
|<---- Result: "4" ---------|
| [Display] |
Benefits:
- UI never freezes during computation
- True parallel execution on multi-core systems
- Clean separation of concerns
- Security isolation
Coordination:
- Synchronous-looking API implemented via async/await
- Promises resolve when worker responds
- Interrupt signals sent via dedicated message type
Interrupt Handling
ESC Key Sequence:
- User presses ESC in terminal
- Main thread detects keypress
- Main thread sends interrupt message to worker
- Worker checks interrupt flag between line executions
- Worker stops program, sends "interrupted" state
- Main thread displays
^CandBREAK IN [line] - Prompt returns to READY
Latency: <100ms typical (bounded by line execution time)
Granularity: Between-line only (cannot interrupt mid-expression)
Example:
10 FOR I = 1 TO 1000000
20 PRINT I
30 NEXT I
RUN
1
2
3
[User presses ESC]
^C
BREAK IN 20
READY.
I/O and Storage
Terminal I/O
Output (PRINT):
- Text sent from worker to main thread via messages
- Main thread appends to terminal display
- No buffering (immediate character transmission)
- Line endings: CR+LF (PETSCII/Commodore standard)
Input (INPUT, GET):
- Main thread prompts user
- Input collected in terminal
- Sent to worker when complete (Enter key)
- Worker parses and assigns to variables
Flow Control:
- RTS/CTS signals simulated for authenticity
- No actual flow control needed (memory-based I/O)
- Signals asserted/deasserted for modem protocol compliance
Persistent Storage
Backend: Browser localStorage API
Namespace: emulator.ca/disk/basic/
File Format: Plain text (human-readable)
10 PRINT "HELLO"
20 INPUT "NAME"; N$
30 PRINT "HELLO, "; N$
40 END
SAVE Operation:
- Serialize program to text format
- Store in localStorage with key:
emulator.ca/disk/basic/FILENAME - Overwrites existing file if present
- Returns success/failure status
LOAD Operation:
- Retrieve from localStorage by key
- Clear current program (NEW)
- Parse each line and add to program storage
- Return to READY prompt
- Report error if file not found
Storage Limits:
- Typical browsers: 5-10MB per origin
- Typical BASIC program: 1-10KB
- Hundreds of programs fit comfortably
Persistence:
- Survives browser restarts
- Survives tab closes
- Persists until localStorage cleared by user
- Not synced across devices (local only)
BackendDisk Integration
Interface: JavaScript bridge between BASIC and localStorage
Operations Supported:
SAVE "filename": Write program to storageLOAD "filename": Read program from storage- Future: DIR/CATALOG, DELETE/SCRATCH
Error Handling:
?FILE NOT FOUND ERROR: File doesn't exist?SAVE ERROR: Write failed (quota exceeded, permissions)?LOAD ERROR: Read failed or corrupt file
Filename Rules:
- Must be quoted strings:
SAVE "MYPROG" - Case-insensitive (stored lowercase)
- No path separators or special characters
- Maximum length: 255 characters
Performance Characteristics
Execution Speed
Benchmarks (typical modern hardware):
| Operation | Operations/sec | Notes |
|---|---|---|
| Empty loop | 100,000 | FOR/NEXT overhead |
| Integer arithmetic | 1,000,000+ | Native performance |
| Floating-point arithmetic | 500,000+ | Hardware FPU |
| String concatenation | 100,000 | Memory allocation overhead |
| Array access | 500,000 | Bounds checking |
| Function calls (DEF FN) | 200,000 | Lookup + evaluation |
| GOSUB/RETURN | 300,000 | Stack operations |
Comparison to Original Hardware:
- C64 CPU: ~1 MHz 6502 processor
- WASM execution: ~100-1000× faster for arithmetic
- Overall program execution: ~50-200× faster typical
Example:
10 FOR I = 1 TO 10000
20 S = S + I
30 NEXT I
- Original C64: ~3-5 seconds
- SLP-BASIC: ~0.05 seconds (100× faster)
Memory Performance
Allocation:
- Variable creation: <0.001ms
- Array allocation: ~0.01ms per 100 elements
- String creation: ~0.001ms + data copy time
Garbage Collection:
- Triggered when string memory fragmented
- Pauses execution briefly (<5ms typical)
- Automatic, transparent to user
Memory Limits:
- WASM linear memory: 64KB initial, grows to 16MB if needed
- BASIC simulated memory: 64KB fixed
- Actual memory usage: ~1-2MB for interpreter + program data
Startup Performance
Cold Start (first load):
- WASM download:
150KB compressed (50-200ms) - WASM compilation: ~50-100ms
- Initialization: ~10ms
- Total: <500ms on broadband
Warm Start (cached):
- WASM from cache: ~10ms
- Initialization: ~10ms
- Total: <50ms
Responsiveness
Interrupt Latency:
- ESC key to program stop: <100ms typical
- Bounded by single line execution time
- Worst case: <1000ms (very complex expression)
UI Update Frequency:
- PRINT output: Immediate (unbuffered)
- Frame rate: 60 FPS maintained
- Input echo: <16ms typical
Browser Compatibility
Minimum Requirements
Browsers (and minimum versions):
- Chrome/Edge: 90+ (April 2021)
- Firefox: 88+ (April 2021)
- Safari: 14+ (September 2020)
- Opera: 76+ (June 2021)
Required Web APIs:
- WebAssembly (wasm32)
- Web Workers
- LocalStorage
- Promises / async-await
- ES2015+ JavaScript features
- TextEncoder/TextDecoder (UTF-8)
Platform Support
| Platform | Status | Notes |
|---|---|---|
| Windows 10+ | ✓ Full | All modern browsers |
| macOS 10.15+ | ✓ Full | All modern browsers |
| Linux (modern) | ✓ Full | All modern browsers |
| ChromeOS | ✓ Full | Chrome browser |
| iOS 14+ | ✓ Full | Safari, Chrome |
| Android 10+ | ✓ Full | Chrome, Firefox |
| Older systems | ⚠ Partial | May lack WASM support |
Mobile Considerations:
- Full functionality on phones and tablets
- Touch keyboard works for input
- Screen size may limit display (scrolling)
- Performance excellent on modern devices
Security Model
WebAssembly Sandbox:
- No direct system access
- No file system access (except localStorage)
- No network access
- No native code execution
- Memory isolated from host
LocalStorage Security:
- Origin-bound (emulator.ca only)
- No cross-origin access
- No server transmission
- Cleared by user browser settings
Content Security Policy Compatibility:
- No eval() or new Function()
- No inline scripts in WASM
- WASM execution allowed by CSP
- Safe for strict CSP environments
Limitations and Constraints
Known Limitations
Not Implemented:
- Graphics commands (POKE to VIC chip)
- Sound commands (POKE to SID chip)
- Sprite manipulation
- Hardware I/O (OPEN, CLOSE, CMD, PRINT#, INPUT#, GET#)
- Machine language (SYS, USR)
- VERIFY command
- IRQ/NMI interrupts
Behavioral Differences:
- WAIT command non-blocking (returns immediately)
- GET command non-blocking (returns empty string if no input)
- Timing not cycle-accurate
- No "jiffy clock" (TI/TI$ not real-time)
- PEEK/POKE simulated (no hardware effects)
Memory Constraints:
- 38,911 bytes (C64 mode) or 3,583 bytes (VIC-20 mode)
- Arrays limited by available memory
- String space shared with variables
- Deeply nested GOSUBs may exhaust stack
Performance Constraints:
- Line-by-line execution granularity
- Cooperative scheduling overhead
- Garbage collection pauses (brief)
- Message passing latency (main ↔ worker)
Future Enhancements
Planned:
- DIR/CATALOG command (list saved programs)
- DELETE/SCRATCH command (remove programs)
- IMPORT/EXPORT (download/upload programs as files)
- DEBUG mode (step through execution)
- Variable watch window
Under Consideration:
- Simple graphics API (non-hardware commands)
- Audio synthesis API (beeps and tones)
- Extended memory modes (more than 64KB)
- Network I/O (modern equivalent of OPEN)
Summary
SLP-BASIC v1.2 is a sophisticated WebAssembly implementation of Commodore BASIC V2:
Core Technology:
- Rust → WebAssembly compilation
- Worker thread architecture
- Cooperative execution model
- IEEE 754 floating-point arithmetic
- UTF-8 string support
Performance:
- 50-200× faster than original hardware
- <500ms cold start
- <100ms interrupt latency
- Near-native WASM execution speed
Compatibility:
- All modern browsers (2021+)
- Desktop and mobile platforms
- Authentic BASIC V2 language support
- localStorage for program persistence
Architecture:
- Modular Rust components (lexer, parser, runtime, executor)
- Message-passing between main thread and worker
- Simulated 64KB address space
- Isolated security sandbox
This technical foundation delivers authentic Commodore BASIC programming with modern reliability, performance, and accessibility.
End of Appendix B
Proceed to Appendix C: Differences from Standard BASIC for a detailed comparison with other BASIC dialects.
Appendix C: Differences from Standard BASIC
Introduction
SLP-BASIC v1.2 faithfully implements Commodore BASIC V2, which itself was a specific dialect of BASIC derived from Microsoft's 6502 BASIC. This appendix documents what features are not implemented compared to the original Commodore specification, explains why these features are omitted, and describes modern enhancements and future plans.
Understanding what's different helps you:
- Know what Commodore BASIC programs will and won't work
- Understand the rationale behind implementation decisions
- Set appropriate expectations for hardware-dependent features
- Plan for future enhancements
Hardware I/O Commands
The most significant differences between SLP-BASIC and original Commodore BASIC involve hardware interaction. Commodore computers had extensive I/O capabilities for tape drives, disk drives, printers, modems, and other peripherals. SLP-BASIC runs in a web browser with no physical hardware to control.
Not Implemented: File Channel I/O
Commands:
OPEN filenum, device, secondary [, "filename"]CLOSE filenumCMD filenumPRINT# filenum, dataINPUT# filenum, variableGET# filenum, variable
Original Purpose: These commands managed I/O channels to Commodore's IEC serial bus devices (disk drives, printers) and RS-232 interfaces.
Example (Original Commodore):
10 REM WRITE TO DISK FILE
20 OPEN 1, 8, 2, "DATA.TXT,S,W"
30 PRINT#1, "HELLO WORLD"
40 CLOSE 1
Why Not Implemented:
- No IEC bus or physical devices in browser environment
- Browser security model prohibits direct device access
- File operations handled through modern storage APIs instead
Alternative: Use SAVE and LOAD for program storage:
10 REM SAVE PROGRAM TO STORAGE
20 SAVE "MYPROG"
Status: Recognized by parser but returns error if used
Not Implemented: Machine Language Interface
Commands:
SYS addressUSR(x)
Original Purpose: Call 6502 machine language subroutines for speed-critical operations, hardware control, or extending BASIC functionality.
Example (Original Commodore):
10 REM CALL ML ROUTINE AT $C000
20 POKE 49152, 169 ' LDA #$00
30 POKE 49153, 0
40 POKE 49154, 96 ' RTS
50 SYS 49152
Why Not Implemented:
- No 6502 processor to execute machine code
- WebAssembly security model prevents arbitrary code execution
- BASIC provides sufficient functionality for most tasks
Alternative: For performance-critical operations, the WASM interpreter itself is already highly optimized. Most programs don't need machine language optimization.
Status: SYS command recognized, USR() function exists but both return error
Not Implemented: Hardware Registers
Functionality: Direct hardware manipulation via PEEK/POKE
Original Use Cases:
- VIC/VIC-II chip (graphics, sprites, colors, screen)
- SID chip (sound synthesis)
- CIA chips (keyboard, joystick, timers, serial I/O)
- Memory configuration (bank switching, ROM/RAM mapping)
Example (Original Commodore - Graphics):
10 REM CHANGE BORDER AND BACKGROUND COLORS
20 POKE 53280, 1 ' Border white
30 POKE 53281, 0 ' Background black
40 REM FILL SCREEN WITH CHARACTER
50 FOR I = 1024 TO 2023
60 POKE I, 81 ' Character 'Q'
70 POKE 55296+I-1024, 1 ' Color white
80 NEXT I
Example (Original Commodore - Sound):
10 REM SIMPLE TONE ON SID CHIP
20 POKE 54296, 15 ' Volume max
30 POKE 54273, 17 ' Voice 1 waveform (sawtooth)
40 POKE 54272, 50 ' Voice 1 frequency low
50 POKE 54273, 20 ' Voice 1 frequency high
60 POKE 54276, 240 ' Voice 1 sustain/release
70 POKE 54278, 65 ' Attack/decay
80 POKE 54273, 17 ' Gate on
SLP-BASIC Behavior:
- PEEK and POKE work with simulated 64KB memory
- Memory is initialized but not connected to hardware
- POKE writes are stored but have no visual/audio effect
- PEEK reads return 0 or simulated values
- Programs don't crash, but hardware effects don't occur
Why Limited:
- No graphics hardware to control
- No sound hardware to drive
- Browser APIs don't expose hardware-level control
- Focus on language features, not hardware emulation
Status: Commands work, but no hardware emulation
Not Implemented: Device Status
Commands/Functions:
ST(status variable for I/O operations)TI(jiffy clock - system timer)TI$(time string "HHMMSS")
Original Purpose:
- ST: Read error status from tape/disk operations
- TI/TI$: System time in 1/60 second increments
Example (Original Commodore):
10 REM CHECK DISK ERROR STATUS
20 OPEN 1, 8, 15
30 INPUT#1, E, E$, T, S
40 IF E > 0 THEN PRINT "ERROR:"; E$
50 CLOSE 1
SLP-BASIC Behavior:
- ST not implemented (no I/O devices to report status)
- TI/TI$ could be implemented with JavaScript Date API
- Currently not implemented
Status: Not implemented, future consideration
Commands Not Implemented
VERIFY
Purpose: Compare program in memory to saved version on tape/disk
Syntax: VERIFY "filename"
Original Use: Ensure tape/disk write was successful by reading back and comparing to memory.
Example (Original Commodore):
10 SAVE "MYPROG"
20 VERIFY "MYPROG"
30 IF ST = 0 THEN PRINT "VERIFY OK"
Why Not Implemented:
- Modern storage (localStorage) is reliable (no write errors)
- Browser APIs provide atomic write operations
- Verification unnecessary with reliable storage
Status: Recognized by parser, returns error
Alternative: Trust SAVE operation (localStorage is reliable)
WAIT
Purpose: Wait for memory location to have specific bit pattern
Syntax: WAIT address, mask [, xor_mask]
Original Use: Synchronize with hardware events (raster beam position, I/O completion).
Example (Original Commodore):
10 REM WAIT FOR TOP OF SCREEN (RASTER SYNC)
20 WAIT 53266, 128
30 REM GRAPHICS UPDATE HERE
SLP-BASIC Behavior:
- Command is recognized and parsed
- Immediately returns (non-blocking)
- Does not actually wait for memory condition
- Prevents infinite loops in browser
Why Non-Blocking:
- No hardware to synchronize with
- Blocking would freeze browser
- Cooperative execution model incompatible with blocking
Status: Implemented but non-blocking (returns immediately)
Behavioral Differences
These features exist but behave differently than on original hardware.
GET Statement
Standard Behavior (Commodore):
- Waits for single keypress
- Returns key character in variable
- No echo to screen
- Blocks until key pressed
SLP-BASIC Behavior:
- Non-blocking (returns immediately)
- Returns empty string if no key waiting
- Must be called repeatedly in loop to detect keypress
Example (Original Commodore):
10 GET A$
20 IF A$ = "" THEN 10 ' Wait for keypress
30 PRINT "YOU PRESSED: "; A$
Example (SLP-BASIC - requires loop):
10 GET A$
20 IF A$ = "" THEN 10 ' Polling loop
30 PRINT "YOU PRESSED: "; A$
Reason: Browser input APIs are asynchronous; blocking waits freeze UI
Impact: Programs using GET work but may have different responsiveness
PEEK/POKE
Standard Behavior (Commodore):
- Direct hardware register access
- Immediate effect on graphics, sound, I/O
- Memory-mapped hardware control
SLP-BASIC Behavior:
- Access to simulated 64KB memory space
- No hardware effects (graphics, sound, I/O)
- Memory retained between PEEK/POKE operations
- Programs don't crash but hardware features non-functional
Example:
10 POKE 53280, 1 ' Would change C64 border color
20 PRINT PEEK(53280) ' Prints 1 (value stored)
Line 10 stores value 1 at address 53280. Line 20 reads it back. But no border color change occurs (no graphics hardware).
Reason: No hardware to control in browser environment
Impact: Computational programs work; graphics/sound programs don't produce visual/audio output
Execution Timing
Standard Behavior (Commodore):
- Predictable timing (1 MHz 6502 clock)
- Programs can rely on execution speed for delays
- FOR loop timing consistent
SLP-BASIC Behavior:
- Much faster execution (50-200× typical)
- Timing varies with CPU load and JavaScript scheduling
- Cooperative execution introduces small delays between lines
Example (Original Commodore):
10 FOR I = 1 TO 1000: NEXT I ' ~0.1 second delay
20 PRINT "DONE"
Example (SLP-BASIC):
10 FOR I = 1 TO 1000: NEXT I ' ~0.001 second
20 PRINT "DONE"
Reason: Modern hardware is much faster; cooperative scheduling differs from continuous execution
Impact:
- Programs run much faster (usually beneficial)
- Timing-dependent programs (games, animations) may need adjustment
- Delays require larger loop counts
Modern Enhancements
SLP-BASIC adds some modern conveniences while maintaining compatibility.
UTF-8 String Support
Enhancement: Full Unicode string support
Original Commodore: PETSCII character set (256 characters, including graphics characters)
SLP-BASIC: UTF-8 encoding (all Unicode characters)
Example:
10 NAME$ = "Café" ' Works (UTF-8 'é')
20 EMOJI$ = "🎮" ' Works (emoji)
30 PRINT NAME$, EMOJI$
Benefit:
- International characters supported
- Modern text processing
- Emoji and symbols available
Compatibility: ASCII and basic PETSCII characters identical
LocalStorage Backend
Enhancement: Modern browser storage for programs
Original Commodore: Cassette tape or floppy disk (sequential access, unreliable)
SLP-BASIC: Browser localStorage (instant access, reliable)
Benefits:
- Instant SAVE/LOAD (no tape rewind, no disk spin-up)
- 100% reliable (no tape degradation, no disk errors)
- Persistent across sessions
- No physical media required
API:
SAVE "filename" ' Instant save to localStorage
LOAD "filename" ' Instant load from localStorage
Limitation: Programs stored per-browser (not synced across devices)
Interrupt with ESC Key
Enhancement: ESC key interrupts program execution
Original Commodore: RUN/STOP key (sometimes STOP+RESTORE)
SLP-BASIC: ESC key (standard on modern keyboards)
Behavior:
- Press ESC during program execution
- Program halts at current line
- Displays
^CandBREAK IN [line] - Returns to READY prompt
Benefit: Universal key available on all keyboards
Cooperative Execution
Enhancement: Non-blocking execution model
Original Commodore: Continuous execution until program completes
SLP-BASIC: Line-by-line execution with yields between lines
Benefits:
- UI remains responsive
- Browser doesn't freeze
- Can interrupt cleanly
- Smooth animation possible
Trade-off: Very tight loops show small performance overhead
Improved Error Messages
Enhancement: Clear error reporting with context
Original Commodore: Terse uppercase error messages
SLP-BASIC: Same format, but sometimes with additional context
Example (Commodore):
?SYNTAX ERROR IN 10
Example (SLP-BASIC):
?SYNTAX ERROR IN 10
Note: Currently identical to maintain authenticity; future versions may add optional verbose mode
Future Roadmap
Planned enhancements while maintaining core compatibility.
Planned: Directory Commands
Commands:
DIRorCATALOG: List saved programsDELETE "filename"orSCRATCH "filename": Remove saved program
Purpose: Manage programs in localStorage
Example (Planned):
DIR
MYPROG
GAME1
GAME2
UTILITY
SCRATCH "GAME1"
DELETED: GAME1
DIR
MYPROG
GAME2
UTILITY
Status: Design phase, not yet implemented
Planned: Import/Export
Feature: Download/upload programs as text files
Commands (proposed):
EXPORT "filename.bas": Download program as text fileIMPORT "filename.bas": Upload program from text file
Purpose:
- Share programs between users
- Backup programs outside browser
- Transfer programs to/from real Commodore hardware
Status: Under consideration
Planned: Debug Mode
Feature: Step-through execution and variable inspection
Commands (proposed):
DEBUG ON: Enable debug modeDEBUG OFF: Disable debug modeSTEP: Execute one line and pauseVARS: Display all variablesWATCH "variable": Track variable value
Example (Proposed):
DEBUG ON
RUN
[Program pauses at line 10]
STEP
[Executes line 10, pauses at line 20]
VARS
A = 5, B$ = "HELLO", COUNT% = 1
STEP
[Continues]
Status: Design phase
Under Consideration: Graphics API
Feature: Simple graphics commands (non-hardware)
Commands (proposed):
SCREEN mode: Set graphics modePIXEL x, y, color: Set pixelLINE x1, y1, x2, y2, color: Draw lineCIRCLE x, y, radius, color: Draw circle
Purpose: Enable basic graphics programming without hardware emulation
Example (Proposed):
10 SCREEN 1
20 FOR I = 0 TO 319
30 PIXEL I, I, 1
40 NEXT I
Status: Exploration phase; would break strict Commodore compatibility
Under Consideration: Audio API
Feature: Simple sound generation (non-hardware)
Commands (proposed):
SOUND frequency, duration: Play toneBEEP: Standard beep soundNOISE duration: White noise
Purpose: Enable basic audio without SID chip emulation
Example (Proposed):
10 SOUND 440, 500 ' 440 Hz for 500ms (A4 note)
20 BEEP
30 NOISE 100
Status: Exploration phase; would break strict Commodore compatibility
Why These Choices?
The implementation philosophy behind what's included and excluded.
Principle 1: Focus on Core Language
Goal: Perfect BASIC language implementation
Included:
- All keywords, operators, functions
- Flow control (IF, FOR, GOTO, GOSUB)
- Data structures (arrays, strings)
- Mathematical and string functions
Excluded:
- Hardware-specific features
- Platform-dependent I/O
- Machine language interfaces
Rationale: The BASIC language itself is timeless and valuable. Hardware interfaces are platform-specific and not central to learning programming.
Principle 2: Modern Reliability
Goal: Eliminate vintage hardware frustrations
Enhanced:
- Instant, reliable program save/load
- No tape alignment issues
- No disk read errors
- Consistent execution speed
Trade-off: Some timing-dependent programs need adjustment
Rationale: Modern users expect reliable storage and consistent performance. Hardware limitations of the 1980s shouldn't constrain 2020s implementation.
Principle 3: Security and Sandboxing
Goal: Safe execution in browser environment
Required:
- No arbitrary code execution (no SYS/USR)
- No direct hardware access (simulated PEEK/POKE)
- No file system access (localStorage only)
- No network access without user consent
Rationale: Browser security model is non-negotiable. Any implementation must respect these constraints.
Principle 4: Authentic Experience
Goal: Feel like real Commodore BASIC
Preserved:
- Exact syntax and keywords
- Error messages with original format
- Line-numbered programming
- Same quirks and limitations (2-char variable significance)
Enhanced:
- Better storage reliability
- Faster execution
- Modern character encoding
Rationale: Balance authenticity with modern improvements. Core experience should match vintage memories while eliminating frustrating limitations.
Compatibility Matrix
Summary of what works and what doesn't.
| Feature | Commodore | SLP-BASIC | Notes |
|---|---|---|---|
| Core Language | |||
| PRINT, INPUT, LET | ✓ | ✓ | Identical |
| IF...THEN...ELSE | ✓ | ✓ | ELSE clause works |
| FOR...NEXT | ✓ | ✓ | Including STEP |
| GOTO, GOSUB, RETURN | ✓ | ✓ | Identical |
| ON...GOTO/GOSUB | ✓ | ✓ | Computed branches |
| END, STOP, CONT | ✓ | ✓ | Identical |
| DIM, DATA, READ | ✓ | ✓ | Arrays and data |
| DEF FN | ✓ | ✓ | User functions |
| All math functions | ✓ | ✓ | SIN, COS, LOG, etc. |
| All string functions | ✓ | ✓ | LEFT$, MID$, etc. |
| Program Management | |||
| NEW, LIST, RUN | ✓ | ✓ | Identical |
| CLR, REM | ✓ | ✓ | Identical |
| SAVE, LOAD | ✓ | ✓ | localStorage backend |
| VERIFY | ✓ | ✗ | Not needed |
| Memory Access | |||
| PEEK, POKE | ✓ | ⚠ | Simulated, no hardware |
| FRE(0), POS(0) | ✓ | ✓ | Memory and cursor |
| Hardware I/O | |||
| OPEN, CLOSE | ✓ | ✗ | No physical I/O |
| PRINT#, INPUT#, GET# | ✓ | ✗ | No device channels |
| CMD | ✓ | ✗ | No output redirection |
| Machine Language | |||
| SYS | ✓ | ✗ | No 6502 execution |
| USR() | ✓ | ✗ | No ML functions |
| Timing/Status | |||
| WAIT | ✓ | ⚠ | Non-blocking |
| GET (keyboard) | ✓ | ⚠ | Non-blocking |
| TI, TI$ | ✓ | ✗ | Not implemented |
| ST | ✓ | ✗ | No device status |
Legend:
- ✓ = Fully supported and compatible
- ⚠ = Supported but with behavioral differences
- ✗ = Not supported
Summary
SLP-BASIC v1.2 provides complete implementation of the Commodore BASIC V2 language while omitting hardware-specific features that don't apply to a browser environment.
What's Included:
- Complete BASIC language (commands, functions, operators)
- Program management (NEW, LIST, RUN, SAVE, LOAD)
- All data types (numeric, integer, string, arrays)
- Flow control (IF, FOR, GOTO, GOSUB)
- Mathematical and string functions
What's Excluded:
- Hardware I/O (OPEN, CLOSE, PRINT#, INPUT#)
- Machine language (SYS, USR)
- Hardware registers (graphics, sound via POKE)
- Device status (ST, TI/TI$)
- VERIFY command
Modern Enhancements:
- UTF-8 string support (Unicode)
- Reliable localStorage backend
- ESC key interrupt
- Cooperative execution (responsive UI)
- Much faster execution
Philosophy: Focus on the timeless BASIC language while leveraging modern technology for reliability and performance. Preserve authentic programming experience while eliminating hardware limitations.
For computational programming, text processing, algorithm learning, and classic BASIC coding, SLP-BASIC provides the complete Commodore BASIC V2 experience.
End of Appendix C
Proceed to Appendix D: Glossary for definitions of technical terms used throughout this manual.
Appendix D: Glossary
BASIC Language Terms
Array: An ordered collection of variables accessed by numeric index. Declared with DIM. Example: DIM SCORES(10) creates an array of 11 elements (0-10).
Assignment: Giving a value to a variable. Example: X = 5 assigns the value 5 to variable X. The LET keyword is optional.
BASIC: Beginner's All-purpose Symbolic Instruction Code. A programming language designed for simplicity and ease of learning, created in 1964 at Dartmouth College.
Branch: Changing program flow by jumping to a different line number. GOTO and GOSUB are branching commands.
Command: An instruction to the interpreter executed immediately without a line number (immediate mode) or as part of a program (program mode).
Concatenation: Joining strings together. In BASIC, the + operator concatenates strings. Example: "HELLO" + " " + "WORLD" produces "HELLO WORLD".
Conditional: A statement that executes different code based on a condition. IF...THEN...ELSE is a conditional statement.
CONT: Continue command. Resumes program execution after STOP has been used to pause the program.
Delimiter: A character that separates items. PRINT uses comma (tab zones) and semicolon (tight spacing) as delimiters.
Expression: A combination of values, variables, operators, and functions that evaluates to a single value. Example: 2 + 3 * 4 evaluates to 14.
Flow Control: Commands that determine the order in which program statements execute. Includes IF, FOR, GOTO, GOSUB, and RETURN.
Function: A predefined operation that takes input (arguments) and returns a value. Examples: SQR(9) returns 3, LEN("HELLO") returns 5.
Immediate Mode: Executing commands directly at the READY prompt without a line number. Results display immediately.
Increment: The change amount in a FOR loop. Specified with STEP keyword. Example: FOR I = 1 TO 10 STEP 2 increments by 2 each iteration.
Index: The numeric position used to access an array element. Example: In A(5), the index is 5.
Integer: A whole number without a decimal point. In BASIC, integer variables use the % suffix and range from -32768 to 32767.
Iteration: One pass through a loop. A FOR loop from 1 TO 10 has 10 iterations.
Keyword: A reserved word in BASIC that has special meaning. Examples: PRINT, IF, FOR, GOTO, DIM. Keywords cannot be used as variable names.
Line Number: A numeric label (1-63999) that identifies a program line. Lines execute in numerical order unless flow control commands change the sequence.
Literal: A fixed value written directly in code. Examples: 42 (numeric literal), "HELLO" (string literal).
Loop: A sequence of statements that repeats multiple times. FOR...NEXT creates a counting loop. GOTO can create an infinite loop.
Nested: Structures placed inside other structures. Example: FOR loops inside other FOR loops are nested loops.
Numeric Variable: A variable that stores numbers. Supports floating-point (default) or integer (% suffix) values.
Operator: A symbol that performs an operation on values. Arithmetic operators (+, -, *, /, ^), comparison operators (=, <, >, <=, >=, <>), logical operators (AND, OR, NOT).
Parameter: A value passed to a function or provided to a command. Example: In SQR(25), the parameter is 25.
Precedence: The order in which operators are evaluated. Parentheses first, then exponentiation, then multiplication/division, then addition/subtraction.
Program Mode: Entering commands with line numbers to build a stored program. Lines are not executed until RUN is used.
Prompt: The symbol(s) indicating the interpreter is ready for input. BASIC uses READY. as its main prompt.
REPL: Read-Eval-Print Loop. The interactive programming environment where you type a command, it executes, results print, and the prompt returns.
Return Value: The result produced by a function. Example: SQR(16) has a return value of 4.
Statement: A complete instruction in BASIC. Example: PRINT "HELLO" is a statement. Multiple statements can be on one line separated by colons.
String: A sequence of characters enclosed in quotes. String variables use the $ suffix. Example: NAME$ = "ALICE".
Subroutine: A reusable section of code called with GOSUB and ended with RETURN. Similar to a function but no formal parameters or return value.
Syntax: The rules that define valid BASIC code structure. Syntax errors occur when code doesn't follow these rules.
Token: The smallest meaningful unit in BASIC code. The lexer breaks code into tokens (keywords, numbers, strings, operators) for the parser to process.
Type Suffix: A character appended to variable names indicating data type: no suffix (floating-point), % (integer), $ (string).
Variable: A named storage location that holds a value. The value can change during program execution. Variable names must start with a letter.
Hardware and System Terms
6502: The 8-bit microprocessor used in Commodore VIC-20 and C64. Runs at approximately 1 MHz clock speed.
Address: A numeric location in memory. BASIC's PEEK and POKE commands access memory by address. Valid range: 0-65535 (64KB).
ASCII: American Standard Code for Information Interchange. A character encoding standard assigning numbers to letters, digits, and symbols. BASIC uses ASC() and CHR$() to convert between characters and ASCII codes.
Banner: The startup message displayed when BASIC loads. Shows the BASIC version and available memory (e.g., "38911 BASIC BYTES FREE").
Baud Rate: The speed of data transmission measured in bits per second. The modem connection to SLP-BASIC simulates 1200 baud.
Buffer: Temporary storage for data being transferred. The BASIC input buffer holds typed commands before execution.
Byte: A unit of computer memory consisting of 8 bits. Can store values 0-255 or one character.
C64: Commodore 64. A home computer released in 1982 with 64KB RAM and BASIC V2. The best-selling single computer model ever made (17+ million units).
Carrier: The signal indicating an active modem connection. Loss of carrier (DCD signal drop) terminates the connection.
Character Set: The collection of symbols available for display. Commodore computers used PETSCII, an extended ASCII variant with graphics characters.
CTS: Clear To Send. An RS-232 signal indicating the remote device is ready to receive data. Part of hardware flow control.
Cursor: The blinking indicator showing where the next character will appear on screen. POS(0) returns the cursor's column position.
DCD: Data Carrier Detect. An RS-232 signal indicating the modem connection is active. When DCD drops, the connection is lost.
DTR: Data Terminal Ready. An RS-232 signal indicating the terminal (or computer) is powered on and ready for communication. Dropping DTR cleanly disconnects.
Flow Control: The mechanism preventing data loss during transmission by signaling when to pause and resume sending. Uses RTS/CTS signals.
Hardware: Physical computer components (chips, memory, disk drives, etc.). Many BASIC commands on original Commodore computers controlled hardware directly.
I/O: Input/Output. The transfer of data between the computer and external devices (keyboard, screen, disk drives, etc.).
IEC Bus: The serial communication system used by Commodore computers to connect to disk drives, printers, and other peripherals.
Interpreter: A program that executes code line-by-line rather than compiling it first. BASIC is an interpreted language.
Jiffy: A unit of time in Commodore BASIC equal to 1/60 second (NTSC) or 1/50 second (PAL). The TI variable counts jiffies since power-on.
Kernal: The core operating system routines in Commodore computers, stored in ROM. Handles I/O, memory management, and other low-level tasks.
LocalStorage: A browser API providing persistent storage for web applications. SLP-BASIC stores saved programs in localStorage.
Memory: Storage for program code, variables, and data. Commodore BASIC uses RAM (Random Access Memory) which loses contents when powered off.
Modem: Modulator-Demodulator. A device that converts digital data to analog signals for transmission over phone lines. SLP-BASIC connects via a simulated modem.
PETSCII: PET Standard Code of Information Interchange. Commodore's character encoding, an extension of ASCII including graphics characters and control codes.
Register: A small, fast storage location in a hardware chip. Graphics and sound chips use registers to control their operation, accessed via PEEK/POKE.
ROM: Read-Only Memory. Non-volatile memory containing firmware or system software. Commodore BASIC V2 was stored in ROM.
RS-232: A standard for serial communication defining voltage levels, signal timing, and connector pinouts. Used for modems, terminals, and serial printers.
RTS: Request To Send. An RS-232 signal indicating the device wants to transmit data. Part of hardware flow control handshaking.
SID: Sound Interface Device. The Commodore 64's programmable sound chip, providing three-voice music synthesis. One of the most advanced sound chips of its era.
Terminal: A device (or software emulating a device) for text-based interaction with a computer. SLP-BASIC is accessed through a terminal emulator.
UART: Universal Asynchronous Receiver-Transmitter. Hardware that handles serial communication, converting parallel data to serial and vice versa.
VIC: Video Interface Chip. The graphics chip in the VIC-20, providing character display and simple graphics capabilities.
VIC-II: The advanced graphics chip in the Commodore 64, supporting sprites, scrolling, and multiple display modes.
WASM: WebAssembly. A binary instruction format for executing code in web browsers at near-native speed. SLP-BASIC is implemented in Rust and compiled to WASM.
Worker Thread: A separate execution context in web browsers that runs code without blocking the UI. SLP-BASIC runs in a worker thread for responsiveness.
Programming Concepts
Algorithm: A step-by-step procedure for solving a problem or performing a task. Programs implement algorithms in code.
Bug: An error in a program that causes incorrect behavior. The term originated from actual insects interfering with early computer equipment.
Comment: Text in source code meant for human readers, ignored by the interpreter. BASIC uses REM for comments.
Debugging: The process of finding and fixing bugs in a program. Techniques include printing variable values and testing sections independently.
Flag: A variable used to indicate a state or condition, typically set to 0 (false) or 1 (true). Example: GAMEOVER = 1 indicates the game has ended.
Initialization: Setting variables to starting values at program beginning. Good practice prevents undefined behavior.
Logic Error: A bug where code runs without syntax errors but produces wrong results due to flawed logic or algorithm.
Modular Design: Breaking programs into logical sections (subroutines) that perform specific tasks. Makes code easier to understand and maintain.
Optimization: Improving program performance (speed or memory usage) while maintaining correct behavior.
Pseudocode: An informal description of an algorithm using structured English-like statements. Helps plan programs before coding.
Recursion: A technique where a subroutine calls itself. Not practical in BASIC due to limited GOSUB stack depth.
Runtime: The period when a program is executing, as opposed to when it's being written or edited. Runtime errors occur during program execution.
Scope: The region of code where a variable is accessible. BASIC has global scope—all variables are accessible everywhere (no local variables).
Syntax Error: An error where code doesn't follow BASIC language rules. Detected when lines are entered or when RUN is used.
Validation: Checking input data to ensure it meets requirements before processing. Example: checking that a number is within an expected range.
Commodore-Specific Terms
Commodore 64: See C64 above. Often abbreviated "C64" or "C=64". Introduced in January 1982, sold until 1994.
Commodore BASIC V2: The version of BASIC used in VIC-20 and Commodore 64. Version 2.0, derived from Microsoft 6502 BASIC.
KERNAL: See Kernal above. Spelled with an 'A' to avoid trademark conflicts with "kernel" (computer science term).
LOAD: Command to load a program from storage into memory. Original: from tape/disk. SLP-BASIC: from localStorage.
READY: The prompt displayed when BASIC is waiting for input. Followed by a period: READY.
RUN/STOP: A key on Commodore keyboards used to interrupt program execution, similar to ESC on modern keyboards.
SAVE: Command to save a program from memory to storage. Original: to tape/disk. SLP-BASIC: to localStorage.
VIC-20: Commodore's first mass-market computer (1980). Called VIC-20 in North America, VC-20 in Germany. First computer to sell over 1 million units.
SLP-BASIC Specific Terms
BackendDisk: The abstraction layer connecting BASIC's SAVE/LOAD commands to browser localStorage. Provides persistent storage without physical media.
Cooperative Execution: SLP-BASIC's execution model where programs run one line at a time, yielding control between lines to keep the UI responsive.
Emulator.ca: The modem simulator platform hosting SLP-BASIC. Provides authentic terminal and modem experience in a web browser.
Interrupt Latency: The delay between pressing ESC and program execution stopping. Typically <100ms in SLP-BASIC, bounded by single line execution time.
Simulated Memory: The 64KB address space maintained by SLP-BASIC for PEEK/POKE compatibility. Not connected to real hardware but allows programs to run without crashing.
SLP-BASIC: The name of this BASIC interpreter implementation. Runs on Emulator.ca's modem network, accessible by dialing 555-0300.
End of Appendix D
End of SLP-BASIC v1.2 Language Reference Manual
Manual Complete
This manual has covered every aspect of SLP-BASIC v1.2:
- 17 Chapters covering language fundamentals, commands, functions, and best practices
- 4 Appendices providing compatibility notes, technical specifications, differences from standard BASIC, and terminology definitions
You now have comprehensive documentation for programming in authentic Commodore BASIC V2, whether you're learning for the first time or rediscovering the computing experience of the 1980s.
Happy programming!