home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 9 / 09.iso / l / l196 / 3.ddi / REMLINE.BA$ / REMLINE.bin
Encoding:
Text File  |  1990-06-24  |  12.5 KB  |  411 lines

  1. DEFINT A-Z
  2. '
  3. '   Microsoft RemLine - Line Number Removal Utility
  4. '   Copyright (C) Microsoft Corporation   - 1985, 1986, 1987
  5. '
  6. '   REMLINE.BAS is a program to remove line numbers from Microsoft BASIC
  7. '   Programs. It removes only those line numbers that are not the object
  8. '   of one of the following statements: GOSUB, RETURN, GOTO, THEN, ELSE,
  9. '   RESUME, RESTORE, or RUN.
  10. '
  11. '   REMLINE is run by typing
  12. '
  13. '      REMLINE [<input> [, <output>]]
  14. '
  15. '   where <input> is the name of the file to be processed and <output>
  16. '   is the name of the file or device to receive the reformatted output.
  17. '   If no extension is given, .BAS is assumed (except for output devices).
  18. '   If file names are not given, REMLINE prompts for file names. If both
  19. '   file names are the same, REMLINE saves the original file with the
  20. '   extension .BAK.
  21. '
  22. '   REMLINE makes several assumptions about the program:
  23. '
  24. '     1. It must be correct syntactically, and must run in BASICA or
  25. '        GWBASIC interpreter.
  26. '     2. There is a 400 line limit. To process larger files, change
  27. '        MaxLines constant.
  28. '     3. The first number encountered on a line is considered a line
  29. '        number; thus some continuation lines (in a compiler specific
  30. '        constructiion) may not be handled correctly.
  31. '     4. REMLINE can handle simple statements that test the ERL function
  32. '        using  relational operators such as =, <, and >. For example,
  33. '        the following statement is handled correctly:
  34. '
  35. '             IF ERL = 100 THEN END
  36. '
  37. '        Line 100 is not removed from the source code. However, more
  38. '        complex expressions that contain the +, -, AND, OR, XOR, EQV,
  39. '        MOD, or IMP operators may not be handled correctly. For example,
  40. '        in the following statement REMLINE does not recognize line 105
  41. '        as a referenced line number and removes it from the source code:
  42. '
  43. '             IF ERL + 5 = 105 THEN END
  44. '
  45. '   If you do not like the way REMLINE formats its output, you can modify
  46. '   the output lines in SUB GenOutFile. An example is shown in comments.
  47.  
  48. ' Function and Subprogram declarations
  49.  
  50. DECLARE FUNCTION GetToken$ (Search$, Delim$)
  51. DECLARE FUNCTION StrSpn% (InString$, Separator$)
  52. DECLARE FUNCTION StrBrk% (InString$, Separator$)
  53. DECLARE FUNCTION IsDigit% (Char$)
  54. DECLARE SUB GetFileNames ()
  55. DECLARE SUB BuildTable ()
  56. DECLARE SUB GenOutFile ()
  57. DECLARE SUB InitKeyTable ()
  58.  
  59. ' Global and constant data
  60.  
  61. CONST TRUE = -1
  62. CONST false = 0
  63. CONST MaxLines = 400
  64.  
  65. DIM SHARED LineTable!(MaxLines)
  66. DIM SHARED LineCount
  67. DIM SHARED Seps$, InputFile$, OutputFile$, TmpFile$
  68.  
  69. ' Keyword search data
  70.  
  71. CONST KeyWordCount = 9
  72. DIM SHARED KeyWordTable$(KeyWordCount)
  73.  
  74. KeyData:
  75.    DATA THEN, ELSE, GOSUB, GOTO, RESUME, RETURN, RESTORE, RUN, ERL, ""
  76.  
  77. ' Start of module-level program code
  78.  
  79.    Seps$ = " ,:=<>()" + CHR$(9)
  80.    InitKeyTable
  81.    GetFileNames
  82.    ON ERROR GOTO FileErr1
  83.    OPEN InputFile$ FOR INPUT AS 1
  84.    ON ERROR GOTO 0
  85.    COLOR 7: PRINT "Working"; : COLOR 23: PRINT " . . .": COLOR 7: PRINT
  86.    BuildTable
  87.    CLOSE #1
  88.    OPEN InputFile$ FOR INPUT AS 1
  89.    ON ERROR GOTO FileErr2
  90.    OPEN OutputFile$ FOR OUTPUT AS 2
  91.    ON ERROR GOTO 0
  92.    GenOutFile
  93.    CLOSE #1, #2
  94.    IF OutputFile$ <> "CON" THEN CLS
  95.  
  96. END
  97.  
  98. FileErr1:
  99.    CLS
  100.    PRINT "      Invalid file name": PRINT
  101.    INPUT "      New input file name (ENTER to terminate): ", InputFile$
  102.    IF InputFile$ = "" THEN END
  103. FileErr2:
  104.    INPUT "      Output file name (ENTER to print to screen) :", OutputFile$
  105.    PRINT
  106.    IF (OutputFile$ = "") THEN OutputFile$ = "CON"
  107.    IF TmpFile$ = "" THEN
  108.       RESUME
  109.    ELSE
  110.       TmpFile$ = ""
  111.       RESUME NEXT
  112.    END IF
  113.  
  114. '
  115. ' BuildTable:
  116. '   Examines the entire text file looking for line numbers that are
  117. '   the object of GOTO, GOSUB, etc. As each is found, it is entered
  118. '   into a table of line numbers. The table is used during a second
  119. '   pass (see GenOutFile), when all line numbers not in the list
  120. '   are removed.
  121. ' Input:
  122. '   Uses globals KeyWordTable$, KeyWordCount, and Seps$
  123. ' Output:
  124. '   Modefies LineTable! and LineCount
  125. '
  126. SUB BuildTable STATIC
  127.  
  128.    DO WHILE NOT EOF(1)
  129.       ' Get line and first token
  130.       LINE INPUT #1, InLin$
  131.       token$ = GetToken$(InLin$, Seps$)
  132.       DO WHILE (token$ <> "")
  133.          FOR KeyIndex = 1 TO KeyWordCount
  134.             ' See if token is keyword
  135.             IF (KeyWordTable$(KeyIndex) = UCASE$(token$)) THEN
  136.                ' Get possible line number after keyword
  137.                token$ = GetToken$("", Seps$)
  138.                ' Check each token to see if it is a line number
  139.                ' (the LOOP is necessary for the multiple numbers
  140.                ' of ON GOSUB or ON GOTO). A non-numeric token will
  141.                ' terminate search.
  142.                DO WHILE (IsDigit(LEFT$(token$, 1)))
  143.                   LineCount = LineCount + 1
  144.                   LineTable!(LineCount) = VAL(token$)
  145.                   token$ = GetToken$("", Seps$)
  146.                   IF token$ <> "" THEN KeyIndex = 0
  147.                LOOP
  148.             END IF
  149.          NEXT KeyIndex
  150.          ' Get next token
  151.          token$ = GetToken$("", Seps$)
  152.       LOOP
  153.    LOOP
  154.  
  155. END SUB
  156.  
  157. '
  158. ' GenOutFile:
  159. '  Generates an output file with unreferenced line numbers removed.
  160. ' Input:
  161. '  Uses globals LineTable!, LineCount, and Seps$
  162. ' Output:
  163. '  Processed file
  164. '
  165. SUB GenOutFile STATIC
  166.  
  167.    ' Speed up by eliminating comma and colon (can't separate first token)
  168.    Sep$ = " " + CHR$(9)
  169.    DO WHILE NOT EOF(1)
  170.       LINE INPUT #1, InLin$
  171.       IF (InLin$ <> "") THEN
  172.          ' Get first token and process if it is a line number
  173.          token$ = GetToken$(InLin$, Sep$)
  174.          IF IsDigit(LEFT$(token$, 1)) THEN
  175.             LineNumber! = VAL(token$)
  176.             FoundNumber = false
  177.             ' See if line number is in table of referenced line numbers
  178.             FOR index = 1 TO LineCount
  179.                IF (LineNumber! = LineTable!(index)) THEN
  180.                   FoundNumber = TRUE
  181.                END IF
  182.             NEXT index
  183.             ' Modify line strings
  184.             IF (NOT FoundNumber) THEN
  185.                token$ = SPACE$(LEN(token$))
  186.                MID$(InLin$, StrSpn(InLin$, Sep$), LEN(token$)) = token$
  187.             END IF
  188.               
  189.             ' You can replace the previous lines with your own
  190.             ' code to reformat output. For example, try these lines:
  191.                
  192.             'TmpPos1 = StrSpn(InLin$, Sep$) + LEN(Token$)
  193.             'TmpPos2 = TmpPos1 + StrSpn(MID$(InLin$, TmpPos1), Sep$)
  194.             '
  195.             'IF FoundNumber THEN
  196.             '   InLin$ = LEFT$(InLin$, TmpPos1 - 1) + CHR$(9) + MID$(InLin$, TmpPos2)
  197.             'ELSE
  198.             '   InLin$ = CHR$(9) + MID$(InLin$, TmpPos2)
  199.             'END IF
  200.  
  201.          END IF
  202.       END IF
  203.       ' Print line to file or console (PRINT is faster than console device)
  204.       IF OutputFile$ = "CON" THEN
  205.          PRINT InLin$
  206.       ELSE
  207.          PRINT #2, InLin$
  208.       END IF
  209.    LOOP
  210.  
  211. END SUB
  212.  
  213. '
  214. ' GetFileNames:
  215. '  Gets a file name from COMMAND$ or by prompting the user.
  216. ' Input:
  217. '  Used Command$ or user input
  218. ' Output:
  219. '  Defines InputFiles$ and OutputFiles$
  220. '
  221. SUB GetFileNames STATIC
  222.  
  223.    IF (COMMAND$ = "") THEN
  224.       CLS
  225.       PRINT " Microsoft RemLine: Line Number Removal Utility"
  226.       PRINT "       (.BAS assumed if no extension given)"
  227.       PRINT
  228.       INPUT "      Input file name (ENTER to terminate): ", InputFile$
  229.       IF InputFile$ = "" THEN END
  230.       INPUT "      Output file name (ENTER to print to screen): ", OutputFile$
  231.       PRINT
  232.       IF (OutputFile$ = "") THEN OutputFile$ = "CON"
  233.    ELSE
  234.       InputFile$ = UCASE$(GetToken$(COMMAND$, Seps$))
  235.       OutputFile$ = UCASE$(GetToken$("", Seps$))
  236.       IF (OutputFile$ = "") THEN
  237.          INPUT "      Output file name (ENTER to print to screen): ", OutputFile$
  238.          PRINT
  239.          IF (OutputFile$ = "") THEN OutputFile$ = "CON"
  240.       END IF
  241.    END IF
  242.    IF INSTR(InputFile$, ".") = 0 THEN
  243.       InputFile$ = InputFile$ + ".BAS"
  244.    END IF
  245.    IF INSTR(OutputFile$, ".") = 0 THEN
  246.       SELECT CASE OutputFile$
  247.          CASE "CON", "SCRN", "PRN", "COM1", "COM2", "LPT1", "LPT2", "LPT3"
  248.             EXIT SUB
  249.          CASE ELSE
  250.             OutputFile$ = OutputFile$ + ".BAS"
  251.       END SELECT
  252.    END IF
  253.    DO WHILE InputFile$ = OutputFile$
  254.       TmpFile$ = LEFT$(InputFile$, INSTR(InputFile$, ".")) + "BAK"
  255.       ON ERROR GOTO FileErr1
  256.       NAME InputFile$ AS TmpFile$
  257.       ON ERROR GOTO 0
  258.       IF TmpFile$ <> "" THEN InputFile$ = TmpFile$
  259.    LOOP
  260.  
  261. END SUB
  262.  
  263. '
  264. ' GetToken$:
  265. '  Extracts tokens from a string. A token is a word that is surrounded
  266. '  by separators, such as spaces or commas. Tokens are extracted and
  267. '  analyzed when parsing sentences or commands. To use the GetToken$
  268. '  function, pass the string to be parsed on the first call, then pass
  269. '  a null string on subsequent calls until the function returns a null
  270. '  to indicate that the entire string has been parsed.
  271. ' Input:
  272. '  Search$ = string to search
  273. '  Delim$  = String of separators
  274. ' Output:
  275. '  GetToken$ = next token
  276. '
  277. FUNCTION GetToken$ (Search$, Delim$) STATIC
  278.  
  279.    ' Note that SaveStr$ and BegPos must be static from call to call
  280.    ' (other variables are only static for efficiency).
  281.    ' If first call, make a copy of the string
  282.    IF (Search$ <> "") THEN
  283.       BegPos = 1
  284.       SaveStr$ = Search$
  285.    END IF
  286.   
  287.    ' Find the start of the next token
  288.    NewPos = StrSpn(MID$(SaveStr$, BegPos, LEN(SaveStr$)), Delim$)
  289.    IF NewPos THEN
  290.       ' Set position to start of token
  291.       BegPos = NewPos + BegPos - 1
  292.    ELSE
  293.       ' If no new token, quit and return null
  294.       GetToken$ = ""
  295.       EXIT FUNCTION
  296.    END IF
  297.  
  298.    ' Find end of token
  299.    NewPos = StrBrk(MID$(SaveStr$, BegPos, LEN(SaveStr$)), Delim$)
  300.    IF NewPos THEN
  301.       ' Set position to end of token
  302.       NewPos = BegPos + NewPos - 1
  303.    ELSE
  304.       ' If no end of token, return set to end a value
  305.       NewPos = LEN(SaveStr$) + 1
  306.    END IF
  307.    ' Cut token out of search string
  308.    GetToken$ = MID$(SaveStr$, BegPos, NewPos - BegPos)
  309.    ' Set new starting position
  310.    BegPos = NewPos
  311.  
  312. END FUNCTION
  313.  
  314. '
  315. ' InitKeyTable:
  316. '  Initializes a keyword table. Keywords must be recognized so that
  317. '  line numbers can be distinguished from numeric constants.
  318. ' Input:
  319. '  Uses KeyData
  320. ' Output:
  321. '  Modifies global array KeyWordTable$
  322. '
  323. SUB InitKeyTable STATIC
  324.  
  325.    RESTORE KeyData
  326.    FOR Count = 1 TO KeyWordCount
  327.       READ KeyWord$
  328.       KeyWordTable$(Count) = KeyWord$
  329.    NEXT
  330.  
  331. END SUB
  332.  
  333. '
  334. ' IsDigit:
  335. '  Returns true if character passed is a decimal digit. Since any
  336. '  BASIC token starting with a digit is a number, the function only
  337. '  needs to check the first digit. Doesn't check for negative numbers,
  338. '  but that's not needed here.
  339. ' Input:
  340. '  Char$ - initial character of string to check
  341. ' Output:
  342. '  IsDigit - true if within 0 - 9
  343. '
  344. FUNCTION IsDigit (Char$) STATIC
  345.  
  346.    IF (Char$ = "") THEN
  347.       IsDigit = false
  348.    ELSE
  349.       CharAsc = ASC(Char$)
  350.       IsDigit = (CharAsc >= ASC("0")) AND (CharAsc <= ASC("9"))
  351.    END IF
  352.  
  353. END FUNCTION
  354.  
  355. '
  356. ' StrBrk:
  357. '  Searches InString$ to find the first character from among those in
  358. '  Separator$. Returns the index of that character. This function can
  359. '  be used to find the end of a token.
  360. ' Input:
  361. '  InString$ = string to search
  362. '  Separator$ = characters to search for
  363. ' Output:
  364. '  StrBrk = index to first match in InString$ or 0 if none match
  365. '
  366. FUNCTION StrBrk (InString$, Separator$) STATIC
  367.  
  368.    Ln = LEN(InString$)
  369.    BegPos = 1
  370.    ' Look for end of token (first character that is a delimiter).
  371.    DO WHILE INSTR(Separator$, MID$(InString$, BegPos, 1)) = 0
  372.       IF BegPos > Ln THEN
  373.          StrBrk = 0
  374.          EXIT FUNCTION
  375.       ELSE
  376.          BegPos = BegPos + 1
  377.       END IF
  378.    LOOP
  379.    StrBrk = BegPos
  380.   
  381. END FUNCTION
  382.  
  383. '
  384. ' StrSpn:
  385. '  Searches InString$ to find the first character that is not one of
  386. '  those in Separator$. Returns the index of that character. This
  387. '  function can be used to find the start of a token.
  388. ' Input:
  389. '  InString$ = string to search
  390. '  Separator$ = characters to search for
  391. ' Output:
  392. '  StrSpn = index to first nonmatch in InString$ or 0 if all match
  393. '
  394. FUNCTION StrSpn% (InString$, Separator$) STATIC
  395.  
  396.    Ln = LEN(InString$)
  397.    BegPos = 1
  398.    ' Look for start of a token (character that isn't a delimiter).
  399.    DO WHILE INSTR(Separator$, MID$(InString$, BegPos, 1))
  400.       IF BegPos > Ln THEN
  401.          StrSpn = 0
  402.          EXIT FUNCTION
  403.       ELSE
  404.          BegPos = BegPos + 1
  405.       END IF
  406.    LOOP
  407.    StrSpn = BegPos
  408.  
  409. END FUNCTION
  410.  
  411.