NAME ^

tools/build/pmc2c.pl - PMC definition to C compiler

SYNOPSIS ^

Create src/pmc/foo.dump:

    % perl tools/build/pmc2c.pl --dump src/pmc/foo.pmc ...

Create vtable.dump:

    % perl tools/build/pmc2c.pl --vtable

Print a class tree for the specified PMCs:

    % perl tools/build/pmc2c.pl --tree src/pmc/*.pmc

Create src/pmc/foo.c and pmc_foo.h from src/pmc/foo.dump:

    % perl tools/build/pmc2c.pl -c src/pmc/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 tools/build/pmc2c.pl --library libfoo -c \
           src/pmc/foo1.pmc src/pmc/foo2.pmc ...

DESCRIPTION ^

The job of the PMC compiler is to take .pmc files and create C files that can be compiled for use with the Parrot interpreter.

COMMAND-LINE OPTIONS ^

--debug

Increase debug level

--verbose

Increase verbose level

--no-lines

Omit source line info

--no-body

Emit an empty body in the dump. This may be useful for debugging.

--include=/path/to/pmc

Specify include path where to find PMCs.

--library=libname

Specifiy the library name. This will create <libname>.c and pmc_<libname>.h. The initialization function will be named after libname and will initialize all PMCs in the library.

Internals ^

To see the internal data structures please run:

    % perl tools/build/pmc2c.pl --c --deb --deb sarray.pmc | less

Compiling PMCs ^

First, the program determines the names of the .c and .h files from the basename of the .pmc file (e.g. perlint.pmc -> perlint.c and perlint.h).

Next, the file is searched for /pmclass \w*/ which attempts to find the class being declared.

Once the class is found, all of its superclasses are scanned and their methods added to the methods of the current PMC. PMCs default to inheriting from 'default'. Only single inheritance is supported.

Once the superclass is determined, it is processed and its method names are extracted and saved.

Next, each method body is processed with various directives (see below) getting replaced by their appropriate values.

Finally, the .c and .h files are generated. The appropriate base class header files are included.

If the noinit flag was used, then no init function is generated. Otherwise, one is generated which sets up the vtable and enters it into the vtables array.

The .c file is generated by appending the functions after the various directives have been replaced.

PMC File Syntax ^

The basic syntax of a PMC file is

  1. A preamble, consisting of code to be copied directly to the .c file
  2. The pmclass declaration:
  3.     pmclass PMCNAME [flags] {

    where flags are:

    extends PMCPARENT

    All methods not defined in PMCNAME are inherited from the PMCPARENT class. If no parent class is defined, methods from default.pmc are used.

    abstract

    This class cannot be instantiated. Abstract classes are shown with lower case class names in the class tree.

    noinit

    Used with abstract: No class_init code is generated.

    const_too

    Classes with this flag get 2 vtables and 2 enums, one pair with read/write set methods, and one with read-only set methods.

    need_ext

    The class needs a PMC_EXT structure. For instance, any class using PMC_data will have need_ext.

    does interface

    The class 'does' the given interfaces (the collection of methods which the class implements).

    The default is "scalar". Other currently used interfaces are:

        array    : container PMC with numerically-keyed elements
        event    : PMC that can be used with event queue
        hash     : container PMC with string-keyed elements
        library  : PMC that corresponds to a dynamic library
        ref      : PMC that references another PMC
        string   : PMC that behaves similarly to the base string type
        boolean  : PMC that does true/false only.
        integer  : PMC that behaves similarly to the base int type
        float    : PMC that behaves similarly to the base number type
        scalar   : (only used by the sample src/dynpmc/foo.pmc)
    This is not a canonical list, but merely a snapshot of what's in use.

    dynpmc

    The class is a dynamic class. These have a special class_init routine suitable for dynamic loading at runtime. See the src/dynpmc directory for an example.

    group GROUP

    The class is part of a group of interrelated PMCs that should be compiled together into a single shared library of the given name. Only valid for dynamic PMCs.

    lib LIB

    The class needs an external library.

    hll HLL

    The High level language this PMC corresponds to.

    maps Type

    The basic parrot PMC type that this PMC correspond to for .HLL usage. For example:

        pmcclass TclInt hll Tcl maps Integer
    allows this PMC to automatically be used when autoboxing I registers to PMCs.

    Requires the hll flag.

  4. A list of vtable method implementations
  5. The final close }

Method Body Substitutions ^

The vtable method bodies can use the following substitutions:

SELF

Converted to the current PMC object of type PMC *.

INTERP

Converted to the interpreter object.

OtherClass.SELF.method(a,b,c)

Calls the static vtable method 'method' in OtherClass.

SELF.method(a,b,c)

Calls the vtable method 'method' using the static type of SELF (in other words, calls another method defined in the same file).

DYNSELF.method(a,b,c)

Calls the vtable method 'method' using the dynamic type of SELF.

DYNSELF(a,b,c)

Same as above, but calls the current method.

OtherClass.SUPER(a,b,c)

Calls the overridden implementation of the current method in OtherClass.

SUPER(a,b,c)

Calls the overridden implementation of the current method in the nearest superclass, using the static type of SELF.

DYNSUPER(a,b,c)

As above, but uses the actual dynamic type of SELF.

AUTHOR ^

Leopold Toetsch.

Cleaned up by Matt Diephouse.

Many thanks to the author of pmc2c.pl, many useful code pieces got reused.

FUNCTIONS ^

my $path = find_file( [$dir1, $dir2], $file, $die_unless_found_flag ); ^

Return the full path to $file (search in the given directories). Optionally, die with an error message if that file cannot be found.

dump_default() ^

Create a .dump file for the default vtable (from which all PMCs inherit).

my ($balanced, $remaining) = extract_balanced($code); ^

Remove a balanced {} construct from the beginning of $code. Return it and the remaining code.

my ($pre, $class_name, $flags) = parse_flags(\$code); ^

Extract a class signature from the code ref and return (a) the code found before the signature, (b) the name of the class, and (c) a hash ref containing the flags associated with the class (such as 'extends' and 'does').

my ($name, $attributes) = parse_pmc($code); ^

Parse PMC code and return the class name and a hash ref of attributes.

gen_parent_list( [$dir1, $dir2], $class, $classes ); ^

Generate an ordered list of parent classes to put in the $classes->{class}->{parents} array, using the given directories to find parents.

dump_1_pmc($file); ^

Returns the class structure from $file for a .dump file.

gen_super_meths($class, $vtable) ^

Generate a list of inherited methods for $class by searching the inheritence tree. The method list is found in $vtable.

add_defaulted($class_structure, $vtable); ^

Add methods to the class structure for each method found in the vtable. This is used to determine all of the 'default' methods from the vtable.dump.

dump_is_newer($file); ^

Return whether the dump of a file is newer than the PMC file. (If it's not, then the PMC file has changed and the dump has not been updated.)

dump_pmc( [$dir1, $dir2], $file1, $file2, ... ); ^

Create a .dump file for each of the passed files (which can be found in the given directories). A '*.pmc' glob may also be passed to emulate a proper shell in the presence of a dumb one.

read_dump( [$dir1, $dir2], $file ); ^

Read in the class definition found in $file (which is found in one of the given directories) and recreate the data structure.

print_tree( [$dir1, $dir2], 0, $file1, $file2, ... ); ^

Print the inheritence tree for each of the files, using the given directories to search for all of correct PMCs. The middle argument is the display depth, which is used for the recursive definition of this function.

gen_c( [$dir1, $dir2], $file1, $file2, ... ) ^

Generate the C source code file for each of the files passed in, using the directories passed in to search for the PMC dump files.

gen_def( [$dir1, $dir2], \%pmc ) ^

Generate a .def file for symbols to export for dynamic PMCs. Currently unused, but retained for being a basis for supporting platforms that need a symbol export list.

sub gen_def { my ($include, $pmcs) = @_;

    my ($pmcfilename, $pmcname);
    my %groups;
    foreach $pmcfilename (keys %$pmcs) {
        # Skip for non-dynpmcs.
        next unless $pmcs->{$pmcfilename}->{flags}->{dynpmc};

        # Get copy of name without extension.
        $pmcname = $pmcfilename;
        $pmcname =~ s/\.pmc$//;

        # Locate .h file and add everything it exports to a list.
        my @exports = ();
        my $file = find_file($include, "pmc_$pmcname.h", 1);

        my $fh = open_file( "<", $file );
        while (<$fh>) {
            if (/^(?:extern\s+)?\w+\*?\s+\*?(\w+)\s*\([^)]+\)\s*;/) {
                push @exports, $1;
            }
        }
        close $fh;

        # Locate .c file and add everything it exports to a list.
        $file = find_file($include, "$pmcname.c", 1);

        $fh = open_file( "<", $file );
        while (<$fh>) {
            if (/^(?:extern\s+)?\w+\*?\s+\*?(\w+)\s*\([^)]+\)\s*;/) {
                push @exports, $1;
            }
        }
        close $fh;

        # If it's in a group, put it in group's PMC array.
        if ($pmcs->{$pmcfilename}->{flags}->{group}) {
            for (keys %{$pmcs->{$pmcfilename}->{flags}->{group}}) {
                push @{$groups{$_}}, @exports;
            }
        }

        # Generate .def file for it.
        # XXX JW Needn't generate these for PMCs in a group?
        #        For now, simplifies sutff.
        $file =~ s/\.c$/.def/;
        $fh = open_file( ">", $file );
        print $fh "LIBRARY $pmcname\nEXPORTS\n";
        print $fh "\t$_\n" foreach @exports;
        close $fh;
    }

    # Generate .def file for groups.
    for my $group (keys %groups) {
        # Get filename of where we'll stash the .def file.
        my $deffile = "$group.def";

        # Does the DEF file already exist?
        my $defexists = -e $deffile;

        # Open the file to append to it.
        my $fh = open_file( ">>", $deffile );
        print $fh "LIBRARY $group\nEXPORTS\n\tParrot_lib_${group}_load\n" unless $defexists;
        print $fh "\t$_\n" foreach @{$groups{$group}};
        close $fh;
    }
}


parrot