PASS2

Pass 2: constants, variable routines, backpatching, header and report. Each section's comment stands above it, each line's comments beside it; point at a name for its meaning; line numbers after GOTO, GOSUB and THEN are links.

Sections (38)
  1. 10 DECLARATIONS: INTEGER VARIABLES, ARRAYS AND THE COMMON BLOCK
  2. 200 PASS 2 OF THE COMPILER
  3. 320 COLLECT A PAIR (LATEST REFERENCE, TARGET) FOR THE DATA CHAIN AND EVERY LINE SYMBOL
  4. 450 SORT THE LINE PAIRS BY LINE NUMBER (A SHELL SORT WITH AN ODD GAP IN PAIRS); THE DATA PAIR
  5. 570 LOOK UP EACH LINE IN THE LINE NUMBER FILE (NUMBER AND ADDRESS OF EVERY LINE, IN ORDER), SO
  6. 740 FUNCTIONS
  7. 900 REPORT WHERE THE REFERENCE AT R4 IS (A FATAL ERROR); PAUSE IF ASKED
  8. 1060 ANY FATAL ERROR ENDS THE COMPILATION HERE
  9. 1090 THE CONSTANT POOL, WRITTEN AFTER THE CODE
  10. 1280 COMMON ALLOCATION IN DECLARATION ORDER FROM THE START OF THE COMMON BLOCK
  11. 1500 SIZE OF THE ROUTINE AREA
  12. 1720 LOCAL VARIABLES START AFTER THE ROUTINES, OR AT THE VARIABLES ADDRESS ASKED FOR
  13. 1780 THE DISPATCHERS THE ROUTINES JUMP TO
  14. 1850 THE ROUTINES AND THE LOCAL VARIABLES, IN THREE PASSES OVER THE SYMBOL TABLE
  15. 2060 A NUMERIC VARIABLE'S ROUTINE
  16. 2370 A STRING VARIABLE'S ROUTINE
  17. 2500 ENTRY: A PAIR (LATEST REFERENCE, ROUTINE ADDRESS) AND SEC, LDA #$18
  18. 2700 ENTRY: LDY #HIGH BYTE, LDA #LOW BYTE OF UF
  19. 2780 AN ARRAY'S ROUTINE
  20. 3000 THE END OF EACH PASS
  21. 3080 BACKPATCHING
  22. 3660 THE HEADER, WRITTEN OVER THE 24 BYTES RESERVED AT THE START OF THE FILE
  23. 3960 THE COMPILATION INFORMATION AND LINE NUMBER REFERENCE TABLE, IF ASKED FOR
  24. 4440 THE END: PUT BACK THE SIX BYTES OF DOS THAT PASS 0 CHANGED
  25. 4600 ADD R9 TO RL()
  26. 4700 ENTRY
  27. 4800 WRITING
  28. 5000 FIND THE LINE THAT HOLDS ADDRESS R4
  29. 5100 AT A VARIABLE REFERENCE IN THE FILE
  30. 5200 AT A CHAINED WORD IN THE FILE
  31. 5300 READ A WORD (LOW BYTE FIRST) INTO R3; 5300 RETURNS IT AS A STORED VALUE (-32767)
  32. 5500 POSITION THE OBJECT FILE FOR READING AT FO
  33. 5600 READ A BYTE INTO OW
  34. 5640 TOO LONG: THE PROGRAM, ITS VARIABLES OR THE REFERENCE LIST DO NOT FIT
  35. 5660 COMPILATION TERMINATED: DELETE THE OBJECT FILE
  36. 5800 REPORT A FATAL ERROR: END THE DIRECT FILE INPUT OR OUTPUT FIRST
  37. 5900 THE MOTOR SWITCHES OF THE SLOT DOS USED LAST
  38. 6000 STOP THE MOTOR AND CLOSE ALL FILES

10DECLARATIONS: INTEGER VARIABLES, ARRAYS AND THE COMMON BLOCK

10REM ! INTEGER MN,EL,SC

INTEGER VARIABLES

EL IS LIBRARY ROUTINE ($0947) THAT RESETS THE STACK, DROPPING EVERY PENDING GOSUB AND FOR, AND RESETS THE DATA POINTER; CALLED AFTER AN ERROR

MN IS DRIVE MOTOR-OFF SWITCH FOR THE BOOT SLOT

SC IS 1 IF THE SOURCE AND OBJECT FILES ARE ON THE BOOT DRIVE (MOTOR KEPT ON), ELSE 0

SC() IS SYMBOL TABLE: CHAIN HEADS, THEN ENTRIES LINKED THROUGH THEIR FIRST WORD

20REM ! INTEGER P8,N1,OO,O4

INTEGER VARIABLES

N1 IS RESUME/DEBUG CODE OPTION (1 = YES)

O4 IS COMPILATION LISTING OPTION (1 = YES)

OO IS PAUSE ON ERRORS OPTION (1 = YES)

P8 IS INTEGER ARITHMETIC OPTION (1 = YES)

30REM ! INTEGER QB,KV,WS,FC,C3

INTEGER VARIABLES

C3 IS COMMON KIND: -1 NONE, 0 DEFINE, 255 USE

FC IS 1 ONCE A FATAL ERROR HAS BEEN REPORTED (NO MORE CODE IS WRITTEN)

KV IS ADDRESS OF THE FIVE PACKED BYTES LEFT BY THE USR ROUTINE ($0371)

QB IS ADDRESS OF THE ROUTINE THAT READS ONE BYTE FROM THE OPEN FILE INTO IX ($037E)

WS IS ADDRESS OF THE ROUTINE THAT WRITES THE BYTE IN IX TO THE OPEN FILE ($0387)

40REM ! INTEGER VC,LB,CD,AK,L1,CY,LH

INTEGER VARIABLES

AK IS ADDRESS BEING COUNTED (COMMON ALLOCATION), SIZE OF THE ROUTINE AREA, START OF THE PAGE BEING PATCHED

CD IS START OF THE COMMON BLOCK (THE PROGRAM START BEFORE COMMON MOVED IT)

CY IS COMMON PASS (0 NUMBERS, 1 STRINGS); ALSO AN OPERATION OR DIMENSION INDEX

L1 IS SCRATCH: A LINE NUMBER, AN ELEMENT SIZE, AN OPERATION MASK

LB IS LIBRARY ADDRESS, STORED AS ADDRESS-32767

LH IS NUMBER OF SOURCE LINES READ

VC IS VARIABLES ADDRESS ASKED FOR, AS ADDRESS-32767, OR -32767 FOR END OF PROGRAM

50REM ! INTEGER R4,K8,GD,NR,DW

INTEGER VARIABLES

DW IS DOS STATE BYTE AT $AA52: POKED BEFORE EACH DIRECT FILE READ OR WRITE

GD IS GAP OF THE SORT; ALSO A POWER OF TWO

K8 IS LOOP INDEX; ALSO THE INDEX IN RL()

NR IS NUMBER OF VALUES IN RL()

R4 IS ADDRESS OF A REFERENCE TO REPORT

60REM ! INTEGER EU,HW,NG,NK,L8,NU,MX,LQ,OH,UV,R9,HD

INTEGER VARIABLES

EU IS SYMBOL TABLE ENTRY BEING WORKED ON

HD IS HIGHEST OPERATION OF A VARIABLE ROUTINE (-1 FOR NONE); ALSO AN INDEX IN THE SORT

HW IS LAST CHAIN HEAD IN SC(); ENTRIES ARE ALLOCATED ABOVE IT

L8 IS CHAIN INDEX; ALSO A TYPE CODE

LQ IS ADDRESS OF THE ROUTINE THAT LISTS THE TOKENIZED LINE IN THE INPUT BUFFER ($038D)

MX IS DRIVE MOTOR-ON SWITCH FOR THE BOOT SLOT ($C089+SLOT*16), TOUCHED TO KEEP THE DRIVE SPINNING

NG IS NUMBER OF CONSTANT HASH CHAINS (32)

NK IS NUMBER OF LINE NUMBER HASH CHAINS (32)

NU IS NUMBER OF VARIABLE HASH CHAINS IN THE SYMBOL TABLE (32)

OH IS INTEGER CONSTANTS OPTION (1 = YES)

R9 IS VALUE TO ADD TO RL()

UV IS ADDRESS OF THE USR ROUTINE THAT PACKS A NUMBER INTO FIVE BYTES ($0377)

70REM ! INTEGER T3,VO,VZ,LM

INTEGER VARIABLES

LM IS LENGTH OF THE RUNTIME LIBRARY IN BYTES (4013)

T3 IS TYPE CODE: -3 REAL, -2 STRING, -1 INTEGER, 19-21 ARRAYS

VO IS FIRST VARIABLE CHAIN HEAD IN SC() (9; 1-4 HOLD FN AND LINE SYMBOLS, 5-8 TEMPORARIES)

VZ IS TYPE CODE AS STORED (50 HIGHER FOR COMMON, 47/49 FOR A REAL/INTEGER CONSTANT)

80REM ! INTEGER OW,DG,CP,OU,IX

INTEGER VARIABLES

CP IS ADDRESS OF THE LAST BYTE OF CODE

DG IS WHICH DISPATCHER: 0 REAL, 1 STRING, 2 INTEGER, 3-5 REAL, STRING AND INTEGER ARRAYS, 6-10 LOOP STARTS AND NEXT

IX IS ADDRESS OF THE ONE-BYTE TRANSFER CELL FOR QB AND WS ($0376)

OU IS OPERATION NUMBER READ AT A REFERENCE

OW IS BYTE TO WRITE TO THE OBJECT FILE (OR JUST READ)

90REM ! INTEGER PC,ED,NI,CC,Q9,UR

INTEGER VARIABLES

CC IS ADDRESS OF THE LINK WORD OF THE LAST DATA BLOCK (DATA BLOCKS ARE CHAINED)

ED IS OBJECT FILE BASE: FILE POSITION = PC - ED (THE FILE STARTS WITH THE BSAVE HEADER)

NI IS SCRATCH: COUNT OF LINE NUMBER RECORDS READ, THE PASS OVER THE SYMBOLS (1 NUMBERS, 2 ARRAYS, 3 STRINGS), A KEY

PC IS ADDRESS OF THE NEXT OBJECT CODE BYTE, AS ADDRESS-32767

Q9 IS SIZE OF RL() (5900 VALUES)

UR IS PROGRAM START, STORED AS ADDRESS-32767; MOVED UP BY COMMON DECLARATIONS

100REM ! INTEGER L,KX,QF,DP(5,1),SC(5350),GG(1),RL(5900),DN(10,1)

INTEGER VARIABLES

DN() IS DISPATCHER ADDRESSES: DN(I,0) LOW BYTE, DN(I,1) HIGH BYTE

DP() IS DOS PATCH TABLE: DP(I,0) ADDRESS (AS A SIGNED WORD, ADDRESS-65536), DP(I,1) ORIGINAL BYTE

GG() IS GG(0) = LAST INDEX OF THE LINE AND FUNCTION PAIRS IN RL(), GG(1) = LAST INDEX OF THE NUMERIC ROUTINE GROUPS

KX IS FIRST CONSTANT CHAIN HEAD IN SC()

L IS FIRST LINE NUMBER CHAIN HEAD IN SC()

QF IS PREVIOUS ENTRY (FOR UNLINKING); ALSO THE END OF THE CODE

RL() IS REFERENCE LIST: FOR EACH LINE, FUNCTION AND DATA CHAIN A PAIR (LATEST REFERENCE, TARGET); FOR EACH NUMERIC VARIABLE OR CONSTANT ITS LATEST REFERENCE, STORAGE ADDRESS, ENTRY COUNT (NEGATIVE FOR AN INTEGER) AND ROUTINE ENTRIES; FOR EACH STRING VARIABLE OR ARRAY ITS LATEST REFERENCE AND ROUTINE ADDRESS

110REM ! USECOMMON NU,NG,NK,VO,KX,L,HW,MX,MN,DW,EL,LM,UV,KV,QB,WS,IX,LQ,LB,UR,VC,PC,LH,CD,CC,ED,SC,O4,OO,N1,P8,OH,FC,C3,DP(5,1),SC(5350),BP$,DI$,OP$,CO$,RV$,WO$,SI$,OD$,LN$,DN$,SB$,OO$

COMMON BLOCK, IN THE ORDER IT IS LAID OUT: NUMBERS FIRST, THEN STRINGS. THE PASSES SHARE IT, SO EVERY PASS DECLARES IT THE SAME WAY

BP$ IS TWO BELLS, SOUNDED BEFORE EACH ERROR MESSAGE

CO$ IS DOS CLOSE COMMAND

DI$ IS CONTROL-D, THE DOS COMMAND PREFIX

DN$ IS SLOT AND DRIVE OF THE BOOT DRIVE (",S6,D1")

LN$ IS NAME OF THE LINE NUMBER FILE ("CLINENUM")

OD$ IS OBJECT FILE NAME

OO$ IS SLOT AND DRIVE OF THE OBJECT FILE

OP$ IS DOS OPEN COMMAND

RV$ IS DOS READ COMMAND

SB$ IS SLOT AND DRIVE OF THE SOURCE FILE

SI$ IS SOURCE FILE NAME

WO$ IS DOS WRITE COMMAND

120DIM MM(5)

ARRAYS

MM() IS MEMORY LAYOUT FOR THE HEADER: MM(0) LOCALS START-1, (1) END OF NUMERIC LOCALS, (2) END OF STRING LOCALS, (3) COMMON START-1, (4) END OF NUMERIC COMMON, (5) END OF STRING COMMON

200PASS 2 OF THE COMPILER: CHECKS THAT EVERY LINE AND FUNCTION REFERRED TO EXISTS, WRITES THE CONSTANTS AND THE VARIABLE ROUTINES AFTER THE CODE, ALLOCATES COMMON AND LOCAL VARIABLES, REPLACES EVERY CHAINED REFERENCE IN THE OBJECT FILE BY ITS ADDRESS, WRITES THE HEADER AND REPORTS. PASS 1 LEFT EACH REFERENCE AS A LINK TO THE PREVIOUS ONE TO THE SAME SYMBOL, THE SYMBOL HOLDING THE LATEST

200Y$ = "COPYRIGHT(C)1981,MICROSOFT"

THE COPYRIGHT NOTICE; Y$ IS THEN THE ANSWER STRING

Y$ IS THE ANSWER TO THE REPORT QUESTION

210PRINT
220PRINT
230PRINT "*****BEGINNING PASS 2"
240PRINT
250PRINT
260DEF FN HB(X) = INT (X / 256)

FN HB(X): HIGH BYTE OF X

270DEF FN LO(X) = X - FN HB(X) * 256

FN LO(X): LOW BYTE OF X

280DEF FN UB(X) = X + 32767

FN UB(X): THE ADDRESS STORED AS X (X+32767)

290DEF FN BI(X) = X - 32767

FN BI(X): ADDRESS X AS IT IS STORED (X-32767)

300DEF FN TY(X) = X - (X > 21) * 50

FN TY(X): TYPE CODE X WITHOUT THE COMMON MARK (X-50 ABOVE 21)

310DEF FN LG(X) = INT ( LOG (X) / .693147181)

FN LG(X): THE NUMBER OF THE HIGHEST BIT SET IN X (FLOOR OF LOG2)

320COLLECT A PAIR (LATEST REFERENCE, TARGET) FOR THE DATA CHAIN AND EVERY LINE SYMBOL

320NR = 0

THE LIST IS EMPTY

330Q9 = 5900
340R9 = CC

THE DATA CHAIN FIRST: ITS LATEST LINK AND -32767 (0 AT THE END OF THE CHAIN)

350GOSUB 4600
360R9 = - 32767
370GOSUB 4600
380PRINT OP$;LN$;DN$

OPEN THE LINE NUMBER FILE AND READ IT FROM THE START

390PRINT RV$;LN$
400GOSUB 5900

KEEP THE DRIVE RUNNING

410FOR K8 = L TO HW

EVERY LINE NUMBER CHAIN

420EU = K8
430IF SC(EU) <> 0 THEN EU = SC(EU):R9 = SC(EU + 1): GOSUB 4600:R9 = SC(EU + 2): GOSUB 4600: GOTO 430

EACH LINE SYMBOL: ITS LATEST REFERENCE AND ITS NUMBER (-32767)

440NEXT K8

450SORT THE LINE PAIRS BY LINE NUMBER (A SHELL SORT WITH AN ODD GAP IN PAIRS); THE DATA PAIR STAYS FIRST

450IF NR = 2 THEN 740

ONLY THE DATA PAIR: NOTHING TO SORT OR LOOK UP

460IF NR = 4 THEN 570

ONE LINE: NO SORT

470GD = NR - 2

THE GAP STARTS AT HALF THE PAIRS ...

480GD = GD / 2
490IF GD / 2 <> INT (GD / 2) THEN GD = GD - 1

... ROUNDED TO WHOLE PAIRS ...

500IF GD / 4 = INT (GD / 4) THEN GD = GD - 2

... AND AN ODD NUMBER OF PAIRS

510FOR K8 = 2 TO NR - 2 - GD STEP 2

COMPARE EACH PAIR WITH THE ONE A GAP FURTHER, MOVING THE SMALLER BACK AS FAR AS IT GOES

520HD = K8
530L1 = HD + GD
540IF RL(HD + 1) > RL(L1 + 1) THEN NI = RL(HD):RL(HD) = RL(L1):RL(L1) = NI:NI = RL(HD + 1):RL(HD + 1) = RL(L1 + 1):RL(L1 + 1) = NI:HD = HD - GD: IF HD >= 2 THEN 530
550NEXT K8
560IF GD > 2 THEN 480

A SMALLER GAP, DOWN TO ONE PAIR

570LOOK UP EACH LINE IN THE LINE NUMBER FILE (NUMBER AND ADDRESS OF EVERY LINE, IN ORDER), SO THE PAIR'S TARGET BECOMES THE LINE'S ADDRESS

570NI = 0

NO RECORDS READ YET

580FOR K8 = 2 TO NR - 2 STEP 2

EACH LINE REFERRED TO, IN ORDER

590IF NI = LH THEN 660

THE WHOLE FILE READ WITHOUT FINDING IT

600GOSUB 5300

THE NEXT RECORD: THE LINE NUMBER ...

610L1 = R3

(KEPT)

620GOSUB 5300

... AND THE ADDRESS

630NI = NI + 1
640IF RL(K8 + 1) = L1 THEN RL(K8 + 1) = R3: GOTO 730

FOUND: THE PAIR'S TARGET IS THE LINE'S ADDRESS

650IF RL(K8 + 1) > L1 THEN 590

NOT YET REACHED: READ ON

660GOSUB 5800

PASSED: NO SUCH LINE

670PRINT "UNDEFINED LINE NUMBER "; FN UB(RL(K8 + 1))
680R4 = RL(K8)

THE LATEST REFERENCE TO IT

690GOSUB 900
700POKE DW,5

READ THE LINE NUMBER FILE FROM THE START AGAIN

710PRINT RV$;LN$;",B0"
720NI = 0
730NEXT K8

740FUNCTIONS: A PAIR (LATEST REFERENCE, ADDRESS OF THE BODY); A FUNCTION NEVER DEFINED IS AN ERROR

740FOR K8 = 1 TO 4

THE FOUR FUNCTION CHAINS

750EU = K8
760IF SC(EU) = 0 THEN 1060
770EU = SC(EU):R9 = SC(EU + 1)

EACH FUNCTION: ITS LATEST REFERENCE ...

780GOSUB 4600
790R9 = SC(EU + 3)

... AND THE ADDRESS OF ITS BODY

800IF - 32767 <> R9 THEN GOSUB 4600: GOTO 760
810GOSUB 5800
820PRINT "UNDEFINED FUNCTION ";
830NI = INT (SC(EU + 2) / 99)

THE NAME FROM ITS HASH, 99*FIRST CHARACTER+SECOND

840PRINT CHR$ (NI); CHR$ (SC(EU + 2) - NI * 99)
850R4 = SC(EU + 1)
860GOSUB 900
870GOTO 760

900REPORT WHERE THE REFERENCE AT R4 IS (A FATAL ERROR); PAUSE IF ASKED

900GOSUB 5000

THE LINE OF THE LATEST REFERENCE

910PRINT
920PRINT "REFERENCED LAST IN LINE ";LN
930FC = 1

A FATAL ERROR

940PRINT
950IF NOT OO THEN 1030

WITHOUT THE PAUSE OPTION, GO ON AT ONCE

960POKE MN,0

STOP THE DRIVE MOTOR WHILE WAITING

970POKE - 16368,0
980PRINT "TYPE CNTRL-C TO ABORT,"
990PRINT "ANY OTHER KEY TO CONTINUE:"
1000NI = PEEK ( - 16384): IF NI < 128 THEN 1000

WAIT FOR A KEY; CONTROL-C ENDS THE COMPILATION

1010POKE - 16368,0
1020IF NI = 131 THEN 5660
1030PRINT
1040PRINT
1050RETURN

1060ANY FATAL ERROR ENDS THE COMPILATION HERE

1060NEXT K8
1070GOSUB 6000

CLOSE THE LINE NUMBER FILE

1080IF FC THEN PRINT : PRINT : PRINT BP$;"*****FATAL ERRORS ENCOUNTERED": PRINT : PRINT : GOTO 5660

1090THE CONSTANT POOL, WRITTEN AFTER THE CODE: REAL CONSTANTS AS 5 BYTES, INTEGER CONSTANTS AS 2 (HIGH BYTE FIRST); AN INTEGER CONSTANT NEVER REFERRED TO IS DROPPED

1090CP = PC - 1

THE CODE ENDS HERE

1100PRINT OP$;OD$;OO$

OPEN THE OBJECT FILE ...

1110GOSUB 5900
1120T9 = ED

T9 IS SCRATCH: A SIZE, A PRODUCT, THE FILE BASE

1130PRINT WO$;OD$;",B";PC - T9

... AND POSITION IT AT ITS END

1140FOR L8 = KX TO L - 1

EVERY CONSTANT CHAIN

1150EU = L8
1160QF = EU

QF = THE PREVIOUS ENTRY

1170IF SC(EU) = 0 THEN 1270
1180EU = SC(EU): IF SC(EU + 3) >= 0 THEN FOR K8 = 3 TO 7:OW = SC(EU + K8): GOSUB 4880: NEXT K8:SC(EU + 3) = PC - 5:SC(EU + 4) = 47: GOTO 1160

A REAL CONSTANT (ITS FIRST BYTE, THE EXPONENT, IS NOT NEGATIVE): WRITE ITS 5 BYTES AND REPLACE THEM BY ITS ADDRESS AND THE MARK 47 (A REAL CONSTANT)

1190IF SC(EU + 1) = - 32767 THEN SC(QF) = SC(EU): GOTO 1170

AN INTEGER CONSTANT NEVER REFERRED TO: UNLINK IT

1200SC(EU + 3) = PC

ITS ADDRESS

1210OW = FN HB(SC(EU + 4))

THE VALUE, HIGH BYTE FIRST

1220GOSUB 4880
1230OW = FN LO(SC(EU + 4))
1240GOSUB 4880
1250SC(EU + 4) = 49

THE MARK 49: AN INTEGER CONSTANT

1260GOTO 1160
1270NEXT L8

1280COMMON ALLOCATION IN DECLARATION ORDER FROM THE START OF THE COMMON BLOCK: NUMBERS FIRST, THEN STRINGS

1280AK = CD

THE FIRST COMMON ADDRESS

1290CY = 0

NUMBERS FIRST

1300MM(3) = FN UB(AK - 1)

FOR THE HEADER: THE ADDRESS BEFORE THE COMMON BLOCK

1310QF = 0

THE LIST OF COMMON DECLARATIONS AT SC(0)

1320IF SC(QF) = 0 THEN 1480
1330QF = SC(QF):EU = SC(QF + 1):NI = SC(EU + 3)

THE NEXT DECLARATION: ITS SYMBOL AND TYPE

1340IF CY = 1 AND ( - 2 = NI OR NI = 20) THEN 1370

IN THE STRING PASS ONLY STRINGS ...

1350IF CY = 0 AND ( - 2 <> NI AND NI <> 20) THEN 1370

... IN THE NUMERIC PASS ONLY NUMBERS

1360GOTO 1320
1370SC(EU + 2) = AK

THE NAME HASH IS REPLACED BY THE STORAGE ADDRESS ...

1380SC(EU + 3) = NI + 50

... AND THE TYPE IS MARKED COMMON (+50)

1390L1 = 2

2 BYTES AN ELEMENT FOR AN INTEGER OR A STRING, 5 FOR A REAL

1400IF - 3 = NI OR NI = 19 THEN L1 = 5
1410IF NI < 0 THEN AK = AK + L1: GOTO 1320

A SIMPLE VARIABLE

1420T9 = 1

AN ARRAY: THE PRODUCT OF (DIMENSION+1)

1430FOR K8 = EU + 5 TO EU + 4 + SC(EU + 4)
1440T9 = (SC(K8) + 1) * T9
1450NEXT K8
1460AK = T9 * L1 + AK
1470GOTO 1320
1480IF CY = 0 THEN MM(4) = FN UB(AK - 1):CY = 1: GOTO 1310

THE END OF THE NUMERIC COMMON; NOW THE STRINGS

1490MM(5) = FN UB(AK - 1)

THE END OF THE STRING COMMON

1500SIZE OF THE ROUTINE AREA: A NUMERIC ROUTINE 3 BYTES PER OPERATION USED PLUS 6, A STRING ROUTINE 10, AN ARRAY ROUTINE 9 + 2 PER DIMENSION

1500AK = 0
1510FOR K8 = 5 TO L - 1

TEMPORARIES, VARIABLES AND CONSTANTS

1520EU = K8
1530IF SC(EU) = 0 THEN 1720
1540EU = SC(EU)
1550IF K8 >= 9 THEN 1600

VARIABLES AND CONSTANTS

1560L8 = SC(EU + 3)

A TEMPORARY: A STRING ONE (FREE OR IN USE) HAS A STRING ROUTINE

1570IF - 2 <> L8 AND - 5 <> L8 THEN 1630
1580AK = AK + 10

10 BYTES

1590GOTO 1530
1600L8 = FN TY(SC(EU + 4))

A VARIABLE OR CONSTANT: ITS TYPE

1610IF - 2 = L8 THEN 1580
1620IF L8 >= 19 AND L8 <= 21 THEN AK = AK + 9 + SC(EU + 5) * 2: GOTO 1530

AN ARRAY: 9 + 2 PER DIMENSION

1630NI = SC(EU + 2): IF NI = 0 THEN 1530

A NUMERIC ONE: NO OPERATION USED, NO ROUTINE

1640L1 = FN LG(NI)

3 BYTES FOR EACH OPERATION BIT SET IN THE MASK ...

1650GD = 2 ^ L1
1660FOR L8 = L1 TO 0 STEP - 1
1670IF NI >= GD THEN AK = AK + 3:NI = NI - GD
1680GD = GD / 2
1690NEXT L8
1700AK = AK + 6

... AND 6 FOR LDY, LDA, JMP

1710GOTO 1530

1720LOCAL VARIABLES START AFTER THE ROUTINES, OR AT THE VARIABLES ADDRESS ASKED FOR

1720NEXT K8
1730GG(0) = NR - 1

THE LINE AND FUNCTION PAIRS END HERE

1740K1 = FN UB(PC) + AK

THE LOCALS START AFTER THE ROUTINES ...

K1 IS NEXT FREE ADDRESS FOR LOCAL VARIABLES

1750PB = K1 - 1

... WHICH END THE PROGRAM

PB IS LAST ADDRESS OF THE PROGRAM (CODE, CONSTANTS AND ROUTINES)

1760IF - 32767 <> VC THEN K1 = FN UB(VC)

OR AT THE ADDRESS ASKED FOR

1770MM(0) = K1 - 1

FOR THE HEADER

1780THE DISPATCHERS THE ROUTINES JUMP TO: LIBRARY OFFSETS OF THE REAL, STRING AND INTEGER DISPATCHERS, THE THREE ARRAY DISPATCHERS, THE FOUR LOOP START ENTRIES AND NEXT

1780DATA 3937,1148,1283,782,785,788,478,482,475,485,558

$1764 REAL, $0C7F STRING, $0D06 INTEGER, $0B11 $0B14 $0B17 ARRAYS, $09E1 $09E5 $09DE $09E8 LOOP STARTS, $0A31 NEXT (FOR THE LIBRARY AT $0803)

1790T9 = FN UB(LB)

THE LIBRARY ADDRESS

1800FOR K8 = 0 TO 10
1810READ UF:UF = UF + T9

EACH OFFSET PLUS THE LIBRARY ADDRESS

UF IS STORAGE ADDRESS OF THE VARIABLE; ALSO A VALUE READ FROM THE DATA TABLE

1820DN(K8,0) = FN LO(UF)
1830DN(K8,1) = FN HB(UF)
1840NEXT K8

1850THE ROUTINES AND THE LOCAL VARIABLES, IN THREE PASSES OVER THE SYMBOL TABLE: 1 NUMERIC VARIABLES, TEMPORARIES AND CONSTANTS, 2 NUMERIC ARRAYS, 3 STRING VARIABLES, TEMPORARIES AND ARRAYS. STORAGE IS ALLOCATED IN THE SAME ORDER

1850FOR NI = 1 TO 3
1860FOR L8 = 5 TO L - 1

THE CHAINS FROM 5: TEMPORARIES, VARIABLES, CONSTANTS

1870EU = L8
1880IF NI = 2 AND L8 <= 8 THEN 3000

NO TEMPORARIES IN THE ARRAY PASS

1890IF NI <> 1 AND L8 >= KX THEN 3010

CONSTANTS ONLY IN THE FIRST PASS

1900IF SC(EU) = 0 THEN 3000
1910IF PEEK ( - 16384) = 131 THEN POKE - 16368,0: GOTO 5660

CONTROL-C ENDS THE COMPILATION

1920EU = SC(EU)
1930IF L8 >= 9 THEN VZ = SC(EU + 4): GOTO 1960

A VARIABLE OR CONSTANT: ITS TYPE IS IN ITS FOURTH WORD

1940VZ = SC(EU + 3)

A TEMPORARY: IN ITS THIRD WORD

1950IF - 4 >= VZ THEN VZ = VZ + 3

A TEMPORARY STILL MARKED IN USE (TYPE-3)

1960T3 = FN TY(VZ)

THE TYPE WITHOUT THE COMMON MARK

1970UF = K1

A LOCAL VARIABLE GOES AT THE NEXT FREE ADDRESS ...

1980IF VZ >= 47 THEN UF = FN UB(SC(EU + 3))

... A CONSTANT OR COMMON VARIABLE HAS ITS ADDRESS ALREADY

1990IF T3 > 0 THEN 2030

ARRAYS

2000IF - 2 = T3 AND NI = 3 THEN 2370

STRINGS IN THE THIRD PASS

2010IF ( - 1 = T3 OR - 3 = T3) AND NI = 1 THEN 2060

NUMBERS IN THE FIRST

2020GOTO 1900
2030IF T3 = 20 AND NI = 3 THEN 2780

STRING ARRAYS IN THE THIRD PASS, NUMERIC ARRAYS IN THE SECOND

2040IF (T3 = 19 OR T3 = 21) AND NI = 2 THEN 2780
2050GOTO 1900

2060A NUMERIC VARIABLE'S ROUTINE: FOR EACH OPERATION USED, HIGHEST FIRST, LDX #OPERATION, EACH BUT THE FIRST PRECEDED BY $AD (THE LDA ABSOLUTE OPCODE SWALLOWS THE NEXT LDX, SO EACH ENTRY FALLS THROUGH); THEN LDY #HIGH, LDA #LOW OF THE STORAGE ADDRESS AND JMP TO THE DISPATCHER. NO OPERATION USED: NO ROUTINE

2060R9 = SC(EU + 1)

THE GROUP IN RL(): THE LATEST REFERENCE ...

2070GOSUB 4600
2080R9 = FN BI(UF)

... THE STORAGE ADDRESS ...

2090GOSUB 4600
2100L1 = SC(EU + 2)

THE OPERATION MASK; HD = ITS HIGHEST BIT

2110HD = - 1
2120IF L1 <> 0 THEN HD = FN LG(L1)
2130R9 = HD + 2

... THE NUMBER OF ENTRIES+1 (NEGATIVE FOR AN INTEGER) ...

2140IF - 1 = T3 THEN R9 = - R9
2150GOSUB 4600
2160IF - 1 = HD THEN 2340
2170GD = 2 ^ HD

... AND FOR EACH OPERATION, HIGHEST FIRST, THE ADDRESS OF ITS ENTRY (-32767 IF NOT USED)

2180FOR CY = HD TO 0 STEP - 1
2190IF L1 < GD THEN R9 = - 32767: GOTO 2270
2200L1 = L1 - GD
2210IF CY <> HD THEN OW = 173: GOSUB 4880

$AD BEFORE EACH ENTRY BUT THE FIRST

2220R9 = PC
2230OW = 162

LDX #OPERATION

2240GOSUB 4880
2250OW = CY
2260GOSUB 4880
2270GOSUB 4600
2280GD = GD / 2
2290NEXT CY
2300GOSUB 2700

LDY #HIGH, LDA #LOW

2310DG = 0

THE REAL DISPATCHER, OR THE INTEGER ONE

2320IF - 1 = T3 THEN DG = 2

THE INTEGER DISPATCHER FOR AN INTEGER

2330GOSUB 4700

JMP

2340T9 = 2

A REAL TAKES 5 BYTES, AN INTEGER 2

2350IF - 3 = T3 THEN T9 = 5
2360GOTO 2960

2370A STRING VARIABLE'S ROUTINE: SEC, LDA #$18 (WHOSE $18 IS THE CLC OF THE SECOND ENTRY, 2 BYTES IN), LDY #HIGH, LDA #LOW, JMP TO THE STRING DISPATCHER: +0 LOADS, +2 STORES

2370GOSUB 2500

SEC, LDA #$18

2380GOSUB 2700

LDY #HIGH, LDA #LOW

2390DG = 1

JMP TO THE STRING DISPATCHER

2400GOSUB 4700
2410T9 = 2

A STRING VARIABLE IS A 2-BYTE POINTER

2420GOTO 2960

2500ENTRY: A PAIR (LATEST REFERENCE, ROUTINE ADDRESS) AND SEC, LDA #$18

2500R9 = SC(EU + 1)
2510GOSUB 4600
2520R9 = PC
2530GOSUB 4600
2540OW = 56

SEC

2550GOSUB 4880

LDA #

2560OW = 169
2570GOSUB 4880
2580OW = 24

$18, THE CLC

2590GOTO 4880

2700ENTRY: LDY #HIGH BYTE, LDA #LOW BYTE OF UF

2700OW = 160

LDY #

2710GOSUB 4880
2720OW = FN HB(UF)

HIGH BYTE

2730GOSUB 4880
2740OW = 169

LDA #

2750GOSUB 4880
2760OW = FN LO(UF)

LOW BYTE

2770GOTO 4880

2780AN ARRAY'S ROUTINE: SEC, LDA #$18, JSR TO THE ARRAY DISPATCHER, THEN THE ARRAY'S ADDRESS, ITS NUMBER OF DIMENSIONS AND EACH DIMENSION (10 IF IT WAS NEVER DIMENSIONED): +0 LOADS AN ELEMENT, +2 GIVES ITS ADDRESS

2780GOSUB 2500
2790OW = 32

JSR TO THE ARRAY DISPATCHER: 3 REAL, 4 STRING, 5 INTEGER

2800DG = T3 - 16
2810GOSUB 4720
2820T9 = 1

THE ARRAY'S ADDRESS

2830W = UF

W IS WORD TO WRITE

2840GOSUB 4840
2850OW = SC(EU + 5)

THE NUMBER OF DIMENSIONS

2860GOSUB 4880
2870FOR CY = 6 TO SC(EU + 5) + 5
2880W = SC(EU + CY)

EACH DIMENSION, OR 10

2890IF SC(EU + 6) = - 1 THEN W = 10
2900T9 = (W + 1) * T9

THE NUMBER OF ELEMENTS

2910GOSUB 4840
2920NEXT CY
2930L1 = 2

TIMES 2, OR 5 FOR A REAL ARRAY

2940IF T3 = 19 THEN L1 = 5
2950T9 = T9 * L1
2960IF VZ >= 47 THEN 1900

CONSTANTS AND COMMON VARIABLES TAKE NO LOCAL STORAGE

2970K1 = K1 + T9

THE NEXT FREE ADDRESS

2980IF K1 > 49152 THEN 5640

THE VARIABLES MUST END BELOW $C000

2990GOTO 1900

3000THE END OF EACH PASS

3000NEXT L8
3010IF NI = 1 THEN GG(1) = NR - 1

AFTER THE FIRST PASS: THE NUMERIC ROUTINE GROUPS END HERE

3020IF NI = 2 THEN MM(1) = K1 - 1

AFTER THE SECOND: THE NUMERIC LOCALS END HERE

3030NEXT NI
3040MM(2) = K1 - 1

THE STRING LOCALS END HERE

3050H4 = MM(2)

THE HIGHEST ADDRESS: THE END OF THE LOCALS, OF THE PROGRAM OR OF THE LIBRARY

H4 IS HIGHEST MEMORY ADDRESS USED

3060IF PB > H4 THEN H4 = PB
3070T9 = FN UB(LB) + LM - 1: IF T9 > H4 THEN H4 = T9

3080BACKPATCHING: WORK THROUGH THE OBJECT FILE 256 BYTES AT A TIME FROM THE END; IN EACH PAGE FOLLOW EVERY CHAIN WHOSE LATEST REFERENCE LIES IN IT, REPLACING EACH LINK BY THE TARGET. BECAUSE LINKS ALWAYS POINT BACK, EVERY REFERENCE IS REACHED IN ITS PAGE

3080QF = PC

KEEP THE END OF THE PROGRAM FOR THE HEADER

3090PC = - 32767

PC COUNTS FROM 0 NOW, SO THE PATCHES DO NOT LOOK TOO LONG

3100POKE DW,5

THE OBJECT FILE IS WRITTEN AGAIN

3110PRINT WO$;OD$
3120T9 = CP

THE FILE POSITION OF THE LAST BYTE OF CODE ...

3130T9 = T9 - ED
3140AK = FN HB(T9) * 256 + ED

... ROUNDED DOWN TO A 256-BYTE PAGE OF THE FILE: AK = THE ADDRESS AT THE PAGE'S START

3150POKE DW,5

END THE DIRECT OUTPUT

3160PRINT DI$
3170PRINT ".";

A DOT FOR EACH PAGE

3180IF RL(0) < AK THEN 3270

THE DATA CHAIN: WHILE ITS LATEST LINK IS IN THIS PAGE ...

3190FO = RL(0)

... READ THE LINK AND POSITION THE FILE OVER IT

FO IS FILE POSITION OF A REFERENCE

3200GOSUB 5200
3210W = RL(1)

THE LAST LINK GETS 0; EACH EARLIER ONE THE ADDRESS RIGHT AFTER THE LATER LINK: SO EACH DATA JMP GOES PAST ITS BLOCK AND EACH BLOCK'S LAST WORD POINTS AT THE NEXT BLOCK'S FIRST ITEM

3220IF - 32767 <> W THEN W = W + 2
3230GOSUB 4820

(WRITE IT)

3240RL(1) = RL(0)

THIS LINK IS THE TARGET OF THE NEXT ONE BACK

3250RL(0) = R3

FOLLOW THE CHAIN

3260GOTO 3180
3270IF GG(0) = 1 THEN 3310

NO LINE OR FUNCTION PAIRS

3280FOR K8 = 2 TO GG(0) STEP 2

EACH LINE AND FUNCTION PAIR: WHILE ITS LATEST REFERENCE IS IN THIS PAGE, READ THE LINK AND WRITE THE TARGET'S ADDRESS OVER IT (THE JMP OR JSR BEFORE IT IS ALREADY THERE)

3290IF RL(K8) >= AK THEN FO = RL(K8): GOSUB 5200:RL(K8) = R3:W = RL(K8 + 1): GOSUB 4820: GOTO 3290
3300NEXT K8
3310IF GG(1) = GG(0) THEN 3480

NO NUMERIC ROUTINES

3320K8 = GG(0) + 1

EACH NUMERIC VARIABLE OR CONSTANT

3330IF RL(K8) < AK THEN 3460

ITS LATEST REFERENCE IS BELOW THIS PAGE: THE NEXT GROUP

3340GOSUB 5100

READ THE OPERATION AND THE LINK

3350RL(K8) = R3

FOLLOW THE CHAIN

3360IF OU <= 13 THEN OW = 32:W = RL(K8 + 1 + ABS (RL(K8 + 2)) - OU): GOSUB 4800: GOTO 3330

OPERATIONS 0-13: JSR TO THE ROUTINE'S ENTRY FOR THE OPERATION

3370IF OU >= 21 AND OU <= 25 THEN OW = 32:DG = OU - 15: GOSUB 4720:W = RL(K8 + 1): GOSUB 4820: GOTO 3330

21-25: JSR TO THE LOOP START OR NEXT ENTRY, THEN THE VARIABLE'S ADDRESS IN THE TWO BYTES AFTER

3380OW = 173

20, AN AND / OR TEST: LDA OF THE VARIABLE ...

3390W = RL(K8 + 1)
3400GOSUB 4800
3410IF RL(K8 + 2) > 0 THEN 3330

... AND FOR AN INTEGER ORA OF ITS SECOND BYTE (THE THREE BYTES PASS 1 LEFT AFTER IT)

3420OW = 13
3430W = RL(K8 + 1) + 1
3440GOSUB 4800
3450GOTO 3330
3460K8 = K8 + 2 + ABS (RL(K8 + 2))

THE NEXT GROUP

3470IF GG(1) >= K8 THEN 3330
3480IF NR - 1 = GG(1) THEN 3600

NO STRING OR ARRAY ROUTINES

3490FOR K8 = GG(1) + 1 TO NR - 1 STEP 2

EACH STRING VARIABLE OR ARRAY: JSR TO ITS ROUTINE, +2 FOR OPERATION 1 (STORE, OR AN ELEMENT'S ADDRESS)

3500IF RL(K8) < AK THEN 3590
3510GOSUB 5100
3520RL(K8) = R3
3530OW = 32
3540W = RL(K8 + 1)
3550IF OU = 0 THEN 3570
3560W = W + 2
3570GOSUB 4800
3580GOTO 3500
3590NEXT K8
3600IF PEEK ( - 16384) = 131 THEN POKE - 16368,0: GOTO 5660

CONTROL-C ENDS THE COMPILATION

3610AK = AK - 256: IF AK >= ED THEN 3150

THE PAGE BEFORE, UNTIL THE START OF THE FILE

3620POKE DW,5

END THE DIRECT OUTPUT

3630PRINT DI$
3640PRINT
3650PRINT WO$;OD$;",B0"

WRITE AT THE START OF THE FILE

3660THE HEADER, WRITTEN OVER THE 24 BYTES RESERVED AT THE START OF THE FILE: THE BINARY FILE'S ADDRESS AND LENGTH, JSR TO THE LIBRARY, THE FIRST DATA ITEM, THE HIGHEST ADDRESS, THE COMMON AND LOCAL BOUNDS, THE COMMON FLAG

3660W = UR

THE BINARY FILE'S ADDRESS ...

3670GOSUB 4820
3680T9 = QF

... AND LENGTH

3690W = T9 - UR
3700GOSUB 4840
3710OW = 32

JSR TO THE LIBRARY, WHICH COPIES THE HEADER TO PAGE ZERO

3720W = LB
3730GOSUB 4800
3740W = RL(1)

THE FIRST DATA ITEM (0 IF THERE IS NO DATA)

3750IF - 32767 <> W THEN W = W + 2
3760GOSUB 4820
3770W = H4

THE HIGHEST ADDRESS USED

3780GOSUB 4840
3790FOR K8 = 3 TO 5

THE COMMON BOUNDS

3800W = MM(K8)
3810GOSUB 4840
3820NEXT K8
3830FOR K8 = 0 TO 2

THE LOCAL BOUNDS

3840W = MM(K8)
3850GOSUB 4840
3860NEXT K8
3870IF - 1 = C3 THEN C3 = 0

THE COMMON FLAG: 0 NONE OR DEFINE, 255 USE

3880OW = C3
3890GOSUB 4880
3900GOSUB 6000

CLOSE THE OBJECT FILE

3910PRINT
3920PRINT
3930PRINT "*****CODE GENERATION COMPLETE"
3940PRINT
3950PRINT

3960THE COMPILATION INFORMATION AND LINE NUMBER REFERENCE TABLE, IF ASKED FOR

3960PRINT "COMPILATION INFORMATION AND LINE NUMBER"
3970INPUT "REFERENCE TABLE? ";Y$

A LINE STARTING WITH CONTROL-D IS A DOS COMMAND: IT IS RUN, AND THE QUESTION IS ASKED AGAIN

3980IF LEN (Y$) = 0 THEN PRINT BP$;: GOTO 3960
3990IF ASC ( LEFT$ (Y$,1)) = 4 THEN PRINT : PRINT Y$: PRINT : GOTO 3960
4000Y$ = LEFT$ (Y$,1)
4010IF Y$ <> "Y" AND Y$ <> "N" THEN PRINT BP$;: GOTO 3960
4020IF Y$ = "N" THEN 4440

NO: SKIP THE REPORT

4030PRINT
4040PRINT
4050PRINT "SOURCE FILE: ";SI$
4060PRINT "OBJECT FILE: ";OD$
4070PRINT "LIBRARY OCCUPIES "; FN UB(LB);" - "; FN UB(LB) + LM - 1
4080PRINT "PROGRAM OCCUPIES "; FN UB(UR);" - ";PB
4090PRINT
4100IF CD = UR THEN PRINT "NO COMMON BLOCK": GOTO 4180

THE PROGRAM START WAS NOT MOVED: NO COMMON

4110IF C3 = 0 THEN PRINT "DEFINE ";: GOTO 4130
4120PRINT "USE ";
4130PRINT "COMMON BLOCK:"
4140IF MM(3) = MM(4) THEN PRINT "NO NUMERIC COMMON": GOTO 4160
4150PRINT "NUMERIC COMMON OCCUPIES ";MM(3) + 1;" - ";MM(4)
4160IF MM(4) = MM(5) THEN PRINT "NO STRING COMMON": GOTO 4180
4170PRINT "STRING COMMON OCCUPIES ";MM(4) + 1;" - ";MM(5)
4180PRINT
4190IF MM(0) = MM(2) THEN PRINT "NO LOCAL VARIABLES": GOTO 4210
4200PRINT "LOCAL VARIABLES OCCUPY ";MM(0) + 1;" - ";MM(2)
4210PRINT
4220PRINT "HIGHEST MEMORY LOCATION: ";H4
4230PRINT
4240PRINT
4250FOR K8 = 1 TO 27 STEP 13

THREE COLUMNS OF LINE NUMBER AND ADDRESS

4260HTAB K8
4270PRINT "LINE# ADDR";
4280NEXT K8
4290PRINT
4300PRINT
4310PRINT OP$;LN$;DN$

READ THE LINE NUMBER FILE FROM THE START

4320GOSUB 5900
4330PRINT RV$;LN$
4340NI = 0
4350FOR L8 = 1 TO 27 STEP 13

EACH RECORD: THE LINE NUMBER AND THE ADDRESS, THREE TO A ROW

4360GOSUB 5400
4370HTAB L8
4380PRINT " ";R3;
4390GOSUB 5400
4400HTAB L8 + 6
4410PRINT " ";R3;
4420NI = NI + 1: IF NI < LH THEN NEXT L8: PRINT : GOTO 4350

(THE NEXT COLUMN, OR A NEW ROW)

4430GOSUB 6000

4440THE END: PUT BACK THE SIX BYTES OF DOS THAT PASS 0 CHANGED

4440PRINT
4450PRINT
4460PRINT "*****COMPILATION COMPLETE"
4470PRINT
4480FOR K8 = 0 TO 5

THE ADDRESSES AND ORIGINAL BYTES PASS 0 SAVED IN DP()

4490POKE DP(K8,0),DP(K8,1)
4500NEXT K8
4510PRINT OP$;LN$;DN$

OPEN AND CLOSE THE LINE NUMBER FILE

4520PRINT CO$
4530END

4600ADD R9 TO RL()

4600RL(NR) = R9
4610NR = NR + 1: IF NR > Q9 THEN 5640

ONLY 5900 VALUES FIT: TOO LONG

4620RETURN

4700ENTRY: JMP TO DISPATCHER DG; ENTRY AT 4720: THE OPCODE IN OW, THEN THE DISPATCHER'S ADDRESS

4700OW = 76
4720GOSUB 4880
4730OW = DN(DG,0)
4740GOSUB 4880
4750OW = DN(DG,1)
4760GOTO 4880

4800WRITING: 4800 THE BYTE OW AND THE WORD W (A STORED ADDRESS); 4820 THE WORD W (A STORED ADDRESS); 4840 THE WORD W AS IT IS; 4880 THE BYTE OW

4800GOSUB 4880
4820W = FN UB(W)
4840OW = FN LO(W)
4850GOSUB 4880
4860OW = FN HB(W)
4880POKE DW,4

DOS'S OUTPUT STATE 4: EVERY CHARACTER GOES TO THE FILE; THE ROUTINE AT $0387 WRITES THE BYTE IN $0376

4890POKE IX,OW
4900CALL WS
4910GOSUB 5930
4920PC = PC + 1

COUNT THE BYTE

4930IF PC > 16384 THEN 5640

THE OBJECT MAY NOT PASS $BFFF

4940RETURN

5000FIND THE LINE THAT HOLDS ADDRESS R4: THE LAST LINE IN THE LINE NUMBER FILE THAT STARTS BELOW IT

5000POKE DW,5

READ THE LINE NUMBER FILE FROM THE START

5010PRINT RV$;LN$;",B0"
5020NI = 0
5030IF NI < LH THEN GOSUB 5400:U6 = R3: GOSUB 5300:NI = NI + 1: IF R3 < R4 THEN LN = U6: GOTO 5030

EACH RECORD UNTIL ONE STARTS AT OR ABOVE THE ADDRESS

LN IS NUMBER OF THE LINE THAT HOLDS IT

U6 IS A LINE NUMBER READ FROM THE LINE NUMBER FILE

5040RETURN

5100AT A VARIABLE REFERENCE IN THE FILE: READ ITS OPERATION BYTE INTO OU AND ITS LINK INTO R3, THEN POSITION THE FILE FOR WRITING THE CALL OVER THEM

5100T9 = ED

THE FILE POSITION OF THE REFERENCE

5110FO = RL(K8) - T9
5120GOSUB 5500
5130GOSUB 5600
5140OU = OW

OU = THE OPERATION

5150GOTO 5220

5200AT A CHAINED WORD IN THE FILE: READ THE LINK INTO R3, THEN POSITION THE FILE FOR WRITING OVER IT

5200FO = FO - ED

THE FILE POSITION

5210GOSUB 5500
5220GOSUB 5300
5230POKE DW,5

DOS WRITE WITH A BYTE POSITION, RELATIVE TO THE FILE'S START

5240PRINT WO$;OD$;",B";FO
5250GOSUB 5930
5260RETURN

5300READ A WORD (LOW BYTE FIRST) INTO R3; 5300 RETURNS IT AS A STORED VALUE (-32767)

5300GOSUB 5400
5310R3 = FN BI(R3)

R3 IS WORD JUST READ

5320RETURN
5400GOSUB 5600

LOW BYTE ...

5410R3 = OW
5420GOSUB 5600

... AND HIGH BYTE

5430T9 = 256:R3 = T9 * OW + R3
5440RETURN

5500POSITION THE OBJECT FILE FOR READING AT FO

5500POKE DW,5
5510PRINT RV$;OD$;",B";FO

DOS READ WITH A BYTE POSITION

5520GOSUB 5930
5530RETURN

5600READ A BYTE INTO OW

5600CALL QB

THE ROUTINE AT $037E READS A BYTE OF THE OPEN FILE INTO $0376

5610GOSUB 5930
5620OW = PEEK (IX)
5630RETURN

5640TOO LONG: THE PROGRAM, ITS VARIABLES OR THE REFERENCE LIST DO NOT FIT

5640GOSUB 5800
5650PRINT "TOO LONG"

5660COMPILATION TERMINATED: DELETE THE OBJECT FILE

5660GOSUB 6000
5670PRINT DI$;"DELETE";OD$;OO$

CLOSE AND DELETE THE UNFINISHED OBJECT FILE

5680PRINT
5690PRINT
5700PRINT "*****COMPILATION TERMINATED"
5710GOTO 4470

5800REPORT A FATAL ERROR: END THE DIRECT FILE INPUT OR OUTPUT FIRST

5800POKE DW,5

DOS'S OUTPUT STATE 5, AND A CONTROL-D ENDS THE DIRECT FILE INPUT OR OUTPUT

5810PRINT DI$
5820PRINT
5830PRINT
5840PRINT BP$;"*****FATAL ERROR"

TWO BELLS

5850RETURN

5900THE MOTOR SWITCHES OF THE SLOT DOS USED LAST

5900MX = - 16247 + PEEK (43626) * 16

$C089 + SLOT*16 ($AA6A IS THE SLOT DOS USED LAST)

5910MN = MX - 1
5930POKE MX,0

KEEP THE DRIVE RUNNING

5940RETURN

6000STOP THE MOTOR AND CLOSE ALL FILES

6000POKE MN,0

STOP THE MOTOR

6010POKE DW,5
6020PRINT CO$
6030RETURN

Variables

NAMETYPEDEFINEDCOMMONMEANING
AKINTEGER40ADDRESS BEING COUNTED (COMMON ALLOCATION), SIZE OF THE ROUTINE AREA, START OF THE PAGE BEING PATCHED
BP$STRING11037TWO BELLS, SOUNDED BEFORE EACH ERROR MESSAGE
C3INTEGER3034COMMON KIND: -1 NONE, 0 DEFINE, 255 USE
CCINTEGER9025ADDRESS OF THE LINK WORD OF THE LAST DATA BLOCK (DATA BLOCKS ARE CHAINED)
CDINTEGER4024START OF THE COMMON BLOCK (THE PROGRAM START BEFORE COMMON MOVED IT)
CO$STRING11040DOS CLOSE COMMAND
CPINTEGER80ADDRESS OF THE LAST BYTE OF CODE
CYINTEGER40COMMON PASS (0 NUMBERS, 1 STRINGS); ALSO AN OPERATION OR DIMENSION INDEX
DGINTEGER80WHICH DISPATCHER: 0 REAL, 1 STRING, 2 INTEGER, 3-5 REAL, STRING AND INTEGER ARRAYS, 6-10 LOOP STARTS AND NEXT
DI$STRING11038CONTROL-D, THE DOS COMMAND PREFIX
DN(10,1)INTEGER()100DISPATCHER ADDRESSES: DN(I,0) LOW BYTE, DN(I,1) HIGH BYTE
DN$STRING11046SLOT AND DRIVE OF THE BOOT DRIVE (",S6,D1")
DP(5,1)INTEGER()10035DOS PATCH TABLE: DP(I,0) ADDRESS (AS A SIGNED WORD, ADDRESS-65536), DP(I,1) ORIGINAL BYTE
DWINTEGER5010DOS STATE BYTE AT $AA52: POKED BEFORE EACH DIRECT FILE READ OR WRITE
EDINTEGER9026OBJECT FILE BASE: FILE POSITION = PC - ED (THE FILE STARTS WITH THE BSAVE HEADER)
ELINTEGER1011LIBRARY ROUTINE ($0947) THAT RESETS THE STACK, DROPPING EVERY PENDING GOSUB AND FOR, AND RESETS THE DATA POINTER; CALLED AFTER AN ERROR
EUINTEGER60SYMBOL TABLE ENTRY BEING WORKED ON
FCINTEGER30331 ONCE A FATAL ERROR HAS BEEN REPORTED (NO MORE CODE IS WRITTEN)
FOREAL3190FILE POSITION OF A REFERENCE
GDINTEGER50GAP OF THE SORT; ALSO A POWER OF TWO
GG(1)INTEGER()100GG(0) = LAST INDEX OF THE LINE AND FUNCTION PAIRS IN RL(), GG(1) = LAST INDEX OF THE NUMERIC ROUTINE GROUPS
H4REAL3050HIGHEST MEMORY ADDRESS USED
HDINTEGER60HIGHEST OPERATION OF A VARIABLE ROUTINE (-1 FOR NONE); ALSO AN INDEX IN THE SORT
HWINTEGER607LAST CHAIN HEAD IN SC(); ENTRIES ARE ALLOCATED ABOVE IT
IXINTEGER8017ADDRESS OF THE ONE-BYTE TRANSFER CELL FOR QB AND WS ($0376)
K1REAL1740NEXT FREE ADDRESS FOR LOCAL VARIABLES
K8INTEGER50LOOP INDEX; ALSO THE INDEX IN RL()
KVINTEGER3014ADDRESS OF THE FIVE PACKED BYTES LEFT BY THE USR ROUTINE ($0371)
KXINTEGER1005FIRST CONSTANT CHAIN HEAD IN SC()
LINTEGER1006FIRST LINE NUMBER CHAIN HEAD IN SC()
L1INTEGER40SCRATCH: A LINE NUMBER, AN ELEMENT SIZE, AN OPERATION MASK
L8INTEGER60CHAIN INDEX; ALSO A TYPE CODE
LBINTEGER4019LIBRARY ADDRESS, STORED AS ADDRESS-32767
LHINTEGER4023NUMBER OF SOURCE LINES READ
LMINTEGER7012LENGTH OF THE RUNTIME LIBRARY IN BYTES (4013)
LNREAL5030NUMBER OF THE LINE THAT HOLDS IT
LN$STRING11045NAME OF THE LINE NUMBER FILE ("CLINENUM")
LQINTEGER6018ADDRESS OF THE ROUTINE THAT LISTS THE TOKENIZED LINE IN THE INPUT BUFFER ($038D)
MM(5)REAL()120MEMORY LAYOUT FOR THE HEADER: MM(0) LOCALS START-1, (1) END OF NUMERIC LOCALS, (2) END OF STRING LOCALS, (3) COMMON START-1, (4) END OF NUMERIC COMMON, (5) END OF STRING COMMON
MNINTEGER109DRIVE MOTOR-OFF SWITCH FOR THE BOOT SLOT
MXINTEGER608DRIVE MOTOR-ON SWITCH FOR THE BOOT SLOT ($C089+SLOT*16), TOUCHED TO KEEP THE DRIVE SPINNING
N1INTEGER2030RESUME/DEBUG CODE OPTION (1 = YES)
NGINTEGER602NUMBER OF CONSTANT HASH CHAINS (32)
NIINTEGER90SCRATCH: COUNT OF LINE NUMBER RECORDS READ, THE PASS OVER THE SYMBOLS (1 NUMBERS, 2 ARRAYS, 3 STRINGS), A KEY
NKINTEGER603NUMBER OF LINE NUMBER HASH CHAINS (32)
NRINTEGER50NUMBER OF VALUES IN RL()
NUINTEGER601NUMBER OF VARIABLE HASH CHAINS IN THE SYMBOL TABLE (32)
O4INTEGER2028COMPILATION LISTING OPTION (1 = YES)
OD$STRING11044OBJECT FILE NAME
OHINTEGER6032INTEGER CONSTANTS OPTION (1 = YES)
OOINTEGER2029PAUSE ON ERRORS OPTION (1 = YES)
OO$STRING11048SLOT AND DRIVE OF THE OBJECT FILE
OP$STRING11039DOS OPEN COMMAND
OUINTEGER80OPERATION NUMBER READ AT A REFERENCE
OWINTEGER80BYTE TO WRITE TO THE OBJECT FILE (OR JUST READ)
P8INTEGER2031INTEGER ARITHMETIC OPTION (1 = YES)
PBREAL1750LAST ADDRESS OF THE PROGRAM (CODE, CONSTANTS AND ROUTINES)
PCINTEGER9022ADDRESS OF THE NEXT OBJECT CODE BYTE, AS ADDRESS-32767
Q9INTEGER90SIZE OF RL() (5900 VALUES)
QBINTEGER3015ADDRESS OF THE ROUTINE THAT READS ONE BYTE FROM THE OPEN FILE INTO IX ($037E)
QFINTEGER100PREVIOUS ENTRY (FOR UNLINKING); ALSO THE END OF THE CODE
R3REAL5310WORD JUST READ
R4INTEGER50ADDRESS OF A REFERENCE TO REPORT
R9INTEGER60VALUE TO ADD TO RL()
RL(5900)INTEGER()100REFERENCE LIST: FOR EACH LINE, FUNCTION AND DATA CHAIN A PAIR (LATEST REFERENCE, TARGET); FOR EACH NUMERIC VARIABLE OR CONSTANT ITS LATEST REFERENCE, STORAGE ADDRESS, ENTRY COUNT (NEGATIVE FOR AN INTEGER) AND ROUTINE ENTRIES; FOR EACH STRING VARIABLE OR ARRAY ITS LATEST REFERENCE AND ROUTINE ADDRESS
RV$STRING11041DOS READ COMMAND
SB$STRING11047SLOT AND DRIVE OF THE SOURCE FILE
SCINTEGER10271 IF THE SOURCE AND OBJECT FILES ARE ON THE BOOT DRIVE (MOTOR KEPT ON), ELSE 0
SC(5350)INTEGER()1036SYMBOL TABLE: CHAIN HEADS, THEN ENTRIES LINKED THROUGH THEIR FIRST WORD
SI$STRING11043SOURCE FILE NAME
T3INTEGER70TYPE CODE: -3 REAL, -2 STRING, -1 INTEGER, 19-21 ARRAYS
T9REAL1120SCRATCH: A SIZE, A PRODUCT, THE FILE BASE
U6REAL5030A LINE NUMBER READ FROM THE LINE NUMBER FILE
UFREAL1810STORAGE ADDRESS OF THE VARIABLE; ALSO A VALUE READ FROM THE DATA TABLE
URINTEGER9020PROGRAM START, STORED AS ADDRESS-32767; MOVED UP BY COMMON DECLARATIONS
UVINTEGER6013ADDRESS OF THE USR ROUTINE THAT PACKS A NUMBER INTO FIVE BYTES ($0377)
VCINTEGER4021VARIABLES ADDRESS ASKED FOR, AS ADDRESS-32767, OR -32767 FOR END OF PROGRAM
VOINTEGER704FIRST VARIABLE CHAIN HEAD IN SC() (9; 1-4 HOLD FN AND LINE SYMBOLS, 5-8 TEMPORARIES)
VZINTEGER70TYPE CODE AS STORED (50 HIGHER FOR COMMON, 47/49 FOR A REAL/INTEGER CONSTANT)
WREAL2830WORD TO WRITE
WO$STRING11042DOS WRITE COMMAND
WSINTEGER3016ADDRESS OF THE ROUTINE THAT WRITES THE BYTE IN IX TO THE OPEN FILE ($0387)
Y$STRING200THE ANSWER TO THE REPORT QUESTION
FN HBREALHIGH BYTE OF X
FN LOREALLOW BYTE OF X
FN UBREALTHE ADDRESS STORED AS X (X+32767)
FN BIREALADDRESS X AS IT IS STORED (X-32767)
FN TYREALTYPE CODE X WITHOUT THE COMMON MARK (X-50 ABOVE 21)
FN LGREALTHE NUMBER OF THE HIGHEST BIT SET IN X (FLOOR OF LOG2)
XREALPARAMETER OF THE DEF FN FUNCTIONS (EACH FUNCTION HAS ITS OWN)