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