(from first prompt to full parameter-stack model)
Prompt 1
User:
write a C++ program that parses a basic program and replaces all occurrences if {} wrapped names with a line number
Assistant:
- Started with a C++ scanner that replaced
{label}
placeholders with line numbers. - Example:
Structured BASIC
PRINT "Welcome"
GOTO {start}
{start}: PRINT "Go!"
Generated BASIC
PRINT "Welcome"
GOTO 10
10 PRINT "Go!"
Prompt 2
User:
the input should not have line numbers
yes, and maybe we can just have labels without the {} like loop: and gosub loop
Assistant:
- Switched to plain
label:
syntax. - Example:
Structured BASIC
PRINT "Welcome"
GOTO start
start:
PRINT "Go!"
Generated BASIC
PRINT "Welcome"
GOTO 10
10
PRINT "Go!"
Prompt 3
User:
support multi liine if/else/end and collcapse them on output into concatencated : statements
Assistant:
- Multi-line IF lowered to GOTOs.
Structured BASIC
IF X > 0 THEN
PRINT "Positive"
ELSE
PRINT "Negative"
END IF
Generated BASIC
IF X > 0 THEN GOTO 10
GOTO 20
10
PRINT "Positive"
GOTO 30
20
PRINT "Negative"
30
Prompt 4
User:
actually to support multi-line if/else/end use goto, also add support for switch also using gotos
Assistant:
- SWITCH lowered to chained IFs and labels.
Structured BASIC
SWITCH K
CASE 1:
PRINT "one"
BREAK
CASE 2:
PRINT "two"
DEFAULT:
PRINT "other"
END SWITCH
Generated BASIC
IF K = 1 THEN GOTO 10
IF K = 2 THEN GOTO 20
GOTO 30
10
PRINT "one"
GOTO 40
20
PRINT "two"
REM fall-through
30
PRINT "other"
40
Prompt 5
User:
format the inout and output nicely
add indentation
Assistant:
- Added indentation, labels on their own lines.
Prompt 6
User:
remember basic variables have a prefix indicating their type
was it typically prefix or suffix
Assistant:
- Classic MS BASIC used suffix typing:
$
strings,%
integers,#
doubles. - We kept suffixes.
Prompt 7
User:
what about user defined types were they available in compiled basic
Assistant:
- In QuickBASIC, yes (
TYPE
). - In 1985 interpreted BASIC, no. Records simulated with
FIELD
.
Structured BASIC
RECORD Customer LEN = 40
Id AS STRING * 5
Name AS STRING * 20
Balance AS STRING * 15
END RECORD
Generated BASIC
REM RECORD Customer (LEN=40)
REM Customer_Id$ (5)
REM Customer_Name$ (20)
REM Customer_Balance$ (15)
Prompt 8
User:
let’s make all labels on their own lines
maybe we add a BLOCK keyword, you can GOTO that, and a SUB keyword you can GOSUB to that
Assistant:
- BLOCK = jump target.
- SUB = callable.
- CALL replaces GOSUB.
Structured BASIC
PRINT "Boot"
GOTO init
BLOCK init
PRINT "Initialising…"
END BLOCK
SUB greet
PRINT "Hello"
END SUB
main:
CALL greet
GOTO done
done:
PRINT "Bye"
Generated BASIC
PRINT "Boot"
GOTO 10
10
REM BLOCK init
PRINT "Initialising…"
20
REM SUB greet
PRINT "Hello"
RETURN
30
REM main
GOSUB 20
GOTO 40
40
REM done
PRINT "Bye"
Prompt 9
User:
convter this to the new structured basic program gbackup;
Assistant:
- Produced a structured BASIC sketch of
gbackup
, using BLOCK, SUB, CALL, RECORD, IF, SWITCH.
Prompt 10
User:
let’s assume we have stacks for each parameter passed to a function (subroutine) show how the genereated basic would look
Assistant:
- First attempt: separate stack per parameter.
Prompt 11
User:
let’s assume a generatlised set of stacks, one for $ one for #, one for record types and stack pointers for each, also use the stack for return values
Assistant:
- Unified three stacks:
S$()
,N#()
,R$()
. - Push args → GOSUB → callee pops → pushes return → caller pops.
Prompt 12
User:
i don’t see multiple return values or them being assigned
Assistant:
- Example:
LoadCustomer
returns three values.
Structured BASIC
(Name$, Balance#, Exists#) = CALL LoadCustomer("1")
Generated BASIC
__argrec$ = "1" : GOSUB 940 ' PUSH_R
GOSUB 200
GOSUB 930 : Exists# = __ret#
GOSUB 930 : Balance# = __ret#
GOSUB 910 : Name$ = __ret$
Callee:
200 ' LoadCustomer
GOSUB 950 : recKey$ = __retrec$
__arg$ = Name$ : GOSUB 900
__arg# = Balance# : GOSUB 920
__arg# = Exists# : GOSUB 920
RETURN
Prompt 13
User:
where are the generalised push, pop macros
Assistant:
- Gave macro and helper-sub approaches.
Prompt 14
User:
pure classic basic please
Assistant:
- Showed helper subs at line numbers 900–950.
900 S_sp% = S_sp% + 1 : S$(S_sp%) = __arg$ : RETURN
910 __ret$ = S$(S_sp%) : S_sp% = S_sp% - 1 : RETURN
920 N_sp% = N_sp% + 1 : N#(N_sp%) = __arg# : RETURN
930 __ret# = N#(N_sp%) : N_sp% = N_sp% - 1 : RETURN
940 R_sp% = R_sp% + 1 : R$(R_sp%) = __argrec$ : RETURN
950 __retrec$ = R$(R_sp%) : R_sp% = R_sp% - 1 : RETURN
Final Summary
- Structured Dialect: modern-looking BASIC with
BLOCK
,SUB
,CALL
,IF/ELSE/END IF
,SWITCH
, andRECORD
. - Generated Classic BASIC: numbered labels, only GOTOs/GOSUBs, FIELD-based records, helper subs for argument/return passing.
- Generalised Stacks: unified per-type stacks (
S$
,N#
,R$
) used for all argument and return passing. - Multiple Returns: supported by pushing values left-to-right, popping right-to-left per type.
- Pure Classic: fully runnable in GW-BASIC/QuickBASIC with the helper subs at 900–950.
This closes the loop: starting from {label}
placeholders, we now have a structured BASIC dialect with modern constructs, compiled down to classic line-numbered BASIC with a defined calling convention.
Example
Structured BASIC (Input)
' ==============================================
' Structured BASIC demo (new dialect)
' Showcases: LABEL, GOTO, IF/ELSE, SWITCH,
' BLOCK, SUB, CALL, RECORD, multiple returns.
' ==============================================
PRINT "Program start"
GOTO init
' --- BLOCK is just a named jump target
BLOCK init
PRINT "Initialising..."
END BLOCK
' --- RECORD declaration (syntactic sugar for FIELD)
RECORD Customer LEN = 40
Id AS STRING * 5
Name AS STRING * 20
Balance AS STRING * 15
END RECORD
' --- SUB with parameters and return value
SUB Remount(mountPoint$, rw%)
PRINT "Remounting "; mountPoint$; " rw="; rw%
RETURN 0
END SUB
' --- SUB with multiple return values (mixed types)
SUB LoadCustomer(recRef$)
Name$ = "Alice" : Balance# = 1234.56 : Exists# = 1
RETURN Name$, Balance#, Exists#
END SUB
' --- SUB with multiple return values (same type)
SUB SplitName(full$)
p% = INSTR(full$, " ")
IF p% > 0 THEN
First$ = LEFT$(full$, p%-1)
Last$ = MID$(full$, p%+1)
ELSE
First$ = full$
Last$ = ""
END IF
RETURN First$, Last$
END SUB
main:
PRINT "In main"
' --- CALL with params + numeric return
rc# = CALL Remount("/", 1)
IF rc# = 0 THEN
PRINT "Remount succeeded"
ELSE
PRINT "Remount failed"
END IF
' --- CALL with multiple returns (mixed types)
(Name$, Balance#, Exists#) = CALL LoadCustomer("1")
PRINT "Loaded:"; Name$, Balance#, Exists#
' --- SWITCH lowered with gotos
SWITCH Mode$
CASE "debug":
PRINT "Debug mode"
BREAK
CASE "safe":
PRINT "Safe mode"
DEFAULT:
PRINT "Normal mode"
END SWITCH
' --- CALL with multiple returns (same type)
(First$, Last$) = CALL SplitName("Alice Bob")
PRINT "First="; First$; " Last="; Last$
GOTO done
done:
PRINT "Goodbye"
Generated Classic BASIC (Output)
REM ==============================================
REM Generated BASIC (classic dialect)
REM Demonstrates how structured features are lowered
REM ==============================================
' --- Global type stacks (for params and returns)
DIM S$(256): S_sp% = 0 ' String stack
DIM N#(256): N_sp% = 0 ' Numeric stack
DIM R$(256): R_sp% = 0 ' Record refs (string)
' --- Helpers (PUSH/POP subs) must exist at 900–950
PRINT "Program start"
GOTO 10
10
REM BLOCK init
PRINT "Initialising..."
REM RECORD Customer (LEN=40)
REM Customer_Id$ (5)
REM Customer_Name$ (20)
REM Customer_Balance$ (15)
' ==============================================
' SUB Remount(mountPoint$, rw%) -> returns rc#
' ==============================================
100
GOSUB 930 : rw# = __ret# ' POP numeric param
GOSUB 910 : mountPoint$ = __ret$ ' POP string param
PRINT "Remounting "; mountPoint$; " rw="; rw#
__arg# = 0 : GOSUB 920 ' push return rc#
RETURN
' ==============================================
' SUB LoadCustomer(recRef$)
' returns: Name$ (S$), Balance# (N#), Exists# (N#)
' ==============================================
200
GOSUB 950 : recRef$ = __retrec$ ' POP record ref
Name2$ = "Alice"
Balance2# = 1234.56
Exists2# = 1
__arg$ = Name2$ : GOSUB 900 ' push returns L→R
__arg# = Balance2# : GOSUB 920
__arg# = Exists2# : GOSUB 920
RETURN
' ==============================================
' SUB SplitName(full$)
' returns: First$ (S$), Last$ (S$)
' ==============================================
300
GOSUB 910 : full$ = __ret$ ' POP string param
p% = INSTR(full$, " ")
IF p% > 0 THEN
First2$ = LEFT$(full$, p%-1)
Last2$ = MID$(full$, p%+1)
ELSE
First2$ = full$
Last2$ = ""
END IF
__arg$ = First2$ : GOSUB 900 ' push returns
__arg$ = Last2$ : GOSUB 900
RETURN
' ==============================================
' main:
' ==============================================
400
PRINT "In main"
' CALL Remount("/", 1)
__arg$ = "/" : GOSUB 900
__arg# = 1 : GOSUB 920
GOSUB 100
GOSUB 930 : rc# = __ret#
IF rc# = 0 THEN GOTO 410
GOTO 420
410
PRINT "Remount succeeded"
GOTO 430
420
PRINT "Remount failed"
430
' CALL LoadCustomer("1")
__argrec$ = "1" : GOSUB 940
GOSUB 200
GOSUB 930 : Exists# = __ret#
GOSUB 930 : Balance# = __ret#
GOSUB 910 : Name$ = __ret$
PRINT "Loaded:"; Name$, Balance#, Exists#
' SWITCH Mode$ -> chained IFs
IF Mode$ = "debug" THEN GOTO 440
IF Mode$ = "safe" THEN GOTO 450
GOTO 460
440
PRINT "Debug mode"
GOTO 470
450
PRINT "Safe mode"
REM fall-through to default
460
PRINT "Normal mode"
470
' CALL SplitName("Alice Bob")
__arg$ = "Alice Bob" : GOSUB 900
GOSUB 300
GOSUB 910 : Last$ = __ret$
GOSUB 910 : First$ = __ret$
PRINT "First="; First$; " Last="; Last$
GOTO 480
480
REM done
PRINT "Goodbye"
END
' ==============================================
' Helper subs (classic BASIC, 900–950)
' ==============================================
900 S_sp% = S_sp% + 1 : S$(S_sp%) = __arg$ : RETURN
910 __ret$ = S$(S_sp%) : S_sp% = S_sp% - 1 : RETURN
920 N_sp% = N_sp% + 1 : N#(N_sp%) = __arg# : RETURN
930 __ret# = N#(N_sp%) : N_sp% = N_sp% - 1 : RETURN
940 R_sp% = R_sp% + 1 : R$(R_sp%) = __argrec$ : RETURN
950 __retrec$ = R$(R_sp%) : R_sp% = R_sp% - 1 : RETURN