!****************************************************************************
! PREPRO.BAS    Assembler Preprocessor
!
!       Eliminates "lengthy" labels and symbols from a version 2.0 .M68
!       file so that the file may be assembled with older versions of an
!       assembler.
!
! by DAVE HEYLIGER - AMUS Staff         08-29-86
!
! NOTE: WILL NOT REPLACE TWO-WORDED SYMBOLS SEPARATED BY A SPACE. YOU MUST
!       CREATE ALL MULTIPLE WORDED SYMBOLS LIKE "THE.LONG.SYMBOL" - NOT
!       "THE LONG SYMBOL".
!
!                  NOT GUARANTEED FOR ALL FILES - WORKS 99%
!             (no danger of file distruction if it doesn't work)
!
!                 HEAVY COMMENTS TO MAKE DEGUBBING A SNAP
!***************************************************************************

MAP1    labels(100),S,32                ! array of lengthy labels
MAP1    l'pointer,F                     ! pointer into label array
MAP1    consts(100),S,32                ! similar....
MAP1    c'pointer,F
MAP1    vars(100),S,32
MAP1    v'pointer,F
MAP1    dat(100),S,32
MAP1    d'pointer,F
MAP1    macro(100),S,32
MAP1    m'pointer,F
MAP1    file'in,S,10                    ! input file name (assumes .M68)
MAP1    file'out,S,10                   ! converted output file (.M68)
MAP1    long,S,130                      ! input line
MAP1    temp'name,S,32                  ! name of string needing replacement
MAP1    i,F                             ! various counters...
MAP1    j,F
MAP1    k,F
MAP1    s,F
MAP1    m,F
MAP1    x,F
MAP1    colon'loc,F                     ! location of string needing replace.
MAP1    i'val,S,3                       ! portion of replacement string
MAP1    r'string,S,6                    ! replacement string
MAP1    r'string'length,F               ! length of longest replacement string
MAP1    file'lines,F                    ! number of lines in .M68 file
MAP1    search'string,S,32              ! string needing replacement
MAP1    blanks,s,40,"                                        "


START:
! Initialize, set up screen, etc....
!------------------------------------
       ? TAB(-1,0)
       ? TAB(2,3)"============================================================================"
       ? TAB(3,3)"| Assembly Preprocessor - removes long labels from a .M68 source code file |"
       ? TAB(4,3)"|                         to allow older version assemblers to function.   |"
       ? TAB(5,3)"============================================================================"
       ? TAB(8,20);:INPUT LINE "Enter file to be preprocessed: ",file'in
       ? TAB(9,20);:INPUT LINE "Enter new name for above file: ",file'out
       file'in = UCS(file'in)
       IF RIGHT$(file'in,4) <> ".M68" THEN file'in = file'in + ".M68"
       ? TAB(-1,29);TAB(4,8)"searching";
       OPEN #1,file'in,INPUT
       l'pointer = c'pointer = v'pointer = d'pointer = m'pointer = k = 1
       x = 10
       file'lines = 0
       r'string'length = 0


NEXT'LINE:
! Read in a line, "fancy" screen work
!
! Variables:    file'lines       = total lines in source file
!               long             = line of source code
!               k,x              = counters for screen output
!------------------------------------------------------------
       INPUT LINE #1,long
       file'lines = file'lines + 1
       k = k + 1
       IF x = k THEN ? TAB(4,8)"         ";
       IF k > 20 THEN k = 0 : x = 10 : ? TAB(4,8)"searching";
       IF EOF(1) THEN GOTO OUT'STRINGS

DATA'DEFINE:
! Searching for the following examples:
!       DEFINE {macro name "a"}={macro name "b"}        type code [1]
!       ESC=33                                          type code [2]
! Bypassing the following examples:
!       source line     ; blah blah = blah blah         type code [3]
!       MOV     #'=,D1                                  type code [4]
!
! Variables:    long            = source code line
!               m               = location of search string "="
!               colon'loc       = location of a ":" in source line
!               temp'name       = long label, var, const, or macro
!               r'string'length = length of longest temp'name
!               c'pointer       = constant array pointer value
!               consts          = array of lengthy constants found
!-------------------------------------------------------------------------
       IF INSTR(1,long,"DEFINE") <> 0 &
          THEN IF INSTR(1,long,"=") = 0 THEN GOTO MACROS               ![1]
       m = INSTR(1,long,"=")                                           ![1,2]
       IF m = 0 THEN GOTO OFDEF
       IF INSTR(1,long,";") = 0 THEN GOTO L8                           ![3]
       IF INSTR(1,long,"=") >= INSTR(1,long,";") THEN GOTO OFDEF       ![3]
L8:     IF INSTR(1,long,",") = 0 THEN GOTO L9                           ![4]
       IF INSTR(1,long,",") < INSTR(1,long,"=") THEN GOTO OFDEF        ![4]
L9:     colon'loc = m
       CALL GET'NAME
       IF LEN(temp'name) <= 6 THEN GOTO NEXT'LINE
       IF LEN(temp'name) > r'string'length &
          THEN r'string'length = LEN(temp'name)
L10:    c'pointer = c'pointer + 1
       consts(c'pointer) = temp'name
       GOTO NEXT'LINE

OFDEF:
! Searching for the following examples:
!       .OFDEF {variable name}                          type code [5]
! Bypassing the following examples:
!       source line     ;get the .OFDEF junk            type code [6]
!
! Variables:    long            = source code line
!               temp'name       = long label, var, const, or macro
!               m               = location of search string
!---------------------------------------------------------------------------
       m = INSTR(1,long,".OFDEF")                                      ![5]
       IF m = 0 THEN GOTO FIND'MARK
       IF INSTR(1,long,";") <> 0 &
         THEN IF INSTR(1,long,".OFDEF") >= INSTR(1,long,";") &
            THEN GOTO NEXT'LINE                                        ![6]
       m = m + 7
       IF long[m;1] = " " THEN m = m + 1
       IF long[m;1] = CHR(9) THEN m = m + 1
       temp'name = long[m;1]
L6:     m = m + 1
       IF long[m;1] = "," THEN GOTO L5
       IF long[m;1] = "=" THEN GOTO L5
       temp'name = temp'name + long[m;1]
       GOTO L6

FIND'MARK:
! Searching for the following:
!       LABEL:
! Bypassing the followng:
!       ; semi-colon at line position 1
!
! Variables:    long            = source code line
!----------------------------------------------------------------------

       FOR i = 1 TO LEN(long)
         IF long[i;1] = ":" THEN GOTO DECIPHER
         IF long[i;1] = ";" THEN GOTO NEXT'LINE
         NEXT i
         GOTO NEXT'LINE

DECIPHER:
! Searching for the following
!       LABEL:  RAD50
!       LABEL:  ASCII
!       LABEL:  BLKB (BLKW or BLKL)
!       LABEL:  BYTE
!
! Variables:    long            = source code line
!               colon'loc       = location of a ":" in source line
!               temp'name       = long label, var, const, or macro
!               r'string'length = length of longest temp'name
!               l'pointer       = label array pointer value
!               labels          = array of lengthy labels found
!------------------------------------------------------------------------
       IF INSTR(1,LEFT$(long,i-1)," ") <> 0 THEN GOTO NEXT'LINE
       IF INSTR(1,LEFT$(long,i-1),CHR(9)) <> 0 THEN GOTO NEXT'LINE
       IF i = LEN(long) THEN colon'loc = i : GOTO L1   !(MUST be a label)
       CALL WHITE'SPACE
       IF long[i;3] = "ASC" THEN GOTO FOUND'CONST
       IF long[i;3] = "RAD" THEN GOTO FOUND'CONST
       IF long[i;3] = "BYT" THEN GOTO FOUND'CONST
       IF long[i;3] = "BLK" THEN GOTO FOUND'VAR
L1:     CALL GET'NAME
       IF LEN(temp'name) <= 6 THEN GOTO NEXT'LINE
       IF LEN(temp'name) > r'string'length &
          THEN r'string'length = LEN(temp'name)
       l'pointer = l'pointer + 1
       labels(l'pointer) = temp'name
       GOTO NEXT'LINE

FOUND'CONST:
! DECIPHER figured it was a constant, so store the name if "lengthy"
!
! Variables:    temp'name       = long label, var, const, or macro
!               r'string'length = length of longest temp'name
!               c'pointer       = constant array pointer value
!               consts          = array of lengthy constants found
!-------------------------------------------------------------------
       CALL GET'NAME
       IF LEN(temp'name) <= 6 THEN GOTO NEXT'LINE
       IF LEN(temp'name) > r'string'length &
          THEN r'string'length = LEN(temp'name)
       c'pointer = c'pointer + 1
       consts(c'pointer) = temp'name
       GOTO NEXT'LINE

FOUND'VAR:
! DECIPHER figured it was a variable, so store the name if "lengthy"
!
! Variables:    temp'name       = long label, var, const, or macro
!               r'string'length = length of longest temp'name
!               v'pointer       = variable array pointer value
!               vars            = array of lengthy variables found
!-------------------------------------------------------------------
       CALL GET'NAME
L5:     IF LEN(temp'name) <= 6 THEN GOTO NEXT'LINE
       IF LEN(temp'name) > r'string'length &
          THEN r'string'length = LEN(temp'name)
       v'pointer = v'pointer + 1
       vars(v'pointer) = temp'name
       GOTO NEXT'LINE

WHITE'SPACE:
! Get rid of tabs and " "'s after the LABEL:
!
! Variables:    long            = source code line
!               colon'loc       = location of a ":" in source line
!               i               = cursor position variable
!--------------------------------------------------------------------
       colon'loc = i
LOOP1:  i = i+1
       IF i = LEN(long) THEN RETURN
       IF long[i;1] = CHR(9) THEN GOTO LOOP1
       IF long[i;1] = CHR(32) THEN GOTO LOOP1
       RETURN

MACROS:
! Found a MACRO definition, so get the name & store if "lengthy"
!
! Variables:    long            = source code line
!               i               = cursor position variable
!               temp'name       = long label, var, const, or macro
!               r'string'length = length of longest temp'name
!               m'pointer       = macro array pointer value
!               macro           = array of lengthy macros found
!---------------------------------------------------------------
       temp'name = ""
       i = INSTR(1,long,"DEFINE")
       i = i + 6
       CALL WHITE'SPACE
L11:    temp'name = temp'name + long[i;1]
       i = i + 1
       IF long[i;1] <> CHR(9) &
          THEN IF long[i;1] <> CHR(32) &
             THEN IF i <= LEN(long) THEN GOTO L11
       IF LEN(temp'name) <= 6 THEN GOTO NEXT'LINE
       IF LEN(temp'name) > r'string'length &
          THEN r'string'length = LEN(temp'name)
       m'pointer = m'pointer + 1
       macro(m'pointer) = temp'name
       GOTO NEXT'LINE


GET'NAME:
! Retrieves the name of the string found
!
! Variables:    long            = source code line
!               i,j             = cursor position variables
!               colon'loc       = location of a ":" in source line
!               temp'name       = long label, var, const, or macro
!---------------------------------------
       i = colon'loc
       j = i-1
LOOP2:
       IF long[j;1] = CHR(9) &
          THEN IF j <> 1 THEN i= j : j = j-1 : GOTO LOOP2 &
                         ELSE temp'name = long[j+1,i-1] : RETURN
       IF long[j;1] = " " THEN temp'name = long[j+1,i-1] : RETURN
       IF j = 1 THEN temp'name = long[j,i-1] : RETURN
       j = j-1
       GOTO LOOP2


OUT'STRINGS:
!
! Display "lengthy" culprets
!
! Variables:    x               = row counter variable for output to screen
!               i               = array index value for all arrays
!               labels, etc     = arrays of all strings found too long
!--------------------------------------------------------------------------
       ? TAB(4,8)"         "
       x = 0
       ? TAB(8,20)blanks;TAB(9,20)blanks
       ? TAB(6,1);"Oversized text:"
       ?
       FOR  i = 1 to 98
         x = x + 1
         IF labels(i) = "" THEN GOTO l2
         IF x > 28 THEN ? TAB(8+(x-30),50)labels(i) &
                   ELSE IF x > 14 THEN ? TAB(8+(x-15),25)labels(i) &
                                  ELSE ? labels(i)
         NEXT i
l2:
       FOR  i = 1 to 98
         x = x + 1
         IF consts(i) = "" THEN GOTO l3
         IF x > 28 THEN ? TAB(8+(x-30),50)consts(i) &
                   ELSE IF x > 14 THEN ? TAB(8+(x-15),25)consts(i) &
                                  ELSE ? consts(i)
         NEXT i
l3:
       FOR  i = 1 to 98
         x = x + 1
         IF vars(i) = "" THEN GOTO l4
         IF x > 28 THEN ? TAB(8+(x-30),50)var(i) &
                   ELSE IF x > 14 THEN ? TAB(8+(x-15),25)vars(i) &
                                  ELSE ? vars(i)
         NEXT i
l4:
       FOR  i = 1 to 98
         x = x + 1
         IF dat(i) = "" THEN GOTO l12
         IF x > 28 THEN ? TAB(8+(x-30),50)dat(i) &
                   ELSE IF x > 14 THEN ? TAB(8+(x-15),25)dat(i) &
                                  ELSE ? dat(i)
         NEXT i
l12:
       FOR  i = 1 to 98
         x = x + 1
         IF macro(i) = "" THEN GOTO l7
         IF x > 28 THEN ? TAB(8+(x-30),50)macro(i) &
                   ELSE IF x > 14 THEN ? TAB(8+(x-15),25)macro(i) &
                                  ELSE ? marco(i)
         NEXT i

l7:     ?

       CLOSE #1

SEARCH'REPLACE:
! Now begin searching each line of the file, replace strings when found
! TRICKY: must replace longest found strings first else errors!
!
! Variables:    long            = source code line
!               x               = dot counter for screen output effects
!               k               = string length (longest ---> shortest)
!               i               = index pointer into array of long strings
!               j               = line number in source file
!               s               = funny screen counter (you'll see...)
!               r'string'length = length of longest temp'name
!               l'pointer       = label array pointer value
!               labels          = array of lengthy labels found
!               search'string   = string needing replacement
!----------------------------------------------------------------------
       x = s = 0
       OPEN #1,file'in,INPUT
       OPEN #2,file'out,OUTPUT
       ?
       ? TAB(-1,28) TAB(21,1)"Replacing strings, creating new file..";

FOR j = 1 to file'lines
        x = x + 1 : s = s + 1
        INPUT LINE #1,long
        CALL NO'COMMENTS
        IF x = 40 THEN ? TAB(21,39)blanks; TAB(21,39);: x = 0 &
                  ELSE ? ".";
        IF s = 80 THEN ? TAB(4,6) "Sorry I'm so slow! ";
        IF s = 240 THEN ? TAB(4,6)"Write shorter code!";
        IF s = 400 THEN ? TAB(4,6)"I'm getting bored. ";
        IF s = 560 THEN ? TAB(4,6)"Go get some coffee.";
        IF s = 720 THEN ? TAB(4,6)"I'm burning out!!! ";
  FOR k = r'string'length TO 1 STEP -1
     r'string = "L00"
     FOR i = 1 to 98
       IF LEN(labels(i)) = k &
           THEN search'string = labels(i) : CALL STRING'MATCH
       IF labels(i) = "" THEN GOTO LL2
       NEXT i

LL2:  r'string = "C00"
     FOR i = 1 to 98
       IF LEN(consts(i)) = k &
           THEN search'string = consts(i) : CALL STRING'MATCH
       IF consts(i) = "" THEN GOTO LL3
       NEXT i

LL3:  r'string = "V00"
     FOR i = 1 to 98
       IF LEN(vars(i)) = k &
           THEN search'string = vars(i) : CALL STRING'MATCH
       IF vars(i) = "" THEN GOTO LL4
       NEXT i

LL4:  r'string = "D00"
     FOR i = 1 to 98
       IF LEN(dat(i)) = k &
           THEN search'string = dat(i) : CALL STRING'MATCH
       IF dat(i) = "" THEN GOTO LL5
       NEXT i

LL5:  r'string = "M00"
     FOR i = 1 to 98
       IF LEN(marco(i)) = k &
           THEN search'string = macro(i) : CALL STRING'MATCH
       IF macro(i) = "" THEN GOTO LL6
       NEXT i

LL6:
       NEXT k
       ? #2,long
     NEXT j
     GOTO HALT

STRING'MATCH:
! Replaces lengthy strings
!
! Variables:    long            = source code line
!               search'string   = lengthy string needing replacement
!------------------------------------------------------------------
           i'val = i
           IF long = search'string THEN long = search'string : RETURN
           m = INSTR(1,long,search'string)
           IF m = 0 THEN RETURN
           IF m = 1 THEN CALL FAR'LEFT : RETURN
           IF (LEFT$(long,m)+search'string) = long &
              THEN CALL FAR'RIGHT : RETURN
           mid'length = LEN(search'string)
           CALL MID
           RETURN


NO'COMMENTS:
! Strips off comment lines
!
! Variables:    long            = source code line
!               m               = position of ";"
!-------------------------------------------------
       m = INSTR(1,long,";")
       IF m < 2 THEN RETURN
       long = LEFT$(long,m-1)
       RETURN

FAR'LEFT:
! Swaps string if found at very far left
!
! Variables:    r'string        = 1/2 replacement string for lengthy string
!               long            = source code line
!               i'val           = second 1/2 of above
!               k               = length of original lengthy string
!---------------------------------------------------------------------------
long = r'string + i'val + MID$(long,k+1,LEN(long))
       RETURN

FAR'RIGHT:
! Swaps string if found at very far right
!
! Variables:    long            = source code line
!               m               = location of string needing replacement
!------------------------------------------------------------------------
       long = LEFT$(long,m) + r'string + i'val
       RETURN

MID:
!
! Swaps string if found in middle of line
!
! Variables:    long            = source code file line
!               m               = location of string needing replacement
!               r'string        = 1/2 of replacement string
!               i'val           = second half of above
!               mid'length      = length of string needing replacement
!-----------------------------------------------------------------------
       long = LEFT$(long,m-1) + r'string + i'val + MID$(long,m+mid'length,LEN(long))
       RETURN

HALT:   CLOSE #1
       CLOSE #2
       ? TAB(4,6)"    Whew!!          "
       ? TAB(22,1)"File conversion complete, "file'out" created!"
       END