The following patch moves all parsing of opcode_table into a
Parrot::Opcode module. It also removes all parsing of interp_guts.h.
This patch incorporates my earlier patches to prefix all C opcode
functions with "Perl_op_".
As best I can tell, everything works the same with the patch as it
did before--the assembler and disassembler both generate identical
output, and test_prog runs as well as before. (Or better on FreeBSD,
where it stops core dumping. :>)
- Damien
diff -r --new-file -u 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 -r --new-file -u parrot.orig/assemble.pl parrot/assemble.pl
--- parrot.orig/assemble.pl Mon Sep 10 14:26:08 2001
+++ parrot/assemble.pl Mon Sep 10 23:51:34 2001
@@ -3,6 +3,7 @@
# assemble.pl - take a parrot assembly file and spit out a bytecode file
use strict;
+use Parrot::Opcode;
my(%opcodes, %labels);
@@ -12,23 +13,7 @@
);
my $sizeof_packi = length(pack($pack_type{i},1024));
-open GUTS, "interp_guts.h";
-my $opcode;
-while (<GUTS>) {
- next unless /\tx\[(\d+)\] = ([a-z_]+);/;
- $opcodes{$2}{CODE} = $1;
-}
-
-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+/, $_;
- $opcodes{$name}{ARGS} = $args;
- $opcodes{$name}{TYPES} = [@types];
-}
+%opcodes = Parrot::Opcode::read_ops();
my $pc = 0;
my @code;
diff -r --new-file -u parrot.orig/build_interp_starter.pl
parrot/build_interp_starter.pl
--- parrot.orig/build_interp_starter.pl Mon Sep 10 14:26:09 2001
+++ parrot/build_interp_starter.pl Mon Sep 10 23:53:26 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,16 +17,8 @@
#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 -r --new-file -u parrot.orig/disassemble.pl parrot/disassemble.pl
--- parrot.orig/disassemble.pl Mon Sep 10 14:45:33 2001
+++ parrot/disassemble.pl Mon Sep 10 23:57:36 2001
@@ -7,6 +7,7 @@
use strict;
my(%opcodes, @opcodes);
+use Parrot::Opcode;
my %unpack_type;
%unpack_type = (i => 'l',
@@ -16,28 +17,10 @@
n => 8,
);
-open GUTS, "interp_guts.h";
-my $opcode;
-while (<GUTS>) {
- next unless /\tx\[(\d+)\] = ([a-z_]+);/;
- $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 -r --new-file -u parrot.orig/make_op_header.pl parrot/make_op_header.pl
--- parrot.orig/make_op_header.pl Mon Sep 10 14:26:09 2001
+++ parrot/make_op_header.pl Mon Sep 10 23:53:09 2001
@@ -2,11 +2,13 @@
#
# 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 /\t/, $_;
- 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 -r --new-file -u parrot.orig/process_opfunc.pl parrot/process_opfunc.pl
--- parrot.orig/process_opfunc.pl Mon Sep 10 14:26:09 2001
+++ parrot/process_opfunc.pl Mon Sep 10 23:52:57 2001
@@ -30,40 +30,9 @@
# of the return offset, are taken from the opcode_table file
use strict;
+use Parrot::Opcode;
-my %opcode;
-
-open GUTS, "interp_guts.h";
-my $opcode;
-while (<GUTS>) {
- next unless /\tx\[(\d+)\] = ([a-z_]+);/;
- $opcode{$2}{OPNUM} = $1;
-}
-
-open OPCODE, "opcode_table" or die "Can't open opcode_table, $!/$^E";
-while (<OPCODE>) {
- s/#.*//;
- s/^\s+//;
- chomp;
- next unless $_;
- my ($name, $params, @params) = split /\s+/;
- $opcode{$name}{PARAM_COUNT} = $params;
- $opcode{$name}{PARAM_ARRAY} = \@params;
-
- my $num_i = () = grep {/i/} @params;
- my $num_n = () = grep {/n/} @params;
- $opcode{$name}{RETURN_OFFSET} = 1 + $num_i + $num_n * 2;
- my $count = 1;
- $opcode{$name}{PARAMETER_SUB} = ["",
- map {if ($_ eq "n") {
- my $temp = '*(NV *)&cur_opcode[' . $count .
']';
- $count += 2;
- $temp;
- } else {
- "cur_opcode[" . $count++ . "]"
- }
- } @params];
-}
+my %opcodes = Parrot::Opcode::read_ops();
my $file = $ARGV[0];
open INPUT, $file or die "Can't open $file, $!/$^E";
@@ -72,16 +41,29 @@
}
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;
}
@@ -91,7 +73,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";
@@ -104,17 +86,20 @@
sub emit_auto_header {
my $line = shift;
my ($name) = $line =~ /AUTO_OP\s+(\w+)/;
-
- print OUTPUT "IV *$name(IV cur_opcode[], struct Perl_Interp *interpreter) {\n";
- return($name, " return cur_opcode + "
- . $opcode{$name}{RETURN_OFFSET}. ";\n}\n");
+
+ my $num_i = () = grep {/i/} @{$opcodes{$name}{TYPES}};
+ my $num_n = () = grep {/n/} @{$opcodes{$name}{TYPES}};
+ my $return_offset = 1 + $num_i + $num_n * 2;
+
+ 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");
}