The main generator file

Traditionally, the main generator file is called gen_XYZ.pl and lies in a directory XYZ where the code generation for TAG is going to take place. We start by giving an example that is available in the MPFQ distribution in src/gf7/gen_gf7.pl:

#!/usr/bin/perl -w

use warnings;
use strict;

use File::Spec;
my $dirname;

BEGIN {
    $dirname = (File::Spec->splitpath($0))[1];
    unshift @INC, "$dirname/../perl-lib";
}

use Mpfq::engine::conf qw(read_api);

use gf7;

# Use the default api file.
my $api_file = "$dirname/../api.pl";

MAIN: {

  # Read api file. At that point, one can also pass one or several
  # api_extensions monikers.
  my $api = Mpfq::engine::conf::read_api $api_file, qw/POLY URE/;
  my $options = {};
  my $code = {};

  # This calls code_for_xxx for all xxx functions in the api.

  my $object = gf7->new();

  $object->create_code($api, $code, $options);

  # This creates the .c and .h files.
  $object->create_files('.', 'gf7');
}


      

The code generation proceeds in 4 steps:

The main generator file is rather short, and does very little beyond the steps above. We go through its different sections in order.

#!/usr/bin/perl -w
use warnings;
use strict;

It is handy to make the main generator file an executable perl script.

use File::Spec;
my $dirname;
BEGIN {
    $dirname = (File::Spec->splitpath($0))[1];
    unshift @INC, "$dirname/../perl-lib";
}   

The fragment above is the chosen mechanism to setup perl's include path to also contain the perl-lib subdirectory at the upper level.

use gf7;

This loads the top-level package file (described in the previous section).

use Mpfq::engine::conf qw(read_api);
my $api_file = "$dirname/../api.pl";
my $api = Mpfq::engine::conf::read_api $api_file, qw/FIELD POLY/;

This is mandatory as one of the tasks of the main generator file is to read the MPFQ API file.

  my $object = gf7->new();

This creates an object of the class defined by the top-level package file.

  my $code = {};
  my $options = {};

The two (references to) hashes above must be created. The first array will hold the complete generated codde, while the $options hash is passed as an argument to all code generation functions. It is a convenient way to pass information to these functions.

  $object->create_code($api, $code, $options);

This effectively does the code generation in memory (within the $code hash, to which $object takes a reference).

$object->create_files('.', 'gf7');

and this final statement creates the source files.

Some extra notes

The definition of the types required by the API can be done at various places, including in the MAIN, like in the example. These types have to be added as the types member of the $code hash.

All along the generation, one might want to pass some information to the code_for_xxx; the $options is meant for that. What to put in this hash is up to the implementor.

Let us summarize the meaning of the 3 important variables:

  • $code is a hash. Here is the expected contents at the end of the process (before entering create_files()).

    • There should be: an entry for each function to implement:

          $code->{'add'} = ...;
                  

      where ... is a hash reference describing the implementation. The implementation may be tagged as macro, function, or inlined. See perl-lib/Mpfq/handler.pm (comments before the ship_code function) for the documentation of the other hash members.

    • There must be an entry describing types (generated either from the gen_TAG.pl or from some init_handler() as described above)

           $code->{'types'} = {
               elt => "typedef unsigned long $elt\[17\];",
               dst =>  "typedef unsigned long * $dst;",
               src =>  "typedef const unsigned long * $src;",
               ...
           }
                  

    • It is possible to have a cpp_asserts entry. This will translates into some assertion at the preprocessor level. For instance, use :

           $code->{'cpp_asserts'} = [ "GMP_LIMB_BITS == 64" ];
                  

      if the generated code is only for 64 bit computers.

    • Another important field is for #include that are required by the implementation. The includes that must be added at the top of the .h file are to be declared as follows:

           $code->{'includes'} = [ '"my_macros.h"', '"grouik.h"' ];
                  

    • More complicated statements that must be put at the top of the .h can be declared in the extra field:

           $code->{'extra'} = [ "#ifndef __GNU_C_\n#warning \"non free compiler!\"\n#endif" ];
                  

    • Finally, $code->{'banner'} is a banner to put in the head of .c and .h files.

  • $options is a hash. It is passed as an argument to every creator. This is up to you to decide which option is relevant for your implementation.

  • $api is another hash. This is essentially a copy of the api.pl file and there is nothing to play with.