Bug Summary

File:src/gf_fortran.c
Warning:line 2002, column 4
Value stored to 'tmpfoam' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name gf_fortran.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/home/kfp/aldor/aldor/aldor/src -fcoverage-compilation-dir=/home/kfp/aldor/aldor/aldor/src -resource-dir /usr/local/lib/clang/18 -D PACKAGE_NAME="aldor" -D PACKAGE_TARNAME="aldor" -D PACKAGE_VERSION="1.4.0" -D PACKAGE_STRING="aldor 1.4.0" -D PACKAGE_BUGREPORT="aldor@xinutec.org" -D PACKAGE_URL="" -D PACKAGE="aldor" -D VERSION="1.4.0" -D YYTEXT_POINTER=1 -D HAVE_STDIO_H=1 -D HAVE_STDLIB_H=1 -D HAVE_STRING_H=1 -D HAVE_INTTYPES_H=1 -D HAVE_STDINT_H=1 -D HAVE_STRINGS_H=1 -D HAVE_SYS_STAT_H=1 -D HAVE_SYS_TYPES_H=1 -D HAVE_UNISTD_H=1 -D STDC_HEADERS=1 -D HAVE_LIBREADLINE=1 -D HAVE_READLINE_READLINE_H=1 -D HAVE_READLINE_HISTORY=1 -D HAVE_READLINE_HISTORY_H=1 -D USE_GLOOP_SHELL=1 -D GENERATOR_COROUTINES=0 -D HAVE_DLFCN_H=1 -D LT_OBJDIR=".libs/" -I . -D VCSVERSION="2c53e759f1e00e345f8b172e7139debda72fda13" -internal-isystem /usr/local/lib/clang/18/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -Wno-empty-body -Wno-enum-compare -Wno-missing-field-initializers -Wno-unused -Wno-unused-parameter -Wno-error=format -Wno-error=type-limits -Wno-error=strict-aliasing -Wno-sign-compare -Wno-error=shift-negative-value -Wno-error=clobbered -std=c99 -ferror-limit 19 -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2026-01-15-223856-845667-1 -x c gf_fortran.c
1/*****************************************************************************
2 *
3 * gf_fortran.c: Foam code generation for the Aldor/Fortran interface.
4 *
5 * Copyright (c) 1990-2007 Aldor Software Organization Ltd (Aldor.org).
6 *
7 ****************************************************************************/
8
9/*
10 * This file handles almost all the code relating to the Aldor/Fortran
11 * interface. The remaining bits are left in genfoam and with some of
12 * the support functions in gf_rtime.c.
13 *
14 * To do:
15 * - factor out the conversions into separate functions
16 * - split gen0ModifyFortranCall into lots of little functions
17 * - shift the Aldor/Fortran conversions out to libraries
18 */
19
20
21/* TODO: delete the #includes that aren't needed anymore */
22#include "compcfg.h"
23#include "fortran.h"
24#include "genfoam.h"
25#include "gf_add.h"
26#include "gf_excpt.h"
27#include "gf_fortran.h"
28#include "gf_gener.h"
29#include "gf_imps.h"
30#include "gf_prog.h"
31#include "gf_reference.h"
32#include "gf_rtime.h"
33#include "gf_util.h"
34#include "of_util.h"
35#include "optfoam.h"
36#include "optinfo.h"
37#include "opttools.h"
38#include "scobind.h"
39#include "simpl.h"
40#include "spesym.h"
41#include "stab.h"
42#include "tform.h"
43#include "util.h"
44#include "sefo.h"
45#include "comsg.h"
46#include "strops.h"
47
48
49extern Bool genfoamDebug;
50extern Bool genfoamHashDebug;
51extern Bool genfoamConstDebug;
52
53/*****************************************************************************
54 *
55 * :: Local functions for the Aldor-calls-Fortran side.
56 *
57 ****************************************************************************/
58
59localstatic Foam gen0FtnFunValue (Foam, TForm, Syme);
60localstatic Foam gen0FtnArrayValue (AbSyn, Foam, TForm);
61localstatic Foam gen0FtnUpdateArray (AbSyn, Foam, Foam, TForm);
62localstatic Foam gen0FtnFSArrayValue (AbSyn, Foam, TForm);
63localstatic Foam gen0FtnUpdateFSArray (AbSyn, Foam, Foam, TForm);
64localstatic Foam gen0FtnFSArrayLen (AbSyn, Foam, TForm);
65
66#if 0
67localstatic Foam gen0MakeAutoApply(AbSyn, Syme, TForm, FoamTag, AInt, Foam *);
68localstatic Foam gen0FtnComplexGet (AbSyn, Foam, TForm, SymeList);
69localstatic Foam gen0FtnComplexPut (AbSyn, Foam, TForm, SymeList);
70#endif
71
72
73/*****************************************************************************
74 *
75 * Foam code generation for Aldor-calls-Fortran
76 *
77 ****************************************************************************/
78
79/*
80 * Rewrite the FOAM for a Fortran function/procedure call so that
81 * the actual PCall is executed with arguments and return values
82 * in Fortran format. Once we have finished mangling the call there
83 * is very little work for genc to do.
84 *
85 * Future work: we ought not to make any assumptions about the format
86 * of FTN_FSComplex values etc. Instead we ought to apply the coerce
87 * function exported by domains satisfying FortranComplexReal etc.
88 */
89Foam
90gen0ModifyFortranCall(Syme syme, Foam call, AbSyn ftnFnResult, Bool valueMode)
91{
92 TForm tf = symeType(syme);
93 Length argc = tfMapArgc(tf), i;
94 Foam arg, res;
95 Foam foam;
96 FoamList fixups;
97 int numresults;
98
99 /* --------------------------------------------- */
100 /* This function is FAR too long and needs to be */
101 /* cut into tiny fragments to make it readable. */
102 /* --------------------------------------------- */
103
104 TForm tfret;
105 Foam *argloc;
106 Foam tmpfoam, tmpvar, tmpget, tmpset;
107 Foam rhs;
108 Foam cpx, creal, cimag, rpart, ipart;
109 FoamList befCall, aftCall;
110 FortranType ftnType, ftnRetType;
111 FoamTag fmType, refType;
112 int extraArg;
113 AInt cfmt, afmt, dfmt;
114
115 /* Compute return types */
116 tfret = tfMapRet(tf)tfFollowArg(tf, 1);
117 ftnRetType = ftnTypeFrDomTForm(tfret);
118
119
120 /* Treat Char and Character in the same way */
121 if (!ftnRetType && (gen0Type(tfret, NULL((void*)0)) == FOAM_Char))
122 ftnRetType = FTN_Character;
123
124
125 /* Do we have an extra first argument? */
126 switch (ftnRetType)
127 {
128 case FTN_Character:
129 case FTN_String:
130 case FTN_XLString:
131 extraArg = 1;
132 break;
133 default:
134 extraArg = 0;
135 break;
136 }
137
138 if (tfMapRetc(tf) > 1)
139 bug("Too many return values for fortran function");
140
141
142 numresults = tfMapArgc(tf);
143
144 if (!tfIsNone(tfMapRet(tf))((((tfFollowArg(tf, 1))->tag) == TF_Multiple) && tfMultiArgc
(tfFollowArg(tf, 1)) == 0)
|| ftnFnResult)
145 numresults += 1;
146
147
148 foam = call; /* Why do we alias call in this way? */
149 fixups = listNil(Foam)((FoamList) 0);
150 befCall = listNil(Foam)((FoamList) 0);
151 aftCall = listNil(Foam)((FoamList) 0);
152
153
154 for (i = 0; i < argc; i++) {
155 TForm tfi, tfiget, tfiset;
156 FoamList ltmp;
157 Bool isReference;
158 AbSyn tmpab;
159 FoamTag fmret;
160 Foam retfoam, recfoam;
161 Foam tmparr = (Foam)NULL((void*)0);
162 SrcPos fp;
163 AInt cfmt, afmt;
164
165 tfi = tfMapArgN(tf, i);
166 arg = foam->foamPCall.argv[i + extraArg];
167 fp = foamPos(arg)((arg)->hdr.pos);
168 tmpab = abNewNothing(fp)abNew(AB_Nothing, fp,0 );
169
170
171 /* Skip any declaration */
172 if (tfIsDeclare(tfi)(((tfi)->tag) == TF_Declare))
173 tfi = tfDeclareType(tfi)tfFollowArg(tfi, 0);
174
175
176 /* Is it a reference? */
177 if ((isReference = tfIsReferenceFn(tfi)))
178 tfi = tfReferenceArg(tfi)tfFollowArg(tfi, 0);
179
180
181 /* What is the type of this argument? */
182 ftnType = ftnTypeFrDomTForm(tfi);
183 fmType = gen0Type(tfi, NULL((void*)0));
184
185
186 /*
187 * Check to see if this is a known Fortran type. We
188 * really ought to be doing this during when we are
189 * processing the import/export declaration.
190 */
191 if (!ftnType)
192 {
193 switch (fmType)
194 {
195 case FOAM_Bool: /* Fall through */
196 case FOAM_Char: /* Fall through */
197 case FOAM_SInt: /* Fall through */
198 case FOAM_SFlo: /* Fall through */
199 case FOAM_DFlo: /* Fall through */
200 case FOAM_Clos: /* Fall through */
201 break;
202 default:
203 comsgWarnPos(fp, ALDOR_W_FtnNotFtnArg11);
204 }
205 }
206
207
208 /* Remove the casts (if any) */
209 while (foamTag(arg)((arg)->hdr.tag) == FOAM_Cast)
210 arg = arg->foamCast.expr;
211
212
213 if (isReference)
214 {
215 /*
216 * When presented with the Aldor:
217 *
218 * local a:T;
219 * import {foo: (Ref T) -> ()} from Foreign Fortran;
220 * foo(ref(a));
221 *
222 * the compiler converts ref(a) into a nullary
223 * function which returns a multi of two functions,
224 * the getter and the setter.
225 *
226 * local a:T;
227 * import {foo: (Ref T) -> ()} from Foreign Fortran;
228 * foo
229 * (
230 * ():Cross(()->T, T->T) +->
231 * (
232 * deref == ():T +-> {free a:T; a},
233 * update! == (v:T):T +-> {free a:T; a := v; v}
234 * )
235 * )
236 *
237 * What we need to do here is extract the getter and
238 * setter functions and then apply the getter function
239 * to initialise the temporary variable. This temporary
240 * is passed to Fortran and its value after the call
241 * is used in an application of the setter function.
242 */
243
244
245 /* Compute the return types of the functions */
246 tfiget = tfMap(tfNone()tfMulti(0), tfi);
247 tfiset = tfMap(tfi, tfi);
248 tfret = tfMulti(2, tfiget, tfiset);
249 fmret = gen0Type(tfret, NULL((void*)0));
250
251
252 /* Extract the getter/setter pair. */
253 retfoam = foamCopy(arg);
254 retfoam = gen0CCallFrFoam(fmret, retfoam,(Length) 0, &argloc);
255 retfoam = gen0ApplyReturn(tmpab, (Syme)NULL((void*)0), tfret,
256 retfoam);
257
258
259 /* Extract the getter */
260 tmpfoam = foamCopy(retfoam);
261 assert(foamTag(tmpfoam) == FOAM_Values)do { if (!(((tmpfoam)->hdr.tag) == FOAM_Values)) _do_assert
(("foamTag(tmpfoam) == FOAM_Values"),"gf_fortran.c",261); } while
(0)
;
262 tmpget = tmpfoam->foamValues.argv[0];
263
264
265 /* Extract the setter */
266 tmpfoam = foamCopy(retfoam);
267 assert(foamTag(tmpfoam) == FOAM_Values)do { if (!(((tmpfoam)->hdr.tag) == FOAM_Values)) _do_assert
(("foamTag(tmpfoam) == FOAM_Values"),"gf_fortran.c",267); } while
(0)
;
268 tmpset = tmpfoam->foamValues.argv[1];
269
270
271 /* Extract the value to pass to the function */
272 tmpfoam = gen0CCallFrFoam(fmType, tmpget,(Length) 0, &argloc);
273 tmpfoam = gen0ApplyReturn(tmpab, (Syme)NULL((void*)0), tfi,
274 tmpfoam);
275 }
276 else {
277 tmpfoam = arg;
278 tmpset = 0;
279 }
280
281
282 /*
283 * Since Fortran uses call-by-reference we need to
284 * pass a pointer to each argument rather than the
285 * argument itself. We need to do this now rather than
286 * during C code generation otherwise the optimiser
287 * will perform invalid transformations on the FOAM.
288 *
289 * This part looks messy but it works and it makes
290 * C generation much simpler. The basic technique
291 * is to convert SingleInteger/SingleFloat etc into
292 * the corresponding machine types SInt/SFlo etc
293 * and stuff these in a record. We assume that any
294 * unrecognised type is represented as a pointer to
295 * something and will always be passed by reference.
296 * The user will have been warned about this already.
297 *
298 * Array-like objects are passed through conversion
299 * conversion functions before and after the call.
300 * This allows, for example, sparse arrays to be
301 * passed to a Fortran function expecting a dense
302 * array and allows multi-dimensional arrays to be
303 * changed into Fortran format.
304 *
305 * Complex numbers are assumed to be represented as
306 * as Record(real:R, imag:R) where R is SingleFloat
307 * or DoubleFloat (which is Record(x:DFlo). These
308 * values are converted into the correct Fortran
309 * format values for the call.
310 */
311 switch (ftnType)
312 {
313 case FTN_Character :
314 refType = FOAM_Char;
315 tmpfoam = foamNewCast(refType, tmpfoam)foamNew(FOAM_Cast, 2, refType, tmpfoam);
316 break;
317 case FTN_Boolean :
318 /* Fall through */
319 case FTN_SingleInteger :
320 /* Store in a record */
321 refType = FOAM_SInt;
322 tmpfoam = foamNewCast(refType, tmpfoam)foamNew(FOAM_Cast, 2, refType, tmpfoam);
323 break;
324 case FTN_FSingle :
325 refType = FOAM_SFlo;
326 tmpfoam = foamNewCast(refType, tmpfoam)foamNew(FOAM_Cast, 2, refType, tmpfoam);
327 break;
328 case FTN_FDouble :
329 refType = FOAM_DFlo;
330 tmpfoam = gen0DoubleValue(foamCopy(tmpfoam));
331 break;
332 case FTN_FSComplex:
333 /* Convert Complex SF into COMPLEX REAL */
334 refType = FOAM_Word;
335
336 /* Create a Fortran-format local */
337 cfmt = gen0SingleCpxFormat(); /* COMPLEX REAL */
338 afmt = gen0AldorCpxFormat(); /* Complex SF */
339 cpx = gen0TempLocal0(FOAM_Rec, cfmt);
340
341 /* Allocate storage for the COMPLEX REAL */
342 recfoam = gen0RNew(cpx, cfmt)foamNew(FOAM_Set, 2, foamCopy(cpx), foamNew(FOAM_RNew, 1, cfmt
))
;
343 befCall = listCons(Foam)(Foam_listPointer->Cons)(recfoam, befCall);
344
345 /* Copy the real part of the Complex SF */
346 creal = foamNewRElt(afmt, foamCopy(tmpfoam), (AInt)0)foamNew(FOAM_RElt,3,(AInt)(afmt),foamCopy(tmpfoam),(AInt)((AInt
)0))
;
347 creal = foamNewCast(FOAM_SFlo, creal)foamNew(FOAM_Cast, 2, FOAM_SFlo, creal);
348 creal = gen0RSet(foamCopy(cpx), cfmt, (AInt)0, creal)foamNew(FOAM_Set, 2, foamNew(FOAM_RElt,3,(AInt)(cfmt),foamCopy
(foamCopy(cpx)),(AInt)((AInt)0)), creal)
;
349 befCall = listCons(Foam)(Foam_listPointer->Cons)(creal, befCall);
350
351 /* Copy the imaginary part */
352 cimag = foamNewRElt(afmt, foamCopy(tmpfoam), (AInt)1)foamNew(FOAM_RElt,3,(AInt)(afmt),foamCopy(tmpfoam),(AInt)((AInt
)1))
;
353 cimag = foamNewCast(FOAM_SFlo, cimag)foamNew(FOAM_Cast, 2, FOAM_SFlo, cimag);
354 cimag = gen0RSet(foamCopy(cpx), cfmt, (AInt)1, cimag)foamNew(FOAM_Set, 2, foamNew(FOAM_RElt,3,(AInt)(cfmt),foamCopy
(foamCopy(cpx)),(AInt)((AInt)1)), cimag)
;
355 befCall = listCons(Foam)(Foam_listPointer->Cons)(cimag, befCall);
356
357 /* Now use the Fortran-format local */
358 tmpfoam = foamCopy(cpx);
359 break;
360 case FTN_FDComplex:
361 /* Convert Complex DF into COMPLEX DOUBLE */
362 refType = FOAM_Word;
363
364 /* Create a Fortran-format local */
365 cfmt = gen0DoubleCpxFormat(); /* COMPLEX DOUBLE */
366 afmt = gen0AldorCpxFormat(); /* Complex DF */
367 dfmt = gen0MakeDoubleFormat(); /* DF */
368 cpx = gen0TempLocal0(FOAM_Rec, cfmt);
369
370 /* Allocate storage for the COMPLEX DOUBLE */
371 recfoam = gen0RNew(cpx, cfmt)foamNew(FOAM_Set, 2, foamCopy(cpx), foamNew(FOAM_RNew, 1, cfmt
))
;
372 befCall = listCons(Foam)(Foam_listPointer->Cons)(recfoam, befCall);
373
374 /* Copy the real DFlo part of the Complex DF */
375 creal = foamNewRElt(afmt, foamCopy(tmpfoam), (AInt)0)foamNew(FOAM_RElt,3,(AInt)(afmt),foamCopy(tmpfoam),(AInt)((AInt
)0))
;
376 creal = foamNewRElt(dfmt, creal, (AInt)0)foamNew(FOAM_RElt,3,(AInt)(dfmt),creal,(AInt)((AInt)0));
377 creal = gen0RSet(foamCopy(cpx), cfmt, (AInt)0, creal)foamNew(FOAM_Set, 2, foamNew(FOAM_RElt,3,(AInt)(cfmt),foamCopy
(foamCopy(cpx)),(AInt)((AInt)0)), creal)
;
378 befCall = listCons(Foam)(Foam_listPointer->Cons)(creal, befCall);
379
380 /* Copy the imaginary part */
381 cimag = foamNewRElt(afmt, foamCopy(tmpfoam), (AInt)1)foamNew(FOAM_RElt,3,(AInt)(afmt),foamCopy(tmpfoam),(AInt)((AInt
)1))
;
382 cimag = foamNewRElt(dfmt, cimag, (AInt)0)foamNew(FOAM_RElt,3,(AInt)(dfmt),cimag,(AInt)((AInt)0));
383 cimag = gen0RSet(foamCopy(cpx), cfmt, (AInt)1, cimag)foamNew(FOAM_Set, 2, foamNew(FOAM_RElt,3,(AInt)(cfmt),foamCopy
(foamCopy(cpx)),(AInt)((AInt)1)), cimag)
;
384 befCall = listCons(Foam)(Foam_listPointer->Cons)(cimag, befCall);
385
386 /* Now use the Fortran-format local */
387 tmpfoam = foamCopy(cpx);
388 break;
389 case FTN_StringArray:
390 /* Replace with (BArr, SInt) pair */
391 refType = fmType;
392
393 /* Store the original array value in a local */
394 tmparr = gen0TempLocal(refType)gen0TempLocal0(refType, 4);
395 tmpfoam = foamNewSet(tmparr, tmpfoam)foamNew(FOAM_Set, 2, tmparr, tmpfoam);
396 befCall = listCons(Foam)(Foam_listPointer->Cons)(tmpfoam, befCall);
397
398 /* Apply the array converter */
399 tmpfoam = gen0FtnFSArrayValue(tmpab, tmparr, tfi);
400 break;
401 case FTN_Array:
402 refType = fmType;
403
404 /* Store the original array value in a local */
405 tmparr = gen0TempLocal(refType)gen0TempLocal0(refType, 4);
406 tmpfoam = foamNewSet(tmparr, tmpfoam)foamNew(FOAM_Set, 2, tmparr, tmpfoam);
407 befCall = listCons(Foam)(Foam_listPointer->Cons)(tmpfoam, befCall);
408
409 /* Apply the array converter */
410 tmpfoam = gen0FtnArrayValue(tmpab, tmparr, tfi);
411 break;
412 default:
413 switch (fmType)
414 {
415 case FOAM_Bool:
416 refType = FOAM_SInt;
417 tmpfoam = foamNewCast(refType, foamCopy(tmpfoam))foamNew(FOAM_Cast, 2, refType, foamCopy(tmpfoam));
418 break;
419 case FOAM_Clos :
420 refType = FOAM_Clos;
421 tmpfoam = gen0FtnFunValue(tmpfoam, tfi, syme);
422 break;
423 default:
424 refType = fmType;
425 break;
426 }
427 break;
428 }
429
430
431 /* Before the call we do all our packing */
432 if (ftnType == FTN_StringArray)
433 {
434 /* Safety checks */
435 assert(foamTag(tmpfoam) == FOAM_Values)do { if (!(((tmpfoam)->hdr.tag) == FOAM_Values)) _do_assert
(("foamTag(tmpfoam) == FOAM_Values"),"gf_fortran.c",435); } while
(0)
;
436 assert(foamArgc(tmpfoam) == 2)do { if (!(((tmpfoam)->hdr.argc) == 2)) _do_assert(("foamArgc(tmpfoam) == 2"
),"gf_fortran.c",436); } while (0)
;
437
438
439 /*
440 * Replace the BArr in the FOAM_Values pair
441 * with a temporary variable.
442 */
443 tmpvar = tmpfoam;
444 tmpfoam = tmpvar->foamValues.argv[0];
445 tmpfoam = gen0MakePointerTo(refType, tmpfoam, &ltmp);
446 tmpvar->foamValues.argv[0] = tmpfoam;
447 }
448 else
449 tmpvar = gen0MakePointerTo(refType, tmpfoam, &ltmp);
450
451
452 /* Code to be executed before the call */
453 befCall = listNConcat(Foam)(Foam_listPointer->NConcat)(ltmp, befCall);
454
455
456 /*
457 * The argument to the call is now the tmpvar
458 * unless it is an StringArray, in which case
459 * it will be a FOAM_Values.
460 */
461 call->foamPCall.argv[i + extraArg] = foamCopy(tmpvar);
462
463
464 /*
465 * In Aldor, array elements are always passed by
466 * reference. Since Fortran can only change the
467 * elements of an array (it cannot change where the
468 * array will find the elements) there is no need
469 * to apply the ref-setter for arrays passed using
470 * ref(). However, we do need to apply the convert
471 * export from FortranArray to allow the elements
472 * of the array to be updated.
473 *
474 * Complex numbers also need special care if they
475 * are passed by reference: the updated Fortran
476 * value must be converted into a Complex R value
477 * which can be used by the ref-setter.
478 *
479 * For all other types that we recognise, we need
480 * to generate code to be executed immediately after
481 * the call which applies the ref-setter to update
482 * the Aldor reference.
483 */
484 if (ftnType == FTN_Array)
485 {
486 /* tmparr holds the original array value */
487 tmpfoam = gen0FtnUpdateArray(tmpab, tmparr, tmpvar, tfi);
488 aftCall = listCons(Foam)(Foam_listPointer->Cons)(tmpfoam, aftCall);
489 }
490 else if (ftnType == FTN_StringArray)
491 {
492 /*
493 * tmparr holds the original array value while
494 * tmpvar holds a FOAM_Values with two elements,
495 * the flattened array and the length of the
496 * fixed string elements.
497 */
498 assert(foamTag(tmpvar) == FOAM_Values)do { if (!(((tmpvar)->hdr.tag) == FOAM_Values)) _do_assert
(("foamTag(tmpvar) == FOAM_Values"),"gf_fortran.c",498); } while
(0)
;
499 assert(foamArgc(tmpvar) == 2)do { if (!(((tmpvar)->hdr.argc) == 2)) _do_assert(("foamArgc(tmpvar) == 2"
),"gf_fortran.c",499); } while (0)
;
500 tmpfoam = gen0FtnUpdateFSArray(tmpab, tmparr, tmpvar, tfi);
501 aftCall = listCons(Foam)(Foam_listPointer->Cons)(tmpfoam, aftCall);
502 }
503 else if (isReference)
504 {
505 /*
506 * Now add the after-call code. References
507 * need to be updated with their new value,
508 * other values are just ignored.
509 *
510 * To do: use gen0FortranConvArg()
511 */
512 tmpfoam = gen0ReadPointerTo(refType, tmpvar);
513 switch (ftnType)
514 {
515 case FTN_Character :
516 /* Fall through */
517 case FTN_Boolean :
518 /* Fall through */
519 case FTN_SingleInteger :
520 tmpfoam = foamNewCast(FOAM_Word, tmpfoam)foamNew(FOAM_Cast, 2, FOAM_Word, tmpfoam);
521 break;
522 case FTN_FSingle :
523 tmpfoam = foamNewCast(FOAM_Word, tmpfoam)foamNew(FOAM_Cast, 2, FOAM_Word, tmpfoam);
524 break;
525 case FTN_FDouble :
526 tmpfoam = gen0MakeDoubleCode(tmpfoam, &ltmp);
527 aftCall = listNConcat(Foam)(Foam_listPointer->NConcat)(ltmp, aftCall);
528 break;
529 case FTN_FSComplex:
530 /*
531 * Convert COMPLEX REAL into Complex SF. To
532 * do this we store the updated Fortran value
533 * in a local. Then we copy and convert the
534 * two components into a new local which is
535 * passed to the ref-setter.
536 */
537 cfmt = gen0SingleCpxFormat();
538 afmt = gen0AldorCpxFormat();
539
540 /* Create a local and store the updated value */
541 tmpvar = gen0TempLocal0(FOAM_Rec, cfmt);
542 tmpfoam = foamNewSet(foamCopy(tmpvar), tmpfoam)foamNew(FOAM_Set, 2, foamCopy(tmpvar), tmpfoam);
543 aftCall = listCons(Foam)(Foam_listPointer->Cons)(tmpfoam, aftCall);
544
545 /* Allocate storage for the Complex SF result */
546 res = gen0TempLocal0(FOAM_Rec, afmt);
547 tmpfoam = gen0RNew(foamCopy(res), afmt)foamNew(FOAM_Set, 2, foamCopy(foamCopy(res)), foamNew(FOAM_RNew
, 1, afmt))
;
548 aftCall = listCons(Foam)(Foam_listPointer->Cons)(tmpfoam, aftCall);
549
550 /* Copy the real part into the local */
551 creal = foamNewRElt(cfmt, foamCopy(tmpvar),foamNew(FOAM_RElt,3,(AInt)(cfmt),foamCopy(tmpvar),(AInt)((AInt
)0))
552 (AInt)0)foamNew(FOAM_RElt,3,(AInt)(cfmt),foamCopy(tmpvar),(AInt)((AInt
)0))
;
553 creal = foamNewCast(FOAM_Word, creal)foamNew(FOAM_Cast, 2, FOAM_Word, creal);
554 creal = gen0RSet(foamCopy(res), afmt, (AInt)0,foamNew(FOAM_Set, 2, foamNew(FOAM_RElt,3,(AInt)(afmt),foamCopy
(foamCopy(res)),(AInt)((AInt)0)), creal)
555 creal)foamNew(FOAM_Set, 2, foamNew(FOAM_RElt,3,(AInt)(afmt),foamCopy
(foamCopy(res)),(AInt)((AInt)0)), creal)
;
556 aftCall = listCons(Foam)(Foam_listPointer->Cons)(creal, aftCall);
557
558 /* Copy the imaginary part into the local */
559 cimag = foamNewRElt(cfmt, foamCopy(tmpvar),foamNew(FOAM_RElt,3,(AInt)(cfmt),foamCopy(tmpvar),(AInt)((AInt
)1))
560 (AInt)1)foamNew(FOAM_RElt,3,(AInt)(cfmt),foamCopy(tmpvar),(AInt)((AInt
)1))
;
561 cimag = foamNewCast(FOAM_Word, cimag)foamNew(FOAM_Cast, 2, FOAM_Word, cimag);
562 cimag = gen0RSet(foamCopy(res), afmt, (AInt)1,foamNew(FOAM_Set, 2, foamNew(FOAM_RElt,3,(AInt)(afmt),foamCopy
(foamCopy(res)),(AInt)((AInt)1)), cimag)
563 cimag)foamNew(FOAM_Set, 2, foamNew(FOAM_RElt,3,(AInt)(afmt),foamCopy
(foamCopy(res)),(AInt)((AInt)1)), cimag)
;
564 aftCall = listCons(Foam)(Foam_listPointer->Cons)(cimag, aftCall);
565
566 /* Use the Complex DF as the result */
567 tmpfoam = res;
568 break;
569 case FTN_FDComplex:
570 /*
571 * Convert COMPLEX DOUBLE into Complex DF.
572 * To do this we store the updated Fortran
573 * value in a local. Then we copy and convert
574 * the two components into a new local which
575 * is passed to the ref-setter.
576 */
577 cfmt = gen0DoubleCpxFormat();
578 afmt = gen0AldorCpxFormat();
579 dfmt = gen0MakeDoubleFormat();
580
581 /* Create a local and store the updated value */
582 tmpvar = gen0TempLocal0(FOAM_Rec, cfmt);
583 tmpfoam = foamNewSet(foamCopy(tmpvar), tmpfoam)foamNew(FOAM_Set, 2, foamCopy(tmpvar), tmpfoam);
584 aftCall = listCons(Foam)(Foam_listPointer->Cons)(tmpfoam, aftCall);
585
586
587 /* Create a DF for the real part */
588 rpart = gen0TempLocal0(FOAM_Rec, dfmt);
589 tmpfoam = gen0RNew(foamCopy(rpart), dfmt)foamNew(FOAM_Set, 2, foamCopy(foamCopy(rpart)), foamNew(FOAM_RNew
, 1, dfmt))
;
590 aftCall = listCons(Foam)(Foam_listPointer->Cons)(tmpfoam, aftCall);
591
592
593 /* Copy the real DFlo part into the DF */
594 creal = foamNewRElt(cfmt, foamCopy(tmpvar),foamNew(FOAM_RElt,3,(AInt)(cfmt),foamCopy(tmpvar),(AInt)((AInt
)0))
595 (AInt)0)foamNew(FOAM_RElt,3,(AInt)(cfmt),foamCopy(tmpvar),(AInt)((AInt
)0))
;
596 creal = gen0RSet(foamCopy(rpart), dfmt,foamNew(FOAM_Set, 2, foamNew(FOAM_RElt,3,(AInt)(dfmt),foamCopy
(foamCopy(rpart)),(AInt)((AInt)0)), creal)
597 (AInt)0, creal)foamNew(FOAM_Set, 2, foamNew(FOAM_RElt,3,(AInt)(dfmt),foamCopy
(foamCopy(rpart)),(AInt)((AInt)0)), creal)
;
598 aftCall = listCons(Foam)(Foam_listPointer->Cons)(creal, aftCall);
599
600
601 /* Create a DF for the imaginary part */
602 ipart = gen0TempLocal0(FOAM_Rec, dfmt);
603 tmpfoam = gen0RNew(foamCopy(ipart), dfmt)foamNew(FOAM_Set, 2, foamCopy(foamCopy(ipart)), foamNew(FOAM_RNew
, 1, dfmt))
;
604 aftCall = listCons(Foam)(Foam_listPointer->Cons)(tmpfoam, aftCall);
605
606
607 /* Copy the imaginary part into the DF */
608 cimag = foamNewRElt(cfmt, foamCopy(tmpvar),foamNew(FOAM_RElt,3,(AInt)(cfmt),foamCopy(tmpvar),(AInt)((AInt
)1))
609 (AInt)1)foamNew(FOAM_RElt,3,(AInt)(cfmt),foamCopy(tmpvar),(AInt)((AInt
)1))
;
610 cimag = gen0RSet(foamCopy(ipart), dfmt,foamNew(FOAM_Set, 2, foamNew(FOAM_RElt,3,(AInt)(dfmt),foamCopy
(foamCopy(ipart)),(AInt)((AInt)0)), cimag)
611 (AInt)0, cimag)foamNew(FOAM_Set, 2, foamNew(FOAM_RElt,3,(AInt)(dfmt),foamCopy
(foamCopy(ipart)),(AInt)((AInt)0)), cimag)
;
612 aftCall = listCons(Foam)(Foam_listPointer->Cons)(cimag, aftCall);
613
614
615 /* Create the Complex DF */
616 res = gen0TempLocal0(FOAM_Rec, afmt);
617 tmpfoam = gen0RNew(foamCopy(res), afmt)foamNew(FOAM_Set, 2, foamCopy(foamCopy(res)), foamNew(FOAM_RNew
, 1, afmt))
;
618 aftCall = listCons(Foam)(Foam_listPointer->Cons)(tmpfoam, aftCall);
619
620
621 /* Fill in the slots of the Complex DF */
622 creal = gen0RSet(foamCopy(res), afmt, (AInt)0,foamNew(FOAM_Set, 2, foamNew(FOAM_RElt,3,(AInt)(afmt),foamCopy
(foamCopy(res)),(AInt)((AInt)0)), foamCopy(rpart))
623 foamCopy(rpart))foamNew(FOAM_Set, 2, foamNew(FOAM_RElt,3,(AInt)(afmt),foamCopy
(foamCopy(res)),(AInt)((AInt)0)), foamCopy(rpart))
;
624 cimag = gen0RSet(foamCopy(res), afmt, (AInt)1,foamNew(FOAM_Set, 2, foamNew(FOAM_RElt,3,(AInt)(afmt),foamCopy
(foamCopy(res)),(AInt)((AInt)1)), foamCopy(ipart))
625 foamCopy(ipart))foamNew(FOAM_Set, 2, foamNew(FOAM_RElt,3,(AInt)(afmt),foamCopy
(foamCopy(res)),(AInt)((AInt)1)), foamCopy(ipart))
;
626 aftCall = listCons(Foam)(Foam_listPointer->Cons)(creal, aftCall);
627 aftCall = listCons(Foam)(Foam_listPointer->Cons)(cimag, aftCall);
628
629
630 /* Use the Complex DF as the result */
631 tmpfoam = res;
632 break;
633 default:
634 switch (fmType)
635 {
636 case FOAM_Bool:
637 tmpfoam = foamNewCast(fmType, tmpfoam)foamNew(FOAM_Cast, 2, fmType, tmpfoam);
638 break;
639 default :
640 break;
641 }
642 break;
643 }
644
645
646 /* Invoke the setter to update the reference */
647 rhs = gen0CCallFrFoam(fmType, tmpset, 1, &argloc);
648 argloc[0] = foamCopy(tmpfoam);
649 tmpfoam = gen0ApplyReturn(tmpab, (Syme)NULL((void*)0), tfi, rhs);
650 aftCall = listCons(Foam)(Foam_listPointer->Cons)(tmpfoam, aftCall);
651 }
652 }
653
654
655 /* Emit the code to be executed before the function call */
656 befCall = listNReverse(Foam)(Foam_listPointer->NReverse)(befCall);
657 while (befCall)
658 {
659 gen0AddStmt(car(befCall)((befCall)->first), NULL((void*)0));
660 befCall = listFreeCons(Foam)(Foam_listPointer->FreeCons)(befCall);
661 }
662
663
664 /* Generate the Fortran call */
665 if (numresults && valueMode)
666 {
667 /*
668 * Bool, Boolean, SingleFloat, DoubleFloat,
669 * Complex(SingleFloat) and Complex(DoubleFloat)
670 * are special cases.
671 */
672 tfret = tfMapRet(tf)tfFollowArg(tf, 1);
673 fmType = gen0Type(tfret, NULL((void*)0));
674 ftnType = ftnTypeFrDomTForm(tfret);
675
676 switch (ftnType)
677 {
678 case FTN_FSingle:
679 /*
680 * Store the SFlo result in a newly created
681 * SingleFloat. Add the cast and return.
682 */
683 call->foamPCall.type = FOAM_SFlo;
684 tmpvar = gen0TempLocal(FOAM_Word)gen0TempLocal0(FOAM_Word, 4);
685 tmpfoam = foamNewCast(FOAM_Word, foamCopy(foam))foamNew(FOAM_Cast, 2, FOAM_Word, foamCopy(foam));
686 tmpfoam = foamNewSet(foamCopy(tmpvar), tmpfoam)foamNew(FOAM_Set, 2, foamCopy(tmpvar), tmpfoam);
687 gen0AddStmt(tmpfoam, NULL((void*)0));
688 res = foamCopy(tmpvar);
689 break;
690 case FTN_FDouble:
691 /*
692 * Store DFlo result in a newly created
693 * DoubleFloat. Add appropriate casts and
694 * return the result.
695 */
696 call->foamPCall.type = FOAM_DFlo;
697 tmpvar = gen0TempLocal(FOAM_Word)gen0TempLocal0(FOAM_Word, 4);
698 tmpfoam = gen0MakeDouble(foamCopy(foam));
699 tmpfoam = foamNewSet(foamCopy(tmpvar), tmpfoam)foamNew(FOAM_Set, 2, foamCopy(tmpvar), tmpfoam);
700 gen0AddStmt(tmpfoam, NULL((void*)0));
701 res = foamCopy(tmpvar);
702 break;
703 case FTN_Boolean:
704 /*
705 * Store the Word result in a newly created
706 * Boolean. Add the cast and return.
707 */
708 call->foamPCall.type = FOAM_Word;
709 tmpvar = gen0TempLocal(FOAM_Word)gen0TempLocal0(FOAM_Word, 4);
710 tmpfoam = foamNewSet(foamCopy(tmpvar), foamCopy(foam))foamNew(FOAM_Set, 2, foamCopy(tmpvar), foamCopy(foam));
711 gen0AddStmt(tmpfoam, NULL((void*)0));
712 res = foamCopy(tmpvar);
713 break;
714 case FTN_FSComplex:
715 /*
716 * Convert COMPLEX REAL into Complex SF. To do
717 * this we store the result of the Fortran call
718 * in a local. Then we copy and convert the two
719 * components into a new local which is used as
720 * the return value for the whole call.
721 */
722 cfmt = gen0SingleCpxFormat(); /* COMPLEX REAL */
723 afmt = gen0AldorCpxFormat(); /* Complex SF */
724
725 /* Create a local and store the return value */
726 tmpvar = gen0TempLocal0(FOAM_Rec, cfmt);
727 tmpfoam = foamNewSet(foamCopy(tmpvar), foamCopy(foam))foamNew(FOAM_Set, 2, foamCopy(tmpvar), foamCopy(foam));
728 gen0AddStmt(tmpfoam, NULL((void*)0));
729
730 /* Allocate storage for the Complex SF result */
731 res = gen0TempLocal0(FOAM_Rec, afmt);
732 tmpfoam = gen0RNew(res, afmt)foamNew(FOAM_Set, 2, foamCopy(res), foamNew(FOAM_RNew, 1, afmt
))
;
733 gen0AddStmt(tmpfoam, NULL((void*)0));
734
735 /* Copy the real part into the local (with cast) */
736 creal = foamNewRElt(cfmt, foamCopy(tmpvar), (AInt)0)foamNew(FOAM_RElt,3,(AInt)(cfmt),foamCopy(tmpvar),(AInt)((AInt
)0))
;
737 creal = foamNewCast(FOAM_Word, creal)foamNew(FOAM_Cast, 2, FOAM_Word, creal);
738 creal = gen0RSet(foamCopy(res), afmt, (AInt)0, creal)foamNew(FOAM_Set, 2, foamNew(FOAM_RElt,3,(AInt)(afmt),foamCopy
(foamCopy(res)),(AInt)((AInt)0)), creal)
;
739 gen0AddStmt(creal, NULL((void*)0));
740
741 /* Copy the imaginary part into the local */
742 cimag = foamNewRElt(cfmt, foamCopy(tmpvar), (AInt)1)foamNew(FOAM_RElt,3,(AInt)(cfmt),foamCopy(tmpvar),(AInt)((AInt
)1))
;
743 cimag = foamNewCast(FOAM_Word, cimag)foamNew(FOAM_Cast, 2, FOAM_Word, cimag);
744 cimag = gen0RSet(foamCopy(res), afmt, (AInt)1, cimag)foamNew(FOAM_Set, 2, foamNew(FOAM_RElt,3,(AInt)(afmt),foamCopy
(foamCopy(res)),(AInt)((AInt)1)), cimag)
;
745 gen0AddStmt(cimag, NULL((void*)0));
746 break;
747 case FTN_FDComplex:
748 /*
749 * Convert COMPLEX DOUBLE into Complex DF. To do
750 * this we store the result of the Fortran call
751 * in a local. Then we copy and convert the two
752 * components into a new local which is used as
753 * the return value for the whole call.
754 */
755 cfmt = gen0DoubleCpxFormat(); /* COMPLEX DOUBLE */
756 afmt = gen0AldorCpxFormat(); /* Complex DF */
757 dfmt = gen0MakeDoubleFormat(); /* DF */
758
759 /* Create a local and store the return value */
760 tmpvar = gen0TempLocal0(FOAM_Rec, cfmt);
761 tmpfoam = foamNewSet(foamCopy(tmpvar), foamCopy(foam))foamNew(FOAM_Set, 2, foamCopy(tmpvar), foamCopy(foam));
762 gen0AddStmt(tmpfoam, NULL((void*)0));
763
764
765 /* Create a DF for the real part */
766 rpart = gen0TempLocal0(FOAM_Rec, dfmt);
767 gen0AddStmt(gen0RNew(foamCopy(rpart), dfmt)foamNew(FOAM_Set, 2, foamCopy(foamCopy(rpart)), foamNew(FOAM_RNew
, 1, dfmt))
, NULL((void*)0));
768
769
770 /* Copy the real DFlo part into the DF */
771 creal = foamNewRElt(cfmt, foamCopy(tmpvar), (AInt)0)foamNew(FOAM_RElt,3,(AInt)(cfmt),foamCopy(tmpvar),(AInt)((AInt
)0))
;
772 creal = gen0RSet(foamCopy(rpart), dfmt, (AInt)0, creal)foamNew(FOAM_Set, 2, foamNew(FOAM_RElt,3,(AInt)(dfmt),foamCopy
(foamCopy(rpart)),(AInt)((AInt)0)), creal)
;
773 gen0AddStmt(creal, NULL((void*)0));
774
775
776 /* Create a DF for the imaginary part */
777 ipart = gen0TempLocal0(FOAM_Rec, dfmt);
778 gen0AddStmt(gen0RNew(foamCopy(ipart), dfmt)foamNew(FOAM_Set, 2, foamCopy(foamCopy(ipart)), foamNew(FOAM_RNew
, 1, dfmt))
, NULL((void*)0));
779
780
781 /* Copy the imaginary part into the DF */
782 cimag = foamNewRElt(cfmt, foamCopy(tmpvar), (AInt)1)foamNew(FOAM_RElt,3,(AInt)(cfmt),foamCopy(tmpvar),(AInt)((AInt
)1))
;
783 cimag = gen0RSet(foamCopy(ipart), dfmt, (AInt)0, cimag)foamNew(FOAM_Set, 2, foamNew(FOAM_RElt,3,(AInt)(dfmt),foamCopy
(foamCopy(ipart)),(AInt)((AInt)0)), cimag)
;
784 gen0AddStmt(cimag, NULL((void*)0));
785
786
787 /* Create the Complex DF */
788 res = gen0TempLocal0(FOAM_Rec, afmt);
789 gen0AddStmt(gen0RNew(res, afmt)foamNew(FOAM_Set, 2, foamCopy(res), foamNew(FOAM_RNew, 1, afmt
))
, NULL((void*)0));
790
791
792 /* Fill in the slots of the Complex DF */
793 creal = foamCopy(rpart);
794 cimag = foamCopy(ipart);
795 creal = gen0RSet(foamCopy(res), afmt, (AInt)0, creal)foamNew(FOAM_Set, 2, foamNew(FOAM_RElt,3,(AInt)(afmt),foamCopy
(foamCopy(res)),(AInt)((AInt)0)), creal)
;
796 cimag = gen0RSet(foamCopy(res), afmt, (AInt)1, cimag)foamNew(FOAM_Set, 2, foamNew(FOAM_RElt,3,(AInt)(afmt),foamCopy
(foamCopy(res)),(AInt)((AInt)1)), cimag)
;
797 gen0AddStmt(creal, NULL((void*)0));
798 gen0AddStmt(cimag, NULL((void*)0));
799 break;
800 default:
801 if (fmType == FOAM_Bool)
802 {
803 /* f95 uses words not bytes */
804 call->foamPCall.type = FOAM_Word;
805 tmpvar = gen0TempLocal(FOAM_Word)gen0TempLocal0(FOAM_Word, 4);
806 }
807 else
808 tmpvar = gen0TempLocal(gen0Type(tfret, NULL))gen0TempLocal0(gen0Type(tfret, ((void*)0)), 4);
809
810 tmpfoam = foamNewSet(foamCopy(tmpvar), foamCopy(foam))foamNew(FOAM_Set, 2, foamCopy(tmpvar), foamCopy(foam));
811 gen0AddStmt(tmpfoam, NULL((void*)0));
812 res = foamCopy(tmpvar);
813 break;
814 }
815 }
816 else
817 {
818 gen0AddStmt(foam, NULL((void*)0));
819 res = NULL((void*)0);
820 }
821
822
823 /* Emit the code to be executed after the function call */
824 aftCall = listNReverse(Foam)(Foam_listPointer->NReverse)(aftCall);
825 while (aftCall)
826 {
827 gen0AddStmt(car(aftCall)((aftCall)->first), NULL((void*)0));
828 aftCall = listFreeCons(Foam)(Foam_listPointer->FreeCons)(aftCall);
829 }
830
831
832 return res;
833}
834
835
836/*
837 * Parameters of functions imported from Fortran which
838 * are themselves functions must be wrapped up so that
839 * the Fortran arguments can be converted into a function
840 * which Fortran is capable of invoking. The actual
841 * exported function will be created at during the C
842 * generation phase but we can deal with reading and
843 * writing argument values during foam generation. We
844 * reuse the export-to-Fortran code.
845 */
846localstatic Foam
847gen0FtnFunValue(Foam foam, TForm tf, Syme syme)
848{
849 Foam wrapper;
850 FoamTag rtype;
851 TForm tfret = tfMapRet(tf)tfFollowArg(tf, 1);
852 FortranType ftntype = ftnTypeFrDomTForm(tfret);
853 String opname = symString(symeId(syme))((((syme)->id))->str);
854
855 if (ftntype)
856 rtype = gen0FtnMachineType(ftntype);
857 else
858 rtype = gen0Type(tfret, NULL((void*)0));
859
860 wrapper = gen0FortranExportFn(tf, rtype, foam, opname, NULL((void*)0));
861
862 return foamCopy(wrapper);
863}
864
865
866#if 0
867/* Apply an export found via a category */
868localstatic Foam
869gen0MakeAutoApply(AbSyn ab, Syme op, TForm tf, FoamTag rtype,
870 AInt argc, Foam *arg)
871{
872 AInt i;
873 SymeList symes;
874 Foam call, *argv;
875 TForm optf, tfret;
876
877
878 /* Convert this export into an import from tf */
879 symes = listSingleton(Syme)(Syme_listPointer->Singleton)(op);
880 symes = symeListSubstSelf(stabFile(), tf, symes);
881 op = car(symes)((symes)->first);
882
883
884 /* Get its full type and follow any substitutions (again) */
885 optf = symeType(op);
886 tfFollow(optf)((optf) = tfFollowFn(optf));
887
888
889 /* What is the return type for this call? */
890 tfret = tfMapRet(optf)tfFollowArg(optf, 1);
891
892
893 /* Apply this export to the array value */
894 call = gen0ExtendSyme(op);
895 call = gen0CCallFrFoam(rtype, call, argc, &argv);
896
897
898 /* Fill in the arguments */
899 for (i = 0;i < argc;i++)
900 argv[i] = foamCopy(arg[i]);
901
902
903 /* Generate the call */
904 call = gen0ApplyReturn(ab, op, tfret, call);
905 return foamCopy(call);
906}
907#endif
908
909
910/*
911 * We allow users to pass array-like objects to Fortran.
912 * This is achieved by applying the (convert: % -> BArr)
913 * operation (from the FortranArray category), to their
914 * array-like value. After the call we apply the other
915 * FortranArray export: (convert: (%, BArr) -> BSInt)
916 * (see gen0FtnUpdateArray() below).
917 */
918localstatic Foam
919gen0FtnArrayValue(AbSyn ab, Foam foam, TForm tf)
920{
921 Syme op = (Syme)NULL((void*)0);
922 SymeList symes;
923 TForm optf, tfret;
924 Foam call, *argv;
925
926
927 /* Get the exports of the FortranArray category */
928 symes = ftnArrayExports();
929
930
931 /* Locate the export { convert: % -> BArr } */
932 for (;!op && symes;symes = cdr(symes)((symes)->rest))
933 {
934 Syme syme = car(symes)((symes)->first);
935 String name = symeString(syme)((((syme)->id))->str);
936
937
938 /* Does this export have the correct name? */
939 if (!strEqual(name, "convert")) continue;
940
941
942 /* Get its full type and follow any substitutions */
943 optf = symeType(syme);
944 tfFollow(optf)((optf) = tfFollowFn(optf));
945
946
947 /*
948 * Type checking: must be a map with one argument
949 * of type % and a return type Arr$Machine. This
950 * isn't the correct way to do this (we ought to
951 * be using tfSat) so we don't check return types.
952 */
953 if (!tfIsAnyMap(optf)((((optf)->tag) == TF_Map) || (((optf)->tag) == TF_PackedMap
))
) continue;
954 if (tfMapArgc(optf) != 1) continue;
955 if (!tfIsSelf(tfMapArgN(optf,(Length) 0))(((((tfMapArgN(optf,(Length) 0))->tag) == TF_General) &&
((((tfMapArgN(optf,(Length) 0))->__absyn))->abHdr.tag)
== AB_Id) && (((tfMapArgN(optf,(Length) 0))->__absyn
)->abId.sym) == (ssymSelf))
) continue;
956
957
958 /* Found it (assume type is correct) */
959 op = syme;
960 }
961
962
963 /* Did we find the required category export? */
964 if (!op) return foamCopy(foam);
965
966/* return gen0MakeAutoApply(ab, op, tf, FOAM_Arr, 1, &foam); */
967
968
969 /* Convert this export into an import from tf */
970 symes = listSingleton(Syme)(Syme_listPointer->Singleton)(op);
971 symes = symeListSubstSelf(stabFile(), tf, symes);
972 op = car(symes)((symes)->first);
973
974
975 /* Get its full type and follow any substitutions (again) */
976 optf = symeType(op);
977 tfFollow(optf)((optf) = tfFollowFn(optf));
978
979
980 /* What is the return type for this call? */
981 tfret = tfMapRet(optf)tfFollowArg(optf, 1);
982
983
984 /* Apply this export to the array value */
985 call = gen0ExtendSyme(op);
986 call = gen0CCallFrFoam(FOAM_Arr, call, 1, &argv);
987 *argv = foamCopy(foam);
988 call = gen0ApplyReturn(ab, op, tfret, call);
989 return foamCopy(call);
990}
991
992
993localstatic Foam
994gen0FtnUpdateArray(AbSyn ab, Foam orig, Foam flat, TForm tf)
995{
996 Syme op = (Syme)NULL((void*)0);
997 SymeList symes;
998 TForm optf, tfret;
999 Foam call, *argv;
1000
1001
1002 /* Get the exports of the FortranArray category */
1003 symes = ftnArrayExports();
1004
1005
1006 /* Locate the export { convert: (%, BArr) -> BSInt } */
1007 for (;!op && symes;symes = cdr(symes)((symes)->rest))
1008 {
1009 Syme syme = car(symes)((symes)->first);
1010 String name = symeString(syme)((((syme)->id))->str);
1011
1012
1013 /* Does this export have the correct name? */
1014 if (!strEqual(name, "convert")) continue;
1015
1016
1017 /* Get its full type and follow any substitutions */
1018 optf = symeType(syme);
1019 tfFollow(optf)((optf) = tfFollowFn(optf));
1020
1021
1022 /*
1023 * Type checking: must be a map with two arguments of
1024 * type % and Arr$Machine. As before we ought to be using
1025 * tfSat but since we are not we skip the check that the
1026 * second argument is Arr$Machine and the result is of
1027 * type SInt$Machine.
1028 */
1029 if (!tfIsAnyMap(optf)((((optf)->tag) == TF_Map) || (((optf)->tag) == TF_PackedMap
))
) continue;
1030 if (tfMapArgc(optf) != 2) continue;
1031 if (!tfIsSelf(tfMapArgN(optf, (Length) 0))(((((tfMapArgN(optf, (Length) 0))->tag) == TF_General) &&
((((tfMapArgN(optf, (Length) 0))->__absyn))->abHdr.tag
) == AB_Id) && (((tfMapArgN(optf, (Length) 0))->__absyn
)->abId.sym) == (ssymSelf))
) continue;
1032 /* Check return type is SInt ... */
1033
1034
1035 /* Found it (assume type is correct) */
1036 op = syme;
1037 }
1038
1039
1040 /* Did we find the required category export? */
1041 if (!op) return foamNewNOp()foamNew(FOAM_NOp, (int) 0);
1042
1043/*
1044 * args[0] = orig;
1045 * args[1] = flat;
1046 * return gen0MakeAutoApply(op, tf, FOAM_SInt, 2, &args);
1047 */
1048
1049
1050 /* Convert this export into an import from tf */
1051 symes = listSingleton(Syme)(Syme_listPointer->Singleton)(op);
1052 symes = symeListSubstSelf(stabFile(), tf, symes);
1053 op = car(symes)((symes)->first);
1054
1055
1056 /* Get its full type and follow any substitutions (again) */
1057 optf = symeType(op);
1058 tfFollow(optf)((optf) = tfFollowFn(optf));
1059
1060
1061 /* What is the return type for this call? */
1062 tfret = tfMapRet(optf)tfFollowArg(optf, 1);
1063
1064
1065 /* Apply this export to the array value */
1066 call = gen0ExtendSyme(op);
1067 call = gen0CCallFrFoam(FOAM_SInt, call, 2, &argv);
1068 argv[0] = foamCopy(orig);
1069 argv[1] = foamCopy(flat);
1070 call = gen0ApplyReturn(ab, op, tfret, call);
1071 return foamCopy(call);
1072}
1073
1074
1075/*
1076 * Fixed-string arrays are strange beasts. We want to
1077 * auto-convert them just like any other array but we
1078 * also have to note how long the string elements are.
1079 * We return a pair containing the raw array and the
1080 * length of the string elements (see gen0FtnArrayValue()
1081 * above for details of the automatic array conversion).
1082 *
1083 * Note: FortranStringArray includes FortranArray.
1084 */
1085localstatic Foam
1086gen0FtnFSArrayValue(AbSyn ab, Foam foam, TForm tf)
1087{
1088 Foam arr, len;
1089
1090
1091 /* Convert the array */
1092 arr = gen0FtnArrayValue(ab, foam, tf);
1093
1094
1095 /* Now find and apply the #: () -> SInt export. */
1096 len = gen0FtnFSArrayLen(ab, foam, tf);
1097
1098
1099 /* Return the pair */
1100 return foamNew(FOAM_Values, 2, foamCopy(arr), foamCopy(len));
1101}
1102
1103
1104localstatic Foam
1105gen0FtnUpdateFSArray(AbSyn ab, Foam orig, Foam flat, TForm tf)
1106{
1107 /* The flat array is in a FOAM_Values */
1108 assert(foamTag(flat) == FOAM_Values)do { if (!(((flat)->hdr.tag) == FOAM_Values)) _do_assert((
"foamTag(flat) == FOAM_Values"),"gf_fortran.c",1108); } while
(0)
;
1109
1110 return gen0FtnUpdateArray(ab, orig, flat->foamValues.argv[0], tf);
1111}
1112
1113
1114/*
1115 * We need to be able to determine the length of fixed
1116 * string values stored in arrays. This is achieved by
1117 * applying the (#: () -> BSInt) operation (from the
1118 * FortranFSArray category), to the * array-like value.
1119 */
1120localstatic Foam
1121gen0FtnFSArrayLen(AbSyn ab, Foam foam, TForm tf)
1122{
1123 Syme op = (Syme)NULL((void*)0);
1124 SymeList symes;
1125 TForm optf, tfret;
1126 Foam call, *argv;
1127
1128
1129 /* Get the exports of the FortranFSArray category */
1130 symes = ftnFSArrayExports();
1131
1132
1133 /* Locate the export { #: () -> BSInt } */
1134 for (;!op && symes;symes = cdr(symes)((symes)->rest))
1135 {
1136 Syme syme = car(symes)((symes)->first);
1137 String name = symeString(syme)((((syme)->id))->str);
1138
1139
1140 /* Does this export have the correct name? */
1141 if (!strEqual(name, "#")) continue;
1142
1143
1144 /* Get its full type and follow any substitutions */
1145 optf = symeType(syme);
1146 tfFollow(optf)((optf) = tfFollowFn(optf));
1147
1148
1149 /*
1150 * Type checking: must be a map with no arguments
1151 * and a return type SInt$Machine. This isn't the
1152 * correct way to do this (we ought to be using
1153 * tfSat) so we don't check return types.
1154 */
1155 if (!tfIsAnyMap(optf)((((optf)->tag) == TF_Map) || (((optf)->tag) == TF_PackedMap
))
) continue;
1156 if (tfMapArgc(optf)) continue;
1157
1158
1159 /* Found it (assume type is correct) */
1160 op = syme;
1161 }
1162
1163
1164 /* Did we find the required category export? */
1165 /* !!! Ought to generate a compiler error !!!!! */
1166 if (!op) return foamCopy(foam);
1167
1168/* return gen0MakeAutoApply(ab, op, tf, FOAM_SInt, 0, (Foam*)NULL); */
1169
1170
1171 /* Convert this export into an import from tf */
1172 symes = listSingleton(Syme)(Syme_listPointer->Singleton)(op);
1173 symes = symeListSubstSelf(stabFile(), tf, symes);
1174 op = car(symes)((symes)->first);
1175
1176
1177 /* Get its full type and follow any substitutions (again) */
1178 optf = symeType(op);
1179 tfFollow(optf)((optf) = tfFollowFn(optf));
1180
1181
1182 /* What is the return type for this call? */
1183 tfret = tfMapRet(optf)tfFollowArg(optf, 1);
1184
1185
1186 /* Apply this export to the array value */
1187 call = gen0ExtendSyme(op);
1188 call = gen0CCallFrFoam(FOAM_SInt, call, (Length)0, &argv);
1189 call = gen0ApplyReturn(ab, op, tfret, call);
1190 return foamCopy(call);
1191}
1192
1193
1194/*
1195 * Given a machine-type, return the FOAM for a value of
1196 * this type stored in a record. We update the final
1197 * argument with the FOAM statements required to pack
1198 * the value in the record.
1199 */
1200Foam
1201gen0MakePointerTo(FoamTag tag, Foam foam, FoamList *ltmp)
1202{
1203 FoamList lst;
1204 Foam tmpvar;
1205 Foam tmpfoam = foamCopy(foam);
1206
1207 switch (tag)
1208 {
1209 case FOAM_Char:
1210 return gen0MakeCharRecValue(tmpfoam, ltmp);
1211 case FOAM_SInt:
1212 return gen0MakeIntRecValue(tmpfoam, ltmp);
1213 case FOAM_SFlo:
1214 return gen0MakeFloatRecValue(tmpfoam, ltmp);
1215 case FOAM_DFlo:
1216 return gen0MakeDoubleCode(tmpfoam, ltmp);
1217 default:
1218 /*
1219 * Assume it is already a pointer and
1220 * store it in a temporary variable.
1221 */
1222 tmpvar = gen0TempLocal(tag)gen0TempLocal0(tag, 4);
1223 tmpfoam = foamNewSet(tmpvar, tmpfoam)foamNew(FOAM_Set, 2, tmpvar, tmpfoam);
1224 lst = listNil(Foam)((FoamList) 0);
1225 lst = listCons(Foam)(Foam_listPointer->Cons)(tmpfoam, lst);
1226 *ltmp = lst;
1227 return foamCopy(tmpvar);
1228 }
1229}
1230
1231/*
1232 * This function simply reverses the job done
1233 * by gen0MakePointerTo(). Given a the type
1234 * of the value being pointed to by foam we
1235 * pull it out and return it to the caller.
1236 */
1237Foam
1238gen0ReadPointerTo(FoamTag tag, Foam foam)
1239{
1240 Foam tmpfoam = foamCopy(foam);
1241
1242 switch (tag)
1243 {
1244 case FOAM_Char:
1245 return gen0ReadCharRecValue(tmpfoam);
1246 case FOAM_SInt:
1247 return gen0ReadIntRecValue(tmpfoam);
1248 case FOAM_SFlo:
1249 return gen0ReadFloatRecValue(tmpfoam);
1250 case FOAM_DFlo:
1251 return gen0DoubleValue(tmpfoam);
1252 default:
1253 return tmpfoam;
1254 }
1255}
1256
1257/*
1258 * This function is the opposite to gen0ReadPointerTo().
1259 * Given a the type of the value being pointed to by
1260 * dst we stuff the value stored in foam into it.
1261 */
1262Foam
1263gen0WritePointerTo(FoamTag tag, Foam dst, Foam foam)
1264{
1265 Foam tmpfoam = foamCopy(foam);
1266
1267 switch (tag)
1268 {
1269 case FOAM_Char:
1270 return gen0WriteCharRecValue(dst, tmpfoam);
1271 case FOAM_SInt:
1272 return gen0WriteIntRecValue(dst, tmpfoam);
1273 case FOAM_SFlo:
1274 return gen0WriteFloatRecValue(dst, tmpfoam);
1275 case FOAM_DFlo:
1276 return gen0WriteDoubleValue(dst, tmpfoam);
1277 default:
1278 return dst;
1279 }
1280}
1281
1282
1283#if 0
1284/* Invoked from gen0FtnSCpxGet() and gen0FtnDCpxGet(). */
1285localstatic Foam
1286gen0FtnComplexGet(AbSyn ab, Foam foam, TForm tf, SymeList symes)
1287{
1288 Syme op = (Syme)NULL((void*)0);
1289
1290
1291 /*
1292 * Locate export { coerce: % -> Record(real:R, imag:R) }
1293 * where R is SFlo or DFlo.
1294 */
1295 for (;!op && symes;symes = cdr(symes)((symes)->rest))
1296 {
1297 TForm optf;
1298 Syme syme = car(symes)((symes)->first);
1299 String name = symeString(syme)((((syme)->id))->str);
1300
1301
1302 /* Does this export have the correct name? */
1303 if (!strEqual(name, "coerce")) continue;
1304
1305
1306 /* Get its full type and follow any substitutions */
1307 optf = symeType(syme);
1308 tfFollow(optf)((optf) = tfFollowFn(optf));
1309
1310
1311 /*
1312 * Type checking: must be a map with one argument
1313 * of type % and a return type Record(). This isn't
1314 * the correct way to do this (we ought to be using
1315 * tfSat) so we don't check return types.
1316 */
1317 if (!tfIsAnyMap(optf)((((optf)->tag) == TF_Map) || (((optf)->tag) == TF_PackedMap
))
) continue;
1318 if (tfMapArgc(optf) != 1) continue;
1319 if (!tfIsSelf(tfMapArgN(optf, (Length) 0))(((((tfMapArgN(optf, (Length) 0))->tag) == TF_General) &&
((((tfMapArgN(optf, (Length) 0))->__absyn))->abHdr.tag
) == AB_Id) && (((tfMapArgN(optf, (Length) 0))->__absyn
)->abId.sym) == (ssymSelf))
) continue;
1320
1321
1322 /* Found it (assume type is correct) */
1323 op = syme;
1324 }
1325
1326
1327 /* Did we find the required category export? */
1328 if (!op) return foamCopy(foam);
1329
1330
1331 /* Apply this operation */
1332 return gen0MakeAutoApply(ab, op, tf, FOAM_Rec, 1, &foam);
1333}
1334
1335
1336/* Invoked from gen0FtnSCpxPut() and gen0FtnDCpxPut(). */
1337localstatic Foam
1338gen0FtnComplexPut(AbSyn ab, Foam foam, TForm tf, SymeList symes)
1339{
1340 Syme op = (Syme)NULL((void*)0);
1341
1342
1343 /*
1344 * Locate export { coerce: Record(real:R, imag:R) -> % }
1345 * where R is SFlo or DFlo.
1346 */
1347 for (;!op && symes;symes = cdr(symes)((symes)->rest))
1348 {
1349 TForm optf;
1350 Syme syme = car(symes)((symes)->first);
1351 String name = symeString(syme)((((syme)->id))->str);
1352
1353
1354 /* Does this export have the correct name? */
1355 if (!strEqual(name, "coerce")) continue;
1356
1357
1358 /* Get its full type and follow any substitutions */
1359 optf = symeType(syme);
1360 tfFollow(optf)((optf) = tfFollowFn(optf));
1361
1362
1363 /*
1364 * Type checking: must be a map with one argument
1365 * of type Record() and a return type %. This isn't
1366 * the correct way to do this (we ought to be using
1367 * tfSat) so we don't check argument types.
1368 */
1369 if (!tfIsAnyMap(optf)((((optf)->tag) == TF_Map) || (((optf)->tag) == TF_PackedMap
))
) continue;
1370 if (tfMapArgc(optf) != 1) continue;
1371 if (!tfIsSelf(tfMapRet(optf))(((((tfFollowArg(optf, 1))->tag) == TF_General) &&
((((tfFollowArg(optf, 1))->__absyn))->abHdr.tag) == AB_Id
) && (((tfFollowArg(optf, 1))->__absyn)->abId.sym
) == (ssymSelf))
) continue;
1372
1373
1374 /* Found it (assume type is correct) */
1375 op = syme;
1376 }
1377
1378
1379 /* Did we find the required category export? */
1380 if (!op) return foamCopy(foam);
1381
1382
1383 /* Apply this operation */
1384 return gen0MakeAutoApply(ab, op, tf, FOAM_Word, 1, &foam);
1385}
1386#endif
1387
1388
1389/*****************************************************************************
1390 *
1391 * :: Local functions for the Fortran-calls-Aldor side.
1392 *
1393 ****************************************************************************/
1394
1395localstatic AbSyn ab0FortranExportArgs (TForm);
1396localstatic AbSyn ab1FortranExportArg (Length);
1397localstatic FoamList gen0FortranExportArgs (TForm, FoamList *, FoamList *);
1398localstatic Foam gen1FortranExportArg (TForm, Length,
1399 FoamList *, FoamList *);
1400localstatic Foam gen0FortranConvArg (Foam, FoamTag, FortranType,
1401 FoamList *);
1402localstatic Foam gen0FortranPackArg (Foam, FoamTag, FortranType,
1403 FoamTag *);
1404localstatic Symbol gen0FortranArgName (Length);
1405
1406
1407/*****************************************************************************
1408 *
1409 * Foam code generation for Fortran-calls-Aldor.
1410 *
1411 ****************************************************************************/
1412
1413/*
1414 * Create a global variable binding for exporting to Fortran.
1415 */
1416void
1417gen0ExportToFortran(AbSyn absyn)
1418{
1419 TForm tf, tfret;
1420 String str;
1421 FoamTag rtype;
1422 FortranType ftntype;
1423 Foam decl, wrapper, glo;
1424 AInt fmtslot, index;
1425 AbSyn name = abDefineeId(absyn);
1426 Syme syme = abSyme(name)((name)->abHdr.seman ? (name)->abHdr.seman->syme : 0
)
;
1427
1428 assert(syme)do { if (!(syme)) _do_assert(("syme"),"gf_fortran.c",1428); }
while (0)
;
1429 tf = symeType(syme);
1430 assert (tfIsMap(tf))do { if (!((((tf)->tag) == TF_Map))) _do_assert(("tfIsMap(tf)"
),"gf_fortran.c",1430); } while (0)
;
1431
1432 /*!! Assumes export to Fortran is exporting a function! */
1433 /*
1434 * Now create the wrapper function. This is stored in a
1435 * global so that it is visible to Fortran. The wrapper
1436 * prepares the arguments for the real exported function,
1437 * notes the return value and updates the arguments passed
1438 * to us from Fortran (if appropriate).
1439 */
1440 tfret = tfMapRet(tf)tfFollowArg(tf, 1);
1441 ftntype = ftnTypeFrDomTForm(tfret);
1442 if (ftntype)
1443 rtype = gen0FtnMachineType(ftntype);
1444 else
1445 rtype = gen0Type(tfret, NULL((void*)0));
1446
1447 fmtslot = gen0FortranSigExportNumber(tf);
1448 str = strCopy(symeString(syme)((((syme)->id))->str));
1449 wrapper = gen0FortranExportFn(tf, rtype, gen0Syme(syme), str, absyn);
1450 decl = foamNewGDecl(FOAM_Clos, str, rtype, fmtslot,foamNew(FOAM_GDecl,6,(AInt)(FOAM_Clos),str, rtype,fmtslot, (AInt
)(FOAM_GDecl_Export),(AInt)(FOAM_Proto_Fortran))
1451 FOAM_GDecl_Export, FOAM_Proto_Fortran)foamNew(FOAM_GDecl,6,(AInt)(FOAM_Clos),str, rtype,fmtslot, (AInt
)(FOAM_GDecl_Export),(AInt)(FOAM_Proto_Fortran))
;
1452 index = gen0AddGlobal(decl);
1453 glo = foamNewGlo(index)foamNew(FOAM_Glo, 1, (AInt)(index));
1454 gen0AddStmt(foamNewSet(glo, wrapper)foamNew(FOAM_Set, 2, glo, wrapper), absyn);
1455
1456
1457 /* Note the global index of the exported wrapper */
1458 gen0BuiltinExports = listCons(AInt)(AInt_listPointer->Cons)(index, gen0BuiltinExports);
1459 gen0BuiltinExports = listCons(AInt)(AInt_listPointer->Cons)(int0((int) 0), gen0BuiltinExports);
1460}
1461
1462
1463/*
1464 * Create a wrapper function in FOAM so that Fortran can invoke
1465 * our exported Aldor function and allow its arguments to be
1466 * updated by Aldor (where appropriate). We really want to do as
1467 * much of this as possible in FOAM rather than leaving it to the
1468 * C generation phase where life is much more messy. It also
1469 * gives the optimiser a chance to do some work.
1470 *
1471 * Ideally our wrapper function foo'() for the exported function
1472 * foo() would have a signature using pointers to machine types.
1473 * The wrapper would unpack the Fortran arguments and create ref()
1474 * values for any parameter of foo() which has type Ref(T). The
1475 * Fortran arguments would be updated after the foo() call.
1476 *
1477 * Thus if we were exporting:
1478 *
1479 * foo: (SingleInteger, Ref(DoubleFloat)) -> Boolean
1480 *
1481 * then our wrapper would be:
1482 *
1483 * foo'(t1:Record(sint:SInt), t2:Record(dflo:DFlo)):Bool ==
1484 * {
1485 * local l1:SingleInteger := (t1.sint)::SingleInteger;
1486 * local l2:DoubleFloat := (t2.dflo)::DoubleFloat;
1487 * local l3:Ref(DoubleFloat) := ref(l2);
1488 * local result:Boolean := foo(l1, l3);
1489 *
1490 * t2.dflo := deref(l3)::DFlo; -- Confuse the optimiser
1491 * result;
1492 * }
1493 *
1494 * Note that the obvious optimisation here is to change the
1495 * deref() line to read:
1496 *
1497 * t2.dflo := l2::DFlo;
1498 *
1499 * The trouble is that the optimiser might try to be too
1500 * clever and assume that the call to foo() will not affect
1501 * the value of l2. This ought not to happen but I don't
1502 * think it is worth the risk just yet. At least this code
1503 * ought to be relatively stable. Anyway, we usually eliminate
1504 * the reference getter/setter functions during inlining.
1505 */
1506Foam
1507gen0FortranExportFn(TForm tf, FoamTag rtype, Foam op, String name, AbSyn absyn)
1508{
1509 TForm tfret;
1510 Foam *argloc;
1511 Foam foam, clos, retvar, tmpfoam;
1512 Foam cpx, recfoam, creal, cimag;
1513 FoamTag retType;
1514 AInt retfmt, cfmt, afmt, dfmt;
1515 AbSyn params;
1516 Length i, nargs;
1517 FoamList bef, aft, pars;
1518 FortranType ftnType;
1519 GenFoamState saved;
1520
1521
1522 /* Note the function signature */
1523 tfret = tfMapRet(tf)tfFollowArg(tf, 1);
1524 retType = gen0Type(tfret, &retfmt);
1525 ftnType = ftnTypeFrDomTForm(tfret);
1526
1527
1528 /* Create a closure for the function */
1529 clos = gen0ProgClosEmpty();
1530 foam = gen0ProgInitEmpty(name, absyn);
1531
1532
1533 /* Save the current state */
1534 saved = gen0ProgSaveState(PT_ExFn);
1535
1536
1537 /*
1538 * Deal with special return types. Since we
1539 * are exporting to Fortran these sort of
1540 * things ought never to appear. However, it
1541 * doesn't hurt to be careful.
1542 */
1543 if (!tfIsNone(tfret)((((tfret)->tag) == TF_Multiple) && tfMultiArgc(tfret
) == 0)
&& tfIsMulti(tfret)(((tfret)->tag) == TF_Multiple))
1544 retfmt = gen0MultiFormatNumber(tfret);
1545
1546 if (tfIsGenerator(tfret)(((tfret)->tag) == TF_Generator))
1547 foamProgSetGenerator(foam)((foam)->foamProg.infoBits |= (1 << 2));
1548
1549
1550 /* Create the parameters for this function */
1551 params = ab0FortranExportArgs(tfMapArg(tf)tfFollowArg(tf, 0));
1552
1553
1554 /* Initialise the program state */
1555 gen0State->type = tf;
1556 gen0State->param = params;
1557 gen0State->program = foam;
1558
1559
1560 /* Create the before and after wrapper code */
1561 bef = listNil(Foam)((FoamList) 0);
1562 aft = listNil(Foam)((FoamList) 0);
1563 pars = gen0FortranExportArgs(tfMapArg(tf)tfFollowArg(tf, 0), &bef, &aft);
1564
1565
1566 /*
1567 * Add the code to be executed before the exported
1568 * function is invoked.
1569 */
1570 bef = listNReverse(Foam)(Foam_listPointer->NReverse)(bef);
1571 while (bef)
1572 {
1573 gen0AddStmt(car(bef)((bef)->first), absyn);
1574 bef = listFreeCons(Foam)(Foam_listPointer->FreeCons)(bef);
1575 }
1576
1577
1578 /* Generate code to apply the exported function */
1579 nargs = listLength(Foam)(Foam_listPointer->_Length)(pars);
1580 tmpfoam = gen0CCallFrFoam(retType, op, nargs, &argloc);
1581
1582
1583 /* Create the FOAM for the procedure arguments */
1584 for (i = 0;i < nargs;pars = listFreeCons(Foam)(Foam_listPointer->FreeCons)(pars), i++)
1585 argloc[i] = foamCopy(car(pars)((pars)->first));
1586 tmpfoam = gen0ApplyReturn(absyn, (Syme)NULL((void*)0), tfret, tmpfoam);
1587
1588
1589 /* Store the function result (if any) in a temp */
1590 if (!tfIsNone(tfret)((((tfret)->tag) == TF_Multiple) && tfMultiArgc(tfret
) == 0)
)
1591 {
1592 retvar = gen0TempLocal0(retType, retfmt);
1593 tmpfoam = foamNewSet(retvar, foamCopy(tmpfoam))foamNew(FOAM_Set, 2, retvar, foamCopy(tmpfoam));
1594 }
1595 else
1596 retvar = 0;
1597
1598 /* Add the function call statement */
1599 gen0AddStmt(tmpfoam, absyn);
1600
1601
1602 /*
1603 * Add the code to be executed after the exported
1604 * function is invoked.
1605 */
1606 aft = listNReverse(Foam)(Foam_listPointer->NReverse)(aft);
1607 while (aft)
1608 {
1609 gen0AddStmt(car(aft)((aft)->first), absyn);
1610 aft = listFreeCons(Foam)(Foam_listPointer->FreeCons)(aft);
1611 }
1612
1613
1614 /*
1615 * Convert the return value into the right type and
1616 * return it (if there is one).
1617 */
1618 if (!tfIsNone(tfret)((((tfret)->tag) == TF_Multiple) && tfMultiArgc(tfret
) == 0)
)
1619 {
1620 FoamTag *junk = (FoamTag *)NULL((void*)0);
1621 tmpfoam = gen0FortranPackArg(retvar, rtype, ftnType, junk);
1622
1623
1624 /* Complex numbers need special treatment */
1625 switch (ftnType)
1626 {
1627 case FTN_FSComplex:
1628 /* Convert Complex SF into COMPLEX REAL */
1629 cfmt = gen0SingleCpxFormat(); /* COMPLEX REAL */
1630 afmt = gen0AldorCpxFormat(); /* Complex SF */
1631 cpx = gen0TempLocal0(FOAM_Rec, cfmt);
1632
1633 /* Allocate storage for the COMPLEX REAL */
1634 recfoam = gen0RNew(cpx, cfmt)foamNew(FOAM_Set, 2, foamCopy(cpx), foamNew(FOAM_RNew, 1, cfmt
))
;
1635 gen0AddStmt(recfoam, absyn);
1636
1637 /* Copy the real part of the Complex SF */
1638 creal = foamNewRElt(afmt, foamCopy(tmpfoam), (AInt)0)foamNew(FOAM_RElt,3,(AInt)(afmt),foamCopy(tmpfoam),(AInt)((AInt
)0))
;
1639 creal = foamNewCast(FOAM_SFlo, creal)foamNew(FOAM_Cast, 2, FOAM_SFlo, creal);
1640 creal = gen0RSet(foamCopy(cpx), cfmt, (AInt)0, creal)foamNew(FOAM_Set, 2, foamNew(FOAM_RElt,3,(AInt)(cfmt),foamCopy
(foamCopy(cpx)),(AInt)((AInt)0)), creal)
;
1641 gen0AddStmt(creal, absyn);
1642
1643 /* Copy the imaginary part */
1644 cimag = foamNewRElt(afmt, foamCopy(tmpfoam), (AInt)1)foamNew(FOAM_RElt,3,(AInt)(afmt),foamCopy(tmpfoam),(AInt)((AInt
)1))
;
1645 cimag = foamNewCast(FOAM_SFlo, cimag)foamNew(FOAM_Cast, 2, FOAM_SFlo, cimag);
1646 cimag = gen0RSet(foamCopy(cpx), cfmt, (AInt)1, cimag)foamNew(FOAM_Set, 2, foamNew(FOAM_RElt,3,(AInt)(cfmt),foamCopy
(foamCopy(cpx)),(AInt)((AInt)1)), cimag)
;
1647 gen0AddStmt(cimag, absyn);
1648
1649 /* Now use the Fortran-format local */
1650 tmpfoam = foamCopy(cpx);
1651 break;
1652 case FTN_FDComplex:
1653 /* Convert Complex DF into COMPLEX DOUBLE */
1654 cfmt = gen0DoubleCpxFormat(); /* COMPLEX DOUBLE */
1655 afmt = gen0AldorCpxFormat(); /* Complex DF */
1656 dfmt = gen0MakeDoubleFormat(); /* DF */
1657 cpx = gen0TempLocal0(FOAM_Rec, cfmt);
1658
1659 /* Allocate storage for the COMPLEX DOUBLE */
1660 recfoam = gen0RNew(cpx, cfmt)foamNew(FOAM_Set, 2, foamCopy(cpx), foamNew(FOAM_RNew, 1, cfmt
))
;
1661 gen0AddStmt(recfoam, absyn);
1662
1663 /* Copy the real DFlo part of the Complex DF */
1664 creal = foamNewRElt(afmt, foamCopy(tmpfoam), (AInt)0)foamNew(FOAM_RElt,3,(AInt)(afmt),foamCopy(tmpfoam),(AInt)((AInt
)0))
;
1665 creal = foamNewRElt(dfmt, creal, (AInt)0)foamNew(FOAM_RElt,3,(AInt)(dfmt),creal,(AInt)((AInt)0));
1666 creal = gen0RSet(foamCopy(cpx), cfmt, (AInt)0, creal)foamNew(FOAM_Set, 2, foamNew(FOAM_RElt,3,(AInt)(cfmt),foamCopy
(foamCopy(cpx)),(AInt)((AInt)0)), creal)
;
1667 gen0AddStmt(creal, absyn);
1668
1669 /* Copy the imaginary part */
1670 cimag = foamNewRElt(afmt, foamCopy(tmpfoam), (AInt)1)foamNew(FOAM_RElt,3,(AInt)(afmt),foamCopy(tmpfoam),(AInt)((AInt
)1))
;
1671 cimag = foamNewRElt(dfmt, cimag, (AInt)0)foamNew(FOAM_RElt,3,(AInt)(dfmt),cimag,(AInt)((AInt)0));
1672 cimag = gen0RSet(foamCopy(cpx), cfmt, (AInt)1, cimag)foamNew(FOAM_Set, 2, foamNew(FOAM_RElt,3,(AInt)(cfmt),foamCopy
(foamCopy(cpx)),(AInt)((AInt)1)), cimag)
;
1673 gen0AddStmt(cimag, absyn);
1674
1675 /* Now use the Fortran-format local */
1676 tmpfoam = foamCopy(cpx);
1677 break;
1678 default:
1679 break;
1680 }
1681
1682
1683 /* Return the value */
1684 tmpfoam = foamNewReturn(foamCopy(tmpfoam))foamNew(FOAM_Return, 1, foamCopy(tmpfoam));
1685 gen0AddStmt(tmpfoam, absyn);
1686 }
1687 else
1688 {
1689 /* Return nothing */
1690 tmpfoam = foamNewReturn(foamNew(FOAM_Values, (AInt)0))foamNew(FOAM_Return, 1, foamNew(FOAM_Values, (AInt)0));
1691 gen0AddStmt(tmpfoam, absyn);
1692 }
1693
1694
1695 /*
1696 * Finish off the FOAM creation. Note that we want to
1697 * use a basic machine type for the return type of this
1698 * function so that Fortran can understand the result.
1699 * This means we use `rtype' in gen0ProgFiniEmpty()
1700 * rather than `retType' which we would do normally.
1701 */
1702 gen0UseStackedFormat((AInt)0); /* These two lines provide a format */
1703 gen0ProgPushFormat((AInt)0); /* for the lexical argument `op' */
1704 gen0ProgFiniEmpty(foam, rtype, emptyFormatSlot4);
1705
1706
1707 /* We are down one lexical level */
1708 gen0AddLexLevels(foam, 1);
1709
1710
1711 /* Optimisation bits */
1712 /* foam->foamProg.infoBits = IB_INLINEME; */
1713 foamOptInfo(foam)((foam)->hdr.info.opt) = optInfoNew(NULL((void*)0), foam, NULL((void*)0), false((int) 0));
1714 foam->foamProg.format = retfmt;
1715
1716
1717 /* Restore the saved state before returning */
1718 gen0ProgRestoreState(saved);
1719 return clos;
1720}
1721
1722
1723/*
1724 * Invent some absyn for the parameter list of a function.
1725 */
1726localstatic AbSyn
1727ab0FortranExportArgs(TForm tf)
1728{
1729 /* How many parameters does this function have? */
1730 Length numargs = tfIsMulti(tf)(((tf)->tag) == TF_Multiple) ? tfMultiArgc(tf) : 1;
1731
1732
1733 /* Deal with single and multiple arguments separately */
1734 if (numargs > 1)
1735 {
1736 /* Multiple arguments: (Comma ...) */
1737 Length i;
1738 AbSynList lst = listNil(AbSyn)((AbSynList) 0);
1739
1740
1741 /* Create each argument */
1742 for (i = 0; i < numargs; i++)
1743 {
1744 AbSyn arg = ab1FortranExportArg(i);
1745 lst = listCons(AbSyn)(AbSyn_listPointer->Cons)(arg, lst);
1746 }
1747
1748
1749 /* Make sure that the list is in the right order */
1750 lst = listNReverse(AbSyn)(AbSyn_listPointer->NReverse)(lst);
1751
1752
1753 /* Return the absyn for the parameter list */
1754 return abNewCommaL(sposNone, lst)abNewOfList(AB_Comma, sposNone,lst);
1755 }
1756 else
1757 return ab1FortranExportArg((Length)0);
1758}
1759
1760localstatic AbSyn
1761ab1FortranExportArg(Length i)
1762{
1763 /* Create absyn for single argument */
1764 Symbol sym;
1765 AbSyn type, param;
1766
1767
1768 /* Construct a name for this parameter. */
1769 sym = gen0FortranArgName(i);
1770
1771
1772 /* Create the absyn for the name and type */
1773 param = abNewId(sposNone, sym)abNew(AB_Id, sposNone,1, sym);
1774 type = abNewId(sposNone, symIntern("Word"))abNew(AB_Id, sposNone,1, symProbe("Word", 1 | 2));
1775
1776
1777 /* Return the parameter declaration */
1778 return abNewDeclare(sposNone, param, type)abNew(AB_Declare, sposNone,2, param,type);
1779}
1780
1781
1782/*
1783 * Construct before and after code for each parameter.
1784 */
1785localstatic FoamList
1786gen0FortranExportArgs(TForm tf, FoamList *bef, FoamList *aft)
1787{
1788 Foam par;
1789 FoamList lst = listNil(Foam)((FoamList) 0);
1790 Length i, numargs;
1791
1792
1793 /* How many parameters does this function have? */
1794 numargs = tfIsMulti(tf)(((tf)->tag) == TF_Multiple) ? tfMultiArgc(tf) : 1;
1795
1796
1797 /* Deal with single and multiple arguments separately */
1798 if (numargs > 1)
1799 {
1800 /* Process each argument */
1801 for (i = 0;i < numargs;i++)
1802 {
1803 /* Get the next argument */
1804 TForm t = tfMultiArgN(tf, i)tfFollowArg(tf, i);
1805
1806 par = gen1FortranExportArg(t, i, bef, aft);
1807 lst = listCons(Foam)(Foam_listPointer->Cons)(par, lst);
1808 }
1809 }
1810 else
1811 {
1812 /* A single argument */
1813 par = gen1FortranExportArg(tf, (Length) 0, bef, aft);
1814 lst = listCons(Foam)(Foam_listPointer->Cons)(par, lst);
1815 }
1816
1817
1818 /* Reverse the list and return it */
1819 lst = listNReverse(Foam)(Foam_listPointer->NReverse)(lst);
1820 return lst;
1821}
1822
1823localstatic Foam
1824gen1FortranExportArg(TForm tforig, Length i,
1825 FoamList *befLst, FoamList *aftLst)
1826{
1827 FoamTag fmtype, argtype, lextype, realType;
1828 FortranType ftnType;
1829 Foam decl, tmpvar, fmparam, tmpfoam, refvar;
1830 Foam cpx, creal, cimag;
1831 FoamList bef, aft;
1832 Symbol sym;
1833 String symstr;
1834 Bool isRef = false((int) 0);
1835 AInt fmt;
1836 TForm tf;
1837
1838
1839 /* Note the "before" and "after" code */
1840 bef = *befLst;
1841 aft = *aftLst;
1842
1843
1844 /* What was the name of this parameter? */
1845 sym = gen0FortranArgName(i);
1846 symstr = strCopy(symString(sym)((sym)->str));
1847
1848
1849 /* Note if passed by reference and map Ref(T) to T */
1850 if (tfIsReference(tforig)(((tforig)->tag) == TF_Reference))
1851 {
1852 isRef = true1;
1853 tf = tfReferenceArg(tforig)tfFollowArg(tforig, 0);
1854 }
1855 else
1856 tf = tforig;
1857
1858
1859 /* What is the type of this argument? */
1860 ftnType = ftnTypeFrDomTForm(tf);
1861 if (ftnType)
1862 fmtype = gen0FtnMachineType(ftnType);
1863 else
1864 fmtype = gen0Type(tf, NULL((void*)0));
1865
1866
1867 /* We only care about a few argument types */
1868 argtype = (fmtype == FOAM_Clos) ? FOAM_Clos : FOAM_Word;
1869
1870
1871 /* Create a declaration for this parameter */
1872 decl = foamNewDecl(argtype, symstr, emptyFormatSlot)foamNew(FOAM_Decl,4,(AInt)(argtype),symstr, (AInt) (0x7FFF), 4
)
;
1873
1874
1875 /* Add the new parameter to the FOAM prog */
1876 gen0AddParam(decl);
1877
1878
1879 /*
1880 * Add to the "before" code: this is simply unpacking
1881 * the value from the Fortran pointer and storing it
1882 * locally as an Aldor value. If we are passing values
1883 * by reference then we use a lexical otherwise a local.
1884 */
1885 fmparam = foamNewPar(i)foamNew(FOAM_Par, 1, (AInt)(i));
1886 lextype = gen0Type(tf, NULL((void*)0));
1887 tmpvar = isRef ? gen0TempLex(lextype)gen0TempLex0(lextype, 4) : gen0TempLocal(lextype)gen0TempLocal0(lextype, 4);
1888 tmpfoam = gen0FortranConvArg(fmparam, fmtype, ftnType, &bef);
1889 tmpfoam = foamNewSet(tmpvar, tmpfoam)foamNew(FOAM_Set, 2, tmpvar, tmpfoam);
1890 bef = listCons(Foam)(Foam_listPointer->Cons)(foamCopy(tmpfoam), bef);
1891
1892
1893 /*
1894 * If we are passing this parameter by reference
1895 * then wrap it up in a Reference(T) value and
1896 * pass that instead. Then after the call we need
1897 * to unpack the reference and update the Fortran
1898 * argument.
1899 */
1900 if (isRef)
1901 {
1902 FoamTag fmret;
1903 AbSyn tmpab;
1904 Foam *argloc;
1905 AInt cfmt, afmt, dfmt;
1906 Foam tmpget, retfoam, stmt;
1907 TForm tfiget, tfiset, tfret;
1908 Syme nsyme = (Syme)NULL((void*)0);
1909
1910
1911 /* Construct the reference to the local */
1912 refvar = gen0TempLocal(gen0Type(tforig, &fmt))gen0TempLocal0(gen0Type(tforig, &fmt), 4);
1913 tmpab = abNewId(sposNone, sym)abNew(AB_Id, sposNone,1, sym);
1914 tmpfoam = genReferenceFrFoam(tmpvar, tf, tmpab);
1915 tmpfoam = foamNewSet(refvar, tmpfoam)foamNew(FOAM_Set, 2, refvar, tmpfoam);
1916 bef = listCons(Foam)(Foam_listPointer->Cons)(foamCopy(tmpfoam), bef);
1917
1918
1919 /*
1920 * Dereference refvar after the call - see the
1921 * comments in gen0ModifyFortranCall() for more
1922 * details on how this bit works. Basically a
1923 * reference is stored as a pair of functions,
1924 * the getter and the setter:
1925 *
1926 * ref: () -> Cross(() -> T, T -> T);
1927 *
1928 * Start by computing function return types.
1929 */
1930 tfiget = tfMap(tfNone()tfMulti(0), tf);
1931 tfiset = tfMap(tf, tf);
1932 tfret = tfMulti(2, tfiget, tfiset);
1933 fmret = gen0Type(tfret, NULL((void*)0));
1934
1935
1936 /*
1937 * Extract the getter/setter pair. This is slightly
1938 * complicated by the fact that we have a multiple
1939 * return value. The gen0ApplyReturn() function will
1940 * invoke gen0AddStmt() in this situation so we can't
1941 * use it here. Instead we use a similar function
1942 * which returns some FOAM to be added to our list
1943 * of things to-do.
1944 */
1945 retfoam = foamCopy(refvar);
1946 retfoam = gen0CCallFrFoam(fmret, retfoam,(Length) 0, &argloc);
1947 retfoam = gen1ApplyReturn(tmpab, nsyme, tfret, retfoam, &stmt);
1948 aft = listCons(Foam)(Foam_listPointer->Cons)(foamCopy(stmt), aft);
1949
1950
1951 /* Extract the getter */
1952 tmpfoam = foamCopy(retfoam);
1953 assert(foamTag(tmpfoam) == FOAM_Values)do { if (!(((tmpfoam)->hdr.tag) == FOAM_Values)) _do_assert
(("foamTag(tmpfoam) == FOAM_Values"),"gf_fortran.c",1953); } while
(0)
;
1954 tmpget = tmpfoam->foamValues.argv[0];
1955
1956
1957 /* Apply the getter to obtain the updated Aldor value */
1958 tmpfoam = gen0CCallFrFoam(lextype, tmpget, (Length) 0, &argloc);
1959 tmpfoam = gen0ApplyReturn(tmpab, (Syme)NULL((void*)0), tf, tmpfoam);
1960
1961
1962 /* Convert the Aldor value into a Fortran value */
1963 tmpfoam = gen0FortranPackArg(tmpfoam,fmtype,ftnType,&realType);
1964
1965
1966 /* !!! BUG !!!
1967 * Note that the lexical that we used for the reference
1968 * to the function parameter may now point to somewhere
1969 * else in memory particularly if it is a FixedString or
1970 * String). Somehow we need to strncpy from the lexical
1971 * to the function parameter. Quite how we can do this
1972 * is beyond me at the moment.
1973 */
1974 retfoam = foamCopy(fmparam);
1975
1976
1977 /*
1978 * gen0FortranPackArg and gen0WritePointerTo do not
1979 * deal with complex numbers. This means that tmpfoam
1980 * is still a Complex R value (where R = SF or DF).
1981 */
1982 if (ftnType == FTN_FSComplex)
1983 {
1984 /* Compute the record formats involved */
1985 cfmt = gen0SingleCpxFormat(); /* COMPLEX REAL */
1986 afmt = gen0AldorCpxFormat(); /* Complex SF */
1987 cpx = retfoam;
1988
1989 /* Copy the real part of the Complex SF */
1990 creal = foamNewRElt(afmt, foamCopy(tmpfoam), (AInt)0)foamNew(FOAM_RElt,3,(AInt)(afmt),foamCopy(tmpfoam),(AInt)((AInt
)0))
;
1991 creal = foamNewCast(FOAM_SFlo, creal)foamNew(FOAM_Cast, 2, FOAM_SFlo, creal);
1992 creal = gen0RSet(foamCopy(cpx), cfmt, (AInt)0, creal)foamNew(FOAM_Set, 2, foamNew(FOAM_RElt,3,(AInt)(cfmt),foamCopy
(foamCopy(cpx)),(AInt)((AInt)0)), creal)
;
1993 aft = listCons(Foam)(Foam_listPointer->Cons)(creal, aft);
1994
1995 /* Copy the imaginary part */
1996 cimag = foamNewRElt(afmt, foamCopy(tmpfoam), (AInt)1)foamNew(FOAM_RElt,3,(AInt)(afmt),foamCopy(tmpfoam),(AInt)((AInt
)1))
;
1997 cimag = foamNewCast(FOAM_SFlo, cimag)foamNew(FOAM_Cast, 2, FOAM_SFlo, cimag);
1998 cimag = gen0RSet(foamCopy(cpx), cfmt, (AInt)1, cimag)foamNew(FOAM_Set, 2, foamNew(FOAM_RElt,3,(AInt)(cfmt),foamCopy
(foamCopy(cpx)),(AInt)((AInt)1)), cimag)
;
1999 aft = listCons(Foam)(Foam_listPointer->Cons)(cimag, aft);
2000
2001 /* Now use the Fortran-format local */
2002 tmpfoam = foamCopy(cpx);
Value stored to 'tmpfoam' is never read
2003 }
2004 else if (ftnType == FTN_FDComplex)
2005 {
2006 /* Convert Complex DF into COMPLEX DOUBLE */
2007 cfmt = gen0DoubleCpxFormat(); /* COMPLEX DOUBLE */
2008 afmt = gen0AldorCpxFormat(); /* Complex DF */
2009 dfmt = gen0MakeDoubleFormat(); /* DF */
2010 cpx = retfoam;
2011
2012 /* Copy the real DFlo part of the Complex DF */
2013 creal = foamNewRElt(afmt, foamCopy(tmpfoam), (AInt)0)foamNew(FOAM_RElt,3,(AInt)(afmt),foamCopy(tmpfoam),(AInt)((AInt
)0))
;
2014 creal = foamNewRElt(dfmt, creal, (AInt)0)foamNew(FOAM_RElt,3,(AInt)(dfmt),creal,(AInt)((AInt)0));
2015 creal = gen0RSet(foamCopy(cpx), cfmt, (AInt)0, creal)foamNew(FOAM_Set, 2, foamNew(FOAM_RElt,3,(AInt)(cfmt),foamCopy
(foamCopy(cpx)),(AInt)((AInt)0)), creal)
;
2016 aft = listCons(Foam)(Foam_listPointer->Cons)(creal, aft);
2017
2018 /* Copy the imaginary part */
2019 cimag = foamNewRElt(afmt, foamCopy(tmpfoam), (AInt)1)foamNew(FOAM_RElt,3,(AInt)(afmt),foamCopy(tmpfoam),(AInt)((AInt
)1))
;
2020 cimag = foamNewRElt(dfmt, cimag, (AInt)0)foamNew(FOAM_RElt,3,(AInt)(dfmt),cimag,(AInt)((AInt)0));
2021 cimag = gen0RSet(foamCopy(cpx), cfmt, (AInt)1, cimag)foamNew(FOAM_Set, 2, foamNew(FOAM_RElt,3,(AInt)(cfmt),foamCopy
(foamCopy(cpx)),(AInt)((AInt)1)), cimag)
;
2022 aft = listCons(Foam)(Foam_listPointer->Cons)(cimag, aft);
2023
2024 /* Now use the Fortran-format local */
2025 tmpfoam = foamCopy(cpx);
2026 }
2027 else
2028 {
2029 /* Stuff the value in the pointer if possible */
2030 tmpfoam = gen0WritePointerTo(realType,retfoam,tmpfoam);
2031 if (tmpfoam != (Foam)NULL((void*)0))
2032 aft = listCons(Foam)(Foam_listPointer->Cons)(foamCopy(tmpfoam), aft);
2033 }
2034
2035
2036 /* Use the reference from now-on */
2037 tmpvar = refvar;
2038 }
2039
2040
2041 /* Update the before and after code */
2042 *befLst = bef;
2043 *aftLst = aft;
2044
2045
2046 /* Return the FOAM for this parameter */
2047 return foamCopy(tmpvar);
2048}
2049
2050/*
2051 * Read a pointer to a machine type such as DFlo into
2052 * an Aldor domain such as DoubleFloat. This is used for
2053 * passing values to-and-from Fortran. If this is a string
2054 * argument then parameter holds its length.
2055 */
2056localstatic Foam
2057gen0FortranConvArg(Foam foam, FoamTag fmType, FortranType ftnType,
2058 FoamList *l)
2059{
2060 FoamTag realType;
2061 FoamList ltmp, lst;
2062 AInt cfmt, afmt, dfmt;
2063 Foam tmpfoam, tmpvar;
2064 Foam res, creal, cimag, rpart, ipart;
2065
2066
2067 /* Local copy of the list */
2068 lst = *l;
2069
2070
2071 /* Fortran passes LOGICAL values as INTEGERs */
2072 realType = (fmType == FOAM_Bool) ? FOAM_SInt : fmType;
2073
2074
2075 /* Unpack the Fortran pointer */
2076 tmpfoam = gen0ReadPointerTo(realType, foam);
2077
2078
2079 /* Apply any extra fixes required */
2080 switch (ftnType)
2081 {
2082 case FTN_Boolean :
2083 /* Fall through */
2084 case FTN_SingleInteger :
2085 /* Fall through */
2086 case FTN_FSingle :
2087 tmpfoam = foamNewCast(FOAM_Word, tmpfoam)foamNew(FOAM_Cast, 2, FOAM_Word, tmpfoam);
2088 break;
2089 case FTN_FDouble :
2090 tmpfoam = gen0MakeDoubleCode(tmpfoam, &ltmp);
2091 lst = listNConcat(Foam)(Foam_listPointer->NConcat)(ltmp, lst);
2092 break;
2093 case FTN_Character :
2094 /* Fall through */
2095 case FTN_String :
2096 /* Fall through */
2097 case FTN_XLString :
2098 /*
2099 * Refer to the code in genc.c to see why
2100 * we don't have to do anything special here.
2101 */
2102 break;
2103 case FTN_FSComplex:
2104 /*
2105 * Convert COMPLEX REAL into Complex SF. To
2106 * do this we store the Fortran argument in
2107 * a local. Then we copy and convert the two
2108 * components into a new local for returning.
2109 */
2110 cfmt = gen0SingleCpxFormat(); /* COMPLEX REAL */
2111 afmt = gen0AldorCpxFormat(); /* Complex SF */
2112
2113 /* Create a local and store the updated value */
2114 tmpvar = gen0TempLocal0(FOAM_Rec, cfmt);
2115 tmpfoam = foamNewSet(foamCopy(tmpvar), tmpfoam)foamNew(FOAM_Set, 2, foamCopy(tmpvar), tmpfoam);
2116 lst = listCons(Foam)(Foam_listPointer->Cons)(tmpfoam, lst);
2117
2118 /* Allocate storage for the Complex SF result */
2119 res = gen0TempLocal0(FOAM_Rec, afmt);
2120 lst = listCons(Foam)(Foam_listPointer->Cons)(gen0RNew(foamCopy(res), afmt)foamNew(FOAM_Set, 2, foamCopy(foamCopy(res)), foamNew(FOAM_RNew
, 1, afmt))
, lst);
2121
2122 /* Copy the real part into the local */
2123 creal = foamNewRElt(cfmt, foamCopy(tmpvar), (AInt)0)foamNew(FOAM_RElt,3,(AInt)(cfmt),foamCopy(tmpvar),(AInt)((AInt
)0))
;
2124 creal = foamNewCast(FOAM_Word, creal)foamNew(FOAM_Cast, 2, FOAM_Word, creal);
2125 creal = gen0RSet(foamCopy(res), afmt, (AInt)0, creal)foamNew(FOAM_Set, 2, foamNew(FOAM_RElt,3,(AInt)(afmt),foamCopy
(foamCopy(res)),(AInt)((AInt)0)), creal)
;
2126 lst = listCons(Foam)(Foam_listPointer->Cons)(creal, lst);
2127
2128 /* Copy the imaginary part into the local */
2129 cimag = foamNewRElt(cfmt, foamCopy(tmpvar), (AInt)1)foamNew(FOAM_RElt,3,(AInt)(cfmt),foamCopy(tmpvar),(AInt)((AInt
)1))
;
2130 cimag = foamNewCast(FOAM_Word, cimag)foamNew(FOAM_Cast, 2, FOAM_Word, cimag);
2131 cimag = gen0RSet(foamCopy(res), afmt, (AInt)1, cimag)foamNew(FOAM_Set, 2, foamNew(FOAM_RElt,3,(AInt)(afmt),foamCopy
(foamCopy(res)),(AInt)((AInt)1)), cimag)
;
2132 lst = listCons(Foam)(Foam_listPointer->Cons)(cimag, lst);
2133
2134 /* Use the Complex DF as the result */
2135 tmpfoam = res;
2136 break;
2137 case FTN_FDComplex:
2138 /*
2139 * Convert COMPLEX DOUBLE into Complex DF. To
2140 * do this we store the Fortran argument in
2141 * a local. Then we copy and convert the two
2142 * components into a new local for returning.
2143 */
2144 cfmt = gen0DoubleCpxFormat();
2145 afmt = gen0AldorCpxFormat();
2146 dfmt = gen0MakeDoubleFormat();
2147
2148 /* Create a local and store the updated value */
2149 tmpvar = gen0TempLocal0(FOAM_Rec, cfmt);
2150 tmpfoam = foamNewSet(foamCopy(tmpvar), tmpfoam)foamNew(FOAM_Set, 2, foamCopy(tmpvar), tmpfoam);
2151 lst = listCons(Foam)(Foam_listPointer->Cons)(tmpfoam, lst);
2152
2153
2154 /* Create a DF for the real part */
2155 rpart = gen0TempLocal0(FOAM_Rec, dfmt);
2156 tmpfoam = gen0RNew(foamCopy(rpart), dfmt)foamNew(FOAM_Set, 2, foamCopy(foamCopy(rpart)), foamNew(FOAM_RNew
, 1, dfmt))
;
2157 lst = listCons(Foam)(Foam_listPointer->Cons)(tmpfoam, lst);
2158
2159
2160 /* Copy the real DFlo part into the DF */
2161 creal = foamNewRElt(cfmt, foamCopy(tmpvar), (AInt)0)foamNew(FOAM_RElt,3,(AInt)(cfmt),foamCopy(tmpvar),(AInt)((AInt
)0))
;
2162 creal = gen0RSet(foamCopy(rpart), dfmt, (AInt)0, creal)foamNew(FOAM_Set, 2, foamNew(FOAM_RElt,3,(AInt)(dfmt),foamCopy
(foamCopy(rpart)),(AInt)((AInt)0)), creal)
;
2163 lst = listCons(Foam)(Foam_listPointer->Cons)(creal, lst);
2164
2165
2166 /* Create a DF for the imaginary part */
2167 ipart = gen0TempLocal0(FOAM_Rec, dfmt);
2168 tmpfoam = gen0RNew(foamCopy(ipart), dfmt)foamNew(FOAM_Set, 2, foamCopy(foamCopy(ipart)), foamNew(FOAM_RNew
, 1, dfmt))
;
2169 lst = listCons(Foam)(Foam_listPointer->Cons)(tmpfoam, lst);
2170
2171
2172 /* Copy the imaginary part into the DF */
2173 cimag = foamNewRElt(cfmt, foamCopy(tmpvar), (AInt)1)foamNew(FOAM_RElt,3,(AInt)(cfmt),foamCopy(tmpvar),(AInt)((AInt
)1))
;
2174 cimag = gen0RSet(foamCopy(ipart), dfmt, (AInt)0, cimag)foamNew(FOAM_Set, 2, foamNew(FOAM_RElt,3,(AInt)(dfmt),foamCopy
(foamCopy(ipart)),(AInt)((AInt)0)), cimag)
;
2175 lst = listCons(Foam)(Foam_listPointer->Cons)(cimag, lst);
2176
2177
2178 /* Create the Complex DF */
2179 res = gen0TempLocal0(FOAM_Rec, afmt);
2180 tmpfoam = gen0RNew(foamCopy(res), afmt)foamNew(FOAM_Set, 2, foamCopy(foamCopy(res)), foamNew(FOAM_RNew
, 1, afmt))
;
2181 lst = listCons(Foam)(Foam_listPointer->Cons)(tmpfoam, lst);
2182
2183
2184 /* Fill in the slots of the Complex DF */
2185 creal = gen0RSet(foamCopy(res), afmt, (AInt)0, foamCopy(rpart))foamNew(FOAM_Set, 2, foamNew(FOAM_RElt,3,(AInt)(afmt),foamCopy
(foamCopy(res)),(AInt)((AInt)0)), foamCopy(rpart))
;
2186 cimag = gen0RSet(foamCopy(res), afmt, (AInt)1, foamCopy(ipart))foamNew(FOAM_Set, 2, foamNew(FOAM_RElt,3,(AInt)(afmt),foamCopy
(foamCopy(res)),(AInt)((AInt)1)), foamCopy(ipart))
;
2187 lst = listCons(Foam)(Foam_listPointer->Cons)(creal, lst);
2188 lst = listCons(Foam)(Foam_listPointer->Cons)(cimag, lst);
2189
2190
2191 /* Use the Complex DF as the result */
2192 tmpfoam = res;
2193 break;
2194 default:
2195 if (fmType == FOAM_Bool)
2196 tmpfoam = foamNewCast(FOAM_Bool, tmpfoam)foamNew(FOAM_Cast, 2, FOAM_Bool, tmpfoam);
2197 break;
2198 }
2199
2200
2201 *l = lst;
2202 return tmpfoam;
2203}
2204
2205/*
2206 * Convert a value from an Aldor domain such as DoubleFloat
2207 * into a machine domain such as DFlo. This is used for passing values
2208 * to-and-from Fortran. If there is no action to be taken to
2209 * achieve the conversion then (Foam)NULL is returned.
2210 */
2211localstatic Foam
2212gen0FortranPackArg(Foam value, FoamTag fmType, FortranType ftnType, FoamTag *res)
2213{
2214 FoamTag realType;
2215 Foam tmpfoam = foamCopy(value);
2216
2217
2218 /* Fortran passes LOGICAL values as INTEGERs */
2219 realType = (fmType == FOAM_Bool) ? FOAM_SInt : fmType;
2220
2221
2222 /* Apply any extra fixes required */
2223 switch (ftnType)
2224 {
2225 case FTN_Boolean : /* Fall through */
2226 case FTN_SingleInteger : /* Fall through */
2227 case FTN_FSingle :
2228 tmpfoam = foamNewCast(realType, tmpfoam)foamNew(FOAM_Cast, 2, realType, tmpfoam);
2229 break;
2230 case FTN_FDouble :
2231 /* Pull out the DFlo */
2232 tmpfoam = gen0DoubleValue(tmpfoam);
2233 break;
2234 default:
2235 /* What is the format of the argument pointer? */
2236 if (fmType == FOAM_Bool)
2237 tmpfoam = foamNewCast(realType, tmpfoam)foamNew(FOAM_Cast, 2, realType, tmpfoam);
2238 break;
2239 }
2240
2241
2242 /* Tell the caller the real type of this foam */
2243 if (res) *res = realType;
2244 return tmpfoam;
2245}
2246
2247/*
2248 * We need to invent names for parameters for the wrapper
2249 * functions. We do this based on the argument number.
2250 */
2251localstatic Symbol
2252gen0FortranArgName(Length i)
2253{
2254 char num[40];
2255
2256 (void)sprintf(num, "%s%d", "x", (int) i);
2257 return symIntern(num)symProbe(num, 1 | 2);
2258}
2259