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.

                          - Damien


diff -u --new-file -r parrot.orig/Parrot/Opcode.pm parrot/Parrot/Opcode.pm
--- parrot.orig/Parrot/Opcode.pm        Wed Dec 31 16:00:00 1969
+++ parrot/Parrot/Opcode.pm     Mon Sep 10 23:52:35 2001
@@ -0,0 +1,86 @@
+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 -u --new-file -r parrot.orig/assemble.pl parrot/assemble.pl
--- parrot.orig/assemble.pl     Thu Sep 13 20:45:05 2001
+++ parrot/assemble.pl  Thu Sep 13 20:33:36 2001
@@ -5,6 +5,7 @@
 # Brian Wheeler ([EMAIL PROTECTED])
 
 use strict;
+use Parrot::Opcode;
 
 my $opt_c;
 if (@ARGV and $ARGV[0] eq "-c") {
@@ -25,32 +26,10 @@
 foreach (keys(%real_type)) {
     $sizeof{$_}=length(pack($pack_type{$real_type{$_}},0));
 }
-                
 
-# get opcodes from guts.
-open GUTS, "interp_guts.h";
-my %opcodes;
-while (<GUTS>) {
-    next unless /\tx\[(\d+)\] = ([a-z_]+);/;
-    $opcodes{$2}{CODE} = $1;
-}
-close GUTS;
 
-# get opcodes and their arg lists
-open OPCODES, "<opcode_table" or die "Can't get opcode table, $!/$^E";
-while (<OPCODES>) {
-    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;
+# get opcodes
+my %opcodes = Parrot::Opcode::read_ops();
 
 
 # read source and assemble
@@ -134,8 +113,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 -u --new-file -r parrot.orig/build_interp_starter.pl 
parrot/build_interp_starter.pl
--- parrot.orig/build_interp_starter.pl Thu Sep 13 20:45:05 2001
+++ parrot/build_interp_starter.pl      Thu Sep 13 20:36:14 2001
@@ -1,10 +1,9 @@
 # !/usr/bin/perl -w
 use strict;
+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;
 /*
  *
@@ -18,17 +17,9 @@
 #define BUILD_TABLE(x) do { \\
 CONST
 
-my $count = 1;
-while (<OPCODES>) {
-    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();
+for my $name (sort {$opcodes{$a}{CODE} <=> $opcodes{$b}{CODE}} keys %opcodes) {
+    print INTERP "\tx[$opcodes{$name}{CODE}] = $opcodes{$name}{FUNC}; \\\n";
 }
 print INTERP "} while (0);\n";
 
diff -u --new-file -r parrot.orig/disassemble.pl parrot/disassemble.pl
--- parrot.orig/disassemble.pl  Thu Sep 13 20:45:05 2001
+++ parrot/disassemble.pl       Thu Sep 13 20:37:47 2001
@@ -5,6 +5,7 @@
 # Turn a parrot bytecode file into text
 
 use strict;
+use Parrot::Opcode;
 
 my(%opcodes, @opcodes);
 
@@ -25,28 +26,10 @@
                   s => 4,
                   );
 
-open GUTS, "interp_guts.h";
-my $opcode;
-while (<GUTS>) {
-    next unless /\tx\[(\d+)\] = ([a-z0-9_]+);/;
-    $opcodes{$2}{CODE} = $1;
-}
-
-open OPCODES, "<opcode_table" or die "Can't get opcode table, $!/$^E";
-while (<OPCODES>) {
-    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]
-                      }
+%opcodes = Parrot::Opcode::read_ops();
+for my $name (keys %opcodes) {
+    $opcodes[$opcodes{$name}{CODE}] = { NAME => $name,
+                                       %{$opcodes{$name}} };
 }
 
 $/ = \4;
diff -u --new-file -r parrot.orig/make_op_header.pl parrot/make_op_header.pl
--- parrot.orig/make_op_header.pl       Thu Sep 13 20:45:06 2001
+++ parrot/make_op_header.pl    Thu Sep 13 20:38:51 2001
@@ -2,11 +2,12 @@
 # 
 # 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+/, $_;
-    print "IV *$name(IV *, struct Perl_Interp *);\n";
+use strict;
+use Parrot::Opcode;
+
+my %opcodes = Parrot::Opcode::read_ops();
+for my $name (sort {$opcodes{$a}{CODE} <=> $opcodes{$b}{CODE}} keys %opcodes) {
+    print "IV *$opcodes{$name}{FUNC}(IV *, struct Perl_Interp *);\n";
 }
 
 BEGIN {
diff -u --new-file -r parrot.orig/process_opfunc.pl parrot/process_opfunc.pl
--- parrot.orig/process_opfunc.pl       Thu Sep 13 20:45:06 2001
+++ parrot/process_opfunc.pl    Thu Sep 13 20:47:57 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