From: Doni Pracner Date: Fri, 19 Jul 2019 15:59:24 +0000 (+0200) Subject: version 0.81 X-Git-Tag: v0.81^0 X-Git-Url: https://svarog.pmf.uns.ac.rs/gitweb/?a=commitdiff_plain;h=refs%2Fheads%2Fmaster;p=asm2wsl.git version 0.81 --- diff --git a/build.xml b/build.xml new file mode 100644 index 0000000..17e3f7d --- /dev/null +++ b/build.xml @@ -0,0 +1,291 @@ + + + Builder script for asm2wsl and related tools + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Used options:${asm2wsl.options} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/compare-w-wt.pl b/lib/compare-w-wt.pl new file mode 100644 index 0000000..11d4714 --- /dev/null +++ b/lib/compare-w-wt.pl @@ -0,0 +1,44 @@ +#!/usr/bin/perl +# +# test if the outputs are the same from two versions of +# WSL programs - the original and the transformation + +sub read_file($) { + my ($file) = @_; + my $in; + open($in, $file) or die "Cannot read $file: $!\n"; + my $data = join("", <$in>); + close($in); + return($data); +} + +# quit unless we have the correct number of command-line args +$num_args = $#ARGV + 1; +if ($num_args != 2) { + print "\nUsage: compare-w-wt.pl directory base_filename \n"; + exit; +} + +$dir=@ARGV[0]; +$base=@ARGV[1]; + +$outw = read_file("$dir/$base.outwsl"); +$outwt = read_file("$dir/$base.outwslt"); + +#print "inputs:\n"; +#print "$outm\n--\n$outw\n\n"; + +#process the WSL output to remove comments +for ($outw, $outwt) { + s/^.*Starting Execution...//s; + s/^.*?\n.*?\n//s; + s/Execution time:.*//s; +} + +if ($outw eq $outwt) { + print "$base - OK\n"; +} else { + print "$base - difference detected!:\n"; + print "$outw###\n--\n$outwt###\n"; + die(); +} \ No newline at end of file diff --git a/samples-with-macros/array-sum-input.asm b/samples-with-macros/array-sum-input.asm new file mode 100644 index 0000000..57d3883 --- /dev/null +++ b/samples-with-macros/array-sum-input.asm @@ -0,0 +1,194 @@ +.model small +;make a sum of an array - version with loading values +;predefined array size + +;#macro-commands-start +end_execution macro +; finish the execution + mov ax, 4c02h + int 21h +endm + +print_str macro s +; print a s string on screen + push ax + push dx + mov dx, offset s + mov ah, 09 + int 21h + pop dx + pop ax +endm + +inttostr macro num1 str1 +; convert num1 to str1 + push ax + push bx + push cx + push dx + push si + mov ax, num1 + mov dl, '$' + push dx + mov si, 10 +itosloop: + mov dx, 0 + div si + add dx, 48 + push dx + cmp ax, 0 + jne itosloop + + mov bx, offset str1 +itosloopa: + pop dx + mov [bx], dl + inc bx + cmp dl, '$' + jne itosloopa + pop si + pop dx + pop cx + pop bx + pop ax +endm + +print_num macro num + ;convert num, print str + inttostr num,tempStr + print_str tempStr +endm + +; new line +print_new_line macro + push ax + push bx + push dx + mov ah,03 + mov bh,0 + int 10h + inc dh + mov dl,0 + mov ah,02 + int 10h + pop dx + pop bx + pop ax +endm + +read_num macro num + read_str tempStr,6 + strtoint tempStr,num +endm + +;read into a buffer, inc the special 0 and 1 bytes +;fixes it into a $ terminated string +read_str macro strbuff, strlen + LOCAL copystr + push ax + push bx + push cx + push dx + push si + mov bp, sp + mov dx, offset strbuff + mov bx, dx + mov ax, strlen + mov byte [bx] ,al + mov ah, 0Ah + int 21h + mov si, dx + mov cl, [si+1] + mov ch, 0 +copystr: + mov al, [si+2] + mov [si], al + inc si + loop copystr + mov [si], '$' + pop si + pop dx + pop cx + pop bx + pop ax +endm + +;ascii to actual number +strtoint macro inStr,outNum + LOCAL mainloop,end + push ax + push bx + push cx + push dx + push si + mov bp, sp + mov bx, offset inStr + mov ax, 0 + mov cx, 0 + mov si, 10 +mainloop: + mov cl, [bx] + cmp cl, '$' + je end + mul si + sub cx, 48 + add ax, cx + inc bx + jmp mainloop +end: + mov outNum, ax + pop si + pop dx + pop cx + pop bx + pop ax +endm +;#macro-commands-end + +.code +start: + mov dx, @data + mov ds, dx + print_str prompt + read_num n + mov ax, 0 + mov cx, n + cmp maxn, cx + jae normal + print_str errorN + end_execution +normal: +loadloop: + print_str prompt + read_num t + mov ax,t + mov bx,n + sub bx,cx + mov niz[bx],al + loop loadloop + print_new_line + ; now sum up + mov cx, n + xor ax,ax +mainloop: + mov bx, cx + add al, niz[bx-1] ; get array memeber, byte + ; store sum in al + loop mainloop ; end calc if done + print_num ax + end_execution + +data segment +n dw 7 +t dw 0 +maxn dw 20 +niz db 1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0 +tempStr db " " +prompt db "Number?$" +errorN db "Number too large!$" +ends +end start + + + + diff --git a/samples-with-macros/array-sum-predef.asm b/samples-with-macros/array-sum-predef.asm new file mode 100644 index 0000000..884a337 --- /dev/null +++ b/samples-with-macros/array-sum-predef.asm @@ -0,0 +1,83 @@ +.model small +;make a sum of an array - version with predefined everything + +;#macro-commands-start +end_execution macro +; finish the execution + mov ax, 4c02h + int 21h +endm + +print_str macro s +; print a s string on screen + push ax + push dx + mov dx, offset s + mov ah, 09 + int 21h + pop dx + pop ax +endm + +inttostr macro num1 str1 +; convert num1 to str1 + push ax + push bx + push cx + push dx + push si + mov ax, num1 + mov dl, '$' + push dx + mov si, 10 +itosloop: + mov dx, 0 + div si + add dx, 48 + push dx + cmp ax, 0 + jne itosloop + + mov bx, offset str1 +itosloopa: + pop dx + mov [bx], dl + inc bx + cmp dl, '$' + jne itosloopa + pop si + pop dx + pop cx + pop bx + pop ax +endm + +print_num macro num + ;convert num, print str + inttostr num,tempStr + print_str tempStr +endm +;#macro-commands-end + +.code +start: + mov dx, @data + mov ds, dx + mov cx, n + mov ax, 0 + mov dx, 0 +mainloop: + mov bx, cx + add al, niz[bx-1] ; get array memeber, byte + ; store sum in al + loop mainloop ; end calc if done + print_num ax + end_execution + +data segment +n dw 7 +niz db 1,2,3,4,5,6,7,0 +tempStr db " " + +ends +end start diff --git a/samples-with-macros/gcd-input.asm b/samples-with-macros/gcd-input.asm new file mode 100644 index 0000000..71e13b1 --- /dev/null +++ b/samples-with-macros/gcd-input.asm @@ -0,0 +1,198 @@ +.model small +;greatest common divisor, with input from terminal +data segment + tempStr db " " + prompt db "num?$" + promptr db "RES $" + m dw 0 + n dw 0 + +data ends +;#macro-commands-start +; print a string on screen +print_str macro s + push ax + push dx + mov dx, offset s + mov ah, 09 + int 21h + pop dx + pop ax +endm + +; new line +print_new_line macro + push ax + push bx + push dx + mov ah,03 + mov bh,0 + int 10h + inc dh + mov dl,0 + mov ah,02 + int 10h + pop dx + pop bx + pop ax +endm + +; write a single char +print_char macro c + push ax + push dx + mov ah, 02 + mov dl, c + int 21h + pop dx + pop ax +endm + +; finish the execution +end_execution macro + mov ax, 4c02h + int 21h +endm + +; Konvertovanje broja u string +inttostr macro num1 str1 + push ax + push bx + push cx + push dx + push si + mov ax, num1 + mov dl, '$' + push dx + mov si, 10 +petlja2: + mov dx, 0 + div si + add dx, 48 + push dx + cmp ax, 0 + jne petlja2 + + mov bx, offset str1 +petlja2a: + pop dx + mov [bx], dl + inc bx + cmp dl, '$' + jne petlja2a + pop si + pop dx + pop cx + pop bx + pop ax +endm + +print_num macro num + inttostr num,tempStr + print_str tempStr +endm +read_num macro num + read_str tempStr,6 + strtoint tempStr,num +endm + +;read into a buffer, inc the special 0 and 1 bytes +;fixes it into a $ terminated string +read_str macro strbuff, strlen + LOCAL copystr + push ax + push bx + push cx + push dx + push si + mov bp, sp + mov dx, offset strbuff + mov bx, dx + mov ax, strlen + mov byte [bx] ,al + mov ah, 0Ah + int 21h + mov si, dx + mov cl, [si+1] + mov ch, 0 +copystr: + mov al, [si+2] + mov [si], al + inc si + loop copystr + mov [si], '$' + pop si + pop dx + pop cx + pop bx + pop ax +endm + +;ascii to actual number +strtoint macro inStr,outNum + LOCAL mainloop,end + push ax + push bx + push cx + push dx + push si + mov bp, sp + mov bx, offset inStr + mov ax, 0 + mov cx, 0 + mov si, 10 +mainloop: + mov cl, [bx] + cmp cl, '$' + je end + mul si + sub cx, 48 + add ax, cx + inc bx + jmp mainloop +end: + mov outNum, ax + pop si + pop dx + pop cx + pop bx + pop ax +endm +;#macro-commands-end + +.code + +start: + mov ax,@data + mov ds,ax + print_str prompt + read_num m + print_new_line + print_str prompt + read_num n + print_new_line + + mov ax,n + mov bx,m + +compare: + cmp ax,bx + je exit ;exit since they're equal + ja greater + sub bx,ax + jmp compare + +greater: + sub ax,bx + jmp compare + +exit: +;exit out of the program + mov n,ax + print_str promptr + print_num n +; print out a result + end_execution + +.stack +end start diff --git a/samples-with-macros/gcd-predef.asm b/samples-with-macros/gcd-predef.asm new file mode 100644 index 0000000..f517316 --- /dev/null +++ b/samples-with-macros/gcd-predef.asm @@ -0,0 +1,98 @@ +.model small +data segment + strNZD db " " +data ends +;#macro-commands-start +; print a string on screen +print_str macro s + push ax + push dx + mov dx, offset s + mov ah, 09 + int 21h + pop dx + pop ax +endm + + +; write a single char +print_char macro c + push ax + push dx + mov ah, 02 + mov dl, c + int 21h + pop dx + pop ax +endm + +; finish the execution +end_execution macro + mov ax, 4c02h + int 21h +endm + +; Konvertovanje broja u string +inttostr macro num1 str1 + push ax + push bx + push cx + push dx + push si + mov ax, num1 + mov dl, '$' + push dx + mov si, 10 +petlja2: + mov dx, 0 + div si + add dx, 48 + push dx + cmp ax, 0 + jne petlja2 + + mov bx, offset str1 +petlja2a: + pop dx + mov [bx], dl + inc bx + cmp dl, '$' + jne petlja2a + pop si + pop dx + pop cx + pop bx + pop ax +endm + +print_num macro num + inttostr num,strNZD + print_str strNZD +endm +;#macro-commands-end + +.code + +start: + mov ax,12 + mov bx,8 + +compare: + cmp ax,bx + je exit ;exit since they're equal + ja greater + sub bx,ax + jmp compare + +greater: + sub ax,bx + jmp compare + +exit: +;exit out of the program + print_num ax +; print out a result + end_execution + +.stack +end start diff --git a/samples-with-macros/rek-gcd-input.asm b/samples-with-macros/rek-gcd-input.asm new file mode 100644 index 0000000..eb72549 --- /dev/null +++ b/samples-with-macros/rek-gcd-input.asm @@ -0,0 +1,222 @@ +.model small +ASSUME DS:data +;recursive version of GCD, input from terminal +data segment + strNZD db " " + tempStr db " " + prompt db "num?$" + promptr db "RES $" + m dw 0 + n dw 0 +data ends +;#macro-commands-start +; print a string on screen +print_str macro s + push ax + push dx + mov dx, offset s + mov ah, 09 + int 21h + pop dx + pop ax +endm + +; new line +print_new_line macro + push ax + push bx + push dx + mov ah,03 + mov bh,0 + int 10h + inc dh + mov dl,0 + mov ah,02 + int 10h + pop dx + pop bx + pop ax +endm + +; write a single char +print_char macro c + push ax + push dx + mov ah, 02 + mov dl, c + int 21h + pop dx + pop ax +endm + +; finish the execution +end_execution macro + mov ax, 4c02h + int 21h +endm + +; Konvertovanje broja u string +inttostr macro num1 str1 + push ax + push bx + push cx + push dx + push si + mov ax, num1 + mov dl, '$' + push dx + mov si, 10 +petlja2: + mov dx, 0 + div si + add dx, 48 + push dx + cmp ax, 0 + jne petlja2 + + mov bx, offset str1 +petlja2a: + pop dx + mov [bx], dl + inc bx + cmp dl, '$' + jne petlja2a + pop si + pop dx + pop cx + pop bx + pop ax +endm + +print_num macro num + inttostr num,strNZD + print_str strNZD +endm + +read_num macro num + read_str tempStr,6 + strtoint tempStr,num +endm + +;read into a buffer, inc the special 0 and 1 bytes +;fixes it into a $ terminated string +read_str macro strbuff, strlen + LOCAL copystr + push ax + push bx + push cx + push dx + push si + mov bp, sp + mov dx, offset strbuff + mov bx, dx + mov ax, strlen + mov byte [bx] ,al + mov ah, 0Ah + int 21h + mov si, dx + mov cl, [si+1] + mov ch, 0 +copystr: + mov al, [si+2] + mov [si], al + inc si + loop copystr + mov [si], '$' + pop si + pop dx + pop cx + pop bx + pop ax +endm + +;ascii to actual number +strtoint macro inStr,outNum + LOCAL mainloop,end + push ax + push bx + push cx + push dx + push si + mov bp, sp + mov bx, offset inStr + mov ax, 0 + mov cx, 0 + mov si, 10 +mainloop: + mov cl, [bx] + cmp cl, '$' + je end + mul si + sub cx, 48 + add ax, cx + inc bx + jmp mainloop +end: + mov outNum, ax + pop si + pop dx + pop cx + pop bx + pop ax +endm +;#macro-commands-end + +.code + +start: + mov ax,@data + mov ds,ax + print_str prompt + read_num m + print_new_line + print_str prompt + read_num n + print_new_line + + push n + push m + call gcd + pop n + print_str promptr + print_num n +; print out a result + end_execution + + +;volatile procedure, ruins ax,bx,cx +gcd proc + ;;#extra-start + pop cx ;ret adress + ;;#extra-end + ;get params + pop ax + pop bx + ;;#extra-start + push cx ;ret for later + ;;#extra-end + cmp ax,bx + je endequal + ja greatera + ;ensure ax is greater + xchg ax,bx +greatera: + sub ax,bx + push bx + push ax + call gcd + pop ax;result + +endequal: + ;;#extra-start + pop cx + ;;#extra-end + push ax; result + ;;#extra-start + push cx;needed before ret + ;;#extra-end + ret +gcd endp + +.stack +end start diff --git a/samples-with-macros/rek-gcd-predef.asm b/samples-with-macros/rek-gcd-predef.asm new file mode 100644 index 0000000..84c2eba --- /dev/null +++ b/samples-with-macros/rek-gcd-predef.asm @@ -0,0 +1,120 @@ +.model small +;recursive version of GCD, predefined input +data segment + strNZD db " " +data ends +;#macro-commands-start +; print a string on screen +print_str macro s + push ax + push dx + mov dx, offset s + mov ah, 09 + int 21h + pop dx + pop ax +endm + + +; write a single char +print_char macro c + push ax + push dx + mov ah, 02 + mov dl, c + int 21h + pop dx + pop ax +endm + +; finish the execution +end_execution macro + mov ax, 4c02h + int 21h +endm + +; Konvertovanje broja u string +inttostr macro num1 str1 + push ax + push bx + push cx + push dx + push si + mov ax, num1 + mov dl, '$' + push dx + mov si, 10 +petlja2: + mov dx, 0 + div si + add dx, 48 + push dx + cmp ax, 0 + jne petlja2 + + mov bx, offset str1 +petlja2a: + pop dx + mov [bx], dl + inc bx + cmp dl, '$' + jne petlja2a + pop si + pop dx + pop cx + pop bx + pop ax +endm + +print_num macro num + inttostr num,strNZD + print_str strNZD +endm +;#macro-commands-end + +.code + +start: + push 8 + push 12 + call gcd + pop ax + print_num ax +; print out a result + end_execution + +;volatile procedure, ruins ax,bx,cx +gcd proc +;#extra-start + pop cx ;ret adress +;#extra-end + ;get params + pop ax + pop bx +;#extra-start + push cx ;ret for later +;#extra-end + cmp ax,bx + je endequal + ja greatera + ;ensure ax is greater + xchg ax,bx +greatera: + sub ax,bx + push bx + push ax + call gcd + pop ax;result + +endequal: +;#extra-start + pop cx +;#extra-end + push ax; result +;#extra-start + push cx;needed before ret +;#extra-end + ret +gcd endp +.stack +end start diff --git a/samples-with-macros/sumn-stack-prompt.asm b/samples-with-macros/sumn-stack-prompt.asm new file mode 100644 index 0000000..063af10 --- /dev/null +++ b/samples-with-macros/sumn-stack-prompt.asm @@ -0,0 +1,197 @@ +.model small +;#macro-commands-start +; finish the execution +end_execution macro + int 20h +endm + +; print a string on screen +print_str macro s + push ax + push dx + mov dx, offset s + mov ah, 09 + int 21h + pop dx + pop ax +endm + +; write a single char +print_char macro c + push ax + push dx + mov ah, 02 + mov dl, c + int 21h + pop dx + pop ax +endm + +; new line +print_new_line macro + push ax + push bx + push dx + mov ah,03 + mov bh,0 + int 10h + inc dh + mov dl,0 + mov ah,02 + int 10h + pop dx + pop bx + pop ax +endm + + +; Konvertovanje broja u string +inttostr macro num1 str1 + push ax + push bx + push cx + push dx + push si + mov ax, num1 + mov dl, '$' + push dx + mov si, 10 +petlja2: + mov dx, 0 + div si + add dx, 48 + push dx + cmp ax, 0 + jne petlja2 + + mov bx, offset str1 +petlja2a: + pop dx + mov [bx], dl + inc bx + cmp dl, '$' + jne petlja2a + pop si + pop dx + pop cx + pop bx + pop ax +endm + +print_num macro num + inttostr num,tempStr + print_str tempStr +endm + +read_num macro num + read_str tempStr,6 + ;push offset tempStr + ;push offset num + strtoint tempStr,num +endm + +;read into a buffer, inc the special 0 and 1 bytes +;fixes it into a $ terminated string +read_str macro strbuff, strlen + LOCAL copystr + push ax + push bx + push cx + push dx + push si + mov bp, sp + mov dx, offset strbuff + mov bx, dx + mov ax, strlen + mov byte [bx] ,al + mov ah, 0Ah + int 21h + mov si, dx + mov cl, [si+1] + mov ch, 0 +copystr: + mov al, [si+2] + mov [si], al + inc si + loop copystr + mov [si], '$' + pop si + pop dx + pop cx + pop bx + pop ax +endm + +;ascii to actual number +strtoint macro inStr,outNum + LOCAL mainloop,end + push ax + push bx + push cx + push dx + push si + mov bp, sp + mov bx, offset inStr + mov ax, 0 + mov cx, 0 + mov si, 10 +mainloop: + mov cl, [bx] + cmp cl, '$' + je end + mul si + sub cx, 48 + add ax, cx + inc bx + jmp mainloop +end: + mov outNum, ax + pop si + pop dx + pop cx + pop bx + pop ax +endm +;#macro-commands-end + +.code +;read_num, print_num, etc are macros + +start: + mov ax, data + mov ds, ax + print_str prompt + read_num n + mov cx, n +l1: + print_str prompt + read_num num + push num + loop l1 + ; now sum up the top n from the stack + mov cx, n + mov ax, 0 + mov dx, 0 +theloop: + pop ax ; get next from stack + add dx, ax ; array sum is in dx + loop theloop + ; result + print_new_line + print_str resStr + print_num dx +end1: + nop + end_execution + + +.data + num dw 12 + n dw 3 + rez dw 0 + tempStr db " " + prompt db "number? $" + resStr db "result $" + +.stack +end start diff --git a/samples/array-sum-input.asm b/samples/array-sum-input.asm new file mode 100644 index 0000000..666a3f3 --- /dev/null +++ b/samples/array-sum-input.asm @@ -0,0 +1,53 @@ +.model small +;make a sum of an array - version with loading values +;predefined array size + +;#macros-removed-from-listing + +.code +start: + mov dx, @data + mov ds, dx + print_str prompt + read_num n + mov ax, 0 + mov cx, n + cmp maxn, cx + jae normal + print_str errorN + end_execution +normal: +loadloop: + print_str prompt + read_num t + mov ax,t + mov bx,n + sub bx,cx + mov niz[bx],al + loop loadloop + print_new_line + ; now sum up + mov cx, n + xor ax,ax +mainloop: + mov bx, cx + add al, niz[bx-1] ; get array memeber, byte + ; store sum in al + loop mainloop ; end calc if done + print_num ax + end_execution + +data segment +n dw 7 +t dw 0 +maxn dw 20 +niz db 1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0 +tempStr db " " +prompt db "Number?$" +errorN db "Number too large!$" +ends +end start + + + + diff --git a/samples/array-sum-predef.asm b/samples/array-sum-predef.asm new file mode 100644 index 0000000..b5d6650 --- /dev/null +++ b/samples/array-sum-predef.asm @@ -0,0 +1,27 @@ +.model small +;make a sum of an array - version with predefined everything + +;#macros-removed-from-listing + +.code +start: + mov dx, @data + mov ds, dx + mov cx, n + mov ax, 0 + mov dx, 0 +mainloop: + mov bx, cx + add al, niz[bx-1] ; get array memeber, byte + ; store sum in al + loop mainloop ; end calc if done + print_num ax + end_execution + +data segment +n dw 7 +niz db 1,2,3,4,5,6,7,0 +tempStr db " " + +ends +end start diff --git a/samples/fakt.asm b/samples/fakt.asm new file mode 100644 index 0000000..ba7454f --- /dev/null +++ b/samples/fakt.asm @@ -0,0 +1,57 @@ +; Evolucija Softvera +; Racunanje faktoriela pomocu sateka i sabiranja + +.286 +.model small + +sseg segment stack + db 256 dup (?) +sseg ends + +.data +n dw 5 ; racunamo faktoriel od 7 +niz db 5,4,3,2,1 + +.code + mov dx, @data + mov ds, dx + ; Direktno indeksno - pomocu labela[DI] i labela[SI] + ;rezultat u dx + mov ax, 0 + mov bx, 0 + mov cx,0 + mov dx,0 + mov dl, niz[bx] ;ubacuje najveci clan n koji ce biti sabran n-1 put + inc bx ;krece od drugog clana + +petlja: + mov cl, niz[bx] ; citaj clan niza + cmp cx,1 ; da li je ax=1? + je kraj ; ako jeste, idi na kraj + +ubaci: ;ubacuje na stek prethodni rezultat n-1 put + cmp cx,1 + je pom + push dx + dec cx + jmp ubaci + +pom: + mov cl, niz[bx] ;uzima vrednost da koliko puta skida sa steka + +mnozenje: + cmp cx,1 + je sledeci + pop ax + add dx,ax + dec cx + jmp mnozenje + +sledeci: + inc bx + jmp petlja + +kraj: + print_num dx ;ispisi rezultat na kraju + nop + end diff --git a/samples/gcd-input.asm b/samples/gcd-input.asm new file mode 100644 index 0000000..1cfb44b --- /dev/null +++ b/samples/gcd-input.asm @@ -0,0 +1,48 @@ +.model small +;greatest common divisor, with input from terminal +data segment + tempStr db " " + prompt db "num?$" + promptr db "RES $" + m dw 0 + n dw 0 + +data ends +;#macros-removed-from-listing + +.code + +start: + mov ax,@data + mov ds,ax + print_str prompt + read_num m + print_new_line + print_str prompt + read_num n + print_new_line + + mov ax,n + mov bx,m + +compare: + cmp ax,bx + je exit ;exit since they're equal + ja greater + sub bx,ax + jmp compare + +greater: + sub ax,bx + jmp compare + +exit: +;exit out of the program + mov n,ax + print_str promptr + print_num n +; print out a result + end_execution + +.stack +end start diff --git a/samples/gcd-predef.asm b/samples/gcd-predef.asm new file mode 100644 index 0000000..b61b2eb --- /dev/null +++ b/samples/gcd-predef.asm @@ -0,0 +1,31 @@ +.model small +data segment + strNZD db " " +data ends +;#macros-removed-from-listing + +.code + +start: + mov ax,12 + mov bx,8 + +compare: + cmp ax,bx + je exit ;exit since they're equal + ja greater + sub bx,ax + jmp compare + +greater: + sub ax,bx + jmp compare + +exit: +;exit out of the program + print_num ax +; print out a result + end_execution + +.stack +end start diff --git a/samples/procgcd.asm b/samples/procgcd.asm new file mode 100644 index 0000000..63b4ea3 --- /dev/null +++ b/samples/procgcd.asm @@ -0,0 +1,36 @@ +.model small +.code + push br1 + push br2 + call gcd + pop rez +end1: + print_num rez + nop + +gcd proc + pop ax ;mov ax,[bp+8] + pop bx ;mov bx,[bp+6] +compare: + cmp ax,bx + je endp + cmp ax,bx + ja greater + sub bx,ax + jmp compare + +greater: + sub ax,bx + jmp compare + +endp: + push ax ;result + ret +gcd endp + +.data + br1 dw 12 + br2 dw 8 + rez dw 0 +.stack +end diff --git a/samples/rek-gcd-input.asm b/samples/rek-gcd-input.asm new file mode 100644 index 0000000..1ea80a1 --- /dev/null +++ b/samples/rek-gcd-input.asm @@ -0,0 +1,59 @@ +.model small +ASSUME DS:data +;recursive version of GCD, input from terminal +data segment + strNZD db " " + tempStr db " " + prompt db "num?$" + promptr db "RES $" + m dw 0 + n dw 0 +data ends +;#macros-removed-from-listing + +.code + +start: + mov ax,@data + mov ds,ax + print_str prompt + read_num m + print_new_line + print_str prompt + read_num n + print_new_line + + push n + push m + call gcd + pop n + print_str promptr + print_num n +; print out a result + end_execution + + +;volatile procedure, ruins ax,bx,cx +gcd proc + ;get params + pop ax + pop bx + cmp ax,bx + je endequal + ja greatera + ;ensure ax is greater + xchg ax,bx +greatera: + sub ax,bx + push bx + push ax + call gcd + pop ax;result + +endequal: + push ax; result + ret +gcd endp + +.stack +end start diff --git a/samples/rek-gcd-predef.asm b/samples/rek-gcd-predef.asm new file mode 100644 index 0000000..62bd88d --- /dev/null +++ b/samples/rek-gcd-predef.asm @@ -0,0 +1,41 @@ +.model small +;recursive version of GCD, predefined input +data segment + strNZD db " " +data ends +;#macros-removed-from-listing + +.code + +start: + push 8 + push 12 + call gcd + pop ax + print_num ax +; print out a result + end_execution + +;volatile procedure, ruins ax,bx,cx +gcd proc + ;get params + pop ax + pop bx + cmp ax,bx + je endequal + ja greatera + ;ensure ax is greater + xchg ax,bx +greatera: + sub ax,bx + push bx + push ax + call gcd + pop ax;result + +endequal: + push ax; result + ret +gcd endp +.stack +end start diff --git a/samples/sumn-stack-prompt.asm b/samples/sumn-stack-prompt.asm new file mode 100644 index 0000000..52ce6ea --- /dev/null +++ b/samples/sumn-stack-prompt.asm @@ -0,0 +1,44 @@ +.model small +;#macros-removed-from-listing + +.code +;read_num, print_num, etc are macros + +start: + mov ax, data + mov ds, ax + print_str prompt + read_num n + mov cx, n +l1: + print_str prompt + read_num num + push num + loop l1 + ; now sum up the top n from the stack + mov cx, n + mov ax, 0 + mov dx, 0 +theloop: + pop ax ; get next from stack + add dx, ax ; array sum is in dx + loop theloop + ; result + print_new_line + print_str resStr + print_num dx +end1: + nop + end_execution + + +.data + num dw 12 + n dw 3 + rez dw 0 + tempStr db " " + prompt db "number? $" + resStr db "result $" + +.stack +end start diff --git a/samples/sumn3.asm b/samples/sumn3.asm new file mode 100644 index 0000000..bd38a4a --- /dev/null +++ b/samples/sumn3.asm @@ -0,0 +1,36 @@ +.model small +.code +;read_num, print_num are macros + read_num n + mov cx, n +l1: + read_num num + push num + loop l1 + push n + call sumn + pop rez + print_num rez +end1: + nop + +sumn proc +;n is on top of the stack +;sum the next n top elements of the stack + pop cx + mov ax, 0 + mov dx, 0 +theloop: + pop ax ; get next from stack + add dx, ax ; array sum is in dx + loop theloop + push dx ; result + ret +sumn endp + +.data + num dw 12 + n dw 3 + rez dw 0 +.stack +end diff --git a/src-wsl/metrics_csv.wsl b/src-wsl/metrics_csv.wsl new file mode 100644 index 0000000..65ff3b8 --- /dev/null +++ b/src-wsl/metrics_csv.wsl @@ -0,0 +1,195 @@ +C:"Doni Pracner (c) 2015"; +C:" +This program is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public +License as published by the Free Software Foundation; either +version 3 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied +warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the GNU General Public License for more +details. + +You should have received a copy of the GNU General Public +License along with this program. If not, see +. +=========================================================="; + +C:"This program generates metrics for WSL programs, +including options for comparing two programs (mainly ment to +compare different versions) and output differences as direct +numbers and percentages in a CSV type of format. + +One of the goals was to enable this to be used both in the +command line for quick checks but also to be used for +automation and creation of CSV files for collections of +programs."; + +C:"usage {option} {filename}"; + +C:"Options"; +C:" -h or --help - help screen"; +C:" -H or --header - print header for metrics"; +C:" -c 'file1' 'file2' - compare two files and print the metrics"; +C:" -HC print header for comparison"; +C:" -o 'file' - set output for the print"; +C:" -s 'separator' - set the separator in outputs (default comma)"; +C:" otherwise print the metrics of the given file(s)"; + +C:"options are processed in sequence, so you can have +for instance multiple outputs during the execution and +run it for different programs"; + +C:"examples; + +'filename' 'file2' 'file3' + - just output the metrics all files on the screen, + each in it's own row + +-c 'f1' 'f2' + - compare two files and output the differences on the + screen + +-o res.tmp -HC -c 'f1' 'f1a' -c 'f2' 'f2a' + - output a header row and two rows comparing the given + files in the specified file +"; + +Field_Separator := ","; + +MW_PROC @Get_New_Name(VAR str) == + IF @Ends_With?(str, ".wsl") THEN + str := SUBSTR(str, 0, SLENGTH(str)-4) + FI; + str := str ++ ".met" +END; + +MW_PROC @Process_File(filename VAR metricslist) == + metricslist := < >; + IF @File_Exists?(filename) THEN + @New_Program(@Parse_File(filename, T_Statements)); + + C:"add them in reverse to the start of the list"; + metricslist := < @Struct_Metric(@Program) > ++ metricslist ; + metricslist := < @Total_Size(@Program) > ++ metricslist ; + metricslist := < @CFDF_Metric(@Program) > ++ metricslist ; + metricslist := < @Gen_Type_Count(T_Expression,@Program) > ++ metricslist ; + metricslist := < @Stat_Count(@Program) > ++ metricslist ; + metricslist := < @Essential(@Program) > ++ metricslist ; + metricslist := < @McCabe(@Program) > ++ metricslist + ELSE + PRINT("ERROR: File ",filename," not found"); + FI +END; + +MW_PROC @Write_Metrics(metrics VAR) == + FOR met IN metrics DO + @WS(Field_Separator); + @WN(met) + OD +END; + +MW_PROC @Write_Metrics_List(prefix VAR) == + @WS(prefix);@WS("McCabe Cyclo");@WS(Field_Separator); + @WS(prefix);@WS("McCabe Essential");@WS(Field_Separator); + @WS(prefix);@WS("Statements");@WS(Field_Separator); + @WS(prefix);@WS("Expressions");@WS(Field_Separator); + @WS(prefix);@WS("CFDF");@WS(Field_Separator); + @WS(prefix);@WS("Size");@WS(Field_Separator); + @WS(prefix);@WS("Structure") +END; + +MW_PROC @Metrics_Main() == +VAR< prog := < >, + filename:="", filename2 := "", + metrics := < >, met2 := < >, + opened := 0, + Argv := ARGV +>: +C:"First one is the script name that is being executed"; +Argv := TAIL(Argv); + +IF Argv = < > THEN + PRINT("no arguments passed; supply a filename to make metrics for "); +ELSE + WHILE Argv <> < > DO + POP(filename,Argv); + IF filename = "-h" OR filename = "--help" THEN + PRINT("HELP - for now in the comments at the start of the script"); + PRINT("options: --header or -H | -c | -HC | -o | -s"); + SKIP + ELSIF filename = "-H" OR filename = "--header" THEN + @WS("filename");@WS(Field_Separator); + @Write_Metrics_List(""); + @WL(""); + ELSIF filename = "-HC" THEN + C:"Header for comparison"; + @WS("filename");@WS(Field_Separator); + @Write_Metrics_List("P1-");@WS(Field_Separator); + @Write_Metrics_List("P2-");@WS(Field_Separator); + @Write_Metrics_List("DIFF-");@WS(Field_Separator); + @Write_Metrics_List("%-"); + @WL(""); + ELSIF filename = "-o" THEN + C:"set output"; + IF Argv = < > THEN + PRINT("argument needed after -o") + ELSE + POP(filename, Argv); + opened := opened + 1; + @Write_To(filename) + FI + ELSIF filename = "-s" THEN + C:"set separator"; + IF Argv = < > THEN + PRINT("argument needed after -s") + ELSE + POP(Field_Separator, Argv); + FI + ELSIF filename = "-c" THEN + C:"compare two files and dump the comparison"; + IF LENGTH(Argv) < 2 THEN + PRINT("two arguments needed after -c") + ELSE + POP(filename, Argv); + + @Process_File(filename VAR metrics); + @WS(filename); + @Write_Metrics(metrics); + + POP(filename2,Argv); + @Process_File(filename2 VAR met2); + @Write_Metrics(met2); + + C:"calculate the differences"; + FOR i := 1 TO LENGTH(metrics) STEP 1 DO + met2[i] := metrics[i] - met2[i]; + IF metrics[i] <> 0 THEN + metrics[i] := met2[i] * 100 DIV metrics[i] + FI + OD; + @Write_Metrics(met2); + @Write_Metrics(metrics); + + @WL(""); + FI; + SKIP + ELSE + @Process_File(filename VAR metrics); + @WS(filename); + @Write_Metrics(metrics); + @WL(""); + SKIP + FI + OD; + C:"be nice and close all the opened writes"; + FOR count := 1 TO opened STEP 1 DO + @End_Write + OD +FI +ENDVAR +END; + +@Metrics_Main() diff --git a/src-wsl/transf-min.wsl b/src-wsl/transf-min.wsl new file mode 100755 index 0000000..5086bc6 --- /dev/null +++ b/src-wsl/transf-min.wsl @@ -0,0 +1,154 @@ +C:" +Copyright (C) 2012,2015 Doni Pracner +http://perun.dmi.rs/pracner + +This program is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public +License as published by the Free Software Foundation; either +version 3 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied +warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the GNU General Public License for more +details. + +You should have received a copy of the GNU General Public +License along with this program. If not, see +. +=========================================================="; + +C:"Automatic transformation tool for simplification of WSL"; +C:"code automaticaly translated from assembly using asm2wsl."; + +C:"a very simple version, ment to be fast and relatively +efficient. It is aimed at action-system programs and should +remove them from the program, while doing other +simlifications in the process."; + +C:"set the following so that Action Systems are not +automaticaly treated as regular"; +C:"Not neccessary with recent versions of FermaT"; +Assume_A_S_Regular := 0; + +C:"Main procedure to transform the loaded program"; +MW_PROC @Process_Prog() == + + @Trans(TR_Constant_Propagation, ""); + + C:"Try to remove the Action systems"; + FOREACH Statement DO + IF @ST(@I) = T_A_S THEN + IF @Trans?(TR_Simplify_Action_System) THEN + @Trans(TR_Simplify_Action_System, "") + FI; + IF @Trans?(TR_Collapse_Action_System) THEN + @Trans(TR_Collapse_Action_System, ""); + FI; + ELSIF @Trans?(TR_Remove_All_Redundant_Vars) THEN + @Trans(TR_Remove_All_Redundant_Vars, ""); + ELSIF @ST(@I) = T_Skip THEN + @Delete + FI + OD; + + C:"remove all the comments "; + FOREACH Statement DO + IF @ST(@I) = T_Comment THEN + @Delete + FI + OD; + + FOREACH Statement DO + IF @Trans?(TR_Simplify_Item) THEN + @Trans(TR_Simplify_Item,"") + FI + OD; + + C:"Convert DO loops into WHILE loops"; + FOREACH Statement DO + IF @Trans?(TR_Floop_To_While) THEN + @Trans(TR_Floop_To_While, ""); + FI + OD; + C:"Go back to the start, and remove redundant"; + @Goto(< >); + @Trans(TR_Delete_All_Redundant, ""); + SKIP +END; + +MW_PROC @Get_New_Name(VAR str) == + IF @Ends_With?(str, ".wsl") THEN + str := SUBSTR(str, 0, SLENGTH(str)-4) + FI; + str := str ++ "_t.wsl" +END; + +MW_PROC @Prog_Stat_Comp(Pro, After VAR)== + VAR < ma := 0, mb :=1 > : + ma := @McCabe(Pro); + mb := @McCabe(After); + PRINT ("McCabe ", ma, " ", mb, " ",(mb-ma)); + ma := @Stat_Count(Pro); + mb := @Stat_Count(After); + PRINT ("Statem ", ma, " ",mb, " ",(mb-ma)); + ma := @CFDF_Metric(Pro); + mb := @CFDF_Metric(After); + PRINT ("CF/DF ", ma," ", mb," ", (mb-ma)); + ma := @Total_Size(Pro); + mb := @Total_Size(After); + PRINT ("Size ", ma," ", mb, " ",(mb-ma)); + ma := @Struct_Metric(Pro); + mb := @Struct_Metric(After); + PRINT ("Struct ", ma, " ",mb, " ",(mb-ma)); + SKIP + ENDVAR +END; + +MW_PROC @Process_File(filename) == + IF @File_Exists?(filename) THEN + @New_Program(@Parse_File(filename, T_Statements)); + PRINT("Processing: ", filename); + prog := @Program; + @Process_Prog(); + @Get_New_Name(VAR filename); + @PP_Item(@Program, 80, filename); + PRINT(filename); + @Prog_Stat_Comp(prog, @Program); + ELSE + PRINT("ERROR: File ",filename," not found"); + FI +END; + +VAR< prog := < >, inifilename := "transf.ini", + filename:="", file := "", inifile:= "", + Argv := ARGV +>: +C:"First one is the script name that is being executed"; +Argv := TAIL(Argv); + +IF Argv = < > THEN + PRINT("no arguments passed; using ",inifilename); + IF @File_Exists?(inifilename) THEN + inifile := @Open_Input_File(inifilename); + filename := @Read_Line(inifile); + C:"check if the loaded is an EOF"; + WHILE NOT @EOF?(filename) DO + @Process_File(filename); + filename := @Read_Line(inifile) + OD; + @Close_Input_Port(inifile); + ELSE + PRINT("ini file (",inifilename,") not found.", + " it should contain a list of filenames to be converted"); + PRINT("you can input a filename now:"); + filename := @Read_Line(Standard_Input_Port); + @Process_File(filename); + FI +ELSE + FOR arg IN Argv DO + @Process_File(arg); + OD +FI +ENDVAR diff --git a/src/asm2wsl.java b/src/asm2wsl.java new file mode 100755 index 0000000..125ac21 --- /dev/null +++ b/src/asm2wsl.java @@ -0,0 +1,746 @@ + +/* +Copyright 2012,2018 Doni Pracner + +This program is free software: you can redistribute it +and/or modify it under the terms of the GNU General Public +License as published by the Free Software Foundation, either +version 3 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied +warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the GNU General Public License for more +details. + +You should have received a copy of the GNU General Public +License along with this program. If not, see +. + +*/ +import java.io.*; +import java.util.*; + +/** + * This program converts files from assembly x86 to WSL language which is a part + * of the FermaT Transformation system.
+ * Currently it works only on a very limited subset of x86, and has a number of + * predefined macro names it uses for translation. It works with 16 bit + * registers (ax,bx, etc) and presumes that the rest of the variables are 8bit + * if not applied to a 16bit reg. Check the documentation for more details. + * + * @author Doni Pracner, http://perun.dmi.rs/pracner http://quemaster.com + */ +public class asm2wsl { + + private static final String PROCEDURE_INTERNAL_SYS = "procedure_internal_sys"; + + /** translation processing switch */ + public boolean originalInComments = false, translateComments = true, + addMemoryDump = false, translateToPopPush = true; + + int mode = MODE_0, nUnknownC = 0, nUnknownD = 0, nKnownC = 0; + + boolean labelfound = false; + + public static final String versionN = "0.81"; + + // regular comments from the original file + // OC when original code is inserted in the file, next to the translations + // SPEC special messages from the translator + // ERR error messages from the translator + public static final char C_REG = ' ', C_OC = '#', C_SPEC = '&', C_ERR = '!'; + + public static final int MODE_0 = 0, MODE_CODE = 1, MODE_DATA = 2, + MODE_STACK = 3, N_MODES = 4; + + public static final String CODE_SEG_START = "SKIP;\n ACTIONS A_S_start:\n A_S_start ==", + CODE_SEG_END = "CALL Z;\nSKIP END\nENDACTIONS;\n", + DATA_SEG_START = "VAR< ", DATA_SEG_END = " \tskipvar := 0 \n>:\n", + fixl = "\n%x := (%x DIV 256) * 256 + t_e_m_p;", + fixh = "\n%x := (%x MOD 256) + t_e_m_p * 256;"; + + public String getStandardStart() { + String ret = "C:\" This file automatically converted from assembler\";\n" + + "C:\" with asm2wsl v " + versionN + "\";\n"; + ret += "VAR < ax := 0, bx := 0, cx := 0, dx := 0,\n" + + " si := 0, di := 0, bp := 0, sp := 0, \n" + + " ss := 0, ds := 0, cs := 0, es := 0,\n" + + " flag_o := 0, flag_d := 0, flag_i := 0, flag_t := 0,\n" + + " flag_z := 0, flag_s := 0, flag_p := 0, flag_a := 0,\n" + + " flag_c := 0, overflow := 256, stack := < >, t_e_m_p := 0 > :\n"; + if (addMemoryDump) + ret += "BEGIN\n"; + return ret; + } + + public String getStandardEnd() { + String ret = "ENDVAR;\n"; + if (addMemoryDump) { + ret += "C:\" end original program. testing features following\";\n" + + "WHERE\n" + "PROC memdump(VAR) ==\n" + + " PRINT(\"'memory' dump: \");\n" + + " PRINT(\"ax \",ax,\" bx \",bx,\" cx \",cx,\" dx \",dx);\n" + + " PRINT(\"flags:\");\n" + " PRINT(\"ODITSZAPC\");\n" + + " PRINT(flag_o,flag_d,flag_i,flag_t,flag_s,flag_z,flag_a,flag_p,flag_c)\n" + + "END\n" + "END\n"; + } + ret += "\nENDVAR"; + return ret; + } + + /** + * When the param works with array addressing, this should reformat it so + * that it works as intended. An important thing to remember is that there + * is a[0] element in WSL, all arrays start with a[1]. + */ + public String arrayFix(String str) { + String param = str.substring(str.indexOf('[') + 1, str.indexOf(']')); + return str.replace(param + "]", formatParam(param) + "+1]"); + } + + /** + * Transforms an asembler source parameter as need so that it can be used in + * WSL. Among other things it converts Hex numbers to decimal, fixes array + * access indexes and the high/low parts of registers. + */ + public String formatParam(String str) { + str = str.toLowerCase(); + if (str.contains("[")) + str = arrayFix(str); + try { + if (str.matches("[0-9][0-9a-f]*h")) + return "" + Integer.parseInt(str.substring(0, str.length() - 1), + 16); + } catch (Exception e) { + System.err.println("error in hex param procesing"); + e.printStackTrace(); + } + if (str.compareTo("al") == 0) + return "(ax MOD 256)"; + else if (str.compareTo("ah") == 0) + return "(ax DIV 256)"; + else if (str.compareTo("bl") == 0) + return "(bx MOD 256)"; + else if (str.compareTo("bh") == 0) + return "(bx DIV 256)"; + else if (str.compareTo("cl") == 0) + return "(cx MOD 256)"; + else if (str.compareTo("ch") == 0) + return "(cx DIV 256)"; + else if (str.compareTo("dl") == 0) + return "(dx MOD 256)"; + else if (str.compareTo("dh") == 0) + return "(dx DIV 256)"; + else + // for undefined variables + if (str.compareTo("(?)") == 0) + return "\" \""; + else + + return str; + } + + /** + * Transforms an asembler destination parameter as need so that it can be + * used in WSL. Among other things it fixes array access indexes and the + * high/low parts of registers. + */ + public String formatDst(String str) { + if (str.contains("[")) + str = arrayFix(str); + str = str.toLowerCase(); + if (str.length() == 2 && str.charAt(0) >= 'a' && str.charAt(0) <= 'd' + && (str.charAt(1) == 'l' || str.charAt(1) == 'h')) + return "t_e_m_p"; + else + return str; + } + + /** + * Used for fixing low/high register access. The given param should be the + * dst operand of an assembler command. + */ + public String getXRegisterFix(String str) { + str = str.toLowerCase(); + if (str.length() == 2 && str.charAt(0) >= 'a' && str.charAt(0) <= 'd') { + char c = str.charAt(0); + if (str.charAt(1) == 'l') + return fixl.replace('%', c); + if (str.charAt(1) == 'h') + return fixh.replace('%', c); + } + return ""; + } + + /** + * Creates a WSL comment with care to quote chars. + */ + public static String createComment(String str) { + return createComment(str, C_REG); + } + + /** + * Creates a WSL comment with care to quote chars, of the given type. Types + * are given as char constants. They can be default comments, comments that + * contain the original code in them, or additional comments regarding the + * translation process. + */ + public static String createComment(String str, char type) { + return "C:\"" + type + str.replace("\"", "''") + "\";"; + } + + /** + * Creates a wsl statement that modifies the overflow limit based on the + * input string that should be the parameter of a command. + */ + public String getOverflow(String str) { + int over = 256; + str = str.toLowerCase(); + if (str.length() == 2) { + if ((str.charAt(1) == 'x' && str.charAt(0) >= 'a' + && str.charAt(0) <= 'd') + || (str.compareTo("si") == 0 || str.compareTo("bp") == 0)) + over = 65536; + } + return "overflow := " + over + "; "; + } + + private void debugPrint(ArrayList com) { + System.out.println(); + for (int i = 0; i < com.size(); i++) { + System.out.print(com.get(i)); + System.out.print("||"); + } + } + + private boolean inMacro = false; + + // internal state, if a procedure body is being translated currently + private boolean inProcedure = false; + + // the name of the procedure currently translated, if there is one + private String currentProcName = ""; + + /** + * Takes a single assembler line and returns the translated WSL line(s). It + * also changes the translator modes (data, code etc). + */ + public String processLine(String str) { + /* Most of the logic is here, some parts could be split off */ + if (str.length() == 0) + return ""; + String[] split = str.split(";", 2); + String rez = split[0]; + String comment = ""; + // removes the comments + if (translateComments && split.length > 1) + comment = createComment(split[1]); + if (rez.compareTo("") != 0) { + // if there is a non-comment part + String[] parts = rez.split("[\t ,]"); + // separators are whitespace: tab, space and comma + ArrayList com = new ArrayList(); + for (String s : parts) + if (s.compareTo("") != 0 && s != null) + com.add(s); + rez = ""; + String a, b; + // special case, we are processing lines in a macro definition + if (inMacro) { + Iterator it = com.iterator(); + while (it.hasNext()) + if (it.next().compareTo("endm") == 0) + inMacro = false; + return createComment(str, C_SPEC) + "\n"; + } + // by this time, all the real words should be in the com array + int i = 0; + boolean work = true; + // debugPrint(com); + while (i < com.size() && work) { + String s = com.get(i).toLowerCase(); + if (s.endsWith(":")) { // should represent a label + s = s.substring(0, s.length() - 1); + rez += "CALL " + s + "\n END\n"; + rez += s + " == "; + // labelfound = true; + } else + // ------------------------------------------------------------ + // procedures, calls and similar activities + if (s.compareTo("proc") == 0) { + // if (labelfound) + rez += "CALL Z; SKIP END \n"; + a = com.get(i - 1); + rez += a + " == "; + b = PROCEDURE_INTERNAL_SYS; + rez += "\nACTIONS " + b + ": \n"; + rez += b + " == "; + inProcedure = true; + currentProcName = a; + } else if (s.compareTo("endp") == 0) { + rez += " SKIP END\n ENDACTIONS\n END\n dummy" + nKnownC + + " == "; + inProcedure = false; + } else if (s.compareTo("ret") == 0) { + rez += " CALL Z;"; + } else if (s.compareTo("call") == 0) { + a = com.get(++i); + // check for recursive calls, don't do outside of current + // action system + if (inProcedure && currentProcName.equals(a)) + a = PROCEDURE_INTERNAL_SYS; + rez += "CALL " + a + ";"; + } else + // segments and other special assembler directives + if (s.charAt(0) == '.') { // + if (s.compareTo(".code") == 0) { + rez = CODE_SEG_START; + mode = MODE_CODE; + } else if (s.compareTo(".data") == 0) { + rez = " "; + mode = MODE_DATA; + } else if (s.compareTo(".stack") == 0) { + rez = " "; + mode = MODE_STACK; + } else if (s.startsWith(".model")) { + if (!s.toLowerCase().endsWith("small")) { + rez += createComment( + "other models than small not supported :: " + + split[0], + C_SPEC); + nUnknownD++; + mode = MODE_0; + } + } else { + rez += createComment( + "directive not supported :: " + split[0], + C_SPEC); + nUnknownD++; + mode = MODE_0; + } + work = false; + } else if (s.compareTo("assume") == 0) { + rez += createComment( + "ASSUME commands not supported :: " + split[0], + C_SPEC); + nUnknownD++; + work = false; + } else if (s.compareTo("segment") == 0) { + String segn = com.get(i - 1).toLowerCase(); + if (segn.compareTo("cseg") == 0 + || segn.compareTo("code") == 0 + || segn.compareTo("code_seg") == 0) { + rez += CODE_SEG_START; + mode = MODE_CODE; + } else if (segn.compareTo("dseg") == 0 + || segn.compareTo("data_seg") == 0 + || segn.compareTo("data") == 0) { + rez += " "; + mode = MODE_DATA; + } else if (segn.compareTo("sseg") == 0 + || segn.compareTo("stack_seg") == 0 + || segn.compareTo("stack") == 0) { + rez += " "; + mode = MODE_STACK; + } else { + rez += createComment( + "unsuported segment type :: " + split[0], + C_SPEC); + nUnknownD++; + mode = MODE_0; + } + work = false; + } else if (s.compareTo("ends") == 0) { // segment end + if (i > 0) { + String segn = com.get(i - 1).toLowerCase(); + if (segn.compareTo("cseg") == 0 + || segn.compareTo("code_seg") == 0 + || segn.compareTo("code") == 0 + || segn.compareTo("dseg") == 0 + || segn.compareTo("data") == 0 + || segn.compareTo("data_seg") == 0 + || segn.compareTo("sseg") == 0 + || segn.compareTo("stack") == 0 + || segn.compareTo("stack_seg") == 0) { + rez += createComment("end of segment " + segn, + C_SPEC); + mode = MODE_0; + } else { + rez += createComment( + "unsuported segment type :: " + split[0], + C_SPEC); + nUnknownD++; + } + } else { + rez += createComment("end of segment", C_SPEC); + mode = MODE_0; + } + work = false; + } else + // macro ideas ---- + if (s.compareTo("macro") == 0) { + rez += createComment( + "found macro definition - macros unsuported", + C_ERR); + nUnknownC++; + inMacro = true; + work = false; + } else if (s.compareTo("endm") == 0) { + rez += createComment( + "found macro definition end - macros unsuported", + C_ERR); + nUnknownC++; + work = false; + } else + + /* + * ------------------------------ + * + * special macro names translated directly + */ + if ((s.compareTo("print_str") == 0 + || s.compareTo("print_num") == 0 + || s.compareTo("print_char") == 0) + && com.get(i + 1).compareTo("macro") != 0) { + rez += "PRINFLUSH(" + com.get(i + 1) + ");"; + + work = false; + } else if (s.compareTo("print_new_line") == 0 + && (com.size() <= i + 1 + || com.get(i + 1).compareTo("macro") != 0)) { + rez += "PRINT(\"\");"; + + work = false; + } else if (s.compareTo("read_str") == 0 + && com.get(i + 1).compareTo("macro") != 0) { + rez += "@Read_Line_Proc(VAR " + com.get(i + 1) + + ", Standard_Input_Port);"; + + work = false; + } else if (s.compareTo("read_num") == 0 + && com.get(i + 1).compareTo("macro") != 0) { + rez += "@Read_Line_Proc(VAR t_e_m_p, Standard_Input_Port);\n"; + rez += com.get(i + 1) + " := @String_To_Num(t_e_m_p);"; + + work = false; + } else if (s.compareTo("end_execution") == 0 + && (com.size() <= i + 1 + || com.get(i + 1).compareTo("macro") != 0)) { + rez += "CALL Z;"; + + work = false; + } else + + // --------------------------------------- + // operators and similar commands + if (s.compareTo("mov") == 0) { + a = com.get(i + 1); + b = com.get(i + 2).toLowerCase(); + if ((b.compareTo("@data") == 0) + || (b.compareTo("dseg") == 0)) { + rez += createComment("unneeded DATA segment fixes", + C_SPEC); + work = false; + } else {// rez += getOverflow(a); + rez += formatDst(a) + " := " + formatParam(b) + ";"; + rez += getXRegisterFix(a); + work = false; + } + } else if (s.compareTo("add") == 0 || s.compareTo("adc") == 0) { + a = com.get(i + 1); + b = com.get(i + 2); + rez += getOverflow(a); + rez += formatDst(a) + " := " + formatParam(a) + " + " + + formatParam(b) + ";\n"; + if (s.compareTo("adc") == 0) + rez += formatDst(a) + " := " + formatParam(a) + " + " + + " + flag_c;\n"; + rez += "IF " + formatDst(a) + " >= overflow THEN " + + formatDst(a) + " := " + formatDst(a) + + " MOD overflow; flag_o :=1; flag_c := 1; ELSE flag_o :=0; flag_c := 0; FI;"; + rez += getXRegisterFix(a); + work = false; + } else if (s.compareTo("sub") == 0 || s.compareTo("cmp") == 0) { + a = com.get(i + 1); + b = com.get(i + 2); + // rez += getOverflow(a); + rez += "IF " + formatParam(a) + " = " + formatParam(b) + + " THEN\n\t flag_z := 1\n ELSE\n\t flag_z := 0\n FI; "; + rez += "IF " + formatParam(a) + " < " + formatParam(b) + + " THEN\n\t flag_c := 1\n ELSE\n\t flag_c := 0\n FI; "; + if (s.compareTo("sub") == 0) + rez += formatDst(a) + " := " + formatParam(a) + " - " + + formatParam(b) + ";"; + work = false; + } else if (s.compareTo("inc") == 0) { + a = com.get(i + 1); + rez += getOverflow(a); + rez += formatDst(a) + " := " + formatParam(a) + " + 1;"; + rez += getXRegisterFix(a); + work = false; + } else if (s.compareTo("dec") == 0) { + a = com.get(i + 1); + rez += getOverflow(a); + rez += formatDst(a) + " := " + formatParam(a) + " - 1;"; + rez += getXRegisterFix(a); + work = false; + } else if (s.compareTo("shr") == 0) { + a = com.get(i + 1); + // rez += getOverflow(a); + rez += "IF " + formatParam(a) + " MOD 2 = 1 THEN " + + " flag_c := 1; ELSE flag_c := 0; FI;"; + rez += formatDst(a) + " := " + formatParam(a) + " DIV 2;"; + rez += getXRegisterFix(a); + work = false; + } else if (s.compareTo("shl") == 0) { + a = com.get(i + 1); + rez += getOverflow(a); + rez += formatDst(a) + " := " + formatParam(a) + " * 2;"; + rez += "IF " + formatDst(a) + " >= overflow THEN " + + formatDst(a) + " := " + formatDst(a) + + " MOD overflow; flag_o :=1; flag_c := 1; ELSE flag_o :=0; flag_c := 0; FI;"; + rez += getXRegisterFix(a); + work = false; + } else if (s.compareTo("xchg") == 0) { + a = com.get(i + 1); + b = com.get(i + 2); + rez += "< " + formatDst(a) + " := " + formatParam(b) + ", " + + formatDst(b) + " := " + formatParam(a) + " >;"; + rez += getXRegisterFix(a); + work = false; + } else + // logical exp + if (s.compareTo("and") == 0) { + // rez += com.get(i+1)+" := "+com.get(i+1)+" AND + // "+formatParam(com.get(i+2))+";"; + rez += createComment( + "and not implemented yet :: " + split[0], C_ERR); + nUnknownC++; + work = false; + } else if (s.compareTo("xor") == 0) { + a = com.get(i + 1); + b = formatParam(com.get(i + 2)); + if (a.compareTo(b) == 0) + rez += a + " := 0;"; + else { + rez += createComment( + "xor not implemnted yet :: " + split[0], C_ERR); + // a+" := ("+a+" AND NOT "+b+") OR (NOT "+a+" AND "+b+" + // );"); + nUnknownC++; + } + work = false; + } else if (s.compareTo("not") == 0) { + // rez += com.get(i+1)+" := NOT "+com.get(i+1)+";"; + rez += createComment( + "NOT not implemented yet :: " + split[0], C_ERR); + nUnknownC++; + work = false; + } else + // jumps + if (s.compareTo("jmp") == 0) { + rez += "CALL " + com.get(i + 1) + ";"; + work = false; + } else if (s.compareTo("je") == 0 || s.compareTo("jz") == 0) { + rez += "IF flag_z = 1 THEN CALL " + com.get(i + 1) + " FI;"; + work = false; + } else if (s.compareTo("jne") == 0 || s.compareTo("jnz") == 0) { + rez += "IF flag_z = 0 THEN CALL " + com.get(i + 1) + " FI;"; + work = false; + } else if (s.compareTo("ja") == 0) { + rez += "IF flag_z = 0 AND flag_c = 0 THEN CALL " + + com.get(i + 1) + " FI;"; + work = false; + } else if (s.compareTo("jae") == 0 || s.compareTo("jnc") == 0) { + rez += "IF flag_c = 0 THEN CALL " + com.get(i + 1) + " FI;"; + work = false; + } else if (s.compareTo("jb") == 0) { + rez += "IF flag_c = 1 THEN CALL " + com.get(i + 1) + " FI;"; + work = false; + } else if (s.compareTo("jcxz") == 0) { + rez += "IF cx = 0 THEN CALL " + com.get(i + 1) + " FI;"; + work = false; + } else if (s.compareTo("jo") == 0) { + rez += "IF flag_o = 1 THEN CALL " + com.get(i + 1) + " FI;"; + work = false; + } else if (s.compareTo("loop") == 0) { + rez += "cx := cx - 1;\n"; + rez += "IF cx>0 THEN CALL " + com.get(i + 1) + + " ELSE CALL dummy" + nKnownC + " FI\n"; + rez += "END\ndummy" + nKnownC + " =="; + work = false; + } else + + // end and other + if (s.compareTo("end") == 0) { + // TODO parse the optional entry label that comes with end + rez += createComment("program end"); + work = false; + } else if (s.compareTo("nop") == 0) { + rez += "SKIP;"; + work = false; + } else + + // stack + if (s.compareTo("pop") == 0) { + if (translateToPopPush) { + rez += "POP(" + formatDst(com.get(i + 1)) + ", stack);"; + } else { + rez += formatDst(com.get(i + 1)) + " := HEAD(stack);\n"; + rez += "stack := TAIL(stack);"; + } + rez += getXRegisterFix(com.get(i + 1)); + work = false; + } else if (s.compareTo("push") == 0) { + if (translateToPopPush) { + rez += "PUSH(stack, " + formatParam(com.get(i + 1)) + + ");"; + } else { + rez += "stack := < " + formatParam(com.get(i + 1)) + + " > ++ stack;"; + } + work = false; + } else + // var definitions + if (s.compareTo("db") == 0 || s.compareTo("dw") == 0) { + if (mode == MODE_DATA) { + if (com.size() == i + 2) { + rez += "\t " + com.get(i - 1) + " := " + + formatParam(com.get(i + 1)) + ","; + } else {// array + rez += "\t " + com.get(i - 1) + " := < " + + formatParam(com.get(i + 1)); + for (int j = i + 2; j < com.size(); j++) + rez += "," + formatParam(com.get(j)); + rez += " >,"; + } + } else { + + } + } + i++; + } + if (rez.compareTo("") == 0 && com.size() > 0) { + rez = createComment(" unkown command:" + split[0], C_ERR); + nUnknownC++; + } else + nKnownC++; // this now counts the directives too... + } + return rez + " " + comment + "\n"; + + } + + /** + * Converts an asm file to a wsl file. It also prints out the number of + * unsupported commands. + */ + public void convertAFile(File f) { + try { + BufferedReader in = new BufferedReader( + new InputStreamReader(new FileInputStream(f))); + String str = in.readLine(), rez = f.getPath(); + if (rez.toLowerCase().endsWith(".asm")) + rez = rez.substring(0, rez.length() - 4); + PrintWriter out = new PrintWriter( + new OutputStreamWriter(new FileOutputStream(rez + ".wsl"))); + nUnknownD = 0; + nUnknownC = 0; + nKnownC = 0; + StringBuilder[] sbs = new StringBuilder[N_MODES]; + for (int i = 0; i < N_MODES; i++) + sbs[i] = new StringBuilder(); + while (str != null) { + rez = processLine(str); + if (originalInComments) + sbs[mode].append(createComment(str, C_OC) + "\n"); + sbs[mode].append(rez); + str = in.readLine(); + } + sbs[MODE_CODE].append(CODE_SEG_END); + if (addMemoryDump) + sbs[MODE_CODE].append("memdump();"); + sbs[MODE_DATA].append(DATA_SEG_END); + // remove comments from dataseg + String datastr = sbs[MODE_DATA].toString() + .replaceAll("C:\"(.*?)\";\n?", ""); + in.close(); + out.print(getStandardStart()); + out.print(sbs[MODE_0]); + out.print(DATA_SEG_START); + out.print(datastr); // out.print(sbs[MODE_DATA]); + out.print(sbs[MODE_CODE]); + out.print(getStandardEnd()); + out.close(); + if (nUnknownD > 0) + System.out.println("warning: " + nUnknownD + + " unkown/unsuported directives were found"); + if (nUnknownC > 0) + System.out.println("errors : " + nUnknownC + + " unkown/unsuported commands were found"); + System.out.println(nKnownC + " commands translated"); + } catch (Exception e) { + System.err.println("error in conversion:"); + e.printStackTrace(); + } + } + + public void run(String[] args) { + if (args.length == 0) { + System.out.println("Assembler to WSL converter. v " + versionN + + ", by Doni Pracner"); + System.out.println("usage:\n\t asm2wsl {-option[ +-]} filename"); + System.out.println("options: (def value in parenthesis)"); + System.out.println("\t -oc : orignal code in comments (" + + (originalInComments ? "+" : "-") + ")"); + System.out.println("\t -c : translate comments (" + + (translateComments ? "+" : "-") + ")"); + System.out.println("\t -dump : add memory dump commands to end (" + + (addMemoryDump ? "+" : "-") + ")"); + } else { + if (args[0].compareTo("-h") == 0 + || args[0].compareTo("--help") == 0) { + run(new String[0]); + return; + } + int i = 0; + while (i < args.length && args[i].charAt(0) == '-') { + if (args[i].startsWith("-oc")) { + if (args[i].length() == 4) + originalInComments = args[i].charAt(3) == '+'; + else + originalInComments = true; + } else if (args[i].startsWith("-c")) { + if (args[i].length() == 3) + translateComments = args[i].charAt(2) == '+'; + else + translateComments = true; + } else if (args[i].startsWith("-dump")) { + addMemoryDump = true; + if (args[i].length() == 6 && args[i].charAt(5) == '-') + addMemoryDump = false; + } + i++; + } + + if (i >= args.length) { + System.out.println("no filename supplied"); + System.exit(2); + } + File f = new File(args[i]); + if (f.exists()) { + Calendar now = Calendar.getInstance(); + convertAFile(f); + long mili = Calendar.getInstance().getTimeInMillis() + - now.getTimeInMillis(); + System.out.println("conversion time:" + mili + " ms"); + } else + System.out.println("file does not exist"); + } + } + + public static void main(String[] args) { + new asm2wsl().run(args); + } +} diff --git a/tests/array-sum-input.1.txt b/tests/array-sum-input.1.txt new file mode 100644 index 0000000..a5a9869 --- /dev/null +++ b/tests/array-sum-input.1.txt @@ -0,0 +1,4 @@ +4 +3 +22 +111 \ No newline at end of file diff --git a/tests/array-sum-input.2.txt b/tests/array-sum-input.2.txt new file mode 100644 index 0000000..22bd915 --- /dev/null +++ b/tests/array-sum-input.2.txt @@ -0,0 +1,2 @@ +1 +15 diff --git a/tests/array-sum-input.3.txt b/tests/array-sum-input.3.txt new file mode 100644 index 0000000..573541a --- /dev/null +++ b/tests/array-sum-input.3.txt @@ -0,0 +1 @@ +0 diff --git a/tests/array-sum-input.4.txt b/tests/array-sum-input.4.txt new file mode 100644 index 0000000..8fdd954 --- /dev/null +++ b/tests/array-sum-input.4.txt @@ -0,0 +1 @@ +22 \ No newline at end of file diff --git a/tests/array-sum-predef.txt b/tests/array-sum-predef.txt new file mode 100644 index 0000000..e69de29 diff --git a/tests/fakt.txt b/tests/fakt.txt new file mode 100644 index 0000000..e69de29 diff --git a/tests/gcd-input.1.txt b/tests/gcd-input.1.txt new file mode 100644 index 0000000..5000edf --- /dev/null +++ b/tests/gcd-input.1.txt @@ -0,0 +1,2 @@ +25 +15 diff --git a/tests/gcd-input.2.txt b/tests/gcd-input.2.txt new file mode 100644 index 0000000..93c538e --- /dev/null +++ b/tests/gcd-input.2.txt @@ -0,0 +1,2 @@ +15 +25 diff --git a/tests/gcd-input.3.txt b/tests/gcd-input.3.txt new file mode 100644 index 0000000..58cd0aa --- /dev/null +++ b/tests/gcd-input.3.txt @@ -0,0 +1,2 @@ +17 +13 diff --git a/tests/gcd-input.4.txt b/tests/gcd-input.4.txt new file mode 100644 index 0000000..c094c55 --- /dev/null +++ b/tests/gcd-input.4.txt @@ -0,0 +1,2 @@ +12 +12 diff --git a/tests/gcd-predef.txt b/tests/gcd-predef.txt new file mode 100644 index 0000000..e69de29 diff --git a/tests/procgcd.txt b/tests/procgcd.txt new file mode 100644 index 0000000..e69de29 diff --git a/tests/rek-gcd-input.1.txt b/tests/rek-gcd-input.1.txt new file mode 100644 index 0000000..5000edf --- /dev/null +++ b/tests/rek-gcd-input.1.txt @@ -0,0 +1,2 @@ +25 +15 diff --git a/tests/rek-gcd-input.2.txt b/tests/rek-gcd-input.2.txt new file mode 100644 index 0000000..93c538e --- /dev/null +++ b/tests/rek-gcd-input.2.txt @@ -0,0 +1,2 @@ +15 +25 diff --git a/tests/rek-gcd-input.3.txt b/tests/rek-gcd-input.3.txt new file mode 100644 index 0000000..58cd0aa --- /dev/null +++ b/tests/rek-gcd-input.3.txt @@ -0,0 +1,2 @@ +17 +13 diff --git a/tests/rek-gcd-input.4.txt b/tests/rek-gcd-input.4.txt new file mode 100644 index 0000000..c094c55 --- /dev/null +++ b/tests/rek-gcd-input.4.txt @@ -0,0 +1,2 @@ +12 +12 diff --git a/tests/rek-gcd-predef.txt b/tests/rek-gcd-predef.txt new file mode 100644 index 0000000..e69de29 diff --git a/tests/sumn-stack-prompt.1.txt b/tests/sumn-stack-prompt.1.txt new file mode 100644 index 0000000..a5a9869 --- /dev/null +++ b/tests/sumn-stack-prompt.1.txt @@ -0,0 +1,4 @@ +4 +3 +22 +111 \ No newline at end of file diff --git a/tests/sumn-stack-prompt.2.txt b/tests/sumn-stack-prompt.2.txt new file mode 100644 index 0000000..22bd915 --- /dev/null +++ b/tests/sumn-stack-prompt.2.txt @@ -0,0 +1,2 @@ +1 +15 diff --git a/tests/sumn-stack-prompt.3.txt b/tests/sumn-stack-prompt.3.txt new file mode 100644 index 0000000..573541a --- /dev/null +++ b/tests/sumn-stack-prompt.3.txt @@ -0,0 +1 @@ +0 diff --git a/update-samples-without-macros.sh b/update-samples-without-macros.sh new file mode 100755 index 0000000..b7a5cf3 --- /dev/null +++ b/update-samples-without-macros.sh @@ -0,0 +1,8 @@ +#!/bin/bash +# copy from samples-with-macros and remove the macros segment in the samples folder + +cp samples-with-macros/*.asm samples/ +sed -i \ + -e '/#macro-commands-start/,/#macro-commands-end/ c ;#macros-removed-from-listing' \ + -e '/#extra-start/,/#extra-end/ d' \ + samples/*.asm \ No newline at end of file