This program is a unit-conversion utility offering eleven conversion types, including temperature (Celsius to Fahrenheit), length (centimeters to inches), and several pharmacist/apothecary-related measurements such as drams, grains, and milligrams. The main menu is displayed at lines 30–80, and user selection dispatches via a chain of IF/GO SUB statements to individual subroutines starting at line 210. Each conversion subroutine uses FLASH 1/FLASH 0 to highlight the result value on screen. Lines 770–820 reveal a hidden developer utility, accessible only by running those lines directly, that provides renumber, rem-kill, delete, and variable-list functions by calling machine code routines via RANDOMIZE USR with addresses computed using a bitmask technique.
Program Analysis
Program Structure
The program divides cleanly into four regions:
- Menu display (lines 20–80): Sets up the display and prints all eleven conversion choices.
- Dispatch (lines 90–200): Reads the user’s choice into
Aand routes to the appropriate subroutine via a chain ofIF … THEN GO SUBstatements, falling through toGO TO 30if no valid option is entered. - Conversion subroutines (lines 210–750): Each subroutine follows the same pattern:
CLS, print a heading,INPUTa value, compute the result, print it withFLASHhighlighting, then call the shared “press any key” subroutine at line 250 beforeRETURNing. - Hidden developer utilities (lines 760–820): A
SAVE/verify block and a developer toolkit that is never reached during normal execution.
Shared “Press Any Key” Subroutine
Line 250 acts as a shared tail-end subroutine called by every conversion routine via GO SUB 250. It prints a prompt at the bottom of the screen using PRINT AT 21,0, waits for a keypress with PAUSE 0, clears the screen, and returns. The subsequent RETURN in the calling subroutine (e.g., line 300’s GO SUB 250: RETURN) correctly unwinds both stack frames.
FLASH Highlighting of Results
Each conversion result is bracketed with FLASH 1 and FLASH 0 inline within a single PRINT statement, so only the numeric answer blinks on screen while the surrounding label text remains static. This is a straightforward but effective way to draw the user’s eye to the converted value.
Hidden Developer Toolkit (Lines 770–820)
These lines are unreachable during normal program flow — line 760 is a SAVE command and line 200 loops back to 30 — so the toolkit can only be invoked by manually running from line 770 with RUN 770 or GO TO 770. It offers four built-in utility functions:
- Renumber — machine code at address 64048
- Remkill — machine code at address 64841
- Delete (range) — machine code at address 65017
- Variable list — machine code at address 65184
The target address is selected using a bitmask technique on line 770: LET zzz=(64048 AND fff=1)+(64841 AND fff=2)+(65017 AND fff=3)+(65184 AND fff=4). In Sinclair BASIC, a boolean expression evaluates to 1 (true) or 0 (false), so multiplying the address by the boolean effectively selects exactly one address while zeroing out the rest. IF NOT zzz THEN GO TO 770 rejects invalid input.
Lines 810–820 pass parameters to the machine code via POKEs into system variables at addresses 23299–23302, then invoke the routine with RANDOMIZE USR zzz. The variable-list function uses PRINT USR zzz: STOP instead, suggesting it returns a value rather than performing an in-place operation.
There is a minor bug on line 810: the first POKE calculates the low byte of fff as fff - 265 * PEEK 23300 instead of the correct fff - 256 * PEEK 23300. This off-by-nine error would corrupt the parameter for the renumber start line when fff >= 256.
Bugs and Anomalies
| Line | Issue |
|---|---|
| 40, 260, 270, 290 | Consistent misspelling: “CENTEMETERS” should be “CENTIMETERS”. |
| 490 | The drams-to-milliliters subroutine prints the result labeled “MILLIGRAMS” instead of “MILLILITERS”. |
| 810 | Low-byte calculation uses multiplier 265 instead of 256, corrupting the parameter when fff ≥ 256. |
| 30–80 | The menu heading and option 8 spell it “FARENHEIT”; lines 210 and 240 also use “FARENHEIT” — correct spelling is “FAHRENHEIT”. |
Key BASIC Idioms
- Chained
IF A=n THEN GO SUB …withoutELSE— standard dispatch pattern in Sinclair BASIC, which has noSELECT CASE. - Boolean arithmetic for address selection:
(address AND condition)used as a multiply-by-boolean. PAUSE 0as an indefinite wait for any keypress (line 250).- Inline
FLASHattribute changes within a singlePRINTto selectively highlight output.
Content
Source Code
10 REM FECIT T. SIMON
20 BORDER 0: PAPER 0: INK 7: CLS
30 PRINT " THIS IS A CONVERSION PROGRAM"'" CHOOSE ONE OF THE FOLLOWING: "''''
40 PRINT TAB 4;"1. CELSIUS TO FARENHEIT"';TAB 4;"2. CENTIMETERS TO INCHES";TAB 4;"3. GRAMS TO GRAINS"
50 PRINT TAB 4;"4. MILLILITERS TO OUNCES";TAB 4;"5. GRAINS TO MILLIGRAMS"
60 PRINT TAB 4;"6. DRAMS TO MILLILITERS";TAB 4;"7. DRAMS (AVDP) TO GRAINS"
70 PRINT TAB 4;"8. IMP.OZS. TO US.FL.OZ.";TAB 4;"9. IMP. GALLONS TO LITERS"
80 PRINT TAB 3;"10. POUNDS TO GRAMS";TAB 3;"11. OUNCES TO MILLILITERS"
90 INPUT A: IF A=1 THEN GO SUB 210
100 IF A=2 THEN GO SUB 260
110 IF A=3 THEN GO SUB 310
120 IF A=4 THEN GO SUB 360
130 IF A=5 THEN GO SUB 410
140 IF A=6 THEN GO SUB 460
150 IF A=7 THEN GO SUB 510
160 IF A=8 THEN GO SUB 560
170 IF A=9 THEN GO SUB 610
180 IF A=10 THEN GO SUB 660
190 IF A=11 THEN GO SUB 710
200 GO TO 30
210 CLS : PRINT "CONVERTING CELSIUS TO FAHRENHEIT"'''
220 INPUT "ENTER CELSIUS TEMPERATURE ";C
230 LET F=1.8*C+32
240 PRINT ''C;" CELSIUS= "; FLASH 1;F; FLASH 0;" FARENHEIT"
250 PRINT AT 21,0;"PRESS ANY KEY TO RESTART": PAUSE 0: CLS : RETURN
260 CLS : PRINT "CONVERTING CENTEMETERS TO INCHES"
270 INPUT "ENTER CENTEMETERS ";C
280 LET I=.3937*C
290 PRINT ''C;" CENTEMETERS = "; FLASH 1;I; FLASH 0;" INCHES"
300 GO SUB 250: RETURN
310 CLS : PRINT "CONVERTING GRAMS TO GRAINS"
320 INPUT ''"ENTER GRAMS ";G
330 LET N=15.432*G
340 PRINT ''G;" GRAMS = "; FLASH 1;N; FLASH 0;" GRAINS"
350 GO SUB 250: RETURN
360 CLS : PRINT "CONVERTING MILLILITERS TO OUNCES"
370 INPUT ''"ENTER MILLILITERS ";M
380 LET O=M/29.573
390 PRINT ''M;" MILLITERS = "; FLASH 1;O; FLASH 0;" OUNCES"
400 GO SUB 250: RETURN
410 CLS : PRINT "CONVERTING GRAINS TO MILLIGRAMS "'''
420 INPUT '"ENTER GRAINS ";N
430 LET G=N*64.799
440 PRINT N;" GRAINS = "; FLASH 1;G; FLASH 0;" MILLIGRAMS"
450 GO SUB 250: RETURN
460 CLS : PRINT "CONVERTING DRAMS TO MILLILITERS"''
470 INPUT "ENTER DRAMS ";D
480 LET M=3.552*D
490 PRINT D;" DRAMS = "; FLASH 1;M; FLASH 0;" MILLIGRAMS"
500 GO SUB 250: RETURN
510 CLS : PRINT "CONVERTING DRAMS(AVDP) TO GRAINS"
520 INPUT "ENTER DRAMS ";D
530 LET G=27.334*D
540 PRINT ''D;" DRAMS = "; FLASH 1;G; FLASH 0;" GRAINS"
550 GO SUB 250: RETURN
560 CLS : PRINT "CONVERTING IMP.OZS. TO US.FL.OZS"
570 INPUT "ENTER IMPERIAL OUNCES ";I
580 LET U=1.041*I
590 PRINT ''I;" IMP. OUNCES = "; FLASH 1;U; FLASH 0;" US. OUNCES"
600 GO SUB 250: RETURN
610 CLS : PRINT "CONVERTING IMP.GALLONS TO LITERS"''
620 INPUT "ENTER IMPERIAL GALLONS ";I
630 LET L=4.546*I
640 PRINT I;" IMP.GALS. = "; FLASH 1;L; FLASH 0;" LITERS"
650 GO SUB 250: RETURN
660 CLS : PRINT "CONVERTING POUNDS TO GRAMS"''
670 INPUT "ENTER POUNDS ";P
680 LET G=453.59*P
690 PRINT P;" POUNDS = "; FLASH 1;G; FLASH 0;" GRAMS"
700 GO SUB 250: RETURN
710 CLS : PRINT "CONVERTING OUNCES TO MILLILITERS"
720 INPUT "ENTER OUNCES ";O
730 LET M=29.573*O
740 PRINT O;" OUNCES = "; FLASH 1;M; FLASH 0;" MILLILITERS"
750 GO SUB 250: RETURN
760 SAVE "CONVERSION" LINE 5: PRINT "REWIND TAPE AND VERIFY": VERIFY "": RUN
770 CLS : PRINT "1) Renumber"'"2) Remkill"'"3) Delete"'"4) Variable list": INPUT fff: LET zzz=(64048 AND fff=1)+(64841 AND fff=2)+(65017 AND fff=3)+(65184 AND fff=4): IF NOT zzz THEN GO TO 770
780 LET ttt=100: LET fff=ttt: IF zzz=64048 THEN INPUT "Start ";fff,"Step ";ttt
790 IF zzz=65017 THEN INPUT "From ";fff,"To ";ttt
800 IF fff>9999 OR fff<1 OR ttt>9999 OR ttt<1 OR (fff>ttt AND zzz=65017) THEN GO TO 770
810 POKE 23300,INT (fff/256): POKE 23299,fff-265*PEEK 23300: POKE 23302,INT (ttt/256): POKE 23301,ttt-256*PEEK 23302: IF zzz=65184 THEN PRINT USR zzz: STOP
820 RANDOMIZE USR zzz
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
