Program lifecycle: what NEW, OLD, CLEAR, RUN and CHAIN inherit and leave behind (BASIC II)

← Acorn BBC BASIC

Program lifecycle in BBC BASIC II: what NEW, OLD, CLEAR, RUN and CHAIN inherit and leave behind

Scope. This article covers the BBC BASIC II commands that start, clear, and re-run a program — NEW, OLD, CLEAR, RUN, CHAIN — and exactly what state each resets versus preserves. Every routine and workspace address is specific to this version and was read from the disassembly (which reassembles byte-identically to the ROM). The expression/parsing machinery these commands hand control to is mapped in parsers and evaluators; the loop stacks they reset are detailed in control flow on five stacks.

The single fact that explains the whole family:

All five commands funnel through one routine, clear_vars_heap_stack (&BD20), which wipes the dynamic-variable world — every named variable, array, string and PROC/FN — but deliberately preserves the resident integer variables @% and A%Z%, along with HIMEM and PAGE. That preservation is not an accident: it is the documented channel for passing data into a CHAINed program.

The shared clear

clear_vars_heap_stack (&BD20) does exactly three things:

  1. LOMEM = VARTOP = TOP — the dynamic-variable heap is emptied by resetting its top back to the end of the program.
  2. reset_data_and_stacks (&BD3A) — the DATA pointer is reset to PAGE (an implicit RESTORE), the BASIC value stack to HIMEM, and the FOR/REPEAT/GOSUB level counters to empty.
  3. clear_var_table (&BD2F) — zeroes the per-letter variable chain-head table.

Step 3 is the crux, and it is precise about its range. It clears &0480&04FF only:

.clear_var_table
    ldx #&80
    lda #0
.clear_var_table_loop
    sta var_table_base,x        ; var_table_base = &047F, so &0480..&04FF
    dex
    bne clear_var_table_loop

It starts at &0480 and never descends into &0400&047F.

The page-4 map: why resident integers survive

That &0480 boundary lines up with the page-4 workspace layout:

Range Contents Cleared by the lifecycle commands?
&0400&046B resint_at (&0400): the resident integers — @% at &0400, then A%Z% at &0404&046B (four bytes each) No — never touched
&046C&047F fp_temps (&046C): four 5-byte floating-point scratch temporaries No (scratch, not user-visible)
&0480&04FF var_ptr_table (&0480): the dynamic-variable chain heads (two bytes per initial-character class) Yes — zeroed every time

So @% and A%Z% live below the cleared region and ride through NEW, OLD, CLEAR, RUN and CHAIN untouched. Because @% is also the PRINT/STR$ number-format control word, the print format carries over too — an easily missed consequence.

The five commands, side by side

Command Handler Program text Dynamic vars / arrays / strings / PROC·FN Resident @%/A%Z% LOMEM DATA ptr FOR/REPEAT/GOSUB + value stack Then
NEW start_new_program (&8ADD) emptied (CR,&FF at PAGE; recoverable by OLD) cleared preserved =TOP =PAGE cleared TRACE off; → immediate
OLD stmt_old (&8AB6) recovered + TOP re-derived cleared preserved =TOP =PAGE cleared → immediate
CLEAR stmt_clear (&928D) kept cleared preserved =TOP =PAGE cleared → next statement
RUN stmt_run (&BD11) kept cleared preserved =TOP =PAGE cleared execute from PAGE
CHAIN stmt_chain (&BF2A) replaced by the loaded file cleared preserved =TOP =PAGE cleared execute from PAGE

HIMEM and PAGE are preserved by every one of them — clear_vars_heap_stack (&BD20) reads HIMEM to reset the stack but never writes it, and PAGE is where each program lives.

A few per-command details worth knowing:

Carried over by every command

This is why the idiom for CHAIN data-passing works: set A%Z% (or stash bytes above a lowered HIMEM) before CHAIN, and read them back in the chained program.

Two clears you might not expect

For a compiler

Model the lifecycle as: NEW/OLD/CLEAR/RUN/CHAIN all reset the dynamic-variable environment (heap, arrays, strings, PROC/FN table, LOMEM, DATA position, all stacks) but preserve the resident integers @%/A%Z%, HIMEM (and reserved memory above it), and PAGE. CHAIN additionally swaps the program text. The resident-integer survival is observable behaviour a faithful implementation must reproduce — programs rely on it both for CHAIN parameter passing and for @% formatting persisting across a RUN.

Cross-references