10 REM > Assem117/s
   20 ver$="1.17"
   30 REM v1.15 29-May-1999 Removed bug code on exit, some tidying
   40 REM v1.16 31-May-1999 Will Assem from text files, PrDec tidied up
   50 REM v1.17 15-Feb-2018 Optimised, replaced PrDec, fits without running into &B00
   60 :
   70 OSRDCH=&FFE0:OSNEWL=&FFE7:OSWRCH=&FFEE:OSWORD=&FFF1
   80 OSARGS=&FFDA:OSFIND=&FFCE:OSBGET=&FFD7:OSWRCR=&FFEC
   90 OSASCI=&FFE3:BRKV=&0202:WORDV=&020C
  100 :
  110 blk=&A8:lptr=&AA:arg=&AC
  120 PRPAD=&80:PRTEMP=&81:LineNumber=&82:len=&85
  130 Handle=&86:HandleFirst=&87:InsideAssem=&88
  140 ErrFlag=&89:FileType=&8A
  150 :
  160 DIM mcode% &300:load%=&FFFF08C0
  170 :
  180 FORP=0TO1
  190   O%=mcode%:P%=load%
  200   [OPT P*3+4
  210   .FileNotFound
  220   BRK:EQUB 214:EQUS "File not found":BRK
  230   :
  240   .go%
  250   LDY #&00:STY ErrFlag:STY InsideAssem   :\ Clear flags
  260   LDA #&01:LDX #lptr:JSR OSARGS
  270   LDX lptr+0:LDY lptr+1:LDA #&40:JSR OSFIND
  280   TAY:BEQ FileNotFound
  290   STY Handle:STY HandleFirst:JSR CheckFileType :\ Check if Basic or Text
  300   JSR SwapVectors                        :\ Set up the vectors
  310   :
  320   .PrintPass                             :\ Print the current pass
  330   LDX #MsgPass-MsgBase
  340   .PrMessage
  350   LDA MsgBase,X:BEQ PrMsgDone
  360   JSR OSASCI:INX:BNE PrMessage
  370   :
  380   .NewWORD
  390   CMP #&00:BEQ Word0:JMP (OldWORDV)
  400   .Word0
  410   STA len                                :\ Clear line length
  420   STX blk+0:STY blk+1                    :\ Point to block
  430   TAY:LDA (blk),Y:STA lptr+0
  440   INY:LDA (blk),Y:STA lptr+1             :\ Get pointer to input buffer
  450   LDA ErrFlag:BEQ WasNoError             :\ Re-entering after an error?
  460   LDX #MsgIgnore-MsgBase:JSR PrMessage
  470   LDA &0256:PHA:LDA &0268:PHA            :\ Save Exec and FKey handles
  480   LDA #0:STA &0256:STA &0268:STA ErrFlag :\ Clear Exec and FKey handles
  490   JSR OSRDCH:AND #&DF:PHA:JSR OSNEWL     :\ Get a key-press
  500   PLA:CMP #ASC"N":BNE IgnoreError        :\ If not 'N', ignore error
  510   PLA:PLA:BEQ NoExecFileOpen
  520   TAY:JSR CloseY                         :\ Close the EXEC file
  530   .NoExecFileOpen
  540   JMP EndOfAssem
  550   :
  560   .PrMsgDone
  570   .EscapePressed
  580   SEC:RTS
  590   :
  600   .IgnoreError
  610   PLA:STA &0268:PLA:STA &0256              :\ Restore Exec and FKey handles
  620   .WasNoError
  630   LDA PassChar:CMP #ASC"5":BCS ReadLineHeader
  640   .PrintAddr
  650   LDA &0440,Y:JSR PrHex:DEY:BPL PrintAddr  :\ Print P%
  660   .ReadLineHeader
  670   INC LineNumber:BNE P%+4:INC LineNumber+1 :\ Inc line number for text file
  680   JSR OSWRCR:LDY Handle                    :\ Print a CR
  690   BIT FileType:BMI SkipLineSpaces          :\ Text file, no line numbers
  700   LDX #2
  710   .ReadLineLp
  720   JSR OSBGET:BCS EndReached                :\ Get line number
  730   STA LineNumber-1,X:DEX:BPL ReadLineLp    :\ and skip line length
  740   LDX LineNumber+1:INX:BEQ EndReached
  750   .SkipLineSpaces
  760   JSR OSBGET:BCS EndReached
  770   CMP #ASC" ":BEQ SkipLineSpaces
  780   LDY #&00:LDX #&FF
  790   CMP #ASC"[":BEQ StartLine                :\ X=&FF, start assembler code
  800   BIT InsideAssem:BPL ReadLine             :\ Outside assembler
  810   PHA
  820   .InsertOPT
  830   LDA MsgOPT,Y:STA (lptr),Y:INY
  840   CMP #ASC":":BNE InsertOPT                :\ Put OPT at start of line
  850   PLA:CMP #ASC"]":BNE ReadLine             :\ End of assembler?
  860   INX                                      :\ X=&00, end assembler code
  870   .StartLine
  880   STX InsideAssem
  890   .ReadLine
  900   STA (lptr),Y:INY:STY len
  910   CMP #&0D:BEQ EndOfLine
  920   CMP #&0A:BEQ EndOfLine
  930   BIT &FF:BMI EscapePressed
  940   LDY Handle:JSR OSBGET:BCS EndReached
  950   LDY len:BNE ReadLine
  960   .EndOfLine
  970   LDY #&00:LDA (lptr),Y
  980   CMP #ASC">":BEQ NextFile
  990   LDY len:CLC:RTS
 1000   :
 1010   .EndReached
 1020   LDA PassChar:CMP #ASC"5":BCS EndOfAssem  :\ Very end reached in pass 2
 1030   INC MsgPass+5:LDA #ASC"7":STA PassChar   :\ Set the number for pass 2
 1040   JSR PrintPass:JSR CloseIfNotFirst
 1050   LDY HandleFirst:STY Handle:JSR RewindFile
 1060   .StartAFile
 1070   JSR CheckFileType:JMP ReadLineHeader
 1080   :
 1090   .CheckFileType
 1100   LDA #0:STA FileType:STA LineNumber:STA LineNumber+1
 1110   JSR OSBGET:CMP #13:BEQ SwapVectorsEnd  :\ Look at first byte
 1120   DEC FileType                           :\ Flag as Text, and rewind
 1130   :
 1140   .RewindFile
 1150   LDX #3:LDA #0
 1160   .Rewind
 1170   STA arg,X:DEX:BPL Rewind
 1180   LDX #arg:LDA #&01:JMP OSARGS           :\ Rewind to start of file
 1190   :
 1200   .NextFile
 1210   JSR CloseIfNotFirst
 1220   LDX lptr+0:LDY lptr+1
 1230   INX:BNE P%+3:INY                       :\ Point to filename in buffer
 1240   LDA #&40:JSR OSFIND:STA Handle
 1250   TAY:BNE StartAFile                     :\ If not present, will fall thru
 1260   :
 1270   .CloseIfNotFirst
 1280   LDY Handle:CPY HandleFirst:BEQ SwapVectorsEnd
 1290   :
 1300   .CloseY
 1310   LDA #&00:JMP OSFIND
 1320   :
 1330   .EndOfAssem
 1340   JSR CloseIfNotFirst:LDY HandleFirst:JSR CloseY
 1350   LDY #0:LDA #&0D:STA (lptr),Y           :\ Length=0, CR in position
 1360   .SwapVectors
 1370   PHP:SEI:LDY #2
 1380   .SwapVecLp
 1390   LDA BRKV-1,Y:LDX OldBRKV-1,Y:STA OldBRKV-1,Y:TXA:STA BRKV-1,Y
 1400   LDA WORDV-1,Y:LDX OldWORDV-1,Y:STA OldWORDV-1,Y:TXA:STA WORDV-1,Y
 1410   DEY:BNE SwapVecLp                      :\ End with Y=0
 1420   PLP:CLC
 1430   .SwapVectorsEnd
 1440   RTS
 1450   :
 1460   .OldBRKV :EQUW NewBRK
 1470   .OldWORDV:EQUW NewWORD
 1480   :
 1490   .PrHex
 1500   PHA:LSR A:LSR A:LSR A:LSR A:JSR PrNyb:PLA:AND #&0F
 1510   .PrNyb
 1520   SED:CLC:ADC #&90:ADC #&40:CLD:JMP OSWRCH
 1530   :
 1540   .NewBRK
 1550   LDY #&00:LDA (&FD),Y
 1560   CMP #&20:BEQ ErrorExit
 1570   CMP #&DE:BNE NotChannelError
 1580   JSR SwapVectors     :\ *BUG* after this, jmp (oldbrkv) will come back here
 1590   .NotChannelError
 1600   LDX #MsgError-MsgBase:STX ErrFlag       :\ Flag for next entry to Osw0
 1610   JSR PrMessage:JSR PRDEC16               :\ Print error line number
 1620   LDA #ASC":":JSR OSWRCH
 1630   .ErrorExit
 1640   JMP (OldBRKV)
 1650   :
 1660   .PRDEC16
 1670   LDA #255:PHA           \ Terminator
 1680   .PRDECDIGIT
 1690   LDX #15                \ 16-bit divide
 1700   LDA #0                 \ Remainder=0
 1710   CLV                    \ V=0 means divide result = 0
 1720   .PRDECDIV10
 1730   CMP #10/2:BCC PRDEC10  \ Calculate OSNUM/10
 1740   SBC #10/2+&80          \ Remove digit & set V=1 to show div result > 0
 1750   SEC                    \ Shift 1 into div result
 1760   .PRDEC10
 1770   ROL LineNumber+0       \ Shift /10 result
 1780   ROL LineNumber+1
 1790   ROL A                  \ Shift bits of input into acc (input mod 10)
 1800   DEX:BNE PRDECDIV10     \ Continue 16-bit divide
 1810   PHA:BVS PRDECDIGIT     \ If V=1, result of /10 was >0, do next digit
 1820   PLA
 1830   .PRDECLP2
 1840   ORA #ASC"0":JSR OSWRCH \ Pop character left to right and print it
 1850   PLA:BPL PRDECLP2:RTS
 1870   :
 1880   .MsgBase
 1890   .MsgIgnore
 1900   EQUS CHR$7+"Ignore? (Y/N)":BRK
 1910   .MsgOPT
 1920   EQUS "[OPT":.PassChar:EQUS "4:"
 1930   .MsgPass
 1940   EQUS "Pass 1":EQUB 13:BRK
 1950   .MsgError
 1960   EQUS "Error at line ":BRK
 1970   :
 1980   EQUS ver$
 1990   \ =&AF9
 2000 ]:NEXT
 2010 PRINT"*Save Assem ";~mcode%;" ";~O%;" ";~go%OR&FFFF0000;" ";~load%