parrotcode: PMC definition to C compiler | |
Contents | Tools |
tools/build/pmc2c.pl - PMC definition to C compiler
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 ...
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.
--debug
--verbose
--no-lines
--no-body
--include=/path/to/pmc
--library=libname
To see the internal data structures please run:
% perl tools/build/pmc2c.pl --c --deb --deb sarray.pmc | less
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.
The basic syntax of a PMC file is
pmclass
declaration: pmclass PMCNAME [flags] {
where flags
are:
extends PMCPARENT
abstract
noinit
abstract
: No class_init
code is generated.const_too
need_ext
PMC_EXT
structure. For instance, any class using PMC_data
will have need_ext
.does interface
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)
dynpmc
class_init
routine suitable for dynamic loading at runtime. See the src/dynpmc directory for an example.group GROUP
lib LIB
hll HLL
maps Type
.HLL
usage. For example: pmcclass TclInt hll Tcl maps Integer
I
registers to PMCs.hll
flag.}
The vtable method bodies can use the following substitutions:
SELF
PMC *
.INTERP
OtherClass.SELF.method(a,b,c)
OtherClass
.SELF.method(a,b,c)
SELF
(in other words, calls another method defined in the same file).DYNSELF.method(a,b,c)
SELF
.DYNSELF(a,b,c)
OtherClass.SUPER(a,b,c)
OtherClass
.SUPER(a,b,c)
SELF
.DYNSUPER(a,b,c)
SELF
.Leopold Toetsch.
Cleaned up by Matt Diephouse.
Many thanks to the author of pmc2c.pl, many useful code pieces got reused.
Return the full path to $file (search in the given directories). Optionally, die with an error message if that file cannot be found.
Create a .dump file for the default vtable (from which all PMCs inherit).
Remove a balanced {} construct from the beginning of $code. Return it and the remaining 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').
Parse PMC code and return the class name and a hash ref of attributes.
Generate an ordered list of parent classes to put in the $classes->{class}->{parents} array, using the given directories to find parents.
Returns the class structure from $file for a .dump file.
Generate a list of inherited methods for $class by searching the inheritence tree. The method list is found in $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.
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.)
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 in the class definition found in $file (which is found in one of the given directories) and recreate the data structure.
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.
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.
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;
}
}
|