'===========================================================================
' Subject: ASSEMBLY TO BASIC                  Date: 04-28-97 (12:15)       
'  Author: Petter Holmberg                    Code: QB, QBasic, PDS        
'  Origin: petter.holmberg@usa.net          Packet: ASMCODE.ABC
'===========================================================================
' -------------------------------------------------------------------------- '
' Absolute Assembly by Petter Holmberg, -97. Ver. 1.1beta:                   '
'                                                                            '
' I recently started using DEBUG to create Assembler routines for BASIC with '
' CALL ABSOLUTE. It didn't took me very long to discover that turning        '
' Assembler code into a BASIC string with machine language was a long and    '
' tedious process. Working with the code in a text file instead of directly  '
' from within DEBUG and then then type:                                      '
' DEBUG < sourcefile > destfile                                              '
' made it a little easier, but it was still a lot of work.                   '
' Before the first run through DEBUG, there's no way of knowing how many     '
' bytes of code to unassemble, and after the second run when the source file '
' was modified to unassemble the correct number of bytes, there was still a  '
' lot of work moving the machine code to BASIC. If you have tried yourself,  '
' you know what I mean.                                                      '
' So I made a program to do the work for me. Absolute Assembly 1.0.          '
' But soon after I had finished Absolute Assembly 1.0, I needed to do a      '
' routine with a JMP instruction. So I made this new version with support    '
' for line labels and comments.                                              '
' This program will let you choose a text file with assembler instructions,  '
' a destination file name and a string variable name. The result will be a   '
' set of commented BASIC lines in the destination file which declares a      '
' string with the name you have chosen, ready to be executed.                '
' Ex:                                                                        '
'                                                                            '
' You have a text file looking like this:                                    '
'                                                                            '
'          XOR AX, AX   ; Set AX to 0.                                       '
'          MOV CX, 10   ; Prepare for a loop.                                '
' TheLoop: INC AX       ; Increase AX.                                       '
'          LOOP TheLoop ; Loop 10 times.                                     '
'          RETF         ; Return to BASIC.                                   '
'                                                                            '
' Run it through this program and you will get these lines moved into a      '
' selected QBASIC program:                                                   '
'                                                                            '
' asm$ = ""                                                                  '
' asm$ = asm$ + CHR$(&H31) + CHR$(&HC0) ' XOR     AX,AX                      '
' asm$ = asm$ + CHR$(&HB9) + CHR$(&H10) + CHR$(&H0) ' MOV        CX,0010     '
' asm$ = asm$ + CHR$(&H40) ' TheLoop: INC AX                                 '
' asm$ = asm$ + CHR$(&HE2) + CHR$(&HFD) ' LOOP    TheLoop                    '
' asm$ = asm$ + CHR$(&HCB) ' RETF                                            '
'                                                                            '
' Notes:                                                                     '
' þ All lines in the source file must have one Assembler instruction in it.  '
'   Don't use blank lines or lines with just comments.                       '
' þ Comments must start with a semicolon, (;).                               '
' þ The maximum number of labels is 256. You shouldn't need half as much.    '
' þ The maximum number of letters for a label is 16. It's easy to change     '
'   the program to accept a larger number, but it's probably not necessary.  '
' þ A label must be immediately followed by a colon, (:).                    '
' þ Never use Assembly opcodes or numbers as labels.                         '
' þ "Label:" and "label:" are processed as different labels.                 '
' þ Do not write lines like: REP MOVSB. When assembling, DEBUG will divide   '
'   this into two lines; REPZ and MOVSB. This will mess up everything for    '
'   this program. Sorry, I didn't bother to write any code to handle such    '
'   occurrences.                                                             '
' þ This program was made in QB45, but you should be able to run it in       '
'   QBASIC, PDS, VBDOS and PB as well.                                       '
' þ I haven't really tested this program for bugs, so please be patient with '
'   me. :)                                                                   '
' þ Any comments/suggestions can be sent to: petter.holmberg@usa.net         '
' þ I know, I know, the source code is VERY crappy, but I wrote this in just '
'   an hour or two and it works! Maybe I'll add some more functions later... '
'                                                                            '
' Enjoy the program and have fun!                                            '
' -------------------------------------------------------------------------- '

CONST rundebug$ = "C:\DOS\DEBUG.EXE" ' Change this if you have DEBUG on
				     ' another location.
CONST tempfile1$ = "TEMPFIL1.TXT"    ' Change this if this filename already
				     ' are in use.
CONST tempfile2$ = "TEMPFIL2.TXT"    ' Change this if this filename already
				     ' are in use.
CONST tempfile3$ = "TEMPFIL3.TXT"    ' Change this if this filename already
				     ' are in use.

TYPE labeltype                       ' Usertype for storing of labels.
  labelname AS STRING * 16
  labelpos AS STRING * 4
  labelnum AS INTEGER
END TYPE

DIM label(1 TO 256) AS labeltype     ' Array for storing of labels.

numlabels% = 0                       ' Label counter.
linecounter% = 1                     ' Line counter.

CLS

PRINT "Absolute Assembly by Petter Holmberg, -97. Ver. 1.1beta:"
PRINT
INPUT "Assembly source text file: ", sourcefilename$
INPUT "QBASIC destination file  : ", destfilename$
INPUT "Name of code string      : ", codestring$
PRINT

conversiontime! = TIMER

' Insert DEBUG instructions and assembly source code into tempfile and take
' care of lables and comments:
OPEN tempfile1$ FOR OUTPUT AS #1

OPEN sourcefilename$ FOR INPUT AS #2
DO
   LINE INPUT #2, sourceline$
   IF INSTR(sourceline$, ";") THEN
    sourceline$ = LEFT$(sourceline$, INSTR(sourceline$, ";") - 1)
   END IF
   IF INSTR(sourceline$, ":") THEN
    numlabels% = numlabels% + 1
    label(numlabels%).labelname = LEFT$(sourceline$, INSTR(sourceline$, ":") - 1)
    sourceline$ = MID$(sourceline$, INSTR(sourceline$, ":") + 1)
    label(numlabels%).labelnum = linecounter%
   END IF
   PRINT #1, sourceline$
   linecounter% = linecounter% + 1
LOOP UNTIL EOF(2)
CLOSE #2

CLOSE #1

OPEN tempfile2$ FOR OUTPUT AS #1
PRINT #1, "a"

OPEN tempfile1$ FOR INPUT AS #2

DO
   LINE INPUT #2, sourceline$
   FOR labelscan% = 1 TO numlabels%
      IF INSTR(sourceline$, RTRIM$(label(labelscan%).labelname)) THEN
       sourceline$ = LEFT$(sourceline$, INSTR(sourceline$, RTRIM$(label(labelscan%).labelname)) - 1) + "100"
      END IF
   NEXT labelscan%
   PRINT #1, sourceline$
LOOP UNTIL EOF(2)

CLOSE #2

PRINT #1, ""
PRINT #1, "u 100, 100"
PRINT #1, "q"
CLOSE #1

' Run DEBUG to create DEBUG output file:
SHELL rundebug$ + "<" + tempfile2$ + ">" + tempfile2$

' Get length in bytes of source code:
OPEN tempfile2$ FOR INPUT AS #1

DO
   oldline$ = midline$
   midline$ = newline$
   LINE INPUT #1, newline$
   SEEK #1, SEEK(1) + 2
   IF INSTR(newline$, "^") THEN
    PRINT "Error in source code detected. Look in "; tempfile2$; " for information."
    END
   END IF
LOOP UNTIL newline$ = "-u 100, 100"

CLOSE #1

asmlength$ = MID$(oldline$, INSTR(oldline$, ":") + 1, 4)

PRINT "Source code byte length detected."

OPEN tempfile2$ FOR OUTPUT AS #1
PRINT #1, "a"

OPEN tempfile1$ FOR INPUT AS #2

DO
   LINE INPUT #2, sourceline$
   FOR labelscan% = 1 TO numlabels%
      IF INSTR(sourceline$, RTRIM$(label(labelscan%).labelname)) THEN
       sourceline$ = LEFT$(sourceline$, INSTR(sourceline$, RTRIM$(label(labelscan%).labelname)) - 1) + "100"
      END IF
   NEXT labelscan%
   PRINT #1, sourceline$
LOOP UNTIL EOF(2)

CLOSE #2

PRINT #1, ""
PRINT #1, "u 100, "; asmlength$
PRINT #1, "q"
CLOSE #1

' Run DEBUG to create DEBUG output file again:
SHELL rundebug$ + "<" + tempfile2$ + ">" + tempfile2$

OPEN tempfile2$ FOR INPUT AS #1

DO
   LINE INPUT #1, readline$
LOOP UNTIL INSTR(readline$, "-u 100,")

SEEK #1, SEEK(1) + 2

labelcounter% = 1
linecounter% = 1

DO
   LINE INPUT #1, readline$
   IF label(labelcounter%).labelnum = linecounter% THEN
    label(labelcounter%).labelpos = MID$(readline$, 6, 4)
    labelcounter% = labelcounter% + 1
   END IF
   linecounter% = linecounter% + 1
LOOP UNTIL readline$ = "-q"
  
CLOSE #1

OPEN tempfile2$ FOR OUTPUT AS #1
PRINT #1, "a"

OPEN tempfile1$ FOR INPUT AS #2

DO
   LINE INPUT #2, sourceline$
   FOR labelscan% = 1 TO numlabels%
      IF INSTR(sourceline$, RTRIM$(label(labelscan%).labelname)) THEN
       sourceline$ = LEFT$(sourceline$, INSTR(sourceline$, RTRIM$(label(labelscan%).labelname)) - 1) + label(labelscan%).labelpos
      END IF
   NEXT labelscan%
   PRINT #1, sourceline$
LOOP UNTIL EOF(2)

CLOSE #2

PRINT #1, ""
PRINT #1, "u 100, "; asmlength$
PRINT #1, "q"
CLOSE #1

PRINT "Label conversion completed."

' Run DEBUG to create DEBUG output file again:
SHELL rundebug$ + "<" + tempfile2$ + ">" + tempfile2$

PRINT "DEBUG output file successfully created."

' Transform the source code into BASIC string declaration lines:
OPEN tempfile2$ FOR INPUT AS #1

DO
   LINE INPUT #1, readline$
LOOP UNTIL INSTR(readline$, "-u 100,")

SEEK #1, SEEK(1) + 2

OPEN destfilename$ FOR OUTPUT AS #2

OPEN tempfile1$ FOR INPUT AS #3

PRINT #2, codestring$ + " = " + CHR$(34) + CHR$(34)

linecounter% = 1
labelcounter% = 1

DO
   LINE INPUT #1, readline$
   IF NOT EOF(3) THEN LINE INPUT #3, sourceline$ ELSE sourceline$ = ""
   'PRINT sourceline$
   readline$ = RTRIM$(readline$)
   IF readline$ <> "-q" THEN
    sourcedata$ = MID$(readline$, 11, 14)
    basicline$ = codestring$ + " = " + codestring$ + " + "
    FOR makebasicline% = 1 TO 13 STEP 2
       IF MID$(sourcedata$, makebasicline%, 2) <> "  " THEN
	basicline$ = basicline$ + "CHR$(&H" + MID$(sourcedata$, makebasicline%, 2) + ") + "
       END IF
    NEXT makebasicline%
    basicline$ = RTRIM$(basicline$)
    basicline$ = LEFT$(basicline$, LEN(basicline$) - 1)
    basicline$ = RTRIM$(basicline$)
    basicline$ = basicline$ + " ' "
    IF label(labelcounter%).labelnum = linecounter% THEN
     basicline$ = basicline$ + RTRIM$(label(labelcounter%).labelname) + ": "
     labelcounter% = labelcounter% + 1
    END IF
    basicline$ = basicline$ + RIGHT$(readline$, (LEN(readline$) - 24))
    FOR labelscan% = 1 TO numlabels%
       IF INSTR(sourceline$, RTRIM$(label(labelscan%).labelname)) THEN
	basicline$ = LEFT$(basicline$, LEN(basicline$) - 4)
	basicline$ = basicline$ + RTRIM$(label(labelscan%).labelname)
       END IF
    NEXT labelscan%
    basicline$ = RTRIM$(basicline$)
    PRINT #2, basicline$
   END IF
   linecounter% = linecounter% + 1
LOOP UNTIL readline$ = "-q"

PRINT #2, ""

CLOSE #3
CLOSE #2
CLOSE #1

PRINT "Source code successfully moved to QBASIC destination file."

KILL tempfile1$
KILL tempfile2$

PRINT
PRINT "Time of conversion:"; TIMER - conversiontime!; "seconds."
