REM "LINK" PROGRAM
REM LAST EDIT DATE 2/15/81
REM ACTS AS PRIMITIVE LINK EDITOR
REM MEANT TO BE USED AS OUTPUT PROCESSOR FOR META 1.X SERIES COMPILERS
REM PERFORMS NUMERIC CONVERSIONS
REM PERFORMS FORWARD AND BACKWARD LABEL RESOLUTION OF 16 BIT ADDRESSES
REM PERFORMS GLOBAL SYMBOL RESOLUTION
REM ALSO PERFORMS LOCAL "SET" AND POLISH STRING EVALUATIONS
REM MANUFACTURES SDOS BINARY FORMAT FILE DIRECTLY

REM COMMAND LINE FORMAT:
REM         .LINK OUTPUTFILE=FILE1,FILE2,FILE3,FILE4,....FILEN
REM ",<CR>" MEANS FILE LIST CONTINUES ON NEXT LINE

REM LINK OBJECT FILE FORMAT:
REM EACH OBJECT FILE CONSISTS OF A SET OF LINK RECORDS
REM EACH LINK RECORD CONSISTS OF A COMMAND TO THE LINKER WITH AN OPTIONAL PARAMETER
REM LINK COMMANDS ARE COMPOSED OF A SINGLE LETTER
REM THE OPTIONAL PARAMETER IMMEDIATELY FOLLOWS
REM A <CR> IS ALLOWED PRECEDING A LINK COMMAND

REM LINK COMMANDS
REM   HXX           (2 HEX DIGITS; LOAD INTO OBJECT FILE AND ADVANCE LP)
REM   WXXXX         (4 HEX DIGITS; LOAD INTO OBJECT FILE AND ADVANCE LP)
REM   VXX XXXXXX... (2 HEX DIGITS INDICATING HOW MANY BYTES FOLLOW)
REM                 ALL FOLLOWING BYTES ARE TREATED AS "H" COMMAND PARAMETERS
REM   S<QUOTECHAR>STRING BODY<QUOTECHAR>        (LOADS STRING BODY)
REM   DXXXX         (DECIMAL VALUE OF UNKNOWN LENGTH; LOAD ONE BYTE)
REM   EXXXX         (DECIMAL VALUE OF UNKNOWN LENGTH; LOAD TWO BYTES)
REM   ASYMBOL<CR>   LOADS VALUE OF GLOBAL SYMBOL INTO NEXT 16 BITS
REM   =SYMBOL<CR>   SETS VALUE OF GLOBAL SYMBOL TO LOAD POINTER
REM   LHEXNUM<CR>   LOADS VALUE OF ITH LOCAL SYMBOL INTO NEXT 16 BITS
REM   :HEXNUM<CR>   SETS VALUE OF ITH LOCAL SYMBOL TO LOAD POINTER
REM   CXXXX<CR>     PUSH DECIMAL CONSTANT ONTO LINK STACK
REM   KXXXX<CR>     PUSH HEX CONSTANT ONTO LINK STACK
REM   PHEXNUM<CR>   PUSH VALUE OF LOCAL SYMBOL ONTO LINK STACK
REM   QSYMBOL<CR>   PUSH VALUE OF GLOBAL SYMBOL ONTO LINK STACK
REM   +             ADD TOP TWO LINK STACK ELEMENTS
REM   *             MULTIPLY TOP TWO LINK STACK ELEMENTS
REM   <             SET TOP OF LINK STACK TO LEFTMOST 8 BITS OF TOP OF LINK STACK
REM   >             SET TOP OF LINK STACK TO RIGHTMOST 8 BITS OF TOP OF LINK STACK
REM   8             LOAD VALUE OF TOP OF LINK STACK INTO MEMORY (8 BITS)
REM   X             LOAD VALUE OF TOP OF LINK STACK INTO MEMORY (16 BITS)
REM   -             SUBTRACT LINK STACK TOS FROM TOS-1
REM   !HEXNUM<CR>   SET LOCAL SYMBOL TO TOP OF LINK STACK
REM   .             PUSH VALUE OF LOCATION COUNTER
REM   ,             SET VALUE OF LOCATION COUNTER TO LINK STACK RESULT
REM   #SYMBOL<CR>   SET VALUE OF GLOBAL SYMBOL TO LINK STACK RESULT
REM   $             (END OF MODULE)

DIM OBJECTFILE$(40),OBJECTSKELETON$/:01,:01,:00,:FE,:FF,:03,:01,:00,:00,:00/
DIM LOADADDRESS/:100/,MAXADDRESS/:FF/
DIM LINKOPCODES$/"K+-*<>8X.CQPHWVSDEA=L:!,#$"/,LINKINSTRUCTION$(132)
DIM LINKOPPUSHVALUE/1/,LINKOPADD/2/,LINKOPSUBTRACT/3/,LINKOPMULTIPLY/4/
DIM LINKOPLEFTBYTE/5/,LINKOPRIGHTBYTE/6/,LINKOPLOADBYTE/7/,LINKOPLOADWORD/8/
DIM LINKSTACK(10),LINKSTACKTOP/0/
DIM RELFILE$(50),RELFILE/1/,OBJECTFILE/2/
DIM COMMANDLINE$(100),QUOTE$(1),BYTE$/:0/,ZERO$/0/
DIM FWDREFSTORAGE$(1000)/""/
DIM UNDEFINEDLOCALLABEL$/0,0,0/
DIM FF$/:FF/,TEMP$(50)

REM LOCAL LABEL TABLE FORMAT:
REM <DEFINED FLAG TRUE/FALSE><16 BIT VALUE>
REM DEFINED FLAG = FALSE --> FORWARD REF, VALUE POINTS TO LAST FWD REF
REM DEFINED FLAG = TRUE --> VALUE IS TRUE VALUE
REM LOWEST VALID LOCAL LABEL SELECTOR = 0
DIM LOCALLABELS$(3000)

REM SYMBOL TABLE FORMAT:
REM <DEFINED FLAG TRUE/FALSE> <VV> <VV> <:FF> <SYMBOL LEN> <SYM CH.>....
REM DEFINED FLAG = FALSE --> FORWARD REF, VVVV POINTS TO LAST FWD REF LOCN
REM DEFINED FLAG = TRUE --> VVVV IS VALUE OF SYMBOL
DIM SYMBOL$(50),SYMBOLS$(5000)/""/,SYMBOL

DEF LOCALLABELDEFINED(LOCALLABELINDEX)
    IF LOCALLABELINDEX*3+3>LEN(LOCALLABELS$)
    THEN
         REM WANTS TO DEFINE NEW LOCAL LABEL
         IF LOCALLABELINDEX*3+3>MAXLEN(LOCALLABELS$)
         THEN PRINT "LOCAL LABEL TABLE EXHAUSTED" \ ERROR 0
         LET LOCALLABELDEFINEDI=LEN(LOCALLABELS$)+1
         LET LEN(LOCALLABELS$)=LOCALLABELINDEX*3+3
         FOR LOCALLABELDEFINEDI=LOCALLABELDEFINEDI TO LEN(LOCALLABELS$) STEP 3
             LET LOCALLABELS$(LOCALLABELDEFINEDI,3)=UNDEFINEDLOCALLABEL$
         NEXT LOCALLABELDEFINEDI
    FI
    RETURN (LOCALLABELS$(LOCALLABELINDEX*3+1))
END
SUBROUTINE SETLOCALLABELDEFINED(LOCALLABELINDEX1,SETLOCALLABELDEFINEDARG)
    LOCALLABELS$(LOCALLABELINDEX*3+1)=SETLOCALLABELDEFINEDARG
    EXIT SUBROUTINE
END

DEF LOCALLABELVALUE(LOCALLABELINDEX2)
    RETURN (LOCALLABELS$(LOCALLABELINDEX2*3+2)**8+...
&          LOCALLABELS$(LOCALLABELINDEX2*3+3))
END
SUBROUTINE SETLOCALLABELVALUE(LOCALLABELINDEX3,SETLOCALLABELVALUEARG)
    LOCALLABELS$(LOCALLABELINDEX3*3+2)=SETLOCALLABELVALUEARG**MINUS8
    LOCALLABELS$(LOCALLABELINDEX3*3+3)=SETLOCALLABELVALUEARG&:FF
    EXIT SUBROUTINE
END

REM SYMBOL TABLE FORMAT:
REM <DEFINED FLAG TRUE/FALSE> <VV> <VV> <:FF> <SYMBOL LEN> <SYM CH.>....
REM DEFINED FLAG = FALSE --> FORWARD REF, VVVV POINTS TO LAST FWD REF LOCN
REM DEFINED FLAG = TRUE --> VVVV IS VALUE OF SYMBOL

DEF SYMBOLDEFINED(SYMBOLINDEX)=SYMBOLS$(SYMBOLINDEX)
SUBROUTINE SETSYMBOLDEFINED(SYMBOLINDEX2,SETSYMBOLDEFVALUE)
    SYMBOLS$(SYMBOLINDEX2)=SETSYMBOLDEFVALUE
    EXIT SUBROUTINE
END

DEF SYMBOLVALUE(SYMBOLINDEX3)
    RETURN (SYMBOLS$(SYMBOLINDEX3+1)**8+SYMBOLS$(SYMBOLINDEX3+2))
END
SUBROUTINE SETSYMBOLVALUE(SYMBOLINDEX5,SETSYMBOLVALUE1)
    SYMBOLS$(SYMBOLINDEX5+1)=SETSYMBOLVALUE1**MINUS8
    SYMBOLS$(SYMBOLINDEX5+2)=SETSYMBOLVALUE1&:FF
    EXIT SUBROUTINE
END

DEF SYMBOLNAME$(SYMBOLINDEX4)
    RETURN SYMBOLS$(SYMBOLINDEX4+5,SYMBOLS$(SYMBOLINDEX4+4))
END

DEF SYMBOLFIND
    LET SYMBOL$=RIGHT$(LINKINSTRUCTION$,2)
    LET SYMBOL$=FF$ CAT CHR$(LEN(SYMBOL$)) CAT SYMBOL$
    LET SYMBOL=FIND(SYMBOLS$,SYMBOL$)
    IF SYMBOL>0 THEN RETURN SYMBOL-3
    IF LEN(SYMBOLS$)+3+LEN(SYMBOL$)>MAXLEN(SYMBOLS$)
    THEN PRINT "SYMBOL TABLE OVERFLOW! "\ ERROR 65535
    ELSE
         LET SYMBOL=LEN(SYMBOLS$)+1
         LET LEN(SYMBOLS$)=LEN(SYMBOLS$)+3+LEN(SYMBOL$)
         LET SYMBOLS$(SYMBOL+3,LEN(SYMBOL$))=SYMBOL$
         LET SYMBOLDEFINED(SYMBOL)=FALSE
         LET SYMBOLVALUE(SYMBOL)=0
         RETURN SYMBOL
    FI
END

REM FORWARD REFERENCE STACK FORMAT:
REM <FWD REF1><FWD REF 2><FWD REF 3>....
REM EACH FWD REF HAS THE FORM OF A POLISH STRING (AS DESCRIBED ABOVE)
REM THE FORWARDS REFS ARE STORED IN THE BYTE ARRAY FWDREFSTORAGE$
REM WITH VALUES CONVERTED TO 16 BITS (MSBYTE AT INDEX N, LSBYTE AT N+1)
REM WITH SYMBOLS CONVERTED TO SYMBOL TABLE CHAIN POINTERS
REM AND LOCAL LABELS CONVERTED TO LOCAL LABEL CHAIN POINTERS
REM END OF MODULE CAUSES ALL LOCAL LABEL CHAINS TO BE RESOLVED
REM THE FIRST OPERATOR TO EXECUTE IN A POLISH STRING IS KEPT AT THE
REM LOWER INDEX THAN THE LAST OPERATOR.
REM THE LINKER BUILDS A POLISH STRING AT THE END OF FWDREFSTORAGE

DEF POLISHOP(POLISHINDEX)=FWDREFSTORAGE$(POLISHINDEX+1)

DEF POLISHVALUE(POLISHINDEX1)
    RETURN (FWDREFSTORAGE$(POLISHINDEX1+1)**8+...
&           FWDREFSTORAGE$(POLISHINDEX1+2))
END

SUBROUTINE SETPOLISHOP(POLISHINDEX2,SETPOLISHOPOP)
    FWDREFSTORAGE$(POLISHINDEX2+1)=SETPOLISHOPOP
    EXIT SUBROUTINE
END

SUBROUTINE SETPOLISHVALUE(POLISHINDEX3,SETPOLISHVALUEVALUE)
    FWDREFSTORAGE$(POLISHINDEX3+1)=SETPOLISHVALUEVALUE**MINUS8
    FWDREFSTORAGE$(POLISHINDEX3+2)=SETPOLISHVALUEVALUE&:FF
    EXIT SUBROUTINE
END

DEF OBJECT(OBJECTADDRESS2)
    REM ***** GET "BYTE" FROM "ADDRESS" IN OBJECT FILE *****
    REM OBJECT FILE FORMAT:
    REM <01><01><00><FE><FF><03><01><00><XX><XX><BB><BB><BB>....
    REM THE FIRST 5 BYTES ARE THE STANDARD FIRST SDOS LOAD RECORD
    REM <XX><XX> IS THE NUMBER OF BYTES ACTUALLY LOADED
    REM <BB><BB>... IS THE BINARY OBJECT BYTES
    PRINT "BUG: SOMEBODY CALLED 'OBJECT'!!"
    EXIT
END

SUBROUTINE SETOBJECT(OBJECTADDRESS1,SETOBJECTBYTE)
    REM **** PUT "BYTE" AT "ADDRESS" IN OBJECT FILE ***
    PRINT "ADDRESS=";HEX$(OBJECTADDRESS1);" BYTE= ";HEX$(SETOBJECTBYTE)
    BYTE$(1)=SETOBJECTBYTE
    WRITE #OBJECTFILE@OBJECTADDRESS1-:100+10,BYTE$
    IF OBJECTADDRESS1>MAXADDRESS THEN MAXADDRESS=OBJECTADDRESS1
    EXIT SUBROUTINE
END

DEF OBJECTWORD(OBJECTADDRESS3)
    REM *** GET "WORD" FROM "ADDRESS" IN OBJECT FILE ***
    RETURN OBJECT(OBJECTADDRESS3)**8+OBJECT(OBJECTADDRESS3+1)
END

SUBROUTINE SETOBJECTWORD(OBJECTADDRESS4,SETOBJECTWORDARG)
    REM *** PUT "WORD" AT "ADDRESS" IN OBJECT FILE ***
    OBJECT(OBJECTADDRESS4)=SETOBJECTWORDARG**MINUS8
    OBJECT(OBJECTADDRESS4+1)=SETOBJECTWORDARG&:FF
    EXIT SUBROUTINE
END

DEF TWOSCOMPLEMENT(TWOSCOMPLEMENTARG)
    IF 0<=TWOSCOMPLEMENTARG
    THEN
        IF TWOSCOMPLEMENTARG<=65535
        THEN RETURN TWOSCOMPLEMENTARG FI
    ELSE
        IF TWOSCOMPLEMENTARG>=-32768
        THEN RETURN 65536+TWOSCOMPLEMENTARG FI
    FI
    PRINT "VALUE IS TOO LARGE FOR 16 BITS!"
    RETURN 0
END
!
!      L I N K -- M A I N  C O D E
!
START: REM *** BEGIN ***
       MINUS8=-8
       POLISHEND = 0
       PRINT "LINK 1.1A"
       INPUT "" COMMANDLINE$
       LET I=FIND(COMMANDLINE$,"=")
       IF I=0 THEN COMMANDSYNTAXERR
       LET OBJECTFILE$=LEFT$(COMMANDLINE$,I)
       LET COMMANDLINE$=RIGHT$(COMMANDLINE$,I+1)
       GOSUB OBJECTFILESETUP

200    REM PROCESS NEXT LINE FULL OF OBJECT FILE NAMES
       IF COMMANDLINE$=","
       THEN INPUT "GOTTA HAVE MORE: " COMMANDLINE$
       IF FIND(COMMANDLINE$,",")=1
       THEN COMMANDLINE$=RIGHT$(COMMANDLINE$,2)
       IF COMMANDLINE$=""
       THEN ALLLINKMODULESPROCESSED
       LET I=FIND(COMMANDLINE$,",")
       IF I=0
       THEN LET RELFILE$=COMMANDLINE$ \ COMMANDLINE$=""
       ELSE LET RELFILE$=LEFT$(COMMANDLINE$,I-1) \ COMMANDLINE$=RIGHT$(COMMANDLINE$,I)
       ON ERROR GOTO BADFILENAME
       REM PROCESS A .REL FILE
       OPEN #RELFILE,RELFILE$
       ON ERROR GOTO OOPS
       LEN(LOCALLABELS$)=0 \ REM RESET THE LOCAL LABELS
       LET LEN(LINKINSTRUCTION$)=0
       LINKSTACKTOP=0 \ ! FIRST UNUSED LINK STACK SLOT
       LET OBJECTLINENUMBER=0
NEXTCMD: REM PROCESS NEXT LINK COMMAND FROM THIS MODULE
       IF LEN(LINKINSTRUCTION$)=0
       THEN
           LET OBJECTLINENUMBER=OBJECTLINENUMBER+1
           INPUT #RELFILE,LINKINSTRUCTION$
           IF EOF(RELFILE) THEN SURPRISEEOF FI
       FI
       ON FIND(LINKOPCODES$,LINKINSTRUCTION$(1,1)) GOTO...
&      LINKPUSHHEX,LINKADD,LINKSUBTRACT,LINKMULTIPLY,...
&      LINKLEFTBYTE,LINKRIGHTBYTE,LINKLOADSTACKBYTE,LINKLOADSTACKWORD,...
&      LINKPUSHLOCATIONCOUNTER,LINKPUSHDECIMAL,...
&      LINKPUSHSYMBOL,LINKPUSHLOCAL,...
&      LINKLOADHEXBYTE,LINKLOADHEXWORD,LINKLOADMULTIPLE,LINKLOADSTRING,...
&      LINKLOADDECIMALBYTE,LINKLOADDECIMALWORD,LINKLOADSYMBOLWORD,...
&      LINKSETSYMBOLHERE,LINKLOADLOCALWORD,LINKSETLOCALHERE,...
&      LINKSETLOCALTOSTACK,LINKSETLOCATIONTOSTACK,LINKSETSYMBOLTOSTACK,...
&      LINKENDMODULE
       GOTO BADLINKOP\ ! ILLEGAL OPCODE ENCOUNTERED
REM LINKOPCODES$/"K+-*<>8X.CQPHWVSDEA=L:!,#$"/

OBJECTFILESETUP:  REM PERFORM INITIAL OBJECT FILE HANDLING
       CREATE #OBJECTFILE,OBJECTFILE$
       WRITE #OBJECTFILE,OBJECTSKELETON$
       RETURN
!
!   L I N K   O P C O D E   P R O C E S S I N G
!
LINKLOADHEXBYTE:   REM HXXXX    LOAD 8 BIT HEX NUMBER
       OBJECT(LOADADDRESS)=VAL(':' CAT LINKINSTRUCTION$(2,2))
       LET LOADADDRESS=LOADADDRESS+1
       LET LINKINSTRUCTION$=RIGHT$(LINKINSTRUCTION$,4)
       GOTO NEXTCMD

LINKLOADHEXWORD:   REM WXXXX    LOAD 16 BIT HEX NUMBER
       LET OBJECTWORD(LOADADDRESS)=VAL(':' CAT LINKINSTRUCTION$(2,4))
       LET LOADADDRESS=LOADADDRESS+2
       LET LINKINSTRUCTION$=RIGHT$(LINKINSTRUCTION$,6)
       GOTO NEXTCMD

LINKLOADMULTIPLE:   REM V CC XXXXXXXXXX...  LOAD VARIABLE COUNT NUMBER OF BYTES
       LET COUNT=VAL(':' CAT LINKINSTRUCTION$(2,2))
       FOR BYTESPROCESSED=1 TO COUNT DO
           OBJECT(LOADADDRESS)=...
&              VAL(':' CAT LINKINSTRUCTION$(4+(BYTESPROCESSED-1)*2,2))
           LET LOADADDRESS=LOADADDRESS+1
       END
       LET LINKINSTRUCTION$=RIGHT$(LINKINSTRUCTION$,3+COUNT*2+1)
       GOTO NEXTCMD

LINKLOADSTRING:   REM S "STRING"     LOAD QUOTED STRING
       LET QUOTE$=LINKINSTRUCTION$(2,1)
       FOR COUNT=0 TO LEN(LINKINSTRUCTION$)-3 ...
&          WHILE LINKINSTRUCTION$(3+COUNT,1)<>QUOTE$
               OBJECT(LOADADDRESS)=LINKINSTRUCTION$(3+COUNT)
               LET LOADADDRESS=LOADADDRESS+1
       END
       LINKINSTRUCTION$=RIGHT$(LINKINSTRUCTION$,4+COUNT)
       GOTO NEXTCMD

LINKLOADDECIMALBYTE:   REM DXXXXX<CR>     LOAD 8 BIT DECIMAL CONSTANT
       OBJECT(LOADADDRESS)=VAL(RIGHT$(LINKINSTRUCTION$,2))
       LET LOADADDRESS=LOADADDRESS+1
       LET LINKINSTRUCTION$=''
       GOTO NEXTCMD

LINKLOADDECIMALWORD:   REM EDDDDD<CR>     LOAD 16 BIT DECIMAL CONSTANT
       OBJECTWORD(LOADADDRESS)=VAL(RIGHT$(LINKINSTRUCTION$,2))
       LET LOADADDRESS=LOADADDRESS+2
       LET LINKINSTRUCTION$=''
       GOTO NEXTCMD

LINKLOADSYMBOLWORD:
       REM ASYMBOL<CR>    LOAD VALUE OF GLOBAL SYMBOL INTO NEXT 16 BITS
       REM FIND SYMBOL IN SYMBOL TABLE
       LET SYMBOL=SYMBOLFIND
       IF SYMBOLDEFINED(SYMBOL)
       THEN LET OBJECTWORD(LOADADDRESS)=SYMBOLVALUE(SYMBOL)
       ELSE
           REM SYMBOL IS NOT DEFINED, BUILD A FORWARD REFERENCE ITEM
           POLISHOP(POLISHEND)=LINKOPPUSHVALUE
           POLISHVALUE(POLISHEND+1)=SYMBOLVALUE(SYMBOL)
           SYMBOLVALUE(SYMBOL)=POLISHEND+1
           POLISHOP(POLISHEND+3)=LINKOPLOADWORD
           POLISHVALUE(POLISHEND+4)=LOADADDRESS
           POLISHEND=POLISHEND+6
       FI
       LET LOADADDRESS=LOADADDRESS+2
       LET LINKINSTRUCTION$=''
       GOTO NEXTCMD

LINKSETSYMBOLHERE:   REM =SYMBOL<CR>     SET VALUE OF GLOBAL SYMBOL TO HERE
       REM FIND SYMBOL IN SYMBOL TABLE
       LET SYMBOL=SYMBOLFIND
       LET SYMBOLDEFINITION=LOADADDRESS
DEFINESYMBOL: ! GLOBAL SYMBOLS MAY NOT BE RE-DEFINED
       IF SYMBOLDEFINED(SYMBOL)
       THEN
            PRINT "DOUBLY-DEFINED SYMBOL: ";SYMBOLNAME$(SYMBOL)
            GOTO PRINTMODULENAMEQUIT
       ELSE
           REM SYMBOL IS SUITABLY UNDEFINED, NOW DEFINE IT!
           SYMBOLDEFINED(SYMBOL)=TRUE
           LET POLISHREFERENCE=SYMBOLVALUE(SYMBOL)
           LET SYMBOLVALUE(SYMBOL)=SYMBOLDEFINITION
           UNTIL POLISHREFERENCE=0 DO
               TEMP=POLISHVALUE(POLISHREFERENCE)
               LET POLISHVALUE(POLISHREFERENCE)=SYMBOLVALUE(SYMBOL)
               LET POLISHREFERENCE=TEMP
           END
           LET LINKINSTRUCTION$=''
           GOTO NEXTCMD
       FI

LINKLOADLOCALWORD:
       REM LNNNN     LOAD VALUE OF LOCAL LABEL NUMBER INTO NEXT 16 BITS
       LET LOCALLABELNUMBER=VAL(':' CAT RIGHT$(LINKINSTRUCTION$,2))
       IF LOCALLABELDEFINED(LOCALLABELNUMBER)
       THEN LET OBJECTWORD(LOADADDRESS)=LOCALLABELVALUE(LOCALLABELNUMBER)
       ELSE
           REM SYMBOL IS NOT DEFINED, BUILD A FORWARD REFERENCE ITEM
           POLISHOP(POLISHEND)=LINKOPPUSHVALUE
           POLISHVALUE(POLISHEND+1)=LOCALLABELVALUE(LOCALLABELNUMBER)
           LOCALLABELVALUE(LOCALLABELNUMBER)=POLISHEND+1
           POLISHOP(POLISHEND+3)=LINKOPLOADWORD
           POLISHVALUE(POLISHEND+4)=LOADADDRESS
           POLISHEND=POLISHEND+6
       FI
       LET LOADADDRESS=LOADADDRESS+2
       LET LINKINSTRUCTION$=''
       GOTO NEXTCMD

LINKSETLOCALTOSTACK: REM !XXXX<CR>     SET LOCAL LABEL TO LINKSTACK RESULT
       LET LOCALLABELNUMBER=VAL(':' CAT RIGHT$(LINKINSTRUCTION$,2))
       IF LINKSTACKTOP<>1 THEN LINKSTKNOTONEDEEP
       LINKSTACKTOP=0
       LET SYMBOLDEFINITION=LINKSTACK(0)
       IF LOCALLABELDEFINED(LOCALLABELNUMBER)
       THEN LET LOCALLABELVALUE(LOCALLABELNUMBER)=0\ REM KILL OFF REF CHAIN
       GOTO LOCALLABELDEFINITION

LINKSETLOCALHERE:   REM :NNNN     SET VALUE OF LOCAL LABEL TO HERE
       LET LOCALLABELNUMBER=VAL(':' CAT RIGHT$(LINKINSTRUCTION$,2))
       SYMBOLDEFINITION=LOADADDRESS
       IF LOCALLABELDEFINED(LOCALLABELNUMBER)
       THEN
            PRINT "DOUBLY-DEFINED LOCAL LABEL: ";HEX$(LOCALLABELNUMBER)
            GOTO PRINTMODULENAMEQUIT
       FI
LOCALLABELDEFINITION: ! LOCAL SYMBOLS MAY BE REDEFINED ONLY BY LINKSTACK RESULT
       REM LOCAL LABEL IS SUITABLY UNDEFINED, NOW DEFINE IT!
       LOCALLABELDEFINED(LOCALLABELNUMBER)=TRUE
       LET POLISHREFERENCE=LOCALLABELVALUE(LOCALLABELNUMBER)
       LET LOCALLABELVALUE(LOCALLABELNUMBER)=SYMBOLDEFINITION
       UNTIL POLISHREFERENCE=0 DO
!          PRINT "POLISH REFERENCE = "; POLISHREFERENCE
           TEMP=POLISHVALUE(POLISHREFERENCE)
           LET POLISHVALUE(POLISHREFERENCE)=LOCALLABELVALUE(LOCALLABELNUMBER)
           LET POLISHREFERENCE=TEMP
       END
       LET LINKINSTRUCTION$=''
       GOTO NEXTCMD

LINKENDMODULE:   REM $     END OF MODULE
       REM SPIN THRU LOCAL LABEL TABLE TO MAKE SURE ALL ARE DEF'D
       FOR LOCALLABELNUMBER=0 TO INT(LEN(LOCALLABELS$)/3)-1
           IF NOT(LOCALLABELDEFINED(LOCALLABELNUMBER))...
&             AND LOCALLABELVALUE(LOCALLABELNUMBER)<>0
           THEN
                PRINT "UNDEFINED LOCAL LABEL: ";HEX$(LOCALLABELNUMBER)
                GOTO PRINTMODULENAMEQUIT
           FI
       END
       CLOSE #RELFILE
       GOTO 200

LINKPUSHDECIMAL:   REM CDDDD<CR> -- PUSH DECIMAL CONSTANT ONTO LINK STACK
       LINKSTACK(LINKSTACKTOP)=VAL(RIGHT$(LINKINSTRUCTION$,2))
       LINKSTACKTOP=LINKSTACKTOP+1
       LINKINSTRUCTION$=''
       GOTO NEXTCMD

LINKPUSHHEX:   REM KXXXX<CR> -- PUSH HEX CONSTANT ONTO LINK STACK
       LINKSTACK(LINKSTACKTOP)=VAL(":" CAT RIGHT$(LINKINSTRUCTION$,2))
       LINKSTACKTOP=LINKSTACKTOP+1
       LINKINSTRUCTION$=''
       GOTO NEXTCMD

LINKPUSHSYMBOL: REM QSSSSS<CR> -- PUSH VALUE OF GLOBAL SYMBOL ONTO LINK STACK
       REM FIND SYMBOL IN SYMBOL TABLE
       LET SYMBOL=SYMBOLFIND
       IF SYMBOLDEFINED(SYMBOL)
       THEN
           LINKSTACK(LINKSTACKTOP)=SYMBOLVALUE(SYMBOL)
           LINKSTACKTOP=LINKSTACKTOP+1
           LET LINKINSTRUCTION$=''
       ELSE
           REM SYMBOL IS NOT DEFINED, BUILD A FORWARD REFERENCE ITEM
           GOSUB COPYLINKSTACKTOFREF
           POLISHOP(POLISHEND)=LINKOPPUSHVALUE
           POLISHVALUE(POLISHEND+1)=SYMBOLVALUE(SYMBOL)
           SYMBOLVALUE(SYMBOL)=POLISHEND+1
           POLISHEND=POLISHEND+3
           LET LINKINSTRUCTION$=''
           LET LINKSTACKTOP=LINKSTACKTOP+1
           GOSUB COPYRESTOFPOLISHTOFREF
       FI
       GOTO NEXTCMD

LINKPUSHLOCAL:   REM PXXXX<CR> -- PUSH VALUE OF LOCAL LABEL ONTO LINK STACK
       LET LOCALLABELNUMBER=VAL(':' CAT RIGHT$(LINKINSTRUCTION$,2))
       IF LOCALLABELDEFINED(LOCALLABELNUMBER)
       THEN
           LINKSTACK(LINKSTACKTOP)=LOCALLABELVALUE(LOCALLABELNUMBER)
           LINKSTACKTOP=LINKSTACKTOP+1
           LET LINKINSTRUCTION$=''
       ELSE
           REM SYMBOL IS NOT DEFINED, BUILD A FORWARD REFERENCE ITEM
           GOSUB COPYLINKSTACKTOFREF
           POLISHOP(POLISHEND)=LINKOPPUSHVALUE
           POLISHVALUE(POLISHEND+1)=LOCALLABELVALUE(LOCALLABELNUMBER)
           LOCALLABELVALUE(LOCALLABELNUMBER)=POLISHEND+1
           POLISHEND=POLISHEND+3
           LET LINKINSTRUCTION$=''
           LET LINKSTACKTOP=LINKSTACKTOP+1
           GOSUB COPYRESTOFPOLISHTOFREF
       FI
       GOTO NEXTCMD

LINKADD:   REM +      ADD TOP TWO LINK STACK ENTRIES TOGETHER
       IF LINKSTACKTOP<2 THEN LINKSTKTOOSHORT
       LINKSTACKTOP=LINKSTACKTOP-1
       LINKSTACK(LINKSTACKTOP-1)=LINKSTACK(LINKSTACKTOP-1)+...
&          LINKSTACK(LINKSTACKTOP)
       LET LINKINSTRUCTION$=RIGHT$(LINKINSTRUCTION$,2)
       GOTO NEXTCMD

LINKSUBTRACT: REM - SUBTRACT TOP OF LINK STACK FROM SECOND TO TOP ENTRY
       IF LINKSTACKTOP<2 THEN LINKSTKTOOSHORT
       LINKSTACKTOP=LINKSTACKTOP-1
       LINKSTACK(LINKSTACKTOP-1)=LINKSTACK(LINKSTACKTOP-1)-...
&          LINKSTACK(LINKSTACKTOP)
       LET LINKINSTRUCTION$=RIGHT$(LINKINSTRUCTION$,2)
       GOTO NEXTCMD

LINKMULTIPLY:   REM *       MULTIPLY TOP TWO LINK STACK ENTRIES TOGETHER
       IF LINKSTACKTOP<2 THEN LINKSTKTOOSHORT
       LINKSTACKTOP=LINKSTACKTOP-1
       LINKSTACK(LINKSTACKTOP-1)=LINKSTACK(LINKSTACKTOP-1)*...
&          LINKSTACK(LINKSTACKTOP)
       LET LINKINSTRUCTION$=RIGHT$(LINKINSTRUCTION$,2)
       GOTO NEXTCMD

LINKLEFTBYTE:   REM <       TAKE LEFTMOST 8 BITS OF TOP OF LINK STACK
       IF LINKSTACKTOP<1 THEN LINKSTKTOOSHORT
       LINKSTACK(LINKSTACKTOP-1)=...
&         TWOSCOMPLEMENT(LINKSTACK(LINKSTACKTOP-1))**-8
       LET LINKINSTRUCTION$=RIGHT$(LINKINSTRUCTION$,2)
       GOTO NEXTCMD

LINKRIGHTBYTE:   REM >       TAKE RIGHTMOST 8 BITS OF TOP OF LINK STACK
       IF LINKSTACKTOP<1 THEN LINKSTKTOOSHORT
       LINKSTACK(LINKSTACKTOP-1)=...
&         TWOSCOMPLEMENT(LINKSTACK(LINKSTACKTOP-1))&:FF
       LET LINKINSTRUCTION$=RIGHT$(LINKINSTRUCTION$,2)
       GOTO NEXTCMD

LINKLOADSTACKBYTE:   REM "8"     LOAD VALUE OF LINKSTACK INTO NEXT 8 BITS
       IF LINKSTACKTOP<>1 THEN LINKSTKNOTONEDEEP
       LET LINKSTACKTOP=0
       LET BYTE=TWOSCOMPLEMENT(LINKSTACK(0))
       LET TEMP=BYTE**MINUS8
       LET BYTE=BYTE&:FF
       IF TEMP=:FF AND BYTE&:80=0 OR TEMP<>0 AND TEMP<>:FF
       THEN VALUETOOBIGFORBYTE
       LET OBJECT(LOADADDRESS)=BYTE
       LET LOADADDRESS=LOADADDRESS+1
       LET LINKINSTRUCTION$=RIGHT$(LINKINSTRUCTION$,2)
       GOTO NEXTCMD

LINKLOADSTACKWORD:   REM X        LOAD VALUE OF LINKSTACK INTO NEXT 16 BITS
       IF LINKSTACKTOP<>1 THEN LINKSTKNOTONEDEEP
       LET LINKSTACKTOP=0
       LET OBJECTWORD(LOADADDRESS)=TWOSCOMPLEMENT(LINKSTACK(0))
       LET LOADADDRESS=LOADADDRESS+2
       LET LINKINSTRUCTION$=RIGHT$(LINKINSTRUCTION$,2)
       GOTO NEXTCMD

LINKPUSHLOCATIONCOUNTER: REM . PUSH VALUE OF LOCATION COUNTER ONTO LINK STACK
       LINKSTACK(LINKSTACKTOP)=LOADADDRESS
       LINKSTACKTOP=LINKSTACKTOP+1
       LET LINKINSTRUCTION$=RIGHT$(LINKINSTRUCTION$,2)
       GOTO NEXTCMD

LINKSETLOCATIONTOSTACK:
       REM , SET LOCATION COUNTER TO VALUE ON TOP OF LINK STACK
       IF LINKSTACKTOP<>1 THEN LINKSTKNOTONEDEEP
       LET LOADADDRESS=LINKSTACK(0)
       LET LINKSTACKTOP=0
       LET LINKINSTRUCTION$=RIGHT$(LINKINSTRUCTION$,2)
       GOTO NEXTCMD

LINKSETSYMBOLTOSTACK:
       REM #SSSSS<CR> DEFINE VALUE OF GLOBAL SYMBOL TO BE LINK STACK RESULT
       REM FIND SYMBOL IN SYMBOL TABLE
       LET SYMBOL=SYMBOLFIND
       IF LINKSTACKTOP<>1 THEN LINKSTKNOTONEDEEP
       LET LINKSTACKTOP=0
       LET SYMBOLDEFINITION=LINKSTACK(0)
       GOTO DEFINESYMBOL

!
!      F O R W A R D   R E F E R E N C E   H A N D L I N G
!
COPYLINKSTACKTOFREF: ! COPY CURRENT CONTENTS OF LINK STACK TO FREF POLISH
       FOR I=0 TO LINKSTACKTOP-1
           POLISHOP(POLISHEND)=LINKOPPUSHVALUE
           POLISHVALUE(POLISHEND+1)=LINKSTACK(I)
           POLISHEND=POLISHEND+3
       NEXT I
       RETURN

COPYRESTOFPOLISHTOFREF: ! COPY INPUT TO FREF POLISH UNTIL FREF EXP IS COMPLETE
FREFNEXTCMD: REM PROCESS NEXT LINK COMMAND FROM THIS MODULE
       IF LEN(LINKINSTRUCTION$)=0
       THEN
           LET OBJECTLINENUMBER=OBJECTLINENUMBER+1
           INPUT #RELFILE,LINKINSTRUCTION$
           IF EOF(RELFILE) THEN SURPRISEEOF FI
       FI
       ON FIND(LINKOPCODES$,LINKINSTRUCTION$(1,1)) GOTO...
&      FREFPUSHHEXCONSTANT,FREFADD,FREFSUBTRACT,FREFMULTIPLY,...
&      FREFLEFTBYTE,FREFRIGHTBYTE,FREFLOADSTACKBYTE,FREFLOADSTACKWORD,...
&      FREFPUSHLOCATIONCOUNTER,FREFPUSHDECIMALCONSTANT,...
&      FREFPUSHSYMBOL,FREFPUSHLOCALLABEL
       PRINT "BAD POLISH STRING"
       GOTO PRINTOBJECTLINEQUIT
FREFCOMPLETE: RETURN

FREFPUSHHEXCONSTANT: REM KXXXX<CR> -- PUSH HEX CONSTANT ONTO LINK STACK
       POLISHOP(POLISHEND)=LINKOPPUSHVALUE
       POLISHVALUE(POLISHEND+1)=VAL(":" CAT RIGHT$(LINKINSTRUCTION$,2))
       POLISHEND=POLISHEND+3
       LINKSTACKTOP=LINKSTACKTOP+1
       LINKINSTRUCTION$=''
       GOTO FREFNEXTCMD

FREFADD: REM +      ADD TOP TWO LINK STACK ENTRIES TOGETHER
       IF LINKSTACKTOP<2 THEN LINKSTKTOOSHORT
       POLISHOP(POLISHEND)=LINKOPADD
       POLISHEND=POLISHEND+1
       LINKSTACKTOP=LINKSTACKTOP-1
       LET LINKINSTRUCTION$=RIGHT$(LINKINSTRUCTION$,2)
       GOTO FREFNEXTCMD

FREFSUBTRACT: REM - SUBTRACT TOP OF LINK STACK FROM SECOND TO TOP ENTRY
       IF LINKSTACKTOP<2 THEN LINKSTKTOOSHORT
       POLISHOP(POLISHEND)=LINKOPSUBTRACT
       POLISHEND=POLISHEND+1
       LINKSTACKTOP=LINKSTACKTOP-1
       LET LINKINSTRUCTION$=RIGHT$(LINKINSTRUCTION$,2)
       GOTO FREFNEXTCMD

FREFMULTIPLY: REM *       MULTIPLY TOP TWO LINK STACK ENTRIES TOGETHER
       IF LINKSTACKTOP<2 THEN LINKSTKTOOSHORT
       POLISHOP(POLISHEND)=LINKOPMULTIPLY
       POLISHEND=POLISHEND+1
       LINKSTACKTOP=LINKSTACKTOP-1
       LET LINKINSTRUCTION$=RIGHT$(LINKINSTRUCTION$,2)
       GOTO FREFNEXTCMD

FREFLEFTBYTE:   REM <       TAKE LEFTMOST 8 BITS OF TOP OF LINK STACK
       IF LINKSTACKTOP<1 THEN LINKSTKTOOSHORT
       POLISHOP(POLISHEND)=LINKOPLEFTBYTE
       POLISHEND=POLISHEND+1
       LET LINKINSTRUCTION$=RIGHT$(LINKINSTRUCTION$,2)
       GOTO FREFNEXTCMD

FREFRIGHTBYTE:   REM >       TAKE RIGHTMOST 8 BITS OF TOP OF LINK STACK
       IF LINKSTACKTOP<1 THEN LINKSTKTOOSHORT
       POLISHOP(POLISHEND)=LINKOPRIGHTBYTE
       POLISHEND=POLISHEND+1
       LET LINKINSTRUCTION$=RIGHT$(LINKINSTRUCTION$,2)
       GOTO FREFNEXTCMD

FREFLOADSTACKBYTE: REM "8"     LOAD VALUE OF LINKSTACK INTO NEXT 8 BITS
       IF LINKSTACKTOP<>1 THEN LINKSTKNOTONEDEEP
       LET LINKSTACKTOP=0
       POLISHOP(POLISHEND)=LINKOPLOADBYTE
       POLISHEND=POLISHEND+3
       LET LOADADDRESS=LOADADDRESS+1
       LET LINKINSTRUCTION$=RIGHT$(LINKINSTRUCTION$,2)
       GOTO FREFCOMPLETE

FREFLOADSTACKWORD: REM X        LOAD VALUE OF LINKSTACK INTO NEXT 16 BITS
       IF LINKSTACKTOP<>1 THEN LINKSTKNOTONEDEEP
       LET LINKSTACKTOP=0
       POLISHOP(POLISHEND)=LINKOPLOADWORD
       POLISHVALUE(POLISHEND+1)=LOADADDRESS
       POLISHEND=POLISHEND+3
       LET LOADADDRESS=LOADADDRESS+2
       LET LINKINSTRUCTION$=RIGHT$(LINKINSTRUCTION$,2)
       GOTO FREFCOMPLETE

FREFPUSHLOCATIONCOUNTER: REM . PUSH VALUE OF LOCATION COUNTER ONTO LINK STACK
       POLISHOP(POLISHEND)=LINKOPPUSHVALUE
       POLISHVALUE(POLISHEND+1)=LOADADDRESS
       POLISHEND=POLISHEND+3
       LINKSTACKTOP=LINKSTACKTOP+1
       LET LINKINSTRUCTION$=RIGHT$(LINKINSTRUCTION$,2)
       GOTO FREFNEXTCMD

FREFPUSHDECIMALCONSTANT: REM CDDDD<CR> -- PUSH DECIMAL CONSTANT ONTO LINK STACK
       POLISHOP(POLISHEND)=LINKOPPUSHVALUE
       POLISHVALUE(POLISHEND+1)=VAL(RIGHT$(LINKINSTRUCTION$,2))
       POLISHEND=POLISHEND+3
       LINKSTACKTOP=LINKSTACKTOP+1
       LINKINSTRUCTION$=''
       GOTO FREFNEXTCMD

FREFPUSHSYMBOL: REM QSSSSS<CR> -- PUSH VALUE OF GLOBAL SYMBOL ONTO LINK STACK
       REM FIND SYMBOL IN SYMBOL TABLE
       LET SYMBOL=SYMBOLFIND
       POLISHOP(POLISHEND)=LINKOPPUSHVALUE
       POLISHVALUE(POLISHEND+1)=SYMBOLVALUE(SYMBOL)
       POLISHEND=POLISHEND+3
       IF NOT(SYMBOLDEFINED(SYMBOL))
       THEN
           REM SYMBOL IS NOT DEFINED, EXTEND FWD REF CHAIN
           SYMBOLVALUE(SYMBOL)=POLISHEND-2
       FI
       LINKSTACKTOP=LINKSTACKTOP+1
       LET LINKINSTRUCTION$=''
       GOTO FREFNEXTCMD

FREFPUSHLOCALLABEL: REM PXXXX<CR>    PUSH VALUE OF LOCAL LABEL ONTO LINK STACK
       LET LOCALLABELNUMBER=VAL(':' CAT RIGHT$(LINKINSTRUCTION$,2))
       POLISHOP(POLISHEND)=LINKOPPUSHVALUE
       POLISHVALUE(POLISHEND+1)=LOCALLABELVALUE(LOCALLABELNUMBER)
           POLISHEND=POLISHEND+3
       IF NOT(LOCALLABELDEFINED(LOCALLABELNUMBER))
       THEN
           REM SYMBOL IS NOT DEFINED, EXTEND FWD REF CHAIN
           LOCALLABELVALUE(LOCALLABELNUMBER)=POLISHEND-2
       FI
       LINKSTACKTOP=LINKSTACKTOP+1
       LET LINKINSTRUCTION$=''
       GOTO FREFNEXTCMD
!
!    E N D   O F   L I N K   E D I T    P R O C E S S I N G
!
ALLLINKMODULESPROCESSED:
    PRINT ">>> SYMBOL TABLE <<<"
    LET SYMBOL=1
    LET NUMBEROFUNDEFINEDS=0
    UNTIL SYMBOL>LEN(SYMBOLS$) DO
          IF SYMBOLDEFINED(SYMBOL)
          THEN LET TEMP$=HEX$(SYMBOLVALUE(SYMBOL))
          ELSE
               LET NUMBEROFUNDEFINEDS=NUMBEROFUNDEFINEDS+1
               LET TEMP$=" ****"
          FI
          PRINT TEMP$;"  ";SYMBOLNAME$(SYMBOL)
          LET SYMBOL=SYMBOL+SYMBOLS$(SYMBOL+4)+5
    END
    PRINT NUMBEROFUNDEFINEDS;" UNDEFINED SYMBOLS"
    REM NOW PROCESS FORWARD REFERENCES
    REM POLISH EXPRESSIONS HAVE BEEN SYNTAX CHECKED, SO NO
    REM STACK OVERFLOW/UNDERFLOW PROCESSING IS REQUIRED
    LET LINKSTACKTOP=0
    LET POLISHSCAN=0
    UNTIL POLISHSCAN>=POLISHEND DO
!       PRINT "POLISH SCAN = " ; POLISHSCAN;" POLISHOP = "; POLISHOP(POLISHSCAN)
        ON POLISHOP(POLISHSCAN) GOSUB...
&       POLISHPUSHVALUE,POLISHADD,POLISHSUBTRACT,POLISHMULTIPLY,...
&       POLISHLEFTBYTE,POLISHRIGHTBYTE,POLISHLOADSTACKBYTE,POLISHLOADSTACKWORD
    END
    REM PERFORM OBJECT FILE CLEANUP
    LET OBJECTWORD(:FE)=MAXADDRESS+1-:100
    GOTO SHAZAM
!
!   P O L I S H   E X E C U T I O N
!
POLISHPUSHVALUE:
    LINKSTACK(LINKSTACKTOP)=POLISHVALUE(POLISHSCAN+1)
!   PRINT "POLISH PUSH: ";HEX$(LINKSTACK(LINKSTACKTOP))
    LINKSTACKTOP=LINKSTACKTOP+1
    POLISHSCAN=POLISHSCAN+3
    RETURN

POLISHADD:
    LINKSTACK(LINKSTACKTOP-2)=LINKSTACK(LINKSTACKTOP-2)+...
&        LINKSTACK(LINKSTACKTOP-1)
    LINKSTACKTOP=LINKSTACKTOP-1
    POLISHSCAN=POLISHSCAN+1
    RETURN

POLISHSUBTRACT:
    LINKSTACK(LINKSTACKTOP-2)=LINKSTACK(LINKSTACKTOP-2)-...
&        LINKSTACK(LINKSTACKTOP-1)
    LINKSTACKTOP=LINKSTACKTOP-1
    POLISHSCAN=POLISHSCAN+1
    RETURN

POLISHMULTIPLY:
    LINKSTACK(LINKSTACKTOP-2)=LINKSTACK(LINKSTACKTOP-2)*...
&        LINKSTACK(LINKSTACKTOP-1)
    LINKSTACKTOP=LINKSTACKTOP-1
    POLISHSCAN=POLISHSCAN+1
    RETURN

POLISHLEFTBYTE:
    LINKSTACK(LINKSTACKTOP-1)=...
&        TWOSCOMPLEMENT(LINKSTACK(LINKSTACKTOP-1))**MINUS8
    POLISHSCAN=POLISHSCAN+1
    RETURN

POLISHRIGHTBYTE:
    LINKSTACK(LINKSTACKTOP-1)=...
&        TWOSCOMPLEMENT(LINKSTACK(LINKSTACKTOP-1))&:7F
    POLISHSCAN=POLISHSCAN+1
    RETURN

POLISHLOADSTACKBYTE:
    LET BYTE=TWOSCOMPLEMENT(LINKSTACK(0))
    LET TEMP=BYTE**MINUS8
    LET BYTE=BYTE&:FF
    IF TEMP=:FF AND BYTE&:80=0 OR TEMP<>0 AND TEMP<>:FF
    THEN VALUETOOBIGFORBYTE
    OBJECT(POLISHVALUE(POLISHSCAN+1))=BYTE
    LINKSTACKTOP=0
    POLISHSCAN=POLISHSCAN+3
    RETURN

POLISHLOADSTACKWORD:
!   PRINT "RESOLVE FREF: ";HEX$(POLISHVALUE(POLISHSCAN+1));...
!&        " VALUE: ";TWOSCOMPLEMENT(LINKSTACK(0))
    OBJECTWORD(POLISHVALUE(POLISHSCAN+1))=...
&        TWOSCOMPLEMENT(LINKSTACK(0))
    LINKSTACKTOP=0
    POLISHSCAN=POLISHSCAN+3
    RETURN

LINKSTKNOTONEDEEP: PRINT "LINK STACK DEPTH <> 1"
 GOTO PRINTOBJECTLINEQUIT

LINKSTKTOOSHORT: PRINT "LINK STACK DOES NOT HAVE ENOUGH OPERANDS"
 GOTO PRINTOBJECTLINEQUIT

COMMANDSYNTAXERR: PRINT "COMMAND SYNTAX IS:"
 PRINT " .LINK OUTPUTFILE=FILE1,FILE2,FILE3,..."
 GOTO SHAZAM

BADFILENAME: PRINT RELFILE$
        ERROR

VALUETOOBIGFORBYTE: PRINT "LINK STACK RESULT TOO LARGE FOR BYTE"
    GOTO PRINTOBJECTLINEQUIT

SURPRISEEOF: PRINT "PREMATURE END OF FILE";
 GOTO PRINTMODULENAMEQUIT

BADLINKOP: PRINT "ILLEGAL LINK INSTRUCTION"
 GOTO PRINTOBJECTLINEQUIT

OOPS: PRINT "OOPS... I GOT ERROR #";ERR;" AT LINE ";ELN;" (HEX ";HEX$(ELN);")"
PRINTOBJECTLINEQUIT: PRINT "IN OBJECT LINE ";OBJECTLINENUMBER;...
&        " WHILE WORKING ON ";LINKINSTRUCTION$
PRINTMODULENAMEQUIT: PRINT "IN MODULE ";RELFILE$
SHAZAM: ON ERROR GOTO 0
    END
