SLP-BASIC v1.2 LANGUAGE REFERENCE

SLP-BASIC v1.2 - Commodore BASIC V2 Compatible

Phone: 555-0300

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:

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:

Software Configuration:

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:

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:

"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:

  1. System Identification - Which computer is being emulated
  2. BASIC Version - V2 is Commodore BASIC Version 2
  3. Available Memory - How many bytes are free for your programs
  4. 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 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:

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:

  1. Immediately halt the current statement
  2. Display ^C to acknowledge the interrupt
  3. Return to the READY prompt
  4. 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:

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:

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:

  1. Turn off the modem
  2. Wait 10 seconds
  3. Turn on the modem
  4. 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:

  1. The interpreter detects DTR deassertion
  2. The interpreter halts execution and clears its state
  3. The modem terminates the carrier signal
  4. The remote modem detects carrier loss
  5. Both modems return to idle state
  6. 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:

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:

  1. Verify phone cable is securely connected to both modem and wall jack
  2. Test phone line by connecting a telephone and listening for dial tone
  3. Check if another device (fax, answering machine) is off-hook on the same line
  4. Try: ATX3 before dialing (disables dial tone detection)
  5. 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:

  1. Verify you're dialing the correct number (555-0300)
  2. Check if you need a dialing prefix (9 for outside line, 1 for long distance)
  3. Increase answer timeout: ATS7=60 (wait 60 seconds for answer)
  4. Try again during off-peak hours (the system may be busy)
  5. 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:

  1. Verify your terminal settings match the requirements:
    • Data bits: 8
    • Parity: None
    • Stop bits: 1
  2. Check baud rate—try forcing a specific speed: AT&N6 (lock at 1200 baud)
  3. Disable software flow control (XON/XOFF) in your terminal program
  4. Enable hardware flow control (RTS/CTS)
  5. Reset modem to factory defaults: AT&F then 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:

  1. 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
  2. Try a shorter phone cable (RJ-11) to modem
  3. Increase carrier loss timeout: ATS10=20 (wait 2 seconds before declaring carrier lost)
  4. Enable error correction: AT&M4 or AT&M5
  5. Try a lower baud rate: AT&N5 (lock at 300 baud)
  6. 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:

  1. Remember the timing: one second pause, three plus signs, one second pause
  2. Verify escape character: ATS2? (should return 43, the ASCII code for +)
  3. Some modems use different escape sequences—check your modem manual
  4. If using a terminal program, use its built-in hangup command instead
  5. 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:

  1. This is not necessarily a problem—wait for the complete banner
  2. If unacceptably slow, try a higher baud rate:
    • Set modem to 2400: AT&N8
    • Or negotiate highest common speed: AT&N0
  3. 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:

  1. Verify serial cable is properly connected
  2. Check your terminal program's COM port setting matches physical port
  3. Try different baud rates in terminal program (2400, 1200, 300)
  4. Enable local echo in terminal program to see what you're typing
  5. Reset modem by power cycling
  6. Try sending: ATE1 (enable echo) followed by RETURN several times
  7. Check if modem has a physical DIP switch configuration—may need to match software settings
  8. 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:

  1. Check if CTS is deasserted (flow control blocking)—try disabling hardware flow control temporarily
  2. Press ESC to attempt interrupt
  3. Check Scroll Lock key on your keyboard—it may be pausing output
  4. Verify local echo is OFF in your terminal program (or you'll see double characters)
  5. Try sending a carriage return (ENTER) alone—may resynchronize
  6. 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:

  1. This doesn't affect functionality—the cursor position is tracked internally
  2. Try different terminal emulation: VT100, ANSI, or TTY
  3. Some terminals have a cursor enable/disable setting—check your terminal program
  4. Not all emulation modes support blinking cursors—steady cursor or no cursor may be normal

When experiencing connection issues, start with the simplest solutions:

  1. Power cycle the modem
  2. Try a different phone jack
  3. Verify configuration with AT&V (view settings)
  4. Reset to factory defaults with AT&F
  5. 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:

During Connection:

After Disconnecting:

Etiquette and Usage:

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:

System Access Fees: Many timesharing systems charged for connect time:

Cost Management Strategies:

  1. Compose programs offline in a text editor
  2. Upload quickly using protocol transfers (XMODEM, Kermit)
  3. Download results and disconnect promptly
  4. Use off-peak hours for development work
  5. 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:

  1. Dial in to SLP-BASIC
  2. Verify you see the proper banner
  3. Type PRINT "HELLO" and press RETURN to confirm communication
  4. Disconnect properly using the ATH command
  5. Verify successful disconnection

Comfort with these procedures ensures smooth sailing throughout your SLP-BASIC journey!


Key Points to Remember:

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.

  1. Run the program (RUN)
  2. Note unexpected behavior
  3. Use immediate mode to check variables
  4. Test suspected logic interactively
  5. Fix the program
  6. 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:

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:

  1. Execution Order: BASIC runs lines from lowest to highest number
  2. Jump Targets: Commands like GOTO and GOSUB use line numbers to direct program flow
  3. 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:

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:

  1. Write code (enter lines)
  2. Review code (LIST)
  3. Execute code (RUN)
  4. 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:

  1. Stores lines sorted by line number
  2. Displays lines in numerical order (with LIST)
  3. 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:

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:

  1. Jumps to the lowest line number
  2. Executes that line
  3. Moves to the next higher line number
  4. Continues until it reaches END or 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
  1. START: BASIC finds the lowest line (10)
  2. LINE 10: Executes PRINT "ONE", displays ONE
  3. LINE 20: Executes PRINT "TWO", displays TWO
  4. LINE 30: Executes PRINT "THREE", displays THREE
  5. LINE 40: Executes END, stops program
  6. 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:

  1. RUN your program
  2. See something you want to change
  3. Retype that line number with new content
  4. RUN again 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:

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:

Delete vs. Edit

Remember the difference:

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:

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:

How NEW Works

Simply type:

NEW

Press ENTER. BASIC immediately:

  1. Deletes all program lines
  2. Clears all variables
  3. Resets to a clean state
  4. 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:

  1. You don't need your current program anymore
  2. You've saved anything important (we'll learn SAVE in Chapter 12)
  3. 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:

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?"

Line 20: INPUT A$

Line 30: PRINT "NICE TO MEET YOU, "; A$

Line 40: PRINT "WELCOME TO BASIC PROGRAMMING!"

Line 50: END

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:

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:

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:

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:

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:

When you see an error:

  1. Read the error message — BASIC usually tells you what's wrong
  2. Check the line number — The error message often includes which line failed
  3. LIST that line — Use LIST 20 to see line 20 by itself
  4. Look for common mistakes — Missing quotes, typos, wrong variable type
  5. Fix and try again — Retype the line correctly and RUN again

One More Thing: The LIST-RUN-FIX Cycle

Experienced programmers use this rhythm:

  1. WRITE some lines
  2. LIST to check what you entered
  3. RUN to test your program
  4. FIX any errors
  5. 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

Essential Commands

Editing Techniques

Programming Concepts

What You've Built

You've written five working programs:

  1. Hello World — Your first program
  2. Name Greeter — Interactive input and personalized output
  3. Simple Calculator — Math with user input
  4. Multiple Greetings — Formatted output with spacing
  5. 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:

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:

  1. Asks for two pieces of information (name and favorite number)
  2. Displays a personalized message using both
  3. 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:

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:

  1. Start with a letter (A-Z, case-insensitive)
  2. Contain letters and numbers after the first character
  3. 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

Precision: Approximately 7 decimal digits

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:

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

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:

Don't use integer variables when:

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:

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:

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:

  1. Erases all variables: Numeric, integer, and string variables are removed
  2. Erases all arrays: Arrays declared with DIM are removed
  3. Resets DATA pointer: RESTORE to the first DATA statement
  4. Clears user-defined functions: DEF FN definitions are erased
  5. 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:

Don't use CLR if:

CLR vs. NEW

Understand the difference:

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:

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:

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:

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:

  1. Use clear naming conventions: Suffix string variables with $ and integer variables with %
  2. Convert explicitly: Never rely on implicit string conversion (there isn't any)
  3. Check input types: After INPUT to string variable, use VAL if you need a number
  4. 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:

Key takeaways:

  1. Plan variable names carefully: The two-character significance rule requires thoughtful naming
  2. Choose the right type: Numeric for decimals and large numbers, integer for fast whole-number math, string for text
  3. Convert explicitly: Always use STR$ and VAL when crossing the number/string boundary
  4. Initialize variables: Don't assume initial values (even though they're predictable)
  5. 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:

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:

PRINT 5 OR 3
 7

In binary:

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:

  1. (2 + 3) = 5
  2. (4 + 5) = 9
  3. 5 * 9 = 45
  4. 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:

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:

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:

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:

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:

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:

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:

  1. A = B produces -1 or 0
  2. 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:

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:

  1. Line 10 sets I = 1 (start value)
  2. Lines 20 executes (prints "LOOP 1")
  3. Line 30 (NEXT) increments I to 2
  4. BASIC checks: is I ≤ 5? Yes → jump back to line 20
  5. Repeat steps 2-4 until I > 5
  6. 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

  1. Inner loop must complete inside outer loop — You can't start a FOR in one loop and NEXT it in another.

  2. 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
  1. 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:

  1. GOSUB saves the current line number on a return stack
  2. Jumps to the target line
  3. 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:

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:

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:

  1. Syntax Errors - Invalid code generates an error and stops
  2. Runtime Errors - Division by zero, array bounds, type mismatch, etc.
  3. 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:

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:

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:

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:

Conditional Execution:

Loops:

Subroutines:

Computed Branching:

Program Control:

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:

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:

Use SPC() when:

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:

  1. BASIC prints ? (the input prompt)
  2. Waits for user to type
  3. User presses ENTER
  4. 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:

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 ?):

Use semicolon (no ?):

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:

GET vs INPUT

Compare:

INPUT:

10 INPUT "PRESS ENTER"; A$

User types HELLO and presses ENTER → A$ = "HELLO"

GET:

10 GET A$

User presses HA$ = "H" (immediately, no ENTER needed)

WASM Context Limitation

In SLP-BASIC's WASM environment, GET behaves differently than on real Commodore hardware:

  • Real Commodore: GET waits for a keypress (blocking)
  • SLP-BASIC: GET returns 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 GOTO pattern
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:

Comma Formatting:

Semicolon Formatting:

TAB(n):

SPC(n):

POS(0):

Input Control

INPUT Statement:

Prompt Styles:

GET Statement:

Practical Skills

You can now create:

Key Principles

Formatting is communication:

Choose the right tool:

Test with real data:

What's Next

You now have all the tools for user interaction and output formatting. The next chapters will teach you:

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:

  1. Displays a formatted menu (using TAB or commas)
  2. Gets user choice (using GET or INPUT)
  3. Collects multiple pieces of data (using INPUT)
  4. 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:

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:

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:

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:

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:

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:

  1. DIM before use: Must declare array before accessing elements
  2. DIM once only: Can't re-DIM an array after it's created
  3. 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:

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:

  1. Memory offset: Index represents offset from array start (0 bytes = first element)
  2. Mathematical elegance: Modulo arithmetic and array wrap-around work naturally
  3. Common practice: Most programming languages (C, Java, Python) use zero-based arrays
  4. 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:

  1. 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
  1. 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:

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:

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:

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:

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:

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:

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:

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:

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:

Key takeaways:

  1. Always DIM arrays explicitly: Prevents subscript errors, documents size
  2. Remember zero-based indexing: Loop from 0 to N, not 1 to N
  3. Match types: Array type (%, $) must match element type
  4. Count DATA carefully: Ensure enough values for all READs
  5. Use arrays for collections: Whenever you have related data, use an array instead of separate variables
  6. Loop patterns are standard: FOR I = 0 TO N processes every element
  7. 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:

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:


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:

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:

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:


SGN(x) - Sign

Returns the sign of a number: -1 for negative, 0 for zero, +1 for positive.

Syntax: SGN(expression)

Parameters:

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:

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:

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:


LOG(x) - Natural Logarithm

Returns the natural logarithm (base e) of a positive number.

Syntax: LOG(expression)

Parameters:

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:


EXP(x) - Exponential

Returns e raised to the power of x (e^x where e ≈ 2.71828).

Syntax: EXP(expression)

Parameters:

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:


RND(x) - Random Number

Returns a pseudo-random number between 0 (inclusive) and 1 (exclusive).

Syntax: RND(expression)

Parameters:

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:


Trigonometric Functions

All trigonometric functions work in radians, not degrees.

Degree/Radian conversion:


SIN(x) - Sine

Returns the sine of an angle (in radians).

Syntax: SIN(expression)

Parameters:

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:

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:

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:

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:

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:

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:

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:

Parameters:

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:

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:

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:

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:

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:

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:

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:

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:

Limitations:

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:

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:

  1. Functions return values, statements perform actions
  2. Trigonometry uses radians (use DEF FN for degree conversion)
  3. INT rounds down, not toward zero
  4. RND(1) generates random, RND(-x) seeds generator
  5. String functions simplify text processing
  6. 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:

  1. Deletes all program lines — Every line, from first to last
  2. Clears all variables — Numeric, integer, and string variables all gone
  3. Resets program state — No execution history remains
  4. 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:

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:

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 -50 to see initialization
  • Use LIST 100-200 to see main loop
  • Use LIST 900- to see subroutines
  • Avoid LIST alone—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:

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:

  1. Clears all variables (fresh start)
  2. Jumps to the lowest line number
  3. Executes lines sequentially
  4. Continues until END or program runs out of lines
  5. 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:

  1. Clears all variables (same as RUN)
  2. Jumps directly to line 50
  3. 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 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:

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:

  1. Stops execution immediately — No more lines execute
  2. Returns to immediate mode — Shows READY. prompt
  3. Keeps variables — All variables retain their values
  4. 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:

  1. Pauses execution — Stops at the STOP line
  2. Shows BREAK message — Displays BREAK IN 50
  3. Returns to immediate mode — Shows READY. prompt
  4. 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:

Use STOP when:

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:

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:

When CONT Fails

CONT does not work after:

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:

  1. Note the problem
  2. Let the program finish (or press ESC)
  3. Edit the lines
  4. RUN again from the start

Use STOP for interactive debugging:

  1. Add STOP before problem section
  2. RUN the program
  3. When it breaks, inspect variables with PRINT
  4. Type CONT to continue
  5. Observe results after resume
  6. Remove STOP when 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:

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:

  1. Sets all numeric variables to 0 — A, X, COUNT%, etc.
  2. Sets all string variables to empty — A$, NAME$, etc.
  3. Clears arrays — All array contents reset
  4. Keeps your program — Every line remains unchanged
  5. 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:

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:

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:

  1. Section headers — Use REM with === borders
  2. Line-by-line explanation — REM before complex lines
  3. Blank REM lines — Use REM alone for visual spacing in listings
  4. 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:

  1. Write 5-10 lines
  2. LIST to review
  3. RUN to test
  4. Fix any problems
  5. 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:

  1. RUN this basic version
  2. Add line 15 INPUT "NAME"; N$
  3. Change line 20 PRINT "HELLO, "; N$
  4. RUN to test
  5. Add line 25 INPUT "AGE"; A
  6. Add line 35 PRINT "IN 10 YEARS YOU'LL BE"; A + 10
  7. LIST to see your evolved program
  8. RUN for final test

Chapter Summary

You've mastered the essential program management tools that every BASIC programmer uses constantly.

Commands Covered

Memory Management:

Viewing Programs:

Execution Control:

Documentation:

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:

How Storage Works

When you save a program named "MYGAME", BASIC:

  1. Converts your program to plain text (one line per program line)
  2. Writes it to browser localStorage
  3. Uses a unique key: emulator.ca/disk/basic/MYGAME
  4. Returns success confirmation

When you load "MYGAME", BASIC:

  1. Looks up the key in localStorage
  2. Reads the plain text
  3. Clears current program (like NEW)
  4. Parses each line back into memory
  5. 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:

You don't interact with BackendDisk directly—you use SAVE and LOAD, and BackendDisk handles the details.

Storage Limitations

Browser localStorage has limits:

Capacity:

What happens when full:

Per-browser isolation:

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:

  1. Press F12 to open DevTools
  2. Go to Application tab (Chrome) or Storage tab (Firefox)
  3. Expand Local Storage
  4. Click on the site domain
  5. Look for keys starting with emulator.ca/disk/basic/
  6. 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:

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:

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":

  1. Validates filename — Checks that it's a non-empty string
  2. Converts program to text — Each line becomes text (e.g., 10 PRINT "HELLO")
  3. Writes to storage — Stores in emulator.ca/disk/basic/filename
  4. Shows confirmation — Prints SAVING filename
  5. Reports errors — Shows ?SAVE ERROR if 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:

Filenames are case-sensitive on some systems:

  • SAVE "MYGAME" and SAVE "mygame" might create different files
  • LOAD "MYGAME" won't find "mygame"

Best practice: use UPPERCASE for consistency (traditional BASIC style).

When SAVE Fails

SAVE can fail if:

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:

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":

  1. Looks up filename — Searches emulator.ca/disk/basic/filename
  2. Checks if exists — Returns ?FILE NOT FOUND if missing
  3. Clears memory — Executes NEW (deletes current program and variables)
  4. Reads file contents — Retrieves plain text from storage
  5. Parses lines — Converts text back to program lines
  6. Loads into memory — Each line is entered (like typing manually)
  7. Shows confirmation — Prints LOADING filename
  8. Returns ready — Program is loaded, ready to LIST or RUN

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:

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:

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:

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:

How much space do programs use?

A typical BASIC program:

With 5-10 MB available, you can store:

Checking Storage Usage

No built-in command shows storage usage. You must use browser DevTools:

  1. Open DevTools (F12)
  2. Go to ApplicationLocal Storage
  3. Click the site domain
  4. Look for keys starting with emulator.ca/disk/basic/
  5. 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:

  1. Delete old programs (use DevTools to remove keys)
  2. Clear browser data (loses everything!)
  3. Use private/incognito mode (fresh storage, but lost on close)
  4. Export programs (copy text manually, import later)

Data Persistence

localStorage data persists:

Per-Browser Isolation

Each browser maintains separate storage:

To share programs between browsers/computers:

  1. LIST the program
  2. Copy the output text
  3. Manually enter lines on the other system
  4. 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:

Disadvantages:

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:

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:

  1. Filename misspelled"MYGAME" vs "MYGAMME"
  2. Case mismatch"MYGAME" vs "mygame"
  3. Program never saved — You intended to save but didn't
  4. Wrong browser — Saved in Chrome, loading in Firefox
  5. Browser data cleared — Storage was reset

Solutions:

?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:

  1. Empty string: SAVE ""
  2. Empty variable: F$ = "" then SAVE F$
  3. Missing quotes: SAVE FILENAME (treats as variable, might be empty)

Solutions:

?SAVE ERROR

Appears during: SAVE

Means: BASIC attempted to save but storage operation failed.

CODE_FENCE_0

Common causes:

  1. Storage is full — Browser localStorage capacity reached
  2. Storage disabled — User disabled storage in browser settings
  3. Permission denied — Browser security blocks storage access
  4. Private mode — Some browsers restrict storage in incognito mode

Solutions:

?LOAD ERROR

Appears during: LOAD

Means: BASIC found the file but couldn't parse it as a valid program.

CODE_FENCE_0

Common causes:

  1. File corrupted — Storage data damaged
  2. Manually edited — You edited storage in DevTools incorrectly
  3. Invalid format — File wasn't created by BASIC
  4. Line number format — Lines don't start with valid numbers

Solutions:

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:

Solutions:

Error Handling Workflow

When you encounter an error:

  1. Read the error message carefully — It usually tells you exactly what's wrong
  2. Check obvious causes — Spelling, case, quotes
  3. Inspect storage — Use DevTools to verify file exists and looks correct
  4. Try alternatives — Different case, different filename
  5. Re-save if needed — If you have the program in memory, save again
  6. 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:

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:

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:

Avoid:

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:

  1. Descriptive? — Will I know what this is in 6 months?
  2. Unique? — Does it conflict with existing programs?
  3. Consistent? — Does it match my naming convention?
  4. 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:

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:

For BASIC programs:

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:

Downside:

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:

  1. LIST your program
  2. Select all output text
  3. Copy to clipboard
  4. Paste into a text editor (Notepad, TextEdit, etc.)
  5. Save as MYGAME.TXT or MYGAME.BAS

Benefits:

Restoration:

  1. Open text file
  2. Copy program lines
  3. In BASIC, type NEW
  4. 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:

  1. Save current versionSAVE "PROGRAM"
  2. Create backupSAVE "PROGRAM-BACKUP"
  3. Export to textLIST, copy, save to file
  4. Verify backupLOAD "PROGRAM-BACKUP" to confirm it works
  5. Proceed with changes — Now it's safe to experiment

When to Delete Backups

Don't let backups accumulate forever:

Keep:

Delete:

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:

  1. Before every session: Save current work
  2. Every 15 minutes: Save during active development
  3. Before risky changes: Save backup copy
  4. End of session: Save final version
  5. 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:

  1. SAVE "IMPORTANT" (main version)
  2. SAVE "IMPORTANT-BACKUP" (backup)
  3. Edit line 40: 40 A = 2000000
  4. RUN (test change)
  5. SAVE "IMPORTANT" (save if good, or...)
  6. 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:

  1. Edit this program (add features)
  2. SAVE "WORKFLOW-V1" (save first version)
  3. Edit again (add more features)
  4. SAVE "WORKFLOW-V2" (save second version)
  5. NEW (clear memory)
  6. LOAD "WORKFLOW-V1" (load old version)
  7. LIST (see the old version)
  8. LOAD "WORKFLOW-V2" (load new version)
  9. 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:

Loading Programs:

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

Best Practices

File naming:

Backup strategy:

Development workflow:

Comparison to Commodore BASIC

Similarities:

Differences:

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:

  1. Save early — Save your first draft immediately
  2. Save often — Every 15 minutes, minimum
  3. 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:

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:

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:

Address Range:

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:

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:

{
  "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

  1. Temporary data storage — Fast, flexible alternative to arrays
  2. Bit manipulation — Store flags, pack multiple booleans into one byte
  3. Hardware control — On real Commodore, essential for graphics/sound
  4. Low-level optimization — Direct memory access is fast
  5. Educational — Understanding memory builds systems thinking

Cautions

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:

Syntax:

WAIT address,mask
WAIT address,mask,mask2

How it works:

  1. Reads byte from address
  2. Performs bitwise AND with mask
  3. (Optional) Performs bitwise XOR with mask2
  4. If result is non-zero, continues
  5. 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:

The XOR Mask

The optional mask2 inverts bits:

WAIT 1000,255,255

This waits until address 1000 becomes zero:

  1. Read byte, AND with 255 (no change)
  2. XOR with 255 (inverts all bits)
  3. 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:

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:

Better alternatives:

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:

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:

Alternatives:

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:

When to avoid:

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:

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:

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:

  1. Program execution stops immediately
  2. Control returns to immediate mode
  3. Error message displays
  4. You can inspect variables (still in memory)
  5. You can LIST the program (still intact)
  6. You cannot CONT (errors break continuity)

To continue, you must:

  1. Fix the error (edit the problematic line)
  2. RUN again from the start
  3. Or GOTO a specific line to resume

Your Debugging Mindset

When you see an error:

  1. Read it carefully — Error name tells you the category
  2. Check the line numberLIST that line to see the code
  3. Understand the cause — Match error to the situation
  4. Fix it — Apply the correct solution
  5. Test again — Verify the fix worked

Don't:

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:

{
  "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:

  1. Carefully read the line mentioned in the error
  2. Compare to correct syntax (reference manual)
  3. Fix typos, add missing parts, correct structure
  4. Re-enter the line

Prevention:

?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:

Prevention:

?ILLEGAL QUANTITY ERROR

Cause: Number outside valid range for the operation.

Common triggers:

{
  "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:

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:

  1. Use LIST to see all line numbers in your program
  2. Either change the GOTO/GOSUB to a line that exists
  3. Or add the missing line at that number

Prevention:

?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:

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:

?OVERFLOW ERROR

Cause: Number too large for BASIC to represent.

Limits:

{
  "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:

{
  "description": "Preventing overflow with floats",
  "program": "10 A=30000: REM FLOAT, NOT INTEGER\n20 B=2\n30 C=A*B\n40 PRINT C"
}

Prevention:

?OUT OF MEMORY ERROR

Cause: Program exhausted available memory.

Triggers:

{
  "description": "Out of memory - large array",
  "program": "10 DIM A(50000)"
}

How to fix:

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:

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:

?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:

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:

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:

How to fix:

  1. Check spelling carefully (case-sensitive on some systems)
  2. Verify file was saved successfully
  3. Try alternative filename
  4. Recreate the program if lost

Prevention:

?SAVE ERROR

Cause: SAVE failed to write file to storage.

Common causes:

{
  "description": "Save with valid filename",
  "program": "10 PRINT \"TEST PROGRAM\"\nSAVE \"VALIDTEST\""
}

How to fix:

  1. Check FRE(0) to ensure program isn't too large
  2. Clear browser storage (Settings → Clear Data)
  3. Exit private/incognito mode
  4. Try shorter filename
  5. Use different browser

Prevention:

?LOAD ERROR

Cause: File found but couldn't be loaded (corrupted or wrong format).

Common causes:

How to fix:

  1. Try loading different file to test system
  2. Clear browser cache
  3. Rewrite program from scratch if unrecoverable
  4. Check browser console for detailed error

Prevention:

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:

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:

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:

  1. Write 5-10 lines
  2. RUN to test
  3. Fix any errors
  4. Add 5-10 more lines
  5. RUN again
  6. 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:

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:

  1. Save current program: SAVE "BROKEN"
  2. NEW
  3. Rewrite the problematic section from scratch
  4. Test it in isolation
  5. Once working, integrate back into main program

Sometimes a fresh perspective reveals obvious mistakes.

Systematic Debugging Process

When faced with a bug:

  1. Reproduce reliably — Can you make it happen consistently?
  2. Isolate — Which line/section causes it?
  3. Understand — What is the code supposed to do vs what it's doing?
  4. Hypothesize — What might be wrong?
  5. Test — Try a fix
  6. 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

Mistake 2: Testing too late

Mistake 3: No variable inspection

Mistake 4: Ignoring edge cases

Mistake 5: Complex code without understanding

Error Prevention Checklist

Before running any program:

✓ Syntax

✓ Logic

✓ Data

✓ Flow

Use this checklist, and 90% of errors disappear before they happen.

When All Else Fails

  1. Take a break — Fresh eyes see bugs instantly
  2. Ask for help — Explain code to someone
  3. Search documentation — Re-read the manual
  4. Simplify — Make smallest possible program that demonstrates bug
  5. 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:

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:

  1. Complete source code with line numbers and comments
  2. Explanation of how it works and why
  3. Sample output showing what you'll see
  4. Modifications you can make to learn more
  5. 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

Modifications to Try

  1. Add your name: Change line 40 to PRINT "HELLO, [YOUR NAME]!"
  2. More messages: Add line 85: PRINT "PROGRAMMING IS FUN!"
  3. ASCII art: Create a simple border using dashes or asterisks
  4. Multiple blanks: Add PRINT on several lines to create more spacing

Exercise

Create a "About Me" program that displays:

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:

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:

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

Modifications to Try

  1. Difficulty levels: Ask user for range (1-10, 1-50, 1-1000)
  2. Guess limit: Give player only 7 tries before game over
  3. Hints: Add "getting warmer" or "getting colder" messages
  4. High score: Track and display best (lowest) number of tries
  5. Better input: Use GET instead of INPUT for 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:

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

Modifications to Try

  1. Larger sequences: Increase limit to 30 (watch for overflow around F(46))
  2. Ratios: Calculate and display ratio of consecutive numbers (approaches golden ratio φ ≈ 1.618)
  3. Sum: Add line to calculate and display sum of all Fibonacci numbers
  4. Formatted output: Use TAB() to align numbers in columns
  5. 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

Modifications to Try

  1. Formatted columns: Print 10 primes per line using POS(0)
  2. Time it: Add delay loop to show algorithm in action
  3. Twin primes: Find prime pairs (p, p+2) like 11,13 or 17,19
  4. Sieve of Eratosthenes: Implement faster algorithm using arrays
  5. 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:

Line 180: ON CHOICE GOTO is computed branching—jumps to different lines based on value:

Lines 240, 340: Round result to 1 decimal place:

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

Modifications to Try

  1. Kelvin: Add third temperature scale (K = C + 273.15)
  2. Batch mode: Accept multiple temperatures in one session
  3. Table: Print conversion table (e.g., 0F to 100F in 10-degree steps)
  4. Reference points: Show water freezing/boiling points
  5. 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:

Subroutine structure: Each subroutine:

  1. Performs its specific operation
  2. Stores result in RESULT variable
  3. Sets OP$ to operator symbol
  4. 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

Modifications to Try

  1. More operations: Add power (^), square root, modulo
  2. Memory: Add M+, M-, MR (memory recall) buttons
  3. History: Store last 10 calculations in array
  4. Chain operations: Use previous result as first number of next operation
  5. 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):

Complete Table (lines 1000-1220):

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

Modifications to Try

  1. Custom range: Ask user for start and end numbers (e.g., 5-15)
  2. Colored output: Use ASCII codes or special characters for emphasis
  3. Quiz mode: Ask user to fill in answers, check correctness
  4. Flash cards: Show random multiplication problems one at a time
  5. 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:

Line 150: MID$(S$, I, 1) extracts one character at position I:

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

Modifications to Try

  1. Case-insensitive palindromes: Ignore capitals (convert to uppercase first)
  2. Ignore spaces/punctuation: "A man a plan a canal Panama"
  3. Word reverser: Reverse order of words, not characters
  4. Encryption: Caesar cipher (shift each letter by N positions)
  5. 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):

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):

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

Modifications to Try

  1. Descending order: Change > to < in line 290
  2. Show passes: Print array after each pass to visualize sorting
  3. Count swaps: Track how many swaps were made
  4. Early exit: Stop if no swaps made (array already sorted)
  5. Random fill: Generate random numbers instead of user input
  6. 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):

Mean Calculation (lines 210-250):

Standard Deviation (lines 280-340):

Histogram Binning (lines 410-440):

Histogram Display (lines 560-630):

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

Modifications to Try

  1. Different ranges: Generate numbers in different ranges (1-10, 1-1000)
  2. Show min/max: Find and display smallest and largest values
  3. Median: Sort array and find middle value
  4. Normal distribution: Use Box-Muller transform for bell curve
  5. Export data: Display raw values for analysis
  6. 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

  1. Hello World: Basic structure, PRINT, END
  2. Number Guessing: RND, INPUT, IF/THEN, loops, counters
  3. Fibonacci: Arrays, FOR loops, DIM, mathematical sequences
  4. Prime Finder: Nested loops, optimization, boolean flags
  5. Temperature Converter: DEF FN, menus, ON GOTO, formatting
  6. Calculator: GOSUB/RETURN, subroutines, code organization
  7. Multiplication Tables: Nested loops, TAB, grid formatting
  8. String Reverser: LEN, MID$, string building, palindromes
  9. Bubble Sort: Sorting algorithms, swapping, array manipulation
  10. Random Statistics: Statistics, histograms, data visualization

Programming Skills Acquired

By working through these examples, you've learned:

Data Structures:

Control Flow:

Functions:

Input/Output:

Algorithms:

What's Next

These ten programs are starting points, not endpoints. The real learning happens when you:

  1. Modify them: Change the programs to do something different
  2. Combine them: Use techniques from multiple programs together
  3. Debug them: Intentionally break them and fix them
  4. Extend them: Add features the original doesn't have
  5. 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:

  1. Hangman game: Combine string manipulation with game logic
  2. Grade book: Array of students, calculate class average
  3. Text adventure: Menu system with branching story
  4. Math tutor: Random problems, track score, provide feedback
  5. Contact list: Store names/numbers in arrays, search/sort
  6. Budget tracker: Income/expenses, calculate balance
  7. Quiz program: DATA statements with questions/answers
  8. Pattern generator: ASCII art using loops and spacing
  9. Number converter: Binary, octal, decimal, hexadecimal
  10. 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:

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:

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:

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:

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:

INPUT

Syntax: INPUT ["prompt"; | "prompt",] variable [, variable2, ...]
Description: Get user input. Semicolon suppresses ?, comma includes it.
Examples:

LET

Syntax: LET variable = expression or variable = expression
Description: Assign value to variable. LET is optional.
Examples:

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:

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:

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)5
ABS(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)7
INT(-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) + 11-6 (dice roll)

SGN(n)
Sign of number: -1 (negative), 0 (zero), 1 (positive).
SGN(-5)-1
SGN(0)0
SGN(3.7)1

SQR(n)
Square root. n must be ≥ 0.
SQR(16)4
SQR(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)1
COS(3.14159)-1 (π radians = 180°)

SIN(n)
Sine of n radians.
SIN(0)0
SIN(1.5708)1 (π/2 radians = 90°)

TAN(n)
Tangent of n radians.
TAN(0)0
TAN(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")65
ASC("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")5
LEN("")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")123
VAL("45.6")45.6
VAL("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:

  1. Parentheses override all precedence
  2. Exponentiation (^) first
  3. Multiplication and division (*, /) next (left to right)
  4. Addition and subtraction (+, -) last (left to right)

Examples:

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.

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:

AND: Both must be true

OR: Either can be true

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

  1. Note the line number: Error message usually includes line where error occurred
  2. LIST the line: LIST 100 to see problematic line
  3. Check variable values: Use immediate mode to PRINT variables
  4. Step through logic: Add PRINT statements to trace execution
  5. Simplify: Comment out sections to isolate problem
  6. 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

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

Line Numbering Convention

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

  1. Commands: Check Command Summary (NEW, LIST, RUN, SAVE, LOAD)
  2. Statements: Check Statement Summary (IF, FOR, PRINT, INPUT, GOSUB)
  3. Functions: Check Function Summary by category (Math, String, System)
  4. Operators: Check Operator Summary with precedence table
  5. Errors: Check Error Code Quick Reference for debugging
  6. ASCII: Check ASCII Table for CHR$() and ASC() values

When You Need To Learn

Quick Lookup Strategy

  1. Know what you need: Function? Statement? Command?
  2. Find the category: Math? String? Control flow?
  3. Scan alphabetically: Each section is alphabetized
  4. Check example: Verify syntax with example
  5. Test in BASIC: Try it in immediate mode

Common Lookups

Most frequently referenced items:

Beyond This Reference

This chapter provides syntax and quick answers. For deeper understanding:

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:

Bad:

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:

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:

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:

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:

Display:

Banner Message:

    **** COMMODORE BASIC V2 ****

  3583 BYTES FREE

READY.

Sound:

Target Market:

Commodore 64 (1982)

Memory Configuration:

Display:

Banner Message:

    **** COMMODORE BASIC V2 ****

 64K RAM SYSTEM  38911 BASIC BYTES FREE

READY.

Sound:

Graphics:

Target Market:

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:

Use C64 mode when:

Example:

READY.
PRINT FRE(0)
 38911
READY.

VIC-20 Mode

Configuration:

Use VIC-20 mode when:

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:

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:

SLP-BASIC Simulated Memory

SLP-BASIC maintains a 64KB simulated memory space (0-65535) for PEEK/POKE compatibility. However:

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:

Graphics Characters:

Reverse Video:

Color Control (C64):

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:

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:

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:

  1. Remove graphics POKEs: Delete or comment out screen, color, and sprite manipulation
  2. Remove sound POKEs: Delete audio-related POKE statements
  3. Replace hardware I/O: Use LOAD/SAVE instead of OPEN/INPUT#/PRINT#
  4. Remove SYS calls: Machine language calls won't work
  5. Test with FRE(0): Ensure program fits in available memory
  6. 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:

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

Why Rust:

Build Process:

wasm-pack build --target web --release

Produces:

Module Structure

Core Components:

  1. 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
  2. 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
  3. 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
  4. 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
  5. Memory (memory.rs): Simulated 64KB address space

    • PEEK/POKE support
    • Zero-initialized at startup
    • No hardware mapping (pure simulation)
  6. 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:

Memory Model:

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:

  1. Check if program is running
  2. Fetch next line to execute
  3. Parse and execute the line
  4. Update program counter
  5. Return execution state (running/stopped/error)
  6. Yield control to JavaScript

Benefits:

Limitations:

Performance Impact:

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:

  1. Syntax Errors: Detected during parsing

    • Reported immediately when line is entered
    • Line rejected, not stored in program
    • Example: 10 PRINT (missing argument)
  2. 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
  3. System Errors: WASM or JS-level errors

    • Caught and converted to BASIC error messages
    • Prevent crashes, maintain stability

Error Recovery:

Data Types and Storage

Numeric Variables

Representation: IEEE 754 single-precision (32-bit) floating-point

Range:

Storage: 4 bytes per variable

Operations:

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:

Performance: ~2-3× faster than floating-point for arithmetic

Use Cases:

String Variables ($)

Representation: UTF-8 encoded byte sequence

Maximum Length: 255 characters

Storage:

Memory Management:

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)

Storage:

Maximum Size: Limited by available memory (FRE(0))

Access Time: O(1) constant time indexing

Multi-dimensional: Maximum 2 dimensions

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:

Worker Thread Architecture

Threading Model

Main Thread (UI thread):

Worker Thread (computation thread):

Communication: Message passing via postMessage()

Main Thread                 Worker Thread
     |                           |
     |---- Execute "PRINT 2+2" -->|
     |                           | [Parse]
     |                           | [Execute]
     |<---- Result: "4" ---------|
     | [Display]                 |

Benefits:

Coordination:

Interrupt Handling

ESC Key Sequence:

  1. User presses ESC in terminal
  2. Main thread detects keypress
  3. Main thread sends interrupt message to worker
  4. Worker checks interrupt flag between line executions
  5. Worker stops program, sends "interrupted" state
  6. Main thread displays ^C and BREAK IN [line]
  7. 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):

Input (INPUT, GET):

Flow Control:

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:

  1. Serialize program to text format
  2. Store in localStorage with key: emulator.ca/disk/basic/FILENAME
  3. Overwrites existing file if present
  4. Returns success/failure status

LOAD Operation:

  1. Retrieve from localStorage by key
  2. Clear current program (NEW)
  3. Parse each line and add to program storage
  4. Return to READY prompt
  5. Report error if file not found

Storage Limits:

Persistence:

BackendDisk Integration

Interface: JavaScript bridge between BASIC and localStorage

Operations Supported:

Error Handling:

Filename Rules:

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:

Example:

10 FOR I = 1 TO 10000
20   S = S + I
30 NEXT I

Memory Performance

Allocation:

Garbage Collection:

Memory Limits:

Startup Performance

Cold Start (first load):

Warm Start (cached):

Responsiveness

Interrupt Latency:

UI Update Frequency:

Browser Compatibility

Minimum Requirements

Browsers (and minimum versions):

Required Web APIs:

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:

Security Model

WebAssembly Sandbox:

LocalStorage Security:

Content Security Policy Compatibility:

Limitations and Constraints

Known Limitations

Not Implemented:

Behavioral Differences:

Memory Constraints:

Performance Constraints:

Future Enhancements

Planned:

Under Consideration:

Summary

SLP-BASIC v1.2 is a sophisticated WebAssembly implementation of Commodore BASIC V2:

Core Technology:

Performance:

Compatibility:

Architecture:

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:

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:

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:

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:

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:

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:

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:

Why Limited:

Status: Commands work, but no hardware emulation

Not Implemented: Device Status

Commands/Functions:

Original Purpose:

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:

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:

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:

Why Non-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):

SLP-BASIC Behavior:

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):

SLP-BASIC Behavior:

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):

SLP-BASIC Behavior:

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:

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:

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:

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:

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:

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:

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):

Purpose:

Status: Under consideration

Planned: Debug Mode

Feature: Step-through execution and variable inspection

Commands (proposed):

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):

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):

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:

Excluded:

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:

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:

Rationale: Browser security model is non-negotiable. Any implementation must respect these constraints.

Principle 4: Authentic Experience

Goal: Feel like real Commodore BASIC

Preserved:

Enhanced:

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:

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:

What's Excluded:

Modern Enhancements:

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:

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!