'known problems:
'   order of operations for the <<, >>, |, & operators probably
'       aren't handled correctly in the simplify.  as long as
'       you use parentheses, you should be fine.
'   cannot simplify things such as "2 | -3" because the minus
'       gets interpreted as the dominant separator character
'   multi-line C comments in the /* */ style aren't removed
'   variables with embedded periods aren't translated
'   dot directives really shouldn't just be commented out
'   filenames to convert need to be modified in the code
'   instructions involving a memory reference with ab additive
'       constant and a scalar are interpreted incorrectly.

DEFINT A-Z
DECLARE FUNCTION BigSum& (value1&, value2&)
DECLARE FUNCTION SimplifyInner% (source$)
DECLARE FUNCTION isalpha% (a$)
DECLARE FUNCTION multiply& (ain&, bin&)
DECLARE FUNCTION Simplify% (source$)
DECLARE FUNCTION SimplifyValue (intext$)
DECLARE FUNCTION isdigit% (a$)
DECLARE FUNCTION isxdigit% (a$)
DECLARE SUB DelSubString (a$, index%, length%)
DECLARE FUNCTION tabtospace$ (line$)
DECLARE FUNCTION separateparam$ (line$)
DECLARE FUNCTION BigMultiply& (value1&, value2&)

OPEN "rg-k6.s" FOR INPUT AS #1
OPEN "rg-k6.asm" FOR OUTPUT AS #2

PRINT "Converting";

PRINT #2, ".386"
PRINT #2, ";.model flat ; some use small model, so use appropriate cmdline switch"
PRINT #2, "             ; eg /mf or /ms for WASM"
PRINT #2, ".code"

DO WHILE NOT EOF(1)
	LINE INPUT #1, line$
	line$ = RTRIM$(LTRIM$(tabtospace$(line$)))

	' translate comments
	index = INSTR(line$, "#")
	comment$ = ""
	IF index > 0 THEN
		comment$ = comment$ + MID$(line$, index + 1)
		line$ = LEFT$(line$, index - 1)
	END IF
	index = INSTR(line$, "/*")
	IF index > 0 THEN
		index2 = INSTR(index, line$, "*/")
		IF index2 > 0 THEN
			comment$ = comment$ + MID$(line$, index + 2, index2 - index - 2)
			line$ = LEFT$(line$, index - 1) + " " + MID$(line$, index2 + 2)
		END IF
	END IF
	index = INSTR(line$, "//")
	IF index > 0 THEN
		comment$ = comment$ + MID$(line$, index + 2)
		line$ = LEFT$(line$, index - 1)
	END IF
	IF comment$ <> "" THEN comment$ = CHR$(9) + ";" + comment$


   
	' line labels
	index = INSTR(line$, " ")
	index2 = INSTR(line$, ":")
	IF (index2 > 0) AND (index < 1 OR index > index2) THEN
		' remove periods from labels
		DO
			dot = INSTR(line$, ".")
			IF (dot > 0) THEN
				CALL DelSubString(line$, dot, 1)
			ELSE
				EXIT DO
			END IF
		LOOP

		' prefix numerical labels
		IF isdigit(LEFT$(line$, 1)) THEN PRINT #2, "Num";

		' print it
		PRINT #2, LEFT$(line$, index2);
		line$ = LTRIM$(MID$(line$, index2 + 1))
	END IF



	' dot directive
	IF LEFT$(line$, 1) = "." THEN
		PRINT #2, ";"; line$;
		line$ = ""
	END IF




	' separate out mnemonic
	index = INSTR(line$, " ")
	IF index > 0 THEN
		mnemonic$ = LEFT$(line$, index - 1)
		line$ = LTRIM$(MID$(line$, index + 1))
		IF LCASE$(RIGHT$(mnemonic$, 1)) = "l" THEN
			mnemonic$ = LEFT$(mnemonic$, LEN(mnemonic$) - 1)
		END IF
	ELSE
		mnemonic$ = line$
		line$ = ""
	END IF


	' separate out parameters
	param1$ = separateparam$(line$)
	param2$ = separateparam$(line$)


	' output line
	PRINT #2, mnemonic$; " ";
	IF LEN(param2$) THEN
		PRINT #2, param2$; ","; param1$;
	ELSEIF LCASE$(LEFT$(mnemonic$, 1)) = "j" THEN
		' jump instruction

		' remove periods
		DO
			dot = INSTR(param1$, ".")
			IF (dot > 0) THEN
				CALL DelSubString(param1$, dot, 1)
			ELSE
				EXIT DO
			END IF
		LOOP

		' prefix numerical labels
		IF isdigit(LEFT$(param1$, 1)) THEN
			' jump instruction with numeric label
			IF LCASE$(RIGHT$(param1$, 1)) = "f" THEN param1$ = LEFT$(param1$, LEN(param1$) - 1)
			PRINT #2, "Num"; param1$;
		ELSE
			PRINT #2, param1$;
		END IF
	ELSE
		PRINT #2, param1$;
	END IF


	' output remaining stuff
	IF LEN(line$) THEN
		PRINT #2, ";(unparsed="; line$; ")";
		line$ = ""
	END IF


	' output comment and line break
	PRINT #2, comment$
	PRINT ".";
LOOP
PRINT

PRINT #2, "end"
CLOSE

' .model small
' .386
' .code
' start:
' push bp
' mov bp,sp
' push si
' push di
' mov si,[bp+6]
' mov di,[bp+8]
' mov eax,ds:[si]
' imul eax,ds:[di]
' mov ds:[si],eax
' pop di
' pop si
' pop bp
' retf 8
' end start

BigSumData:
DATA &H55,&H8B,&HEC,&H56,&H57,&H8B,&H76,&H06
DATA &H8B,&H7E,&H08,&H66,&H8B,&H04,&H66,&H03
DATA &H05,&H66,&H89,&H04,&H5F,&H5E,&H5D,&HCA
DATA &H04,&H00,-1
BigMultiplyData:
DATA &H55,&H8B,&HEC,&H56,&H57,&H8B,&H76,&H06
DATA &H8B,&H7E,&H08,&H66,&H8B,&H04,&H66,&H0F
DATA &HAF,&H05,&H66,&H89,&H04,&H5F,&H5E,&H5D
DATA &HCA,&H04,&H00,-1

FUNCTION BigMultiply& (value1&, value2&)
	RESTORE BigMultiplyData
	DIM a%(16)
	DEF SEG = VARSEG(a%(0))
	FOR i% = 0 TO 32
	   READ d%
	   IF d% = -1 THEN EXIT FOR
	   POKE VARPTR(a%(0)) + i%, d%
	NEXT i%
	temp& = value2&
	CALL ABSOLUTE(value1&, temp&, VARPTR(a%(0)))
	DEF SEG
	BigMultiply& = temp&
END FUNCTION

FUNCTION BigSum& (value1&, value2&)
	RESTORE BigSumData
	DIM a%(16)
	DEF SEG = VARSEG(a%(0))
	FOR i% = 0 TO 32
	   READ d%
	   IF d% = -1 THEN EXIT FOR
	   POKE VARPTR(a%(0)) + i%, d%
	NEXT i%
	temp& = value2&
	CALL ABSOLUTE(value1&, temp&, VARPTR(a%(0)))
	DEF SEG
	BigSum& = temp&
END FUNCTION

SUB DelSubString (a$, index, length)
	a$ = LEFT$(a$, index - 1) + MID$(a$, index + length)
END SUB

FUNCTION isalpha (a$)
	IF LEN(a$) > 1 THEN ERROR 1
	isalpha = (a$ >= "A" AND a$ <= "Z") OR (a$ >= "a" AND a$ <= "z")
END FUNCTION

FUNCTION isdigit (a$)
	IF LEN(a$) > 1 THEN ERROR 1
	isdigit = a$ >= "0" AND a$ <= "9"
END FUNCTION

FUNCTION isxdigit (a$)
	IF LEN(a$) > 1 THEN ERROR 1
	isxdigit = (a$ >= "0" AND a$ <= "9") OR (UCASE$(a$) >= "A" AND UCASE$(a$) <= "F")
END FUNCTION

FUNCTION multiply& (ain&, bin&)
	result& = 0
	a& = ain&
	b& = bin&
	WHILE (a& <> 0)
		IF (a& AND 1) THEN result& = result& + b&
		a& = a& \ 2
		b& = b& AND &H7FFFFFFF
		b& = b& * 2
	WEND
	multiply& = result&
END FUNCTION

FUNCTION separateparam$ (line$)
	DIM param$(1 TO 10)
	level = 0
	thisparam = 1


	' split the parameter out into groups
	DO WHILE LEN(line$) > 0
		a$ = LEFT$(line$, 1)
		line$ = MID$(line$, 2)
		IF a$ = "," THEN
			IF (level = 0) THEN
				EXIT DO
			ELSE
				param$(thisparam) = param$(thisparam) + "+"
			END IF
		ELSEIF a$ = "(" THEN
			IF level = 0 AND LEN(param$(thisparam)) THEN
				thisparam = thisparam + 1
			END IF
			level = level + 1
			param$(thisparam) = param$(thisparam) + a$
		ELSEIF a$ = ")" THEN
			level = level - 1
			param$(thisparam) = param$(thisparam) + a$
			IF level = 0 THEN thisparam = thisparam + 1
		ELSEIF a$ = "+" AND level = 0 THEN
			IF LEN(param$(thisparam)) THEN thisparam = thisparam + 1
		ELSE
			param$(thisparam) = param$(thisparam) + a$
		END IF
	LOOP


	' Join everything together
	total$ = ""
	memoryaccess = 0
	gotfirst = 0
	FOR i = 1 TO thisparam
		' eat leading and training parens
		parens = LEFT$(param$(i), 1) = "(" AND RIGHT$(param$(i), 1) = ")"
		IF parens THEN
			param$(i) = MID$(param$(i), 2, LEN(param$(i)) - 2)
		END IF


		' translate register references
		foundreg = 0
		DO
			index = INSTR(param$(i), "%")
			IF (index > 0) THEN
				IF parens THEN memoryaccess = 1
				MID$(param$(i), index, 1) = " "
				foundreg = 1
			ELSE
				EXIT DO
			END IF
		LOOP
		IF foundreg = 0 AND isalpha(LEFT$(param$(i), 1)) THEN
			memoryaccess = 1
		END IF
		

		' do number prefix offset
		DO
			index = INSTR(param$(i), "$")
			IF (index > 0) AND isdigit(MID$(param$(i), index + 1, 1)) THEN
				CALL DelSubString(param$(i), index, 1)
			ELSE
				EXIT DO
			END IF
		LOOP
		IF param$(i) = "$" THEN param$(i) = ""


		' do hexadecimal translation
		DO
			index = INSTR(LCASE$(param$(i)), "0x")
			IF (index > 0) AND isxdigit(MID$(param$(i), index + 2, 1)) THEN
				FOR j = index + 2 TO LEN(param$(i))
					IF NOT isxdigit(MID$(param$(i), j, 1)) THEN j = j - 1: EXIT FOR
				NEXT j
				param$(i) = LEFT$(param$(i), j) + "h " + MID$(param$(i), j + 1)
				param$(i) = LEFT$(param$(i), index - 1) + "0" + MID$(param$(i), index + 2)

				' chop leading zeros
				DO
					IF MID$(param$(i), index, 1) = "0" AND isdigit(MID$(param$(i), index + 1, 1)) THEN
						CALL DelSubString(param$(i), index, 1)
					ELSE
						EXIT DO
					END IF
				LOOP
			ELSE
				EXIT DO
			END IF
		LOOP


		' append to our list
		param$(i) = LTRIM$(RTRIM$(param$(i)))
		IF LEN(param$(i)) THEN
			IF gotfirst THEN total$ = total$ + "+"
			total$ = total$ + param$(i)
			gotfirst = 1
		END IF
	NEXT i
	x = Simplify(total$)
	IF memoryaccess THEN total$ = "[" + total$ + "]"

	separateparam$ = LTRIM$(RTRIM$(total$))
END FUNCTION

FUNCTION Simplify (source$)
	' simplifies a text/numeric expression with parentheses
	' returns true if the simplfication was successful
	text$ = source$

	' recursively simplify embedded parentheses expressions
	DO WHILE INSTR(text$, ")") > 0
		'find the first innermost pair of parentheses
		index1 = 0: index2 = INSTR(text$, ")")
		FOR i = index2 TO 1 STEP -1
			IF MID$(text$, i, 1) = "(" THEN index1 = i: EXIT FOR
		NEXT i
		IF index1 = 0 THEN
			PRINT "Mismatched parentheses detected."
			Simplify = 0
			EXIT FUNCTION
		END IF

		'cut out the parentheses expression
		leftpart$ = LEFT$(text$, index1 - 1)
		bodypart$ = MID$(text$, index1 + 1, index2 - index1 - 1)
		rightpart$ = MID$(text$, index2 + 1)

		'simplify it and replace in the new value
		body$ = bodypart$
		IF SimplifyInner(body$) THEN
			text$ = leftpart$ + body$ + rightpart$
		ELSE
			PRINT "Error simplifying paren-expression <"; bodypart$; ">"
			Simplify = 0
			EXIT FUNCTION
		END IF
	LOOP

	' final pass over expression
	IF SimplifyInner(text$) THEN
		source$ = text$: Simplify = 1
	ELSE
		Simplify = 0
	END IF
END FUNCTION

FUNCTION SimplifyInner (source$)
	' simplifies a text/numeric expression without parentheses
	' returns true if the simplification was successful
	text$ = LTRIM$(RTRIM$(source$))

	' split remaining expression
	DIM SumList$(1 TO 20)
	CurrentSum = 1
	FOR i = 1 TO LEN(text$)
		a$ = MID$(text$, i, 1)
		IF a$ = "+" THEN
			IF LEN(SumList$(CurrentSum)) AND SumList$(CurrentSum) <> "-" THEN
				CurrentSum = CurrentSum + 1
			END IF
		ELSEIF a$ = "-" THEN
			IF LEN(SumList$(CurrentSum)) THEN
				IF SumList$(CurrentSum) = "-" THEN
					SumList$(CurrentSum) = ""
				ELSE
					CurrentSum = CurrentSum + 1
					SumList$(CurrentSum) = "-"
				END IF
			ELSE
				SumList$(CurrentSum) = "-"
			END IF
		ELSE
			SumList$(CurrentSum) = SumList$(CurrentSum) + a$
		END IF
	NEXT i

	' simplify out higher-priority math
	DIM IsNumeric(1 TO 20)
	FOR i = 1 TO CurrentSum
		IsNumeric(i) = SimplifyValue(SumList$(i))
	NEXT i

	' move all of the numeric expressions forward
	FOR i = 1 TO CurrentSum
		FOR j = i + 1 TO CurrentSum
			IF NOT IsNumeric(i) AND IsNumeric(j) THEN
				SWAP IsNumeric(i), IsNumeric(j)
				SWAP SumList$(i), SumList$(j)
			END IF
		NEXT j
	NEXT i


	' combine adjascent numeric expressions
	FOR i = 1 TO CurrentSum - 1
		IF IsNumeric(i) AND IsNumeric(i + 1) THEN
			SumList$(i + 1) = STR$(BigSum(VAL(SumList$(i)), VAL(SumList$(i + 1))))
			SumList$(i) = ""
		END IF
	NEXT i

	' put everything together and return a single string
	text$ = ""
	FOR i = 1 TO CurrentSum
		IF LEN(SumList$(i)) THEN
			IF LEFT$(SumList$(i), 1) = "-" THEN
				text$ = text$ + SumList$(i)
			ELSE
				IF LEN(text$) THEN
					text$ = text$ + "+" + SumList$(i)
				ELSE
					text$ = SumList$(i)
				END IF
			END IF
		END IF
	NEXT i
	source$ = text$
	SimplifyInner = 1
END FUNCTION

FUNCTION SimplifyValue (intext$)
	' returns true if the value was numerical and was simplified successfully
	intext$ = LTRIM$(RTRIM$(intext$))
	text$ = intext$
	Number$ = "": IsHex = 0
	IF LEFT$(text$, 1) = "-" THEN
		Number$ = "-"
		text$ = MID$(text$, 2)
	END IF
	FOR j = 1 TO LEN(text$)
		a$ = MID$(text$, j, 1)
		IF isxdigit(a$) THEN
			Number$ = Number$ + a$
		ELSEIF LCASE$(a$) = "h" AND LEN(Number$) THEN
			IsHex = 1
			text$ = MID$(text$, j + 1)
			EXIT FOR
		ELSE
			text$ = MID$(text$, j)
			EXIT FOR
		END IF
	NEXT j
	IF Number$ = text$ THEN text$ = ""
   
	IF LEN(Number$) THEN
		IF IsHex THEN
			value& = VAL("&H" + Number$)
		ELSE
			value& = VAL(Number$)
		END IF
	ELSE
		SimplifyValue = 0
		EXIT FUNCTION
	END IF

	text$ = LTRIM$(text$)
	IF text$ = "" THEN
		'nothing, perfect conversion
	ELSEIF LEFT$(text$, 1) = "*" THEN
		text$ = MID$(text$, 2)
		IF SimplifyValue(text$) THEN
			value& = BigMultiply(value&, VAL(text$))
		ELSE
			SimplifyValue = 0
			EXIT FUNCTION
		END IF
	ELSEIF LEFT$(text$, 1) = "/" THEN
		text$ = MID$(text$, 2)
		IF SimplifyValue(text$) THEN
			value& = value& \ VAL(text$)
		ELSE
			SimplifyValue = 0
			EXIT FUNCTION
		END IF
	ELSEIF LEFT$(text$, 2) = "<<" THEN
		text$ = MID$(text$, 3)
		IF SimplifyValue(text$) THEN
			value& = BigMultiply(value&, 2 ^ VAL(text$))
		ELSE
			SimplifyValue = 0
			EXIT FUNCTION
		END IF
	ELSEIF LEFT$(text$, 2) = ">>" THEN
		text$ = MID$(text$, 3)
		IF SimplifyValue(text$) THEN
			value& = value& \ (2 ^ VAL(text$))
		ELSE
			SimplifyValue = 0
			EXIT FUNCTION
		END IF
	ELSEIF LEFT$(text$, 1) = "|" THEN
		text$ = MID$(text$, 2)
		IF SimplifyValue(text$) THEN
			value& = value& OR VAL(text$)
		ELSE
			SimplifyValue = 0
			EXIT FUNCTION
		END IF
	ELSEIF LEFT$(text$, 1) = "&" THEN
		text$ = MID$(text$, 2)
		IF SimplifyValue(text$) THEN
			value& = value& AND VAL(text$)
		ELSE
			SimplifyValue = 0
			EXIT FUNCTION
		END IF
	ELSE
		SimplifyValue = 0
		EXIT FUNCTION
	END IF

	intext$ = STR$(value&)
	SimplifyValue = 1
END FUNCTION

FUNCTION tabtospace$ (line$)
	temp$ = line$
	DO
		index = INSTR(temp$, CHR$(9))
		IF index > 0 THEN
			MID$(temp$, index, 1) = SPACE$(4)
		ELSE
			EXIT DO
		END IF
	LOOP
	tabtospace$ = temp$
END FUNCTION

