Compass Compiler

Developer(s): John Richard Coffey
Date: 1988
Type: Program
Platform(s): TS 2068
Tags: Compiler

This program is a two-pass Z80 assembler and integer BASIC compiler combined into a single listing. The assembler section (lines 366–8999) reads REM-statement source lines, performs two passes to resolve forward label references stored in string array B$, and writes Z80 machine code bytes directly into memory using POKE, with the entire Z80 opcode table encoded as a single long REM statement at line 0. The compiler section (lines 9000–9999) translates a subset of Sinclair BASIC—including LET, IF, PRINT, LPRINT, GO TO, GO SUB, RETURN, DIM, POKE, BEEP, PLOT, PAUSE, OUT, BORDER, INVERSE, OVER, INK, PAPER, FLASH, and string handling—into Z80 machine code using DATA statements and a RESTORE/READ loop to emit opcode sequences. Line 9999 prints instructions explaining that the assembler can coexist with the compiler in memory, but the compiler requires the assembler to be deleted first.


Program Analysis

Overall Structure

The listing contains two largely independent tools sharing a single file. Lines 0–8999 implement a two-pass Z80 assembler (“JRC TWO PASS ASSEMBLER”), while lines 9000–9999 implement an integer BASIC compiler (“Integer Basic Compiler”), both credited to John Richard Coffey / JRC Software, 1984. Line 9999 explicitly documents that the assembler can run alongside the compiler but the compiler requires the assembler to be deleted first, due to variable and memory conflicts.

Line 0 — The Opcode Table

Line 0 is an enormous REM statement containing a concatenated string of every Z80 mnemonic (including CB- and ED-prefixed opcodes, IX/IY variants, and ED-block instructions). The assembler’s lookup routine at line 3000 searches this string using USR 31909 — it POKEs the search key into a fixed memory area starting at address 31898 and calls machine code to locate the mnemonic, returning an opcode number k. This is an elegant technique: the entire opcode table fits in one REM line and is searched by a machine-code routine rather than by slow BASIC string scanning.

Assembler: Two-Pass Design (Lines 366–8999)

The assembler uses the variable L cycling from -1 to 0 (line 369) to implement two passes. On pass 1 (L=-1), label addresses are collected but no output is generated for forward-reference arguments (line 3210 substitutes 0). On pass 2 (L=0), real values are resolved and both PRINT and LPRINT output occur (line 495).

Source code is embedded as REM statements in the BASIC program itself (lines 11–81 show the sample program). The GET subroutine (line 400) reads memory directly with PEEK starting at address G, skipping the BASIC line header and tokenized keyword bytes, and normalizes lowercase to uppercase (line 425).

Assembler: Label and Symbol Handling

Labels are defined with a backtick prefix (e.g., `LOOP) and processed in the LBL subroutine (lines 2400–2500). Symbols defined with LET pseudo-ops are stored in parallel arrays B$ (names, padded to 10 chars) and M (values), both dimensioned to 100 entries at line 367. The EEV subroutine (lines 3200–3350) handles expression evaluation and label substitution within operand strings, replacing label names with their numeric values via STR$ insertion.

Duplicate label resolution is handled at lines 8000–8500: when a label is redefined on pass 2, the earlier entry is updated and the duplicate entry is collapsed.

Assembler: Pseudo-Ops

Pseudo-opHandler linesFunction
ORG620–690Sets base address D and saves origin in E
NUM1000–1060Emits a 16-bit little-endian word
TXT1400–1460Emits a quoted ASCII string as bytes
TBL1600–1670Emits a table of N word values from subsequent source lines
RSV1800–1840Reserves N bytes (advances D without emitting)
BYT2200–2240Emits a single evaluated byte
LET2000–2110Defines a named numeric constant
STOP800–890Ends assembly, prints size and label table

Assembler: Opcode Encoding (Lines 392–398)

After finding opcode index k via USR 31909, the assembler encodes prefix bytes automatically. If k>255, a 0xCB prefix is POKEd; if k>511, a 0xED prefix is POKEd instead. The base opcode is then written as k MOD 256 (with double-subtraction handling both ranges). The ARG subroutine (lines 3600–3690) uses a second machine-code lookup at address 31130+k to determine the argument type (0=none, 1=byte, 2=relative branch, 4=word via DPK).

Compiler: Structure (Lines 9000–9999)

The compiler also uses a two-pass loop (FOR P=0 TO 1, lines 9005–9006). On pass 0, line/address pairs are accumulated in parallel string arrays X$ and Y$ (each pair encoded as two characters) by the STORE subroutine (lines 9550–9560), allowing forward GO TO/GO SUB branch targets to be resolved on pass 1. The variable LOC tracks the current machine code write address.

Three DEF FN functions are defined: FN P reads a 16-bit little-endian value from memory, FN H extracts the high byte, and FN L extracts the low byte. These are used throughout to decompose addresses for POKE sequences and DATA streams.

Compiler: POKE/DATA Idiom

The compiler’s most pervasive technique is using RESTORE to a specific line number followed by GO SUB POKE, where the POKE subroutine (lines 9530–9540) READs values from a DATA statement on the same line until it encounters -PI as a sentinel. This allows each BASIC statement handler to embed its Z80 opcode sequence inline. Some DATA values use FN L(...) and FN H(...) to compute address bytes dynamically (e.g., for DIM array addresses and string constant pointers).

Compiler: Expression Evaluation

Arithmetic expressions are evaluated by E1 (line 9240) and E2 (line 9230), which call ITEM and then loop on operators +, -, =, <, *, /, AND, and OR. Results are accumulated in the HL register pair in generated machine code, with DE used as a second operand via the E2 push/exchange pattern (line 9230: PUSH HL / E1 / EX DE,HL / POP HL). Division (line 9300) emits a 43-byte inline Z80 routine performing 16-bit integer division by repeated subtraction with shifts.

Compiler: String Handling

The STRING subroutine (lines 9620–9730) handles PRINT arguments including quoted literals (emitting LD A,n / RST 16 sequences), CHR$, INKEY$, STR$, AT, TAB, INVERSE, BRIGHT, OVER, PAPER, INK, FLASH, and the newline shorthand '. String variable assignment (LET a$=) is handled separately at lines 9900–9980, supporting both expression-based and literal string assignment via LDIR block copy.

Compiler: SOUND Statement

Lines 9740–9770 handle the SOUND keyword by rewriting the source string in-place, translating SOUND-specific delimiters into OUT 245, and OUT 246, sequences before falling through to the normal statement dispatcher. This is a simple textual macro expansion within the compiler’s input buffer A$.

Notable Bugs and Anomalies

  • Line 1630 calls GO SUB EEV+1 (i.e., address 3201), which skips the first character strip of the EEV subroutine — this appears intentional for the TBL context but could cause subtle parsing differences.
  • Line 3335 uses PI/NOT PI (which is PI/0) to force a division-by-zero error when an undefined label is encountered — a deliberate error-stopping technique.
  • In the compiler’s IF handler (line 9190), the false branch jumps to the next BASIC line number by embedding GO TO NLINE in the reconstructed source, which only works correctly if NLINE has been read ahead; this is set at lines 9045/9070.
  • Line 2240 uses GO TO ADV (a variable holding line number 1200) rather than GO SUB ADV, meaning after advancing D, execution falls into whatever follows line 1200 rather than returning — the RETURN at line 1220 will nevertheless return to the BYT caller’s caller, which works because BYT sets H=1 before calling.
  • The compiler’s SAVE line at 9998 saves with LINE 9998, causing auto-run from line 9998 on load, which re-presents the save/verify prompt.

Memory Map

AddressUsage
31898–31908Assembler mnemonic search buffer (POKEd by BASIC, searched by USR 31909)
31909Entry point of assembler opcode-search machine code routine
31130+kAssembler argument-type table indexed by opcode number k
31997Default start address for assembler source scan (G)
USR “A” + 2*nCompiler: 16-bit integer variable storage for variables A–Z (52 bytes)
ORG / LOCUser-specified or default (60000) machine code output area

Content

Appears On

Related Products

Integer compiler and two-pass assembler. Supports integer expression evaluation, multiple statements per line, one-dimension strings and the following commands: PRINT,...

Related Articles

Related Content

Image Gallery

Source Code

    0 REM NOPLD BC,eLD (BC),AINC BCINC BDEC BLD B,eRLCAEX AF,AFADD HL,BCLD A,(BC)DEC BCINC CDEC CLD C,eRRCHDJNZ eLD DE,eLD (DE),AINC DEINC DDEC DLD D,eRLAJR eADD HL,DELD A,(DE)DEC DEINC EDEC ELD E,eRRAJR NZ,eLD HL,eLD (e),HLINC HLINC HDEC HLD H,eDAAJR Z,eADD HL,HLLD HL,(e)DEC HLINC LDEC LLD L,eCPLJR NC,eLD SP,eLD (e),AINC SPINC (HL)DEC (HL)LD (HL),eSCFJR C,eADD HL,SPLD A,(e)DEC SPINC ADEC ALD A,eCCFLD B,BLD B,CLD B,DLD B,ELD B,HLD B,LLD B,(HL)LD B,ALD C,BLD C,CLD C,DLD C,ELD C,HLD C,LLD C,(HL)LD C,ALD D,BLD D,CLD D,DLD D,ELD D,HLD D,LLD D,(HL)LD D,ALD E,BLD E,CLD E,DLD E,ELD E,HLD E,LLD E,(HL)LD E,ALD H,BLD H,CLD H,DLD H,ELD H,HLD H,LLD H,(HL)LD H,ALD L,BLD L,CLD L,DLD L,ELD L,HLD L,LLD L,(HL)LD L,ALD (HL),BLD (HL),CLD (HL),DLD (HL),ELD (HL),HLD (HL),LHALTLD (HL),ALD A,BLD A,CLD A,DLD A,ELD A,HLD A,LLD A,(HL)LD A,AADD A,BADD A,CADD A,DADD A,EADD A,HADD A,LADD A,(HL)ADD A,AADC A,BADC A,CADC A,DADC A,EADC A,HADC A,LADC A,(HL)ADC A,ASUB BSUB CSUB DSUB ESUB HSUB LSUB (HL)SUB ASBC A,BSBC A,CSBC A,DSBC A,ESBC A,HSBC A,LSBC A,(HL)SBC A,AAND BAND CAND DAND EAND HAND LAND (HL)AND AXOR BXOR CXOR DXOR EXOR HXOR LXOR (HL)XOR AOR BOR COR DOR EOR HOR LOR (HL)OR ACP BCP CCP DCP ECP HCP LCP (HL)CP ARET NZPOP BCJP NZ,eJP eCALL NZ,ePUSH BCADD A,eRST 0RET ZRETJP Z,eCALL Z,eCALL eADC A,eRST 8RET NCPOP DEJP NC,eOUT (e),ACALL NC,ePUSH DESUB eRST 16RET CEXXJP C,eIN A,(e)CALL C,eIXSBC A,eRST 24RET POPOP HLJP PO,eEX (SP),HLCALL PO,ePUSH HLAND eRST 32RET PEJP (HL)JP PE,eEX DE,HLCALL PE,eXOR eRST 40RET PPOP AFJP P,eDICALL P,ePUSH AFOR eRST 48RET MLD SP,HLJP M,eEICALL M,eIYCP eRST 56RLC BRLC CRLC DRLC ERLC HRLC LRLC (HL)RLC ARRC BRRC CRRC DRRC ERRC HRRC LRRC (HL)RRC ARL BRL CRL DRL ERL HRL LRL (HL)RL ARR BRR CRR DRR ERR HRR LRR (HL)RR ASLA BSLA CSLA DSLA ESLA HSLA LSLA (HL)SLA ASRA BSRA CSRA DSRA ESRA HSRA LSRA (HL)SRA ASRL BSRL CSRL DSRL ESRL HSRL LSRL (HL)SRL ABIT 0,BBIT 0,CBIT 0,DBIT 0,EBIT 0,HBIT 0,LBIT 0,(HL)BIT 0,ABIT 1,BBIT 1,CBIT 1,DBIT 1,EBIT 1,HBIT 1,LBIT 1,(HL)BIT 1,ABIT 2,BBIT 2,CBIT 2,DBIT 2,EBIT 2,HBIT 2,LBIT 2,(HL)BIT 2,ABIT 3,BBIT 3,CBIT 3,DBIT 3,EBIT 3,HBIT 3,LBIT 3,(HL)BIT 3,ABIT 4,BBIT 4,CBIT 4,DBIT 4,EBIT 4,HBIT 4,LBIT 4,(HL)BIT 4,ABIT 5,BBIT 5,CBIT 5,DBIT 5,EBIT 5,HBIT 5,LBIT 5,(HL)BIT 5,ABIT 6,BBIT 6,CBIT 6,DBIT 6,EBIT 6,HBIT 6,LBIT 6,(HL)BIT 6,ABIT 7,BBIT 7,CBIT 7,DBIT 7,EBIT 7,HBIT 7,LBIT 7,(HL)BIT 7,ARES 0,BRES 0,CRES 0,DRES 0,ERES 0,HRES 0,LRES 0,(HL)RES 0,ARES 1,BRES 1,CRES 1,DRES 1,ERES 1,HRES 1,LRES 1,(HL)RES 1,ARES 2,BRES 2,CRES 2,DRES 2,ERES 2,HRES 2,LRES 2,(HL)RES 2,ARES 3,BRES 3,CRES 3,DRES 3,ERES 3,HRES 3,LRES 3,(HL)RES 3,ARES 4,BRES 4,CRES 4,DRES 4,ERES 4,HRES 4,LRES 4,(HL)RES 4,ARES 5,BRES 5,CRES 5,DRES 5,ERES 5,HRES 5,LRES 5,(HL)RES 5,ARES 6,BRES 6,CRES 6,DRES 6,ERES 6,HRES 6,LRES 6,(HL)RES 6,ARES 7,BRES 7,CRES 7,DRES 7,ERES 7,HRES 7,LRES 7,(HL)RES 7,ASET 0,BSET 0,CSET 0,DSET 0,ESET 0,HSET 0,LSET 0,(HL)SET 0,ASET 1,BSET 1,CSET 1,DSET 1,ESET 1,HSET 1,LSET 1,(HL)SET 1,ASET 2,BSET 2,CSET 2,DSET 2,ESET 2,HSET 2,LSET 2,(HL)SET 2,ASET 3,BSET 3,CSET 3,DSET 3,ESET 3,HSET 3,LSET 3,(HL)SET 3,ASET 4,BSET 4,CSET 4,DSET 4,ESET 4,HSET 4,LSET 4,(HL)SET 4,ASET 5,BSET 5,CSET 5,DSET 5,ESET 5,HSET 5,LSET 5,(HL)SET 5,ASET 6,BSET 6,CSET 6,DSET 6,ESET 6,HSET 6,LSET 6,(HL)SET 6,ASET 7,BSET 7,CSET 7,DSET 7,ESET 7,HSET 7,LSET 7,(HL)SET 7,AIN B,(C)OUT (C),BSBC HL,BCLD (e),BCNEGRETNIM 0LD I,AIN C,(C)OUT (C),CADC HL,BCLD BC,(e)RETILD R,AIN D,(C)OUT (C),DSBC HL,DELD (e),DEIM 1LL A,IIN E,(C)OUT (C),EADC HL,DELD DE,(e)IM 2LD A,RIN H,(C)OUT (C),HSBC HL,HLLD (e),HLRRDIN L,(C)OUT (C),LADC HL,HLLD HL,(e)RLDSBC HL,SPLD (e),SPIN A,(C)OUT (C),AADC HL,SPLD SP,(e)LDICPIINIOUTILDDCPDINDOUTDLDIRCPIRINIROTIRLDDRCPDRINDROTDRLD HL,eAMh!\k STICK PEEK  #>= PRINT RETURN ( SAVE LN >= STOP MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMN
    5 REM REM JRC TWO PASS                     ASSEMBLER                 \* 1984 BY JRC SOFTWARE                    po box 448                scottsburg, in 47170
   11 REM REM sample program;             INSTANT SCREEN INVERSE             
   15 REM ORG 60000
   21 REM LD HL,16384
   31 REM LD BC,6144
   41 REM `LOOP;LD A,(HL);XOR 255
   51 REM LD (HL),A;INC HL
   61 REM DEC BC;LD A,B;OR C
   71 REM JR NZ,LOOP
   81 REM RET
  366 REM STOP 
  367 DIM B$(100,10): DIM m(100)
  368 GO SUB 600
  369 FOR L=-1 TO 0
  370 LET G=31997: GO SUB GET
  375 GO SUB GET
  376 LET H=0
  377 GO SUB STP
  378 GO SUB NUM
  379 GO SUB TXT
  380 IF NOT LEN I$ THEN GO TO VAL "375"
  381 GO SUB TBL
  382 GO SUB RSV
  383 GO SUB LET
  384 IF CODE I$=CODE " LET " THEN GO TO VAL "375"
  385 GO SUB BYT
  386 GO SUB LBL
  387 IF H THEN GO TO 373+H+SGN LEN I$
  388 LET g$=i$: LET j$=""
  389: IF LEN g$ THEN IF g$(1)<>" " THEN LET j$=j$+CHR$ CODE g$: LET g$=g$(2 TO ): GO TO 389
  390 LET g$=g$(2 TO ): GO SUB rip
  391 IF LEN t$ THEN LET j$=j$+" "+t$: LET g$=g$(2 TO ): GO SUB rip:: IF LEN t$ THEN LET j$=j$+","+t$
  392 GO SUB fnd
  393 IF k>255 THEN POKE D,203
  394 IF k>511 THEN POKE D,237
  395 IF k>255 THEN GO SUB ADV
  396 POKE D,k-256*(k>255)-256*(k>511)
  397 GO SUB ADV
  398 GO SUB ARG
  399 GO TO 375
  400: LET I$="": IF PEEK g=32 THEN LET g=g+1: GO TO 400
  401 IF CHR$ PEEK G<>" REM " THEN GO TO VAL "410"
  405 LET G=G+1
  407 IF PEEK G<>13 THEN GO TO 405
  410 IF PEEK G=13 THEN GO TO 460
  420 IF PEEK G=CODE ";" OR PEEK g=CODE ":" THEN GO TO 470
  425 IF PEEK g>=CODE "a" AND PEEK g<=CODE "z" THEN POKE g,PEEK g-CODE "a"+CODE "A"
  430 LET I$=I$+CHR$ PEEK G
  440 LET G=G+1
  450 GO TO 410
  460 LET G=G+5
  470 LET G=G+1
  480 IF NOT LEN I$ THEN GO TO GET
  485 POKE 23692,99
  490 PRINT I$,D
  495 IF L THEN LPRINT I$,D
  500 RETURN 
  600 LET l=-1: LET d=0: LET g=31997: LET dpk=1030::: LET arg=3600: LET get=400: LET stp=800: LET num=1000: LET adv=1200: LET txt=1400: LET tbl=1600: LET rsv=1800: LET let=2000: LET byt=2200: LET lbl=2400: LET fnd=3000: LET eev=3200: LET rip=3400
  610 GO SUB get
  620 IF i$( TO 4)<>"ORG " THEN PRINT "NO ORG (NUMBER) AT BEGINNING": STOP 
  625 LET D=VAL I$(5 TO )
  630 LET c=0
  660 LET E=D
  690 RETURN 
  800 IF CODE I$<>CODE " STOP " THEN RETURN 
  820 IF NOT L THEN PRINT "THE MACHINE CODE TAKES ";D-E;" BYTES"
  830 IF L THEN LET D=E:
  840 NEXT L
  850 PRINT "LABEL","ADDRESS"
  860 IF C THEN FOR H=1 TO C
  870 IF C THEN PRINT B$(H),M(H)
  880 IF C THEN NEXT H
  890 STOP 
 1000 IF LEN I$<3 THEN RETURN 
 1001 IF I$( TO 3)<>"NUM" THEN RETURN 
 1010 LET H=1
 1020 GO SUB EEV
 1030 LET N=INT (VAL I$/256)
 1040 POKE D,VAL I$-N*256
 1050 GO SUB ADV
 1060 POKE D,N
 1200 LET D=D+1
 1220 RETURN 
 1400 IF CODE I$<>34 THEN RETURN 
 1410 LET H=1
 1420 LET I$=I$(2 TO )
 1430 IF NOT LEN I$ THEN RETURN 
 1440 POKE D,CODE I$
 1450 GO SUB ADV
 1460 GO TO 1420
 1600 IF (I$+"  ")( TO 3)<>"TBL" THEN RETURN 
 1610 FOR H=1 TO VAL I$(4 TO )
 1620 GO SUB GET
 1630 GO SUB EEV+1
 1640 GO SUB DPK
 1650 NEXT H
 1660 LET H=1
 1670 RETURN 
 1800 IF (I$+"  ")( TO 3)<>"RSV" THEN RETURN 
 1810 LET D=D+VAL I$(4 TO )
 1830 LET H=1
 1840 RETURN 
 2000 IF CODE I$<>CODE " LET " THEN RETURN 
 2010 LET H=1
 2020 IF NOT L THEN RETURN 
 2030 LET J$=""
 2040 LET I$=I$(2 TO )
 2050 IF CODE I$=CODE "=" THEN GO TO 2080
 2060 LET J$=J$+CHR$ CODE I$
 2070 GO TO 2040
 2080 LET C=C+1
 2090 LET B$(C)=J$
 2100 LET M(C)=VAL I$(2 TO )
 2110 GO TO 8000
 2200 IF (I$+"  ")( TO 3)<>"BYT" THEN RETURN 
 2210 GO SUB EEV
 2220 POKE D,VAL I$
 2230 LET H=1
 2240 GO TO ADV
 2400 IF CODE i$<>CODE "`" THEN RETURN 
 2410 LET i$=i$(2 TO ): LET J$=""
 2420 LET J$=J$+CHR$ (CODE I$)
 2430 LET I$=I$(2 TO )
 2440 IF I$>="A" THEN IF I$<="Z" THEN GO TO 2420
 2450 LET H=2
 2460 IF NOT L THEN RETURN 
 2470 LET C=C+1
 2480 LET B$(C)=J$
 2490 LET M(C)=D
 2500 GO TO 8000
 3000:: FOR U=31898 TO LEN J$+31897: POKE U,CODE J$(U-31897): NEXT U: POKE U,13: LET k=USR 31909
 3100 IF k=768 THEN PRINT "SYNTAX ERROR"'"THIS STATEMENT INCORRECT"'VAL ""
 3150 RETURN 
 3200 LET I$=I$(4 TO LEN I$)
 3210 IF L THEN LET I$="0"
 3220 IF L THEN RETURN 
 3230 FOR K=1 TO LEN I$
 3240 IF I$(K)>="A" AND I$(K)<="Z" THEN GO TO 3270
 3250 NEXT K
 3260 RETURN 
 3270 LET V=K
 3280 IF V=LEN I$ THEN GO TO 3320
 3290 IF I$(V+1)<"A" OR I$(V+1)>"Z" THEN GO TO 3320
 3300 LET V=V+1
 3310 GO TO 3280
 3320 FOR U=1 TO C
 3330 IF B$(U)<>I$(K TO V)+"          "( TO 10+k-v-1) THEN NEXT U
 3335 IF U>C THEN PRINT "ERROR:  ";I$(K TO V);" UNDEFINED";PI/NOT PI
 3340 LET I$=I$( TO K-1)+STR$ M(U)+I$(V+1 TO )
 3350 GO TO 3230
 3400 REM rip
 3410 LET t$=""
 3420 IF LEN g$ THEN IF g$(1)<>"," THEN LET t$=t$+CHR$ CODE g$: LET g$=g$(2 TO ): GO TO 3420
 3430 IF LEN t$<=2+(CODE t$=CODE "(")*2 THEN RETURN 
 3440 IF t$(1)="(" THEN LET i$=t$(2 TO LEN t$-1): LET t$="(e)"
 3450 IF t$(1)<>"(" THEN LET i$=t$: LET t$="e"
 3460 RETURN 
 3600 LET W=PEEK (31130+k)
 3610 IF NOT W THEN RETURN 
 3620 LET I$="   "+i$
 3630 GO SUB EEV
 3640 IF W=4 THEN GO TO DPK
 3650 IF W=1 THEN POKE D,VAL I$
 3660 IF W=1 THEN GO TO ADV
 3670 LET Y=VAL I$-d-(W=2)
 3680 IF NOT L THEN POKE D,Y+256*(Y<0)
 3690 GO TO ADV
 8000 FOR U=SGN PI TO C
 8100 IF B$(U)<>B$(C) THEN NEXT U
 8200 IF U=C THEN RETURN 
 8300 LET M(U)=M(C)
 8400 LET C=C-SGN PI
 8500 RETURN 
 8999 STOP                                  
 9000 REM RESET  1984 JRC SOFTWARE             Integer Basic Compiler          writtn by                   John Richard Coffey                 with thanks to         John M. Brown                                                                  JRC SOFTWARE                    po box 448                      Scottsburg, In                  47170
 9001: DIM s(26): LET M=0: LET MODE=PI: LET HIMEM=0
 9002 LET STRING=9620: POKE USR "A"+54,195: LET LTOT=0: LET ITEM2=9315: DIM X$(2000): DIM Y$(2000): LET CHOP=9490: LET FETCH=9500: LET CONS=9360: LET CONS2=9440: LET ITEM=9320: LET E1=9240: LET E2=9230: LET POKE=9530: LET BRANCH=9565: LET ADVANCE=9480: LET STATEMENT=9120: LET LINE=9050: LET STORE=9550
 9005 IF MODE THEN INPUT "WHERE DO YOU WANT TO PUT THE    MACHINE CODE"'''N: LET ORG=N: FOR P=0 TO 1: LET LOC=ORG
 9006 IF NOT MODE THEN POKE 23692,99: LET N=6E4: LET ORG=N: FOR P=0 TO 1: LET LOC=ORG
 9010 DEF FN P(A)=PEEK A+256*PEEK (A+1)
 9020 DEF FN H(A)=INT (A/256)
 9030 DEF FN L(A)=A-256*FN H(A)
 9040 LET NPROG=FN P(23635)+4
 9045 LET NLINE=PEEK (NPROG-3)+256*PEEK (NPROG-4)
 9050 LET PROG=NPROG:: REM LINE
 9060 LET NPROG=PROG+FN P(PROG-2)+4
 9065: GO SUB STORE
 9070 LET NLINE=PEEK (NPROG-3)+256*PEEK (NPROG-4)
 9080 IF NLINE>9E3 THEN GO SUB 9990: NEXT p: PRINT INVERSE 1; INK 4;"THE MACHINE CODE TAKES ";LOC-ORG;" BYTES": STOP 
 9090:: LET A$="": FOR L=PROG TO NPROG-6:: IF PEEK L=14 THEN LET L=L+5: GO TO 9110
 9095 IF PEEK L>=CODE "a" AND PEEK l<=CODE "z" THEN IF PEEK (l-1)=CODE " LET " OR PEEK (l+1)=CODE "$" THEN POKE l,PEEK l-CODE "a"+CODE "A"
 9100 LET A$=A$+CHR$ PEEK L
 9110 NEXT L: PRINT LOC;TAB 6;a$            : POKE 23692,99            
 9120:: IF NOT LEN A$ THEN GO TO LINE
 9123 IF A$(1)=":" THEN GO SUB CHOP
 9124 IF NOT LEN a$ THEN GO TO line
 9125: IF A$(1)=" REM " THEN GO TO LINE: REM STATEMENT
 9130 IF A$(1)=" STOP " OR A$(1)=" RETURN " THEN POKE LOC,201: GO SUB ADVANCE: GO TO LINE
 9135 IF A$(1)=" COPY " THEN RESTORE 9135: GO SUB chop: GO SUB poke: GO TO statement: DATA 205,2,10,-PI
 9140 IF A$(1)=" GO TO " THEN :: POKE LOC,195: GO TO BRANCH
 9145 IF A$(1)="}" THEN GO TO 9740
 9150 IF A$(1)=" GO SUB " THEN POKE LOC,205: GO TO BRANCH
 9160 IF CODE A$<>CODE " DIM " THEN GO TO 9170
 9161 GO SUB CHOP: LET S=1+CODE A$-CODE "A": GO SUB CHOP: GO SUB CHOP: GO SUB CHOP:: LET J=0
 9162 LET J=J*10+VAL CHR$ CODE A$: GO SUB CHOP: IF CODE A$<>CODE ")" THEN GO TO 9162
 9163 IF NOT P THEN LET S(S)=J
 9170 IF A$(1)=" POKE " THEN GO SUB E1:: GO SUB E2: POKE LOC,115: GO SUB ADVANCE: GO TO STATEMENT
 9172 IF A$(1)=" BEEP " THEN GO SUB E1: GO SUB E2: RESTORE 9172: GO SUB POKE: GO TO STATEMENT: DATA 235,1,60,0,9,197,229,213,205,233,48,193,205,233,48,239,1,5,56,193,205,233,48,193,205,233,48,239,3,56,205,54,4,-PI
 9174 IF A$(1)=" PLOT " THEN GO SUB E1: GO SUB E2: RESTORE 9174: GO SUB POKE: GO TO STATEMENT: DATA 67,77,205,62,38,-PI
 9175 IF A$(1)=" RANDOMIZE " THEN GO SUB E1:: RESTORE 9175: GO SUB POKE: GO TO STATEMENT: DATA 68,77,205,215,30,-PI
 9176 IF A$(1)=" CLS " THEN GO SUB chop: RESTORE 9176: GO SUB POKE: GO TO STATEMENT: DATA 205,234,8,-PI
 9179 IF A$(1)=" PAUSE " THEN GO SUB E1:: RESTORE 9179: GO SUB POKE: GO TO STATEMENT: DATA 68,77,205,233,48,205,235,31,-PI
 9180 IF A$(1)=" OUT " THEN GO SUB E1: GO SUB E2: RESTORE 9180: GO SUB POKE: GO TO STATEMENT: DATA 68,77,235,237,105,-PI
 9182 IF A$(1)=" RUN " THEN LET A$=" GO TO 1"+A$(2 TO ): GO TO STATEMENT
 9185 IF A$(1)=" INVERSE " OR A$(1)=" OVER " OR A$(1)="AT " OR A$(1)= "TAB " OR A$(1)=" BRIGHT " OR A$(1)=" PAPER " OR A$(1)=" INK " OR A$(1)=" FLASH " THEN GO SUB STRING: RESTORE  9185: GO SUB POKE: GO TO STATEMENT : DATA 215,42,143,92,34,141,92,-PI
 9187 IF A$(1)=" BORDER " THEN        GO SUB E1: RESTORE 9187       : GO SUB POKE                   : GO TO STATEMENT: DATA 125,      211,254
 9190 IF A$(1)=" IF " THEN GO SUB E1:: RESTORE 9190: GO SUB POKE: LET A$=" GO TO "+STR$ NLINE+":"+A$(2 TO ):: GO TO 9140: DATA 124,181,32,3,-PI
 9195 IF a$(1)=" LET " THEN IF a$(3)="$" THEN GO SUB 9900: GO TO 9210
 9200 IF A$(1)=" LET " THEN LET V=USR "A"+2*(CODE A$(2)-CODE "A")::: GO SUB CHOP: GO SUB CHOP: GO SUB E1: POKE LOC,34::: POKE LOC+1,FN L(V): POKE LOC+2,FN H(V): LET LOC=LOC+3:: GO TO STATEMENT
 9201: IF A$(1)<>" PRINT " AND a$(1)<>" LPRINT " THEN GO TO 9210
 9203 LET lprint=a$(1)=" LPRINT ": IF lprint THEN RESTORE 9203: GO SUB poke: DATA 33,59,92,203,206,-PI
 9204: GO SUB CHOP
 9205: IF LEN A$>=2 THEN IF A$(1 TO 2)=";:" THEN GO SUB CHOP: GO SUB CHOP: GO TO 9800
 9206: IF LEN A$=1 THEN IF A$(1)=";" THEN GO SUB CHOP: GO TO 9800
 9207: IF CODE A$=CODE ":" OR NOT LEN A$ THEN GO SUB CHOP: RESTORE 9207:    GO SUB POKE: GO TO 9800: DATA 62,13,215,42,141,92,34,143,92,-PI
 9208: IF CODE A$<>CODE ";" THEN GO SUB STRING:: POKE LOC,215: GO SUB ADVANCE: GO TO 9205
 9209 GO TO 9204
 9210: IF LEN A$ THEN IF A$(1)<>":" AND LEN A$ THEN GO SUB chop: GO TO 9210
 9220 LET A$=A$(2 TO ): GO TO STATEMENT*SGN LEN A$+LINE*NOT LEN A$    
 9230: POKE LOC,229: GO SUB ADVANCE: GO SUB E1: POKE LOC,235: GO SUB ADVANCE: POKE LOC,225: GO TO ADVANCE    : REM    E2                       
 9240: GO SUB ITEM: REM E1
 9250 IF NOT LEN A$ THEN RETURN 
 9251 LET LOOP=9250: IF A$(1)="+" THEN GO SUB ITEM2: POKE LOC,25: GO SUB ADVANCE: GO TO LOOP
 9260 IF A$(1)="-" THEN GO SUB ITEM2: POKE LOC,167: POKE LOC+1,237: POKE LOC+2,82: LET LOC=LOC+3: GO TO LOOP
 9270 IF A$(1)="=" THEN GO SUB ITEM2: RESTORE 9270: GO SUB POKE: GO TO LOOP: DATA 167,237,82,124,181,46,1,40,2,46,0,38,0,-PI
 9280 IF A$(1)="<" THEN GO SUB ITEM2: RESTORE 9280: GO SUB POKE: GO TO LOOP: DATA 167,237,82,46,0,48,2,46,1,38,0,-PI
 9290 IF A$(1)="*" THEN GO SUB ITEM2: RESTORE 9290: GO SUB POKE: GO TO LOOP: DATA 205,104,52,-PI
 9300 IF A$(1)="/" THEN GO SUB ITEM2: RESTORE 9300: GO SUB POKE: GO TO LOOP: DATA 122,179,200,124,77,33,0,0,6,16,203,17,23,237,106,237,82,63,48,16,16,244,24,14,203,17,23,237,106,167,237,90,56,242,40,237,16,242,203,17,23,25,71,96,105,-PI
 9305 IF A$(1)=" AND " THEN GO SUB ITEM2: RESTORE 9305: GO SUB POKE: GO TO LOOP: DATA 124,162,103,125,163,111,-PI
 9307 IF A$(1)=" OR " THEN GO SUB ITEM2: RESTORE 9307: GO SUB POKE: GO TO LOOP: DATA 124,178,103,125,179,111,-PI
 9310 RETURN                      
 9315 POKE LOC,235:                   GO SUB ADVANCE:                 GO SUB ITEM :                   POKE LOC,235:                   GO TO ADVANCE
 9320: LET A$=A$(2 TO ): REM ITEM
 9325 IF LEN a$>1 THEN IF A$(1 TO 2)="POINT (" THEN GO SUB chop: GO SUB CONS2: POKE loc,229: GO SUB advance: GO SUB cons2: GO SUB chop:: RESTORE 9325: GO TO POKE: DATA 227,229,193,205,233,48,193,205,233,48,205,36,38,205,96,49,197,225,-PI
 9330 IF A$(1)="PEEK " THEN GO SUB CONS2: POKE LOC,110: POKE LOC+1,38: POKE LOC+2,0: LET LOC=LOC+3: RETURN 
 9335 IF A$(1)="CODE " THEN           GO SUB CHOP: GO SUB STRING:     RESTORE 9335: GO TO POKE:       DATA 38,0,111,-PI
 9340 IF A$(1)="USR " THEN GO SUB CONS2: RESTORE 9340: GO TO POKE: DATA 213,34,143,255,205,142,255,96,105,209,-PI
 9350 IF A$(1)="IN " THEN GO SUB CONS2: RESTORE 9350: GO TO POKE: DATA 68,77,237,72,38,0,105,-PI      
 9360: REM CONS
 9365:  IF LEN A$>=7 THEN IF A$(1 TO 7)="RND*65536"    THEN LET A$=A$(8 TO ): RESTORE 9365            : GO TO POKE: DATA 237,75,118,92,205,233,48,239,161,15,52,       55,22,4,52,128,65,0,0,128,      50,2,161,3,49,56,205,96,        49,237,67,118,92,96,105,-PI
 9369 IF A$(1)<="z" THEN IF a$(1)>="a" THEN LET a$(1)=CHR$ (CODE a$(1)-CODE "a"+CODE "A")
 9370 LET DO=A$(1)<="Z" AND A$(1)>="A"
 9380 IF NOT DO THEN GO SUB FETCH: POKE LOC,33
 9390 IF DO THEN LET NUM=USR "A"+2*(CODE A$-CODE "A"): LET A$=A$(2 TO ): POKE LOC,42
 9400 POKE LOC+1,FN L(NUM)
 9410 POKE LOC+2,FN H(NUM)
 9420 LET LOC=LOC+3
 9430 RETURN                      
 9440 GO SUB CHOP:                    GO TO CONS:                     REM CONS2                       
 9480 LET LOC=LOC+1: RETURN :                          REM ADVANCE             
 9490 LET A$=A$(2 TO ): RETURN :             REM CHOP             
 9500 LET NUM=0: REM FETCH
 9510 IF CODE A$<CODE "0" OR CODE A$>CODE "9" THEN RETURN 
 9520 LET NUM=NUM*10+CODE A$-CODE "0": GO SUB CHOP: GO TO 9510                    
 9530: READ ZZZZ: IF ZZZZ<>-PI THEN POKE LOC,ZZZZ:: GO SUB ADVANCE: GO TO 9530: REM POKE
 9540 RETURN                        
 9550 IF P THEN RETURN 
 9555 LET LTOT=LTOT+1: LET X$(LTOT*2-1 TO LTOT*2)=CHR$ FN L(NLINE)+CHR$ FN H(NLINE): REM STORE
 9560 LET Y$(LTOT*2-1 TO LTOT*2)=CHR$ FN L(LOC)+CHR$ FN H(LOC): RETURN : REM STORE   
 9565: GO SUB ADVANCE: GO SUB CHOP     :: GO SUB FETCH: REM BRANCH
 9570 IF NOT P THEN GO SUB ADVANCE: GO SUB ADVANCE: GO TO STATEMENT
 9580 FOR I=1 TO LTOT*2-1 STEP 2:
 9590 IF NUM>CODE X$(I)+256*CODE      X$(I+1) THEN NEXT I
 9600 POKE LOC,CODE Y$(I):                 GO SUB ADVANCE            
 9610 POKE LOC,CODE Y$(I+1):             GO SUB ADVANCE                 : GO TO STATEMENT
 9620 REM STRING EVALUATOR
 9625:: IF LEN A$>=2 THEN IF a$(2)="$" THEN : LET k=s(1+CODE a$-CODE "A"): GO SUB chop: GO SUB chop: GO SUB chop: POKE loc,229: GO SUB advance: GO SUB cons: GO SUB chop: RESTORE 9625: GO TO poke: DATA 1,FN l(k-1),FN h(k-1),9,126,225,-PI
 9630 IF A$(1)="INKEY$" THEN GO SUB CHOP: RESTORE 9630: GO TO POKE:  DATA 213,205,225,2,209,58,      5,92,167,40,3,58,8,92,-PI
 9635 IF A$(1)="," THEN GO SUB CHOP: RESTORE 9635: GO TO POKE: DATA 62,6,-PI
 9640 IF A$(1)="AT " THEN            GO SUB E1: GO SUB E2::           RESTORE 9640: GO TO POKE        : DATA 62,22,215,125,215,       123,-PI
 9642 IF A$(1)="STR$ " THEN GO SUB E1: RESTORE 9642: GO TO POKE: DATA 68,77,205,233,48,205,161,49,62,32,-PI
 9644 IF A$(1)="'" THEN GO SUB CHOP: RESTORE       9644: GO TO POKE: DATA 62,      13,-PI
 9650 IF A$(1)="TAB " THEN            GO SUB E1: RESTORE 9650:        GO TO POKE: DATA 62,23,215,     125,215,62,0,-PI
 9655 IF A$(1)=" INVERSE " THEN       GO SUB E1: RESTORE 9655:        GO TO POKE: DATA 62,20,215,     125,-PI
 9660 IF A$(1)=" BRIGHT " THEN        GO SUB E1: RESTORE 9660:        GO TO POKE: DATA 62,19,215,     125,-PI
 9665 IF A$(1)=" OVER " THEN        GO SUB E1: RESTORE 9665:        GO TO POKE: DATA 62,21,215,     125,-PI
 9670 IF A$(1)=" PAPER " THEN         GO SUB E1: RESTORE 9670:        GO TO POKE: DATA 62,17,215,     125,-PI
 9680 IF A$(1)=" INK " THEN           GO SUB E1: RESTORE 9680:        GO TO POKE: DATA 62,16,215,     125,-PI
 9690 IF A$(1)=" FLASH " THEN         GO SUB E1: RESTORE 9690:        GO TO POKE: DATA 62,18,215,     125,-PI
 9695:: IF A$(1)="CHR$ " THEN POKE loc,229: GO SUB advance: GO SUB E1: POKE loc,125: GO SUB advance: POKE LOC,225: GO TO ADVANCE
 9700 IF A$(1)<>"""" THEN RETURN 
 9710 GO SUB CHOP
 9720 IF A$(1)<>"""" THEN             POKE LOC,62: GO SUB ADVANCE   : POKE LOC,CODE A$              : GO SUB ADVANCE: GO SUB CHOP   : IF A$(1)<>"""" THEN             POKE LOC,215                  : GO SUB ADVANCE: GO TO 9720
 9730 GO TO CHOP
 9740 REM SOUND
 9745 LET SD=0
 9750 LET SD=SD+1: IF A$(SD)=":" THEN GO TO 9770
 9760 IF A$(SD)=";" THEN LET A$=A$( TO SD-1)+":}"+A$(SD+1 TO )
 9765 IF A$(SD)="}" THEN LET A$=A$( TO SD-1)+" OUT 245,"+A$(SD+1 TO ): LET SD=SD+5:
 9767 IF A$(SD)="," THEN LET A$=A$( TO SD-1)+": OUT 246,"+A$(SD+1 TO ): LET SD=SD+5
 9769 IF SD<LEN A$ THEN GO TO 9750
 9770 GO TO STATEMENT
 9800 IF NOT lprint THEN GO TO statement
 9810 RESTORE 9810: GO SUB poke: GO TO statement: DATA 33,59,92,203,142,-PI
 9900 REM TRUE STRINGS
 9910 LET S=1+CODE A$(2)-CODE "A"
 9915 GO SUB CHOP: GO SUB CHOP: GO SUB CHOP
 9920: IF CODE A$=CODE "=" THEN GO TO 9950
 9921 GO SUB item
 9922 GO SUB CHOP: GO SUB CHOP: GO SUB string
 9923 RESTORE 9923:: GO TO POKE: DATA 1,FN L(S(S)-1),FN H(S(S)-1),9,119,-PI
 9924 REM                           LD BC,STRING ADDRESS            ADD HL,BC                       LD (HL),A
 9950 IF a$( TO 2)<>"=""" THEN PRINT "string syntax error": STOP 
 9955: GO SUB chop: GO SUB chop
 9962 LET SL=HIMEM: LET SH=SL
 9965: IF CODE A$<>CODE """" THEN POKE HIMEM*P,CODE A$: LET HIMEM=HIMEM+1: LET SH=SH+1:: GO SUB CHOP: GO TO 9965
 9970:: RESTORE 9970: IF SH>SL THEN :: GO TO POKE: DATA 17,FN L(S(S)),FN H(S(S)),33,FN L(SL),FN H(SL),1,FN L(SH-SL),FN H(SH-SL),237,176,-PI
 9980 RETURN 
 9990 REM 
 9991: LET loc=(loc+himem)*(NOT p)+p*himem: IF NOT p THEN LET himem=loc-himem:
 9992 IF NOT p THEN FOR s=1 TO 26:: LET temp=s(s): LET s(s)=loc: LET loc=temp+loc: NEXT s: RETURN 
 9993: RETURN 
 9998 PRINT "RESAVE?": PAUSE 0: IF INKEY$="Y" OR INKEY$="y" THEN SAVE "COMPASS" LINE 9998: PRINT "now VERIFY ": VERIFY "COMPASS": PRINT "program OK": GO TO 9998
 9999 CLS : PRINT               "If you want to use the assembler then type:  DELETE 8888,9999                                            OR                     If you want to use the compiler  then type:  DELETE 0,8888                                                                      Note that the assembler will    work with the compiler still in memory, but the compiler will   not work with the assembler in  memory.  So DELETE the assemblerif you want to use the compiler."

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

Scroll to Top