1 %TITLE "FIXIT Utility for Old BASIC Programs" %SBTTL "Declarations and Variable Directory" %IDENT "FIXIT" OPTION TYPE = EXPLICIT ! Author: Tom Harris August 1, 1983 ! Digital Equipment Corp (ZK2-3/K06) ! 110 Spit Brook Road ! Nashua, NH USA 03062 ! ------------------------------------------------------------ ! Input: an input file name, and conversion controls ! input can be BASIC-PLUS-2 V1.6 or MicroBASIC ! style programs. Keyboard input is allowed. ! ------------------------------------------------------------ ! Output: a BASIC program, formatted for V2 BASIC ! ------------------------------------------------------------ ! Support: Here it is, have fun, suggestions welcome, ! but no guarantees. ! ------------------------------------------------------------ ! THIS IS A HANDOUT DEVELOPED FOR FALL US DECUS 1983 ! ------------------------------------------------------------ DECLARE INTEGER CONSTANT & No_Tabs = 16 ! EDIT$ code & ,No_Blanks = 424 ! EDIT$ codes & ,Trim_Front = 8 ! EDIT$ code & ,Trim_Back = 128 ! EDIT$ code & ,TRUE = -1 DECLARE STRING CONSTANT Break = "\" ! Backslash & DECLARE STRING & DIMs.MAP(200) ! To move -> top/prog. & ,F.In ! Input file name & ,F.Out ! Output File Name & ,Main ! Working input buffer & ,Out ! Output line image & ,Source ! Input line image & ,S1 ,S2, S3 ! Temp String DECLARE LONG & Bad.File ! Error on File OPEN & ,Comment.Column ! Comments to column x & ,DIMs.MAPs.Count ! Count DIM/MAPs & ,TAB.Back ! Fixup indents w/this & ,First.Break ! THEN/ELSE/... tests & ,Endfile ! End-of-File flag & ,I ! General Use & ,IF.Count ! Nesting counter & ,Lines.In ! Counts # Lines input & ,Lines.Out ! Lines output & ,Loop.Count ! Loop nesting counter & ,MicroBASIC ! TRUE if a micro BASIC & ,MAP.DIM.Line.Number ! Line # for DIM/MAP's & ,Start.Time ! Seconds since 00:00 & ,T1 ,T2, T3 ! Temp working storage & ,TT.Output ! TRUE if F.Out="TT:" %PAGE ! The following flags are used by the uBASIC FUNCTION ! as a type of "OWN" storage, i.e. static storage ! that retains values between invocations. They are ! initialized to 0 as the main program starts running. ! The flags correspond to uBASIC statements or functions ! for which DEC BASIC functions or subroutines must ! be generated (i.e. no easy 1-1 transform exists). ! e.g. PRINT @128,"Hi" becomes PRINT AT(128);"Hi" ! and a BASIC function named AT has to be inserted ! into the front of the converted program. MAP (FLAGS) BYTE Action.Flag ! Caller must do something & ,At_Flag ! Output PRINT AT functn & ,MKS_Flag ! Output MKS function & ,MKI_Flag ! Output MKI function & ,MKD_Flag ! Output MKD function & ,CVS_Flag ! Output CVS function & ,CVI_Flag ! Output CVI function & ,CVD_Flag ! Output CVD function & ,INKEY_Flag ! Output INKEY$ function MAP (FLAGS) BYTE All_Flags(10) ! This makes initializing easier ! Below, we test the %VARIANT value (use the SET VARIANT command in the BASIC environment) ! to see whether we should minimize the size of this program by excluding HELP text and by ! skipping the call on UBASIC thus omitting that code from the executable program. Minimizing ! in this manner lets one run FIXIT on a PDP-11 system without having to overlay any code ! thus getting best possible performance. ! ! The default is NOT to minimize. To request the smaller program: SET VARIANT:1 before compiling ! %LET %Small = 1% ! SET VARIANT = 1 when compiling, and the MicroBASIC code drops out, %LET %Large = 2% ! and then you don't have to overlay the translator %IF %VARIANT = 0% %THEN %LET %Size = %Large EXTERNAL STRING FUNCTION uBASIC(STRING) ! This EXTERNAL happens only on %Large systems %ELSE %LET %Size = %Small %END %IF %PAGE I = CTRLC ON ERROR GOTO Oops GOTO Bye IF Bad.File ! Error Handler "OOPS" resumes here when unable to OPEN the *INPUT* file PRINT "FIXIT V1.0-AA ";TIME$(0) PRINT " " Begin_Processing: LINPUT "What input file (? = HELP) ";F.In ! Get an input file name, and append .BAS to it ! as a default extension - unless the file name ! might be a device spec, e.g. TT: or TTA3: F.In = EDIT$(F.In,No_Blanks) IF F.In = "?" THEN GOSUB Help GOTO Begin_Processing END IF F.In = F.In + ".BAS" IF (F.In <>"") AND 0=INSTR(1,F.In,".") AND 0=INSTR(1,F.In,":") F.In = "TT:" IF LEN(F.In) = 0 OPEN F.In FOR INPUT AS FILE #1, ACCESS READ, VARIABLE, RECORDSIZE 132 LINPUT "What output file ";F.Out ! Do the same thing for the output file name F.Out = F.Out + ".BAS" IF EDIT$(F.Out,No_Blanks)<>"" AND 0=INSTR(1,F.Out,".") AND 0=INSTR(1,F.Out,":") IF EDIT$(F.Out,No_Blanks)="" THEN F.Out="TT:" TT.Output = True END IF OPEN F.Out FOR OUTPUT AS FILE #2,VARIABLE, RECORDSIZE 132 %PAGE MAP.DIM.Line.Number = 3 ! Default: move MAP/DIM's to line "3" Comment.Column = 16 ! Default: try to start comments in column 16 DIMs.MAPs.Count = 0 ! Global counter: tels how many DIM/MAP's saved up to move when program ends. All_Flags(I) = 0 FOR I = 0 to 10 ON ERROR GOTO Hiccup LINPUT "Is this a Microprocessor BASIC Program ";S1 MicroBASIC = TRUE IF EDIT$(Left(S1+"N",1),No_Blanks)="Y" LINPUT "Want to customize program conversion ? Answer Yes or No ";S1 IF EDIT$(LEFT(S1+"N",1),No_Blanks) = "Y" THEN INPUT "What line number should be used for moved DIM's and MAP's <3>";MAP.DIM.Line.Number MAP.DIM.Line.Number = 3 IF MAP.DIM.Line.Number = 0 INPUT "What column should be used to start comments in <16>";Comment.Column Comment.Column = 16 IF Comment.Column < 2 OR Comment.Column > 60 S1,S2,S3 = "" END IF Start.Time = TIME(0%) ! Start timing the conversion %PAGE %SBTTL "Main Loop" Main_Loop: WHILE TRUE GOSUB DeBlock_Line EXIT Main_Loop IF Endfile AND LEN(Main)=0 GOSUB ReBlock_Line Break.Lines: IF LEN(Out) > 132 ! This is where we break a line that is too long ... THEN T1 = INSTR(78,Out,";") T2 = INSTR(78,Out,",") ! We'll break on a comma, semicolon, plus, AND, OR, or paren T3 = INSTR(78,Out,"+") T3 = INSTR(78,Out," AND ") IF T3 = 0 T3 = INSTR(78,Out," OR ") IF T3 = 0 T1 = T2 IF T1 = 0 OR (T2<>0 AND T20 AND T3 0 THEN PRINT #2, Out ! Here, the line fits OK - no need to break it Lines.Out = Lines.Out + 1 END IF END IF PRINT Lines.Out; IF Lines.Out = 100*INT(Lines.Out/100) AND NOT TT.Output ! Show progress... NEXT PRINT IF TT.Output GOTO Done %PAGE %SBTTL "HELP Text" Help: PRINT " " %IF %Size = %Large %THEN PRINT " " PRINT " This program converts V1 BASIC programs to a possibly more" PRINT " readable and executable format under V2 BASIC. It handles" PRINT " BASIC-PLUS-2 V1.x source as well as elements of MicroBASIC" PRINT " source code." PRINT " " PRINT " NOTE: This is a sample program which itself illustrates" PRINT " capabilities of DEC BASIC. The program has purposely been" PRINT " kept to a simple no-brains approach - it does not use" PRINT " sophisticated parsing techniques and thus does not perfectly" PRINT " convert all of the possible program formats which the" PRINT " BASIC's allow. However, it has proven useful for a number" PRINT " of different programs, and can no doubt be altered to handle" PRINT " even more." PRINT " " PRINT " The program moves MAPs and DIMs, changes REM statements to" PRINT " '!', inserts 'END IF' statements where necessary, and" PRINT " indents statement blocks to indicate control" PRINT " structures while performing minor clean-ups on code." PRINT " " PRINT " You will be asked for input and output file names and" PRINT " whether you wish to supply customizing directions or take" PRINT " default processing parameters. Input and Output file names" PRINT " are assumed to have a .BAS extension, so you need not type" PRINT " it in (other extensions are permitted - just type 'em in!)." PRINT " " PRINT " You will be requested to tell the FIXIT program whether" PRINT " the input text is in space-compressed MicroBASIC format so" PRINT " that expansions can be performed (and syntax peculiar to" PRINT " that implementation can be massaged into forms acceptable on" PRINT " this system." PRINT " " PRINT " Customizing means telling the FIXIT program whether to move" PRINT " COMMON/DIMENSION/MAP statements and what line number to move" PRINT " them to (if you give a line number less than zero, they" PRINT " won't be moved - may be advisable if you have truly complex" PRINT " MAP or COMMON statements), you will be asked what column to" PRINT " TRY to align comments on (numbers between 8 and 70 are OK)." PRINT " " PRINT " The program then runs, reporting each 100 " PRINT " statements processed. Termination reporting tells how many" PRINT " input statements and how many output statements were" PRINT " processed." PRINT " " %ELSE PRINT "Help Text is not available" %END %IF RETURN %PAGE %SBTTL "Source Input Routine" DeBlock_Line: ! Return 1 stmt/line in *Source* Out,Source,S1,S2 = "" IF LEN(Main)=0 AND NOT Endfile ! *Main* holds working text THEN IF LEN(S3) = 0 THEN LINPUT #1, Main Lines.In = Lines.In + 1 Main = EDIT$(Main,No_Blanks) %IF %Size = %Large %THEN Main = uBASIC(Main) IF MicroBASIC %END %IF ELSE Main = S3 S3 = "" END IF END IF Handle.Continuation: IF MID(Main,LEN(Main),1)="&" ! Continuation lines -> *Main* THEN T1 = INSTR(1,Main,"!") Main = EDIT$(LEFT(Main,LEN(Main)-1),Trim_Back)+" " LINPUT #1, S1 S1 = EDIT$(S1,No_Blanks) Lines.In = Lines.In + 1 IF T1= 0 THEN S1 = Break+" "+S1 IF LEFT(S1,1)="!" Main = Main + EDIT$(S1,Trim_Front) GOTO Handle.Continuation ELSE S3 = S1 S1 = "" END IF END IF %PAGE T1 = INSTR(1,Main,Break) ! NOW, get a stmt into *Source* IF T1 <> 0 THEN Source = EDIT$(LEFT(Main,T1-1),Trim_Front) Main = EDIT$(RIGHT(Main,T1+1),Trim_Front) Main = Break+Main IF LEN(Source) <> 0 GOTO DeBlock_Line IF LEN(Source) = 0 ELSE Source = EDIT$(Main,Trim_Front) Main = "" END IF T1 = INSTR(1,Source,"!") ! Break lines on THEN, ELSE and T2 = INSTR(1,Source,"THEN") ! work to avoid being fooled by T3 = INSTR(1,Source,"ELSE") ! comments containing THEN/ELSE RETURN IF (T2 + T3) = 0 ! RETURN IF (T10) ! First.Break = 999 ! Aha, something(s).. pick first one First.Break = T2 IF T2 <> 0 AND T2 < First.Break AND ( (T1 = 0) OR (T1<>0 AND T2 0 AND T3 < First.Break AND ( (T1 = 0) OR (T1<>0 AND T3 INSTR(1,"0123456789",LEFT(Main,1)) AND LEN(Main) <> 0 Source = S1 END IF RETURN %PAGE %SBTTL "Output Editing Subroutine" ReBlock_Line: ! Do pretty tabs & text fixups... Source = EDIT$(Source,Trim_Back) RETURN IF LEN(Source) = 0 T1 = INSTR(1,Source,"!") ! Handles RSTS CUSP convention S1 = EDIT$(Left(Source,T1-1),Trim_Back+No_Tabs) T3 = LEN(S1) Source = S1+SPACE$(Comment.Column-T3) + RIGHT(Source,T1) IF T10 S1 = LEFT(Source,1) T1 = ASCII(S1) S2 = "" SELECT T1 ! Look for Line numbers CASE 48,49,50,51,52,53,54,55,56,57 ! Start text in column 9 T2 = INSTR(1,Source," ") ! Space T3 = INSTR(1,Source," ") ! TAB T2 = T3 IF (T2 = 0) T2 = T3 IF (T3 > 0) AND (T3 < T2) T2 = LEN(Source)+1 IF T2 = 0 Out = LEFT(Source,T2-1) + SPACE$(8-T2) + EDIT$(RIGHT(Source,T2),Trim_Front) Out = Out + "!" IF T2 = LEN(Source)+1 IF IF.Count > 0 THEN PRINT #2, SPACE$(7+4*(Loop.Count+(IF.Count-I)));"END IF" FOR I=1 TO IF.Count Lines.Out = Lines.Out + IF.Count IF.Count = 0 END IF CASE ELSE Out = SPACE$(7)+EDIT$(Source,Trim_Front) END SELECT ! *WHEW* BASIC source in col-8 ! Now, do fixups... Out = LEFT(Out,7)+"! "+EDIT$(RIGHT(Out,12),Trim_Front) IF MID(Out,8,3)="REM" Out = LEFT(Out,7) +EDIT$(RIGHT(Out,12),Trim_Front) IF MID(Out,8,3)="LET" %PAGE %SBTTL "Pretty Print Formatting" Loop.Count = Loop.Count - 1 IF MID(Out,8,4)="NEXT" Loop.Count = 0 IF Loop.Count < 0 IF.Count = IF.Count - 1 IF 0 <> INSTR(1,Out,"END IF") AND IF.Count > 0 IF.Count = 0 IF IF.Count < 0 T1 = INSTR(1,Out,"ELSE") T3 = INSTR(1,Out,"!") TAB.Back = 0 ! TAB.Back = 1 IF T1 > 0 AND ((T3=0) OR (T3<>0 AND T10 T1 = INSTR(1,Source,"!") ! Key off THEN (not stmt modifier) T2 = INSTR(1,Source,"THEN") IF.Count = IF.Count + 1 IF T2<>0 AND (T1=0 OR (T1<>0 AND T2 0 AND T1=0 THEN DIMs.MAPs.Count = DIMs.MAPs.Count + 1 DIMs.MAP(DIMs.MAPs.Count) = SPACE$(7)+LEFT(Out,I)+SPACE$(58-I)+" &" Out = EDIT$(RIGHT(Out,I+1),Trim_Front) Find.Comma: I = INSTR(1,Out,",") IF I > 0 THEN GOSUB Add.Item GOTO Find.Comma END IF DIMs.MAPs.Count = DIMs.MAPs.Count + 1 DIMs.MAP(DIMs.MAPs.Count) = SPACE$(15)+Out ELSE DIMs.MAPs.Count = DIMs.MAPs.Count + 1 DIMs.MAP(DIMs.MAPs.Count) = SPACE$(7)+Out END IF Out = LEFT(S1,7)+SPACE$(Comment.Column-7)+"! ** MOVED COMMON, DIM, or MAP ** " RETURN Add.Item: DIMs.MAPs.Count = DIMs.MAPs.Count + 1 DIMs.MAP(DIMs.MAPs.Count) = SPACE$(15) + & EDIT$(LEFT(Out,I),Trim_Front)+ & SPACE$(50-I)+" &" Out = EDIT$(RIGHT(Out,I+1),Trim_Front) RETURN %PAGE %SBTTL "Exception Handling and Program Termination Code" Hiccup: Endfile = TRUE PRINT IF F.Out <> "TT:" PRINT ERT$(ERR);" Error ";ERR IF ERR <> 11 RESUME 9 Oops: PRINT "Sorry, unable to open that file, program ends" Bad.File = TRUE RESUME 1 9 ! Done: IF IF.Count > 0 ! Put any pending END IF's THEN PRINT #2, SPACE$(7+4*(IF.Count-I));"END IF" FOR I=1 TO IF.Count Lines.Out = Lines.Out + IF.Count END IF IF DIMs.MAPs.Count <> 0 ! Also, dump the DIM/MAP's THEN PRINT #2, NUM1$(MAP.DIM.Line.Number);TAB(Comment.Column); "! ** COMMON, DIM, and MAP's have been moved here ** " PRINT #2, DIMs.MAP(I) FOR I = 1 TO DIMs.MAPs.Count Lines.Out = Lines.Out + DIMs.MAPs.Count + 1 END IF %PAGE %SBTTL "Generated DEF's (for MicroBASIC Operations)" %IF %Size = %Large %THEN All_Flags(10) = All_Flags(10) + All_Flags(I) FOR I = 1 TO 9 IF All_Flags(10) <> 0 THEN PRINT PRINT #2, "4";TAB(Comment.Column);"! ** Added functions here **" PRINT "Added Line 4 ("; IF F.Out <> "TT:" IF CVI_Flag <> 0% THEN PRINT " CVI"; IF F.Out <> "TT:" PRINT #2, " DEF WORD CVI(STRING CVI_IN)" PRINT #2, " MAP (CVIMAP) STRING CVI_STRING = 2" PRINT #2, " MAP (CVIMAP) WORD CVI_WORD" PRINT #2, "" PRINT #2, " CVI_STRING = CVI_IN" PRINT #2, " CVI = CVI_WORD" PRINT #2, " END DEF" PRINT #2, "" Lines.Out = Lines.Out + 8 END IF IF CVS_Flag <> 0 THEN PRINT " CVS"; IF F.Out <> "TT:" PRINT #2, " DEF SINGLE CVS(STRING CVS_IN)" PRINT #2, " MAP (CVSMAP) STRING CVS_STRING = 4" PRINT #2, " MAP (CVSMAP) SINGLE CVS_SINGLE" PRINT #2, "" PRINT #2, " CVS_STRING = CVS_IN" PRINT #2, " CVS = CVS_SINGLE" PRINT #2, " END DEF" PRINT #2, "" Lines.Out = Lines.Out + 8 END IF IF CVD_Flag <> 0 THEN PRINT " CVD"; IF F.Out <> "TT:" PRINT #2, " DEF SINGLE CVD(STRING CVD_IN)" PRINT #2, " MAP (CVDMAP) STRING CVD_STRING = 8" PRINT #2, " MAP (CVDMAP) SINGLE CVD_DOUBLE" PRINT #2, "" PRINT #2, " CVD_STRING = CVD_IN" PRINT #2, " CVD = CVD_DOUBLE" PRINT #2, " END DEF" PRINT #2, "" Lines.Out = Lines.Out + 8 END IF %PAGE IF MKI_Flag <> 0 THEN PRINT " MKI"; IF F.Out <> "TT:" PRINT #2, " DEF STRING MKI(WORD MKI_IN)" PRINT #2, " MAP (MKIMAP) STRING MKI_STRING = 2" PRINT #2, " MAP (MKIMAP) WORD MKI_WORD" PRINT #2, "" PRINT #2, " MKI_WORD = MKI_IN" PRINT #2, " MKI = MKI_STRING" PRINT #2, " END DEF" PRINT #2, "" Lines.Out = Lines.Out + 8 END IF IF MKS_Flag <> 0 THEN PRINT " MKS"; IF F.Out <> "TT:" PRINT #2, " DEF STRING MKS(SINGLE MKS_IN)" PRINT #2, " MAP (MKSMAP) STRING MKS_STRING = 4" PRINT #2, " MAP (MKSMAP) SINGLE MKS_SINGLE" PRINT #2, "" PRINT #2, " MKS_SINGLE = MKS_IN" PRINT #2, " MKS = MKS_STRING" PRINT #2, " END DEF" PRINT #2, "" Lines.Out = Lines.Out + 8 END IF IF MKD_Flag <> 0 THEN PRINT " MKD"; IF F.Out <> "TT:" PRINT #2, " DEF STRING MKD(DOUBLE MKD_IN)" PRINT #2, " MAP (MKDMAP) STRING MKD_STRING = 8" PRINT #2, " MAP (MKDMAP) SINGLE MKD_DOUBLE" PRINT #2, "" PRINT #2, " MKD_DOUBLE = MKD_IN" PRINT #2, " MKD = MKD_STRING" PRINT #2, " END DEF" PRINT #2, "" Lines.Out = Lines.Out + 8 END IF IF At_Flag <> 0 THEN PRINT " AT"; IF F.Out <> "TT:" PRINT #2, " DEF STRING At( WORD At.Line, At.Column) = ESC + '[' + NUM1$(At.Line)+';'+NUM1$(At.Column)+'f'" PRINT #2, " DEF STRING CLS( WORD CLS.Line, CLS.Column) = AT(CLS.Line,CLS.Column) + Clear.Below" PRINT #2, " " Lines.Out = Lines.Out + 3 END IF %PAGE IF INKEY_Flag <> 0 THEN PRINT " INKEY"; IF F.Out <> "TT:" PRINT #2, " %PAGE" PRINT #2, " %SBTTL 'Keyboard Input Routine (VMS Only)' " PRINT #2, " EXTERNAL LONG CONSTANT &" PRINT #2, " IO$_READVBLK &" PRINT #2, " ,IO$M_NOECHO &" PRINT #2, " ,SS$_NORMAL" PRINT #2, "" PRINT #2, " EXTERNAL LONG FUNCTION SYS$ASSIGN ( &" PRINT #2, " STRING BY DESC &" PRINT #2, " ,WORD BY REF &" PRINT #2, " ,LONG BY VALUE &" PRINT #2, " ,LONG BY VALUE )" PRINT #2, "" PRINT #2, " EXTERNAL LONG FUNCTION SYS$QIOW ( &" PRINT #2, " LONG BY VALUE &" PRINT #2, " ,WORD BY VALUE &" PRINT #2, " ,LONG BY VALUE &" PRINT #2, " ,LONG BY REF &" PRINT #2, " ,LONG BY REF &" PRINT #2, " ,LONG BY VALUE &" PRINT #2, " ,WORD BY REF &" PRINT #2, " ,LONG BY VALUE &" PRINT #2, " ,LONG BY VALUE &" PRINT #2, " ,LONG BY REF &" PRINT #2, " ,LONG BY REF &" PRINT #2, " ,LONG BY VALUE )" PRINT #2, "" PRINT #2, " DECLARE STRING CONSTANT &" PRINT #2, " Clear.Screen = ESC + '[2J' &" PRINT #2, " ,Clear.Below = ESC + '[0J' &" PRINT #2, " ,Clear.Right = ESC + '[K' &" PRINT #2, " ,Clear.Line = ESC + '[2K' &" PRINT #2, " ,Col.132 = ESC + '[?3h' &" PRINT #2, " ,Black.Screen = ESC + '[?5l' &" PRINT #2, " ,Normal.Chars = ESC + '[0m' &" PRINT #2, " ,Bold.Chars = ESC + '[1m' &" PRINT #2, " ,Reverse.Chars = ESC + '[7m' &" PRINT #2, " ,Underscore.On = ESC + '[4m' &" PRINT #2, " ,Blink = ESC + '[5m' &" PRINT #2, " ,Scroll.Down = ESC + 'M'" PRINT #2, "" %PAGE PRINT #2, " DECLARE INTEGER CONSTANT &" PRINT #2, " True = -1 &" PRINT #2, " ,False = 0 &" PRINT #2, " ,Up = 1 &" PRINT #2, " ,Down = 0 &" PRINT #2, "" PRINT #2, " DECLARE STRING &" PRINT #2, " Hold.Value &" PRINT #2, " ,Key.Value &" PRINT #2, " ,Key.Pad &" PRINT #2, " ,Text" PRINT #2, "" PRINT #2, " DECLARE WORD &" PRINT #2, " Chan &" PRINT #2, " ,QIO.Char &" PRINT #2, " ,Direction &" PRINT #2, "" PRINT #2, " DECLARE LONG &" PRINT #2, " S.Status &" PRINT #2, "" PRINT #2, " %PAGE" PRINT #2, " %SBTTL 'Keypad (One Character) Input Function'" PRINT #2, " DEF STRING InKey" PRINT #2, " DECLARE BYTE Arrow.Key" PRINT #2, " S.Status = SYS$ASSIGN('TT',Chan,,) ! " PRINT #2, " PRINT 'ERROR ON SYS$ASSIGN ' IF S.Status <> SS$_NORMAL" PRINT #2, " Arrow.Key = False" PRINT #2, " Key.Pad = CHR$(0)" PRINT #2, "" PRINT #2, " C1: WHILE TRUE" PRINT #2, " S.Status = SYS$QIOW( &" PRINT #2, " ,Chan &" PRINT #2, " ,(IO$_READVBLK OR IO$M_NOECHO) &" PRINT #2, " , &" PRINT #2, " , &" PRINT #2, " , &" PRINT #2, " ,QIO.Char &" PRINT #2, " ,1% &" PRINT #2, " , &" PRINT #2, " , &" PRINT #2, " , &" PRINT #2, " , &" PRINT #2, " )" PRINT #2, " PRINT 'ERROR ON SYS$QIOW' IF S.Status <> SS$_NORMAL" PRINT #2, " Arrow.Key = True IF QIO.Char = 27 AND Arrow.Key = False" PRINT #2, " EXIT C1 IF NOT Arrow.Key" PRINT #2, " ITERATE C1 IF QIO.Char = ASCII('[') OR QIO.Char = ASCII('O')" PRINT #2, "" PRINT #2, " IF QIO.Char <> ASCII('[') AND QIO.Char <> 27" PRINT #2, " THEN" PRINT #2, " SELECT QIO.Char" PRINT #2, " CASE 65" PRINT #2, " QIO.Char = ASCII('{') ! ESC [ A is up-arrow" PRINT #2, " CASE 66" PRINT #2, " QIO.Char = ASCII('v') ! ESC [ B is down-arrow" PRINT #2, " CASE 67" PRINT #2, " QIO.Char = ASCII('>') ! ESC [ C is right-arrow" PRINT #2, " CASE 68" PRINT #2, " QIO.Char = ASCII('<') ! ESC [ D is left-arrow" PRINT #2, " CASE ELSE" PRINT #2, " Key.Pad = CHR$(QIO.Char)" PRINT #2, " QIO.Char = ASCII('?') ! ESC [ other is probably a keypad key" PRINT #2, " END SELECT" PRINT #2, " EXIT C1" PRINT #2, " END IF" PRINT #2, " NEXT" PRINT #2, " InKey = CHR$(QIO.Char)" PRINT #2, " CALL SYS$DASSGN (Chan BY VALUE)" PRINT #2, " END DEF" PRINT #2, " %PAGE" PRINT #2, " %SBTTL 'Program Text...'" Lines.Out = Lines.Out + 113 END IF PRINT " )" IF F.Out <> "TT:" END IF %END %IF %PAGE %SBTTL "Program Termination and Statistics" CLOSE #2 CLOSE #1 I = TIME(0%) ! Compute elapsed time IF Start.Time < I THEN I = I - Start.Time ! Daytime run ELSE I = I + (24*60*60 - Start.Time) ! Midnight run END IF PRINT PRINT "("; NUM1$(Lines.In); ") Input Lines from " ; F.In ; ", ("; & NUM1$(Lines.Out) ; ") lines written to " ; F.Out PRINT "("; NUM1$(DIMs.MAPs.Count);") lines of DIM and MAP statements moved." PRINT "("+NUM1$(I)+")Seconds elapsed time ... ("+NUM1$(Lines.In/(I/60))+") lines/minute" Bye: END 400 %SBTTL "Fixup MicroBASIC Funnies" FUNCTION STRING uBASIC(STRING Source) OPTION TYPE = EXPLICIT DECLARE LONG CONSTANT TRUE = -1 DECLARE LONG I, J, K, T1, T2, T3, T4, T5, Action_Code, X DECLARE STRING Keyword, New.word, S1, S2 ! The following flags are used by the uBASIC FUNCTION ! as a type of "OWN" storage, i.e. static storage ! that retains values between invocations. They are ! initialized to 0 as the main program starts running. ! The flags correspond to uBASIC statements or functions ! for which DEC BASIC functions or subroutines must ! be generated (i.e. no easy 1-1 transform exists). ! e.g. PRINT @128,"Hi" becomes PRINT AT(128);"Hi" ! and a BASIC function named AT has to be inserted ! into the front of the converted program. MAP (FLAGS) BYTE Action.Flag ! Caller must do something & ,At_Flag ! Output PRINT AT functn & ,MKS_Flag ! Output MKS function & ,MKI_Flag ! Output MKI function & ,MKD_Flag ! Output MKD function & ,CVS_Flag ! Output CVS function & ,CVI_Flag ! Output CVI function & ,CVD_Flag ! Output CVD function & ,INKEY_Flag ! Output INKEY$ function MAP (FLAGS) BYTE All_Flags(10) ! This makes initializing easier GOTO Colon IF LEN(Source) = 0 ! White Space GOSUB Lin.Num IF 0 <> INSTR(1,"0123456789",LEFT(Source,1)) GOTO Set IF "REM" = LEFT(EDIT$(RIGHT(Source,J),-1),3) RESTORE %PAGE ! Here, we read from a table of DATA statements, looking for transforms ! to perform on the line of text sent into this FUNCTION. The table consists ! of: thing-to-find, thing-to-change-to, and a special-action-code. The ! BASIC function INSTR does the lookup. The action code simply tells us ! to set one of the flags checked by the calling main program as it ! determines whether to emit DEF's at the end of the program being translated. Look: WHILE TRUE READ Keyword, New.Word, Action_Code EXIT Look IF Keyword = "..." I = 1 Again: WHILE TRUE I = INSTR(I,Source,Keyword) ! The lookup ITERATE Look IF I = 0 ! J = INSTR(1,Source,'"') ! K = INSTR(J+1,Source,'"') ! its no success if the find is inside a literal EXIT Again IF JI ! in that case, ignore the find. EXIT off end-of-line SELECT Action_Code ! CASE 0 ! No Special Action Needed CASE 1,2,3,4,5,6,7,8 ! Need action: set a flag All_Flags(Action_Code) = 1 Action.Flag = 1 ! and the flag that says "some flags are set" CASE ELSE ! END SELECT Source = LEFT(Source,I-1) + New.Word+ RIGHT(Source,I+Len(Keyword)) ! I = I + LEN(New.Word) ! ... and scan for next word NEXT NEXT Colon: ! Lets turn colon-within-literal into a dash I = INSTR(1,Source,':"') ! Source = MID(Source,1,I-1)+"-"+MID(Source,I+1,LEN(Source)-I) IF I <> 0 GOTO Colon IF I <> 0 I = INSTR(1,Source,': "') ! ditto, for colon-space into a dash Source = MID(Source,1,I-1)+"-"+MID(Source,I+1,LEN(Source)-I) IF I <> 0 GOTO Colon IF I <> 0 I = INSTR(1,Source,":") ! If we see just a colon, that turns into a backslash Source = LEFT(Source,I-1)+"\"+RIGHT(Source,I+1) IF I <> 0 GOTO Colon IF I <> 0 T1 = INSTR(1,Source," IF ") T2 = INSTR(1,Source," THEN ") IF T1 <> 0 GOSUB Fix.IF IF (T1 <> 0) AND (T2 = 0) ! special handling for IF and OPEN GOSUB Fix.OPEN IF 0 <> INSTR(1,Source,"OPEN") GOSUB Print.At IF 0 <> INSTR(1,Source,"@") ! and for PRINT @ to PRINT AT Set: Source = EDIT$(Source,8+16+32+128+256) ! discard any junk characters uBASIC = Source ! and exit: this line is done. EXIT FUNCTION %PAGE %SBTTL "Fixup MicroBASIC Syntax for DEC Systems" Lin.Num: J = 0 ! inserts white space to the right of BASIC line numbers L.Scan: FOR I=2 TO LEN(Source) IF 0=INSTR(1,"0123456789",MID(Source,I,1)) THEN J = I EXIT L.Scan END IF NEXT I Source = Left(Source,J-1)+" "+RIGHT(Source,J) IF J <> 0 RETURN Fix.IF: J = T1 ! some variants of IF omit the keyword "THEN" T1 = INSTR(J,Source,"GO") T2 = INSTR(J,Source,"PRINT") T3 = INSTR(J,Source,"INPUT") T4 = INSTR(J,Source,"LET") T5 = 999 T5 = T1 IF T1 < T5 AND T1 <> 0 T5 = T2 IF T2 < T5 AND T2 <> 0 T5 = T3 IF T3 < T5 AND T3 <> 0 T5 = T4 IF T4 < T5 AND T4 <> 0 Source = LEFT(Source,T5-1)+" THEN "+RIGHT(Source,T5) IF T5 <> 999 ! insert a THEN if its needed RETURN Fix.OPEN: ! the MicroBASIC OPEN has the right kind of components, T1 = INSTR(1,Source,'"O"') ! OPEN FOR OUTPUT and T2 = INSTR(1,Source,'"I"') ! OPEN FOR INPUT ... its just the spelling and the ordering... RETURN IF T1+T2 = 0 S2 = "FOR INPUT" S2 = "FOR OUTPUT" IF T1 <> 0 T1 = T2 IF T2 <> 0 AND T1 = 0 T3 = INSTR(T1,Source,",") ! pickup the channel number S1 = " AS FILE #" + MID(Source,T3+1,1) T3 = INSTR(T3+1,Source,",") T2 = INSTR(T3,Source,"\") ! and the file name T4 = INSTR(T3,Source,"ELSE") T2 = T4 IF T40 T2 = LEN(Source)+1 IF T2 = 0 S1 = MID(Source, T3+1, T2-T3-1) + " " + S2 + S1 Source = LEFT(Source,T1-1)+S1+RIGHT(Source,T2) ! and output a DEC-style OPEN statement GOTO FIX.OPEN %PAGE Print.At: ! careful here, there are several variations of PRINT-at I = INSTR(1,Source,"@") ! Typical use ... J = INSTR(I,Source,",") ! PRINT @255+13,"Hello" J = INSTR(I,Source,";") IF J = 0 ! PRINT @255+13;"Hello" ! I J RETURN IF J=0 Source = LEFT(Source,I-1) + "AT(" + MID(Source,I+1,J-I-1) + ");"+RIGHT(Source,J+1) At_Flag = TRUE Action.Flag = TRUE RETURN %PAGE %SBTTL "Conversion DATA Tables" ! GENERAL TABLE FORMAT IS SIMPLY... ! ! , , Additional Action Code ! ! 1000 DATA "AND" , " AND " , 0 1050 DATA "OR" , " OR " , 0 1100 DATA "'" , " ! " , 0 1150 DATA "&" , " PRINT" , 0 1160 ! 1200 DATA "/BAS" , ".BAS" , 0 1250 DATA "/DAT" , ".DAT" , 0 1300 ! 2000 ! 2200 DATA "CLEAR" , " ! *CLEAR* " , 0 2250 DATA "CLOSE" , " CLOSE " , 0 2295 DATA "CLR$" , "C.LR$" , 0 2300 DATA "CLR" , " PRINT FOR CLR. = 1 TO 24 ! *CLR* " , 0 2350 DATA "CLS" , " PRINT FOR CLS. = 1 TO 24 ! *CLS* " , 0 2360 DATA "CMD" , " PRINT '*CMD*' ! " , 0 2370 DATA "CVI" , "CVI" , 6 2380 DATA "CVS" , "CVS" , 5 2390 DATA "CVD" , "CVD" , 7 2440 ! 2450 DATA "DATA" , " DATA " , 0 2500 DATA "DEFDBL" , " ! DECLARE DOUBLE ( *DEFDBL* ) " , 0 2550 DATA "DEFN" , " ! (*DEFFN*) " , 0 2600 DATA "DEFINT" , " ! DECLARE WORD ( *DEFINT* ) " , 0 2650 DATA "DEFSNG" , " ! DECLARE SINGLE ( *DEFSNG* ) " , 0 2700 DATA "DEFUSR" , " ! (*DEFUSR*) " , 0 2750 DATA "DEFSTR" , " ! DECLARE STRING ( *DEFSTR* ) " , 0 2800 DATA "DELETE" , " DELETE " , 0 2850 DATA "DIM" , " DIM " , 0 2855 ! 2900 DATA "ELSE" , " ELSE " , 0 2925 DATA "WEND" , " NEXT " , 0 2950 DATA "END" , " END " , 0 3000 DATA "ERROR" , " ERROR " , 0 3005 ! 3050 DATA "FIELD" , " FIELD ! *FIELD* ! " , 0 3100 DATA "FOR" , " FOR " , 0 3105 ! 3110 DATA " F OR " , " FOR " , 0 3150 DATA "GET" , " GET " , 0 3200 DATA "GOSUB" , " GOSUB " , 0 3250 DATA "GOTO" , " GOTO " , 0 3255 ! 3300 DATA "IF" , " IF " , 0 3350 DATA "INKEY$" , " INKEY" , 8 3360 DATA "INPUT" , " INPUT " , 0 3375 ! 3400 DATA "KILL" , " KILL " , 0 3405 ! 3425 DATA "LET" , " LET " , 0 3450 DATA "LSET" , " LSET " , 0 3500 DATA "RSET" , " RSET " , 0 3550 DATA "LINE INPUT" , " LINPUT " , 0 3555 ! 3600 DATA "MAX" , "MAXI" , 0 3605 DATA "MKI$" , "MKI" , 3 3610 DATA "MKS$" , "MKS" , 2 3615 DATA "MKD$" , "MKD" , 4 3645 ! 3650 DATA "NAME" , " NAME " , 0 3700 DATA "NEXT" , " NEXT " , 0 3705 ! 3800 DATA "F OR" , " FOR" , 0 3850 DATA "OPEN" , " OPEN " , 0 3860 DATA "OPTION" , " ! OPTION " , 0 3900 DATA "OUT" , " ! *OUT* " , 0 3905 ! 3950 DATA "PEEK" , " ! *PEEK* ! '?' * " , 0 4000 DATA "POKE" , "? ! *POKE* " , 0 4050 DATA "PRINT" , "PRINT " , 0 4060 DATA "WIDTH LPRINT" , "MARGIN #9, " , 0 4100 DATA "LPRINT" , " PRINT #9," , 0 4150 DATA "PUT" , "PUT " , 0 4155 ! 4200 DATA "RANDOM" , " RANDOM " , 0 4250 DATA "RANDOM IZE" , " RANDOMIZE " , 0 4300 DATA "READ" , " READ " , 0 4350 DATA "REM" , "\ REM " , 0 4400 DATA "RESET" , " RESET " , 0 4450 DATA "RESTORE" , " RESTORE " , 0 4500 DATA "RESUME" , " RESUME " , 0 4550 DATA "RETURN" , " RETURN " , 0 4600 DATA "RND(" , "RND*(" , 0 4605 ! 4650 DATA "SET" , " SET " , 0 4660 DATA "SP" , "SP." , 0 4700 DATA "STEP" , " STEP " , 0 4750 DATA "STOP" , " STOP " , 0 4755 ! 4800 DATA "THEN" , " THEN " , 0 4850 DATA "TO" , " TO " , 0 4900 DATA "GO TO" , "GOTO" , 0 4905 ! 4910 DATA " S TO P " , " STOP " , 0 4950 DATA "USING" , " USING " , 0 5000 DATA "#9, USING" , "#9 USING" , 0 5001 DATA "#9, USING" , "#9 USING" , 0 5002 DATA "#9, USING" , "#9 USING" , 0 5005 ! 5050 DATA "WHILE" , " WHILE " , 0 5850 ! 5900 DATA "..." , " ..." , 0 9000 ! 9999 END FUNCTION