===MMBasic Source Code Formatter=== //This module is part of the original MMBasic library. It is reproduced here with kind permission of Hugh Buckle and Geoff Graham. Be aware it may reference functionality which has changed or is deprecated in the latest versions of MMBasic.// __MMBasic Source Formatter ver 2.3 20/4/2013__ Format.bas is a program to indent lines of MMBasic source code in order to highlight the program structure. __Four methods to invoke__: ===1. Implied Run Command=== MMBasic ver 4.3A allows you to invoke a program from the prompt with the program name followed by a parameter list. The parameter list is passed to the program in the Read-Only Variable MM.CMDLINE$. At the MMBasic prompt type: FORMAT InFileName[.bas] OutFileName[.bas] [Indent] [/P] Where: InFileName is the program source to be formatted. OutFileName is the result of formatting. OutFileName must not be the same as InfileName. Indent is the optional number of characters to indent at each level (default 2) /P is an optional switch to list the output, pausing each screenful If an extension is not provided on the file names, Format inserts .bas. If you prefer, you can separate parms with either a blank or a comma so this is also valid: FORMAT InFileName[.bas],OutFileName[.bas],[Indent],[/P] ===2. Chaining from another program=== If you Chain to Format, you can either - create a file FORMAT.DAT containing the parameters (see method 3 below) or - let Format prompt for all four parameters as if you had just used method 4 below or - you can pass the 4 parameters to it in a variable CMDParm$. To use the latter, transfer control to Format using: CMDParm$ = "InFileName[.bas] OutFileName[.bas] [Indent] [/p]" CHAIN "FORMAT.BAS" Format uses about 55kB of memory, so if your Chaining program uses large arrays, you may need to ERASE them before chaining to Format. ===3. Config file FORMAT.DAT=== If Format doesn't find the parameter list in MM.CMDLINE$ or CMDParm$, then it looks for a file FORMAT.DAT. This file contains a single line in the same format as the parameter list for the Implied RUN Command. i.e. InFileName[.bas] OutFileName[.bas] [Indent] [/P] or InFileName[.bas],OutFileName[.bas],[Indent],[/P] ===4. "Normal" invocation=== You can invoke Format by typing RUN "FORMAT[.BAS]" at the command prompt and Format will prompt for the four parameters. FORMAT's standard set of rules: - Lines starting with a Label are aligned to the left margin as are SUB, END SUB, FUNCTION and END FUNCTION. - The first non-label line is indented to the first level. - Lines following a single line IF, DO and FOR are not further indented. - Multiline DO and FOR have their respective LOOP and NEXT aligned. Intervening lines are indented one level. - The NEXT that closes multiple levels of FOR is aligned under the first FOR. - Multiline IF statements have their ELSE, ELSEIF and ENDIF aligned under the relevant IF. Intervening statements are indented one level. - Nesting increases the indent one level. - For numbered programs, the line number is left aligned and the rest of the source uses the length of the longest number plus one as the left margin. - Other than setting the indent, the source line is not altered. - No attempt is made to check or report program errors. ===Implementaion Details=== Initialisation gets input and output file names, indent and pause. The input file is checked to make sure it exists and if the output exists, the user is asked to confirm that it be used. The program doesn't allow the output to overwrite the input in case of a power or equipment failure. The program first runs through the input file looking for line numbers, storing the length of the longest line number. If found, the line numbers are aligned at the left margin and the margin for the rest of the code set at the longest line number plus one space.. Each line is read in turn and, working on a copy of the line, the indent of the current and next line is found. The original line is then stripped of any leading spaces, indented with an appropriate number of blanks and written out. If the Pause switch has been set, the program copies the formatted source to the screen, pausing at each screenful for the user to press a key. Each line is examined and processed in turn, writing it out when completed. The first text encountered on the line is tested to see if it is, in order of precedence: - A comment or end-of-line. - SUB, END SUB, FUNCTION, END FUNCTION - DO - LOOP - FOR - NEXT - IF... THEN - ELSEIF - ELSE - Label Appropriate indenting action is taken if one of these commands is found at the start of a line. The line is then searched for colons and indenting adjusted if another of these commands is found. Lines starting with SUB, END SUB, FUNCTION, END FUNCTION or a label are aligned to the left margin. Lines starting with DO, FOR and IF signal that the following line should be indented one level. Lines starting with LOOP, NEXT, ELSEIF and ELSE are set to one less level of indent than the previous line. If the NEXT is followed by multiple loop variables, then an indent is removed for each variable. If a LOOP or NEXT appears on the same line as it's DO and FOR, then the level change for the next line is cancelled. If an IF... THEN is followed by a statement (and optional ELSE), then it is treated as a single-line-if and the level change for the next line cancelled. ===Tables=== Two tables, populated by DATA statements, are used to help parse a line: - One contains reserved words which can be followed immediately by a colon. e.g. PRINT: This is used to prevent these words from being incorrectly identified as a label. - The other table contains a list of operators which is used to differenitate between a label and any other statement. Contiguous text containing an operator cannot be a label. e.g. A=B: is not a label. ===Change Log=== 20/4/2013 V2.3 - When a file has line numbers followed by one or more spaces and a colon, the colon is moved adjacent to the line number. This mod was triggerd by MMPREY.BAS in MMLib which exhibits this condition. - If a line starts with a colon (after the optional line number and its optional colon) then it is removed. - e.g. "1234 : Statement" is changed to "1234: Statement". "1234: :Statement" is changed to "1234: Statement". " :Statement :Statement" is changed to " Statement :Statement" - Fixed a problem when nested FOR/NEXT loops appear on a single line and one of the NEXT statements terminates more than one level. Hugh Buckle **FORMAT.BAS**: ' MMBasic Program Source Formatter v2.3 ' Hugh Buckle March 2013 - updated April 2013 '********************************************************** ' You can run this version from the prompt using the Implied RUN Command ' ' FORMAT InFileName[.BAS] OutFileName[.BAS] [Indent] [/p] ' ' You can use either a comma or space between parameters ' ' Where: OutFileName must not be the same as InFileName ' Indent will default to 2 characters. ' /p lists the result to the screen - press a key to continue. ' You will be prompted if: ' The input file doesn't exist ' The output file exists or is the same as the input file ' Indent is outside the range 1 to 6. ' ' You can also run the program in the normal way using the RUN command ' in which case you will be prompted for file names, indent and pause. ' FORMAT's standard set of rules: ' - Lines starting with a Label are aligned to the left margin ' as are SUB, END SUB, FUNCTION and END FUNCTION. ' - The first non-label line is indented to the first level. ' - Lines following a single line IF, DO and FOR are not further indented. ' - Multiline DO and FOR have their respective LOOP and NEXT aligned. ' Intervening lines are indented one level. ' - The NEXT that closes multiple levels of FOR is aligned ' under the first FOR. ' - Multiline IF statements have their ELSE, ELSEIF and ENDIF aligned ' under the relevant IF. Intervening statements are indented one level. ' - Nesting increases the indent one level. ' - For numbered programs, the left margin is the longest number plus one. ' - Other than setting the indent, the source line is not altered. However, ' if the line starts with a colon (after the line number and its optional ' colon), then it is removed. ' - No attempt is made to check the program for errors. '********************************************************** true=1 false=0 Restore 'JD Addition CMDParmFile$ = "Format.dat" 'File of command line parms in format 'InFileName[.bas] OutFileName[.bas] [Indent] [/P] ' Data contains operators, used to differentiate ' between a label and any other statement. Data "=","+","-","*","/","<",">","\","^" Operators=9 Dim Operator$(Operators) For I=1 To Operators Read Operator$(i) Next ' Data contains MMBasic commands which could be interpreted as labels Data "PRINT","RETURN","CLS","RESTORE","CLEAR","EXIT","FILES","MEMORY","NEW" Data "KEYDOWN","TROFF","TRON","DO","LOOP","NEXT" Commands=15 Dim Command$(Commands) For i=1 To Commands Read Command$(i) Next Mainline: '********************************************************** ' Initialisation gets input and output file names, indent and pause. ' Each line is read in turn and, working on a copy of the line, ' the indent of the current and next line is found. The original line ' is indented with an appropriate number of blanks and written out. ' If the first line contains a line number then the program skips through ' to the last line to find the maximum sized line number. Lines are then ' processed as before, adding a padded line number and indent to the code. '********************************************************** initialise(Ifile$, Ofile$, Indent) Print Print "Formatting ";ifile$;" and writing to ";Ofile$ Print String$(78,"_") CheckForLineNumbers CLI = Indent 'Current line indent NLI = Indent 'Next line indent Do While Not Eof(#1) CLI = NLI Line Input #1, iline$ ' Get next line oline$ = StripBlanks$(iline$) ' Strip off leading blanks If LineNumbers Then ExtractLineNo ' Remove the line number cline$ = oline$ ' Make working copy AdjustIndent ' Find current & next line indents oline$ = Space$(CLI) + Oline$ ' Indent current line If LineNumbers Then Oline$ = LineNo$ + Oline$ Print #2, oline$ ' Write to output file If PauseList$="Y" Then Print oline$ ' Print a copy to screen wait ' Pause at a screenful Else Print "."; EndIf Loop Close #1 Close #2 Print Print String$(78,"_") Print "Formatting finished. Please test the output file." If MasterFile$ <> "" Then 'JD Addition UpTo = UpTo + 1 Chain MasterFile$ EndIf End 'Mainline Function StripBlanks$(A$) '********************************************************** ' Strips blanks, tabs and colons from the beginning of the line. '********************************************************** Local i i=1 Do While Mid$(A$,i,1)=" " Or Mid$(A$,i,1)=Chr$(9) Or Mid$(A$,i,1)=":" i=i+1 Loop StripBlanks$ = Mid$(A$,i) ' Copies from i to end of a$ to the function End Function 'StripBlanks Function Variable(a$,s) '********************************************************** ' Checks the character after a command name to see if it's a variable. ' s points to the character after the command name '********************************************************** Variable=True b$=Mid$(a$,s,1) If Len(a$)=Len(a$) Or Mid$(a$,p,1)="'" Or UCase$(Mid$(a$,p,3))="REM" Then b$="" Else b$=Mid$(a$,p,1) If b$=Chr$(34) Then Do ' skip over quoted text p=p+1 Loop Until Mid$(a$,p,1)=Chr$(34) Or p = Len(a$) EndIf p=p+1 EndIf Loop Until b$="" Or b$<>" " End Sub 'GetNextNonBlankChar Sub ExtractLineNo '********************************************************** ' Saves the line number if present and pads it to ' the length of the longest one. If some of the code uses line ' numbers and some not, then those without line numbers are ' indented as if they had a line number. ' If the line number is followed by one or more spaces and ' a colon, the spaces between line number and colon are removed. '********************************************************** Local j If Left$(Oline$,1)>="0" And Left$(Oline$,1)<="9" Then LineNo$=Left$(Oline$,Instr(1,Oline$," ")) j=Len(LineNo$) GetNextNonBlankChar(Oline$,j,b$) If b$=":" Then LineNo$=Left$(LineNo$,Len(LineNo$)-1)+": " Oline$=Mid$(Oline$,j) EndIf If Len(LineNo$) < LineNoLen Then ' pad to longest line no LineNo$ = LineNo$ + Space$(LineNoLen-Len(LineNo$)) EndIf Oline$=Right$(Oline$,Len(Oline$)-Instr(1,Oline$," ")) Oline$=StripBlanks$(Oline$) Else LineNo$=Space$(LineNoLen) EndIf End Sub 'ExtractLineNo Sub AdjustIndent '********************************************************** ' For each command that affects the indent, ' adjust both current (CLI) and next line indent (NLI). ' Repeat until comment or end-of-line reached to handle multi-statement lines. '********************************************************** EOL=False ForNest=False 'Nest level of FOR/NEXT DoFound=False Do Found=False Test_LineEnd(Found,EOL) If Not Found Then Test_Sub_Fn(Found) If Not Found Then Test_Do(Found) If Not Found Then Test_Loop(Found) If Not Found Then Test_For(Found) If Not Found Then Test_Next(Found) If Not Found Then Test_If_Then(Found,MultiLine) If Not Found Then Test_ElseIf(Found,MultiLine) If Not Found Then Test_Else(Found,MultiLine) If Not Found Then Test_EndIf(Found) If Not Found Then Test_for_label(Found) ' Look for other statements in the line If Not EOL Then FlushToColon Cline$=Stripblanks$(Cline$) If Cline$="" Then EOL=True EndIf Loop Until EOL End Sub 'AdjustIndent Sub Test_LineEnd(Found,EOL) '********************************************************** ' Test if finished processing this line '********************************************************** If Len(CLine$)<=1 Or Left$(Cline$,1)="'" Or Left$(UCase$(Cline$),4)="REM " Then Found=True EOL=True EndIf End Sub 'Test_LineEnd Sub FlushToColon '********************************************************** ' Find the next statement on a multi-statement line '********************************************************** Local i i=1 Do GetNextNonBlankChar(Cline$,i,a$) Loop Until a$ = ":" Or a$ = "" If a$="" Then Cline$="" ' reached EOL Else Cline$=Right$(Cline$,Len(Cline$)-i+1) EndIf End Sub 'FlushToColon Sub Test_Sub_Fn(Found) '********************************************************** ' SUB & FUNCTION start & end stmts are aligned to the left margin '********************************************************** If UCase$(Left$(Cline$,4))="SUB " Then Found = True ElseIf UCase$(Left$(Cline$,7))="END SUB" Then Found = True ElseIf UCase$(Left$(Cline$,9))="FUNCTION " Then Found = True ElseIf UCase$(Left$(Cline$,12))="END FUNCTION" Then Found = True EndIf If Found Then NLI = CLI 'save current indent CLI = 0 'Move this line to the left margin EndIf End Sub 'Test_Sub_Fn Sub Test_Do(Found) '********************************************************** 'Print the DO at the current indent but indent the next line further '********************************************************** If UCase$(Left$(Cline$,2))="DO" And Not Variable(Cline$,3) Then NLI = NLI + Indent DoFound=True Found = True EndIf End Sub 'Test_Do Sub Test_Loop(Found) '********************************************************** 'If LOOP, print this and the next line one less indent '********************************************************** If UCase$(Left$(Cline$,4))="LOOP" And Not Variable(Cline$,5) Then If DoFound Then NLI=CLI Else CLI = CLI - Indent 'remove one level of indent NLI = CLI 'make the next line indent the same EndIf Found = True EndIf End Sub 'Test_Loop Sub Test_For(Found) '********************************************************** 'Print the FOR at the current indent but indent the next line one indent '********************************************************** If UCase$(Left$(Cline$,3))="FOR" And Not Variable(Cline$,4) Then NLI = NLI + Indent ForNest=ForNest+1 Found = True EndIf End Sub 'Test_For Sub Test_Next(Found) '********************************************************** 'If NEXT, print this and the next line one less indent '********************************************************** If UCase$(Left$(Cline$,4))="NEXT" And Not Variable(Cline$,5) Then If ForNest Then NLI = CLI ForNest=ForNest-1 Else CLI = CLI - Indent 'remove one level of indent NLI = CLI 'make the next line indent the same EndIf Ptr = 5 ' Look for a comma which closes multiple For levels Do GetNextNonBlankChar(Cline$,Ptr,a$) If a$ = "," Then If ForNest Then ForNest=ForNest-1 Else CLI = CLI - Indent 'remove another level of indent NLI = CLI 'make the next line indent the same EndIf EndIf Loop Until a$ = "" Or a$ = ":" ' Both end the NEXT statement Found=True EndIf End Sub 'Test_Next Sub Test_If_Then(Found,ML) '********************************************************** 'Print the IF/ELSE at the current indent but indent the next line further '********************************************************** If UCase$(Left$(Cline$,3))="IF " Then ' test for one-line IF/THEN. ' "Then" will be followed by a non-blank character Ptr = Instr(4,UCase$(Cline$)," THEN") Ptr=Ptr+6 GetNextNonBlankChar(Cline$, Ptr, b$) ' if statement continues on next line, indent the next line If b$="" Or b$=" " Then NLI = CLI + Indent ML=1 'Indicate a multi-line IF EndIf Found=True EndIf End Sub 'Test_If_Then Sub Test_ElseIf(Found,ML) '********************************************************** ' If on entry, MultiLn=1, the previous THEN/ELSE was a multiline statement '********************************************************** If UCase$(Left$(Cline$,6))="ELSEIF" And Not Variable(Cline$,7) Then If ML = 1 Then CLI = CLI - Indent ML=0 ' test for one-line ELSEIF/THEN. ' The ELSE will be followed by a non-blank character Ptr = Instr(4,UCase$(Cline$)," THEN") Ptr=Ptr+6 GetNextNonBlankChar(Cline$, Ptr, b$) If b$="" Or b$<>" " Then NLI = CLI + Indent ML=1 EndIf Found=True EndIf End Sub 'Test_ElseIf Sub Test_Else(Found,ML) '********************************************************** ' If on entry, MultiLn=1, the previous THEN/ELSE was a multiline statement '********************************************************** If UCase$(Left$(Cline$,4))="ELSE" And Not Variable(Cline$,5) Then If ML = 1 Then CLI = CLI - Indent ML=0 ' test for one-line ELSE/THEN. ' The ELSE will be followed by a non-blank character Ptr = Instr(4,UCase$(Cline$)," THEN") Ptr=Ptr+6 GetNextNonBlankChar(Cline$, Ptr, b$) If b$="" Or b$<>" " Then NLI = CLI + Indent ML=1 EndIf Found=True EndIf End Sub 'Test_Else Sub Test_EndIf(Found) '********************************************************** 'If ENDIF, print this and the next line one less indent '********************************************************** If UCase$(Left$(Cline$,5))="ENDIF" And Not Variable(Cline$,6) Then CLI = CLI - Indent 'remove one level of indent NLI = CLI 'make the next line indent the same Found=True EndIf End Sub 'Test_EndIf Sub Test_for_Label(Found) '********************************************************** ' A line starting with a label is aligned to the left margin ' A label is terminated with a colon and musn't ' - have an imbedded blank or operator. ' - be an MMBasic command terminated with a colon. '********************************************************** Found=False p=Instr(1,Cline$,":") ' Look for first colon If p<>0 Then Found=True 'Provided there is no imbedded blank or operator For i=1 To p-1 a$=Mid$(Cline$,i,1) If a$=" " Or IsOperator(a$) Then Found=False Exit For EndIf Next EndIf ' Check that it is not a one word MMBasic command If found And p<>0 Then For i=1 To Commands If UCase$(Left$(Cline$,p-1))=Command$(i) Then Found=False Exit For EndIf Next EndIf If Found=True Then CLI=0 EndIf End Sub 'Test_for_Label Function IsOperator(a$) '********************************************************** ' Tests a$ to see if it is an operator '********************************************************** Local i IsOperator=False For i=1 To Operators If a$=Operator$(i) Then IsOperator=True Exit For EndIf Next End Function 'IsOperator Sub Initialise(Ifile$,Ofile$,Indent) '********************************************************** ' Input and Output file names, indent and pause switch can come from ' 4 sources (in order of precedence: ' - MM.CMDLine$, the implied RUN command ' - CMDParm$, a variable passed by a program that chains to Format. ' - FORMAT.DAT file in the same format as MM.CMDline$ ' - User prompts ' If file names are missing from the first 2, the user is prompted to ' enter them. If indent and pause switch are omitted, defaults are used. '********************************************************** a$=MM.CmdLine$ If a$<>"" Then Print "Getting parms from MM.CMDLine$." GetCMDLine(a$) ElseIf CMDParm$<>"" Then ' CMDParm$ is intended to be passed by a Chaining program Print "Getting parms from CMDParm$." GetCMDLine(CMDParm$) Else a$=GetParmsFromFile$(CMDParmFile$) If MM.Errno=0 Then Print "Getting parms from file ";CMDParmFile$ If a$<>"" Then GetCMDLine(a$) EndIf Do If Ifile$="" Then Input "Give me the Input filename (.BAS assumed) - 'Exit' to exit: ", Ifile$ EndIf If LCase$(Ifile$)="exit" Then End CheckInputFileName(Ifile$) Loop Until Ifile$<>"" Do If Ofile$="" Then Input "Give me the Output filename (.BAS assumed) - 'Exit' to exit: ", Ofile$$ EndIf If LCase$(Ofile$)="exit" Then End CheckOutputFilename(Ofile$, Ifile$) Loop Until Ofile$<>"" If Indent = 0 Then GetIndent(Indent) If Indent=0 Then End EndIf If PauseList$="" Then GetPause(PauseList$) End Sub 'Initialise Function GetParmsFromFile$(DATFile$) '********************************************************** 'Gets the parameters from a file provided by Renumber '********************************************************** Local a$ Option error continue Open DATFile$ For input As #3 If MM.Errno = 0 Then Line Input #3,a$ GetParmsFromFile$=a$ Close #3 EndIf Option error abort End Function 'GetParmsFromFile Sub GetCMDLine(a$) '********************************************************** ' MMBasic 4.3A onward which supports implied Run command ' User can start the program with FORMAT infilename outfilename [Indent] [/p] ' /p lists the output a screenful at a time. Press any key to continue. ' On exit Parm$(1) = infilename, Parm$(2) = outfilename, Parm3 = Indent 0r 0 '********************************************************** Local i If a$<>"" Then ParmNo=5 ' Examine up to 5 parms ' Set the delimiter between parms If Instr(1,a$,",") Then ParmDelimiter$="," Else ParmDelimiter$=" " Dim Parm$(ParmNo) ParseParm(a$,ParmNo,ParmDelimiter$) Ifile$=Parm$(1) Ofile$=Parm$(2) Indent=2 PauseList$="N" For i=3 To ParmNo If Val(Parm$(i)) > 0 Then Indent=Val(Parm$(3)) If UCase$(Parm$(i))="/P" Then PauseList$="Y" Next EndIf Erase Parm$ 'Not needed any more - save the space End Sub 'GetCMDLine Sub ParseParm(p$,PNo,Delim$) '********************************************************** ' Parse the parameters on the Implied Run Command line, ' from CMDparm$ or the DAT file. '********************************************************** Local i,Strt,Ptr Strt=1 For i=1 To PNo Ptr=Instr(Strt,p$,Delim$) If Ptr=0 Then Ptr=Len(p$)+1 Parm$(i)=Mid$(p$,Strt,Ptr-Strt) If Ptr>=Len(p$) Then Exit For Strt=Ptr FindNextParmDelimiter(p$,Strt,Delim$) Next If UCase$(Parm$(3))="/P" Then ' user opted to omit Indent so Parm$(4)=Parm$(3) ' shift pause list parm to it's proper place Parm$(3)="" ' and clear the Indent parm EndIf End Sub 'ParseParm Sub FindNextParmDelimiter(a$,p,Delim$) '********************************************************** ' Fine the start of the next parameter '********************************************************** Do p=p+1 Loop Until Mid$(a$,p,1)<>Delim$ Or p=Len(a$) End Sub 'FindNextParmDelimiter Sub CheckInputFilename(i$) '********************************************************** ' Adds .BAS if an extension is not provided and checks that is accessible '********************************************************** If Instr(1,i$,".")=0 Then i$=i$+".bas" Option error continue Open i$ For INPUT As #1 If MM.Errno <> 0 Then Print i$ " doesn't exist." Print i$="" EndIf Option error abort End Sub 'CheckInputFilename Sub CheckOutputFileName(o$,i$) '********************************************************** ' Adds .BAS if an extension is not provided and checks that it does't alread exit. ' If it exists, asks user if ok to overwrite. '********************************************************** If Instr(1, o$, ".") = 0 Then o$ = o$ + ".bas" If LCase$(o$)=LCase$(i$) Then Print "You cannot write to the input file - give me another." Print o$="" Else ' If old file exists, ask if it should be replaced. If not, get another filename Option error continue Open o$ For input As #2 If MM.Errno = 0 Then Print "OK to overwrite "+o$+" Y/N";:Input ""; Reply$ If LCase$(Left$(Reply$,1)) = "y" Then Close #2 Open o$ For output As #2 Else Close #2 Print o$="" EndIf Else Open o$ For output As #2 EndIf Option error abort EndIf End Sub 'CheckOutputFileName Sub GetIndent(i) '********************************************************** ' Asks user for number of spaces to use for each level of indent '********************************************************** Do Input "What indent should I use? (Range 1-6, 0 to exit): ", i If i<0 Or i>6 Then Print "Indent needs to be in the range 1 to 6, or type 0 to exit" Print EndIf Loop Until i>=0 And i<=6 End Sub 'GetIndent Sub GetPause(a$) '********************************************************** ' Asks user if screen listing should be paused at end of each screenful. '********************************************************** Do Input "Pause the listing at the end of each screenful (y/n)?", a$ a$ = UCase$(a$) If a$ <> "Y" And a$ <> "N" Then Print "Please answer Y or N." Print EndIf Loop Until a$ = "Y" Or a$ = "N" End Sub 'GetPause Sub PrintInstructions '********************************************************** Print @(MM.HRes/2-12*10,1) "Program Source Formatter v2.0" Print @(MM.HRes/2-12*10,12) "=============================" Print "This program reads a basic program file and creates a new one following" Print "these indent rules:" Print " - Lines starting with a Label are aligned to the left margin" Print " as are SUB, END SUB, FUNCTION and END FUNCTION." Print " - The first non-label line is indented to the first level." Print " - Lines following a single line IF, DO and FOR are not further indented." Print " - Multiline DO and FOR have their respective LOOP and NEXT aligned." Print " Intervening lines are indented one level." Print " - Multiline IF statements have their ELSE, ELSEIF and ENDIF aligned" Print " under the relevant IF. Intervening statements are indented one level." Print " - Nesting increases the indent one level." Print " - For numbered programs, the left margin is the longest number plus one." Print " - Other than setting the indent, the source line is not altered." Print " - No attempt is made to check the program for errors." Print Print "From MMBasic V4.3a you can invoke FORMAT from the Basic prompt using" Print "the implied RUN command. The syntax is:" Print Print " FORMAT InFileName[.BAS] OutFileName[.BAS] [Indent] [/p]" Print Print "Where: InFileName must not be the same as OutFileName" Print " Indent defaults to 2 and" Print " switch /p pauses the listing at a screenful." Print End Sub 'PrintInstructions Sub CheckForLineNumbers '********************************************************** ' Check for line numbers and find the longest number ' Length of longest number + 1 will be used as the left margin '********************************************************** Local i LineNumbers=False Do Line Input #1, Iline$ ILine$=StripBlanks$(ILine$) 'Remove any leading blanks If Left$(ILine$,1)>="0" And Left$(ILine$,1)<="9" Then LineNumbers=True i=Instr(1,ILine$," ") If i>LineNoLen Then LineNoLen=i EndIf Loop Until Eof(#1) Close #1 Open Ifile$ For Input As #1 End Sub 'CheckForLineNumbers Sub wait '********************************************************** ' Causes the program to pause at the end of each screenful. ' Any keystroke causes the program to continue. '********************************************************** w=w+1 If w>30 Then w=0 Do k$=Inkey$ Loop Until k$<>"" EndIf End Sub 'Wait