Code: Select all
/ ** FORTH-8 **
/FORTH COMPILER/INTERPRETER
/FOR TSS/8.24 PAL/D assembler
/STARTED 29-JUL-84
/BY JOHN WILSON.
/
*0
  JMP START
/BETCHA DIDN'T KNOW YOU COULD JUMP-START A PROGRAM!
/
FIXTAB  BSW=  7002
/
JUMP=  JMS I .
  JUMP0  /JUMP TO ADDRESS FOLLOWING JMS
CALL=  JMS I .
  CALL0  /CALL TO ADDR FOLLOWING JMS, USING STACK
RET=  JMP I .
  RET0  /POP VALUE OFF STACK, JUMP TO IT
RPUSH=  JMS I .
  RPUSH0  /PUSH AC TO RETURN STACK
RPOP=  JMS I .
  RPOP0  /POP RETURN STACK TO AC
PPUSH=  JMS I .
  PPUSH0  /PUSH AC TO PARAMETER STACK
PPOP=  JMS I .
  PPOP0  /POP PARAMETER STACK TO AC
*10
INDEX1,  0  /SCRATCH AUTO-INDEXING POINTER
INDEX2,  0
INDEX3,  0
/CONSTANTS:
C0007,  7
C0027,  27
C0077,  77
C0240,  240
C7540,  7540
*20
DP,  USRDCT  /DICTIONARY PTR
IMMDP,  ICODE  /DICT PTR INTO IMMEDIATE BUFFER
/
SP,  0  /RETURN STACK POINTER
PSP,  0  /PARAMETER STACK POINTER
NSP,  0  /NESTING STACK POINTER
/
/TEMPORARY VARIABLES:
TEMP1,  0
TEMP2,  0
TEMP3,  0
TEMP4,  0
TEMP5,  0
/
ERROR=  JMS I .
  ERROR0  /PRINT TRIMMED ASCII ERROR MESSAGE AFTER JMS, & ABORT
PPUSHC=  JMS I .
  PPC0  /PUSH CONSTANT AFTER JMS TO PARAMETER STACK
NPUSH=  JMS I .
  NPUSH0  /PUSH AC AND WORD AFTER JMS TO NESTING STACK
NPOP=  JMS I .
  NPOP0  /CHECK FOR MATCH WITH WORD AFTER JMS, POP AC FROM NSTACK
DCTVAL=  JMS I .
  DCTVA0  /PUT AC IN DICT (ONLY), AND ADVANCE DP
DCTCON=  JMS I .
  DCTCO0  /PUT WORD FOLLOWING JMS IN DICT, ADVANCE DP
PUTVAL=  JMS I .
  PUTVA0  /PUT AC IN CURRENT BUFFER, AND ADVANCE PTR
PUTCON=  JMS I .
  PUTCO0  /PUT WORD FOLLOWING JMS IN CURR BUFF, & ADVANCE PTR
TYPE=  JMS I .
  TYPE0  /TYPE .ASCIZ STRING FOLLOWING JMS
PRINT=  JMS I .
  PRINT0  /PRINT CHAR IN AC, UPDATE PRCOL
CRLF=  JMS I .
  CRLF0  /PRINT CR, LF
RTS=  JMP I .
  DOWORD  /DO NEXT WORD (RETURN FROM TSTRU'S)
RUNIMM=  JMS I .
  RUNIM0  /RUN IMMEDIATE CODE, IF ANY
CURRDP=  JMS I .
  CURRD0  /RETURN DP FOR CURRENT BUFFER (SELON INWORD)
IF=  JMS I .
WHILE=  JMS I .
UNTIL=  JMS I .
  JUMPZ  /PPOP, JUMP TO @PC IF ZERO
DO=  JMS I .
  DO0  /COPY TOP TWO ARGS ON PSTACK TO RSTACK
LOOP=  JMS I .
  LOOP0  /INC @RSP, LOOP IF NOT EQUAL TO @RSP+1, ELSE CLEAR RSTACK
/
/NESTING STACK TOKENS:
TIF=  1  /IF-ELSE-THEN
TBEGIN=  2  /BEGIN-UNTIL, BEGIN-WHILE-REPEAT, BEGIN-AGAIN
TWHILE=  3  /BEGIN-WHILE-REPEAT
TDO=  4  /DO-LOOP, DO-+LOOP, DO-/LOOP
/
PRCOL,  0  /CURRENT PRINTING COLUMN (FOR TABS)
KBFILE,  0  /<>0 -> REDIRECTING KB INPUT FROM CHANNEL 0 (LOAD)
INWORD,  0  /<>0 -> COMPILING A WORD (: ... ;)
NLEVEL,  0  /CURRENT NESTING LEVEL
CARETF,  0  /<>0 -> PRINT "^" UNDER LAST WORD READ ON ERROR
ERRCOL,  0  /ADDR OF BEGN OF LAST WORD READ FROM LINE (FOR "^" ON ERR)
PROMPT,  0  /<>0 -> PROMPT WITH "OK" (ONLY IF THINGS ARE OKAY!)
DELFLG,  0  /<>0 -> BETWEEN \'S (ON INPUT)
LINPTR,  LINE  /PTR TO NEXT WORD IN LINE
/
M0211,  -211
WORDM1,  WORD-1
CLINE,  LINE
CWORD,  WORD
LOOKUP,  LOOKU0  /PTR TO LOOKUP ROUTINE
MAKEW,  MAKEW0  /PTR TO ROUTINE TO BUILD A WORD HEADER
GETWRD,  GETW  /PTR TO ROUTINE TO READ A WORD FROM THE KB
SMUDGE,  0  /PTR TO LINK TO LAST CREATED WORD (ZEROED ON ERR)
/
/INITIALIZE POINTERS, SET ^C VECTOR
  CTRLC  /^C VECTOR
START,  CLA+400    /=7600 (RSTACK/PSTACK BOUNDARY)
  TAD .-2    /GET ^C VECTOR
  SRA    /SET IT
  UND    /TURN OFF ECHO
  STA    /SET KB BREAK
  KSB    /TO ANYTHING
  TYPE    /PRINT "FORTH-8 BY JOHN WILSON"
  "F;"O+40;"R+40;"T+40;"H+40;"-;"8;240;240 /KINKY LOWER CASE
  "B+40;"Y+40;240;"J;"O+40;"H+40;"N+40;240
  "W;"I+40;"L+40;"S+40;"O+40;"N+40
  215;212;0  /CR,LF,<NUL>
/
RESET,  TAD START  /LOAD 7600
  DCA PSP    /SET PSTACK PTR
CTRLC,  CLA    /JUMP HERE ON ^C
  DCA I LINPTR  /FORCE KB READ ON NEXT GETW
  TAD ICODE0  /GET PTR TO IMM CODE
  DCA IMMDP  /POKE IT TO PTR
  DCA NSP    /SET NSTACK PTR
  DCA SP    /SET RSTACK PTR
  IAC    /SET BIT FOR CHAN 0 (KB REDIRECTION)
  ISZ KBFILE  /REDIRECTING INPUT?
  SKP CLA    /NO, DON'T WASTE FIP'S TIME
  CLOS    /YES, CLOSE THE FILE
  DCA KBFILE  /ANYWAY, WE'RE NOT NOW
  TAD SMUDGE  /KILL LAST WORD?
  SNA CLA
  JMP .+5    /NO, CONTINUE
  TAD I SMUDGE  /YES, GET LINK TO CONDEMNED WORD
  DCA DP    /BACK UP DP
  DCA I SMUDGE  /CLEAR OUT THE LINK
  DCA SMUDGE  /DON'T DO THIS AGAIN
  DCA NLEVEL  /CLEAR NESTING LEVEL
  CMA    /PRINT "^" UNDER ERRORS
  DCA CARETF
  DCA INWORD  /NOT IN A WORD (: DEF'N)
/THAT SHOULD DO IT - NOW START THE INTERPRETER
  JMP I .+1
C0200,  DOWORD    /JUMP INTO LOOP
ICODE0,  ICODE  /BEGN OF IMMEDIATE CODE
/
PAGE
/
DOWORD,  /GET AND COMPILE A WORD
  JMS GETW  /GET A WORD
  JMS I LOOKUP  /LOOK UP THE WORD
  SZL    /SKIP IF FOUND
  JMP DOWOR1  /NOT FOUND, MAYBE IT'S A #
  TAD I TEMP1  /GET TYPE
  DCA TEMP2  /SAVE
  ISZ TEMP1  /INC PTR
  JMP I TEMP2  /TYPE IS ALSO VECTOR
TCONS,  /CONSTANT
  TAD I TEMP1  /GET VALUE
  DCA TEMP1  /SAVE AS ADDR (FAKE OUT TVARI)
TVARI,  /VARIABLE
  PUTCON    /COMPILE A PPUSHC
  PPUSHC    /THAT'S WHAT I SAID
  TAD TEMP1  /GET ADDR (VALUE IF TCONS)
  PUTVAL    /COMPILE IT IN-LINE
  JMP DOWORD  /LOOP
TSUBR,  /SUBROUTINE (: ... ;)
  PUTCON    /COMPILE A CALL
  CALL    /YEP
  TAD TEMP1  /GET ADDR
  PUTVAL    /LOOKS AN AWFUL LOT LIKE TVARI!
  JMP DOWORD  /LOOP
TSTRU,  /CONTROL STRUCTURE (DO-LOOP, IF-ELSE-THEN, ETC.)
  JMP I TEMP1  /JUMP TO COMPILATION ROUTINE
/CONTROL STRUC ROUTINES RETURN VIA "RTS" (JMP I (DOWORD))
DOWOR1,  /WORD NOT DEFINED, CHECK FOR NUMBER
  TAD CWORD  /POINT AT WORD
  DCA TEMP1  /SAVE PTR
  JMS NUM    /SEE IF NUMBER
  SNL    /NO, ERROR
  JMP DOWOR2  /YES, VALUE IS IN TEMP2, GO PPUSHC IT
  ERROR    /UNDEFINED WORD
  TEXT /WHAT?/  /I JUST LOVE VAGUE MESSAGES!
DOWOR2,  PUTCON    /PPUSHC
  PPUSHC    /...
  TAD TEMP2  /GET VAL BACK
  PUTVAL    /COMPILE IN-LINE
  JMP DOWORD  /DO ANOTHER WORD
/
NUM,  0  /CONVERT .ASCIZ NUMBER AT @TEMP1 TO BINARY
/RESULT IN TEMP2, LINK SET IF NOT VALID NUMBER.
  DCA TEMP2  /CLEAR ACCUMULATOR
  DCA TEMP3  /CLEAR NEGATIVE FLAG
  TAD I TEMP1  /GET FIRST CHAR
  TAD MMINUS  /"-" ?
  SZA CLA    /SKIP IF SO
  JMP NUM1  /NO
  ISZ TEMP3  /SET FLAG
  ISZ TEMP1  /INC PTR
NUM1,  TAD I TEMP1  /GET A CHAR
  SNA    /SKIP IF NOT DONE
  JMP NUM2  /DONE, WHEE!
  TAD NUM4  /MOVE TO RANGE [-10,-1]
  CLL
  TAD C0012  /FLIP LINK IF VALID DECIMAL
  SNL    /SKIP IF HOOPY
  JMP NUM3  /INVALID DIGIT - NOT A NUMBER
  DCA TEMP4  /SAVE
  TAD TEMP2  /GET OLD NUMBER
  CLL RTL    /*4
  TAD TEMP2  /+NUMBER
  CLL RAL    /*2 =(((N*4)+N)*2)=N*10.
  TAD TEMP4  /ADD IN NEW DIGIT
  DCA TEMP2  /REPLACE
  ISZ TEMP1  /INC PTR
  JMP NUM1  /LOOP
NUM2,  TAD TEMP3  /NEGATE?
  SNA CLA
  JMP .+4    /NO, SKIP
  TAD TEMP2  /GET NUMBER
  CIA    /NEGATE
  DCA TEMP2  /REPLACE
  CLL    /CLEAR LINK - VALID NUMBER
  JMP I NUM  /RETURN WITH VALUE IN TEMP2
NUM3,  STL    /NOT A NUMBER
  JMP I NUM  /RETURN
NUM4,  -12-"0
C0012,  12
MMINUS,  -"-
/
GETW,  0
/READ A WORD FROM @LINPTR TO FIRST CTRL CHAR OR SPACE
/ENTER WITH AC CLEAR
/RETURN WITH .ASCIZ STRING IN WORD
  TAD WORDM1  /PT AT WORD (AX)
  DCA INDEX1  /OUTPUT PTR
GETW1,  TAD LINPTR  /SET ERRCOL TO POINT HERE
  DCA ERRCOL  /IN CASE THIS IS A NASTY WORD
  TAD I LINPTR  /GET CHAR
  SNA    /END OF LINE?
  JMP I READLN  /YES, GET ANOTHER ONE
  TAD M0241  /SPACE OR CTRL CHAR?
  SMA
  JMP GETW2  /NO
  IAC    /SPACE?
  SZA
  TAD C0027  /TAB?
  SZA CLA    /YES, ONE OR THE OTHER
  JMP .+3    /NO, ILLEGAL CHAR
  ISZ LINPTR  /INC PTR (IGNORE)
  JMP GETW1  /LOOP
  ERROR    /ILLEGAL CHAR
  TEXT /ILL CHAR/
GETW2,  CLA
GETW3,  TAD I LINPTR  /GET CHAR
  TAD M0241  /CTRL CHAR OR SPACE?
  SPA CLA
  JMP GETW4  /YES, GO RETURN
  TAD I LINPTR  /NO, RESTORE CHAR
  TAD C7405  /CVT LOWER CASE TO [-26.,-1]
  CLL
  TAD C0032  /LOWER CASE?
  SZL CLA    /NO, SKIP
  TAD M0040  /YES, SUBTRACT 32.
  TAD I LINPTR  /GET CHAR BACK
  DCA I INDEX1  /SAVE
  ISZ LINPTR  /INC PTR
  JMP GETW3  /LOOP
GETW4,  DCA I INDEX1  /MARK END WITH <NUL>
  JMP I GETW  /RETURN
M0241,  -241  /SPACE, CTRL CHARS -> [-32.,-1]
C0032,  32  /[-26.,-1] -> [0,25.] (FLIPPING LINK)
C7405,  7405  /LOWER CASE -> [-26.,-1]
M0040,  -40  /LOWER CASE -> UPPER CASE
READLN,  READL0  /PROMPT, GET A LINE
/
PAGE
/
READL0,  /CALLS INPUT, AND RESETS LINPTR
  RUNIMM    /RUN IMMEDIATE CODE FIRST
  TAD PROMPT  /PROMPT?
  SNA CLA
  JMP READL1  /NO
  TYPE    /YES, PRINT PROMPT
  "O+40;"K+40;215;212;0  /"OK<CR><LF>" (LOWER CASE)
READL1,  CMA    /REMEMBER TO PROMPT NEXT TIME, ANYWAY
  DCA PROMPT
  TAD CLINE  /PT AT LINE BUFFER
  DCA TEMP1  /PUT IN TEMP1
  JMS INPUT  /READ A LINE
  TAD CLINE  /GET PTR TO LINE
  DCA LINPTR  /PT AT LINE
  JMP I .+1  /TRY AGAIN
  GETW+1
/
INPUT,  0  /READ 80 CHARS FROM TTY TO @TEMP1
/ENTER WITH AC CLEAR
/0 MARKS END OF INPUT STRING
  TAD TEMP1  /GET START OF BUFFER
  CIA    /NEGATE
  DCA TEMP2  /USED TO CHECK BEG OF BUFF ON RUBOUT
  TAD TEMP1  /GET PTR
  DCA INDEX2  /SAVE IT
  TAD TEMP1  /GET START OF BUFFER
  TAD D0080  /PT AT LAST NON-CR CHAR IN BUFFER
  CIA    /NEGATE
  DCA TEMP3  /USED TO CHECK END OF BUFF ON INSERT
  DCA DELFLG  /NOT BETWEEN \'S
INPUT1,  KRB    /GET A CHAR
  DCA TEMP4  /SAVE IT
  TAD NUMSPC  /-(NUMBER OF SPECIALLY TREATED CHARS)
  DCA TEMP5  /LOOP CTR
  TAD CIDISP  /PT AT IDISP (DISP. TABLE)
  DCA INDEX1  /SAVE
  TAD TEMP4  /GET CHAR BACK
INPUT2,  TAD I INDEX1  /IS THIS THE CHAR?
  SNA    /SKIP IF THIS ISN'T IT
  JMP INPUT5  /THIS IS IT, GO JUMP TO IT
  ISZ INDEX1  /SKIP OVER ADDR
  ISZ TEMP5  /DONE?
  JMP INPUT2  /NO, TRY NEXT VALUE
  CLA
INPUT3,  /INSERT AND ECHO CHAR
  JMS BACKSL  /PRINT \ AND CLEAR DELFLG IF DELFLG
  TAD TEMP1  /GET PTR
  TAD TEMP3  /OUT OF SPACE?
  SZA CLA    /SKIP IF SO
  JMP INPUT4  /OTHERWISE CONTINUE
  TAD C0007  /RING BELL
  PRINT
  JMP INPUT1  /AND IGNORE
INPUT4,  TAD TEMP4  /GET CHAR
  DCA I TEMP1  /PUT IN BUFFER
  ISZ TEMP1  /INC PTR
  JMS I ECHOA  /ECHO THE CHAR
  JMP INPUT1  /LOOP
INPUT5,  /JUMP TO DISPATCH TABLE ADDRESS
  CLA    /CLEAR AC
  TAD I INDEX1  /GET DISPATCH VALUE
  DCA BACKSL  /SAVE
  JMP I BACKSL  /JUMP TO IT
BACKSL,  0  /IF DELFLG.NE.0, PRINT \ AND CLEAR DELFLG
  TAD DELFLG  /INSIDE \'S?
  SNA CLA
  JMP I BACKSL  /NO, RETURN
  DCA DELFLG  /CLEAR FLAG
  TAD .+3    /LOAD "\"
  PRINT    /PRINT IT
  JMP I BACKSL  /AND RETURN
  "\    /DELIMITS DELETED CHAR'S
INPUT6,  /MARK END OF STRING AND RETURN
  JMS BACKSL  /"\" IF NESSA
  DCA I TEMP1  /ZERO AT END
  CRLF    /CR,LF
  JMP I INPUT  /RETURN
INPUT7,  /^R - CR,LF AND REDRAW STRING
  JMS BACKSL  /"\" IF NESSA
  JMS I ECHOA  /PRINT "^R"
  CRLF    /CR,LF
  DCA I TEMP1  /MARK END OF STRING, FOR NOW
  CMA    /LOAD -1
  TAD INDEX2  /PT AT START OF STRING -1
  DCA INDEX3  /SAVE
INPUT8,  TAD I INDEX3  /GET A CHAR
  SNA    /SKIP IF NOT ZERO
  JMP INPUT1  /GET ANOTHER CHAR
  DCA TEMP4  /SAVE THE CHAR
  JMS I ECHOA  /ECHO IT
  JMP INPUT8  /LOOP UNTIL 0
INPUT9,  /^U - CR,LF AND CANCEL STRING
  JMS I ECHOA  /PRINT "^U"
  CRLF    /CR,LF
  TAD INDEX2  /GET START OF BUFFER
  DCA TEMP1  /RESET POINTER
  JMP INPUT1  /GET ANOTHER CHAR
  "$
INPU10,  /ESCAPE - ECHO $ AND RETURN
  JMS BACKSL  /"\" IF NESSA
  TAD .-2    /GET "$"
  PRINT    /PRINT IT
  DCA I TEMP1  /MARK END OF STRING
  JMP I INPUT  /AND RETURN
/
RUBOUT,  /RUBOUT - PRINT "\" (IF NESSA) AND ECHO LAST CHAR
  TAD TEMP1  /GET PTR
  TAD TEMP2  /GET -(START)
  SZA CLA    /BUFFER EMPTY?
  JMP RUB1  /NO
  JMS BACKSL  /PRINT CLOSING \ IF NESSA
  CRLF    /YES, CR,LF
  JMP INPUT1  /AND IGNORE
RUB1,  TAD DELFLG  /NEED A "\" ?
  SZA CLA
  JMP RUB2  /NO, ALREADY INSIDE \'S
  TAD INPUT6-1  /GET \
  PRINT    /PRINT IT
  ISZ DELFLG  /SET DELFLG
RUB2,  CMA    /BACK UP PTR
  TAD TEMP1
  DCA TEMP1
  TAD I TEMP1  /GET CHAR TO BE DELETED
  DCA TEMP4  /PUT IN CHAR BUFF
  JMS I ECHOA  /ECHO IT
  TAD TEMP1  /AT BEGN OF BUFF NOW?
  TAD TEMP2
  SZA CLA
  JMP INPUT1  /NO, LOOP
  JMS BACKSL  /PRINT "\"
  CRLF    /CR,LF
  JMP INPUT1  /AND DO ANOTHER CHAR
ECHOA,  ECHO  /PTR TO ECHO ROUTINE
D0080,  120  /80. (LENGTH OF BUFFER)
NUMSPC,  -13  /-(NUMBER OF SPECIAL INPUT CHARS)
CIDISP,  IDISP-1  /PTR TO INPUT DISPATCH TABLE
/
PAGE
/
ECHO,  0  /ECHO CHAR IN TEMP4
  TAD TEMP4  /GET CHAR
  AND C7540  /CLEAR AC4,AC7-AC11
  SNA CLA    /CTRL CHAR?
  JMP ECHO2  /YES, SPECIAL TREATMENT
ECHO1,  TAD TEMP4  /GET CHAR
  PRINT    /PRINT IT
  JMP I ECHO  /RETURN
ECHO2,  TAD TEMP4  /GET CHAR
  TAD M0211  /TAB?
  SZA    /SKIP IF SO
  IAC    /BACKSPACE?
  SNA CLA    /SKIP IF NOT
  JMP ECHO1  /HT & BS ARE ECHOED AS-IS
  TAD UPARR  /PRINT "^"
  PRINT
  7203    /CLA IAC BSW (PAL-D BUG) LOAD 64.
  TAD TEMP4  /LOAD CHAR+64.
  PRINT    /ECHO IT
  JMP I ECHO  /RETURN
UPARR,  "^  /FOR CTRL CHARS
/
/DISPATCH TABLE FOR SPECIAL CHARACTERS:
IDISP,  /INPUT DISPATCH TABLE (RO,ESC,^U,^R,^M,^L,^K,^J,^I,^H,NUL)
  -377  /RUBOUT
  RUBOUT
  377-233  /ESCAPE
  INPU10
  233-225  /^U
  INPUT9
  225-222  /^R
  INPUT7
  222-215  /CR
  INPUT6
  215-214  /FF
  INPUT6
  214-213  /VT
  INPUT6
  213-212  /LF
  INPUT6
  212-211  /TAB
  INPUT3
  211-210  /BACKSPACE
  INPUT3
  210-200  /NUL
  INPUT1
/DWEE!
/
  0  /TEMP BUFFER FOR CHAR
PRINT0,  0  /PRINT CHAR IN AC, DEAL WITH TABS
  DCA PRINT0-1  /SAVE
  TAD PRINT0-1  /GET BACK
  TAD M0211  /TAB?
  SNA
  JMP TAB    /YES, DEAL WITH IT
  IAC    /BACKSPACE?
  SNA    /NO, SKIP
  JMP BCKSPC  /YES, SPECIAL TREATMENT
  TAD C7773  /CR?
  SNA CLA
  JMP CARRET  /YES
  TAD PRINT0-1  /GET CHAR
  AND C7540  /CTRL CHAR?
  SZA CLA    /SKIP IF SO
  ISZ PRCOL  /OTHERWISE INC PRCOL
PRINT1,  TAD PRINT0-1  /GET CHAR
  TLS    /PRINT IT
  CLA    /CLEAR AC
  JMP I PRINT0  /RETURN
/
BCKSPC,  CLL CMA    /DEC PRCOL
  TAD PRCOL
  SZL    /UNLESS IT'S ALREADY 0 (DEC TERMINALS)
  DCA PRCOL
  CLA    /IN CASE WE JUST SKIPPED
  JMP PRINT1  /PRINT BS AND RETURN
TAB,  TAD C0240  /PRINT A SPACE
  TLS
  CLA
  ISZ PRCOL  /MOVE OVER A COL
  TAD PRCOL  /GET PRCOL
  AND C0007  /AT A TAB STOP?
  SZA CLA    /SKIP IF SO
  JMP TAB    /ELSE LOOP
  JMP I PRINT0  /RETURN
CARRET,  DCA PRCOL  /CLEAR PRINT COLUMN
  JMP PRINT1  /PRINT CR AND RETURN
/
C7773,  7773
/
CRLF0,  0  /PRINT CR,LF
  TYPE    /A LITTLE SLOW, BUT SO WHAT?
  215;212;0  /CR,LF
  JMP I CRLF0  /RETURN
/
TYPE0,  0  /PRINT .ASCIZ STRING FOLLOWING "TYPE"
  TAD I TYPE0  /GET CHAR
  ISZ TYPE0  /INC PTR
  SNA    /DONE YET?
  JMP I TYPE0  /YES, RETURN
  PRINT    /NO, PRINT THE CHAR
  JMP TYPE0+1  /LOOP UNTIL 0
/
RPUSH0,  0  /PUSH AC TO RETURN STACK (7600-7777)
  DCA TYPE0  /SAVE AC
  TAD SP    /GET SP
  TAD C0200  /STACK FULL?
  SZA CLA
  JMP RPUSH1  /NO, GO PUSH
  ERROR    /YES, PRINT MESSAGE
  TEXT /RSTACK OVERFLOW/
RPUSH1,  CMA    /DEC SP
  TAD SP
  DCA SP
  TAD TYPE0  /GET AC BACK
  DCA I SP  /PUSH IT
  JMP I RPUSH0  /RETURN
/
PAGE
/
ERROR0,  0  /PRINT TRIMMED ASCII MESSAGE AFTER JMS & ABORT
  TAD CARETF  /PRINT "^"?
  SNA CLA
  JMP ERROR3  /NO
  TAD ERRCOL  /GET COLUMN OF ERROR
  CIA    /NEGATE
  DCA TEMP1  /SAVE
  TAD CLINE  /PT AT LINE
  DCA TEMP2  /SAVE
ERROR1,  TAD TEMP1  /DONE?
  TAD TEMP2
  SNA CLA
  JMP ERROR2  /YES, GO PRINT "^ "
  TAD I TEMP2  /GET CHAR
  TAD M0211  /TAB?
  SZA CLA
  TAD C0027  /NO, PRINT A SPACE
  TAD C0211  /YES, PRINT A TAB
  PRINT    /HACK, HACK, HACK
  ISZ TEMP2  /INC PTR
  JMP ERROR1  /LOOP
ERROR2,  TYPE    /PRINT "^ "
  "^;" ;0
ERROR3,  STA CLL RAL  /LOAD -2
  DCA RPOP0  /SAVE LOOP CTR
  TAD I ERROR0  /GET CHAR
  BSW    /GET HIGH CHAR
ERROR4,  AND C0077  /MASK OUT HIGH BITS
  SNA    /DONE?
  JMP ERROR6  /YES, CR/LF AND RESTART
  DCA LOOKU0  /NO, SAVE THE CHAR
  TAD LOOKU0  /GET BACK
  CMA    /FLIP EVERYTHING
  AND C0040  /BIT 6 SET?
  CLL RAL    /HACK HACK HACK
  TAD C0200  /ADD MISSING BITS
  TAD LOOKU0  /GET CHAR BACK
  PRINT    /PRINT IT
  ISZ RPOP0  /WAS THAT THE HIGH OR THE LOW CHAR?
  JMP ERROR5  /HIGH
  ISZ ERROR0  /LOW - PT TO NEXT CHAR
  JMP ERROR3  /DO THE NEXT TWO CHARS
ERROR5,  TAD I ERROR0  /GET LOW CHAR
  JMP ERROR4  /PRINT IT
ERROR6,  CRLF    /CR,LF
  DCA PROMPT  /NOT "OK"
  JMP RESET  /GO RESTART
C0040,  40
C0211,  211  /TAB
/
LOOKU0,  0  /LOOK UP WORD IN WORD BUFFER
/RETURN WITH LINK CLEAR AND TEMP1 POINTING AT TYPE IF
/FOUND, OR WITH LINK SET IF NOT FOUND.
  TAD CDICT  /PT AT DICT
  DCA TEMP1
  DCA TEMP2  /PTR TO LAST LINK (FORGET)
LOOKU1,  TAD WORDM1  /#WORD -1
  DCA INDEX1  /SOURCE PTR (AX)
LOOKU2,  CMA CLL RAL  /LOAD -2 (2 CH'S/WORD)
  DCA TEMP3  /LOOP CTR
  TAD I TEMP1  /GET 2 CHARS
  BSW    /LOOK AT HIGH ORDER FIRST
LOOKU3,  AND C0077  /REMOVE HIGH CHAR
  SNA    /END OF ENTRY?
  JMP LOOKU5  /YES, SEE IF END OF WORD
  TAD C0240  /CVT TO ASCII
  CIA    /NEGATE
  TAD I INDEX1  /=?
  SZA CLA
  JMP LOOKU6  /NO, SKIP TO LINK
  ISZ TEMP3  /FINISHED WORD?
  JMP LOOKU4  /NO, CHECK LOW CHAR
  ISZ TEMP1  /YES, PT AT NEXT PAIR OF CHARS
  JMP LOOKU2  /LOOP
LOOKU4,  TAD I TEMP1  /GET PAIR OF CHARS BACK
  JMP LOOKU3  /CHECK LOW CHAR
LOOKU5,  TAD I INDEX1  /END OF WORD?
  SZA CLA
  JMP LOOKU6  /NO, SKIP TO NEXT ENTRY
  ISZ TEMP1  /YES, PT AT LINK
  ISZ TEMP1  /PT AT TYPE
  CLL    /SIGNIFY FOUND
  JMP I LOOKU0  /RETURN
LOOKU6,  TAD I TEMP1  /GET CHAR
  ISZ TEMP1  /PT AT NEXT CHAR OR LINK
  AND C0077  /BOTTOM BYTE SHOULD BE 0, ANYWAY
  SZA CLA    /IS IT?
  JMP LOOKU6  /NO, TRY NEXT WORD
  TAD TEMP1  /YES, GET PTR TO LINK
  DCA TEMP2  /SAVE IN CASE OF <FORGET>
  TAD I TEMP1  /GET LINK
  STL    /IN CASE THIS IS THE END OF THE DICT
  SNA    /IS IT?
  JMP I LOOKU0  /YES, RETURN, LINK SET
  DCA TEMP1  /NO, PT TO NEXT NAME FIELD
  JMP LOOKU1  /CHECK THIS ENTRY
CDICT,  DICT  /BEGINNING OF DICTIONARY
/
DCTVA0,  0  /PUT AC IN DICTIONARY, ADVANCE DP (CHECK PSTACK)
  DCA I DP  /THERE IS ALWAYS AT LEAST 1 FREE WORD
  TAD DP    /GET DP
  CMA    /NEGATE, SUBTRACT 1 (HACK HACK)
  TAD PSP    /PSTACK COLLISION?
  SZA CLA
  JMP DCTVA1  /NO
  ERROR    /YES, ERROR
  TEXT /DICT FULL/
DCTVA1,  ISZ DP    /ALL OK, INC DP
  JMP I DCTVA0  /RETURN, AC CLEAR
/
DCTCO0,  0  /PUT WORD AFTER JMS IN DICT, ADVANCE DP
  CLA
  TAD I DCTCO0  /GET WORD TO PUT
  JMS DCTVA0  /PUT IT IN THE DICT
  ISZ DCTCO0  /PT PAST ARG
  JMP I DCTCO0  /RETURN, AC CLEAR
/
PAGE
/
MAKEW0,  0  /CREATE ENTRY FOR WORD IN WORD BUF IN DICT
/FIRST, CHECK TO MAKE SURE THE WORD DOESN'T ALREADY EXIST.
/USE TYPE IN WORD FOLLOWING JMS.
  JMS I LOOKUP  /TRY TO LOOK THE WORD UP
  SZL    /SKIP IF FOUND
  JMP MAKEW1  /NOT THERE, MAKE IT
  ERROR    /ALREADY DEFINED
  TEXT /ILL REDEF'N/
MAKEW1,  TAD TEMP2  /GET PTR TO LINK IN LAST ENTRY
  DCA SMUDGE  /SAVE IN CASE OF COMPILATION ERROR
  TAD WORDM1  /PT AT WORD
  DCA INDEX1  /SOURCE PTR
MAKEW2,  CMA CLL RAL  /-2
  DCA TEMP1  /LOOP CTR
MAKEW3,  TAD I INDEX1  /GET A CHAR
  SNA    /END?
  JMP MAKEW6  /YES, FINISH OFF
  TAD M0240  /NO, CVT TO SIXBIT
  DCA TEMP2  /SAVE
  TAD TEMP2  /CHECK
  AND C7700  /ANY EXTRA BITS?
  SNA CLA
  JMP MAKEW4  /OK, CONTINUE
  ERROR    /ILLEGAL NAME
  TEXT /ILL NAME/
MAKEW4,  TAD TEMP2  /GET CHAR
  ISZ TEMP1  /CHAR 1, OR 2?
  JMP MAKEW5  /1
  TAD TEMP3  /2 - GET OLD CHAR
  DCTVAL    /COMPILE INTO DICTIONARY
  JMP MAKEW2  /LOOP
MAKEW5,  BSW    /LEFT 6 BITS
  DCA TEMP3  /SAVE
  JMP MAKEW3  /LOOP
MAKEW6,  /END OF WORD
  ISZ TEMP1  /CHAR 1, OR 2?
  SKP    /1 - PUT 0,0
  TAD TEMP3  /2 - PUT CHAR,0
  DCTVAL    /COMPILE LAST WORD OF NAME
  DCTVAL    /LINK IS 0
  TAD I MAKEW0  /GET TYPE
  DCTVAL    /COMPILE IT
  ISZ MAKEW0  /SKIP OVER TYPE
  JMP I MAKEW0  /RETURN
C7700,  7700  /CLEAR OUT CHAR
M0240,  -240  /CONVERT ASCII TO SIXBIT
/
PUTVA0,  0  /PUT AC IN DICT OR IMMBUF, DEPENDING ON INWORD
  DCA MAKEW0  /SAVE AC
  TAD INWORD  /IN A : DEFN?
  SNA CLA    /SKIP IF SO
  JMP PUTVA1  /ELSEWISE, GO PUT IN ICODE
  TAD MAKEW0  /GET AC
  DCTVAL    /SAVE IN DICT
  JMP I PUTVA0  /RETURN
PUTVA1,  TAD IMMDP  /GET IMMEDIATE PSEUDO-DICTIONARY PTR
  TAD PUTVA3  /ICODE FULL?
  SZA CLA    /YES, ERROR
  JMP PUTVA2  /NO, POKE THE VALUE
  ERROR
  TEXT /IMM BUFF FULL/
PUTVA2,  TAD MAKEW0  /GET AC
  DCA I IMMDP  /PUT IN ICODE
  ISZ IMMDP  /INC PTR
  JMP I PUTVA0  /RETURN
PUTVA3,  -ICODE-176  /ALWAYS LEAVE ONE EXTRA WORD FOR "RET"
/
PUTCO0,  0  /PUT WORD AFTER JMS IN APPROPRIATE BUFFER
  CLA
  TAD I PUTCO0  /GET WORD
  JMS PUTVA0  /POKE TO BUFFER
  ISZ PUTCO0  /INC PTR
  JMP I PUTCO0  /RETURN
/
JUMP0,  0  /JUMP TO ADDR AFTER JMS
  CLA
  TAD I JUMP0  /GET ADDR
  DCA JUMP0  /SAVE
  JMP I JUMP0  /JUMP TO IT
/
CALL0,  0  /CALL ADDR FOLLOWING "CALL," USING RSTACK
  CLA IAC    /LOAD 1
  TAD CALL0  /RETURN ADDRESS
  RPUSH    /PUSH TO RSTACK
  TAD I CALL0  /GET ADDR TO CALL
  DCA CALL0  /SAVE
  JMP I CALL0  /JUMP TO IT
/
RET0,  /POP PC OFF OF RSTACK
  RPOP    /GET RETURN ADDRESS
  DCA CALL0  /SAVE
  JMP I CALL0  /JUMP TO IT
/
PPUSH0,  0  /PUSH AC TO PSTACK
  DCA CALL0  /SAVE AC
  CMA    /DEC PSP
  TAD PSP
  DCA PSP
  TAD DP    /PSP-DP-1=0?
  CMA
  TAD PSP
  SZA CLA
  JMP PPUSH1  /NO, EVERYTHING'S HIP
  ERROR
  TEXT /PSTACK OVERFLOW/
PPUSH1,  TAD CALL0  /RESTORE AC
  DCA I PSP  /PUSH IT
  JMP I PPUSH0
/
PAGE
/
PPOP0,  0  /POP AC FROM PSTACK
  CLA
  TAD PSP    /GET PSP
  TAD C0200  /PSP=7600?
  SZA CLA
  JMP PPOP1  /NO
  ERROR
  TEXT /PSTACK UNDFL/
PPOP1,  TAD I PSP  /POP A VALUE
  ISZ PSP    /INC PSP
  JMP I PPOP0  /RETURN
/
RPOP0,  0  /POP AC FROM RETURN STACK (7600-7777)
  TAD SP    /GET SP
  SZA CLA
  JMP RPOP1  /STACK OK, GO POP
  ERROR    /UNDERFLOW, PRINT ERROR
  TEXT /RSTACK UNDFL/
RPOP1,  TAD I SP  /GET AC
  ISZ SP    /INC SP
  NOP    /THIS WILL SKIP ON THE LAST WORD
  JMP I RPOP0  /RETURN
/
PPC0,  0  /PPUSH CONSTANT IN LOCN AFTER "PPUSHC"
  CLA
  TAD I PPC0  /GET CONSTANT
  PPUSH    /PPUSH IT
  ISZ PPC0  /INC PAST ARG
  JMP I PPC0  /RETURN
/
RUNIM0,  0  /RUN IMMEDIATE CODE
  TAD INWORD  /COMPILING A : DEFN?
  SZA CLA
  JMP IMM1  /YES, DON'T WORRY ABOUT NESTING
  TAD NLEVEL  /NLEVEL=NSP?
  CIA
  TAD NSP
  SNA CLA
  JMP IMM1  /YES, NO PROBLEM
  ERROR    /NO, GACK
  TEXT /UNCLOSED STRUC/
IMM1,  DCA CARETF  /NO "^" ON RUN-TIME ERRORS
  TAD CRET  /"RET" AT END OF IMM CODE
  DCA I IMMDP
  CALL    /CALL THE CODE
  ICODE
  TAD CICODE  /PT AT ICODE
  DCA IMMDP  /RESET IMMDP
  CMA    /^ ON ERRORS
  DCA CARETF
  JMP I RUNIM0  /RETURN
CRET,  RET
CICODE,  ICODE
/
NPUSH0,  0  /PUSH AC, @PC TO NESTING STACK
  DCA RPOP0  /SAVE AC
  TAD NSP    /GET NSTACK PTR
  TAD NPUSH2  /STACK FULL?
  SZA CLA
  JMP NPUSH1  /NO
  ERROR    /YES, ERROR
  TEXT /TOO MUCH NESTING/
NPUSH1,  TAD NSP    /GET OFFSET
  TAD CNSTAK  /ADD BASE
  DCA PPC0  /SAVE PTR
  TAD RPOP0  /GET ADDRESS BACK
  DCA I PPC0  /PUSH IT
  ISZ PPC0  /INC PTR
  ISZ NSP    /INC OFFSET
  TAD I NPUSH0  /GET KEYWORD TOKEN
  DCA I PPC0  /PUSH IT
  ISZ NSP    /INC OFFSET (NOT PTR)
  ISZ NPUSH0  /SKIP OVER ARG
  JMP I NPUSH0  /RETURN
NPUSH2,  -40  /STACK BIG ENOUGH FOR 16 LEVELS OF NESTING
CNSTAK,  NSTACK  /PTR TO BASE OF NSTACK
/
PAGE
/
NPOP0,  0  /POP AC OFF OF NESTING STACK
/CHECK TO SEE IF TOKEN AGREES WITH ONE AFTER CALL (NEGATIVE)
  CLA    /JUST TO MAKE SURE
  TAD NSP    /GET NSTACK PTR
  SZA    /SKIP IF EMPTY
  JMP NPOP1  /OTHERWISE START THE POP
  ERROR    /NO MATCHING NPUSH
  TEXT /STRUC ERR/
NPOP1,  TAD NSTAK1  /ADD BASE TO OFFSET
  DCA TEMP5  /SAVE THIS PTR
  TAD I TEMP5  /GET TOKEN
  TAD I NPOP0  /GET -TOKEN TO MATCH
  SNA CLA    /DO THEY MATCH?
  JMP NPOP2  /YES
  ERROR    /NO
  TEXT /NEST ERR/
NPOP2,  STA CLL RAL  /-2
  TAD NSP    /DEC NSP BY 2
  DCA NSP
  STA    /DEC PTR BY 1
  TAD TEMP5
  DCA TEMP5
  TAD I TEMP5  /GET ADDRESS
  ISZ NPOP0  /SKIP OVER TOKEN
  JMP I NPOP0  /RETURN
NSTAK1,  NSTACK-1
/
CURRD0,  0  /RETURN DP FOR CURRENT BUFFER
  CLA    /JUST MAKING SURE
  TAD INWORD  /IN A COLON DEFINITION?
  SZA CLA
  JMP .+3    /YES
  TAD IMMDP  /NO
  JMP I CURRD0  /RETURN
  TAD DP    /GET DICTIONARY POINTER
  JMP I CURRD0  /RETURN
/
/DATA AREAS
NSTACK=  .  /NESTING STACK
*.+40    /ALLOW 16. LEVELS OF NESTING
WORD=  .  /BUFFER FOR WORD
*.+40    /ALLOW 32. CHARS BEFORE HITTING LINE
LINE=  .  /BUFFER FOR INPUT LINE
*.+120    /ALLOW 80 CHARS
ICODE=  .  /BUFFER FOR IMMEDIATE MODE CODE
*.+200    /ALLOW A LOT OF THAT
DICT=  .  /START OF PREDEFINED DICTIONARY
/
  0100  /!
  PAREN
  TSUBR
/( VAL ADDR -- ) POKES ADDR TO VAL
  PPOP    /GET ADDRESS
  DCA TEMP1  /SAVE
  PPOP    /GET VALUE
  DCA I TEMP1  /POKE
  RET    /RETURN
/
PAREN,  1000  /(
  MULT
  TSTRU
/( -- TEXT ')') IGNORES TEXT TO NEXT ")"
  CLA
PAREN1,  TAD I LINPTR  /LOOK FOR ")"
  ISZ LINPTR  /PT AT NEXT CHAR
  SNA    /END OF LINE?
  JMP PAREN2  /YES, GO READ ANOTHER ONE (BIG COMMENT)
  TAD PAREN3  /")" ?
  SZA CLA
  JMP PAREN1  /NO, LOOP
  RTS    /YES, RETURN
PAREN2,  TAD CLINE  /PT AT LINE BUFF
  DCA TEMP1  /SAVE PTR FOR INPUT
  JMS I PAREN4  /CALL INPUT
  TAD CLINE  /PT AT LINE, AGAIN
  DCA LINPTR  /SET LINPTR TO POINT THERE
  JMP PAREN1  /SEARCH LINE FOR ")"
PAREN3,  -")  /SEARCH CHARACTER
PAREN4,  INPUT
/
MULT,  1200  /*
  PLUS
  TSUBR
  PPOP    /GET FIRST VALUE
  DCA TEMP1  /SAVE IT
  PPOP    /GET SECOND VALUE
  DCA TEMP2  /SAVE IT
  JMS MULT0  /PERFORM THE MULTIPLY
  TAD TEMP4  /GET THE PRODUCT
  PPUSH    /RETURN IT
  RET
/
MULT0,  0  /MULTIPLY TEMP1 BY TEMP2, RESULT IN TEMP4
  TAD M0014  /-12.
  DCA TEMP3  /BIT COUNTER
  DCA TEMP4  /ACCUMULATOR
MULT1,  TAD TEMP1  /GET MULTIPLIER
  RAR    /AC11 INTO LINK
  DCA TEMP1  /SAVE RESULT
  SNL    /SKIP IF 1
  JMP MULT2  /0, DON'T ADD
  TAD TEMP4  /GET ACCUMULATOR
  TAD TEMP2  /ADD MULTIPLICAND
  DCA TEMP4  /SAVE SUM
MULT2,  TAD TEMP2  /ROTATE MULTIPLICAND LEFT ONE BIT
  CLL RAL
  DCA TEMP2
  ISZ TEMP3  /DONE ALL 12. BITS?
  JMP MULT1  /NO, LOOP
  JMP I MULT0  /YES, RETURN (RESULT IN TEMP4)
M0014,  -14  /-(NUMBER OF BITS IN A WORD)
/
PLUS,  1300  /+
  COMMA
  TSUBR
( VAL1 VAL2 -- VAL1+VAL2) RETURNS SUM OF TOP TWO VALUES
  PPOP    /GET FIRST VALUE
  DCA TEMP1  /SAVE IT
  PPOP    /GET SECOND VALUE
  TAD TEMP1  /ADD FIRST VALUE
  PPUSH    /PUSH SUM
  RET
/
COMMA,  1400  /,
  MINUS
  TSUBR
( VALUE -- ) PUTS VALUE INTO DICTIONARY AND ADVANCES DP
  PPOP    /GET VALUE
  DCTVAL    /POKE INTO DICTIONARY
  RET
/
MINUS,  1500  /-
  DOT
  TSUBR
( VAL1 VAL2 -- VAL1-VAL2) RETURNS DIFFERENCE BETWIXT TOP TWO VALUES
  PPOP    /GET VAL1
  DCA TEMP1  /SAVE
  PPOP    /GET VAL2
  CIA    /NEGATE
  TAD TEMP1  /ADD VAL1
  PPUSH    /PUSH RESULT
  RET
/
DOT,  1600  /.
  DOTQ
  TSUBR
( VAL -- ) PRINTS VALUE ON TOP OF STACK, SIGNED
  PPOP    /GET VALUE
  JMS .+2    /PRINT THE VALUE
  RET    /RETURN
/
PRNUM0,  0  /PRINT SPACE, AC (SIGNED)
  SMA    /NEGATIVE?
  JMP PRNUM1  /NO
  CIA    /MAKE POSITIVE
  DCA TEMP1  /SAVE
  TYPE    /PRINT " -"
  " ;"-;0
  JMP PRNUM2  /GO PRINT THE #
PRNUM1,  DCA TEMP1  /SAVE NUMBER
  TYPE    /PRINT " "
  " ;0
PRNUM2,  TAD TEMP1  /GET NUMBER BACK
  JMS I PRNUM3  /PRINT IT
  RET    /AND RETURN
PRNUM3,  UPRNUM  /ROUTINE TO PRINT A #, UNSIGNED
/
*.  /TO AVOID "PE" ERRORS (PAL-D BUG)
DOTQ,  1602  /."
  0000
  DIVD
  TSTRU    /SPECIAL CASE COMPILATION
  PUTCON    /COMPILE "DOTQUO"
  DOTQUO
  JMS ASCIZ0  /COMPILE IN-LINE .ASCIZ CONSTANT
  RTS
/
ASCIZ0,  0  /COMPILE IN-LINE STRING TERMINATED WITH "
  TAD I LINPTR  /END OF LINE HERE?
  SNA CLA    /NO
  JMP ASCIZE  /YES, ERROR (UNTERMINATED)
ASCIZ1,  ISZ LINPTR  /PT AT NEXT CHAR
  TAD I LINPTR  /GET A CHAR (LOWER CASE OK)
  SNA    /SHOULDN'T BE END OF LINE
  JMP ASCIZE  /ERROR IF SO
  TAD ASCIZ3  /END OF STRING?
  SNA CLA
  JMP ASCIZ2  /YES, <NUL> AT END AND RETURN
  TAD I LINPTR  /NO, RESTORE CHAR
  PUTVAL    /PUT IN DICTIONARY
  JMP ASCIZ1  /LOOP
ASCIZ2,  ISZ LINPTR  /SKIP OVER "
  PUTVAL    /COMPILE A <NUL>
  RTS    /AND RETURN
ASCIZ3,  -242  /QUOTE
ASCIZE,  ERROR  /ERROR IF END OF LINE ENCOUNTERED
  TEXT /NO CLOSING "/
/
DOTQU0,  0  /RUN-TIME ROUTINE TO PRINT .ASCIZ STRING FOLLOWING CALL
  CLA    /JUST TO MAKE SURE
DOTQU1,  TAD I DOTQU0  /GET A CHAR
  ISZ DOTQU0  /PT AT NEXT ONE
  SNA    /DONE?
  JMP I DOTQU0  /YES, RETURN
  PRINT    /NO, PRINT THE CHAR
  JMP DOTQU1  /LOOP UNTIL 0
/
DIVD,  1700  /"/"
/ADD THIS LATER
USRDCT=  .  /USER-DEFINED WORDS START HERE
$ THAT'S ALL, FOLKS!