NAME

classes/pmc2c.pl - PMC compiler (Old Version)

SYNOPSIS

This script has now been superceeded by classes/pmc2c2.pl.

% perl pmc2c.pl [--no-lines] [--tree] foo.pmc [foo2.pmc...]
% perl pmc2c.pl B<-f> method *.pmc

The first class.pmc should be the name of the class you wish to create. Normally, the pmc2c.pl translator uses #line pragmas to tell the C compiler where each function in the .pmc file begins (line number). This allows the compiler to issue warnings and errors based on the .pmc file instead of on the .c file which should not be edited. However, there are times when this is not desirable and therefore the --no-lines option is provided.

If --tree is set, the inheritance tree of given classes is printed, no further processing is done. The common base class 'default' is not printed.

If -f is set, the pmcs are printed, where this method is implemented.

DESCRIPTION

The pmc2c program's job is to take .pmc files and create .c files which can be compiled for use with the Parrot interpreter.

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 Parrot_base_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:

    pmclass PMCNAME [extends PMCPARENT] [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 can't 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.

    dynpmc

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

    const_too

    Classes with this flag get 2 vtables and 2 enums, one with r/w set methods one with r/o set methods.

    need_ext

    The class needs a PMC_EXT structure (its using e.g. PMC_data).

    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
    hash
  3. A list of vtable method implementations

  4. 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.

Internal Methods

extract_balanced($code)

This function's purpose is to extract the C code between the opening and closing brace of a function definition. For example, the function

void f( int x ) {
    if( x == 9 ) {
        printf( "Hello!" );
    }
    else {
        printf( "Goodbye!" );
    }
}

would generate a return value of:

q{    if( x == 9 ) {
        printf( "Hello!" );
    }
    else {
        printf( "Goodbye!" );
    }
}

It will actually return a triple consisting of the above, the passed in string with the above removed, and the current line number after the above has been removed.

parse_superpmc($data)

This function looks for a superclass declaration in the current PMC class. If none was found, it assumes that default is the superclass. It then reads in the class definition for the superclass and remembers the method names. It returns an array ref to the method names and the name of the superclass that was analyzed.

superpmc_info($class)

This function opens the file containing the superclass reads in the data and calls parse_superpmc().

scan_inheritance_tree($classname)

This function repeatedly calls superpmc_info() passing in the current class name. superpmc_info() will return a tuple containing all of the defined methods (not default) in that class as well as the name of the superclass that was processed. This function stops when the default superclass is processed. It returns a hash that maps the method name to the most derived class it was defined in.

count_newlines($string)

Returns the number of newlines in $string.

filter($contents, $file, $cfile)

The filter() function choreographs the previous functions actions on the pmcfile in question. It first scans the inheritance hierarchy to get all of the methods and their corresponding class of definition. Next, it skips over the extends clause and processes any flags (such as noinit). Afterwards, it loops through each function declared and replaces directives with the appropriate values. Finally, it generates the .c and .h files for the .pmc file being analyzed.

TODO

  • Document the undocumented functions.