TITLE TENTH EXPUNGE .SWAP,.BEGIN,.END,.ELSE,.I IFNDEF TS,TS==0 IFNDEF KA,KA==0 IFNDEF KS,KS==1 IFN TS+KA+KS-1,.ERR Must assemble for one of TS, KA, or KS. X=14 ; pointer into code/parameter field PC=15 ; the interpreter's program counter PP=16 ; parameter stack pointer P=17 ; return stack pointer IFN KS,[ APR=0 CTYIN=32 CTYOUT=33 ] IFN KA,[ TTY=120 ] IFN TS,[ TYIC==1 TYOC==2 ] PDLLEN=100 PDL: .=.+PDLLEN PPDL: .=.+PDLLEN RSP: -PDLLEN,,PDL-1 PSP: -PDLLEN,,PPDL-1 INP: 0 INBUF: 0 ? .=.+40 INBUFBP: 440700,,INBUF+1 WORDBUF: 0 ? .=.+10 WORDBP: 440700,,WORDBUF+1 START: IFN KS, SETZM CTYIN IFN TS,[ .OPEN TYIC,[.UAI,,'TTY] .LOSE .OPEN TYOC,[.UAO,,'TTY] .LOSE .CALL [ SETZ ; turn off echoing SIXBIT /TTYSET/ MOVEI TYIC MOVE [030202,,020202] SETZ [030202,,020202] ] ] MOVE P,RSP MOVE PP,PSP MOVEI PC,[.QUIT] JRST NEXT ; ; output ; ; print ASCII character in AC 0 - changes AC 0 PUTCHAR: IFN KS,[ IORI 0,400 ; valid bit MOVEM 0,CTYOUT CONO APR,12000 ; 10000 = set flags, 2000 = interrupt flag SKIPE CTYOUT ; wait for transmission to complete JRST .-1 ] IFN KA,[ CONSZ TTY,20 JRST .-1 DATAO TTY,0 ] IFN TS, .IOT TYOC,0 CAIE 0,IFN KS,[400\]^J POPJ P, MOVEI 0,^M JRST PUTCHAR ; print null-terminated ASCII string in AC 0 - changes AC 0 1 PUTS: MOVE 1,0 ; address HRLI 1,440700 ; 7-bit bytes ILDB 0,1 CAIN 0,0 POPJ P, PUSHJ P,PUTCHAR JRST .-4 ; prints a counted ASCII string in AC 0 PUTSN: MOVE 2,@0 ; char count AOS 0 MOVE 1,0 HRLI 1,440700 PUTSN1: SOSGE 2 POPJ P, ILDB 0,1 PUSHJ P,PUTCHAR JRST PUTSN1 ; print 'panic' and halt PANIC: MOVEI 0,[ ASCIZ " panic " ] PUSHJ P,PUTS JRST 4,. BASE: 12 DIGITS: "0 ? "1 ? "2 ? "3 ? "4 ? "5 ? "6 ? "7 ? "8 ? "9 ? "A ? "B ? "C ? "D ? "E ? "F ; print number in AC 1 - changes AC 0 1 2 PRINTN: JUMPGE 1,UPRINTN MOVEI 0,"- PUSHJ P,PUTCHAR MOVM 1,1 UPRINTN: IDIV 1,BASE JUMPE 1,UPR1 PUSH P,2 PUSHJ P,UPRINTN POP P,2 UPR1: MOVE 0,DIGITS(2) JRST PUTCHAR ; prints number in AC 1 and a space - changes AC 0 1 PRNTNSP: PUSHJ P,PRINTN MOVEI 0,40 ; space JRST PUTCHAR ; reads one character into AC 0 GETCH: IFN KS,[ CONO APR,12000 ; 10000 = set flags, 2000 = interrupt flag MOVE 0,CTYIN CAIN 0,0 JRST .-2 SETZM CTYIN TRZ 0,400 ] IFN KA,[ CONSO TTY,40 JRST .-1 DATAI TTY,0 ] IFN TS, .IOT TYIC,0 CAIN 0,^M MOVEI 0,^J POPJ P, ; ; input ; ; reads one character into AC 0 and echos - changes AC 0 1 GETCHAR: PUSHJ P,GETCH MOVE 1,0 PUSHJ P,PUTCHAR MOVE 0,1 POPJ P, ; reads characters into INBUF - changes AC 0 1 2 GETS: SETZM INP MOVE 1,INBUFBP SETZ 2, NEXTC: PUSHJ P,GETCH CAIN 0,^J JRST GETSNL CAIN 0,25 JRST GETSKL CAIN 0,^H JRST GETSBS IDPB 0,1 AOS 2 PUSHJ P,PUTCHAR JRST NEXTC GETSKL: ; kill line MOVEI 0,^J PUSHJ P,PUTCHAR JRST GETS GETSBS: ; backspace PUSHJ P,PUTCHAR MOVE 1,INBUFBP SOSGE 2 SETZ 2, MOVE 0,2 SOSGE 0 JRST NEXTC IBP 1 JRST .-3 GETSNL: MOVEI 0,40 ; space PUSHJ P,PUTCHAR SETZ 0, IDPB 0,1 MOVEM 2,INBUF POPJ P, ; ; forth things ; ; Code field values ASM: AOS X JRST (X) DOCON: AOS X MOVE 0,(X) PUSH PP,0 JRST NEXT DOVAR: AOS X PUSH PP,X JRST NEXT DOCOL: AOS X PUSH P,PC MOVE PC,X JRST NEXT ; counterpart of DOCOL ..EXIT: 0 ? 0,,4 ? ASCII "EXIT" .EXIT: ASM POP P,PC JRST NEXT ; execute forth word at PC and increment PC NEXT: MOVE X,(PC) AOS PC MOVE 1,(X) JRST (1) ; Dictionary LATEST: .LATEST HERE: END1 ; parses one word from the input stream into the word buffer ; skips if a word was read PARSEWORD: SETZM WORDBUF MOVE 0,INP MOVE 1,INBUFBP SOSGE 0 JRST .+3 IBP 1 JRST .-3 POP PP,2 ; terminator MOVE 0,INP PWDELIM: ILDB 3,1 AOS 0 CAMLE 0,INBUF ; check length JRST PWEND CAMN 3,2 ; check for delimiter JRST PWDELIM MOVEM 0,INP ; save beginning of word MOVE 4,WORDBP PWCHAR: IDPB 3,4 ILDB 3,1 AOS 0 CAMLE 0,INBUF ; check length JRST .+3 CAME 3,2 ; check for delimiter JRST PWCHAR MOVE 1,INP SUB 1,0 MOVMM 1,WORDBUF PWEND: MOVEM 0,INP SKIPE WORDBUF ; skip one instruction if we have a word AOS (P) POPJ P, ; find word AC 1 in dictionary, skip if found at return it in AC 1 FIND: MOVE 2,LATEST SKIPA FINDNEXT: MOVE 2,(2) SKIPN 2 POPJ P, ; not found HRRZ 0,1(2) ; length CAME 0,(1) JRST FINDNEXT MOVEI 3,1(1) ; byte pointer of word to look up HRLI 3,440700 MOVEI 4,2(2) ; byte pointer of word in dictionary HRLI 4,440700 FINDLOOP: ILDB 5,3 ILDB 6,4 CAME 5,6 JRST FINDNEXT SOJG 0,FINDLOOP ; found MOVE 1,2 AOS (P) POPJ P, ; go from dictionary entry AC 1 to code field TCFA: HRRZ 0,1(1) ; length MOVEI 2,2(1) ; byte pointer HRLI 2,440700 IBP 2 SOJG 0,.-1 HRRZ 1,4 ; get word address from byte pointer HLRZ 0,4 CAIE 0,440700 ; go to next word unless we're already there AOS 1 POPJ P, ; parse number in string AC 1, skip if number and return it in AC 0 CHECKNUM: SETZ 0, MOVE 2,(1) ; length AOS 1 HRLI 1,440700 ; byte pointer SETZ 4, ; sign ILDB 3,1 CAIE 3,"- JRST .+5 SOSN 2 POPJ P, AOS 4 NUM1: ILDB 3,1 CAIGE 3,"0 POPJ P, CAILE 3,"9 JRST .+3 SUBI 3,"0 JRST NUM2 CAIGE 3,"A POPJ P, CAILE 3,"F JRST .+3 SUBI 3,"A JRST NUM2 CAIGE 3,"a POPJ P, CAILE 3,"f POPJ P, SUBI 3,"a NUM2: IMUL 0,BASE ADD 0,3 SOJG 2,NUM1 SKIPE 4 ; negate if sign is set MOVN 0,0 AOS (P) POPJ P, STATE: 0 ; interpreter state (0 = interpreting, else compiling) ..INTERPRET: ..EXIT ? 0,,9 ? ASCII "INTERPRET" .INTERPRET: ASM SKIPN INBUF PUSHJ P,GETS NEXTW: MOVEI 0,40 ; space PUSH PP,0 PUSHJ P,PARSEWORD JRST OK ; end of line MOVEI 1,WORDBUF PUSHJ P,FIND JRST NUMBER HLR X,1(1) ; get flags PUSHJ P,TCFA JUMPN X,.+3 ; immediate SKIPE STATE JRST COMPW ; compile word MOVE X,1 ; interpret word MOVE 1,(X) JRST (1) COMPW: MOVE 2,HERE MOVEM 1,(2) AOS HERE JRST NEXTW NUMBER: MOVEI 1,WORDBUF PUSHJ P,CHECKNUM JRST PANIC SKIPE STATE JRST COMPN ; compile number PUSH PP,0 ; interpret number JRST NEXTW COMPN: MOVE 1,HERE MOVEI 2,.LITERAL MOVEM 2,(1) MOVEM 0,1(1) AOS HERE AOS HERE JRST NEXTW OK: SKIPE STATE JRST .+3 MOVEI 0,[ASCIZ " ok "] JRST .+2 MOVEI 0,[ASCIZ " compiled "] PUSHJ P,PUTS JRST NEXTW-1 ..QUIT: ..INTERPRET ? 0,,4 ? ASCII "QUIT" .QUIT: DOCOL [ ASM ? MOVE P,RSP ? JRST NEXT ] .INTERPRET .BRANCH -2 ..ABORT: ..QUIT ? 0,,5 ? ASCII "ABORT" .ABORT: DOCOL [ ASM ? MOVE PP,PSP ? JRST NEXT ] .QUIT ..CREATE: ..ABORT ? 0,,6 ? ASCII "CREATE" .CREATE: ASM PUSHJ P,CREATE JRST NEXT CREATE: MOVEI 0,40 ; space PUSH PP,0 PUSHJ P,PARSEWORD JRST PANIC MOVE 1,LATEST MOVE 2,HERE MOVEM 1,(2) ; link into dict MOVEM 2,LATEST MOVEI 1,WORDBUF ; copy word HRRZ 0,0(1) ; length MOVEM 0,1(2) MOVEI 3,1(1) ; byte pointer of word buffer HRLI 3,440700 MOVEI 4,2(2) ; byte pointer of word in dictionary HRLI 4,440700 ILDB 5,3 ; copy chars IDPB 5,4 SOJG 0,.-2 HRRZ 1,4 ; get word address from byte pointer HLRZ 0,4 CAIE 0,440700 ; go to next word unless we're already there AOS 1 MOVEM 1,HERE POPJ P, ..COLON: ..CREATE ? 0,,1 ? ASCII ":" .COLON: DOCOL .CREATE .LITERAL ? DOCOL ? .COMMA .RBRK .EXIT ..SEMICOLON: ..COLON ? 1,,1 ? ASCII ";" .SEMICOLON: DOCOL .LITERAL ? .EXIT ? .COMMA .LBRK .EXIT ..CONST: ..SEMICOLON ? 0,,8 ? ASCII "CONSTANT" .CONST: DOCOL .CREATE .LITERAL ? DOCON ? .COMMA .COMMA .EXIT ..VAR: ..CONST ? 0,,8 ? ASCII "VARIABLE" .VAR: DOCOL .CREATE .LITERAL ? DOVAR ? .COMMA .LITERAL ? 0 ? .COMMA .EXIT ..BRANCH: ..VAR ? 0,,6 ? ASCII "BRANCH" .BRANCH: ASM MOVE 0,(PC) ADD PC,0 JRST NEXT ..ZBRANCH: ..BRANCH ? 0,,7 ? ASCII "0BRANCH" .ZBRANCH: ASM POP PP,1 SKIPE 1 JRST .+4 MOVE 0,(PC) ADD PC,0 JRST NEXT AOS PC JRST NEXT ..LITERAL: ..ZBRANCH ? 0,,9 ? ASCII "(LITERAL)" .LITERAL: ASM MOVE 0,(PC) AOS PC PUSH PP,0 JRST NEXT ..COMMA: ..LITERAL ? 0,,1 ? ASCII "," .COMMA: ASM MOVE 1,HERE POP PP,0 MOVEM 0,(1) AOS HERE JRST NEXT ..LBRK: ..COMMA ? 0,,1 ? ASCII "[" .LBRK: ASM SETZM STATE JRST NEXT ..RBRK: ..LBRK ? 0,,1 ? ASCII "]" .RBRK: ASM MOVEI 0,1 MOVEM 0,STATE JRST NEXT ..IMMED: ..RBRK ? 0,,9 ? ASCII "IMMEDIATE" .IMMED: ASM MOVE 1,LATEST MOVS 0,1 XORM 0,1(1) JRST NEXT ..DOT: ..IMMED ? 0,,1 ? ASCII "." .DOT: ASM POP PP,1 PUSHJ P,PRNTNSP JRST NEXT ..DOTS: ..DOT ? 0,,2 ? ASCII ".S" .DOTS: ASM MOVEI 0,"< PUSHJ P,PUTCHAR HRRZ 1,PP SUBI 1,PPDL-1 MOVN 3,1 ; loop counter PUSHJ P,PRINTN MOVEI 0,"> PUSHJ P,PUTCHAR SKIPN 3 JRST NEXT ; empty stack MOVS 3,3 ; put counter in left word HRRI 3,PPDL MOVEI 0,40 PUSHJ P,PUTCHAR MOVE 1,(3) PUSHJ P,PRNTNSP AOBJN 3,.-2 JRST NEXT ..DROP: ..DOTS ? 0,,4 ? ASCII "DROP" .DROP: ASM POP PP,0 JRST NEXT ..SWAP: ..DROP ? 0,,4 ? ASCII "SWAP" .SWAP: ASM POP PP,0 EXCH 0,(PP) PUSH PP,0 JRST NEXT ..DUP: ..SWAP ? 0,,3 ? ASCII "DUP" .DUP: ASM PUSH PP,(PP) JRST NEXT ..QDUP: ..DUP ? 0,,4 ? ASCII "?DUP" .QDUP: ASM SKIPE (PP) PUSH PP,(PP) JRST NEXT ..OVER: ..QDUP ? 0,,4 ? ASCII "OVER" .OVER: ASM PUSH PP,-1(PP) JRST NEXT ..ROT: ..OVER ? 0,,3 ? ASCII "ROT" .ROT: ASM POP PP,0 POP PP,1 POP PP,2 PUSH PP,1 PUSH PP,0 PUSH PP,2 JRST NEXT ..NROT: ..ROT ? 0,,4 ? ASCII "-ROT" .NROT: ASM POP PP,0 POP PP,1 POP PP,2 PUSH PP,0 PUSH PP,2 PUSH PP,1 JRST NEXT ..TOR: ..NROT ? 0,,2 ? ASCII ">R" .TOR: ASM POP PP,0 PUSH P,0 JRST NEXT ..FROMR: ..TOR ? 0,,2 ? ASCII "R>" .FROMR: ASM POP P,0 PUSH PP,0 JRST NEXT ..FTCH: ..FROMR ? 0,,2 ? ASCII "R@" .FTCHR: ASM MOVE 0,(P) PUSH PP,0 JRST NEXT ..RSP: ..FTCH ? 0,,4 ? ASCII "RSP@" .RSP: ASM PUSH PP,P JRST NEXT ..INCR: ..RSP ? 0,,2 ? ASCII "1+" .INCR: ASM AOS (PP) JRST NEXT ..DECR: ..INCR ? 0,,2 ? ASCII "1-" .DECR: ASM SOS (PP) JRST NEXT ..PLUS: ..DECR ? 0,,1 ? ASCII "+" .PLUS: ASM POP PP,0 ADDM 0,(PP) JRST NEXT ..MINUS: ..PLUS ? 0,,1 ? ASCII "-" .MINUS: ASM POP PP,0 POP PP,1 SUB 1,0 PUSH PP,1 JRST NEXT ..MUL: ..MINUS ? 0,,1 ? ASCII "*" .MUL: ASM POP PP,0 IMULM 0,(PP) JRST NEXT ..DIVMOD: ..MUL ? 0,,4 ? ASCII "/MOD" .DIVMOD: ASM POP PP,1 POP PP,0 IDIV 0,1 PUSH PP,1 PUSH PP,0 JRST NEXT ..DIV: ..DIVMOD ? 0,,1 ? ASCII "/" .DIV: ASM POP PP,1 POP PP,0 IDIV 0,1 PUSH PP,0 JRST NEXT ..MOD: ..DIV ? 0,,3 ? ASCII "MOD" .MOD: ASM POP PP,1 POP PP,0 IDIV 0,1 PUSH PP,1 JRST NEXT ..EQU: ..MOD ? 0,,1 ? ASCII "=" .EQU: ASM POP PP,0 CAME 0,(PP) JRST FALSE TRUE: SETOM (PP) JRST NEXT FALSE: SETZM (PP) JRST NEXT ..NEQU: ..EQU ? 0,,2 ? ASCII "<>" .NEQU: ASM POP PP,0 CAMN 0,(PP) JRST FALSE JRST TRUE ..LT: ..NEQU ? 0,,1 ? ASCII "<" .LT: ASM POP PP,0 CAMG 0,(PP) JRST FALSE JRST TRUE ..LE: ..LT ? 0,,2 ? ASCII "<=" .LE: ASM POP PP,0 CAMGE 0,(PP) JRST FALSE JRST TRUE ..GT: ..LE ? 0,,1 ? ASCII ">" .GT: ASM POP PP,0 CAML 0,(PP) JRST FALSE JRST TRUE ..GE: ..GT ? 0,,2 ? ASCII ">=" .GE: ASM POP PP,0 CAMLE 0,(PP) JRST FALSE JRST TRUE ..ZEQU: ..GE ? 0,,2 ? ASCII "0=" .ZEQU: ASM SKIPE (PP) JRST FALSE JRST TRUE ..ZNEQU: ..ZEQU ? 0,,3 ? ASCII "0<>" .ZNEQU: ASM SKIPN (PP) JRST FALSE JRST TRUE ..ZLT: ..ZNEQU ? 0,,2 ? ASCII "0<" .ZLT: ASM SKIPL (PP) JRST FALSE JRST TRUE ..ZLE: ..ZLT ? 0,,3 ? ASCII "0<=" .ZLE: ASM SKIPLE (PP) JRST FALSE JRST TRUE ..ZGT: ..ZLE ? 0,,2 ? ASCII "0>" .ZGT: ASM SKIPG (PP) JRST FALSE JRST TRUE ..ZGE: ..ZGT ? 0,,3 ? ASCII "0>=" .ZGE: ASM SKIPGE (PP) JRST FALSE JRST TRUE ..AND: ..ZGE ? 0,,3 ? ASCII "AND" .AND: ASM POP PP,0 ANDM 0,(PP) JRST NEXT ..OR: ..AND ? 0,,2 ? ASCII "OR" .OR: ASM POP PP,0 IORM 0,(PP) JRST NEXT ..XOR: ..OR ? 0,,3 ? ASCII "XOR" .XOR: ASM POP PP,0 XORM 0,(PP) JRST NEXT ..NOT: ..XOR ? 0,,3 ? ASCII "NOT" .NOT: ASM ; same as 0= SKIPE (PP) JRST FALSE JRST TRUE ..ABS: ..NOT ? 0,,3 ? ASCII "ABS" .ABS: ASM MOVM 0,(PP) MOVEM 0,(PP) JRST NEXT ..NEG: ..ABS ? 0,,6 ? ASCII "NEGATE" .NEG: ASM MOVN 0,(PP) MOVEM 0,(PP) JRST NEXT ..MIN: ..NEG ? 0,,3 ? ASCII "MIN" .MIN: ASM POP PP,0 CAMGE 0,(PP) MOVEM 0,(PP) JRST NEXT ..MAX: ..MIN ? 0,,3 ? ASCII "MAX" .MAX: ASM POP PP,0 CAMLE 0,(PP) MOVEM 0,(PP) JRST NEXT ..WORD: ..MAX ? 0,,4 ? ASCII "WORD" .WORD: ASM PUSHJ P,PARSEWORD JRST .+1 PUSH PP,WORDBUF JRST NEXT ..STORE: ..WORD ? 0,,1 ? ASCII "!" .STORE: ASM POP PP,1 POP PP,0 MOVEM 0,(1) JRST NEXT ..PSTORE: ..STORE ? 0,,2 ? ASCII "+!" .PSTORE: ASM POP PP,1 POP PP,0 ADDM 0,(1) JRST NEXT ..FETCH: ..PSTORE ? 0,,1 ? ASCII "@" .FETCH: ASM MOVE 1,(PP) MOVE 1,(1) MOVEM 1,(PP) JRST NEXT ..HERE: ..FETCH ? 0,,4 ? ASCII "HERE" .HERE: DOCON ? HERE ..STATE: ..HERE ? 0,,5 ? ASCII "STATE" .STATE: DOCON ? STATE ..BASE: ..STATE ? 0,,4 ? ASCII "BASE" .BASE: DOCON ? BASE ..INP: ..BASE ? 0,,3 ? ASCII ">IN" .INP: DOCON ? INP ..IF: ..INP ? 1,,2 ? ASCII "IF" .IF: DOCOL .LITERAL ? .ZBRANCH ? .COMMA .HERE ? .FETCH .LITERAL ? 0 ? .COMMA .EXIT ..THEN: ..IF ? 1,,4 ? ASCII "THEN" .THEN: DOCOL .DUP .HERE ? .FETCH ? .SWAP ? .MINUS .SWAP ? .STORE .EXIT ..ELSE: ..THEN ? 1,,4 ? ASCII "ELSE" .ELSE: DOCOL .LITERAL ? .BRANCH ? .COMMA .HERE ? .FETCH .LITERAL ? 0 ? .COMMA .SWAP .DUP .HERE ? .FETCH ? .SWAP ? .MINUS .SWAP ? .STORE .EXIT ..BEGIN: ..ELSE ? 1,,5 ? ASCII "BEGIN" .BEGIN: DOCOL .HERE ? .FETCH .EXIT ..AGAIN: ..BEGIN ? 1,,5 ? ASCII "AGAIN" .AGAIN: DOCOL .LITERAL ? .BRANCH ? .COMMA .HERE ? .FETCH ? .MINUS ? .COMMA .EXIT ..UNTIL: ..AGAIN ? 1,,5 ? ASCII "UNTIL" .UNTIL: DOCOL .LITERAL ? .ZBRANCH ? .COMMA .HERE ? .FETCH ? .MINUS ? .COMMA .EXIT ; same as IF really ..WHILE: ..UNTIL ? 1,,5 ? ASCII "WHILE" .WHILE: DOCOL .LITERAL ? .ZBRANCH ? .COMMA .HERE ? .FETCH .LITERAL ? 0 ? .COMMA .EXIT ..REPEAT: ..WHILE ? 1,,6 ? ASCII "REPEAT" .REPEAT: DOCOL .LITERAL ? .BRANCH ? .COMMA .SWAP .HERE ? .FETCH ? .MINUS ? .COMMA .DUP .HERE ? .FETCH ? .SWAP ? .MINUS .SWAP ? .STORE .EXIT ..DO: ..REPEAT ? 1,,2 ? ASCII "DO" .DO: DOCOL .LITERAL ? .SWAP ? .COMMA .LITERAL ? .TOR ? .COMMA .LITERAL ? .TOR ? .COMMA .HERE ? .FETCH .EXIT ; remove index and limit from return stack ..UNLOOP: ..DO ? 0,,6 ? ASCII "UNLOOP" .UNLOOP: ASM POP P,0 POP P,0 JRST NEXT ..LOOP: ..UNLOOP ? 1,,4 ? ASCII "LOOP" .LOOP: DOCOL .LITERAL ? .FROMR ? .COMMA ; index .LITERAL ? .INCR ? .COMMA .LITERAL ? .DUP ? .COMMA .LITERAL ? .FTCHR ? .COMMA ; limit .LITERAL ? .GE ? .COMMA ; branch back if i >= limit is false .LITERAL ? .SWAP ? .COMMA ; put index back on return stack .LITERAL ? .TOR ? .COMMA .LITERAL ? .ZBRANCH ? .COMMA .HERE ? .FETCH ? .MINUS ? .COMMA .LITERAL ? .UNLOOP ? .COMMA .EXIT ..PLULOOP: ..LOOP ? 1,,5 ? ASCII "+LOOP" .PLUSLOOP: DOCOL .LITERAL ? .FROMR ? .COMMA ; index .LITERAL ? .PLUS ? .COMMA ; only difference to above code .LITERAL ? .DUP ? .COMMA .LITERAL ? .FTCHR ? .COMMA ; limit .LITERAL ? .GE ? .COMMA ; branch back if i >= limit is false .LITERAL ? .SWAP ? .COMMA ; put index back on return stack .LITERAL ? .TOR ? .COMMA .LITERAL ? .ZBRANCH ? .COMMA .HERE ? .FETCH ? .MINUS ? .COMMA .LITERAL ? .UNLOOP ? .COMMA .EXIT ..I: ..PLULOOP ? 0,,1 ? ASCII "I" .I: ASM MOVE 0,(P) PUSH PP,0 JRST NEXT ..J: ..I ? 0,,1 ? ASCII "J" .J: ASM MOVE 0,2(P) PUSH PP,0 JRST NEXT ..EMIT: ..J ? 0,,4 ? ASCII "EMIT" .EMIT: ASM POP PP,0 PUSHJ P,PUTCHAR JRST NEXT ..KEY: ..EMIT ? 0,,3 ? ASCII "KEY" .KEY: ASM PUSHJ P,GETCH PUSH PP,0 JRST NEXT ..CR: ..KEY ? 0,,2 ? ASCII "CR" .CR: DOCOL .LITERAL ? ^J .EMIT .EXIT .LATEST: ..SP: ..KEY ? 0,,5 ? ASCII "SPACE" .SP: DOCOL .LITERAL ? 40 .EMIT .EXIT END1: END START