--- title: "ZIP BASIC Compiler" id: 72055 type: "computer_media" slug: "zip-basic-compiler" url: "http://localhost/computer_media/zip-basic-compiler/" markdown_url: "http://localhost/computer_media/zip-basic-compiler.md" published_at: "2026-10-20T15:00:23+00:00" modified_at: "2026-10-20T15:00:23+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2026/10/Zip_Compiler-scaled.jpg" excerpt: "An optimizing compiler, written in BASIC, that turns integer-only TS2068 BASIC programs into Z80 machine code, with a run-time library and a demo game." 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: "Knighted Computers" slug: "knighted-computers" taxonomy: "post_tag" url: "http://localhost/tag/knighted-computers/" - 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: "Jon A. Smith" slug: "jon-a-smith" taxonomy: "indiv" url: "http://localhost/indiv/jon-a-smith/" - name: "Simon Goodwin" slug: "simon-goodwin" taxonomy: "indiv" url: "http://localhost/indiv/simon-goodwin/" genre: - name: "Compiler" slug: "compiler" taxonomy: "genre" url: "http://localhost/type/compiler/" media_type: "Cassette" programmers: - name: "Simon Goodwin" slug: "simon-goodwin" taxonomy: "indiv" url: "http://localhost/indiv/simon-goodwin/" - name: "Jon A. Smith" slug: "jon-a-smith" taxonomy: "indiv" url: "http://localhost/indiv/jon-a-smith/" download_url: "https://archive.org/download/timex-sinclair-software-archive/ZIP%20BASIC%20Compiler%20%281985%29%28Goodwin%2C%20Simon%3B%20Smith%2C%20Jon%20A.%29%28TS2068%29%28US%29%28Cassette%29.zip" tsrun_member: "ZIP BASIC Compiler (1985)(Goodwin, Simon; Smith, Jon A.)(TS2068)(US)(Cassette)/Zip_Compiler.tap" mediadate: "1985" producer_company: - id: 11024 title: "Knighted Computers" type: "company" url: "http://localhost/company/knighted-computers/" images: - url: "http://localhost/wp-content/uploads/2026/10/Zip_Compiler-scaled.jpg" article_media: - id: 23118 title: "Review: ZIP BASIC Compiler" type: "article" url: "http://localhost/article/review-zip-basic-compiler/" - id: 37677 title: "ZIP Basic Compiler" type: "article" url: "http://localhost/article/zip-basic-compiler/" - id: 44514 title: "ZIP BASIC Review" type: "article" url: "http://localhost/article/zip-basic-review/" related_products: - id: 14686 title: "ZIP BASIC Compiler" type: "product" url: "http://localhost/product/zip/" media_type_tags: "Compiler" --- # ZIP BASIC Compiler Compiles a BASIC program into Z80 machine code on the TS2068. The user types the program to be compiled in lines below 5000, tests it in BASIC with `RUN`, then enters `GO TO 5000`. The compiler, itself written in BASIC, scans the program in two passes and reports the code size. It then gives the `SAVE "..."CODE` addresses for the result and the `RANDOMIZE USR` address that runs it. It handles integer BASIC only: strings, streams, decimal values, numbers beyond ±65535 and multi-letter variable names are rejected with an error message, and arrays are one-dimensional with single-letter names. The cassette label reads “ZIP COMPILER – TIMEX SINCLAIR 2068 – LOAD “” – Dist By KNIGHTED COMPUTERS – (C) SIMON GOODWIN 1985″. The loader’s title screen describes it as “An optimizing BASIC compiler for the Timex Sinclair 2068 computer” by Simon N Goodwin and Jon A Smith, Version 1.5, and the compiler’s REM header gives a last revision date of 29/01/85. The tape holds four blocks: the BASIC loader; `lib`, a 1,530-byte run-time library loaded at 53247; the compiler, saved as `ZIP`; and `demo game`, a BASIC game called “Star Base!”, (c)1984 Simon N Goodwin, written in the compiler’s BASIC subset. ## Program Analysis ### Program Structure The loader runs `CLEAR 53246` when RAMTOP is too high, draws a title graphic with `PLOT` and `DRAW`, then loads the library CODE and the compiler. The compiler program is laid out in labeled sections: - 5000–5440: initialization: token-type and operator-precedence tables read from `DATA`, named constants for character and keyword codes (`LET then=VAL "203"`, `LET goto=VAL "236"` and so on), and variables holding the line numbers of its own subroutines (`pass1`, `pass2`, `maths`, `Z80` and others). - 6000–6155: lexical analysis, reading the source program directly from memory through the `PROG` system variable and reporting what is not allowed. - 6500–6590: pass 1, which lists each line as it scans, counts lines and sets aside space for each `DIM`. - 6700–6925: memory tables and a cross-reference of line addresses kept at the top of memory, with a binary search to find a line and a list of forward references to fill in afterwards. - 7000–7970: pass 2, a statement parser and an expression handler that uses an operator stack with precedences to turn expressions into stack-based code. - 8000 onward: code generation from numbered templates, and an optimization module at 8280 that rewrites common pairs, for example a `PRINT CHR$` of a constant into a direct `LD A,n` and `RST 16`. ### Demo Game Star Base! puts a gun at the center of the screen that turns clockwise with 7 and anticlockwise with 6 and fires with 0, against enemies that approach from eight directions, with 500 rounds of ammunition and a score line. Because it is written for the compiler, it uses only integers: the keyboard is read with `IN 61438` and decoded arithmetically, random numbers come from its own routine at 4530 that also mixes in `PEEK 23692`, and sound comes from a few bytes of machine code POKEd into the printer buffer at 23500. ### Notable Techniques - Readable names throughout the compiler, including names with spaces such as `find line` and `capital A`, which the TS2068 allows in numeric variables. - `GO SUB` through named variables (`GO SUB pass1`, `GO SUB deek`) instead of line numbers. - 16-bit memory access with small `deek` and `doke` subroutines. - Constants written as `VAL "n"` and zero as `NOT PI` to save memory in the larger sections. - The compiled program carries a BREAK trap, and the output starts at the library address so library and program save together as one CODE block. ## Source Code ``` 20 PRINT AT 17,0;"Type RUN to test this code in BASIC, and then GO TO 5000 to compile it into machine code. Enter RANDOMIZE USR prog to execute the compiled code." 30 FOR i=16384 TO 20479 40 POKE i,BIN 10011011 50 NEXT i 60 STOP 5000 REM TMS 2068 BASIC compiler 5005 REM Last revision: 29/01/85 5010 REM S N Goodwin & J A Smith 5015 REM 5020 REM **** INITIALISATION 5022 GO TO VAL "5035" 5025 IF PEEK VAL "23731">VAL "207" THEN CLEAR VAL "53246" 5030 PRINT "Load library.": LOAD ""CODE VAL "53247" 5035 DIM t(VAL "91"): REM Token types 5040 DIM a(VAL "27"): REM Array bases 5045 DIM p(VAL "27"): DIM o(VAL "27"): REM Function precedences & opcodes 5047 LET t=VAL "1": LET i=t: LET j=i: LET s=i: LET p=i: LET pc=i: LET z=i: LET s2=i: LET c=i: LET bugs=i: REM Search fast 5050 LET maxz=VAL "22": DIM l(maxz): DIM s(maxz): REM Maths stacks 5060 RESTORE : LET y=VAL "1": LET n=NOT PI: FOR i=VAL "1" TO VAL "91": READ t(i): NEXT i: DATA n,n,n,n,n,n,y,y,y,n,n,n,n,n,n,n,n,n,n,n,n,y,n,y,y,y,y,y,n,y,y,y,y,y,y,y,y,n,y,y,y,n,n,n,n,n,n,n,n,n,n,n,y,y,y,y,y,y,y,n,n,y,n,n,n,n,y,n,y,y,y,y,y,y,n,n,y,y,y,y,y,y,n,n,y,y,y,y,y,y,n 5070 FOR i=VAL "1" TO VAL "27": READ p(i): READ o(i): NEXT i: DATA VAL "14",-VAL "1",NOT PI,-VAL "1",VAL "8",VAL "15",VAL "6",VAL "16",VAL "1",-VAL "1",VAL "6",VAL "17",VAL "9",VAL "56",VAL "8",VAL "18",VAL "12",VAL "3",VAL "5",VAL "42",VAL "5",VAL "51",VAL "5",VAL "44",VAL "11",VAL "39",VAL "11",VAL "40",VAL "11",VAL "36",VAL "11",VAL "38",VAL "11",VAL "37",-VAL "1",-VAL "1",VAL "11",VAL "47",VAL "4",VAL "41",-VAL "1",-VAL "1",VAL "2",VAL "54",VAL "3",VAL "55",VAL "5",VAL "43",VAL "5",VAL "45",VAL "5",VAL "46",VAL "11",VAL "50" 5190 REM 5200 REM **** MANIFEST CONSTANTS 5205 LET true=VAL "1": LET false=NOT PI: LET eof=VAL "5000" 5210 LET appos=VAL "39": LET plus=VAL "43": LET number=VAL "14": LET enter=VAL "13": LET string=VAL "50": LET overflow=VAL "15": LET quote=VAL "34": LET comma=VAL "44": LET space=VAL "32": LET dollar=VAL "36": LET hash=VAL "35": LET op=VAL "42": LET variable=VAL "1" 5220 LET keyword=VAL "164": LET digit 0=VAL "48": LET digit 9=VAL "57": LET capital A=VAL "65": LET capital Z=VAL "90": LET colon=VAL "58": LET semi=VAL "59" 5225 LET attr=VAL "171": LET at=VAL "172": LET tab=VAL "173": LET chr=VAL "194": LET then=VAL "203": LET to=VAL "204": LET step=VAL "205": LET ink=VAL "217": LET paper=VAL "218": LET flash=VAL "219": LET bright=VAL "220": LET inverse=VAL "221": LET over=VAL "222" 5230 LET border=VAL "231": LET dim=VAL "233": LET rem=VAL "234": LET for=VAL "235": LET goto=VAL "236": LET gosub=VAL "237": LET input=VAL "238": LET let=VAL "241": LET pause=VAL "242": LET next=VAL "243": LET poke=VAL "244": LET print=VAL "245": LET random=VAL "249": LET if=VAL "250": LET cls=VAL "251": LET clear=VAL "253": LET return=VAL "254" 5235 LET out=VAL "223": LET stop=VAL "226": LET int=VAL "186": LET bin=VAL "196": LET lbracket=VAL "40": LET rbracket=VAL "41": LET small a=VAL "97": LET small z=VAL "122" 5250 LET source=VAL "23635": LET scroll=VAL "23692": REM System variables 5255 LET index=VAL "9": LET uminus=VAL "7": LET opbrt=VAL "1": LET clbrt=VAL "2" 5390 REM 5400 REM **** BASIC LABELS 5405 LET gets=VAL "6012": LET fetch=VAL "6015": LET init=VAL "6010": LET dump=VAL "8035" 5410 LET deek=VAL "6205": LET doke=VAL "6300": LET find line=VAL "6745": LET too big=VAL "6715": LET request=VAL "6900": LET skip st=VAL "7970": LET p2error=VAL "7950" 5415 LET pass1=VAL "6500": LET pass2=VAL "7000": LET patch=VAL "6795": LET tables=VAL "6700": LET addln=VAL "6725": LET next1=VAL "6555": LET Z80=VAL "8000": LET itm=VAL "7330" 5420 LET p1error=VAL "6125": LET parsestr=VAL "7910": LET nextln=VAL "7030": LET nextst=VAL "7050": LET pre colon=VAL "7660": LET atcolon=VAL "7670": LET store=VAL "7690" 5440 LET exppush=VAL "7752": LET exppop=VAL "7770": LET maths=VAL "7785": LET expnexts=VAL "7900": LET expnext=VAL "7800": LET expop=VAL "7822": LET expdoop=VAL "7857" 5790 REM 5800 REM **** MAIN PROGRAM 5805 OVER 0: LET bottom=VAL "53247": LET vars=bottom+VAL "1537": LET arrays=vars+VAL "26"*VAL "8": LET prog=arrays: LET pc=prog 5810 LET top=VAL "65535": LET linetab=top: LET tp=linetab 5815 LET last=NOT PI: LET F1=VAL "54": LET errors=NOT PI: LET lines=NOT PI: FOR i=VAL "1" TO VAL "26": LET a(i)=NOT PI: NEXT i 5820 GO SUB pass1: PRINT PAPER VAL "5"; INK NOT PI;'lines;" LINES scanned: ";errors;" ERRORS.": IF errors THEN STOP 5830 GO SUB tables: GO TO pass2 5840 IF errors THEN PRINT AT NOT PI,NOT PI; PAPER VAL "1";"ZIP FOUND ";errors;" ERRORS.": STOP 5845 GO SUB patch: REM Correct forward jumps 5850 PRINT AT NOT PI,NOT PI; PAPER VAL "1";"ZIP HAS FINISHED (";pc-prog-VAL "34" 5860 POKE (prog+8),0: PRINT AT VAL "19",NOT PI; INVERSE VAL "1";"Save: SAVE ""???""CODE ";bottom;",";pc-bottom+VAL "2",,,"Run: RANDOMIZE USR prog [";prog;"]": STOP 5990 REM 6000 REM **** LEXICAL ANALYSIS 6005 REM Init & Fetch (source) 6010 LET t=source: GO SUB deek: LET p=t: LET s=enter: GO TO 6100 6012 IF bugs THEN RETURN 6015 LET last=s: LET s=PEEK p: LET p=p+1 6017 IF s>keyword THEN IF s<>bin THEN IF t(s-keyword) THEN RETURN : REM Keyword OK 6020 IF s=enter THEN GO TO 6100 6021 IF s<=space THEN GO TO 6015 6022 IF s>=small a THEN IF s<=small z THEN LET s=s-32: REM lower case 6023 IF s=quote THEN LET num=p: RETURN 6024 REM Analyse variable name 6025 IF lastcapital Z OR scapital Z THEN GO TO 6030 6026 IF s>digit 9 THEN IF s=small a AND s<=small z THEN LET s=s-32 6028 IF (s>=digit 0 AND s<=digit 9) OR s=space OR (s>=capital A AND s<=capital Z) THEN LET p=p+1: GO TO 6027 6029 LET s=variable: GO TO p1error 6030 IF s>=digit 0 THEN IF s=bin OR s<=digit 9 THEN GO TO 6110 6045 IF s=hash OR s=dollar THEN GO TO p1error 6050 IF s>keyword THEN GO TO p1error 6090 RETURN 6095 REM New line found 6100 LET num=256*PEEK p+PEEK (p+1): LET lnum=num: LET t=p+2: GO SUB deek: LET p=p+4: RETURN 6105 REM Number found 6110 IF PEEK p<>number THEN LET p=p+1: GO TO 6110 6112 IF PEEK (p+1)<>0 THEN LET s=overflow: LET p=p+6: GO TO p1error 6115 LET p=p+3: LET t=p: GO SUB deek: LET num=t: IF PEEK (p-1) THEN LET num=-num 6120 LET p=p+3: LET s=number: RETURN 6122 REM PASS 1 Error (p1error) 6125 PAPER 6: INK 0: PRINT 6130 IF s=dollar OR s=l bracket THEN PRINT "Strings"; 6135 IF s=variable THEN PRINT "Variable name"; 6140 IF s=hash THEN PRINT "Streams"; 6145 IF s>keyword THEN PRINT CHR$ s; 6150 IF s=overflow THEN PRINT "Decimal values & integers beyond+/-65535"; 6155 PRINT " not allowed.": LET errors=errors+1: PAPER 0: INK 7: RETURN 6190 REM 6195 REM **** DEEK and DOKE 6200 REM Deek - t=contents of address t 6205 LET t=PEEK t+256*PEEK (t+1): RETURN 6295 REM Doke - put t at address i 6300 POKE i,t-INT (t/256)*256: POKE i+1,INT (t/256): RETURN 6490 REM 6495 REM **** PASS1 Allocate RAM 6500 PAPER 0: INK 7: BORDER 0: CLS : PRINT PAPER 5; INK 0;"TMS 2068 BASIC COMPILER PASS 1.": GO SUB init 6505 IF s=enter THEN IF num>=eof THEN RETURN 6507 IF s=enter THEN LET lines=lines+1: PRINT : PRINT num;" ";: POKE scroll,255: GO TO next1 6510 IF s=number THEN PRINT num;: GO TO next1 6512 IF s=rem THEN GO TO 6545 6513 IF s=dim THEN GO SUB 6565 6514 IF s=step THEN LET f1=false 6515 IF s<>quote THEN PRINT CHR$ s;: GO TO next1 6520 PRINT """"; 6530 PRINT CHR$ PEEK p; 6535 IF PEEK p<>quote THEN LET p=p+1: GO TO 6530 6540 LET p=p+1: GO SUB fetch: IF s=l bracket THEN GO SUB p1error 6542 GO TO 6505 6545 PRINT CHR$ s;: LET s=PEEK p: LET p=p+1: IF s<>enter THEN GO TO 6545 6550 LET p=p-1: GO TO next1 6555 GO SUB fetch: GO TO 6505 6560 REM Evaluate DIM 6565 PRINT " DIM ";: GO SUB fetch: IF scapital Z THEN GO TO 6590 6570 LET v=s-64: PRINT CHR$ (s);: GO SUB fetch: IF s<>lbracket OR a(v) THEN GO TO 6590 6575 PRINT "(";: GO SUB fetch: IF s<>number THEN GO TO 6590 6580 PRINT num;: GO SUB fetch: IF s<>rbracket OR num<1 THEN GO TO 6590 6585 LET a(v)=num: RETURN 6590 PRINT PAPER 6; INK 0;'"Faulty DIM statement.": LET errors=errors+1: RETURN 6690 REM 6695 REM **** BUILD RAM TABLES 6700 FOR i=1 TO 26: LET t=prog: LET prog=prog+a(i)*2: LET a(i)=t: NEXT i: LET a(27)=prog: LET pc=prog 6705 LET linetab=top-4*lines-4: LET tp=linetab: FOR i=tp TO top-1: POKE i,127: NEXT i 6710 IF tp>pc THEN RETURN 6715 PRINT AT 21,0; PAPER 6; INK 0;"Insufficient memory.": STOP 6718 REM 6720 REM **** CROSS REFERENCE ROUTINES 6725 REM Add an entry to line address table (addln) 6730 LET t=lnum: LET i=xref: GO SUB doke: LET i=xref-2: LET t=pc+1: GO SUB doke: LET xref=xref-4: RETURN 6740 REM Find line n (return T pointing to its address) 6745 LET L=1: LET u=(top-linetab)/4 6750 IF L>u THEN LET t=u*4+linetab-2: RETURN 6755 LET t1=INT ((u+l)/2): LET t=t1*4+linetab-2: GO SUB deek 6760 IF n=t THEN LET t=t1*4+linetab-2: RETURN 6765 IF n>t THEN LET u=t1-1: GO TO 6750 6770 LET L=t1+1: GO TO 6750 6790 REM 6795 REM Correct line references (patch) 6800 FOR q=linetab-2 TO tp STEP -2: LET t=q: GO SUB deek: LET i=t: GO SUB deek: LET n=t: GO SUB find line: LET t=t-2: GO SUB deek: GO SUB doke: NEXT q: RETURN 6895 REM Put address of line t at pc-1 (request) 6910 IF lnum=eof THEN LET lnum=9999: GO SUB addln: LET c=53: GO SUB Z80: POKE pc,255: GO TO 5840: REM End with 'OK' message 7045 PRINT AT 0,15; FLASH 1;lnum: GO SUB addln 7050 REM nextst 7080 GO SUB gets 7100 IF s<>rem THEN GO TO 7120 7105 LET s=PEEK p: LET p=p+1: IF s<>enter THEN GO TO 7105 7110 LET p=p-1: GO TO pre colon 7120 IF s<>goto AND s<>gosub THEN GO TO 7150 7125 LET c=4+(s=gosub): GO SUB gets: IF s=number THEN LET t=num: GO SUB Z80: GO TO pre colon 7130 LET bugs=number: GO TO p2error 7150 IF s=let THEN GO SUB gets: GO SUB store: GO SUB gets: GO SUB maths: LET c=assmod: LET t=assvar: GO SUB Z80: GO TO atcolon 7175 IF s=return THEN LET c=6: GO SUB Z80: GO TO pre colon 7185 IF s=if THEN GO SUB gets: GO SUB maths: LET c=48: LET t=lnum+1: GO SUB Z80: GO TO nextst 7205 IF s=stop THEN LET c=53: GO SUB Z80: GO TO pre colon 7210 IF s<>for THEN GO TO 7245 7215 GO SUB gets: LET assvar=s: GO SUB gets: GO SUB gets: GO SUB maths: GO SUB gets: GO SUB maths: IF s=step THEN GO SUB gets: GO SUB maths: GO TO 7230 7225 IF f1=false THEN LET c=2: LET t=1: GO SUB Z80: REM Generate STEP 1 7230 LET c=7+f1: LET t=assvar-65: GO SUB Z80: GO TO atcolon 7245 IF s=next THEN GO SUB gets: LET c=8+f1: LET t=s-65: GO SUB Z80: GO TO pre colon 7250 IF s<>246 THEN IF s<>252 THEN GO TO 7260 7252 LET assmod=59+(s=252): LET c=52: GO SUB Z80: REM Open #2 7254 GO SUB gets: IF s>=ink AND s<=over THEN LET sep=s: GO SUB gets: GO SUB maths: LET c=sep-189: GO SUB Z80: GO TO 7254 7258 GO SUB maths: GO SUB gets: GO SUB maths: LET c=assmod: GO SUB Z80: GO TO atcolon 7260 IF s<>border AND s<>pause AND (sover) THEN GO TO 7295 7265 LET assmod=s-197: IF s=border THEN LET assmod=19 7266 IF s=pause THEN LET assmod=58 7270 GO SUB gets: GO SUB maths: LET c=assmod: GO SUB Z80: GO TO atcolon 7295 IF s=poke OR s=out THEN LET assmod=12+2*(s=out): GO SUB gets: GO SUB maths: GO SUB gets: GO SUB maths: LET c=assmod: GO SUB Z80: GO TO atcolon 7315 IF s=clear OR s=cls THEN LET c=10+39*(s=clear): GO SUB Z80: GO TO pre colon 7320 IF s<>print THEN GO TO 7500 7323 LET sep=false: LET c=52: GO SUB Z80 7325 GO SUB gets 7327 REM Check print item (itm) 7330 IF s=enter OR s=colon THEN GO TO 7480 7334 LET sep=true 7335 IF s=semi THEN GO TO 7325 7340 IF s=appos THEN LET c=2: LET t=13: GO SUB Z80: LET c=47: GO SUB Z80: GO TO 7325 7345 IF s=comma THEN LET c=2: LET t=6: GO SUB Z80: LET c=47: GO SUB Z80: GO TO 7325 7346 LET sep=false 7355 IF s=chr THEN GO SUB maths: GO TO itm 7365 IF s<>quote THEN GO TO 7385 7370 LET sptr=num 7375 GO SUB parsestr: IF num THEN LET t=sptr: LET c=26: GO SUB Z80 7376 IF more THEN LET t=quote: LET c=2: GO SUB Z80: LET c=47: GO SUB Z80: LET sptr=nptr+1: GO TO 7375 7377 LET p=nptr: GO SUB gets: GO TO itm 7385 IF s=at THEN GO SUB gets: GO SUB maths: GO SUB gets: GO SUB maths: LET c=34: GO SUB Z80: GO TO itm 7405 IF s=tab THEN GO SUB gets: GO SUB maths: LET c=35: GO SUB Z80: LET c=2: LET t=0: GO SUB Z80: LET c=47: GO SUB Z80: GO TO itm: REM Oddly, TAB requires a 2 byte parameter! 7425 IF s>=ink AND s<=over THEN LET assmod=s: GO SUB gets: GO SUB maths: LET c=assmod-189: GO SUB Z80: GO TO itm 7440 GO SUB maths: LET c=27: GO SUB Z80: GO TO itm 7480 IF NOT sep THEN LET c=2: LET t=13: GO SUB Z80: LET c=47: GO SUB Z80 7485 GO TO atcolon 7500 IF s<>input THEN GO TO 7535 7505 GO SUB gets 7507 IF s=semi OR s=comma THEN GO TO 7505 7515 IF s=colon OR s=enter THEN GO TO atcolon 7520 IF s>=capital A AND s<=capital Z THEN GO SUB store: LET c=9: GO SUB Z80: LET c=assmod: LET t=assvar: GO SUB Z80: GO TO 7507 7525 LET bugs=input: GO TO p2error 7535 IF s=random THEN GO SUB gets: IF s<>enter AND s<>colon THEN GO SUB maths: LET c=57: GO SUB Z80: GO TO atcolon 7635 GO SUB skip st: GO TO atcolon 7660 REM pre colon 7665 GO SUB gets 7670 REM atcolon 7675 IF s=colon THEN GO TO nextst 7680 IF s=enter THEN GO TO nextln 7685 GO TO 7130: REM Computed GO TO / GO SUB error?? 7687 REM store (var. name in s) 7690 LET assvar=s-65: GO SUB gets: LET assmod=11: IF s=lbracket THEN GO SUB gets: LET assmod=13: GO SUB maths: GO SUB gets: IF a(assvar+1)=a(assvar+2) THEN LET bugs=index: GO TO p2error 7695 RETURN 7698 REM 7700 REM **** EXPRESSION HANDLER 7750 REM exppush 7752 IF z=maxz THEN GO TO p2error 7755 LET z=z+1: LET S(z)=tsav: LET L(z)=s2: LET oplast=true 7760 RETURN 7765 REM exppop 7770 LET z=z-1: RETURN 7780 REM Scan expression (maths) 7785 LET commas=0: LET z=0 7790 LET s2=opbrt: LET tsav=0: GO SUB exppush: REM mark start 7795 REM expnext 7800 LET s2=s: IF s2<>number THEN GO TO 7805 7802 IF L(z)=uminus THEN LET num=-num: GO SUB exppop: GO TO 7802: REM Perform negation at once 7803 LET c=2: LET oplast=false: LET t=num: GO SUB Z80: GO TO expnexts: REM Put num on Z80 stack 7805 IF s2>capital Z OR s2 etc. 7830 IF s2=45 AND oplast THEN LET s2=uminus: GO TO expdoop 7835 IF s2<=47 AND s2>=40 THEN LET s2=s2-39: GO TO expdoop 7840 IF s2<=62 AND s2>=60 THEN LET s2=s2-50: GO TO expdoop 7845 IF s2<=201 AND s2>=188 THEN LET s2=s2-175: GO TO expdoop 7847 IF s2=attr THEN LET s2=27: LET commas=commas+1: GO TO expdoop 7850 GO TO p2error: REM Unrecognised operator in s2 7855 REM expdoop 7857 IF z=1 AND s2=clbrt THEN RETURN : REM finished 7860 LET prio=P(L(z)): IF L(z)=opbrt THEN LET prio=0 7865 IF oplast OR prio-1 THEN GO SUB Z80: GO TO expdoop 7887 LET commas=commas-1: GO TO expdoop 7890 REM expnexts 7900 GO SUB gets: GO TO expnext 7910 REM parsestr 7915 LET i=sptr 7920 IF PEEK (i)<>quote THEN LET i=i+1: GO TO 7920 7925 LET nptr=i+1: LET more=PEEK (nptr)=quote: LET num=sptr-i: RETURN 7950 REM PASS 2 Error (p2error) 7955 LET errors=errors+1: LET t=xref+4: GO SUB deek: PRINT AT errors+1,0;t;" ";: REM Echo the most recent line reference 7956 IF bugs=index THEN PRINT "ARRAY ";CHR$ (assvar+65);"() WAS NOT DIMENSIONED": GO TO 7963 7957 IF bugs=input THEN PRINT "WRONG INPUT FORMAT": GO TO 7963 7958 PRINT "CALCULATION ";: IF z=maxz THEN PRINT "TOO COMPLEX": LET z=1: GO TO 7963 7960 IF bugs=number THEN PRINT "NOT ALLOWED": GO TO 7963 7961 PRINT "NOT UNDERSTOOD" 7963 LET bugs=false 7964 IF s<>enter THEN GO SUB fetch: GO TO 7964 7965 IF errors<15 THEN GO TO nextln 7967 STOP 7970 REM skip st 7975 IF s<>colon AND s<>enter THEN GO SUB gets: GO TO 7975 7980 RETURN 7990 REM 7995 REM **** Z80 CODE GENERATION 8000 IF errors THEN RETURN 8005 GO TO 8300: REM Attempt to optimise the code 8010 IF pc>prog+34 THEN PRINT AT 0,21; PAPER 1;pc-prog-34 8015 LET oldc=c: LET oldt=t 8020 IF c<=5 OR c=7 OR c=8 OR c=11 OR c=13 OR c=26 OR c=37 OR c=48 OR c=61 OR c=62 OR c=68 THEN GO TO 8100 8025 REM Store code routine 'c' 8030 IF c>=28 AND c<=33 THEN LET c=35: GO SUB dump: POKE pc-3,oldc-12: RETURN : REM Handle INK, PAPER etc alike 8032 REM dump (template No. c) 8035 LET j=bottom+c*2: LET t=j: GO SUB deek: LET i=t: LET t=j+2: GO SUB deek: LET j=t-i 8045 IF pc+j>=tp THEN GO TO too big 8050 LET peep=peep AND PEEK (i)=225: IF peep THEN LET pc=pc-2 8055 FOR t=1+peep TO j: POKE t+pc,PEEK (i+t-1): NEXT t: LET pc=pc+j 8060 LET peep=PEEK pc=229: RETURN 8100 GO SUB dump: LET t=oldt 8105 IF c=1 THEN LET i=pc-2: LET t=vars+8*t: GO SUB doke: RETURN 8110 IF c=2 THEN LET i=pc-2: GO SUB doke: RETURN 8115 IF c=3 THEN LET i=pc-9: LET t=a(t+1): GO SUB doke: RETURN 8120 IF c=4 OR c=5 OR c=48 THEN GO SUB request: RETURN 8125 IF c<>7 THEN GO TO 8142 8130 LET t1=t*8+vars: LET i=pc-15: LET t=t1+2: GO SUB doke: LET i=pc-11: LET t=t1+4: GO SUB doke 8135 LET i=pc-7: LET t=t1: GO SUB doke: LET i=pc-4: LET t=pc+1: GO SUB doke 8140 LET i=pc-1: LET t=t1+6: GO SUB doke: RETURN 8142 IF c<>61 THEN GO TO 8150 8144 LET t1=t*8+vars: LET i=pc-11: LET t=t1+4: GO SUB doke 8146 LET i=pc-7: LET t=t1: GO SUB doke: LET i=pc-4: LET t=pc+1: GO SUB doke 8148 LET i=pc-1: LET t=t1+6: GO SUB doke: RETURN 8150 IF c<>8 THEN GO TO 8170 8155 LET t1=vars+t*8: LET i=pc-28: LET t=t1: GO SUB doke: LET i=pc-24: LET t=t1+2: GO SUB doke 8160 LET i=pc-20: LET t=t1: GO SUB doke: LET i=pc-16: LET t=t1+4: GO SUB doke: LET i=pc-2: LET t=t1+6: GO SUB doke: RETURN 8170 IF c<>62 THEN GO TO 8180 8172 LET t1=vars+t*8: LET i=pc-18: LET t=t1: GO SUB doke: LET i=pc-14: LET t=t1: GO SUB doke 8174 LET i=pc-10: LET t=t1+4: GO SUB doke: LET i=pc-2: LET t=t1+6: GO SUB doke: RETURN 8180 IF c=11 THEN LET i=pc-1: LET t=vars+8*t: GO SUB doke: RETURN 8185 IF c=13 THEN LET i=pc-7: LET t=a(t+1): GO SUB doke: RETURN 8190 IF c<>26 THEN GO TO 8205 8192 LET i=0 8194 LET i=i+1: IF PEEK (t+i)<>quote THEN GO TO 8194 8196 IF i+pc>=tp THEN GO TO too big 8200 LET pc=pc+1: FOR j=0 TO i: POKE pc+j,PEEK (t+j): NEXT j: LET pc=pc+i: RETURN 8205 IF c=37 THEN LET i=pc-4: LET t=pc: GO SUB doke: RETURN 8210 IF c=68 THEN LET t=bottom+c*2-2: GO SUB deek: LET i=t+1: LET t=top-8: GO SUB doke: RETURN 8280 REM ZIP OPTIMISATION MODULE 8285 REM Alter common code pairs 8290 REM 8300 IF oldc=VAL "2" THEN IF c=VAL "47" THEN LET pc=pc-VAL "1": POKE pc-VAL "2",VAL "62": POKE pc,VAL "215": RETURN : REM PRINT CHR$ num 8305 IF oldc<>VAL "2" OR cVAL "18" THEN GO TO VAL "8010": REM Const. op? 8310 IF oldtNOT PI THEN IF c=VAL "16" OR c=VAL "17" THEN FOR i=pc-VAL "4" TO pc-VAL "5"+oldt: POKE i,VAL "35"+VAL "8"*(c=VAL "17"): NEXT i: LET pc=pc-VAL "4"+oldt: GO TO VAL "8400": REM ADD/SUB number 1 to 6 8315 IF oldt=VAL "256" THEN IF c=VAL "18" THEN RESTORE VAL "8315": FOR i=pc-VAL "4" TO pc+VAL "7": READ j: POKE i,j: NEXT i: LET pc=pc+VAL "8": GO TO VAL "8400": DATA VAL "203",VAL "124",VAL "40",VAL "1",VAL "43",VAL "108",VAL "38",NOT PI,VAL "40",VAL "2",VAL "37",VAL "35" 8320 IF c=VAL "18" THEN IF oldt>VAL "1" THEN IF oldtVAL "15" THEN GO TO VAL "8010" 8330 IF oldt=VAL "256" THEN LET pc=pc-VAL "1": POKE pc-VAL "3",VAL "101": POKE pc-VAL "2",VAL "46": POKE pc-VAL "1",NOT PI: GO TO VAL "8400" 8335 IF oldtVAL "100" THEN GO TO VAL "8010" 8340 LET pc=pc-VAL "5": LET j=NOT PI 8345 IF oldt=VAL "1" THEN FOR i=VAL "1" TO j: LET pc=pc+VAL "2": POKE pc-VAL "1",VAL "209": POKE pc,VAL "25": NEXT i: LET pc=pc+VAL "1": GO TO VAL "8400" 8350 LET oldt=oldt/VAL "2": IF oldt<>INT oldt THEN LET oldt=INT oldt: LET j=j+VAL "1": LET pc=pc+VAL "1": POKE pc,VAL "229" 8355 LET pc=pc+VAL "1": POKE pc,VAL "41": GO TO VAL "8345" 8400 POKE pc,VAL "229": LET oldc=NOT PI: RETURN ```