#!/usr/local/bin/perl

package x86ms;

$label="L000";

$align=($main'aout)?"4":"16";
$under=($main'aout)?"_":"";
$com_start=($main'sol)?"/":"#";

if ($main'cpp)
        {
        $align="ALIGN";
        $under="";
        $com_start='/*';
        $com_end='*/';
        }

%lb=(   'eax',  '%al',
        'ebx',  '%bl',
        'ecx',  '%cl',
        'edx',  '%dl',
        'ax',   '%al',
        'bx',   '%bl',
        'cx',   '%cl',
        'dx',   '%dl',
        );

%hb=(   'eax',  '%ah',
        'ebx',  '%bh',
        'ecx',  '%ch',
        'edx',  '%dh',
        'ax',   '%ah',
        'bx',   '%bh',
        'cx',   '%ch',
        'dx',   '%dh',
        );

%regs=( 'eax',  '%eax',
        'ebx',  '%ebx',
        'ecx',  '%ecx',
        'edx',  '%edx',
        'esi',  '%esi',
        'edi',  '%edi',
        'ebp',  '%ebp',
        'esp',  '%esp',
        );

sub main'LB
        {
        (defined($lb{$_[0]})) || die "$_[0] does not have a 'low byte'\n";
        return($lb{$_[0]});
        }

sub main'HB
        {
        (defined($hb{$_[0]})) || die "$_[0] does not have a 'high byte'\n";
        return($hb{$_[0]});
        }

sub main'DWP
        {
        local($addr,$reg1,$reg2,$idx)=@_;


        $ret="";

        $addr =~ s/(^|[+ \t])([A-Za-z_]+)($|[+ \t])/$1$under$2$3/;

        $reg1="$regs{$reg1}" if defined($regs{$reg1});
        $reg2="$regs{$reg2}" if defined($regs{$reg2});
        $ret.=$addr if ($addr ne "") && ($addr ne 0);
        if ($reg2 ne "")
                {
                $ret.="($reg1,$reg2,$idx)";
                }
        else
                {
                $ret.="($reg1)"
                }
        return($ret);
        }

sub main'BP
        {
        local($addr,$reg1,$reg2,$idx)=@_;


        $ret="";

        $addr =~ s/(^|[+ \t])([A-Za-z_]+)($|[+ \t])/$1$under$2$3/;

        $reg1="$regs{$reg1}" if defined($regs{$reg1});
        $reg2="$regs{$reg2}" if defined($regs{$reg2});
        $ret.=$addr if ($addr ne "") && ($addr ne 0);
        if ($reg2 ne "")
                {
                $ret.="($reg1,$reg2,$idx)";
                }
        else
                {
                $ret.="($reg1)"
                }
        return($ret);
        }

sub main'mov    { &out2("movl",@_); }
sub main'movb   { &out2("movb",@_); }
sub main'and    { &out2("andl",@_); }
sub main'or     { &out2("orl",@_); }
sub main'shl    { &out2("sall",@_); }
sub main'shr    { &out2("shrl",@_); }
sub main'xor    { &out2("xorl",@_); }
sub main'add    { &out2("addl",@_); }
sub main'sub    { &out2("subl",@_); }
sub main'rotl   { &out2("roll",@_); }
sub main'rotr   { &out2("rorl",@_); }
sub main'exch   { &out2("xchg",@_); }
sub main'cmp    { &out2("cmpl",@_); }
sub main'jmp    { &out1("jmp",@_); }
sub main'je     { &out1("je",@_); }
sub main'jne    { &out1("jne",@_); }
sub main'jnz    { &out1("jnz",@_); }
sub main'jz     { &out1("jz",@_); }
sub main'dec    { &out1("decl",@_); }
sub main'push   { &out1("pushl",@_); }
sub main'call   { &out1("call",$under.$_[0]); }


sub out2
        {
        local($name,$p1,$p2)=@_;
        local($l,$ll,$t);

        print "\t$name\t";
        $t=&conv($p2).",";
        $l=length($t);
        print $t;
        $ll=4-($l+9)/8;
        print "\t" x $ll;
        print &conv($p1);
        print "\n";
        }

sub out1
        {
        local($name,$p1)=@_;
        local($l,$t);

        print "\t$name\t";
        print &conv($p1);
        print "\n";
        }

sub conv
        {
        local($p)=@_;

#       $p =~ s/0x([0-9A-Fa-f]+)/0$1h/;

        $p=$regs{$p} if (defined($regs{$p}));

        $p =~ s/^([0-9A-Fa-f]+)$/\$$1/;
        $p =~ s/^(0x[0-9A-Fa-f]+)$/\$$1/;
        return $p;
        }

sub main'file
        {
        local($file)=@_;

        print <<"EOF";
        .file   "$file.s"
        .version        "01.01"
gcc2_compiled.:
EOF
        }

sub main'function_begin
        {
        local($func,$num)=@_;

        $params=$num*4;

        $func=$under.$func;

        print <<"EOF";
.text
        .align $align
.globl $func
EOF
        if ($main'cpp)
                { printf("\tTYPE($func,\@function)\n"); }
        else    { printf("\t.type       $func,\@function\n"); }
        print <<"EOF";
$func:
        pushl   %ebp
        pushl   %ebx
        pushl   %esi
        pushl   %edi

EOF
        $stack=20;
        }

sub main'function_end
        {
        local($func)=@_;

        $func=$under.$func;

        print <<"EOF";
        popl    %edi
        popl    %esi
        popl    %ebx
        popl    %ebp
        ret
.${func}_end:
EOF
        if ($main'cpp)
                { printf("\tSIZE($func,.${func}_end-$func)\n"); }
        else    { printf("\t.size\t$func,.${func}_end-$func\n"); }
        print ".ident   \"desasm.pl\"\n";
        $stack=0;
        %label=();
        }

sub main'function_end_A
        {
        local($func)=@_;

        print <<"EOF";
        popl    %edi
        popl    %esi
        popl    %ebx
        popl    %ebp
        ret
EOF
        }

sub main'function_end_B
        {
        local($func)=@_;

        $func=$under.$func;

        print <<"EOF";
.${func}_end:
EOF
        if ($main'cpp)
                { printf("\tSIZE($func,.${func}_end-$func)\n"); }
        else    { printf("\t.size\t$func,.${func}_end-$func\n"); }
        print ".ident   \"desasm.pl\"\n";
        $stack=0;
        %label=();
        }

sub main'wparam
        {
        local($num)=@_;

        return(&main'DWP($stack+$num*4,"esp","",0));
        }

sub main'wtmp_b
        {
        local($num,$b)=@_;

        return(&main'BP(-(($num+1)*4)+$b,"esp","",0));
        }

sub main'wtmp
        {
        local($num)=@_;

        return(&main'DWP(-($num+1)*4,"esp","",0));
        }

sub main'comment
        {
        foreach (@_)
                {
                if (/^\s*$/)
                        { print "\n"; }
                else
                        { print "\t$com_start $_ $com_end\n"; }
                }
        }

sub main'label
        {
        if (!defined($label{$_[0]}))
                {
                $label{$_[0]}=".${label}${_[0]}";
                $label++;
                }
        return($label{$_[0]});
        }

sub main'set_label
        {
        if (!defined($label{$_[0]}))
                {
                $label{$_[0]}=".${label}${_[0]}";
                $label++;
                }
        print ".align $align\n";
        print "$label{$_[0]}:\n";
        }

sub main'file_end
        {
        }
