# MASM-to-osimplay translat0r in Bash     Rick Hohensee aug 2003

# dwibblers

chom 		() {	#	util to chom(chomp) = chom
	echo -n ${1:0:${#1}-1}
}


ec 		() {	# 	util  shorthand for echo -n
	echo -n "$1"
}


# subordinates


syncode 	() {	#	subordinate to a full pass like swapargs
		# make array of syntax codes of the tokens
set -f		# This and the following run under other command-type routines
		# that are file-wise. These are line-wise.
unset sc 			# (binary) syntax code
ttn=0
wascomment=
	    for tt in $*				; do
		if test $ttn -eq 0   ; then
			sc[ttn]="O"
			bsc[ttn]="N"
			if test "$tt" = "#" ; then wascomment=yes ; fi
		else
			if test "$wascomment" 	; then
				sc[ttn]="#"
			else
 		           case $tt in
			#/
A|B|C|D|SP|BP|DI|SI|AX|BX|CX|DX|AL|BL|CL|DL|AH|BH|CH|DH|DS|ES|FS|GS)
				sc[ttn]="R"			;;
			",")	sc[ttn]=","			;;
		"*2^"|not|carry|sign|parity|overflow|C-1|dual|quad|byte)
				sc[ttn]="qual"			;;
			"#")	wascomment=yes
				sc[ttn]="#"			;;
			"@")	sc[ttn]="@"			;;
			"*")	sc[ttn]="*"			;;
			"{")	sc[ttn]="{"			;;
			"}")	sc[ttn]="}"			;;
			"?")	sc[ttn]="T"			;;
			")")	sc[ttn]=")"			;;
			"(")	sc[ttn]="("			;;
			"-")	sc[ttn]="-"			;;
			"+")	sc[ttn]="+"			;;
			 / | "|" | "&" | "^")
				sc[ttn]="2"			;;
			*)
				sc[ttn]="?"			;;
		    esac
			fi
		fi
		ttn=$((ttn+1))
		sc[ttn]="EOL"
	   done
}




bisyncode 	() {	#	make array of binary syntax codes of the tokens
ttn=0
unset bsc
wascomment=
	    for tt in $*				; do
		if test $ttn -eq 0   ; then
			bsc[ttn]="N"
			if test "$tt" = "#" ; then wascomment=yes ; fi
		else
			if test "$wascomment" 	; then
				bsc[ttn]="N"
			else
 		           case $tt in
			#/
A|B|C|D|SP|BP|DI|SI|AX|BX|CX|DX|AL|BL|CL|DL|AH|BH|CH|DH|DS|ES|FS|GS)
				bsc[ttn]="N"			;;
		"*2^"|not|carry|sign|parity|overflow|C-1|dual|quad|byte)
				bsc[ttn]="N"			;;
			",")	bsc[ttn]="N"			;;
			"?")	bsc[ttn]="N"			;;
			"#")	wascomment=yes
				bsc[ttn]="N"			;;
			"*")	bsc[ttn]="Y"			;;
			")")	bsc[ttn]="Y"			;;
			"@")	bsc[ttn]="N"			;;
			"{")	bsc[ttn]="N"			;;
			"}")	bsc[ttn]="N"			;;
			"(")	bsc[ttn]="Y"			;;
			"+"|"-")	bsc[ttn]="Y"
			if test "${bsc[ttn-1]}"  = "N"   ; then
					bsc[ttn]="Y"	; fi	;;
			"/" | "|" | "&" | "^") bsc[ttn]="Y"     ;;
			*)
				bsc[ttn]="Y"			;;
		    esac
			fi
		fi
		ttn=$((ttn+1))
		bsc[ttn]="N"
	   done
}


# filewise passes


lex 		() {	# first pass; bust out meaningful single chars
local line cc tc
while read -r line ;  do
	cc=0
	tc=
	while true ; do
		tc=${line:$cc:1}
		if test "$tc" ; then
		      case $tc in
			",")	ec  " , " 			;;
			";")	ec  " # "		 	;;
			"[")	ec  " @ "			;;
			")")	ec  " ) "			;;
			"(")	ec  " ( "			;;
			"]")	ec  "   "			;;
			"*")	ec  " * "			;;
			"+")	ec  " + "			;;
			"-")	ec  " - "			;;
			"'")	ec  " ? "			;;
			"/")	ec  " / "			;;
			"$")	echo -ne " \$H "		;;
			" ")    ec "  "			;;
			*)	ec $tc			;;
		      esac
		else break
		fi
		let cc=$cc+1
	done
echo
done
}




t0 		() {	# resolve second-token and 2-token keys to first-token
			# presumes use32
set -f
	while read -a t	   				; do
		if test "${t[0]}" != ";" ; then
			case ${t[1]} in
			   "dd" | "dw" | "db" )
				if test ${t[0]} != "#"    ; then
					echo "L  ${t[0]}"
					t[0]=
					echo ${t[*]}" "
				else	 echo ${t[*]}" "
				fi				;;
			   equ)
				echo -n " ${t[0]}= "
				t[0]= t[1]=
				echo	" ${t[*]} "		;;
			   MACRO)
				ec ${t[0]}"	( ) { # MACRO       _  "
		    		if test $((${#t[*]}-2)) -gt 0	; then
					echo "# ######HAND-CONVERT ARGUMENTS   "
					echo "# ## ${t[2]}=\$1 ... "	
				else
					echo 
		    		fi
		 		;;	
			   movsd)
				if test ${t[0]} = "rep" ; then 
					ec "copies "		
				else 
					ec "copy "
				fi
				;;
			   movsb)
				if test ${t[0]} = "rep" ; then 
					ec "copies bytes "
				else 
					ec "copy byte "
				fi
				;;
			   movsw)
				if test ${t[0]} = "rep" ; then 
					ec "otheroperandsize ; copies "
				else
					ec "otheroperandsize ; copy "
				fi
				;;
			   stosw)
				if test ${t[0]} = "rep" ; then 
					ec "otheroperandsize ; fill "
				else
				 ec "ab 0xab  # ### FILL ONE CELL?"
				fi
				;;
			   stosb)
				if test ${t[0]} = "rep" ; then 
					ec "fill bytewise "
				else 
				 ec "ab 0xaa # ### FILL ONE BYTE?"
				fi
				;;
			   stosd)
				if test ${t[0]} = "rep" ; then 
					ec "fill "
				else
				 ec "ab 0xab # ### FILL ONE CELL?"
				fi
				;;
			   scasd)
				if test ${t[0]} = "rep" ; then 
					ec "scan cells "
				else
				  ec "ab 0xaf # ### SCAN ONE CELL?"
				fi
				;;
			   scasw)
				if test ${t[0]} = "rep" ; then 
					ec "otheroperandsize ; scan cells "
				else
					ec "ab 0xaf # ### SCAN ONE CELL?"	
				fi
				;;
			   scasb)
				if test ${t[0]} = "rep" ; then 
					ec "scan "
				else
					ec "ab 0xae  # ###scan one byte? "
				fi
				;;
			   lodsb)
				if test ${t[0]} = "rep" ; then 
					ec "fetches bytes "
				else
					ec "ab 0xac  # ###fetch one byte? "
				fi
				;;
			   lodsd)
				if test ${t[0]} = "rep" ; then 
					ec "fetches "
				else
					ec "ab 0xad  # ###fetch one byte? "
				fi
				;;
			   *)
				echo ${t[*]}" "			;;
			esac
		fi
	done
}



zeroize		() {	# convert xor reg , samereg   to   zero reg
set -f
        while read -a t                                 ; do
            case ${t[0]} in
		xor)
			if test "${t[1]}" = "${t[3]}" ; then
				echo "zero ${t[1]}"
			fi
		 ;;
		*)
			echo ${t[*]}
		 ;;
	    esac
	done
}



unshl		() {	# Bash-ify the shl's that aren't t[0]
set -f
        while read -a t                                 ; do
		tn=0
		for i in ${t[*]} 		; do
			case $i in
			    shl)
				if test $tn -ne 0 ; then
				   t[tn]="<<"
				else
				   t[tn]="upshift"
				fi
				;;
			    shr)
				if test $tn -ne 0 ; then
				   t[tn]=">>"
				else
				   t[tn]="downshift"
				fi
				;;
			esac
			let tn=tn+1
		done
	echo ${t[*]}
	done
}




asmacs 		() {	# asmacs begat shasm begat osimplay begat unmasm
			# Handy with <your assembler here>
			# hmmmm, why did I used to need m4 for this?
whichnll=0
set -f
	while read -a t	   				; do
	wascomment=
		for each in ${t[*]}			; do
		if test "$wascomment" ; then
			ec "$each "
		else
			case $each in
				"#")	ec "		  # "
					wascomment=yes		;;
				"*")    echo  -ne "* " 		;;
				"@")    ec " @ "		;;
				0*|1*|2*|3*|4*|5*|6*|7*|8*|9*)
				    case $each in
					*h) ec 0x;  chom $each
						ec " " 		;;
					*o)
						  ec "0"
						chom $each
						ec " "  	;;
					*)  ec "$each "		;;
				    esac
								;;
				@@:)	let whichnll=$whichnll+1
					ec "  L " ;
					cll=$whichnll
					echo l__$cll		;;
				*:)	ec "L " ; chom $each
					echo	;;
				EAX)	ec "A "			;;
				EBX)	ec "B "			;;
				ECX)	ec "C "			;;
				EDX)	ec "D "			;;
				EBP)	ec "BP "		;;
				ESP)	ec "SP "		;;
				ESI)	ec "SI "		;;
				EDI)	ec "DI "		;;
		mov)	ec " = "			;;
		cmp)	ec " -test "			;;
		add)	ec " + "			;;
		xor)	ec " XOR "			;;
		and)	ec " AND "			;;
		or)	ec " OR "			;;
		sub)	ec " - "			;;
		int)	ec " submit "			;;
		cli)	ec " IRQsoff "			;;
		sti)	ec " IRQson "			;;
		cld)	ec " increasing "		;;
		std)	ec " decreasing "		;;
		div)	ec " / "			;;
		imul)	ec " signedmultiply "		;;
		neg)	ec " negate "			;;
		rol)	ec " uproll "			;;
		sar)	ec " signeddownshift "		;;
		lodsd)  ec " ab 0xad # ###  lodsd "	;;
		stosd)  ec " ab 0xab # ###  stosd "	;;
		xchg)	ec " swap "			;;
		inc)	ec " 1+ "			;;
		dec)	ec " 1- "			;;
		ret)	echo "	return "		;;
		test)   ec " ANDtest "			;;
		jz)	ec " when   zero	"	;;
		jnz)	ec " when   not zero	" 	;;
		js)	ec " when   sign	"	;;
		jns)	ec " when   not sign	"	;;
		jc)	ec " when   carry	"	;;
		jnc)	ec " when   not carry   "	;;
		jmp)	ec " jump "			;;
		call)	ec " call "			;;
		pop)	ec " pull "			;;
		push)	ec " push "			;;
		lea)	ec " address "			;;
		in)	ec "	recieve "		;;
		out)	ec "	send "			;;
		iret)	ec " dismiss "			;;

			ALIGN)  ec " align " 		;;
			ptr)	ec " "			;;
			dword)	ec  " quad "		;;
			word)	ec  " dual "		;;
			offset)	ec " "			;;
			include)	ec " . "	;;
			ENDM)	ec " } "		;;
			@b)	ec " l__$cll "		;;
			@f)	ec " l__$((cll+1)) "	;;
			org)	ec " H= "		;;
			dd)	ec " aq "		;;
			dw)	ec " ad "		;;
			db)	ec " ab "		;;
			       *)	ec "$each "	;;
	    		esac
		fi
	  	done
	echo
	done
}




memshift 	() {	# catch the REG *2^'s before umnuming
set -f
unset t
while read -a t                                 ; do
    os2=
    syncode ${t[*]}
    case ${t[0]} in
      "#"|L|IRQson|IRQsoff|halt|dismiss|H=|ab|ad|aq)
		echo ${t[*]}
			;;
      *)
	addy=					# is there a @?
	for i in ${t[*]}	; do
		if test $i = "@"	; then
			addy=yes
		fi
	done
	if test "$addy"		; then
	    mn=0
            for pp in ${t[*]}                                     ; do
		case ${sc[mn]}${sc[mn+1]}${sc[mn+2]} in
		    "R*?")
			t[mn+1]=" *2^ "
			sc[mn+1]="R"
			sc[mn+2]="R"
			bsc[mn+1]="N"
			bsc[mn+2]="N"
		        case ${t[mn+2]} in
				2) t[mn+2]=" 1 "	
				 ;;
				4) t[mn+2]=" 2 "	
				 ;;
				8) t[mn+2]=" 3 "	
				 ;;
			esac
					;;
		esac
	        let mn=$mn+1
	    done		  # token
	fi
	echo ${t[*]}
    esac			 # line
done				# file
}



RPNify		() {	# Reverse Polish data declaration doodad
			# somewhat Chuck-Moore-specific
set -f
 while read -a t					; do
    hadparen=
    case "${t[0]}" in
	aq|ad)
		ni=0	unset np
	  	for i in ${t[*]}		; do	# np is no parens
			case $i in
				ad|aq)
				: ;;
				"("|")")
				hadparen=yes
				 ;;
				*)
					np[ni]=$i
					let ni=$ni+1
				;;
			esac
		done

		os="rpn	"	tn=0	incomment=
		if test "$hadparen" ; then 
	  	  for i in ${np[*]}				; do
		    if test $tn -eq 0			 ; then
			os=$os" "$i" "			
		    else
			if ! test "$incomment"		; then
			    case $i in
				"#")
				    incomment=yes
				    os=$os"  ,  "$i
				 ;;
				[0-9]*)		os=$os" "$i" "$op" "
				 ;;
				,)		os=$os" , "
				 ;;
				*)		op=$i
			      ;;
			    esac
			else
				os=$os" "$i
			fi
		    fi
		   let tn=$tn+1
		  done
 		  echo $os
		else
		  echo "${t[*]}"
		fi
	 ;;
	*)
		echo "${t[*]}"
	 ;;
    esac
done
}


numnum 		() {	# enclose compound numerics ala $(( bla ))
			# YYN is end_compound, NYY is begin_compound
set -f
while read -a t								; do
    bisyncode ${t[*]}
    syncode ${t[*]}
    case "${t[0]}" in
	"#"|rpn|when|L|IRQson|IRQsoff|halt|dismiss|H=)	# bail early
		echo ${t[*]}
	 ;;
	*)
	ostring=
	tn=0
	ended=	started=
	for Q in ${t[*]}					; do
	    case "${sc[tn]}${sc[tn+1]}${sc[tn+2]}" in
		*"()")
		bsc[tn+1]=N	bsc[tn+1]=N
		 echo ${t[*]}
		 continue 2
		 ;;
		+R)				# lose a +- by an R
		:
		 ;;
		R+)				# lose a +- by an R
		t[tn+1]=" "
		bsc[tn+1]=N
		ostring=$ostring" "${t[tn]}
		 ;;
		*)
		    case "${bsc[tn]}${bsc[tn+1]}${bsc[tn+2]}" 		in
			NYY)	ostring=$ostring" "${t[tn]}" \$(("
				started=yes
				ended=
					;;
			YYN)	ostring=$ostring" ${t[tn]} "
				ended=yes
					;;
			YN*)	if  test "$ended" ; then
					if ! test "${t[tn]}" = "+" ; then
					  ostring=$ostring" "${t[tn]}" )) "
					  ended=
					else
					  ostring=$ostring")) "
					  ended=
					fi
				else
					ostring=$ostring" ${t[tn]} "
				fi
					;;
			*)	ostring=$ostring" ${t[tn]} "
					;;
		    esac
			;;
	    esac
	      let tn=$tn+1
	done
	echo $ostring
    esac
done
}



snugnum		() { # compress or undo compounding of numerics
set -f
unset t
        while read -a t						; do
	innum=	os=	snum=0	ms=	ls=	st=0
	    for i in ${t[*]}				; do
		case $i in 
		    "\$((")
			innum=yes
			let snum=$st
			ms="\$(("
		    	ls=
		       ;;
		    "))")		# resolve mash/lose choice 
			if test $(($st-$snum)) -lt 4	; then
#			echo $(($st-$snum))
			    os=$os" "$ls
			else
			    os=$os" "$ms$i
			 fi
			ms=	ls=
		      ;;
		    *)	
			if test "$innum"	; then
			    ms=$ms$i
			    ls=$ls" "$i  
			else
		 	    os=$os" "$i
			fi
		       ;;
		esac
		let st=$st+1
	    done
	    echo $os
	done
}




equsnug 	() {	# pull the numeric snug to the =
set -f
unset t
        while read -a t                                 ; do
		case ${t[0]} in
			*?=)
			# Borscht.
				t[0]=${t[0]}${t[1]}${t[2]}${t[3]}
				t[1]= t[2]= t[3]= 			;;
			*)		:				;;
		esac
		echo ${t[*]}
	done
}


						# Got milk?

decomma 	() {	# elide commas from data lines
set -f
unset t
while read -a t                                 ; do
    case ${t[0]} in
	ab|ad|aq)
		lt=0
	wascomment=
	for tt in ${t[*]}					; do
		if test "$tt" = "#" ; then wascomment=yes
		fi
		if test "$wascomment" != "yes" ; then
			if test "$tt" != ","	; then
				echo -n " $tt "
			fi
		else
			echo -n " $tt "
		fi
	done
	echo							;;
    *)
        echo ${t[*]}						;;
    esac
done
}



# first tokens should be sufficient syntax keys before syntax( ) happens
# gonna hafta track cell to automate dual|quad|otheroperandsize

					# BLINK, Rick. Gooboy Rick.


swapargs 	() {	# source/dest swap
set -f
unset t
        while read -a t                                 ; do

case ${t[0]} in
 "#"|ab|rpn)
  echo ${t[*]}
 ;;
*)
		dualie=
		syncode ${t[*]}
		lt=0
		for i in ${t[*]}		; do
			case ${sc[lt]} in
				",")
				dualie=yes	;;
			esac
		       let lt=$lt+1
		done

		left=	right=	opc=${t[0]}	tail=	started=
		mode=lefting
	      if test "$dualie"					   ; then
		for i in ${t[*]}                		; do
		    if test "$started" ; then
		    	if test "$i" = "," ; then mode=righting	; fi
		    	if test "$i" = "#" ; then mode=tailing 	; fi
		    	case $mode$i in
				"righting,")
				    :				;;
				righting*)
				    right=$right" "$i" "	;;
				tailing*)
				    tail=$tail" "$i" "		;;
				*)
				    left=$left" "$i" "		;;
		    	esac
		    else	started=yes
			fi
		done
		echo $opc" "$right" "to" "$left" "$tail
	      else
		echo ${t[*]}
	      fi
 ;;
esac
	done
}




cell2ify 	() {	#	use16 side of cellify
		lt=0
		OOS=
		for i in ${t[*]}			; do
			case $i in
				dual)
					t[lt]=" "	;;
				quad)
					OOS=yes
					t[lt]=" "	;;
			esac
			let lt=$lt+1
		done
		if test "$OOS"	; then
			echo -n "otheroperandsize ;	"
		fi
		echo ${t[*]}
}




cell4ify 	() {	# 	use32 side of cellify
		lt=0
		OOS=
		for i in ${t[*]}			; do
			case $i in
				quad)
					t[lt]=" "	;;
				dual)
					OOS=yes
					t[lt]=" "	;;
			esac
			let lt=$lt+1
		done
		if test "$OOS"	; then
			echo -n "otheroperandsize ;	"
		fi
		echo ${t[*]}
}




cellify 	() {	# otheroperandsize things osimplay-style
CELL=FOUR
set -f
unset t
        while read -a t                                         ; do
	    for i in ${t[*]}                        ; do
		case $i in
		    "cell="?)
			if test $i = "cell=2"	; then CELL=TWO  ; fi
			if test $i = "cell=4"	; then CELL=FOUR ; fi
					;;
		     *)
			:		;;
		esac
	    done

	    if test $CELL = FOUR ; then
		cell4ify
	    else
		cell2ify
	    fi
	done
}




ascii 		() {	# make asciis out of   db ' bla'  LOSES SPACES
set -f
unset t
        while read -a t                                 ; do
		ticks=
		lt=0
		for i in ${t[*]}		; do
			intext=
			case $i in
			    "?")
				ticks=yes
				t[0]=" ascii "
				if test "$intext" ; then
					t[lt]=" \" "
					intext=
				else
					t[lt]=" \" "
					intext=yes
				fi
			 		;;
			    "#")
				if ! test "$intext" ; then
				break 	; fi	;;
			    *)
				:		;;
			esac
			let lt=$lt+1
		done
		echo ${t[*]}
	done
}


spacey	 	() {	# indent, spread comments
set -f
unset t
while read -a t							; do
	ti=0
	for i in ${t[*]}				; do
	    case $i in
		"#")		ec "		# "
		 ;;
		L|*?=*) 		ec $i" "
		 ;;
		return|dismiss)
			ec "			"$i
		 ;;
		"*n*zero"|sign|carry)
			ec " "$i"		"
		 ;;
		when)
			ec "	 when "
		 ;;
		call)
			ec "	  call "
		 ;;
		*)	if test $ti -eq 0	; then
				ec "	"$i
			else
				ec " "$i
			fi
		 ;;
	    esac
	   let ti=$ti+1
	done
	    echo
done
}


unmasm 		() {	# cat toebone | footbone | anklebone | shinbone

echo "# UNMASM" > blarf
ec "# " >> blarf
pwd >> blarf
ec "# " >> blarf
echo $1 >> blarf
ec "# " >> blarf
date >> blarf
echo >> blarf

cat blarf $1 | lex | t0 | zeroize| asmacs | unshl | RPNify |   \
memshift | numnum  |equsnug | decomma  |		\
swapargs | cellify | ascii | spacey

# no snugnum, which drops stuff

rm blarf
}

				# mouse pasties
# grep "()" unmasm
# . unmasm
# unmasm DEMO
# cat unmasm

