Index: classes/pmc2c2.pl
===================================================================
RCS file: /cvs/public/parrot/classes/pmc2c2.pl,v
retrieving revision 1.14
diff -u -2 -r1.14 pmc2c2.pl
--- classes/pmc2c2.pl	15 Aug 2004 10:08:58 -0000	1.14
+++ classes/pmc2c2.pl	21 Aug 2004 16:11:01 -0000
@@ -25,4 +25,10 @@
     % perl classes/pmc2c2.pl -c classes/foo.pmc ...
 
+Create fooX.c and pmc_fooX.h from fooX.dump files, also create libfoo.c
+containing the initialization function for all fooX PMCs.
+
+    % perl classes/pmc2c2.pl --library libfoo -c \
+           classes/foo1.pmc classes/foo2.pmc ...
+
 =head1 DESCRIPTION
 
@@ -54,4 +60,10 @@
 Specify include path where to find PMCs.
 
+=item C<--library=libname>
+
+Specifiy the library name. This will create E<lt>libnameE<gt>.c and
+pmc_E<lt>libnameE<gt>.h. The initialization function will be named
+after libname and will initialize all PMCs in the library.
+
 =back
 
@@ -562,33 +574,15 @@
     my $include = shift;
     my (@files) = @_;
-    foreach my $file (@files) {
-	my $class = read_dump($include, $file);
-        # finally append vtable.dump
-        $class->{vtable} = read_dump($include, "vtable.pmc");
-	my $generator = Parrot::Pmc2c->new($class, \%opt);
-	print Data::Dumper->Dump([$generator]) if $opt{debug} > 1;
-
-	my $hout = $generator->gen_h($file);
-        print $hout if $opt{debug};
-        my $h;
-        ($h = $file) =~ s/\.\w+$/.h/;
-        $h =~ s/(\w+)\.h$/pmc_$1.h/;
-        print "Writing $h\n" if $opt{verbose};
-        open H, ">$h" or die "Can't write '$h";
-        print H $hout;
-        close H;
-	my $cout = $generator->gen_c($file);
-        print $cout if $opt{debug};
-        my $c;
-        ($c = $file) =~ s/\.\w+$/.c/;
-        print "Writing $c\n" if $opt{verbose};
-        open C, ">$c" or die "Can't write '$c";
-        print C $cout;
-        close C;
-    }
+
+    my $library = Parrot::Pmc2c::Library->new
+      ( \%opt, read_dump($include, "vtable.pmc"),
+        map { $_, read_dump($include, $_) }
+            @files );
+
+    $library->write_all_files;
 }
 
 sub main {
-    my ($default, $dump, $gen_c, $result, $tree, $debug, $verbose, $nobody, $nolines, @include);
+    my ($default, $dump, $gen_c, $result, $tree, $debug, $verbose, $nobody, $nolines, @include, $library);
     $result = GetOptions(
 	"vtable"        => \$default,
@@ -601,4 +595,5 @@
 	"verbose+"      => \$verbose,
         "include=s"     => \@include,
+        "library=s"     => \$library,
     );
     $opt{debug} = $debug || 0;
@@ -606,5 +601,6 @@
     $opt{nobody} = $nobody || 0;
     $opt{nolines} = $nolines || 0;
-    unshift @include, "$FindBin::Bin/..", $FindBin::Bin;
+    $opt{library} = $library;
+    unshift @include, ".", "$FindBin::Bin/..", $FindBin::Bin;
 
     $default and do {
Index: dynclasses/foo.pmc
===================================================================
RCS file: /cvs/public/parrot/dynclasses/foo.pmc,v
retrieving revision 1.3
diff -u -2 -r1.3 foo.pmc
--- dynclasses/foo.pmc	25 Aug 2003 09:46:29 -0000	1.3
+++ dynclasses/foo.pmc	21 Aug 2004 16:11:04 -0000
@@ -5,9 +5,4 @@
 #include "parrot/parrot.h"
 
-/*
- * the real class enum is created at load time
- */
-#define enum_class_Foo -1
-
 pmclass Foo dynpmc {
 
Index: lib/Parrot/Pmc2c.pm
===================================================================
RCS file: /cvs/public/parrot/lib/Parrot/Pmc2c.pm,v
retrieving revision 1.37
diff -u -2 -r1.37 Pmc2c.pm
--- lib/Parrot/Pmc2c.pm	17 Aug 2004 08:50:48 -0000	1.37
+++ lib/Parrot/Pmc2c.pm	21 Aug 2004 16:11:16 -0000
@@ -106,10 +106,10 @@
 }
 
-=item C<dynext_load_code($classname, $call_class_init)>
+=item C<dynext_load_code($library_name, @classes)>
 
-C<$classname> is the name of a PMC.
+C<$library_name> is the name of the dynamic library to be created.
 
-C<$call_class_init> is the C code for a call to the PMC's class
-initialization method.
+C<@classes> are the names of the PMCs for which initialization
+code is to be generated.
 
 This function is exported.
@@ -118,19 +118,38 @@
 
 sub dynext_load_code {
-    my ($classname, $call_class_init ) = @_;
-    my $lc_classname = lc $classname;
-    return <<"EOC";
+    my ($libname, @classes ) = @_;
+    my $lc_libname = lc $libname;
+    my $cout;
+
+    $cout .= <<"EOC";
 /*
  * This load function will be called to do global (once) setup
  * whatever is needed to get this extension running
  */
+#include "parrot/parrot.h"
+#include "parrot/extend.h"
 #include "parrot/dynext.h"
 
-PMC* Parrot_lib_${lc_classname}_load(Interp *interpreter); /* don't warn */
-PMC* Parrot_lib_${lc_classname}_load(Interp *interpreter)
+EOC
+    foreach my $class (@classes) {
+        my $lc_class = lc $class;
+        $cout .= <<"EOC";
+#include "pmc_${lc_class}.h"
+EOC
+    }
+    $cout .= <<"EOC";
+
+Parrot_PMC Parrot_lib_${lc_libname}_load(Parrot_INTERP interpreter); /* don't warn */
+Parrot_PMC Parrot_lib_${lc_libname}_load(Parrot_INTERP interpreter)
 {
-    STRING *whoami;
-    PMC *pmc;
-    INTVAL type;
+    Parrot_STRING whoami;
+    Parrot_PMC pmc;
+EOC
+    foreach my $class (@classes) {
+        $cout .= <<"EOC";
+    Parrot_Int type${class};
+EOC
+    }
+    $cout .= <<"EOC";
     int pass;
 
@@ -146,10 +165,25 @@
      * for all PMCs we want to register:
      */
-    whoami = string_from_cstring(interpreter, "$classname", 0);
-    type = pmc_register(interpreter, whoami);
+EOC
+    foreach my $class (@classes) {
+        $cout .= <<"EOC";
+    whoami = string_from_cstring(interpreter, "$class", 0);
+    type${class} = pmc_register(interpreter, whoami);
+EOC
+    }
+    $cout .= <<"EOC";
+
     /* do class_init code */
     for (pass = 0; pass <= 1; ++pass) {
-        $call_class_init
+EOC
+    foreach my $class (@classes) {
+        my $lc_class = lc $class;
+        $cout .= <<"EOC";
+        Parrot_${class}_class_init(interpreter, type$class, pass);
+EOC
     }
+    $cout .= <<"EOC";
+    }
+
     return pmc;
 }
@@ -321,5 +355,5 @@
     }
     return <<"EOC";
-$extern$ret${newl}Parrot_${classname}_$meth(Parrot_Interp$interp, PMC*$pmc$args)$semi
+$extern$ret${newl}Parrot_${classname}_$meth(Interp*$interp, PMC*$pmc$args)$semi
 EOC
 }
@@ -498,8 +532,5 @@
     my $self = shift;
     my $classname = $self->{class};
-    # TODO multiple (e.g. Const subclasses)
-    my $call_class_init =
-        "Parrot_${classname}_class_init(interpreter, type, pass);\n";
-    return dynext_load_code($classname, $call_class_init);
+    return dynext_load_code($classname, $classname);
 }
 
@@ -618,11 +649,4 @@
     */
 EOC
-    # init vtable slot
-    if ($self->{flags}{dynpmc}) {
-        $cout .= <<"EOC";
-
-    temp_base_vtable.base_type = entry;
-EOC
-    }
     # declare auxiliary variables for dyncpmc IDs
     foreach my $dynclass (keys %init_mmds) {
@@ -632,4 +656,11 @@
 EOC
     }
+    # init vtable slot
+    if ($self->{flags}{dynpmc}) {
+        $cout .= <<"EOC";
+
+    temp_base_vtable.base_type = entry;
+EOC
+    }
     # init MMD "right" slots with the dynpmc types
     foreach my $entry (@init_mmds) {
@@ -653,5 +684,13 @@
     }
     $cout .= <<"EOC";
-    if (!pass) {
+    if (pass == 0) {
+EOC
+    # init vtable slot
+    if ($self->{flags}{dynpmc}) {
+        $cout .= <<"EOC";
+        temp_base_vtable.base_type = entry;
+EOC
+    }
+    $cout .= <<"EOC";
         /*
          * Parrot_base_vtables is a true global - register just once
@@ -677,5 +716,34 @@
     $cout .= <<"EOC";
     $class_init_code
-    if (pass) {
+    if (pass == 1) {
+EOC
+    # declare auxiliary variables for dyncpmc IDs
+    foreach my $dynclass (keys %init_mmds) {
+        next if $dynclass eq $classname;
+        $cout .= <<"EOC";
+        int my_enum_class_$dynclass = Parrot_PMC_typenum(interp, "$dynclass");
+EOC
+    }
+    # init MMD "right" slots with the dynpmc types
+    foreach my $entry (@init_mmds) {
+        if ($entry->[1] eq $classname) {
+            $cout .= <<"EOC";
+        _temp_mmd_init[$entry->[0]].right = entry;
+EOC
+        }
+        else {
+            $cout .= <<"EOC";
+        _temp_mmd_init[$entry->[0]].right = my_enum_class_$entry->[1];
+EOC
+        }
+    }
+    # just to be safe
+    foreach my $dynclass (keys %init_mmds) {
+        next if $dynclass eq $classname;
+        $cout .= <<"EOC";
+        assert(my_enum_class_$dynclass != enum_class_default);
+EOC
+    }
+    $cout .= <<"EOC";
 #define N_MMD_INIT (sizeof(_temp_mmd_init)/sizeof(_temp_mmd_init[0]))
         Parrot_mmd_register_parents(interp, entry,
@@ -1332,4 +1400,136 @@
 =back
 
+=head1 Parrot::Pmc2c::Library
+
+This class is a wrapper around a collection of PMCs linked in the same
+dynamic library. A degenerate case is having an unnamed library with just ne
+PMC, which is the case used by the Parrot core.
+
+=head2 Parrot::Pmc2c::Library Instance Methods
+
+=over 4
+
+=cut
+
+package Parrot::Pmc2c::Library;
+
+=item C<new($opt, $vtable_dump, %pmcs)
+
+    $library = Parrot::Pmc2c::Library->new
+        ( $options,     # hash refernce, the same passet to other constructors
+          $vtable_dump, # vtable.dump
+          pmc1        => $pmc1_dump,
+          pmc2        => $pmc2_dump,
+          ... );
+
+Creates a new library object. If the C<$options> hash contains a
+C<library> key its value will be used for the library name.
+
+=cut
+
+sub new {
+    my ($class, $opt, $vtable_dump) = (shift, shift, shift);
+    my %pmcs = @_;
+
+    foreach my $file (keys %pmcs) {
+        $pmcs{$file}->{vtable} = $vtable_dump;
+        $pmcs{$file} = Parrot::Pmc2c->new($pmcs{$file}, $opt);
+    }
+
+    return bless { opt         => $opt,
+                   pmcs        => \%pmcs,
+                 }, $class;
+}
+
+=item C<write_all_files()>
+
+Writes C and header files for all the PMCs in the library,
+plus E<lt>libnameE<gt>.c and pmc_E<lt>libnameE<gt>.h if his object
+represents a named library.
+
+=cut
+
+sub write_all_files {
+    my $self = shift;
+    my %opt = %{$self->{opt}};
+    my $library = $opt{library} ? 1 : 0;
+
+    while (my @fc = each %{$self->{pmcs}}) {
+        my ($file, $generator) = @fc;
+	print Data::Dumper->Dump([$generator]) if $opt{debug} > 1;
+
+	my $hout = $generator->gen_h($file);
+        print $hout if $opt{debug};
+        my $h;
+        ($h = $file) =~ s/\.\w+$/.h/;
+        $h =~ s/(\w+)\.h$/pmc_$1.h/;
+        print "Writing $h\n" if $opt{verbose};
+        open H, ">$h" or die "Can't write '$h";
+        print H $hout;
+        close H;
+	my $cout = $generator->gen_c($file);
+        print $cout if $opt{debug};
+        my $c;
+        ($c = $file) =~ s/\.\w+$/.c/;
+        print "Writing $c\n" if $opt{verbose};
+        open C, ">$c" or die "Can't write '$c";
+        print C $cout;
+        close C;
+    }
+
+    if ($library) {
+	my $hout = $self->gen_h($opt{library});
+        my $h = "$opt{library}.h";
+        print "Writing $h\n" if $opt{verbose};
+        open H, ">$h" or die "Can't write '$h";
+        print H $hout;
+        close H;
+	my $cout = $self->gen_c($opt{library});
+        print $cout if $opt{debug};
+        my $c = "$opt{library}.c";
+        print "Writing $c\n" if $opt{verbose};
+        open C, ">$c" or die "Can't write '$c";
+        print C $cout;
+        close C;
+    }
+}
+
+=item C<gen_h>
+
+Writes the header file for the library.
+
+=cut
+
+sub gen_h {
+    my ($self, $file) = @_;
+    my $hout = Parrot::Pmc2c->dont_edit('various files');
+    my $lc_libname = lc $self->{opt}{library};
+
+    $hout .= <<"EOH";
+Parrot_PMC Parrot_lib_${lc_libname}_load(Parrot_INTERP interpreter);
+EOH
+
+    return $hout;
+}
+
+=item C<gen_c>
+
+Writes the C file for the library.
+
+=cut
+
+sub gen_c {
+    my ($self, $file) = @_;
+    my $cout = Parrot::Pmc2c->dont_edit('various files');
+
+    $cout .= Parrot::Pmc2c::dynext_load_code($self->{opt}{library},
+                                             map { $_->{class} }
+                                                 values %{$self->{pmcs}} );
+
+    return $cout;
+}
+
+=back
+
 =head1 SEE ALSO
 
