10 REM > BasConv 1.01
   20 REM v1.01 22-Jun-2020: Tokenises 'BY', opt%=128 tokenises 'PRIVATE', 'EXIT'
   30 :
   40 PRINT "Convert between Acorn/6502/6809/PDP11/32K/ARM"'" and Russell/Z80/80x86 BASIC files"
   50 PROCBasConvInit
   60 ON ERROR PRINT:REPORT:PROCCloseAll:PRINT:OSCLI LEFT$("QUIT",PAGE>&FFFF):END
   70 REPEAT
   80   INPUT LINE"Source file:                     "src$
   90   INPUT LINE"Source type (Acorn/Russell):     "A$:srctype%=(INSTR(".AaBbRrPpTt",LEFT$(A$,1))+2)/4
  100   INPUT LINE"Dest. file:                      "dst$
  110   INPUT LINE"Dest. type (Acorn/Russell/Text): "A$:dsttype%=(INSTR(".AaBbRrPpTt",LEFT$(A$,1))+2)/4
  120   INPUT LINE"List options:                    "opt%
  130   err%=FNBasConv(src$,srctype%,dst$,dsttype%,opt%)
  140   IF err%=214:PRINT"'"src$"' not found"
  150   IF err%=192:PRINT"Can't open '"dst$"'"
  160   IF err%=127:PRINT"Unknown file type"
  170   IF err%=126:PRINT"Conversion not supported"
  180   PRINT
  190 UNTIL FALSE
  200 :
  210 REM -------------------------------------------------------------------
  220 REM src$=source file, srctype%=source type, 1=Acorn, 2=Russell
  230 REM dst$=dest. file,  dsttype%=dest. type,  1=Acorn, 2=Russell, 3=Text
  240 REM opt%=LISTO options when outputting to text
  250 REM  bit 0: space before line
  260 REM  bit 1: indent structures
  270 REM  bit 2: split lines at ":" (not implemented)
  280 REM  bit 3: don't list line number (ignored if line destination found)
  290 REM  bit 4: list tokens in lower case (not implemented)
  300 REM  bit 5: pause at end of screen (not implemented)
  310 REM  bit 6:
  320 REM  bit 7: extension: tokenise PRIVATE, EXIT
  330 REM Returns 0=Ok, <>0=failure
  340 REM  126: conversion not supported
  350 REM  127: unknown file type
  360 REM  192: couldn't save to destination file
  370 REM  214: source file not found
  380 REM -------------------------------------------------------------------
  390 DEFFNBasConv(src$,srctype%,dst$,dsttype%,opt%)
  400 IF srctype%<1 OR srctype%>3 OR dsttype%<0 OR dsttype%>3:=127
  410 IF srctype%=3 OR srctype%=dsttype%:=126
  420 in%=OPENIN(src$):IF in%=0:=214
  430 out%=OPENOUT(dst$):IF out%=0:CLOSE#in%:in%=0:=192
  440 PROCConvert:IF dsttype%=3:IF lnum%:IF opt% AND 8:opt%=opt% AND -9:PTR#in%=0:PTR#out%=0:PROCConvert
  450 PROCCloseAll
  460 =0
  470 :
  480 DEFPROCBasConvInit
  490 in%=0:out%=0
  500 DIM tkn$(255),line% 3:FOR A%=117 TO 272:READ tkn$(A%AND255):NEXT A%
  510 ENDPROC
  520 :
  530 DEFPROCConvert
  540 indent%=0:lnum%=0
  550 IF srctype%=1:A%=BGET#in%
  560 IF dsttype%=1:BPUT#out%,13
  570 REPEAT
  580   IF srctype%=1:hi%=FNrd(255):lo%=FNrd(0):len%=FNrd(0)
  590   IF srctype%=2:len%=FNrd(0):lo%=FNrd(0):hi%=FNrd(255)
  600   L$="":num%=hi%*256+lo%:IF len%:PROCRdLine:len%=LENL$+3
  610   IF dsttype%=1:BPUT#out%,hi%:IF hi%<>255:BPUT#out%,lo%:BPUT#out%,len%
  620   IF dsttype%=2:BPUT#out%,len%:BPUT#out%,lo%:BPUT#out%,hi%
  630   IF dsttype%=3:PROCWrLine ELSE PROCwr(L$)
  640 UNTIL EOF#in% OR len%=0 OR hi%=&FF
  650 ENDPROC
  660 :
  670 DEFPROCRdLine
  680 P$=" "
  690 REPEAT
  700   A%=BGET#in%:B$=CHR$A%:len%=len%-1
  710   IF srctype%=1:IF INSTR(CHR$&7F+CHR$&C6+CHR$&C8+CHR$&CC+"B",B$):B$=FNRdByte2
  720   IF srctype%=2:IF dsttype%=1:IF A%<17 OR (A%>=&C6 AND A%<=&CC):B$=FNRdByte1
  730   L$=L$+B$:IF B$<>" ":P$=B$
  740 UNTIL len%<4
  750 IF dsttype%=2:IF LEFT$(L$,1)=" ":REPEAT:L$=MID$(L$,2):UNTIL LEFT$(L$,1)<>" "
  760 ENDPROC
  770 :
  780 REM Translate Russell 1-byte tokens
  790 DEFFNRdByte1
  800 IF A%=&00 OR A%=&0D:=CHR$A%                               :REM End of line
  810 IF A%<&0D+((opt%AND128)DIV32):B$=CHR$(EVAL("&"+MID$("008F9D909791989394999C969A0DA500A6",A%*2+1,2))):IF ASCB$:=CHR$&C8+B$
  820 IF A%<&11:=tkn$(A%)                                       :REM 'PRIVATE', 'EXIT', convert to text
  830 IF A%=&C6:=CHR$&C6+CHR$&8E                                :REM 'SUM'
  840 IF A%=&C7:=CHR$&C8+CHR$&95                                :REM 'WHILE'
  850 IF A%=&C8:=CHR$&C8+CHR$&8E                                :REM 'CASE'
  860 IF A%=&CC:=CHR$&7F                                        :REM 'OTHERWISE'
  870 =CHR$A%                                                   :REM Leave as is
  880 :
  890 REM Translate Acorn 2-byte tokens
  900 REM &7F    1-byte OTHERWISE
  910 REM &CC    1-byte ELSE
  920 REM 'B'    'BY' if immediately after DRAW/FILL/MOVE
  930 REM &C6,xx 2-byte functions
  940 REM &C7,xx 2-byte immediate commands, if &C7 must be non-ARM BASIC edited on RISC OS
  950 REM &C8,xx 2-byte commands
  960 DEFFNRdByte2
  970 IF A%=&7F:=CHR$&CC                                        :REM 'OTHERWISE'
  980 IF A%=&CC:=CHR$&8B                                        :REM 'ELSE'
  990 A%=A%*256+BGET#in%:len%=len%-1                            :REM Two-byte token
 1000 IF A%=&4259:IF INSTR(CHR$&EC+CHR$&DF+CHR$&03,P$):=CHR$&0F :REM [MOVE|DRAW|FILL] 'BY'
 1010 IF A%=&C68E:=CHR$&C6                                      :REM 'SUM'
 1020 IF A%=&C68F:=tkn$(117)                                    :REM 'BEAT'
 1030 IF A%>=&C88E:IF A%<=&C89D:=CHR$(EVAL("&"+MID$("C8010305F00708C70B0406090C0C0A02",(A%-&C88E)*2+1,2)))
 1040 IF A%>=&C89E:IF A%<=&C8A4:=tkn$(118+A%-&C89E)             :REM No 1-byte equivalent, convert to text
 1050 IF A%>=&C8A5:IF A%<=&C8A6:=CHR$(&0E+(A%-&C8A5)*2)         :REM 'PRIVATE', 'EXIT'
 1060 PTR#in%=PTR#in%-1:len%=len%+1:=CHR$(A%DIV256)             :REM Leave as is
 1070 :
 1080 DEFPROCWrLine
 1090 IF L$="":ENDPROC
 1100 IF num%:IF (opt% AND 8)=0:PROCwr(FNd(num%,5)) ELSE IF (opt% AND 8)=0:PROCwr("     ")
 1110 IF opt% AND 1:BPUT#out%,32
 1120 FOR ptr%=1 TO LEN L$
 1130   IF INSTR(CHR$&ED+CHR$&FD+CHR$&CE+CHR$&CB+CHR$&CD,MID$(L$,ptr%,1)):indent%=indent%-1
 1140 NEXT ptr%
 1150 IF opt% AND 2:PROCwr(STRING$(2*indent% AND (indent%>0)," "))
 1160 FOR ptr%=1 TO LEN L$
 1170   B%=ASCMID$(L$,ptr%,1)
 1180   IF B%=&8D:$line%=MID$(L$,ptr%+1,3):ptr%=ptr%+3:lnum%=TRUE
 1190   IF B%=&8D:PROCwr(STR$(((line%?2 EOR 16*?line%)*256+(line%?1 EOR (4*?line% AND &C0)))AND&FFFF))
 1200   IF B%<&7F:IF B%>&1F:BPUT#out%,B% ELSE IF B%<>&8D:PROCwr(tkn$(B%))
 1210   IF INSTR(CHR$&E3+CHR$&F5+CHR$&C7+CHR$&C8,CHR$B%):indent%=indent%+1
 1220 NEXT ptr%
 1230 IF RIGHT$(L$,2)=CHR$&8C+CHR$13:indent%=indent%+1
 1240 BPUT#out%,10
 1250 ENDPROC
 1260 :
 1270 DEFFNrd(A%):IF EOF#in%:=A% ELSE =BGET#in%
 1280 DEFPROCwr(A$):IF A$<>"":FOR A%=1 TO LEN A$:BPUT#out%,ASCMID$(A$,A%,1):NEXT A%
 1290 ENDPROC
 1300 :
 1310 DATA BEAT,BEATS,TEMPO,VOICES,VOICE,STEREO,OVERLAY,MANDEL,PRIVATE,EXIT
 1320 DATA OTHERWISE,AND,DIV,EOR,MOD,OR,ERROR,LINE,OFF,STEP,SPC,TAB(,ELSE,THEN,,OPENIN,PTR
 1330 DATA PAGE,TIME,LOMEM,HIMEM,ABS,ACS,ADVAL,ASC,ASN,ATN,BGET,COS,COUNT,DEG,ERL,ERR,EVAL
 1340 DATA EXP,EXT,FALSE,FN,GET,INKEY,INSTR(,INT,LEN,LN,LOG,NOT,OPENUP,OPENOUT,PI,POINT(,POS
 1350 DATA RAD,RND,SGN,SIN,SQR,TAN,TO,TRUE,USR,VAL,VPOS,CHR$,GET$,INKEY$,LEFT$(,MID$(,RIGHT$(
 1360 DATA STR$,STRING$(,EOF,SUM,WHILE,CASE,WHEN,OF,ENDCASE,OTHERWISE,ENDIF,ENDWHILE,PTR
 1370 DATA PAGE,TIME,LOMEM,HIMEM,SOUND,BPUT,CALL,CHAIN,CLEAR,CLOSE,CLG,CLS,DATA,DEF,DIM,DRAW
 1380 DATA END,ENDPROC,ENVELOPE,FOR,GOSUB,GOTO,GCOL,IF,INPUT,LET,LOCAL,MODE,MOVE,NEXT,ON,VDU
 1390 DATA PLOT,PRINT,PROC,READ,REM,REPEAT,REPORT,RESTORE,RETURN,RUN,STOP,COLOUR,TRACE,UNTIL
 1400 DATA WIDTH,OSCLI,,CIRCLE,ELLIPSE,FILL,MOUSE,ORIGIN,QUIT,RECTANGLE,SWAP,SYS,TINT,WAIT
 1410 DATA INSTALL,,PRIVATE,BY,EXIT
 1420 :
 1430 DEFPROCCloseAll
 1440 out%=out%:IFout%:A%=out%:out%=0:CLOSE#A%
 1450 in%=in%:IFin%:A%=in%:in%=0:CLOSE#A%
 1460 ENDPROC
 1470 :
 1480 DEFFNd(A%,N%)=RIGHT$("         "+STR$A%,N%)
 1490 :
 1500 PRINT BY;by;"BY":DRAW BY 1,2:DRAW 1+BY,2:MOVE BY 1,2:FILL BY 1,2:REM GOTO 1510
 1510 LOAD "file",address:SAVE "file",start,end:LIST TO "file"