git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@1092 379699f6-c40d-0410-875b-85095c16579ebranch_1_1
parent
6a30f5c91d
commit
cb159304d8
@ -0,0 +1,711 @@ |
|||||||
|
use strict; |
||||||
|
|
||||||
|
my (@tstack, @vstack); |
||||||
|
|
||||||
|
my $incindent = 4; |
||||||
|
|
||||||
|
my $instr_addr; |
||||||
|
my (%instr, %next_instr, %prev_instr); |
||||||
|
|
||||||
|
@tstack = (); |
||||||
|
@vstack = (); |
||||||
|
|
||||||
|
sub print_stack { |
||||||
|
my ($type, $value); |
||||||
|
while (@tstack and @vstack) { |
||||||
|
$type = shift @tstack; |
||||||
|
$value = shift @vstack; |
||||||
|
print STDERR "($type) $value, "; |
||||||
|
} |
||||||
|
if (@tstack) { |
||||||
|
print STDERR "TSTACK to big : @tstack "; |
||||||
|
} elsif (@vstack) { |
||||||
|
print STDERR "VSTACK to big : @vstack "; |
||||||
|
} |
||||||
|
@tstack = (); |
||||||
|
@vstack = (); |
||||||
|
} |
||||||
|
|
||||||
|
sub print_code { |
||||||
|
my ($indent, $code, $addr) = @_; |
||||||
|
#print " "x$indent, $code, (defined addr)?"/* $addr */":"", "\n"; |
||||||
|
print " "x$indent, $code, "\n"; |
||||||
|
} |
||||||
|
|
||||||
|
sub dump_program { |
||||||
|
my $addr; |
||||||
|
foreach $addr (sort { $a <=> $b } keys %instr) { |
||||||
|
print_code (0, "$addr $instr{$addr}"); |
||||||
|
} |
||||||
|
return 1 |
||||||
|
} |
||||||
|
|
||||||
|
sub convert_value($$$) { |
||||||
|
my ($value, $oldtype, $newtype) = @_; |
||||||
|
return "$value" if ($oldtype eq $newtype); |
||||||
|
return "$value" if ($oldtype =~ /\*/ or $newtype =~ /\*/); |
||||||
|
return "$value" if ($oldtype eq "boolean" && $newtype eq "int"); |
||||||
|
if ($oldtype eq "int" && $newtype eq "boolean") { |
||||||
|
$value =~ s/1/true/g; |
||||||
|
$value =~ s/0/false/g; |
||||||
|
$value =~ s/\&/\&\&/g; |
||||||
|
$value =~ s/\|/\|\|/g; |
||||||
|
return $value; |
||||||
|
} |
||||||
|
return $value; # "/*warn: conv: $oldtype => $newtype*/ $value"; |
||||||
|
} |
||||||
|
|
||||||
|
sub get_type ($) { |
||||||
|
my $type; |
||||||
|
$_ = $_[0]; |
||||||
|
SWITCH: { |
||||||
|
/^b$/ && ($type = "byte",last); |
||||||
|
/^c$/ && ($type = "char",last); |
||||||
|
/^s$/ && ($type = "short",last); |
||||||
|
/^i$/ && ($type = "int",last); |
||||||
|
/^l$/ && ($type = "long",last); |
||||||
|
/^f$/ && ($type = "float",last); |
||||||
|
/^d$/ && ($type = "double",last); |
||||||
|
/^a$/ && ($type = "*",last); |
||||||
|
die "internal error in get_type"; |
||||||
|
} |
||||||
|
return $type; |
||||||
|
} |
||||||
|
|
||||||
|
sub pop_value_type ($) { |
||||||
|
if (not @tstack || not @vstack) { |
||||||
|
die "Stack is empty??"; |
||||||
|
} |
||||||
|
my $result = ""; |
||||||
|
my $want_type = $_[0]; |
||||||
|
my $act_type = pop @tstack; |
||||||
|
my $value = pop @vstack; |
||||||
|
warn "want_type not defined" |
||||||
|
if (not defined $want_type); |
||||||
|
warn "act_type not defined" |
||||||
|
if (not defined $act_type); |
||||||
|
$result = convert_value($value, $act_type, $want_type); |
||||||
|
return ($result, $act_type); |
||||||
|
} |
||||||
|
|
||||||
|
sub pop_value($) { |
||||||
|
@_ = pop_value_type($_[0]); |
||||||
|
return $_[0]; |
||||||
|
} |
||||||
|
|
||||||
|
sub parse_type($) { |
||||||
|
$_[0] =~ /^\#\d+\s+ <Class |
||||||
|
\s+(\S+) # type |
||||||
|
>\s*$/x or die "Wrong field parameter `$_[0]'"; |
||||||
|
return $1; |
||||||
|
} |
||||||
|
|
||||||
|
sub parse_field($) { |
||||||
|
$_[0] =~ /^\#\d+\s+ <Field |
||||||
|
\s+(\S+) # type |
||||||
|
\s+([^\[>]+) # name |
||||||
|
((?:\[\])*) # [][]... belongs to type |
||||||
|
>\s*$/x or die "Wrong field parameter `$_[0]'"; |
||||||
|
return $1.$3, $2; |
||||||
|
} |
||||||
|
|
||||||
|
sub parse_special($) { |
||||||
|
$_[0] =~ /\#\d+\s+<Method |
||||||
|
\s+([^\(\s]+) # method |
||||||
|
\s*\(([^\)]*)\) # params |
||||||
|
>\s*$/x or die "Wrong method parameter `$_[0]'"; |
||||||
|
my ($method, $params) = ($1,$2); |
||||||
|
my @params = split /,\s*/, $params; |
||||||
|
return $method, @params; |
||||||
|
} |
||||||
|
|
||||||
|
sub parse_method($) { |
||||||
|
$_[0] =~ /\#\d+\s+<Method |
||||||
|
\s+(\S+) # type |
||||||
|
\s+([^\(\s]+) # method |
||||||
|
\s*\(([^\)]*)\) # params |
||||||
|
>\s*$/x or die "Wrong method parameter `$_[0]'"; |
||||||
|
my ($type, $method, $params) = ($1, $2,$3); |
||||||
|
my @params = split /,\s*/, $params; |
||||||
|
return $type, $method, @params; |
||||||
|
} |
||||||
|
|
||||||
|
sub classify($$) { |
||||||
|
my $class = $_[0] . "."; |
||||||
|
$class = "" if $class eq "this."; |
||||||
|
return $class.$_[1]; |
||||||
|
} |
||||||
|
|
||||||
|
sub new_instr($) { |
||||||
|
if (defined ($instr{$instr_addr})) { |
||||||
|
$instr{$instr_addr} .= "\n/*warn: multiple*/\n".$_[0]; |
||||||
|
} else { |
||||||
|
$instr{$instr_addr} = $_[0]; |
||||||
|
} |
||||||
|
# print STDERR "$instr_addr: $instr{$instr_addr}\n"; |
||||||
|
} |
||||||
|
|
||||||
|
sub new_assign($$) { |
||||||
|
my ($var, $value) = @_; |
||||||
|
if (@vstack) { |
||||||
|
if (("$value" eq "($var + 1)") && |
||||||
|
($vstack[-1] eq "$var")) { |
||||||
|
$vstack[-1] = "$var++"; |
||||||
|
} else { |
||||||
|
warn("`$var = $value' in expression, while vstack"); |
||||||
|
} |
||||||
|
} else { |
||||||
|
new_instr("$var = $value;"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
sub combine_if_block { |
||||||
|
my ($addr, $end) = @_; |
||||||
|
|
||||||
|
$instr{$addr} =~ /if (\(.*\)) goto (\d+);/ or return; |
||||||
|
my ($cond, $dest) = ($1, $2); |
||||||
|
|
||||||
|
COMBINE: |
||||||
|
while (1) { |
||||||
|
my $if; |
||||||
|
|
||||||
|
|
||||||
|
# First combine ifs with the same dest addr, that is ors. |
||||||
|
my @conds = ($cond); |
||||||
|
for ($if = $next_instr{$addr}; $if < $end; $if = $next_instr{$addr}) { |
||||||
|
|
||||||
|
$instr{$if} =~ /if (\(.*\)) goto ($dest);/ or last; |
||||||
|
|
||||||
|
push @conds, $1; |
||||||
|
#remove unnecessary ifs (hope there are no goto's) |
||||||
|
$next_instr{$addr} = $next_instr{$if}; |
||||||
|
$prev_instr{$next_instr{$if}}= $addr; |
||||||
|
delete $instr{$if}; |
||||||
|
delete $prev_instr{$if}; |
||||||
|
delete $next_instr{$if}; |
||||||
|
} |
||||||
|
if (@conds > 1) { |
||||||
|
# combine conditions with or and reset the list |
||||||
|
$cond = join " || ", @conds; |
||||||
|
$cond = "($cond)"; |
||||||
|
} |
||||||
|
|
||||||
|
last COMBINE if ($if >= $end || $instr{$if} !~ /^if/); |
||||||
|
|
||||||
|
# Now try if we can combine all further ifs until the destination (that is and) |
||||||
|
combine_if_block($if, $dest) |
||||||
|
unless ($next_instr{$if} == $dest); |
||||||
|
|
||||||
|
last COMBINE if ($next_instr{$if} != $dest); |
||||||
|
|
||||||
|
# This is an and |
||||||
|
$instr{$if} =~ /if (\(.*\)) goto (\d+);/; |
||||||
|
$cond = "(!$cond && $1)"; |
||||||
|
$dest = $2; |
||||||
|
$next_instr{$addr} = $next_instr{$if}; |
||||||
|
$prev_instr{$next_instr{$if}}= $addr; |
||||||
|
delete $instr{$if}; |
||||||
|
delete $prev_instr{$if}; |
||||||
|
delete $next_instr{$if}; |
||||||
|
} |
||||||
|
|
||||||
|
# Okay, we are stuck here, build the combined if. |
||||||
|
$instr{$addr} = "if $cond goto $dest;"; |
||||||
|
} |
||||||
|
|
||||||
|
sub simplify_instructions { |
||||||
|
my ($addr, $end) = @_; |
||||||
|
ADDR: |
||||||
|
for (; $addr < $end; $addr = $next_instr{$addr}) { |
||||||
|
combine_if_block($addr, $end) |
||||||
|
if $instr{$addr} =~ /^if /; |
||||||
|
|
||||||
|
while ( $instr{$addr} =~ |
||||||
|
/^(.*)new (java\.lang\.)?StringBuffer\((\).append\(.*)+\).toString\(\)(.*)$/ ) { |
||||||
|
my ($first, $middle, $last) = ($1,$3,$4); |
||||||
|
$middle =~ s/\).append\(/\+/g; |
||||||
|
$middle =~ s/^\+//; |
||||||
|
$instr{$addr} = $first.$middle.$last; |
||||||
|
} |
||||||
|
|
||||||
|
while ( $instr{$addr} =~ s/([A-Za-z_\$][A-Za-z_\$0-9]*) = \(\1 \+ 1\)/$1++/) { |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
# The parameters: |
||||||
|
# start first instruction to decode |
||||||
|
# end last instruction to decode + 1 |
||||||
|
# next instruction where control flows after this block |
||||||
|
# (usually end but may be bigger) |
||||||
|
# break instruction where a break would bring us to |
||||||
|
# indent The indentation of this block |
||||||
|
|
||||||
|
sub print_stmtlist ($$$$$) { |
||||||
|
my ($start, $end, $next, $break, $indent) = @_; |
||||||
|
my $addr; |
||||||
|
$addr = $start; |
||||||
|
ADDR: |
||||||
|
while ($addr < $end) { |
||||||
|
(dump_program && die "Addresses out of range: $addr") if (not defined $next_instr{$addr}); |
||||||
|
|
||||||
|
$_ = $instr{$addr}; |
||||||
|
/^goto (\d+);$/ && do { |
||||||
|
my $dest = $1; |
||||||
|
if ($dest == $break) { |
||||||
|
print_code($indent, "break $dest;", $addr); |
||||||
|
$addr = $next_instr{$addr}; |
||||||
|
next ADDR; |
||||||
|
} |
||||||
|
my $begin = $next_instr{$addr}; |
||||||
|
if ($instr{$dest} =~ /^if\s\((.*)\)\sgoto\s$begin/) { |
||||||
|
# This is a while-loop |
||||||
|
print_code($indent, "while ($1) {", $addr); |
||||||
|
print_stmtlist($begin, $dest, $dest, $dest, $indent+$incindent); |
||||||
|
print_code($indent, "}"); |
||||||
|
$addr = $next_instr{$dest}; |
||||||
|
next ADDR; |
||||||
|
} |
||||||
|
}; |
||||||
|
/^if \((.*)\) goto (\d+);/ && do { |
||||||
|
my $cond = $1; |
||||||
|
my $next_after_if = $2; |
||||||
|
if ($next_after_if > $addr && |
||||||
|
($next_after_if <= $end || $next_after_if == $next)) { |
||||||
|
# This seems to be an if. |
||||||
|
print_code($indent, "if (!($cond)) {", $addr); |
||||||
|
|
||||||
|
# endthen is the last instruction in then block + 1 |
||||||
|
my $endthen = ($next_after_if > $end) ? $end : $next_after_if; |
||||||
|
my $prev = $prev_instr{$endthen}; |
||||||
|
if ($instr{$prev} =~ /^goto\s(.*);/ && |
||||||
|
$1 > $endthen && ($1 <= $end || $1 == $next)) { |
||||||
|
$next_after_if = $1; |
||||||
|
my $endelse = $1; |
||||||
|
if ($endelse > $end) { |
||||||
|
$endelse = $end; |
||||||
|
} |
||||||
|
# there is an else part |
||||||
|
print_stmtlist ($next_instr{$addr}, $prev, |
||||||
|
$next_after_if, $break, $indent+$incindent); |
||||||
|
print_code($indent, "} else {"); |
||||||
|
print_stmtlist ($endthen, $endelse, |
||||||
|
$next_after_if, $break, $indent+$incindent); |
||||||
|
$addr = $endelse; |
||||||
|
} else { |
||||||
|
# no else-part |
||||||
|
print_stmtlist ($next_instr{$addr}, $endthen, |
||||||
|
$next_after_if, $break, $indent+$incindent); |
||||||
|
$addr = $endthen; |
||||||
|
} |
||||||
|
print_code($indent, "}"); |
||||||
|
next ADDR; |
||||||
|
} |
||||||
|
if ($next_after_if == $break) { |
||||||
|
# This is an if () break; |
||||||
|
print_code($indent, "if ($cond) break;", $addr); |
||||||
|
$addr = $next_instr{$addr}; |
||||||
|
next ADDR; |
||||||
|
} |
||||||
|
}; |
||||||
|
/^case ((.|\n)*)$/ && do { |
||||||
|
my $default; |
||||||
|
my $cond = "NONE"; |
||||||
|
my @lines = split "\n", $1; |
||||||
|
$_ = shift @lines; |
||||||
|
/^\((.*)\)$/ and $cond = $1; |
||||||
|
(shift @lines) =~ /^default: goto (\d+);/ and $default = $1; |
||||||
|
my $next_after_switch = $default; |
||||||
|
if ($instr{$prev_instr{$default}} =~ /^goto\s(\d+);/ and |
||||||
|
$1 > $default) { |
||||||
|
$next_after_switch = $1; |
||||||
|
} |
||||||
|
print_code ($indent, "switch ($cond) {", $addr); |
||||||
|
my %cases = ($default => "default"); |
||||||
|
foreach (@lines) { |
||||||
|
(/^(\d+): goto (\d+);$/ and $cases{$2} = "case $1") |
||||||
|
or warn ("ILLEGAL case : `$_'"); |
||||||
|
my $casepos = $1; |
||||||
|
if ($casepos > $next_after_switch) { |
||||||
|
if ($instr{$prev_instr{$1}} =~ /^goto\s(\d+);/ and |
||||||
|
$1 > $casepos) { |
||||||
|
$next_after_switch = $1; |
||||||
|
} else { |
||||||
|
$next_after_switch = $casepos; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
$next_after_switch = $end |
||||||
|
if ($next_after_switch > $end && $next_after_switch != $next); |
||||||
|
my $endswitch = ($next_after_switch > $end) ? $end : $next_after_switch; |
||||||
|
#print STDERR "Addr: $addr, labels: `", |
||||||
|
# (join ":", keys %cases ), "', default: $default, end: $next_after_switch\n"; |
||||||
|
$addr = $next_instr{$addr}; |
||||||
|
foreach $_ (sort { $a <=> $b } keys %cases) { |
||||||
|
my $next_case = $_; |
||||||
|
if ($instr{$prev_instr{$next_case}} eq |
||||||
|
"goto $next_after_switch;") { |
||||||
|
print_stmtlist($addr, $prev_instr{$next_case}, |
||||||
|
$next_after_switch, $next_after_switch, |
||||||
|
$indent+$incindent); |
||||||
|
print_code($indent+$incindent, "break;"); |
||||||
|
} else { |
||||||
|
print_stmtlist($addr, $next_case, |
||||||
|
$next_case, $next_after_switch, |
||||||
|
$indent+$incindent); |
||||||
|
} |
||||||
|
print_code($indent, $cases{$next_case}.":"); |
||||||
|
$addr = $next_case; |
||||||
|
} |
||||||
|
print_stmtlist($addr, $endswitch, |
||||||
|
$endswitch, $next_after_switch, |
||||||
|
$indent+$incindent); |
||||||
|
print_code($indent, "}"); |
||||||
|
$addr = $endswitch; |
||||||
|
next ADDR; |
||||||
|
}; |
||||||
|
print_code($indent, $_, $addr); |
||||||
|
$addr = $next_instr{$addr}; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
my %locals = (); |
||||||
|
my $addr; |
||||||
|
|
||||||
|
LINE: while (<>) { |
||||||
|
|
||||||
|
chomp; |
||||||
|
(/^\s*(\d+)\s+(.*)$/ and $addr = $1, $_ = $2) or do { |
||||||
|
warn "Line `$_' ist not formatted correctly\n"; |
||||||
|
next LINE; |
||||||
|
}; |
||||||
|
|
||||||
|
if (not @vstack) { |
||||||
|
if (defined ($instr_addr)) { |
||||||
|
new_instr("/*warn: missing instruction!*/") |
||||||
|
if (not defined $instr{$instr_addr}); |
||||||
|
$next_instr{$instr_addr} = $addr; |
||||||
|
$prev_instr{$addr} = $instr_addr; |
||||||
|
} else { |
||||||
|
$prev_instr{$addr} = -1; |
||||||
|
} |
||||||
|
$instr_addr = $addr; |
||||||
|
} |
||||||
|
|
||||||
|
INSTR: |
||||||
|
{ |
||||||
|
/^([ilfda])load[\s_]+(\d+)\s*$/ && do { |
||||||
|
push @tstack, get_type($1); |
||||||
|
my $local; |
||||||
|
if ($2 == 0) { |
||||||
|
$local = "this"; |
||||||
|
} else { |
||||||
|
$local = "local_$2"; |
||||||
|
} |
||||||
|
push @vstack, $local; |
||||||
|
last INSTR; |
||||||
|
}; |
||||||
|
/^([bcsilfda])aload\s*$/ && do { |
||||||
|
my $warn = ""; |
||||||
|
my $index = pop_value("int"); |
||||||
|
my ($array, $atype) = pop_value_type(get_type($1)."[]"); |
||||||
|
my $type = $atype; |
||||||
|
($atype =~ /(.*)\[\]/ and $type = $1) or |
||||||
|
$warn = "/*warn: `$atype' not an array*/ "; |
||||||
|
push @tstack, $type; |
||||||
|
push @vstack, "$warn$array"."[$index]"; |
||||||
|
last INSTR; |
||||||
|
}; |
||||||
|
(/^[bs](i)push\s+(-?\d+)\s*$/ || |
||||||
|
/^([ilfda])const[\s_]+([m\-]?[\d.Ee\+\-]+|null)\s*$/) && do { |
||||||
|
push @tstack, get_type($1); |
||||||
|
push @vstack, ($2 eq "m1") ? -1 : $2; |
||||||
|
last INSTR; |
||||||
|
}; |
||||||
|
/ldc[12]?_?w?\s+\#\d+\s+\<(\S+)\s+([^\>]+)\>/ && do { |
||||||
|
push @tstack, $1; |
||||||
|
push @vstack, $2; |
||||||
|
last INSTR; |
||||||
|
}; |
||||||
|
/^([ilfda])store[\s_]+(\d+)\s*$/ && do { |
||||||
|
my $local; |
||||||
|
my ($value, $type) = pop_value_type(get_type($1)); |
||||||
|
if ($2 == 0) { |
||||||
|
$local = "this"; |
||||||
|
} else { |
||||||
|
$local = "local_$2"; |
||||||
|
if (not defined $locals{$2}) { |
||||||
|
$locals{$2} = $type; |
||||||
|
$local = "$type $local"; |
||||||
|
} else { |
||||||
|
$local = convert_value($local, $type, $locals{$2}); |
||||||
|
} |
||||||
|
} |
||||||
|
new_assign($local, $value); |
||||||
|
last INSTR; |
||||||
|
}; |
||||||
|
/^([bcsilfda])astore\s*$/ && do { |
||||||
|
my ($value, $type) = pop_value_type(get_type($1)); |
||||||
|
my $index = pop_value("int"); |
||||||
|
my ($array, $atype) = pop_value_type(get_type($1)."[]"); |
||||||
|
($atype =~ /(.*)\[\]/ and $atype = $1) or |
||||||
|
$atype = "`$atype' not an array*/\n\t"; |
||||||
|
new_assign("$array"."[$index]", |
||||||
|
convert_value("$value", $type, $atype)); |
||||||
|
|
||||||
|
last INSTR; |
||||||
|
}; |
||||||
|
/^new\s+(.*)\s*/ && do { |
||||||
|
my ($type) = parse_type($1); |
||||||
|
push @tstack, $type; |
||||||
|
push @vstack, "new $type"; |
||||||
|
last INSTR; |
||||||
|
}; |
||||||
|
/^newarray\s+(\S+)\s*$/ && do { |
||||||
|
my $arrtype = $1; |
||||||
|
my $value = pop_value("int"); |
||||||
|
push @tstack, $arrtype."[]"; |
||||||
|
push @vstack, "new ".$arrtype."[$value]"; |
||||||
|
last INSTR; |
||||||
|
}; |
||||||
|
/^getfield\s+(.*)$/ && do { |
||||||
|
my ($type, $field) = parse_field($1); |
||||||
|
my $class = pop_value("*") . "."; |
||||||
|
$class = "" if $class eq "this."; |
||||||
|
push @tstack, $type; |
||||||
|
push @vstack, "$class$field"; |
||||||
|
last INSTR; |
||||||
|
}; |
||||||
|
/^getstatic\s+(.*)$/ && do { |
||||||
|
my ($type, $field) = parse_field($1); |
||||||
|
push @tstack, $type; |
||||||
|
my $class="FIXME."; |
||||||
|
push @vstack, "$class$field"; |
||||||
|
last INSTR; |
||||||
|
}; |
||||||
|
/^putfield\s+(.*)$/ && do { |
||||||
|
my ($dtype, $field) = parse_field($1); |
||||||
|
my $value = pop_value($dtype); |
||||||
|
$field = classify(pop_value("*"), $field); |
||||||
|
new_assign($field, $value); |
||||||
|
last INSTR; |
||||||
|
}; |
||||||
|
/^goto\s+(\d+)\s*$/ && do { |
||||||
|
new_instr("goto $1;"); |
||||||
|
last INSTR; |
||||||
|
}; |
||||||
|
/^tableswitch\s+(\d+)\s+to\s+(\d+): default=(\d+)\s*$/ && do { |
||||||
|
my $from = $1; |
||||||
|
my $to = $2; |
||||||
|
my $default = $3; |
||||||
|
my $num; |
||||||
|
my $casestmt = "case (" . pop_value("int") . ")\n"; |
||||||
|
$casestmt .= "default: goto $default;\n"; |
||||||
|
for $num ($from .. $to) { |
||||||
|
$_ = <>; |
||||||
|
if ( $_ =~ /\s+$num:\s*(\d+)/ ) { |
||||||
|
$casestmt .= "$num: goto $1;\n"; |
||||||
|
} else { |
||||||
|
warn "unknown case: `$_' at $."; |
||||||
|
} |
||||||
|
} |
||||||
|
new_instr($casestmt); |
||||||
|
last INSTR; |
||||||
|
}; |
||||||
|
/^lookupswitch\s+(\d+):\s+default=(\d+)\s*$/ && do { |
||||||
|
my $anz = $1; |
||||||
|
my $default = $2; |
||||||
|
my $num; |
||||||
|
my $casestmt = "case (" . pop_value("int") . ")\n"; |
||||||
|
$casestmt .= "default: goto $default;\n"; |
||||||
|
for $num (1 .. $anz) { |
||||||
|
$_ = <>; |
||||||
|
if ( $_ =~ /\s+(\d+):\s*(\d+)/ ) { |
||||||
|
$casestmt .= "$1: goto $2;\n"; |
||||||
|
} else { |
||||||
|
$casestmt .= "error in case"; |
||||||
|
} |
||||||
|
} |
||||||
|
new_instr($casestmt); |
||||||
|
last INSTR; |
||||||
|
}; |
||||||
|
|
||||||
|
/^invokespecial\s+(.*)$/ && do { |
||||||
|
my ($method, @paramtypes) = parse_special ($1); |
||||||
|
my @params=(); |
||||||
|
# Constructoraufruf! Wenn alles glatt laeuft... |
||||||
|
while (@paramtypes) { |
||||||
|
my $ptype = pop @paramtypes; |
||||||
|
my $value = pop_value($ptype); |
||||||
|
unshift @params, $value; |
||||||
|
} |
||||||
|
my ($new_class, $class_type) = pop_value_type ("*"); |
||||||
|
$method = $new_class; |
||||||
|
my $call = "$method(" . join (", ", @params) . ")"; |
||||||
|
if ($vstack[-1] eq $new_class) { |
||||||
|
$vstack[-1] = "$call"; |
||||||
|
} else { |
||||||
|
new_instr("$call;"); |
||||||
|
} |
||||||
|
last INSTR; |
||||||
|
}; |
||||||
|
/^invoke(virtual|static)\s+(.*)$/ && do { |
||||||
|
my ($type, $method, @paramtypes) = parse_method ($2); |
||||||
|
my @params=(); |
||||||
|
while (@paramtypes) { |
||||||
|
my $ptype = pop @paramtypes; |
||||||
|
my $value = pop_value($ptype); |
||||||
|
unshift @params, $value; |
||||||
|
} |
||||||
|
my ($class, $class_type) = ($1 eq "virtual")? pop_value_type ("*") : "FIXME"; |
||||||
|
$method = classify($class, $method); |
||||||
|
my $call = "$method(" . join (", ", @params) . ")"; |
||||||
|
if ($type eq "void") { |
||||||
|
new_instr("$call;"); |
||||||
|
} else { |
||||||
|
push @tstack, $type; |
||||||
|
push @vstack, $call; |
||||||
|
} |
||||||
|
last INSTR; |
||||||
|
}; |
||||||
|
/^return\s*$/ && do { |
||||||
|
new_instr("return;"); |
||||||
|
last INSTR; |
||||||
|
}; |
||||||
|
/^pop\s*$/ && do { |
||||||
|
unless (@vstack) { |
||||||
|
print STDERR "pop: Stack is empty at $addr"; |
||||||
|
} |
||||||
|
new_instr(pop(@vstack).";"); |
||||||
|
pop @tstack; |
||||||
|
last INSTR; |
||||||
|
}; |
||||||
|
/^dup\s*$/ && do { |
||||||
|
push @tstack, $tstack[-1]; |
||||||
|
push @vstack, $vstack[-1]; |
||||||
|
last INSTR; |
||||||
|
}; |
||||||
|
/^dup2\s*$/ && do { |
||||||
|
push @tstack, $tstack[-2]; |
||||||
|
push @vstack, $vstack[-2]; |
||||||
|
push @tstack, $tstack[-2]; |
||||||
|
push @vstack, $vstack[-2]; |
||||||
|
last INSTR; |
||||||
|
}; |
||||||
|
/^dup_x([12])\s*$/ && do { |
||||||
|
splice @tstack, -1-$1, 0, $tstack[-1]; |
||||||
|
splice @vstack, -1-$1, 0, $vstack[-1]; |
||||||
|
last INSTR; |
||||||
|
}; |
||||||
|
/^([ilfd])neg\s*$/ && do { |
||||||
|
my $type = get_type($1); |
||||||
|
my $op1 = pop_value($type); |
||||||
|
push @tstack, $type; |
||||||
|
push @vstack, "-$op1"; |
||||||
|
last INSTR; |
||||||
|
}; |
||||||
|
/^([ilfd])(add|sub|mul|div|rem|and|or|xor|shl|shr)\s*$/ && do { |
||||||
|
my $type = get_type($1); |
||||||
|
my $op2 = pop_value($type); |
||||||
|
my $op1 = pop_value($type); |
||||||
|
my $op; |
||||||
|
for ($2) { |
||||||
|
/add/ && ($op="+", last); |
||||||
|
/sub/ && ($op="-", last); |
||||||
|
/mul/ && ($op="*", last); |
||||||
|
/div/ && ($op="/", last); |
||||||
|
/rem/ && ($op="%", last); |
||||||
|
/and/ && ($op="&", last); |
||||||
|
/or/ && ($op="|", last); |
||||||
|
/xor/ && ($op="^", last); |
||||||
|
/shl/ && ($op="<<", last); |
||||||
|
/shr/ && ($op=">>", last); |
||||||
|
} |
||||||
|
push @tstack, $type; |
||||||
|
push @vstack, "($op1 $op $op2)"; |
||||||
|
last INSTR; |
||||||
|
}; |
||||||
|
/^iinc\s+(\d+)\s+(-?\d+)\s*$/ && do { |
||||||
|
my $value = $2; |
||||||
|
my $local; |
||||||
|
if ($1 == 0) { |
||||||
|
$local = "this"; |
||||||
|
} else { |
||||||
|
$local = "local_$1"; |
||||||
|
} |
||||||
|
new_instr(convert_value("$local", "int", $locals{$1}). |
||||||
|
(($2 == 1)? "++;" : " += $2;")); |
||||||
|
last INSTR; |
||||||
|
}; |
||||||
|
/^([bcifld])2([bcifld])\s*$/ && do { |
||||||
|
my $value = pop_value(get_type($1)); |
||||||
|
my $type = get_type($2); |
||||||
|
push @tstack, $type; |
||||||
|
push @vstack, "($type) $value"; |
||||||
|
last INSTR; |
||||||
|
}; |
||||||
|
/^([lfd])cmp([lg]?)\s*$/ && do { |
||||||
|
my $type = get_type($1); |
||||||
|
my $op2 = pop_value($type); |
||||||
|
my $op1 = pop_value($type); |
||||||
|
push @tstack, "int"; |
||||||
|
push @vstack, "($op1 <=>$2 $op2)"; |
||||||
|
last INSTR; |
||||||
|
}; |
||||||
|
/^if(eq|lt|le|ne|gt|ge)\s+(\d+)\s*$/ && do { |
||||||
|
my $op; |
||||||
|
my $dest = $2; |
||||||
|
for ($1) { |
||||||
|
/eq/ && ($op="==", last); |
||||||
|
/lt/ && ($op="<", last); |
||||||
|
/le/ && ($op="<=", last); |
||||||
|
/ne/ && ($op="!=", last); |
||||||
|
/gt/ && ($op=">", last); |
||||||
|
/ge/ && ($op=">=", last); |
||||||
|
} |
||||||
|
my $op1 = pop_value("int"); |
||||||
|
new_instr("if ($op1 $op 0) goto $dest;"); |
||||||
|
last INSTR; |
||||||
|
}; |
||||||
|
/^if_icmp(eq|lt|le|ne|gt|ge)\s+(\d+)\s*$/ && do { |
||||||
|
my $op; |
||||||
|
my $dest = $2; |
||||||
|
for ($1) { |
||||||
|
/eq/ && ($op="==", last); |
||||||
|
/lt/ && ($op="<", last); |
||||||
|
/le/ && ($op="<=", last); |
||||||
|
/ne/ && ($op="!=", last); |
||||||
|
/gt/ && ($op=">", last); |
||||||
|
/ge/ && ($op=">=", last); |
||||||
|
} |
||||||
|
my $op2 = pop_value("int"); |
||||||
|
my $op1 = pop_value("int"); |
||||||
|
new_instr("if ($op1 $op $op2) goto $dest;"); |
||||||
|
last INSTR; |
||||||
|
}; |
||||||
|
/^if(null|nonnull)\s+(\d+)\s*$/ && do { |
||||||
|
my $dest = $2; |
||||||
|
my $op; |
||||||
|
for ($1) { |
||||||
|
/notnull/ && ($op="!=", last); |
||||||
|
/null/ && ($op="==", last); |
||||||
|
} |
||||||
|
my $op1 = pop_value("*"); |
||||||
|
new_instr("if ($op1 $op null) goto $dest;"); |
||||||
|
last INSTR; |
||||||
|
}; |
||||||
|
|
||||||
|
do { |
||||||
|
print STDERR "Stack: "; |
||||||
|
&print_stack; |
||||||
|
print STDERR "\nUnknown Instruction: `$_'\n\t"; |
||||||
|
}; |
||||||
|
} |
||||||
|
} |
||||||
|
$addr++; |
||||||
|
$next_instr{$instr_addr} = $addr; |
||||||
|
|
||||||
|
simplify_instructions (0, $addr); |
||||||
|
print_stmtlist(0, $addr, $addr, $addr, 2*$incindent); |
Loading…
Reference in new issue