214 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
		
		
			
		
	
	
			214 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
| 
								 | 
							
								#!/usr/bin/perl -w
							 | 
						||
| 
								 | 
							
								# Generate Fortran 2003 interfaces from a sequence of C function declarations
							 | 
						||
| 
								 | 
							
								# of the form (one per line):
							 | 
						||
| 
								 | 
							
								#     extern <type> <name>(...args...)
							 | 
						||
| 
								 | 
							
								#     extern <type> <name>(...args...)
							 | 
						||
| 
								 | 
							
								#     ...
							 | 
						||
| 
								 | 
							
								# with no line breaks within a given function.  (It's too much work to
							 | 
						||
| 
								 | 
							
								# write a general parser, since we just have to handle FFTW's header files.)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								sub canonicalize_type {
							 | 
						||
| 
								 | 
							
								    my($type);
							 | 
						||
| 
								 | 
							
								    ($type) = @_;
							 | 
						||
| 
								 | 
							
								    $type =~ s/ +/ /g;
							 | 
						||
| 
								 | 
							
								    $type =~ s/^ //;
							 | 
						||
| 
								 | 
							
								    $type =~ s/ $//;
							 | 
						||
| 
								 | 
							
								    $type =~ s/([^\* ])\*/$1 \*/g;
							 | 
						||
| 
								 | 
							
								    return $type;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								# C->Fortran map of supported return types
							 | 
						||
| 
								 | 
							
								%return_types = (
							 | 
						||
| 
								 | 
							
								    "int" => "integer(C_INT)",
							 | 
						||
| 
								 | 
							
								    "ptrdiff_t" => "integer(C_INTPTR_T)",
							 | 
						||
| 
								 | 
							
								    "size_t" => "integer(C_SIZE_T)",
							 | 
						||
| 
								 | 
							
								    "double" => "real(C_DOUBLE)",
							 | 
						||
| 
								 | 
							
								    "float" => "real(C_FLOAT)",
							 | 
						||
| 
								 | 
							
								    "long double" => "real(C_LONG_DOUBLE)",
							 | 
						||
| 
								 | 
							
								    "__float128" => "real(16)",
							 | 
						||
| 
								 | 
							
								    "fftw_plan" => "type(C_PTR)",
							 | 
						||
| 
								 | 
							
								    "fftwf_plan" => "type(C_PTR)",
							 | 
						||
| 
								 | 
							
								    "fftwl_plan" => "type(C_PTR)",
							 | 
						||
| 
								 | 
							
								    "fftwq_plan" => "type(C_PTR)",
							 | 
						||
| 
								 | 
							
								    "void *" => "type(C_PTR)",
							 | 
						||
| 
								 | 
							
								    "char *" => "type(C_PTR)",
							 | 
						||
| 
								 | 
							
								    "double *" => "type(C_PTR)",
							 | 
						||
| 
								 | 
							
								    "float *" => "type(C_PTR)",
							 | 
						||
| 
								 | 
							
								    "long double *" => "type(C_PTR)",
							 | 
						||
| 
								 | 
							
								    "__float128 *" => "type(C_PTR)",
							 | 
						||
| 
								 | 
							
								    "fftw_complex *" => "type(C_PTR)",
							 | 
						||
| 
								 | 
							
								    "fftwf_complex *" => "type(C_PTR)",
							 | 
						||
| 
								 | 
							
								    "fftwl_complex *" => "type(C_PTR)",
							 | 
						||
| 
								 | 
							
								    "fftwq_complex *" => "type(C_PTR)",
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								# C->Fortran map of supported argument types
							 | 
						||
| 
								 | 
							
								%arg_types = (
							 | 
						||
| 
								 | 
							
								    "int" => "integer(C_INT), value",
							 | 
						||
| 
								 | 
							
								    "unsigned" => "integer(C_INT), value",
							 | 
						||
| 
								 | 
							
								    "size_t" => "integer(C_SIZE_T), value",
							 | 
						||
| 
								 | 
							
								    "ptrdiff_t" => "integer(C_INTPTR_T), value",
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    "fftw_r2r_kind" => "integer(C_FFTW_R2R_KIND), value",
							 | 
						||
| 
								 | 
							
								    "fftwf_r2r_kind" => "integer(C_FFTW_R2R_KIND), value",
							 | 
						||
| 
								 | 
							
								    "fftwl_r2r_kind" => "integer(C_FFTW_R2R_KIND), value",
							 | 
						||
| 
								 | 
							
								    "fftwq_r2r_kind" => "integer(C_FFTW_R2R_KIND), value",
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    "double" => "real(C_DOUBLE), value",
							 | 
						||
| 
								 | 
							
								    "float" => "real(C_FLOAT), value",
							 | 
						||
| 
								 | 
							
								    "long double" => "real(C_LONG_DOUBLE), value",
							 | 
						||
| 
								 | 
							
								    "__float128" => "real(16), value",
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    "fftw_complex" => "complex(C_DOUBLE_COMPLEX), value",
							 | 
						||
| 
								 | 
							
								    "fftwf_complex" => "complex(C_DOUBLE_COMPLEX), value",
							 | 
						||
| 
								 | 
							
								    "fftwl_complex" => "complex(C_LONG_DOUBLE), value",
							 | 
						||
| 
								 | 
							
								    "fftwq_complex" => "complex(16), value",
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    "fftw_plan" => "type(C_PTR), value",
							 | 
						||
| 
								 | 
							
								    "fftwf_plan" => "type(C_PTR), value",
							 | 
						||
| 
								 | 
							
								    "fftwl_plan" => "type(C_PTR), value",
							 | 
						||
| 
								 | 
							
								    "fftwq_plan" => "type(C_PTR), value",
							 | 
						||
| 
								 | 
							
								    "const fftw_plan" => "type(C_PTR), value",
							 | 
						||
| 
								 | 
							
								    "const fftwf_plan" => "type(C_PTR), value",
							 | 
						||
| 
								 | 
							
								    "const fftwl_plan" => "type(C_PTR), value",
							 | 
						||
| 
								 | 
							
								    "const fftwq_plan" => "type(C_PTR), value",
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    "const int *" => "integer(C_INT), dimension(*), intent(in)",
							 | 
						||
| 
								 | 
							
								    "ptrdiff_t *" => "integer(C_INTPTR_T), intent(out)",
							 | 
						||
| 
								 | 
							
								    "const ptrdiff_t *" => "integer(C_INTPTR_T), dimension(*), intent(in)",
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    "const fftw_r2r_kind *" => "integer(C_FFTW_R2R_KIND), dimension(*), intent(in)",
							 | 
						||
| 
								 | 
							
								    "const fftwf_r2r_kind *" => "integer(C_FFTW_R2R_KIND), dimension(*), intent(in)",
							 | 
						||
| 
								 | 
							
								    "const fftwl_r2r_kind *" => "integer(C_FFTW_R2R_KIND), dimension(*), intent(in)",
							 | 
						||
| 
								 | 
							
								    "const fftwq_r2r_kind *" => "integer(C_FFTW_R2R_KIND), dimension(*), intent(in)",
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    "double *" => "real(C_DOUBLE), dimension(*), intent(out)",
							 | 
						||
| 
								 | 
							
								    "float *" => "real(C_FLOAT), dimension(*), intent(out)",
							 | 
						||
| 
								 | 
							
								    "long double *" => "real(C_LONG_DOUBLE), dimension(*), intent(out)",
							 | 
						||
| 
								 | 
							
								    "__float128 *" => "real(16), dimension(*), intent(out)",
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    "fftw_complex *" => "complex(C_DOUBLE_COMPLEX), dimension(*), intent(out)",
							 | 
						||
| 
								 | 
							
								    "fftwf_complex *" => "complex(C_FLOAT_COMPLEX), dimension(*), intent(out)",
							 | 
						||
| 
								 | 
							
								    "fftwl_complex *" => "complex(C_LONG_DOUBLE_COMPLEX), dimension(*), intent(out)",
							 | 
						||
| 
								 | 
							
								    "fftwq_complex *" => "complex(16), dimension(*), intent(out)",
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    "const fftw_iodim *" => "type(fftw_iodim), dimension(*), intent(in)",
							 | 
						||
| 
								 | 
							
								    "const fftwf_iodim *" => "type(fftwf_iodim), dimension(*), intent(in)",
							 | 
						||
| 
								 | 
							
								    "const fftwl_iodim *" => "type(fftwl_iodim), dimension(*), intent(in)",
							 | 
						||
| 
								 | 
							
								    "const fftwq_iodim *" => "type(fftwq_iodim), dimension(*), intent(in)",
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    "const fftw_iodim64 *" => "type(fftw_iodim64), dimension(*), intent(in)",
							 | 
						||
| 
								 | 
							
								    "const fftwf_iodim64 *" => "type(fftwf_iodim64), dimension(*), intent(in)",
							 | 
						||
| 
								 | 
							
								    "const fftwl_iodim64 *" => "type(fftwl_iodim64), dimension(*), intent(in)",
							 | 
						||
| 
								 | 
							
								    "const fftwq_iodim64 *" => "type(fftwq_iodim64), dimension(*), intent(in)",
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    "void *" => "type(C_PTR), value",
							 | 
						||
| 
								 | 
							
								    "FILE *" => "type(C_PTR), value",
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    "const char *" => "character(C_CHAR), dimension(*), intent(in)",
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    "fftw_write_char_func" => "type(C_FUNPTR), value",
							 | 
						||
| 
								 | 
							
								    "fftwf_write_char_func" => "type(C_FUNPTR), value",
							 | 
						||
| 
								 | 
							
								    "fftwl_write_char_func" => "type(C_FUNPTR), value",
							 | 
						||
| 
								 | 
							
								    "fftwq_write_char_func" => "type(C_FUNPTR), value",
							 | 
						||
| 
								 | 
							
								    "fftw_read_char_func" => "type(C_FUNPTR), value",
							 | 
						||
| 
								 | 
							
								    "fftwf_read_char_func" => "type(C_FUNPTR), value",
							 | 
						||
| 
								 | 
							
								    "fftwl_read_char_func" => "type(C_FUNPTR), value",
							 | 
						||
| 
								 | 
							
								    "fftwq_read_char_func" => "type(C_FUNPTR), value",
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # Although the MPI standard defines this type as simply "integer",
							 | 
						||
| 
								 | 
							
								    # if we use integer without a 'C_' kind in a bind(C) interface then
							 | 
						||
| 
								 | 
							
								    # gfortran complains.  Instead, since MPI also requires the C type
							 | 
						||
| 
								 | 
							
								    # MPI_Fint to match Fortran integers, we use the size of this type
							 | 
						||
| 
								 | 
							
								    # (extracted by configure and substituted by the Makefile).
							 | 
						||
| 
								 | 
							
								    "MPI_Comm" => "integer(C_MPI_FINT), value"
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								while (<>) {
							 | 
						||
| 
								 | 
							
								    next if /^ *$/;
							 | 
						||
| 
								 | 
							
								    if (/^ *extern +([a-zA-Z_0-9 ]+[ \*]) *([a-zA-Z_0-9]+) *\((.*)\) *$/) {
							 | 
						||
| 
								 | 
							
									$ret = &canonicalize_type($1);
							 | 
						||
| 
								 | 
							
									$name = $2;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									$args = $3;
							 | 
						||
| 
								 | 
							
									$args =~ s/^ *void *$//;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									$bad = ($ret ne "void") && !exists($return_types{$ret});	
							 | 
						||
| 
								 | 
							
									foreach $arg (split(/ *, */, $args)) {
							 | 
						||
| 
								 | 
							
									    $arg =~ /^([a-zA-Z_0-9 ]+[ \*]) *([a-zA-Z_0-9]+) *$/;
							 | 
						||
| 
								 | 
							
									    $argtype = &canonicalize_type($1);
							 | 
						||
| 
								 | 
							
									    $bad = 1 if !exists($arg_types{$argtype});
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									if ($bad) {
							 | 
						||
| 
								 | 
							
									    print "! Unable to generate Fortran interface for $name\n";
							 | 
						||
| 
								 | 
							
									    next;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									# any function taking an MPI_Comm arg needs a C wrapper (grr).
							 | 
						||
| 
								 | 
							
									if ($args =~ /MPI_Comm/) {
							 | 
						||
| 
								 | 
							
									    $cname = $name . "_f03";
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									else {
							 | 
						||
| 
								 | 
							
									    $cname = $name;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									# Fortran has a 132-character line-length limit by default (grr)
							 | 
						||
| 
								 | 
							
									$len = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									print "    "; $len = $len + length("    ");
							 | 
						||
| 
								 | 
							
									if ($ret eq "void") {
							 | 
						||
| 
								 | 
							
									    $kind = "subroutine"
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									else {
							 | 
						||
| 
								 | 
							
									    print "$return_types{$ret} ";
							 | 
						||
| 
								 | 
							
									    $len = $len + length("$return_types{$ret} ");
							 | 
						||
| 
								 | 
							
									    $kind = "function"
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									print "$kind $name("; $len = $len + length("$kind $name(");
							 | 
						||
| 
								 | 
							
									$len0 = $len;
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									$argnames = $args;
							 | 
						||
| 
								 | 
							
									$argnames =~ s/([a-zA-Z_0-9 ]+[ \*]) *([a-zA-Z_0-9]+) */$2/g;
							 | 
						||
| 
								 | 
							
									$comma = "";
							 | 
						||
| 
								 | 
							
									foreach $argname (split(/ *, */, $argnames)) {
							 | 
						||
| 
								 | 
							
									    if ($len + length("$comma$argname") + 3 > 132) {
							 | 
						||
| 
								 | 
							
										printf ", &\n%*s", $len0, "";
							 | 
						||
| 
								 | 
							
										$len = $len0;
							 | 
						||
| 
								 | 
							
										$comma = "";
							 | 
						||
| 
								 | 
							
									    }
							 | 
						||
| 
								 | 
							
									    print "$comma$argname";
							 | 
						||
| 
								 | 
							
									    $len = $len + length("$comma$argname");
							 | 
						||
| 
								 | 
							
									    $comma = ",";
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									print ") "; $len = $len + 2;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if ($len + length("bind(C, name='$cname')") > 132) {
							 | 
						||
| 
								 | 
							
									    printf "&\n%*s", $len0 - length("$name("), "";
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									print "bind(C, name='$cname')\n";
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									print "      import\n";
							 | 
						||
| 
								 | 
							
									foreach $arg (split(/ *, */, $args)) {
							 | 
						||
| 
								 | 
							
									    $arg =~ /^([a-zA-Z_0-9 ]+[ \*]) *([a-zA-Z_0-9]+) *$/;
							 | 
						||
| 
								 | 
							
									    $argtype = &canonicalize_type($1);
							 | 
						||
| 
								 | 
							
									    $argname = $2;
							 | 
						||
| 
								 | 
							
									    $ftype = $arg_types{$argtype};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									    # Various special cases for argument types:
							 | 
						||
| 
								 | 
							
									    if ($name =~ /_flops$/ && $argtype eq "double *") {
							 | 
						||
| 
								 | 
							
										$ftype = "real(C_DOUBLE), intent(out)" 
							 | 
						||
| 
								 | 
							
									    }
							 | 
						||
| 
								 | 
							
									    if ($name =~ /_execute/ && ($argname eq "ri" ||
							 | 
						||
| 
								 | 
							
													$argname eq "ii" || 
							 | 
						||
| 
								 | 
							
													$argname eq "in")) {
							 | 
						||
| 
								 | 
							
										$ftype =~ s/intent\(out\)/intent(inout)/;
							 | 
						||
| 
								 | 
							
									    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									    print "      $ftype :: $argname\n"
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									print "    end $kind $name\n";
							 | 
						||
| 
								 | 
							
									print "    \n";
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 |