Index: tools/build/ops2pm.pl =================================================================== --- tools/build/ops2pm.pl (revision 16899) +++ tools/build/ops2pm.pl (working copy) @@ -1,8 +1,48 @@ #! perl - # Copyright (C) 2001-2004, The Perl Foundation. # $Id$ +use warnings; +use strict; +use Getopt::Long; +use lib 'lib'; +use Parrot::Ops2pm::Utils; +use Parrot::Ops2pm::Auxiliary qw( Usage getoptions ); +my $flagref = getoptions(); + +if ($flagref->{help} or ! @ARGV) { + Usage(); + exit; +} + +my $self = Parrot::Ops2pm::Utils->new( { + argv => [ @ARGV ], + nolines => $flagref->{nolines}, + renum => $flagref->{renum}, + moddir => "lib/Parrot/OpLib", + module => "core.pm", + inc_dir => "include/parrot/oplib", + inc_f => "ops.h", + script => "tools/build/ops2pm.pl", +} ); + +$self->prepare_ops(); + +if ($flagref->{renum}) { + $self->renum_op_map_file(); + exit 0; +} + +$self->load_op_map_files(); +$self->sort_ops(); +$self->prepare_real_ops(); +$self->print_module(); +$self->print_h(); + +exit 0; + +################### DOCUMENTATION #################### + =head1 NAME tools/build/ops2pm.pl - Generate Perl module from operation definitions @@ -15,10 +55,15 @@ =head1 DESCRIPTION Reads the ops files listed on the command line and outputs a -C module containing information about the ops. +F module containing information about the ops. +Also outputs F. This program is called by Parrot's +F. -=head2 Options +If called with the C<--renum> flag, checks the numbering of ops against +F. +=head1 OPTIONS + =over 4 =item C<--help> @@ -36,8 +81,14 @@ =back -=head2 WARNING +Most of the functionality in this program is now held in Parrot::Ops2pm::Util +methods and a small number of Parrot::Ops2pm::Auxiliary subroutines. +See those modules' documentation for discussion of those functions. +Revisions to the functionality should be made in those packages and tested +against tests found in F. +=head1 WARNING + Generating a C module for a set of ops files that you do not later turn into C code (see F) with the same op content and order is a recipe for disaster. But as long as you @@ -71,374 +122,47 @@ =item F. -=back +=item F. -=cut +=item F. -use warnings; -use strict; -use lib 'lib'; +=item F. -use Data::Dumper; -$Data::Dumper::Useqq = 1; +=back -#$Data::Dumper::Terse = 1; -#$Data::Dumper::Indent = 0; -use Getopt::Long; +=head1 AUTHOR -use Parrot::OpsFile; +Over the years, F has been worked on by the following Parrot hackers: -# -# Look at the command line options -# + bernhard + brentdax + chip + chromatic + coke + dan + gregor + jkeenan + leo + mikescott + particle + paultcochrane + petdance + robert + simon + tewk -# TODO: Use Pod::Usage -my ( $nolines_flag, $help_flag, $renum_flag ); -GetOptions( - "no-lines" => \$nolines_flag, - "help" => \$help_flag, - "renum" => \$renum_flag, -); +Others who provided code cited in the version control logs include: -sub Usage { - print STDERR <<_EOF_; -usage: $0 [--help] [--no-lines] input.ops [input2.ops ...] -_EOF_ - exit; - return; -} + Andy Dougherty + Jeff Gof + Steve Fink + +=cut -Usage() if $help_flag; -Usage() unless @ARGV; - -# -# Read in the first ops file. -# - -my $package = "core"; -my $moddir = "lib/Parrot/OpLib"; -my $module = "$moddir/core.pm"; - -my $file = shift @ARGV; -die "$0: Could not find ops file '$file'!\n" unless -e $file; -my $ops = Parrot::OpsFile->new( [$file], $nolines_flag ); -die "$0: Could not read ops file '$file'!\n" unless defined $ops; - -# -# Copy the ops from the remaining .ops files to the object just created. -# - -my %seen; - -for $file (@ARGV) { - if ( $seen{$file} ) { - print STDERR "$0: Ops file '$file' mentioned more than once!\n"; - next; - } - $seen{$file} = 1; - - die "$0: Could not find ops file '$file'!\n" unless -e $file; - my $temp_ops = Parrot::OpsFile->new( [$file], $nolines_flag ); - die "$0: Could not read ops file '$file'!\n" unless defined $temp_ops; - - die "OPS invalid for $file" unless ref $temp_ops->{OPS}; - - my $experimental = $file =~ /experimental/; - - # mark experimental ops - if ($experimental) { - for $_ ( @{ $temp_ops->{OPS} } ) { - $_->{experimental} = 1; - } - } - - push @{ $ops->{OPS} }, @{ $temp_ops->{OPS} }; - $ops->{PREAMBLE} .= "\n" . $temp_ops->{PREAMBLE}; -} - -# Renumber ops/num based on old ops.num and *.ops -if ($renum_flag) { - renum_op_map_file($ops); - exit 0; -} - -# else check strictly against ops.num and renumber -else { - load_op_map_files(); - - my $cur_code = 0; - for ( @{ $ops->{OPS} } ) { - $_->{CODE} = find_op_number( $_->full_name, $_->{experimental} ); - } - - @{ $ops->{OPS} } = sort { $a->{CODE} <=> $b->{CODE} } ( @{ $ops->{OPS} } ); -} - -# create opsfile with valid ops from ops.num -# or from experimental - -my $real_ops = Parrot::OpsFile->new( [], $nolines_flag ); -$real_ops->{PREAMBLE} = $ops->{PREAMBLE}; -$real_ops->version( $ops->version ); - -# verify opcode numbers -my $seq = 0; -for ( @{ $ops->{OPS} } ) { - next if ( $_->{CODE} < 0 ); # skip - my $opname = $_->full_name; - my $n = $ParrotOps::optable{$opname}; - if ( $n != $_->{CODE} ) { - die "op $opname: number mismatch: ops.num $n vs. core.ops $_->{CODE}"; - } - if ( $seq != $_->{CODE} ) { - die "op $opname: sequence mismatch: ops.num $seq vs. core.ops $_->{CODE}"; - } - push @{ $real_ops->{OPS} }, $_; - ++$seq; -} - -# Open the output file: -if ( !-d $moddir ) { - mkdir( $moddir, 0755 ) or die "$0: Could not mkdir $moddir: $!!\n"; -} -open my $MODULE, '>', $module - or die "$0: Could not open module file '$module' for writing: $!!\n"; - -# -# Print the preamble for the MODULE file: -# - -my $version = $real_ops->version(); - -# Hide the pod. - -( my $pod = <<"END_POD") =~ s/^ //osmg; - =head1 NAME - - Parrot::OpLib::$package - Parrot Op Info - - =head1 DESCRIPTION - - This is an autogenerated file, created by F<$0>. - - It contains Parrot version info, a preamble for inclusion in C code, - and an array of C instances representing the Parrot ops. - - =cut -END_POD - -my $preamble = <Dump( [ $real_ops->preamble, [ $real_ops->ops ] ], - [qw($preamble $ops)] ); - -print $MODULE <', $inc_f or die "Can't write $inc_f: $!"; - -print $OUT <{OPS} } ) { - my $opname = $_->full_name; - my $n = $_->{CODE}; - my $comma = $n < @{ $real_ops->{OPS} } - 1 ? "," : ""; - $opname = "PARROT_OP_$opname$comma"; - - printf $OUT " %-30s\t/* %4d */\n", $opname, $n; -} - -print $OUT <) { - push @lines, $_ if $fix; - chomp; - $fix = 0 if /^###DYNAMIC###/; - s/#.*$//; - s/\s*$//; - s/^\s*//; - next unless $_; - ( $name, $number ) = split( /\s+/, $_ ); - $seen{$name} = $number; - $fixed{$name} = $number if ($fix); - } - close $OP; - open $OP, '>', $file or die "Can't open $file, error $!"; - print $OP @lines; - my ($n); - - # - # we can't use all autogenerated ops from oplib/core - # there are unwanted permutations like 'add_i_ic_ic - # which aren't opcodes but calced at compile-time - # - - for ( @{ $ops->{OPS} } ) { - if ( defined $fixed{ $_->full_name } ) { - $n = $fixed{ $_->full_name }; - } - elsif ( $seen{ $_->full_name } ) { - printf $OP "%-31s%4d\n", $_->full_name, ++$n; - } - } - close $OP; - - return; -} - -sub load_op_map_files { - my $num_file = "src/ops/ops.num"; - my $skip_file = "src/ops/ops.skip"; - - my ( $op, $name, $number, $prev ); - - $ParrotOps::max_op_num ||= 0; - - open $op, '<', $num_file - or die "Can't open $num_file: $!"; - $prev = -1; - while (<$op>) { - chomp; - s/#.*$//; - s/\s*$//; - s/^\s*//; - next unless $_; - ( $name, $number ) = split( /\s+/, $_ ); - if ( $prev + 1 != $number ) { - die "hole in ops.num before #$number"; - } - if ( exists $ParrotOps::optable{$name} ) { - die "duplicate opcode $name and $number"; - } - $prev = $number; - $ParrotOps::optable{$name} = $number; - if ( $number > $ParrotOps::max_op_num ) { - $ParrotOps::max_op_num = $number; - } - } - undef $op; - - open $op, '<', $skip_file - or die "Can't open $skip_file: $!"; - while (<$op>) { - chomp; - s/#.*$//; - s/\s*$//; - s/^\s*//; - next unless $_; - ($name) = split( /\s+/, $_ ); - if ( exists $ParrotOps::optable{$name} ) { - die "skipped opcode is also in $num_file"; - } - $ParrotOps::skiptable{$name} = 1; - } - undef $op; - - return; -} - -exit 0; - # Local Variables: # mode: cperl # cperl-indent-level: 4 # fill-column: 100 # End: # vim: expandtab shiftwidth=4: