Flexicon

Products: Flexicon
Type: Program
Platform(s): TS 2068

This program is the consolidation module of a business spreadsheet application called “FLEXICON” by Saxon Computing. It manages two named matrices (A and B) stored as string arrays, allowing users to load and save them to tape as three separate files per dataset (parameters, data, and formula files, distinguished by single-character suffixes “P”, “D”, and “F”). The core operations are validation, addition, and subtraction of corresponding cells across the two matrices, with cell data packed into 10-character fixed-width slots within the string arrays. Validation uses machine code called via RANDOMIZE USR 23780, with parameters set by POKEing addresses 23768, 23769, and 23772, suggesting a resident machine code routine handles string comparison or manipulation. Navigation between functions uses a computed GO TO (VAL Z$*1000) and computed GO SUB (VAL Z$*100+1400/1420/1440) idioms to route tape operations cleanly.


Program Analysis

Program Structure

The program is organized into clearly delineated functional blocks, each starting at a round line number:

Line RangeFunction
1REM header (contains embedded binary/graphic data)
800Initialization — sets POKE 23609 and jumps to main menu
900–904Common “press X to return” subroutine
1010–1220Load/Save file menu and tape orchestration
1500–1640Tape I/O subroutines for parameters, data, and formula arrays
1900–1920Matrix selection subroutine (A or B)
2000–2920Validation module
3000–3800Addition/consolidation module
4000–4200Subtraction module
9000–9040Main menu
9500–9980Developer/debug utilities (unreachable from menu)

Data Model

Each matrix dataset is held in a two-dimensional string array (S$ for matrix A, G$ for matrix B). Cells are packed into fixed 10-character slots within each row: for column K, the slot starts at character position Z = K*10-9. The first character of each slot is a type/flag byte, and characters 2–10 hold the numeric value as a string. This encoding allows variable-length numeric strings to be stored in a fixed-width string array without dynamic allocation.

A separate numeric array A() holds parameters: A(1)=rows, A(2)=columns, A(3)=formula count, A(4)=a formula pointer F. A formula string array F$(A,42) is also maintained.

Tape File Strategy

Each dataset is saved as three separate tape files, with the filename suffix distinguishing them:

  • N$+"P" — parameters array A()
  • N$+"D" — data string array S$() or G$()
  • N$+"F" — formula string array F$()

The tape subroutines at lines 1500–1640 are selected using a computed GO SUB: GO SUB VAL Z$*100+1400, +1420, and +1440. Since Z$ is either "1" (load) or "2" (save), this resolves to subroutines at 1500/1520/1540 (load) or 1600/1620/1640 (save), a compact dispatch mechanism.

Machine Code Usage

The validation loops at lines 2100 and 2110 invoke machine code via RANDOMIZE USR 23780. Before each call, three system addresses are prepared:

  • POKE 23768, PEEK 23629 and POKE 23769, PEEK 23630 — copies the current string array’s base address (from the STKEND/STRMS area) into a parameter block at 23768/23769
  • POKE 23772, C1 — passes the column count as a parameter

The self-assignment idiom LET S$(L,1)=S$(L,1) (also at line 9980) is a known technique to force the BASIC interpreter to update the string’s address in the BASIC stack or stale pointer area, ensuring PEEK 23629/23630 reflects the correct current row pointer before the machine code runs.

Validation Logic

After the machine code preprocessing, lines 2400–2490 compare each corresponding cell across the two matrices. The condition at line 2410 is:

IF S$(L,Z)=G$(L,Z) OR CODE S$(L,Z) AND CODE G$(L,Z)>98 THEN GO TO 2490

This skips incompatibility reporting if the type bytes match, or if both cells have a type code above 98 (likely both are “empty” or a special marker). The validation flag CVF is set to 1 on any mismatch and checked before arithmetic operations at lines 3015 and 4015.

Arithmetic Operations

Addition (lines 3100–3150) and subtraction (lines 4100–4150) are structurally identical. For each non-blank cell in S$, the numeric substring (characters Z+1 to K*10) is extracted with VAL, arithmetic is applied with the corresponding G$ cell, and the result is written back with STR$. A check at code 99 (which is the code for the lowercase letter ‘c’, likely used as a “credit/negative” flag) clears the flag byte to a space after the operation. The subtraction module reuses the addition module’s NEXT statement at line 3150 via a cross-module GO TO, and both share the completion message at 3200.

Main Menu Dispatch

The main menu at line 9030 polls INKEY$ and validates the keypress by checking CODE Z$ against the range 49–52 (ASCII for ‘1’–’4′). The dispatch at line 9040 uses GO TO VAL Z$*1000, routing to lines 1000, 2000, 3000, or 4000. Note that line 1000 does not exist; the program instead lands at line 1010, which is the intended entry point for the load/save module — a well-known technique exploiting BASIC’s “next line at or after” line-lookup behavior.

Developer Utilities

Lines 9500–9980 contain debug tools that are unreachable from the menu:

  • Lines 9500–9510: Memory dump — prints 20 bytes from a user-specified address as characters
  • Lines 9900–9910: Dumps the current S$ array region using the BASIC stack pointer at 23768/23769
  • Lines 9950–9960: Dumps the string data area using STKEND pointers at 23629/23630
  • Line 9980: Forces S$ pointer refresh then falls through to 9950

These routines use STOP mid-line to halt after output, a common interactive debugging pattern.

Notable Anomalies

  • Line 4110 branches to GO TO 3150 (in the addition module’s loop body) rather than the logically equivalent line 4150. This is intentional code reuse but could cause subtle issues if the addition module’s loop structure ever changed independently.
  • The DIM X$(10) at line 1050 is unused — N$ is populated by INPUT N$, not X$. This appears to be a vestigial statement.
  • Line 800 POKEs 23609 (REPDEL, the key repeat delay) to 65 at startup, extending the key repeat delay.

Content

Appears On

Related Products

Formatting utility for Flexicalc 48 reports

Related Articles

Related Content

Image Gallery

Flexicon

Source Code

    1 REM x.-\/ABS 0ABS x2\ \xxxxx: BRIGHT \O* CIRCLE \" VERIFY \ CLEAR " MOVE \ CLEAR " ERASE \ CLEAR " FLASH \ CLEAR " INVERSE \* VERIFY \#" VERIFY \ RESTORE >-! ERASE \\g LLIST LINE ]>-2 ERASE \\g LINE c] RESTORE >.! MOVE \\g LLIST LINE 4]>.\gCHR$ 4]>.2 MOVE \NOT c] FREE VERIFY  CHR$ J]: FLASH \ VERIFY 2CHR$ \' ]> 2 INVERSE \NOT c]: INVERSE \ VERIFY  LINE \' ] FREE VERIFY 0 IF \' ] FREE VERIFY : PAUSE \' ]>22 FLASH \CHR$ ]* CIRCLE \ FREE VERIFY  CHR$ r]6c* CIRCLE \ GO SUB Z" CIRCLE \CHR$ CONTINUE \<>* CIRCLE \6 NOT r]<> CLOSE #\CHR$ DATA \<>! CIRCLE \6 NOT r]<><>xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  800 POKE 23609,65: GO TO 9000
  900 PRINT FLASH 1;"   PRESS X TO RETURN TO MENU    "
  902 LET Z$=INKEY$: BEEP .2,8: IF Z$<>"X" THEN GO TO 902
  904 GO TO 9000
 1010 CLS : PRINT INVERSE 1;"****** LOAD OR SAVE FILES ******"
 1015 PRINT BRIGHT 1;'" PRESS 1 TO LOAD FILE "'" PRESS 2 TO SAVE FILE ": FOR L=1 TO 20: NEXT L
 1020 LET Z$=INKEY$: IF Z$<>"1" AND Z$<>"2" THEN GO TO 1020
 1030 LET M$="LOAD": IF Z$="2" THEN LET M$="SAV"
 1035 IF Z$="1" THEN GO SUB 1900
 1040 PRINT '"ENTER NAME OF FILE TO BE ";M$;"ED","(max 9 characters)  ";
 1050 DIM X$(10): INPUT N$: IF LEN N$>9 THEN GO TO 1050
 1060 PRINT BRIGHT 1;N$
 1070 PRINT '"START TAPE THEN PRESS ANY KEY": PAUSE 4E4
 1100 PRINT AT 19,0; FLASH 1;"    ";M$;"ING PARAMETERS FILE    ": GO SUB VAL Z$ *100 +1400
 1110 PRINT AT 19,0; FLASH 1;"     ";M$;"ING DATA FILE         ": GO SUB VAL Z$ *100 +1420     
 1120 PRINT AT 19,0; FLASH 1;"     ";M$;"ING FORMULA FILE      ": GO SUB VAL Z$ *100 +1440
 1200 PRINT AT 19,0; FLASH 1;"   TAPE OPERATIONS COMPLETED    "'"   PRESS X TO RETURN TO MENU    "
 1210 LET Z$=INKEY$: BEEP .5,8: IF Z$<>"X" THEN GO TO 1210
 1220 GO TO 9000
 1500 LET X$=N$+"P": LOAD X$ DATA A(): IF Y$="B" THEN GO TO 1503
 1501 LET C=A(1): LET C1=A(2): LET A=A(3): LET F=A(4): DIM F$(A,42)
 1502 DIM S$(C,C1*10+1): RETURN 
 1503 LET C2=A(1): LET C3=A(2): LET A=A(3): LET F=A(4): DIM F$(A,42)
 1504 DIM G$(C2,C3*10+1): RETURN 
 1520 LET X$=N$+"D": IF Y$="B" THEN GO TO 1522
 1521 LOAD X$ DATA S$(): RETURN 
 1522 LOAD X$ DATA G$(): RETURN 
 1540 LET X$=N$+"F": LOAD X$ DATA F$(): RETURN 
 1600 LET A(4)=F: LET X$=N$+"P": BEEP 2,8: SAVE X$ DATA A(): RETURN 
 1620 LET X$=N$+"D": BEEP 2,8: SAVE X$ DATA S$(): RETURN 
 1640 LET X$=N$+"F": BEEP 2,8: SAVE X$ DATA F$(): RETURN 
 1900 PRINT '"WHICH CONSOLIDATION MATRIX DO","YOU WANT FILLED A OR B         ";
 1910 LET Y$=INKEY$: IF Y$<>"A" AND Y$<>"B" THEN GO TO 1910
 1920 PRINT INVERSE 1;Y$: RETURN 
 2000 REM VALIDATION
 2005 IF C=0 OR C1=0 THEN GO TO 2900
 2010 CLS : LET CVF=0
 2020 IF C=C2 AND C1=C3 THEN GO TO 2060
 2030 PRINT AT 10,0;"MODEL MATRICES ARE NOT SAME SIZE   PRESS X TO RETURN TO MENU    "
 2040 LET Z$=INKEY$: BEEP .2,8: IF Z$<>"X" THEN GO TO 2040
 2050 GO TO 9000
 2060 PRINT AT 10,0; FLASH 1;"     VALIDATION IN PROGRESS     "
 2100 FOR L=1 TO C: LET S$(L,1)=S$(L,1): POKE 23768,PEEK 23629: POKE 23769,PEEK 23630: POKE 23772,C1: RANDOMIZE USR 23780: NEXT L
 2110 FOR L=1 TO C: LET G$(L,1)=G$(L,1): POKE 23768,PEEK 23629: POKE 23769,PEEK 23630: POKE 23772,C1: RANDOMIZE USR 23780: NEXT L
 2400 FOR L=1 TO C: FOR K=1 TO C1: LET Z=K*10-9
 2410 IF S$(L,Z)=G$(L,Z) OR CODE S$(L,Z) AND CODE G$(L,Z)>98 THEN GO TO 2490
 2420 PRINT "MATRICES INCOMPATIBLE AT ";L;",";K: LET CVF=1
 2490 NEXT K: NEXT L
 2500 PRINT AT 10,0; FLASH 1;"      VALIDATION COMPLETE       ": GO TO 900
 2900 CLS : PRINT AT 10,0; FLASH 1;"  ONE OF THE MATRICES IS EMPTY        PRESS X TO CONTINUE       "
 2910 LET Z$=INKEY$: BEEP .5,8: IF Z$<>"X" THEN GO TO 2910
 2920 GO TO 9000
 3000 REM ADDITION
 3010 CLS 
 3015 IF CVF=1 THEN GO TO 3800
 3020 PRINT AT 10,0; FLASH 1;"     ADDITION IN PROGRESS       "
 3100 FOR L=1 TO C: FOR K=1 TO C1: LET Z=K*10-9
 3110 IF S$(L,Z)=" " THEN GO TO 3150
 3120 LET S$(L,Z+1 TO K*10)=STR$ (VAL S$(L,Z+1 TO K*10)+VAL G$(L,Z+1 TO K*10))
 3140 IF CODE S$(L,Z)=99 THEN LET S$(L,Z)=CHR$ 32
 3150 NEXT K: NEXT L
 3200 PRINT AT 10,0; FLASH 1;"     CONSOLIDATION COMPLETE     ": GO TO 900
 3800 PRINT AT 10,0; FLASH 1;"MATRICES NOT CORRECTLY VALIDATED": GO TO 900
 4000 REM SUBTRACTION
 4010 CLS 
 4015 IF CVF=1 THEN GO TO 3800
 4020 PRINT AT 10,0; FLASH 1;"     SUBTRACTION IN PROGRESS    "
 4100 FOR L=1 TO C: FOR K=1 TO C1: LET Z=K*10-9
 4110 IF S$(L,Z)=" " THEN GO TO 3150
 4120 LET S$(L,Z+1 TO K*10)=STR$ (VAL S$(L,Z+1 TO K*10)-VAL G$(L,Z+1 TO K*10))
 4140 IF CODE S$(L,Z)=99 THEN LET S$(L,Z)=CHR$ 32
 4150 NEXT K: NEXT L
 4200 GO TO 3200
 9000 REM MAIN MENU
 9010 CLS : PRINT TAB 8; INVERSE 1;"SAXON COMPUTING"'"******* FLEXICON OPTIONS *******"
 9020 PRINT BRIGHT 1;''" Press 1 to LOAD OR SAVE A FILE "''" Press 2 to VALIDATE MODELS     "''" Press 3 to ADD MODELS          "''" Press 4 to SUBTRACT MODELS     "
 9030 LET Z$=INKEY$: IF CODE Z$<49 OR CODE Z$>52 THEN GO TO 9030
 9040 GO TO VAL Z$*1000
 9500 INPUT N
 9510 FOR K=0 TO 19: PRINT K+N;"  ";CHR$ PEEK (K+N): NEXT K: STOP : LET N=N+K: GO TO 9510
 9900 LET L=(256*PEEK 23769)+PEEK 23768: INPUT N: INVERSE 1: PRINT L;"  TO  ";L+N
 9910 FOR K=L TO L+N: PRINT CHR$ (PEEK K);: NEXT K: INVERSE 0: STOP 
 9950 LET L=(256*PEEK 23630)+PEEK 23629: INPUT N: PRINT L;"  TO  ";L+N
 9960 FOR K=L TO L+N: PRINT CHR$ (PEEK K);: NEXT K: INVERSE 0: STOP 
 9980 LET S$(1,1)=S$(1,1): GO TO 9950
    1 REM x.-\/ABS 0ABS x2\ \xxxxx: BRIGHT \O* CIRCLE \" VERIFY \ CLEAR " MOVE \ CLEAR " ERASE \ CLEAR " FLASH \ CLEAR " INVERSE \* VERIFY \#" VERIFY \ RESTORE >-! ERASE \\g LLIST LINE ]>-2 ERASE \\g LINE c] RESTORE >.! MOVE \\g LLIST LINE 4]>.\gCHR$ 4]>.2 MOVE \NOT c] FREE VERIFY  CHR$ J]: FLASH \ VERIFY 2CHR$ \' ]> 2 INVERSE \NOT c]: INVERSE \ VERIFY  LINE \' ] FREE VERIFY 0 IF \' ] FREE VERIFY : PAUSE \' ]>22 FLASH \CHR$ ]* CIRCLE \ FREE VERIFY  CHR$ r]6c* CIRCLE \ GO SUB Z" CIRCLE \CHR$ CONTINUE \<>* CIRCLE \6 NOT r]<> CLOSE #\CHR$ DATA \<>! CIRCLE \6 NOT r]<><>xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  800 POKE 23609,65: GO TO 9000
  900 PRINT FLASH 1;"   PRESS X TO RETURN TO MENU    "
  902 LET Z$=INKEY$: BEEP .2,8: IF Z$<>"X" THEN GO TO 902
  904 GO TO 9000
 1010 CLS : PRINT INVERSE 1;"****** LOAD OR SAVE FILES ******"
 1015 PRINT BRIGHT 1;'" PRESS 1 TO LOAD FILE "'" PRESS 2 TO SAVE FILE ": FOR L=1 TO 20: NEXT L
 1020 LET Z$=INKEY$: IF Z$<>"1" AND Z$<>"2" THEN GO TO 1020
 1030 LET M$="LOAD": IF Z$="2" THEN LET M$="SAV"
 1035 IF Z$="1" THEN GO SUB 1900
 1040 PRINT '"ENTER NAME OF FILE TO BE ";M$;"ED","(max 9 characters)  ";
 1050 DIM X$(10): INPUT N$: IF LEN N$>9 THEN GO TO 1050
 1060 PRINT BRIGHT 1;N$
 1070 PRINT '"START TAPE THEN PRESS ANY KEY": PAUSE 4E4
 1100 PRINT AT 19,0; FLASH 1;"    ";M$;"ING PARAMETERS FILE    ": GO SUB VAL Z$ *100 +1400
 1110 PRINT AT 19,0; FLASH 1;"     ";M$;"ING DATA FILE         ": GO SUB VAL Z$ *100 +1420     
 1120 PRINT AT 19,0; FLASH 1;"     ";M$;"ING FORMULA FILE      ": GO SUB VAL Z$ *100 +1440
 1200 PRINT AT 19,0; FLASH 1;"   TAPE OPERATIONS COMPLETED    "'"   PRESS X TO RETURN TO MENU    "
 1210 LET Z$=INKEY$: BEEP .5,8: IF Z$<>"X" THEN GO TO 1210
 1220 GO TO 9000
 1500 LET X$=N$+"P": LOAD X$ DATA A(): IF Y$="B" THEN GO TO 1503
 1501 LET C=A(1): LET C1=A(2): LET A=A(3): LET F=A(4): DIM F$(A,42)
 1502 DIM S$(C,C1*10+1): RETURN 
 1503 LET C2=A(1): LET C3=A(2): LET A=A(3): LET F=A(4): DIM F$(A,42)
 1504 DIM G$(C2,C3*10+1): RETURN 
 1520 LET X$=N$+"D": IF Y$="B" THEN GO TO 1522
 1521 LOAD X$ DATA S$(): RETURN 
 1522 LOAD X$ DATA G$(): RETURN 
 1540 LET X$=N$+"F": LOAD X$ DATA F$(): RETURN 
 1600 LET A(4)=F: LET X$=N$+"P": BEEP 2,8: SAVE X$ DATA A(): RETURN 
 1620 LET X$=N$+"D": BEEP 2,8: SAVE X$ DATA S$(): RETURN 
 1640 LET X$=N$+"F": BEEP 2,8: SAVE X$ DATA F$(): RETURN 
 1900 PRINT '"WHICH CONSOLIDATION MATRIX DO","YOU WANT FILLED A OR B         ";
 1910 LET Y$=INKEY$: IF Y$<>"A" AND Y$<>"B" THEN GO TO 1910
 1920 PRINT INVERSE 1;Y$: RETURN 
 2000 REM VALIDATION
 2005 IF C=0 OR C1=0 THEN GO TO 2900
 2010 CLS : LET CVF=0
 2020 IF C=C2 AND C1=C3 THEN GO TO 2060
 2030 PRINT AT 10,0;"MODEL MATRICES ARE NOT SAME SIZE   PRESS X TO RETURN TO MENU    "
 2040 LET Z$=INKEY$: BEEP .2,8: IF Z$<>"X" THEN GO TO 2040
 2050 GO TO 9000
 2060 PRINT AT 10,0; FLASH 1;"     VALIDATION IN PROGRESS     "
 2100 FOR L=1 TO C: LET S$(L,1)=S$(L,1): POKE 23768,PEEK 23629: POKE 23769,PEEK 23630: POKE 23772,C1: RANDOMIZE USR 23780: NEXT L
 2110 FOR L=1 TO C: LET G$(L,1)=G$(L,1): POKE 23768,PEEK 23629: POKE 23769,PEEK 23630: POKE 23772,C1: RANDOMIZE USR 23780: NEXT L
 2400 FOR L=1 TO C: FOR K=1 TO C1: LET Z=K*10-9
 2410 IF S$(L,Z)=G$(L,Z) OR CODE S$(L,Z) AND CODE G$(L,Z)>98 THEN GO TO 2490
 2420 PRINT "MATRICES INCOMPATIBLE AT ";L;",";K: LET CVF=1
 2490 NEXT K: NEXT L
 2500 PRINT AT 10,0; FLASH 1;"      VALIDATION COMPLETE       ": GO TO 900
 2900 CLS : PRINT AT 10,0; FLASH 1;"  ONE OF THE MATRICES IS EMPTY        PRESS X TO CONTINUE       "
 2910 LET Z$=INKEY$: BEEP .5,8: IF Z$<>"X" THEN GO TO 2910
 2920 GO TO 9000
 3000 REM ADDITION
 3010 CLS 
 3015 IF CVF=1 THEN GO TO 3800
 3020 PRINT AT 10,0; FLASH 1;"     ADDITION IN PROGRESS       "
 3100 FOR L=1 TO C: FOR K=1 TO C1: LET Z=K*10-9
 3110 IF S$(L,Z)=" " THEN GO TO 3150
 3120 LET S$(L,Z+1 TO K*10)=STR$ (VAL S$(L,Z+1 TO K*10)+VAL G$(L,Z+1 TO K*10))
 3140 IF CODE S$(L,Z)=99 THEN LET S$(L,Z)=CHR$ 32
 3150 NEXT K: NEXT L
 3200 PRINT AT 10,0; FLASH 1;"     CONSOLIDATION COMPLETE     ": GO TO 900
 3800 PRINT AT 10,0; FLASH 1;"MATRICES NOT CORRECTLY VALIDATED": GO TO 900
 4000 REM SUBTRACTION
 4010 CLS 
 4015 IF CVF=1 THEN GO TO 3800
 4020 PRINT AT 10,0; FLASH 1;"     SUBTRACTION IN PROGRESS    "
 4100 FOR L=1 TO C: FOR K=1 TO C1: LET Z=K*10-9
 4110 IF S$(L,Z)=" " THEN GO TO 3150
 4120 LET S$(L,Z+1 TO K*10)=STR$ (VAL S$(L,Z+1 TO K*10)-VAL G$(L,Z+1 TO K*10))
 4140 IF CODE S$(L,Z)=99 THEN LET S$(L,Z)=CHR$ 32
 4150 NEXT K: NEXT L
 4200 GO TO 3200
 9000 REM MAIN MENU
 9010 CLS : PRINT TAB 8; INVERSE 1;"SAXON COMPUTING"'"******* FLEXICON OPTIONS *******"
 9020 PRINT BRIGHT 1;''" Press 1 to LOAD OR SAVE A FILE "''" Press 2 to VALIDATE MODELS     "''" Press 3 to ADD MODELS          "''" Press 4 to SUBTRACT MODELS     "
 9030 LET Z$=INKEY$: IF CODE Z$<49 OR CODE Z$>52 THEN GO TO 9030
 9040 GO TO VAL Z$*1000
 9500 INPUT N
 9510 FOR K=0 TO 19: PRINT K+N;"  ";CHR$ PEEK (K+N): NEXT K: STOP : LET N=N+K: GO TO 9510
 9900 LET L=(256*PEEK 23769)+PEEK 23768: INPUT N: INVERSE 1: PRINT L;"  TO  ";L+N
 9910 FOR K=L TO L+N: PRINT CHR$ (PEEK K);: NEXT K: INVERSE 0: STOP 
 9950 LET L=(256*PEEK 23630)+PEEK 23629: INPUT N: PRINT L;"  TO  ";L+N
 9960 FOR K=L TO L+N: PRINT CHR$ (PEEK K);: NEXT K: INVERSE 0: STOP 
 9980 LET S$(1,1)=S$(1,1): GO TO 9950

Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.

People

No people associated with this content.

Scroll to Top