On Fri, Sep 14, 2001 at 10:20:00AM +0100, Simon Cozens wrote:
> On Thu, Sep 13, 2001 at 08:54:40PM -0700, Damien Neil wrote:
> > Here's an updated version of my original patch, to account for recent
> > changes in CVS.  As before, this includes opcode-munging to let Parrot
> > run on FreeBSD.
...
> These three patches didn't apply and I really want them. Hence, I'm
> taking no more patches to:

Third time's the charm, maybe?  The following patch applies cleanly
against CVS.

I changed the opcode munging to match what exists in CVS--
"#define end Parrot_op_end" in the header, rather than simply renaming 
all uses of the function.

I've also added a Parrot::Opcode::fingerprint() function to get the
opcode table fingerprint.

                           - Damien


diff --new-file -r -u old/parrot/Parrot/Opcode.pm parrot/Parrot/Opcode.pm
--- old/parrot/Parrot/Opcode.pm Wed Dec 31 16:00:00 1969
+++ parrot/Parrot/Opcode.pm     Fri Sep 14 10:29:59 2001
@@ -0,0 +1,192 @@
+package Parrot::Opcode;
+
+use strict;
+use Symbol;
+use Digest::MD5 qw(&md5_hex);
+
+our %opcode;
+our $fingerprint;
+
+sub _load {
+    my $file = @_ ? shift : "opcode_table";
+
+    my $fh = gensym;
+    open $fh, $file or die "$file: $!\n";
+
+    my $md5 = Digest::MD5->new;
+    my $count = 1;
+    while (<$fh>) {
+       $md5->add($_);
+
+       s/#.*//;
+       s/^\s+//;
+       chomp;
+       next unless $_;
+
+       my($name, @params) = split /\s+/;
+       if (@params && $params[0] =~ /^\d+$/) {
+           my $count = shift @params;
+           die "$file, line $.: opcode $name parameters don't match count\n"
+             if ($count != @params);
+       }
+
+       warn "$file, line $.: opcode $name redefined\n" if $opcode{$name};
+
+       $opcode{$name}{ARGS}  = @params;
+       $opcode{$name}{TYPES} = \@params;
+       $opcode{$name}{CODE}  = ($name eq "end") ? 0 : $count++;
+       $opcode{$name}{FUNC}  = $name;
+
+       my $num_i = () = grep {/i/} @params;
+       my $num_n = () = grep {/n/} @params;
+       $opcode{$name}{RETURN_OFFSET} = 1 + $num_i + $num_n * 2;
+    }
+
+    $fingerprint = $md5->hexdigest;
+}
+
+sub read_ops {
+    _load(@_) unless defined $fingerprint;
+    return %opcode;
+}
+
+
+sub fingerprint {
+    _load(@_) unless defined $fingerprint;
+    return $fingerprint;
+}
+
+1;
+
+
+__END__
+
+=head1 NAME
+
+Parrot::Opcode - Read opcode definitions
+
+=head1 SYNOPSIS
+
+  use Parrot::Opcode;
+
+  %opcodes = Parrot::Opcode::read_ops();
+
+=head1 DESCRIPTION
+
+The read_ops() function parses the Parrot opcode_table file, and
+returns the contents as a hash.  The hash key is the opcode name;
+values are hashrefs containing the following fields:
+
+=over
+
+=item CODE
+
+The opcode number.
+
+=item ARGS
+
+The opcode argument count.
+
+=item TYPES
+
+The opcode argument types, as an arrayref.
+
+=item FUNC
+
+The name of the C function implementing this op.
+
+=back
+
+read_ops() takes an optional argument: the file to read the opcode table
+from.
+
+The fingerprint() function returns the MD5 signature (in hex) of the
+opcode table.
+
+=cut
+package Parrot::Opcode;
+
+use strict;
+use Symbol;
+
+sub read_ops {
+    my $file = @_ ? shift : "opcode_table";
+
+    my $fh = gensym;
+    open $fh, $file or die "$file: $!\n";
+
+    my %opcode;
+    my $count = 1;
+    while (<$fh>) {
+       s/#.*//;
+       s/^\s+//;
+       chomp;
+       next unless $_;
+
+       my($name, @params) = split /\s+/;
+       if (@params && $params[0] =~ /^\d+$/) {
+           my $count = shift @params;
+           die "$file, line $.: opcode $name parameters don't match count\n"
+             if ($count != @params);
+       }
+
+       warn "$file, line $.: opcode $name redefined\n" if $opcode{$name};
+
+       $opcode{$name}{ARGS}  = @params;
+       $opcode{$name}{TYPES} = \@params;
+       $opcode{$name}{CODE}  = ($name eq "end") ? 0 : $count++;
+       $opcode{$name}{FUNC}  = "Parrot_op_$name";
+
+       my $num_i = () = grep {/i/} @params;
+       my $num_n = () = grep {/n/} @params;
+       $opcode{$name}{RETURN_OFFSET} = 1 + $num_i + $num_n * 2;
+    }
+
+    return %opcode;
+}
+
+1;
+
+
+__END__
+
+=head1 NAME
+
+Parrot::Opcode - Read opcode definitions
+
+=head1 SYNOPSIS
+
+  use Parrot::Opcode;
+
+  %opcodes = Parrot::Opcode::read_ops();
+
+=head1 DESCRIPTION
+
+The read_ops() function parses the Parrot opcode_table file, and
+returns the contents as a hash.  The hash key is the opcode name;
+values are hashrefs containing the following fields:
+
+=over
+
+=item CODE
+
+The opcode number.
+
+=item ARGS
+
+The opcode argument count.
+
+=item TYPES
+
+The opcode argument types, as an arrayref.
+
+=item FUNC
+
+The name of the C function implementing this op.
+
+=back
+
+read_ops() takes an optional argument: the file to read the opcode table
+from.
+
+=cut
diff --new-file -r -u old/parrot/assemble.pl parrot/assemble.pl
--- old/parrot/assemble.pl      Fri Sep 14 10:27:48 2001
+++ parrot/assemble.pl  Fri Sep 14 10:27:33 2001
@@ -7,6 +7,7 @@
 use strict;
 use Digest::MD5 qw(&md5_hex);
 use Getopt::Long;
+use Parrot::Opcode;
 
 my %options;
 GetOptions(\%options,('checksyntax',
@@ -56,40 +57,12 @@
 foreach (keys(%real_type)) {
     $sizeof{$_}=length(pack($pack_type{$real_type{$_}},0));
 }
-                
 
-# get opcodes from guts.
-open(GUTS, "<interp_guts.h") or
-  open(GUTS, "<../interp_guts.h") or
-  die "Can't get opcodes from guts, $!/$^E";
-my %opcodes;
-while (<GUTS>) {
-    next unless /\tx\[(\d+)\] = ([a-z0-9_]+);/;
-    $opcodes{$2}{CODE} = $1;
-}
-close GUTS;
 
-# get opcodes and their arg lists
-open(OPCODES, "<opcode_table") or
-  open(OPCODES, "<../opcode_table") or
-  die "Can't get opcode table, $!/$^E";
-my $opcode_table;
-while (<OPCODES>) {
-    $opcode_table .= $_;
-    next if /^\s*#/;
-    chomp;
-    s/^\s+//;
-    next unless $_;
-    my ($name, $args, @types) = split /\s+/, $_;
-    my @rtypes=@types;
-    @types=map { $_ = $real_type{$_}} @types;
-    $opcodes{$name}{ARGS} = $args;
-    $opcodes{$name}{TYPES} = [@types];
-    $opcodes{$name}{RTYPES}=[@rtypes];
-}
-close OPCODES;
-my $opcode_fingerprint = md5_hex($opcode_table);
-constantize($opcode_fingerprint); # Make it constant zero.
+# get opcodes
+my %opcodes = Parrot::Opcode::read_ops();
+
+constantize(Parrot::Opcode::fingerprint()); # Make it constant zero.
 
 my $listing="PARROT ASSEMBLY LISTING - ".scalar(localtime)."\n\n";
 
@@ -183,8 +156,8 @@
         $pc+=4;
 
         foreach (0..$#args) {
-            my($rtype)=$opcodes{$opcode}{RTYPES}[$_];
-            my($type)=$opcodes{$opcode}{TYPES}[$_];
+            my($rtype)=$opcodes{$opcode}{TYPES}[$_];
+            my($type)=$real_type{$opcodes{$opcode}{TYPES}[$_]};
             if($rtype eq "I" || $rtype eq "N" || $rtype eq "P" || $rtype eq "S") {
                 # its a register argument
                 $args[$_]=~s/^[INPS](\d+)$/$1/i;
diff --new-file -r -u old/parrot/build_interp_starter.pl parrot/build_interp_starter.pl
--- old/parrot/build_interp_starter.pl  Fri Sep 14 10:27:48 2001
+++ parrot/build_interp_starter.pl      Fri Sep 14 10:31:26 2001
@@ -1,11 +1,10 @@
 # !/usr/bin/perl -w
 use strict;
 use Digest::MD5 qw(&md5_hex);
+use Parrot::Opcode;
 
 open INTERP, "> interp_guts.h" or die "Can't open interp_guts.h, $!/$^E";
 
-open OPCODES, "opcode_table" or die "Can't open opcode_table, $!/$^E";
-
 print INTERP <<CONST;
 /*
  *
@@ -19,24 +18,13 @@
 #define BUILD_TABLE(x) do { \\
 CONST
 
-my $opcode_table;
-my $count = 1;
-while (<OPCODES>) {
-    $opcode_table .= $_;
-    chomp;
-    s/#.*$//;
-    s/^\s+//;
-    next unless $_;
-    my($name) = split /\s+/;
-    my $num = $count;
-    $num = 0 if $name eq 'end';
-    print INTERP "\tx[$num] = $name; \\\n";
-    $count++ unless $name eq 'end';
+my %opcodes            = Parrot::Opcode::read_ops();
+my $opcode_fingerprint = Parrot::Opcode::fingerprint();
+
+for my $name (sort {$opcodes{$a}{CODE} <=> $opcodes{$b}{CODE}} keys %opcodes) {
+    print INTERP "\tx[$opcodes{$name}{CODE}] = $name; \\\n";
 }
-close OPCODES;
-my $opcode_fingerprint = md5_hex($opcode_table);
 print INTERP "} while (0);\n";
-
 
 # Spit out the DO_OP function
 print INTERP <<EOI;
diff --new-file -r -u old/parrot/disassemble.pl parrot/disassemble.pl
--- old/parrot/disassemble.pl   Fri Sep 14 10:27:48 2001
+++ parrot/disassemble.pl       Fri Sep 14 10:34:19 2001
@@ -6,8 +6,7 @@
 
 use strict;
 use Digest::MD5 qw(&md5_hex);
-
-my(%opcodes, @opcodes);
+use Parrot::Opcode;
 
 my %unpack_type = (i => 'l',
                   I => 'l',
@@ -26,32 +25,13 @@
                   s => 4,
                   );
 
-open GUTS, "interp_guts.h";
-my $opcode;
-while (<GUTS>) {
-    next unless /\tx\[(\d+)\] = ([a-z0-9_]+);/;
-    $opcodes{$2}{CODE} = $1;
-}
-
-my $opcode_table;
-open OPCODES, "<opcode_table" or die "Can't get opcode table, $!/$^E";
-while (<OPCODES>) {
-    $opcode_table .= $_;
-    next if /^\s*#/;
-    s/^\s+//;
-    chomp;
-    next unless $_;
-    my ($name, $args, @types) = split /\s+/, $_;
-    next unless defined $name;
-    $opcodes{$name}{ARGS} = $args;
-    $opcodes{$name}{TYPES} = [@types];
-    my $code = $opcodes{$name}{CODE};
-    $opcodes[$code] = {NAME => $name,
-                      ARGS => $args,
-                      TYPES => [@types]
-                      }
+my %opcodes            = Parrot::Opcode::read_ops();
+my $opcode_fingerprint = Parrot::Opcode::fingerprint();
+my @opcodes;
+for my $name (keys %opcodes) {
+    $opcodes[$opcodes{$name}{CODE}] = { NAME => $name,
+                                       %{$opcodes{$name}} };
 }
-my $opcode_fingerprint = md5_hex($opcode_table);
 
 $/ = \4;
 
diff --new-file -r -u old/parrot/make_op_header.pl parrot/make_op_header.pl
--- old/parrot/make_op_header.pl        Fri Sep 14 10:27:48 2001
+++ parrot/make_op_header.pl    Fri Sep 14 10:35:47 2001
@@ -2,10 +2,10 @@
 # 
 # rip through opcode_table and spit out a chunk of C header for the
 # functions in it
-while (<>) {
-    next if /^\s*#/ or /^\s*$/;
-    chomp;
-    ($name, undef) = split /\s+/, $_;
+use strict;
+use Parrot::Opcode;
+my %opcodes = Parrot::Opcode::read_ops();
+for my $name (sort {$opcodes{$a}{CODE} <=> $opcodes{$b}{CODE}} keys %opcodes) {
     print "#define $name Parrot_op_$name\n";
     print "IV *$name(IV *, struct Perl_Interp *);\n";
 }
diff --new-file -r -u old/parrot/process_opfunc.pl parrot/process_opfunc.pl
--- old/parrot/process_opfunc.pl        Wed Sep 12 16:12:00 2001
+++ parrot/process_opfunc.pl    Fri Sep 14 10:12:18 2001
@@ -30,6 +30,9 @@
 # of the return offset, are taken from the opcode_table file
 
 use strict;
+use Parrot::Opcode;
+
+my %opcodes = Parrot::Opcode::read_ops();
 
 my %opcode;
 
@@ -87,16 +90,28 @@
 }
 open OUTPUT, ">$file" or die "Can't open $file, $!/$^E";
 
-my($name, $footer);
+my($name, $footer, @param_sub);
 while (<INPUT>) {
 
     if (/^AUTO_OP/) {
        ($name, $footer) = emit_auto_header($_);
-       next;
     }
 
     if (/^MANUAL_OP/) {
        ($name, $footer) = emit_manual_header($_);
+    }
+
+    if (/^(AUTO|MANUAL)_OP/) {
+       my $count = 1;
+       @param_sub = ("",
+                     map {if ($_ eq "n") {
+                         my $temp = '*(NV *)&cur_opcode[' . $count . ']';
+                         $count += 2;
+                         $temp;
+                     } else {
+                         "cur_opcode[" . $count++ . "]"
+                     }
+                      } @{$opcodes{$name}{TYPES}});
        next;
     }
 
@@ -106,7 +121,7 @@
 
     s/RETURN\((.*)\)/return cur_opcode + $1/;
 
-    s/\bP(\d+)\b/$opcode{$name}{PARAMETER_SUB}[$1]/g;
+    s/\bP(\d+)\b/$param_sub[$1]/g;
 
     if (/^}/) {
         print OUTPUT $footer, "\n";
@@ -119,17 +134,26 @@
 sub emit_auto_header {
     my $line = shift;
     my ($name) = $line =~ /AUTO_OP\s+(\w+)/;
+
+    my $psize=0;
+    foreach (@{$opcodes{$name}{TYPES}}) {
+       $psize+=$psize{$_};
+    }
+    my $return_offset = $psize + 1;
+
+    $opcode{$name}{RETURN_OFFSET} = 1 + $psize;
     
-    print OUTPUT "IV *$name(IV cur_opcode[], struct Perl_Interp *interpreter) {\n";
-    return($name, "  return cur_opcode + "
-    . $opcode{$name}{RETURN_OFFSET}. ";\n}\n");
+    print OUTPUT ("IV *$opcodes{$name}{FUNC}".
+                 "(IV cur_opcode[], struct Perl_Interp *interpreter) {\n");
+    return($name, "  return cur_opcode + " . $return_offset . ";\n}\n");
 }
 
 sub emit_manual_header {
     my $line = shift;
     my ($name) = $line =~ /MANUAL_OP\s+(\w+)/;
     
-    print OUTPUT "IV *$name(IV cur_opcode[], struct Perl_Interp *interpreter) {\n";
+    print OUTPUT ("IV *$opcodes{$name}{FUNC}".
+                 "(IV cur_opcode[], struct Perl_Interp *interpreter) {\n");
     print OUTPUT "  IV return_offset = 1;\n";
     return($name, "  return cur_opcode + return_offset;\n}\n");
 }

Reply via email to