1,6c1,74
< #! /usr/bin/perl -w
< #
< # ops2c.pl
< #
< # Generate a C source file from the methods defined in a .pmc file.
< #
---
> #!/usr/bin/perl -w
> 
> =head2 Parrot PMC -> C converter
> 
> The pmc2c program's job is to take .pmc files and create .c files
> which can be compiled for use with the Parrot interpreter.
> 
> =head1 PMC class grammar
> 
> The PMC class grammar is:
> 
> start -> pmc_header pmc_body pmc_footer
> pmc_header -> 'pmclass' id extends_opt no_init_opt '{'
> extends_opt -> 'extends' id | /*empty*/
> no_init_opt -> noinit | /*empty*/
> pmc_body -> member_function_list
> member_function_list -> member_function member_function_list
>                      | /* empty */
> member_function -> function_header function_body
>                    | function_header '=' 'default'
> function_header -> return_type id '(' arg_list ')'
> return_type -> id
> arg_list -> id arg_list
>          | /* empty */
> function_body -> '{' c_statement_list '}'
> pmc_footer -> '}'
> 
> =head1 PMC Macros
> 
> The SELF, INTERP, and RECALL macros can be used inside a pmclass.
> SELF refers to the object which is having the method called on it.
> INTERP refers to the interpreter executing the method
> RECALL is for use after a CHANGE_TYPE macro has been used.  It
> re-calls the current function after the PMC type has changed
> (say from a PerlInt to a PerlString).
> 
> =head1 Usage
> 
> pmc2c.pl class.pmc [--no-lines] [class2.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.
> 
> =head1 Overview
> 
> 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, each of its
> superclasses are searched for and thier methods are added to
> the methods of the current PMC.  All PMCs inherit from default
> automatically.  Only single inheritance is supported.  Once the
> superclass is found (or default if none was found), it is
> processed and its method names are extracted and saved.
> As an added feature, a method can be declared as being default.
> If this is the case, then the method is overlooked when dealing
> with inheritance and that of its superclass is used instead.
> Next, each method is looked at and RECALL, SELF, and INTERP
> are replaced by their appropriate values.  Finally, the .c
> and .h files are generated.  If default methods are used,
> then 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 RECALL, SELF, and INTERP directives have been
> replaced.
> 
> =cut
14a83,90
> =head2 default class
> 
> The vtable.tbl file contains all of the functions that can
> be overridden by a pmclass.  $default is an arrayref
> that contains the names of those methods
> 
> =cut
>   
15a92,99
> 
> # The signature regex is used to parse a function signature
> # for example void func( int x ) { ... }
> # after having applied the signature_re will have
> # $1 eq "void", $2 eq "func" and $3 eq "int x".
> # However, thoughout most of this code, $signature_re
> # is surrounded by parens ($signature_re) making the
> # numbers shift over one (i.e. $2 eq "void", $3 eq "func", $4 eq "int x")
29a114,143
> =head2 extract_balanced
> 
> This functions 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 three tuple consisting of the above, the
> passed in string with the above removed, and the current line number
> after the above has been removed.
> 
> =cut
> 
47a162,205
> =head2 parse_parameters
> 
> This functions purpose is to get the parameter names
> from a string representation of the parameter list.
> It returns those names back in an array.
> For example:
> 
> int x, void* p
> 
> would return an array containing (x,p).
> 
> =cut
> 
> sub parse_parameters {
>   my $parms = shift;
>   my @parm_array = split /,/, $parms;
>   my $i = 0;
>   # Before we get here, the program has added an extra comma at the beginning
>   # of the parameter list, get rid of it.
>   shift @parm_array while( @parm_array && $parm_array[0] =~ /^\s*$/ );
>   foreach( @parm_array ) {
>     # get rid of the type and any following [] (for arrays).
>     if( $_ =~ /.*?(\w+)(?:\[\d*\])*$/ ) {
>       $_ = $1;
>     }
>     else {
>       die "Cannot perform RECALL with unnamed parameter: $_.\n";
>     }
>   }
>   return @parm_array;
> }
> 
> =head2 parse_superpmc
> 
> 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.
> 
> =cut
> 
78a237,243
> =head2 superpmc_info
> 
> This function opens the file containing the superclass
> reads in the data and calls parse_superpmc
> 
> =cut
> 
89a255,267
> =head2 scan_inheritance_tree
> 
> 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.
> 
> =cut
> 
96a275
>             # most derived should be saved, so only overwrite if it is undefined.
101a281,282
>     # now loop through all of the methods in the default class
>     # and add them if they have not already been added.
129a311
>   #make the .c and .h file names
134a317
>   # sanity checks
154a338,343
> =head2 count_newlines
> 
> return the number of newlines in the current string
> 
> =cut
> 
158a348,362
> =head2 filter
> 
> 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 RECALL,
> SELF, and INTERP with the appropriate values.
> Finally, it generates the .c and .h files for
> the .pmc file being analyzed.
> 
> =cut
> 
163c367,368
<   $contents =~ s/^(.*?^\s*)pmclass ([\w]*)//ms; 
---
>   $contents =~ s/^(.*?^\s*)pmclass ([\w]*)//ms;
>   #pre might be things like static functions, etc...
166a372
>   # methodloc is a hash reference methodname => defining class
168a375
>   # look through the pmc declaration header for flags such as noinit
170d376
<   my $superpmc = 'default';
174d379
<           $superpmc = $2;
182a388
>   # get the entire class definition
202a409
>   # start processing methods
206a414,416
>      # because we are going to prepend the self PMC and the
>      # interpreter, we want to stick a comma before the
>      # parameters if we have any.
207a418,419
>      # see if this is a default function.  If so, remember
>      # it and carry on.
217c429,453
<   
---
> 
>      # if the method contains a CHANGE_TYPE statement on itself (pmc or SELF)
>      # then we should check for the RECALL statement
>      if( $methodblock =~ /CHANGE_TYPE\(\s*(?:pmc|SELF)\s*,\s*(?:\w+)\s*\)/ ) {
>        # parse the parameters of the function, we will then add INTERP and SELF as the first
>        # two parameters and let these parms follow.
>        my @parm_names = parse_parameters( $parameters );
>        my $parm_list = '';
>        if( @parm_names ) {
>          $parm_list = ", " . join( ',', @parm_names);
>        }
>        $parm_list = "INTERP, SELF$parm_list";
>        # now replace the RECALL statement with the appropriate vtable call.
>        unless( $methodblock =~ s/RECALL/SELF->vtable->$methodname($parm_list)/g ) {
>          warn "Warning $pmcfile:$methodname contains a CHANGE_TYPE without a following RECALL.\n";
>        }
>      }
>      # here we did not have a CHANGE_TYPE statement, so if we have a RECALL we
>      # need to issue an error.
>      elsif( $methodblock =~ /\bRECALL\b/ ) {
>        die "Error in $pmcfile:$methodname.  Cannot call RECALL without first calling CHANGE_TYPE.\n";
>      }
> 
>      # now replace SELF and INTERP.
>      # WARNING: THIS MUST COME AFTER THE RECALL REPLACEMENT AS IT RELIES ON THIS CODE
220c456,458
<     
---
> 
>      # now create the function prototype based on the class name, method name, and parameters
>      # make it extern in the .h file and add the actual code for the ...c file
228a467
>      # set the class block to the remaining code
232a472,476
>   # now lets set up the vtable for insertion into the Parrot core (if necessary)
>   
>   # after this insane line of code @methods will have the correct
>   # function name for each of the methods listed in the vtable.tbl
>   # file.
234a479
>   #this collapses the array and makes sure the spacing is right for the vtable
237a483,485
>   # generate the #include directives for each of the superclasses.
>   # we get superclasses from the %methodloc hash, however, we have
>   # to dedup them.
239,240c487,488
<   @visible_supers{values %$methodloc} = ();
< 
---
>   @visible_supers{values %$methodloc} = ();  # dedup
>   
