--- title: "Compass Compiler" id: 54959 type: "computer_media" slug: "compass-compiler" url: "http://localhost/computer_media/compass-compiler/" markdown_url: "http://localhost/computer_media/compass-compiler.md" published_at: "2024-06-10T01:16:19+00:00" modified_at: "2026-03-30T23:51:14+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2019/02/20230809-041332.jpg" excerpt: "A two-in-one development toolkit packs a full two-pass Z80 assembler and an integer BASIC compiler into one BASIC listing, complete with label resolution and direct machine code output." category: - name: "Archived Media" slug: "archived-media" taxonomy: "category" url: "http://localhost/category/archived-media/" post_tag: - name: "Downloadable" slug: "downloadable" taxonomy: "post_tag" url: "http://localhost/tag/downloadable/" - name: "JRC Software" slug: "jrc-software" taxonomy: "post_tag" url: "http://localhost/tag/jrc-software/" - name: "TS 2068" slug: "ts2068" taxonomy: "post_tag" url: "http://localhost/tag/ts2068/" model: - name: "Timex/Sinclair 2068" slug: "ts-2068" taxonomy: "model" url: "http://localhost/model/ts-2068/" indiv: - name: "John Richard Coffey" slug: "john-richard-coffey" taxonomy: "indiv" url: "http://localhost/indiv/john-richard-coffey/" genre: - name: "Compiler" slug: "compiler" taxonomy: "genre" url: "http://localhost/type/compiler/" media_type: "Program" programmers: - name: "John Richard Coffey" slug: "john-richard-coffey" taxonomy: "indiv" url: "http://localhost/indiv/john-richard-coffey/" download_url: "https://archive.org/download/timex-sinclair-software-archive/Compass%20Compiler%20%281988%29%28JRC%20Software%29%28TS2068%29%28US%29%28Program%29.zip" mediadate: "1988" producer_company: - id: 10999 title: "JRC Software" type: "company" url: "http://localhost/company/jrc-software/" images: - url: "http://localhost/wp-content/uploads/2024/06/SCR-20260330-rfsm.png" related_products: - id: 20297 title: "Compass Compiler" type: "product" url: "http://localhost/product/compass-2068/" related_content: - id: 35732 title: "COMPASS Compiler manual" type: "document" url: "http://localhost/document/compass-compiler-manual/" media_type_tags: "Compiler" --- # Compass 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-op | Handler lines | Function | | --- | --- | --- | | `ORG` | 620–690 | Sets base address `D` and saves origin in `E` | | `NUM` | 1000–1060 | Emits a 16-bit little-endian word | | `TXT` | 1400–1460 | Emits a quoted ASCII string as bytes | | `TBL` | 1600–1670 | Emits a table of N word values from subsequent source lines | | `RSV` | 1800–1840 | Reserves N bytes (advances `D` without emitting) | | `BYT` | 2200–2240 | Emits a single evaluated byte | | `LET` | 2000–2110 | Defines a named numeric constant | | `STOP` | 800–890 | Ends 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 | Address | Usage | | --- | --- | | 31898–31908 | Assembler mnemonic search buffer (POKEd by BASIC, searched by USR 31909) | | 31909 | Entry point of assembler opcode-search machine code routine | | 31130+k | Assembler argument-type table indexed by opcode number k | | 31997 | Default start address for assembler source scan (G) | | USR “A” + 2*n | Compiler: 16-bit integer variable storage for variables A–Z (52 bytes) | | ORG / LOC | User-specified or default (60000) machine code output area | ## 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 "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 SDCODE """" 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." ```