This is a payroll management system that handles employee records, weekly hours input, pay stub generation, and year-to-date withholding tracking for up to 32 employees. Employee data is stored compactly in a two-dimensional string array N$(25,200), encoding numeric values such as hours, rates, and accumulated totals as raw character bytes using a three-byte binary packing scheme (lines 16–28 and 36–42) to work around the limited numeric storage of the platform. The program supports multiple withholding categories (federal tax, state tax, FICA, disability, unemployment, and other) with configurable percentage rates and a FICA dollar cap. Menu navigation uses INKEY$ scanning with CODE-based dispatch via a calculated GOTO at line 700.
Program Structure
The program is organised as a menu-driven application with a main dispatch loop at lines 500–700 and numbered sections at every 1000th line. The top of the file (lines 10–116) contains shared subroutines, and the menu entry point at line 500 prints a title before falling through to the menu at line 570.
| Line range | Purpose |
|---|---|
| 10–14 | Subroutine: “Press Enter to continue” pause |
| 16–28 | Subroutine: pack integer X into 3-char string X$ |
| 36–42 | Subroutine: unpack 3-char string X$ into integer X |
| 44–52 | Subroutine: input a value and store as CHR$ in N$ |
| 56–66 | Subroutine: display employee list (two columns) |
| 70–94 | Subroutine: print data-entry screen labels |
| 100–116 | Subroutine: format and print a monetary value P with decimal alignment |
| 200–440 | Subroutine: calculate and display a pay stub for employee K, week Y |
| 500–703 | Startup banner and main menu with INKEY$ dispatch |
| 1000–1130 | Option 1: Add a new employee |
| 1520–1690 | Per-field data-entry subroutines (called via calculated GOSUB) |
| 2000–2410 | Option 2: Input weekly hours for all employees |
| 3000–3140 | Option 3: Print individual pay stub |
| 4000–4220 | Option 4: Print weekly payroll totals |
| 5000–5160 | Option 5: Print year-to-date withholding totals |
| 6000–6310 | Option 6: Change employee data |
| 7000–7240 | Option 7: Initialise (clear) all data |
| 8000–8020 | Option 8: SAVE program to tape |
| 9000–9110 | Option 9: Update tax-rate constants |
| 9100–9110 | Error handler: “INITIATE FIRST” guard |
Data Storage: Binary Packing in a String Array
All employee records live in N$(25,200), a 25-row × 200-character string array. Numeric values that exceed a single byte range (e.g., hourly rates in cents, year-to-date totals) are stored as 2- or 3-byte sequences using CHR$ encoding. The pack subroutine at lines 16–28 decomposes an integer into base-65536, base-256, and remainder components, storing each as a character. The corresponding unpack subroutine (lines 36–42) reconstructs the value with CODE and multiplications. This avoids storing floating-point numbers (which consume 5 bytes each) and instead uses only as many characters as needed.
The layout of significant byte offsets within each employee row is as follows:
| Column(s) | Content |
|---|---|
| 1–10 | Last name (padded) |
| 11 | Initial |
| 12–13 | Hourly rate × 100 (2 bytes) |
| 14–18 | Withholding % rates (1 byte each: FWT, STAX, FICA-flag, DISA, VAC) |
| 19–20 | Vacation/sick deduction × 100 (2 bytes) |
| W+20 | Hours for week W (packed: hours×4 + vac×32) |
| 2W+70–2W+71 | Rate snapshot for week W (2 bytes) |
| 177–179 | YTD gross pay × 100 (3 bytes) |
| 180–198 | YTD withholdings by category (3 bytes each, 7 categories) |
Menu Dispatch
The main menu (lines 680–700) reads a keypress with INKEY$ in a tight polling loop, validates that its CODE falls in the range 29–37 (keys 1–9), then executes GOTO 1000*(CODE B$-28). This maps key “1” → line 1000, “2” → 2000, …, “9” → 9000 in a single calculated jump, a classic Sinclair BASIC dispatch idiom.
Data-entry field subroutines during employee add/change are similarly dispatched with GOSUB K*20+1500 (lines 1090, 6270), stepping through fields at lines 1520, 1540, 1560, 1580/1600, 1620, 1640, 1660, 1680.
Monetary Formatting Subroutine (Lines 100–116)
The formatting routine at line 100 is a pure-BASIC fixed-point formatter for currency values stored as floating-point. It rounds to two decimal places, converts via STR$, then applies a cascade of string-length checks to ensure exactly two digits appear after the decimal point. If the value is six or more characters (i.e., ≥ 1000.00), a comma is inserted three places from the right. Output is right-aligned to column V+10 using TAB.
Pay Calculation (Lines 200–440)
The pay stub routine unpacks hours (dividing the stored byte by 4 to recover quarter-hours) and separates regular from overtime (anything above 40 hours). Base pay is R*H; premium overtime pay applies the employee’s overtime multiplier stored at offset 14. Withholding deductions (FWT, STAX, FICA, disability, unemployment, other) are each computed as a percentage of gross and accumulated into both weekly totals T() and year-to-date totals W(). The FICA deduction is capped by checking the running YTD total against the configured dollar limit T. The Z flag controls whether totals are accumulated (Z=0) or the stub is display-only (Z=1 or Z=2).
Notable Techniques and Idioms
- The
INKEY$polling loop at lines 680–700 and 2210–2230 is used withoutPAUSE 0pre-delay, relying on the loop itself for debounce. RUN 7015at line 7011 during initialisation clears all variables and restarts execution mid-program, a technique used to reliably reset all arrays and variables without a separate clear routine.- The
H$()string array (8 rows × 4 chars) stores short category labels (“GRSS”, “FWT”, “STAX”, “FICA”, “DISA”, “UNEM”, “OTAX”, “OTHR”) for reuse throughout display and input prompts, avoiding repeated string literals. DIM W(7)appears twice (lines 7015 and 7050) — the secondDIMreinitialises the array to zero after the rate-input section, which effectively doubles as a year-to-date accumulator reset.- The block-graphic characters in lines 78, 80, 82, 84 (rendered as
\ '/\.= ▝▖ = a “%” lookalike) are used decoratively as a percent-sign substitute within labels.
Content
Source Code
10 PRINT AT 21,0;"%T%O% %C%O%N%T%I%N%U%E% %P%R%E%S%S% %E%N%T%E%R"
12 INPUT X$
14 RETURN
16 DIM X$(3)
18 LET X1=INT (X/65536+.001)
20 LET X$(1)=CHR$ X1
21 LET X2=X-X1*65536
23 LET X2=INT (X2/256+.001)
24 LET X$(2)=CHR$ X2
25 LET X3=INT (ABS (X-INT (X1*65536)-INT (X2*256)))
27 LET X$(3)=CHR$ X3
28 RETURN
36 LET X=CODE X$(1)*65536
37 LET X=X+CODE X$(2)*256
38 LET X=X+CODE X$(3)
42 RETURN
44 INPUT X
46 PRINT AT K+1,22;X
48 GOSUB 16
50 LET N$(F,K+10)=CHR$ X
52 RETURN
56 FOR K=1 TO F
58 LET X=K
60 IF K>12 THEN LET X=K-12
62 PRINT AT X,16*(K>12);K;TAB (4+(20*(K>12)));N$(K, TO 10);" ";N$(K,11 TO 12)
64 NEXT K
66 RETURN
70 CLS
71 PRINT AT 2,0;"1.LAST NAME="
72 PRINT "2.INITIAL="
76 PRINT "3.HOURLY RATE="
78 PRINT "4.O.T( '/. HRLY RATE)="
80 PRINT "5. '/. ";H$(2)
82 PRINT "6. '/. ";H$(3)
84 PRINT "7. '/. ";H$(8)
90 PRINT "8.VAC/SICK DAYS="
92 PRINT "9.";H$(8)
94 RETURN
100 LET P=INT (100*P+.05)/100
101 LET Y$=" "
102 IF P=0 THEN GOTO 114
103 LET Y$=STR$ P
104 IF LEN Y$=1 THEN LET Y$=Y$+".00"
106 IF LEN Y$=2 THEN LET Y$=Y$+".0"
108 IF Y$(LEN Y$-1)="." THEN LET Y$=Y$+"0"
110 IF Y$(LEN Y$-2)<>"." THEN LET Y$=Y$+".00"
112 IF LEN Y$>6 THEN LET Y$=Y$( TO LEN Y$-6)+","+Y$(LEN Y$-5 TO LEN Y$)
114 PRINT TAB (V+10-LEN Y$);Y$
116 RETURN
200 CLS
202 PRINT N$(K, TO 10);",";N$(K,11);TAB 24;"%W%E%E%K:";Y
204 LET X$=" "+N$(K,20+Y)
206 GOSUB 36
208 LET H=X/4
232 LET I=0
234 IF H>40 THEN LET I=H-40
236 LET H=H-I
238 LET X$=" "+N$(K,2*Y+70 TO 2*Y+71)
240 GOSUB 36
242 LET R=X/100
244 PRINT
246 LET P=R*H
247 LET G=P
248 LET V=22
250 PRINT "BASE PAY";
251 LET J=1
252 GOSUB 100
253 PRINT "PREMIUM PAY";
254 LET X$=" "+N$(K,14)
255 GOSUB 36
256 LET P=I*R*(1+X/100)
257 LET G=G+P
258 GOSUB 100
259 PRINT "%G%R%O%S%S% %P%A%Y";
260 LET P=G
261 GOSUB 100
262 IF Z=0 THEN LET T(8)=T(8)+P
265 PRINT
266 PRINT H$(2);
267 LET A=15
268 LET B=180
269 LET R=G
270 GOSUB 272
271 GOTO 296
272 LET X$=" "+N$(K,A)
273 GOSUB 36
274 LET P=G*X/100
275 LET V=13
276 GOSUB 100
277 IF Z>0 THEN GOTO 293
278 LET X$=N$(K,B TO B+2)
279 GOSUB 36
280 LET X=X+P*100
282 GOSUB 16
284 LET N$(K,B TO B+2)=X$
285 IF Z=0 THEN LET T(J)=T(J)+P
286 IF Z=0 THEN LET W(J)=W(J)+P
293 LET R=R-P
294 RETURN
296 PRINT H$(3);
297 LET J=2
298 LET A=16
300 LET B=183
302 GOSUB 272
304 PRINT H$(4);
306 LET X$=N$(K,186 TO 188)
308 GOSUB 36
309 IF X/100<>T THEN GOTO 312
310 LET P=0
311 GOTO 324
312 LET P=G*S/100
314 IF P>T-X/100 THEN LET P=T-XV100
317 LET X=X+P*100
318 GOSUB 16
319 LET N$(K,186 TO 188)=X$
320 GOSUB 100
321 IF Z>0 THEN GOTO 324
322 LET T(3)=T(3)+P
323 LET W(3)=W(3)+P
324 LET R=R-P
326 PRINT H$(7);
327 LET J=6
328 LET A=17
330 LET B=195
332 GOSUB 272
334 PRINT H$(5);
336 LET P=G*D/100
337 LET B=189
338 LET J=4
340 GOSUB 276
342 PRINT H$(6);
344 LET P=G*U/100
346 LET B=192
348 LET J=5
350 GOSUB 276
362 PRINT H$(8);
364 LET X$=" "+N$(K,19 TO 20)
366 GOSUB 36
368 LET P=X/100
369 LET J=7
370 LET B=198
372 GOSUB 276
384 PRINT
388 PRINT "%N%E%T% %P%A%Y";
390 LET V=22
395 LET P=R
400 GOSUB 100
402 IF Z>0 THEN GOTO 414
404 LET X$=N$(K,177 TO 179)
406 GOSUB 36
408 LET X=X+G*100
410 GOSUB 16
412 LET N$(K,177 TO 179)=X$
414 PRINT
415 IF Z=2 THEN RETURN
416 PRINT "%Y%E%A%R% %T%O%D%A%T%E%:"
418 FOR J=1 TO 8
420 LET A=16
422 LET V=5
424 IF J>4 THEN LET A=12
426 IF J>4 THEN LET V=22
428 PRINT AT A+J,V-5;H$(J);
430 LET X$=N$(K,3*J+174 TO 3*J+176)
432 GOSUB 36
434 LET P=X/100
436 GOSUB 100
438 NEXT J
440 RETURN
500 FAST
520 PRINT " PAYROLL COPYRIGHT UAS BOX 612 HADDONFIELD,N.J.08033"
530 PRINT
540 GOTO 570
550 FAST
560 CLS
570 PRINT "%P%R%E%S%S% %N%U%M%B%E%R% %D%E%S%I%R%E%D"
580 PRINT
590 PRINT "1..ADD NAME"
600 PRINT "2..INPUT WEEKLY INFO"
610 PRINT "3..EMPLOYEE PAY STUB"
620 PRINT "4..TOTAL PAYROLL"
630 PRINT "5..TOTAL WITH-HOLDING TODATE"
640 PRINT "6..CHANGE EMPLOYEE DATA"
650 PRINT "7..INITIATE"
660 PRINT "8..SAVE"
665 PRINT "9..UPDATE CONSTANTS"
670 SLOW
680 LET B$=INKEY$
690 IF CODE B$<29 OR CODE B$>37 THEN GOTO 680
700 GOTO 1000*(CODE B$-28)
703 LET W=0
1000 FAST
1010 CLS
1015 IF E=0 THEN GOTO 9100
1020 IF E<33 THEN GOTO 1060
1030 PRINT "%F%I%L%E% %F%U%L%L"
1040 PAUSE 100
1050 GOTO 550
1060 PRINT "%A%D%D% %N%A%M%E..FILE NUMBER=";E
1070 PRINT
1080 GOSUB 70
1081 LET F=E
1082 FOR K=1 TO 9
1085 PRINT AT K+1,22;"% ";C$(23 TO 31)
1090 GOSUB K*20+1500
1100 NEXT K
1110 LET E=E+1
1120 GOSUB 10
1130 GOTO 550
1520 INPUT N$(F, TO 10)
1522 PRINT AT K+1,22;N$(F, TO 10)
1524 RETURN
1540 INPUT N$(F,11)
1542 PRINT AT K+1,22;N$(F,11 TO 12)
1544 RETURN
1560 INPUT X
1562 PRINT AT K+1,22;X
1564 LET X=X*100
1566 GOSUB 16
1568 LET N$(F,12 TO 13)=X$(2 TO )
1570 RETURN
1580 GOTO 1600
1600 GOSUB 44
1602 RETURN
1620 GOTO 1600
1660 GOTO 1600
1680 INPUT X
1682 PRINT AT K+1,22;X
1684 LET X=X*100
1686 GOSUB 16
1688 LET N$(F,19 TO 20)=X$(2 TO )
1690 RETURN
2000 FAST
2002 DIM T(8)
2005 IF E=0 THEN GOTO 9100
2010 CLS
2020 PRINT "%W%E%E%K%L%Y% %I%N%F%O"
2025 PRINT
2026 PRINT "INPUT WEEK NO.="
2030 INPUT X
2040 IF X>W THEN GOTO 2070
2050 PRINT "%A%L%R%E%A%D%Y% %E%N%T%E%R%E%D"
2060 GOTO 1040
2070 LET W=X
2080 FOR K=1 TO E-1
2090 FAST
2100 DIM X(2)
2105 CLS
2110 PRINT N$(K, TO 10);",";N$(K,11)
2120 PRINT
2130 PRINT "%I%N%P%U%T HRS(.25 PER 1/4 HR)=";
2140 INPUT X(1)
2150 PRINT X(1)
2151 LET K$="PAID VAC/SICK DAYS"
2155 PRINT
2156 PRINT K$;" TODATE:";
2157 LET X$=" "+N$(K,18)
2158 GOSUB 36
2159 PRINT X
2160 PRINT "%I%N%P%U%T ";K$;"=";
2170 INPUT X(2)
2180 PRINT X(2)
2190 PRINT AT 21,0;"CHANGE Y OR N?"
2200 SLOW
2210 IF INKEY$="N" THEN GOTO 2270
2220 IF INKEY$="Y" THEN GOTO 2090
2230 GOTO 2210
2270 FAST
2280 CLS
2290 LET X=X(1)*4+X(2)*32
2300 GOSUB 16
2310 LET N$(K,W+20)=X$(3)
2320 LET X=X(2)
2330 GOSUB 16
2340 LET N$(K,18)=X$(3)
2350 LET N$(K,W*2+70 TO W*2+71)=N$(K,12 TO 13)
2360 LET Z=0
2370 LET Y=W
2380 GOSUB 200
2390 GOSUB 10
2400 NEXT K
2410 GOTO 550
3000 FAST
3005 IF E=0 THEN GOTO 9100
3010 CLS
3015 GOSUB 3020
3016 GOTO 3050
3020 FOR K=1 TO E-1 STEP 2
3030 PRINT CHR$ (K+156);TAB 3;N$(K, TO 10)+","+N$(K,11);TAB 16;CHR$ (K+157);TAB 20;N$(K+1, TO 10)+","+N$(K+1,11)
3040 NEXT K
3045 RETURN
3050 PRINT
3060 PRINT "%I%N%P%U%T NUMBER=";
3070 INPUT K
3080 PRINT K
3090 PRINT "%I%N%P%U%T WEEK "
3095 LET Z=1
3100 INPUT Y
3105 IF Y>W THEN GOTO 550
3110 IF Y<>W THEN LET Z=2
3120 GOSUB 200
3130 GOSUB 10
3140 GOTO 550
4000 FAST
4010 CLS
4015 IF E=0 THEN GOTO 9100
4020 PRINT "%P%A%Y%R%O%L%L% %F%O%R% %W%E%E%K%: ";W
4030 PRINT
4040 PRINT "GROSS PAY ";
4045 LET V=15
4050 LET P=T(8)
4060 GOSUB 100
4070 PRINT "%W%I%T%H%-%H%O%L%D%I%N%G%S"
4074 PRINT
4075 LET V=7
4080 FOR K=2 TO 8
4090 PRINT H$(K);
4100 LET P=T(K-1)
4110 GOSUB 100
4120 NEXT K
4210 GOSUB 10
4220 GOTO 550
5000 FAST
5010 CLS
5015 IF E=0 THEN GOTO 9100
5020 PRINT "%W%I%T%H%-%H%O%L%D%I%N%G%S% %T%O% %W%E%E%K ";W
5030 PRINT
5090 LET V=8
5100 FOR K=1 TO 7
5105 PRINT H$(K+1);
5110 LET P=W(K)
5120 PRINT AT K+1,0;
5130 GOSUB 100
5140 NEXT K
5150 GOSUB 10
5160 GOTO 550
6000 FAST
6005 IF E=0 THEN GOTO 9100
6010 CLS
6020 PRINT "%C%H%A%N%G%E% %D%A%T%A"
6025 GOSUB 3020
6030 PRINT AT 21,0;"INPUT FILE NO."
6032 INPUT Y
6050 GOSUB 70
6060 PRINT AT 2,22;N$(Y, TO 10)
6070 PRINT AT 3,22;N$(Y,11)
6110 LET X$=" "+N$(Y,12 TO 13)
6120 GOSUB 36
6130 PRINT AT 4,22;X/100
6150 FOR K=14 TO 18
6160 LET X$=" "+N$(Y,K)
6170 GOSUB 36
6180 PRINT AT K-9,22;X
6190 NEXT K
6200 LET X$=" "+N$(Y,19 TO 20)
6210 GOSUB 36
6220 PRINT AT 10,22;X/100
6230 PRINT AT 21,0;"INPUT LINE NO,OR 0 FOR END"
6240 INPUT K
6250 IF K=0 THEN GOTO 550
6260 IF K<1 OR K>10 THEN GOTO 6240
6265 PRINT AT K+1,22;"% ";C$( TO 9)
6268 PRINT AT 21,0;C$
6269 LET F=Y
6270 GOSUB K*20+1500
6310 GOTO 6230
7000 CLS
7001 PRINT "THIS MODE CLEARS FILES %P%R%E%S%S: Y IF YOU WANT IT, N IF NOT"
7002 SLOW
7003 IF INKEY$="N" THEN GOTO 550
7004 IF INKEY$="Y" THEN GOTO 7010
7005 GOTO 7003
7010 FAST
7011 RUN 7015
7015 DIM W(7)
7020 DIM C$(32)
7030 DIM N$(25,200)
7031 DIM H$(8,4)
7032 LET H$(2)="FWT"
7033 LET H$(3)="STAX"
7034 LET H$(4)="FICA"
7035 LET H$(5)="DISA"
7036 LET H$(6)="UNEM"
7037 LET H$(7)="OTAX"
7038 LET H$(8)="OTHR"
7040 LET E=1
7041 LET H$(1)="GRSS"
7050 DIM W(7)
7060 FAST
7070 CLS
7080 PRINT H$(4);" '/. RATE=";
7090 INPUT S
7100 PRINT S
7110 PRINT H$(4);" $ LIMIT=";
7120 INPUT T
7130 PRINT T
7140 PRINT H$(5);" '/. RATE=";
7150 INPUT D
7160 PRINT D
7170 PRINT H$(6);" '/. RATE=";
7180 INPUT W
7190 PRINT W
7200 PRINT AT 21,0;"CHANGE Y OR N?"
7210 SLOW
7220 IF INKEY$="Y" THEN GOTO 7060
7230 IF INKEY$="N" THEN GOTO 550
7240 GOTO 7220
8000 CLS
8010 SAVE "PA%Y"
8020 GOTO 500
9000 FAST
9010 CLS
9020 IF E=0 THEN GOTO 9100
9030 PRINT H$(4);" '/. RATE=";S
9040 PRINT H$(4);" $ LIMIT=";T
9050 PRINT H$(5);" '/. RATE=";D
9060 PRINT H$(6);" '/. RATE=";U
9070 GOTO 7200
9100 PRINT "%I%N%I%T%I%A%T%E% %F%I%R%S%T"
9110 GOTO 1040
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.

