cannam@95
|
1 #!/usr/bin/perl -w
|
cannam@95
|
2 # Generate Fortran 2003 interfaces from a sequence of C function declarations
|
cannam@95
|
3 # of the form (one per line):
|
cannam@95
|
4 # extern <type> <name>(...args...)
|
cannam@95
|
5 # extern <type> <name>(...args...)
|
cannam@95
|
6 # ...
|
cannam@95
|
7 # with no line breaks within a given function. (It's too much work to
|
cannam@95
|
8 # write a general parser, since we just have to handle FFTW's header files.)
|
cannam@95
|
9
|
cannam@95
|
10 sub canonicalize_type {
|
cannam@95
|
11 my($type);
|
cannam@95
|
12 ($type) = @_;
|
cannam@95
|
13 $type =~ s/ +/ /g;
|
cannam@95
|
14 $type =~ s/^ //;
|
cannam@95
|
15 $type =~ s/ $//;
|
cannam@95
|
16 $type =~ s/([^\* ])\*/$1 \*/g;
|
cannam@95
|
17 return $type;
|
cannam@95
|
18 }
|
cannam@95
|
19
|
cannam@95
|
20 # C->Fortran map of supported return types
|
cannam@95
|
21 %return_types = (
|
cannam@95
|
22 "int" => "integer(C_INT)",
|
cannam@95
|
23 "ptrdiff_t" => "integer(C_INTPTR_T)",
|
cannam@95
|
24 "size_t" => "integer(C_SIZE_T)",
|
cannam@95
|
25 "double" => "real(C_DOUBLE)",
|
cannam@95
|
26 "float" => "real(C_FLOAT)",
|
cannam@95
|
27 "long double" => "real(C_LONG_DOUBLE)",
|
cannam@95
|
28 "float128__" => "real(16)",
|
cannam@95
|
29 "fftw_plan" => "type(C_PTR)",
|
cannam@95
|
30 "fftwf_plan" => "type(C_PTR)",
|
cannam@95
|
31 "fftwl_plan" => "type(C_PTR)",
|
cannam@95
|
32 "fftwq_plan" => "type(C_PTR)",
|
cannam@95
|
33 "void *" => "type(C_PTR)",
|
cannam@95
|
34 "char *" => "type(C_PTR)",
|
cannam@95
|
35 "double *" => "type(C_PTR)",
|
cannam@95
|
36 "float *" => "type(C_PTR)",
|
cannam@95
|
37 "long double *" => "type(C_PTR)",
|
cannam@95
|
38 "float128__ *" => "type(C_PTR)",
|
cannam@95
|
39 "fftw_complex *" => "type(C_PTR)",
|
cannam@95
|
40 "fftwf_complex *" => "type(C_PTR)",
|
cannam@95
|
41 "fftwl_complex *" => "type(C_PTR)",
|
cannam@95
|
42 "fftwq_complex *" => "type(C_PTR)",
|
cannam@95
|
43 );
|
cannam@95
|
44
|
cannam@95
|
45 # C->Fortran map of supported argument types
|
cannam@95
|
46 %arg_types = (
|
cannam@95
|
47 "int" => "integer(C_INT), value",
|
cannam@95
|
48 "unsigned" => "integer(C_INT), value",
|
cannam@95
|
49 "size_t" => "integer(C_SIZE_T), value",
|
cannam@95
|
50 "ptrdiff_t" => "integer(C_INTPTR_T), value",
|
cannam@95
|
51
|
cannam@95
|
52 "fftw_r2r_kind" => "integer(C_FFTW_R2R_KIND), value",
|
cannam@95
|
53 "fftwf_r2r_kind" => "integer(C_FFTW_R2R_KIND), value",
|
cannam@95
|
54 "fftwl_r2r_kind" => "integer(C_FFTW_R2R_KIND), value",
|
cannam@95
|
55 "fftwq_r2r_kind" => "integer(C_FFTW_R2R_KIND), value",
|
cannam@95
|
56
|
cannam@95
|
57 "double" => "real(C_DOUBLE), value",
|
cannam@95
|
58 "float" => "real(C_FLOAT), value",
|
cannam@95
|
59 "long double" => "real(C_LONG_DOUBLE), value",
|
cannam@95
|
60 "__float128" => "real(16), value",
|
cannam@95
|
61
|
cannam@95
|
62 "fftw_complex" => "complex(C_DOUBLE_COMPLEX), value",
|
cannam@95
|
63 "fftwf_complex" => "complex(C_DOUBLE_COMPLEX), value",
|
cannam@95
|
64 "fftwl_complex" => "complex(C_LONG_DOUBLE), value",
|
cannam@95
|
65 "fftwq_complex" => "complex(16), value",
|
cannam@95
|
66
|
cannam@95
|
67 "fftw_plan" => "type(C_PTR), value",
|
cannam@95
|
68 "fftwf_plan" => "type(C_PTR), value",
|
cannam@95
|
69 "fftwl_plan" => "type(C_PTR), value",
|
cannam@95
|
70 "fftwq_plan" => "type(C_PTR), value",
|
cannam@95
|
71 "const fftw_plan" => "type(C_PTR), value",
|
cannam@95
|
72 "const fftwf_plan" => "type(C_PTR), value",
|
cannam@95
|
73 "const fftwl_plan" => "type(C_PTR), value",
|
cannam@95
|
74 "const fftwq_plan" => "type(C_PTR), value",
|
cannam@95
|
75
|
cannam@95
|
76 "const int *" => "integer(C_INT), dimension(*), intent(in)",
|
cannam@95
|
77 "ptrdiff_t *" => "integer(C_INTPTR_T), intent(out)",
|
cannam@95
|
78 "const ptrdiff_t *" => "integer(C_INTPTR_T), dimension(*), intent(in)",
|
cannam@95
|
79
|
cannam@95
|
80 "const fftw_r2r_kind *" => "integer(C_FFTW_R2R_KIND), dimension(*), intent(in)",
|
cannam@95
|
81 "const fftwf_r2r_kind *" => "integer(C_FFTW_R2R_KIND), dimension(*), intent(in)",
|
cannam@95
|
82 "const fftwl_r2r_kind *" => "integer(C_FFTW_R2R_KIND), dimension(*), intent(in)",
|
cannam@95
|
83 "const fftwq_r2r_kind *" => "integer(C_FFTW_R2R_KIND), dimension(*), intent(in)",
|
cannam@95
|
84
|
cannam@95
|
85 "double *" => "real(C_DOUBLE), dimension(*), intent(out)",
|
cannam@95
|
86 "float *" => "real(C_FLOAT), dimension(*), intent(out)",
|
cannam@95
|
87 "long double *" => "real(C_LONG_DOUBLE), dimension(*), intent(out)",
|
cannam@95
|
88 "__float128 *" => "real(16), dimension(*), intent(out)",
|
cannam@95
|
89
|
cannam@95
|
90 "fftw_complex *" => "complex(C_DOUBLE_COMPLEX), dimension(*), intent(out)",
|
cannam@95
|
91 "fftwf_complex *" => "complex(C_FLOAT_COMPLEX), dimension(*), intent(out)",
|
cannam@95
|
92 "fftwl_complex *" => "complex(C_LONG_DOUBLE_COMPLEX), dimension(*), intent(out)",
|
cannam@95
|
93 "fftwq_complex *" => "complex(16), dimension(*), intent(out)",
|
cannam@95
|
94
|
cannam@95
|
95 "const fftw_iodim *" => "type(fftw_iodim), dimension(*), intent(in)",
|
cannam@95
|
96 "const fftwf_iodim *" => "type(fftwf_iodim), dimension(*), intent(in)",
|
cannam@95
|
97 "const fftwl_iodim *" => "type(fftwl_iodim), dimension(*), intent(in)",
|
cannam@95
|
98 "const fftwq_iodim *" => "type(fftwq_iodim), dimension(*), intent(in)",
|
cannam@95
|
99
|
cannam@95
|
100 "const fftw_iodim64 *" => "type(fftw_iodim64), dimension(*), intent(in)",
|
cannam@95
|
101 "const fftwf_iodim64 *" => "type(fftwf_iodim64), dimension(*), intent(in)",
|
cannam@95
|
102 "const fftwl_iodim64 *" => "type(fftwl_iodim64), dimension(*), intent(in)",
|
cannam@95
|
103 "const fftwq_iodim64 *" => "type(fftwq_iodim64), dimension(*), intent(in)",
|
cannam@95
|
104
|
cannam@95
|
105 "void *" => "type(C_PTR), value",
|
cannam@95
|
106 "FILE *" => "type(C_PTR), value",
|
cannam@95
|
107
|
cannam@95
|
108 "const char *" => "character(C_CHAR), dimension(*), intent(in)",
|
cannam@95
|
109
|
cannam@95
|
110 "fftw_write_char_func" => "type(C_FUNPTR), value",
|
cannam@95
|
111 "fftwf_write_char_func" => "type(C_FUNPTR), value",
|
cannam@95
|
112 "fftwl_write_char_func" => "type(C_FUNPTR), value",
|
cannam@95
|
113 "fftwq_write_char_func" => "type(C_FUNPTR), value",
|
cannam@95
|
114 "fftw_read_char_func" => "type(C_FUNPTR), value",
|
cannam@95
|
115 "fftwf_read_char_func" => "type(C_FUNPTR), value",
|
cannam@95
|
116 "fftwl_read_char_func" => "type(C_FUNPTR), value",
|
cannam@95
|
117 "fftwq_read_char_func" => "type(C_FUNPTR), value",
|
cannam@95
|
118
|
cannam@95
|
119 # Although the MPI standard defines this type as simply "integer",
|
cannam@95
|
120 # if we use integer without a 'C_' kind in a bind(C) interface then
|
cannam@95
|
121 # gfortran complains. Instead, since MPI also requires the C type
|
cannam@95
|
122 # MPI_Fint to match Fortran integers, we use the size of this type
|
cannam@95
|
123 # (extracted by configure and substituted by the Makefile).
|
cannam@95
|
124 "MPI_Comm" => "integer(C_MPI_FINT), value"
|
cannam@95
|
125 );
|
cannam@95
|
126
|
cannam@95
|
127 while (<>) {
|
cannam@95
|
128 next if /^ *$/;
|
cannam@95
|
129 if (/^ *extern +([a-zA-Z_0-9 ]+[ \*]) *([a-zA-Z_0-9]+) *\((.*)\) *$/) {
|
cannam@95
|
130 $ret = &canonicalize_type($1);
|
cannam@95
|
131 $name = $2;
|
cannam@95
|
132
|
cannam@95
|
133 $args = $3;
|
cannam@95
|
134 $args =~ s/^ *void *$//;
|
cannam@95
|
135
|
cannam@95
|
136 $bad = ($ret ne "void") && !exists($return_types{$ret});
|
cannam@95
|
137 foreach $arg (split(/ *, */, $args)) {
|
cannam@95
|
138 $arg =~ /^([a-zA-Z_0-9 ]+[ \*]) *([a-zA-Z_0-9]+) *$/;
|
cannam@95
|
139 $argtype = &canonicalize_type($1);
|
cannam@95
|
140 $bad = 1 if !exists($arg_types{$argtype});
|
cannam@95
|
141 }
|
cannam@95
|
142 if ($bad) {
|
cannam@95
|
143 print "! Unable to generate Fortran interface for $name\n";
|
cannam@95
|
144 next;
|
cannam@95
|
145 }
|
cannam@95
|
146
|
cannam@95
|
147 # any function taking an MPI_Comm arg needs a C wrapper (grr).
|
cannam@95
|
148 if ($args =~ /MPI_Comm/) {
|
cannam@95
|
149 $cname = $name . "_f03";
|
cannam@95
|
150 }
|
cannam@95
|
151 else {
|
cannam@95
|
152 $cname = $name;
|
cannam@95
|
153 }
|
cannam@95
|
154
|
cannam@95
|
155 # Fortran has a 132-character line-length limit by default (grr)
|
cannam@95
|
156 $len = 0;
|
cannam@95
|
157
|
cannam@95
|
158 print " "; $len = $len + length(" ");
|
cannam@95
|
159 if ($ret eq "void") {
|
cannam@95
|
160 $kind = "subroutine"
|
cannam@95
|
161 }
|
cannam@95
|
162 else {
|
cannam@95
|
163 print "$return_types{$ret} ";
|
cannam@95
|
164 $len = $len + length("$return_types{$ret} ");
|
cannam@95
|
165 $kind = "function"
|
cannam@95
|
166 }
|
cannam@95
|
167 print "$kind $name("; $len = $len + length("$kind $name(");
|
cannam@95
|
168 $len0 = $len;
|
cannam@95
|
169
|
cannam@95
|
170 $argnames = $args;
|
cannam@95
|
171 $argnames =~ s/([a-zA-Z_0-9 ]+[ \*]) *([a-zA-Z_0-9]+) */$2/g;
|
cannam@95
|
172 $comma = "";
|
cannam@95
|
173 foreach $argname (split(/ *, */, $argnames)) {
|
cannam@95
|
174 if ($len + length("$comma$argname") + 3 > 132) {
|
cannam@95
|
175 printf ", &\n%*s", $len0, "";
|
cannam@95
|
176 $len = $len0;
|
cannam@95
|
177 $comma = "";
|
cannam@95
|
178 }
|
cannam@95
|
179 print "$comma$argname";
|
cannam@95
|
180 $len = $len + length("$comma$argname");
|
cannam@95
|
181 $comma = ",";
|
cannam@95
|
182 }
|
cannam@95
|
183 print ") "; $len = $len + 2;
|
cannam@95
|
184
|
cannam@95
|
185 if ($len + length("bind(C, name='$cname')") > 132) {
|
cannam@95
|
186 printf "&\n%*s", $len0 - length("$name("), "";
|
cannam@95
|
187 }
|
cannam@95
|
188 print "bind(C, name='$cname')\n";
|
cannam@95
|
189
|
cannam@95
|
190 print " import\n";
|
cannam@95
|
191 foreach $arg (split(/ *, */, $args)) {
|
cannam@95
|
192 $arg =~ /^([a-zA-Z_0-9 ]+[ \*]) *([a-zA-Z_0-9]+) *$/;
|
cannam@95
|
193 $argtype = &canonicalize_type($1);
|
cannam@95
|
194 $argname = $2;
|
cannam@95
|
195 $ftype = $arg_types{$argtype};
|
cannam@95
|
196
|
cannam@95
|
197 # Various special cases for argument types:
|
cannam@95
|
198 if ($name =~ /_flops$/ && $argtype eq "double *") {
|
cannam@95
|
199 $ftype = "real(C_DOUBLE), intent(out)"
|
cannam@95
|
200 }
|
cannam@95
|
201 if ($name =~ /_execute/ && ($argname eq "ri" ||
|
cannam@95
|
202 $argname eq "ii" ||
|
cannam@95
|
203 $argname eq "in")) {
|
cannam@95
|
204 $ftype =~ s/intent\(out\)/intent(inout)/;
|
cannam@95
|
205 }
|
cannam@95
|
206
|
cannam@95
|
207 print " $ftype :: $argname\n"
|
cannam@95
|
208 }
|
cannam@95
|
209
|
cannam@95
|
210 print " end $kind $name\n";
|
cannam@95
|
211 print " \n";
|
cannam@95
|
212 }
|
cannam@95
|
213 }
|