This program implements a general ledger accounting system, providing functions for creating ledger cards, entering transactions, generating trial balances, and producing profit-and-loss statements. Up to 30 accounts are supported, each holding up to 10 transaction entries stored in parallel arrays (date in D$, reference in E$, debit in F, credit in G), with running balances maintained in H(). The currency formatting subroutine at line 4000 uses STR$ with rounding to two decimal places, and includes fixes for leading decimal points such as “.50” becoming “0.50”. A year-end transfer routine at line 7000 clears transaction arrays and posts the closing balance as a brought-forward entry, resetting each card to a single opening entry. Data is saved to tape via a STOP/CONT pattern that allows the user to prepare the recorder before executing the SAVE command.
Program Analysis
Program Structure
The program is organised as a menu-driven shell (lines 10–60) dispatching to six functional modules via GOTO. The main menu loop runs from line 10 and re-enters itself after most operations via GOTO 10.
- Lines 10–60: Main menu and dispatcher
- Lines 100–500: Register initialisation (option 0) — DIM statements and variable resets, year entry
- Lines 1001–1050: Open new ledger card (option 1)
- Lines 2005–2610: Account search and transaction entry (option 2)
- Lines 3000–3980: Trial balance and P+L statement (option 3)
- Lines 4000–4215: Subroutines — currency formatting (4000), display transaction row (4100), display balance (4200)
- Lines 6000–6003: Save to tape (option 4)
- Lines 7002–7150: Year-end account transfer (option 5)
Data Structures
The program uses parallel arrays to simulate a record structure. Each account occupies a fixed block of 10 slots in the transaction arrays. Account C maps to transaction indices (C*10)+1 through C*10+10.
| Array | Size | Purpose |
|---|---|---|
A$(30,10) | 30 × 10 chars | Account names (10-char limit) |
C(30) | 30 | Declared but not actively used (balance stored in H) |
D$(310,5) | 310 × 5 chars | Transaction date |
E$(310,4) | 310 × 4 chars | Transaction reference |
F(310) | 310 | Debit amounts |
G(310) | 310 | Credit amounts |
H(30) | 30 | Running account balance (debit positive, credit negative) |
N(30) | 30 | Next free transaction index per account |
T(30) | 30 | Account type: 0=balance sheet, 1=P+L |
B(1), J(1), K(1) | 1 | Scalar placeholders (single-element arrays) |
The scalar variables B, J, K, etc. are used independently of the single-element arrays of the same letter — a common Sinclair BASIC technique where DIM B(1) does not affect the plain variable B.
Currency Formatting Subroutine (line 4000)
The subroutine at line 4000 converts numeric value P into a formatted two-decimal-place string P$. It handles three edge cases:
- Values between 0 and 1 where
STR$produces".5"— prefixed with"0"at line 4010. - Negative values between -1 and 0 where
STR$produces"-."— corrected to"-0..."at line 4020. - Integers with no decimal point —
".00"appended at line 4060. - Values with only one decimal digit — a trailing
"0"appended at line 4070.
Rounding is achieved via INT (P*100+.5)/100, which is the standard Sinclair BASIC two-decimal rounding idiom.
Transaction Entry Flow
Entry begins at line 2100. The variable X holds C*10, the base offset for the current account’s transaction block. N steps from X+1 up to a maximum of X+10. For each transaction, date (D$), reference (E$), debit (F), and credit (G) are collected sequentially. The running balance H(C) is updated immediately: debits add, credits subtract. A three-option sub-menu (continue, error correction, return) appears after each entry.
The error-correction path (option 2, line 2550) allows the user to reverse the last debit or credit entry by decrementing N and adjusting H(C), then re-entering from line 2320 (which is line 2325 effectively — a minor label off-by-one, jumping into the middle of the entry loop).
Trial Balance (lines 3000–3200)
The trial balance iterates over accounts 1 to O (where O holds the count of opened accounts). Positive balances are accumulated in R (debits) and negative balances in S (credits, stored as negative). The display uses TAB with LEN P$ subtracted to right-align figures in debit (column 21) and credit (column 32) positions. If the account count exceeds 14, the balance is carried forward across two screen pages using STOP/CONT as a pause mechanism (lines 3099 and 3205).
The error line at 3200 prints the difference between debit and credit totals. Ideally this should be zero; the label “ERROR:” is used to indicate any imbalance.
Profit and Loss Statement (lines 3500–3980)
P+L only processes accounts where T(C)=1. Income accounts (credit balance, i.e. H(C)<1) accumulate in S; expense accounts (H(C)>1) in R. The net result is computed as (R+S)*-1 — a negative result indicates a loss, as noted on screen.
Year-End Transfer (lines 7002–7150)
The transfer routine clears the 10-entry transaction block for the chosen account, then writes a single brought-forward ("BFD.") entry using the closing balance. If the balance is positive it is placed in the debit column (F(N)); if negative, in the credit column (G(N)). The account pointer N(C) is reset to the first slot.
Tape Save (lines 6000–6003)
Saving uses the STOP/CONT idiom: execution halts at line 6001, the user starts the tape recorder, then continues. The SAVE "G/%L" at line 6002 saves the program. After saving, GOTO 5 targets a non-existent line, which causes execution to fall through to line 8 (the next line in the program), effectively restarting cleanly from the copyright REM.
Bugs and Anomalies
- Lines 200–235 use plain variables (
LET B=0,LET C=0, etc.) to initialise what are intended to be array elements, but without subscripts these reset the scalar variables only, not the array contents. The arrays themselves are left at their default zero/space values fromDIM, so this is harmless in practice on first run but would not correctly re-initialise arrays if option 0 were selected after data entry. - The trial balance loop at line 3065 uses
FOR C=U TO C, where both the loop variable and the limit share the nameC. The limit is evaluated once at loop start, so this works correctly, but it is unusual style. - Line 3097 checks
IF C>=O THEN GOTO 3200to skip the page-break prompt if all accounts fit on one page, but the condition should perhaps beC>14or similar; the current logic depends on the loop having incrementedCpastOnaturally. - The P+L thresholds at lines 3620 and 3630 use
>1and<1rather than>0and<0, meaning accounts with a balance of exactly 1 or -1 are excluded from both totals. - Line 4100 is entered via
GOSUB 4100but the subroutine body begins at line 4106, with lines 4100–4105 absent. Execution falls through from 4100 to 4106 correctly since there are no intervening lines, but theGOSUBtarget is effectively line 4106. - Line 7080 uses
IF H(C)<1(should be<0) for the credit brought-forward test, meaning a balance of exactly 0 would write a zero to the credit column rather than being skipped.
Content
Source Code
5 REM "G/L" 16-105 (BY NO.)
8 REM COPYRIGHT M.SIEDER 1983
10 CLS
30 PRINT AT 1,10;"GENERAL LEDGER";AT 2,0;Y$
40 PRINT AT 3,2;"ENTER LEAD NO.FOR OPERATION";
41 PRINT AT 5,3;"0)CLEAR REGISTERS";AT 6,3;"1)OPEN NEW LEDGER CARD";AT 7,3;"2)SEARCH FOR ACCT.+ENTRIES";AT 8,3;"3)TRIAL BAL. AND P+L STATEMT.";AT 9,3;"4) SAVE ON TAPE";AT 10,3;"5)TRANSFER OF ACCT.BAL."
45 INPUT I
46 CLS
50 IF I=0 THEN GOTO 100
51 IF I=1 THEN GOTO 1000
52 IF I=2 THEN GOTO 2000
53 IF I=3 THEN GOTO 3000
56 IF I=4 THEN GOTO 6000
58 IF I=5 THEN GOTO 7000
60 IF I>5 THEN GOTO 10
101 DIM B(1)
105 DIM A$(30,10)
110 DIM C(30)
115 DIM D$(310,5)
120 DIM E$(310,4)
125 DIM F(310)
130 DIM G(310)
135 DIM H(30)
140 DIM J(1)
145 DIM K(1)
150 DIM N(310)
155 DIM T(30)
200 LET B=0
202 LET C=0
205 LET F=0
210 LET N=0
212 LET O=0
215 LET G=0
220 LET H=0
225 LET J=0
230 LET K=0
235 LET T=0
240 LET Y$="--------------------------------"
300 PRINT AT 10,11;"ENTER YEAR"
310 INPUT B
320 CLS
500 GOTO 10
\n1001 LET C=O
\n1005 LET C=C+1
\n1010 IF C>30 THEN GOTO 2600
\n1016 LET O=C
\n1020 PRINT AT 8,4;"ACCT.NO.";C;AT 9,4;"ENTER""0""FOR BAL.SHEET ACCT.";AT 10,4;"ENTER""1""FOR P+L ACCT."
\n1021 INPUT T(C)
\n1022 CLS
\n1030 PRINT AT 10,4;"ENTER ACCT.NAME";" NO.";T(C);"-";C;AT 12,6;"( 10 DIGITS ONLY )"
\n1040 INPUT A$(C)
\n1045 CLS
\n1050 GOTO 2100
\n2005 PRINT AT 9,5;"ENTER NO. OF ACCOUNT"
\n2010 INPUT I
\n2015 LET C=I
\n2035 GOTO 2100
\n2065 CLS
\n2070 GOTO 10
\n2100 CLS
\n2105 LET X=C*10
\n2110 LET N=X+1
\n2200 PRINT AT 1,0;"NO.";T(C);"-";C;AT 1,9;A$(C);AT 1,25;"YR:";B
\n2205 PRINT AT 2,0;Y$
\n2210 PRINT AT 3,0;"NO.";AT 3,4;"DATE";AT 3,10;"REF.";AT 3,16;"DEBIT";AT 3,25;"CREDIT"
\n2215 PRINT AT 4,0;Y$
\n2265 PRINT AT 17,12;"PRES.BAL.:"
\n2270 GOSUB 4200
\n2300 FOR N=(X+1) TO N(C)
\n2305 IF N>10+X THEN GOTO 2500
\n2306 GOSUB 4100
\n2310 IF N=N(C) THEN GOTO 2325
\n2315 NEXT N
\n2325 IF N>10+X THEN GOTO 2500
\n2330 PRINT AT 21,19;"DATE ";N
\n2335 INPUT D$(N)
\n2340 PRINT AT 21,19;"REF. ";N
\n2345 INPUT E$(N)
\n2350 PRINT AT 21,19;"DEBIT ";N
\n2352 INPUT F(N)
\n2358 LET H(C)=H(C)+F(N)
\n2360 PRINT AT 21,19;"CREDIT ";N
\n2362 INPUT G(N)
\n2368 LET H(C)=H(C)-G(N)
\n2370 PRINT AT 17,22;" ";AT 21,19;" "
\n2380 GOSUB 4100
\n2382 GOSUB 4200
\n2385 LET N=N+1
\n2390 LET N(C)=N
\n2400 IF N<=10+X THEN GOTO 2520
\n2500 IF N>10+X THEN PRINT AT 19,6;"FULL ACCT.CARD";AT 20,4;"ENTER""1"" TO RETURN";AT 21,4;"ENTER""0"" TO COPY "
\n2505 INPUT I
\n2507 IF I<1 THEN COPY
\n2508 GOTO 10
\n2510 IF I>=1 THEN GOTO 10
\n2520 PRINT AT 19,20;"1)CONT.ENT.";AT 20,20;"2)ERROR ";AT 21,20;"3)RETURN "
\n2525 INPUT I
\n2530 PRINT AT 19,20;" ";AT 20,20;" ";AT 21,20;" "
\n2535 IF I=1 THEN GOTO 2320
\n2536 IF I=2 THEN GOTO 2550
\n2537 LET C=O
\n2538 IF I>2 THEN GOTO 10
\n2550 PRINT AT 19,20;"1)DEBIT ";AT 20,20;"2)CREDIT"
\n2555 INPUT I
\n2560 PRINT AT 19,20;" ";AT 20,20;" "
\n2565 IF I=1 THEN LET H(C)=H(C)-F(N-1)
\n2570 IF I=2 THEN LET H(C)=H(C)+G(N-1)
\n2575 IF I<3 THEN LET N=N-1
\n2580 IF I<3 THEN GOTO 2320
\n2600 PRINT AT 11,2;"OUT OF LEDGER CARDS"
\n2605 PAUSE 50
\n2610 GOTO 10
\n3000 REM "TRIAL BALANCE"
\n3005 PRINT AT 10,2;"ENTER DATE OF TRIAL BALANCE"
\n3010 INPUT I$
\n3015 CLS
\n3020 PRINT AT 1,1;"TRIAL BALANCE AS OF: ";I$
\n3025 PRINT Y$
\n3030 PRINT AT 3,0;"NO.";AT 3,3;"ACCOUNT";AT 3,15;"DEBITS";AT 3,23;"CREDITS"
\n3035 PRINT Y$
\n3053 LET R=0
\n3055 LET S=0
\n3060 LET C=14
\n3061 LET U=1
\n3065 FOR C=U TO C
\n3067 IF H(C)<0 THEN GOTO 3080
\n3070 LET R=R+H(C)
\n3071 LET P=H(C)
\n3072 GOSUB 4000
\n3074 PRINT TAB 0;C;TAB 3;A$(C);TAB 21-LEN P$;P$
\n3075 GOTO 3090
\n3080 LET S=S-H(C)
\n3081 LET P=H(C)
\n3082 GOSUB 4000
\n3085 PRINT TAB 0;C;TAB 3;A$(C);TAB 32-LEN P$;P$
\n3090 NEXT C
\n3092 PRINT Y$
\n3093 LET R$=STR$ R
\n3094 LET S$=STR$ S
\n3096 PRINT TAB 0;"TOTALS:";TAB 21-LEN R$;R$;TAB 32-LEN S$;S$
\n3097 IF C>=O THEN GOTO 3200
\n3098 PRINT AT 21,0;"ENTER"" CONT "" OR "" COPY """
\n3099 STOP
\n3100 LET C=O
\n3101 LET U=15
\n3105 CLS
\n3106 PRINT TAB 2;"BFD.";TAB 21-LEN R$;R$;TAB 32-LEN S$;S$
\n3110 GOTO 3065
\n3200 PRINT TAB 0;"ERROR: ";INT ((R-S)*100+.5)/100
\n3202 LET U=1
\n3203 LET C=O
\n3204 PRINT AT 21,0;"ENTER"" CONT "" OR "" COPY """
\n3205 STOP
\n3208 PRINT AT 9,4;"ENTER 1)FOR DAILY P+L";AT 10,10;"2)FOR RETURN"
\n3210 INPUT I
\n3215 CLS
\n3220 IF I>1 THEN GOTO 10
\n3225 IF I=0 THEN GOTO 10
\n3230 IF I=1 THEN GOTO 3500
\n3500 PRINT AT 2,2;"P+L AS OF: ";I$;AT 3,0;Y$
\n3555 LET R=0
\n3560 LET S=0
\n3600 FOR C=1 TO O
\n3610 IF T(C)=0 THEN GOTO 3800
\n3615 IF T(C)=1 THEN GOTO 3620
\n3620 IF H(C)>1 THEN LET R=R+H(C)
\n3630 IF H(C)<1 THEN LET S=S+H(C)
\n3800 NEXT C
\n3810 LET P=-S
\n3815 GOSUB 4000
\n3820 PRINT AT 4,4;"REVENUES: ";AT 4,32-LEN P$;P$
\n3825 LET P=-R
\n3830 GOSUB 4000
\n3835 PRINT AT 6,4;"EXPENSES: ";AT 6,32-LEN P$;P$
\n3920 PRINT AT 7,0;Y$
\n3924 LET P=(R+S)*-1
\n3926 GOSUB 4000
\n3930 PRINT AT 8,4;"RESULT: ";AT 8,32-LEN P$;P$
\n3940 PRINT AT 10,4;"( - MEANS LOSS)"
\n3950 PRINT AT 20,10;" INPUT ""1"" TO RETURN ";AT 21,10;" INPUT ""0"" TO COPY "
\n3960 INPUT I
\n3974 IF I<1 THEN COPY
\n3975 GOTO 10
\n3980 IF I>=1 THEN GOTO 10
\n4000 LET P$=STR$ (INT (P*100+.5)/100)
\n4010 IF P$(1)="." THEN LET P$="0"+P$
\n4020 IF LEN P$>1 THEN IF P$(1 TO 2)="-." THEN LET P$="-0"+P$(2 TO )
\n4030 FOR L=1 TO LEN P$
\n4040 IF P$(L)="." THEN GOTO 4070
\n4050 NEXT L
\n4060 LET P$=P$+".00"
\n4070 IF L=LEN P$-1 THEN LET P$=P$+"0"
\n4080 RETURN
\n4106 LET P=F(N)
\n4107 GOSUB 4000
\n4108 PRINT AT 4+(N-X),23-LEN P$;P$
\n4109 LET P=G(N)
\n4110 GOSUB 4000
\n4111 PRINT AT 4+(N-X),32-LEN P$;P$
\n4114 PRINT AT 4+(N-X),0;N;AT 4+(N-X),4;D$(N);AT 4+(N-X),10;E$(N)
\n4120 RETURN
\n4200 LET P=H(C)
\n4205 GOSUB 4000
\n4210 PRINT AT 17,31-LEN P$;P$
\n4215 RETURN
\n6000 PRINT AT 9,2;"START TAPE IN ""RECORD"" MODE";AT 10,12;" AND ";AT 11,6;"ENTER""CONT""TO SAVE"
\n6001 STOP
\n6002 SAVE "G/%L"
\n6003 GOTO 5
\n7002 PRINT AT 10,2;"ENTER DATE OF TRANSFER";AT 11,3;"(DAY AND MONTH ONLY)"
\n7010 INPUT I$
\n7015 CLS
\n7017 PRINT AT 6,0;"ENTER 1-30 FOR ACCT.TO TRSF."
\n7020 INPUT I
\n7022 CLS
\n7025 LET C=I
\n7030 LET N=(C*10)+1
\n7032 LET N(C)=N
\n7035 FOR Y=N TO (N+9)
\n7040 LET D$(Y)=" "
\n7045 LET E$(Y)=" "
\n7050 LET F(Y)=0
\n7055 LET G(Y)=0
\n7060 NEXT Y
\n7065 LET D$(N)=I$
\n7070 LET E$(N)="BFD."
\n7075 IF H(C)>1 THEN LET F(N)=H(C)
\n7080 IF H(C)<1 THEN LET G(N)=H(C)
\n7085 LET C=O
\n7100 PRINT AT 10,6;"TRANSFER COMPLETED"
\n7105 PAUSE 50
\n7150 GOTO 10
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
