Example Programs and Traceback Information

The following sections provide example programs that show the use of traceback to locate the cause of the error:

Example: End-of-File Condition, Program teof

In the following example, a READ statement creates an End-Of-File error, which the application has not handled:

  program teof
  integer*4 i,res
  i=here( )
  end

  integer*4 function here( )
  here = we( )
  end

  integer*4 function we( )
  we = go( )
  end

  integer*4 function go( )
  go = again( )
  end

  integer*4 function again( )
  integer*4 a
  open(10,file='xxx.dat',form='unformatted',status='unknown')
  read(10) a
  again=a
  end

The diagnostic output that results when this program is built with traceback enabled and linked against the single-threaded, DLL Fortran run-time library on the ia32 platform:

forrtl: severe (24): end-of-file during read, unit 10, file E:\USERS\xxx.dat
Image            PC        Routine         Line     Source
DFORRT.dll       1000A3B2  Unknown         Unknown  Unknown
DFORRT.dll       1000A184  Unknown         Unknown  Unknown
DFORRT.dll       10009324  Unknown         Unknown  Unknown
DFORRT.dll       10009596  Unknown         Unknown  Unknown
DFORRT.dll       10024193  Unknown         Unknown  Unknown
teof.exe         004011A9  AGAIN                21  teof.for
teof.exe         004010DD  GO                   15  teof.for
teof.exe         004010A7  WE                   11  teof.for
teof.exe         00401071  HERE                  7  teof.for
teof.exe         00401035  TEOF                  3  teof.for
teof.exe         004013D9  Unknown         Unknown  Unknown
teof.exe         004012DF  Unknown         Unknown  Unknown
KERNEL32.dll     77F1B304  Unknown         Unknown  Unknown

The first line of the output is the standard Fortran run-time error message. What follows is the result of walking the call stack in reverse order to determine where the error originated. Each line of output represents a call frame on the stack. Since the application was compiled with /traceback, the PC's that fall in Fortran code are correlated to their matching routine name, line number and source module. PC's which are not in Fortran code are not correlated and are reported as "Unknown."

The first five frames show the calls to routines in the Fortran run-time library (in reverse order). Since the application was linked against the single threaded DLL version of the library, the image name reported is DFORRT.dll. These are the run-time routines that were called to do the READ and upon detection of the EOF condition, were invoked to report the error. In the case of an unhandled I/O programming error, there will always be a few frames on the call stack down in run-time code like this.

The stack frame of real interest to the Fortran developer is the first frame in image teof.exe which shows that the error originated in the routine named AGAIN in source module teof.for at line 21. Looking in the source code at line 21, we see the Fortran READ statement that incurred the end-of-file condition.

The next four frames show that completes the trail of calls in the Fortran user code that led to the routine that got the error (TEOF->HERE->WE->GO->AGAIN).

Finally, the bottom three frames are routines which handled the startup and initialization of the program.

If this program had been linked against the single-threaded, static Fortran run-time library, the output would then look like:

forrtl: severe (24): end-of-file during read, unit 10, file E:\USERS\xxx.dat
Image          PC        Routine        Line     Source
teof.exe       004067D2  Unknown        Unknown  Unknown
teof.exe       0040659F  Unknown        Unknown  Unknown
teof.exe       00405754  Unknown        Unknown  Unknown
teof.exe       004059C5  Unknown        Unknown  Unknown
teof.exe       00403543  Unknown        Unknown  Unknown
teof.exe       004011A9  AGAIN               21  teof.for
teof.exe       004010DD  GO                  15  teof.for
teof.exe       004010A7  WE                  11  teof.for
teof.exe       00401071  HERE                 7  teof.for
teof.exe       00401035  TEOF                 3  teof.for
teof.exe       004202F9  Unknown        Unknown  Unknown
teof.exe       00416063  Unknown        Unknown  Unknown
KERNEL32.dll   77F1B304  Unknown        Unknown  Unknown

Notice that the initial five stack frames now show routines in image teof.exe, not DFORRT.DLL. The routines are the same five run-time routines as previously reported for the DLL case but since the application was linked against the static Fortran run-time library (dfor.lib), the object modules containing these routines were linked into the application image (teof.exe). Using the map file, you can determine that the PC reported in the top stack frame, 004067D2, is from routine _for_stack_trace, in module for_diags.obj of library dfor.lib (004067a0 < PC=004067D2 < 004079f0):

 ...
 0001:000057a0       _for_stack_trace           004067a0 f dfor:for_diags.obj
 0001:000069f0       _for__find_trace_info_file 004079f0 f dfor:for_diags.obj
 ...

Now suppose the application was compiled without traceback enabled and once again, linked against the single-threaded, static Fortran library. The diagnostic output would then appear as follows:

forrtl: severe (24): end-of-file during read, unit 10, file E:\USERS\xxx.dat
Image            PC        Routine       Line     Source
teof.exe         00406792  Unknown       Unknown  Unknown
teof.exe         0040655F  Unknown       Unknown  Unknown
teof.exe         00405714  Unknown       Unknown  Unknown
teof.exe         00405985  Unknown       Unknown  Unknown
teof.exe         00403503  Unknown       Unknown  Unknown
teof.exe         00401169  Unknown       Unknown  Unknown
teof.exe         004010A8  Unknown       Unknown  Unknown
teof.exe         00401078  Unknown       Unknown  Unknown
teof.exe         00401048  Unknown       Unknown  Unknown
teof.exe         0040102F  Unknown       Unknown  Unknown
teof.exe         004202B9  Unknown       Unknown  Unknown
teof.exe         00416023  Unknown       Unknown  Unknown
KERNEL32.dll     77F1B304  Unknown       Unknown  Unknown

Without the correlation information in the image that /traceback previously supplied, the Fortran run-time system cannot correlate PC's to routine name, line number, and source file. You can still use the map file to at least determine the routine names and what modules they are in. Look at the beginning of the entry point list in the map file for this image:

  Address         Publics by Value      Rva+Base   Lib:Object

 0001:00000000       _TEOF              00401000 f teof.obj
 0001:00000000       _TEOF@0            00401000 f teof.obj
 0001:00000000       _MAIN__            00401000 f teof.obj
 0001:0000003d       _HERE              0040103d f teof.obj
 0001:0000003d       _HERE@0            0040103d f teof.obj
 0001:0000006d       _WE@0              0040106d f teof.obj
 0001:0000006d       _WE                0040106d f teof.obj
 0001:0000009d       _GO                0040109d f teof.obj
 0001:0000009d       _GO@0              0040109d f teof.obj
 0001:000000cd       _AGAIN             004010cd f teof.obj
 0001:000000cd       _AGAIN@0           004010cd f teof.obj
 0001:00000180       _for_rtl_init_     00401180 f dfor:for_init.obj
 ...

After determining that the first five stack frames fall in run-time code (using portions of the map file not shown here), the sixth frame shows a PC of 00401169. Using the fragment of the map file shown above, it can be seen that this PC is greater than 004010cd but less than 00401180 and is therefore in routine _AGAIN, the first Fortran routine on the call stack. The remaining PC's can be manually correlated in a similar fashion to reconstruct the calling sequence.

Remember that compiling with /traceback increases the size of your application's image because of the extra PC correlation information included in the image. You can see if the extra traceback information is included in an image (checking for the presence of a .trace section) by typing:

  link -dump -summary your_app.exe

For the teof.exe example, the following is displayed:

  Microsoft (R) COFF Binary File Dumper Version x.xx.xxxx
  Copyright (C) Microsoft Corp 1992-1998. All rights reserved.

  Dump of file teof.exe

  File Type: EXECUTABLE IMAGE

     Summary

        1000 .data
        1000 .idata
        1000 .rdata
        1000 .text
        1000 .trace

Check the file size with a simple directory command. Here's the teof.exe example linked against the dynamic Fortran library with traceback:

   03/03/98  01:45p                 5,120 teof.exe
                1 File(s)           5,120 bytes

Without traceback, the following appears:

  03/03/98  01:46p                 4,608 teof.exe
                1 File(s)          4,608 bytes

For this simple example, the traceback correlation information added 512 bytes to the image size. In a real application, this would probably be much larger. For any application, the developer must decide if the increase in image size is worth the benefit of automatic PC correlation or if manually correlating PC's with a map file is acceptable.

For command-line use and in the release configuration in the visual development environment, traceback information is not included by default in Fortran compiles (default is /notraceback). In the visual development environment, the default is /traceback in the debug configuration. For the release configuration, request traceback in the Run Time category of the Project Settings dialog box.

If an error occurs when traceback was requested during compilation, the run-time library will produce the correlated call stack display.

If an error occurs when traceback was disabled during compilation, the run-time library will produce the uncorrelated call stack display.

If you do not want to see the call stack information displayed, you can set the environment variable FOR_DISABLE_STACK_TRACE to true. You will still get the Fortran run-time error message:

 forrtl: severe (24): end-of-file during read, unit 10, file E:\USERS\xxx.dat

Example: Machine Exception Condition, Program ovf

The following program generates a floating-point overflow exception when compiled with /fpe:0:

  program ovf
  real*4 a
  a=1e37
  do i=1,10
     a=hey(a)
  end do
  print *, 'a= ', a
  end

  real*4 function hey(b)
  real*4 b
  hey = watch(b)
  end

  real*4 function watch(b)
  real*4 b
  watch = out(b)
  end

  real*4 function out(b)
  real*4 b
  out = below(b)
  end

  real*4 function below(b)
  real*4 b
  below = b*10.0e0
  end

When this program is compiled on an ia32 system with /traceback, /fpe:0, and /optimization:0, the traceback output appears as follows:

forrtl: error (72): floating overflow
Image              PC        Routine            Line        Source
ovf.exe            00401161  BELOW                      29  ovf.f90
ovf.exe            0040113C  OUT                        24  ovf.f90
ovf.exe            0040111B  WATCH                      19  ovf.f90
ovf.exe            004010FA  HEY                        14  ovf.f90
ovf.exe            0040105B  OVF                         7  ovf.f90
ovf.exe            00432429  Unknown               Unknown  Unknown
ovf.exe            00426C74  Unknown               Unknown  Unknown
KERNEL32.dll       77F1B9EA  Unknown               Unknown  Unknown

Notice that unlike the previous example of an unhandled I/O programming error, the stack walk can begin right at the point of the exception. There are no run-time routines on the call stack to dig through. The overflow occurs in routine BELOW at PC 00401161 which is correlated to line 29 of the source file ovf.f90.

When the program is compiled at a higher optimization level, /optimization:4, with /fpe:0 and /traceback, the traceback output appears as follows:


forrtl: error (72): floating overflow
Image              PC        Routine            Line        Source
ovf.exe            00401070  OVF                        29  ovf.f90
ovf.exe            004323E9  Unknown               Unknown  Unknown
ovf.exe            00426C34  Unknown               Unknown  Unknown
KERNEL32.dll       77F1B9EA  Unknown               Unknown  Unknown

With /optimize:4, the entire program has been inlined. We can see this with a quick look in the listing file:

...
				.CODE
				PUBLIC	_MAIN__
	     0000	_MAIN__ PROC
55           0000		push	ebp
EC8B         0001		mov	ebp, esp
30EC83       0003		sub	esp, 48
000000E8     0006		call _for_check_flawed_pentium@0
00
04EC83       000B		sub	esp, 4
0020058D     000E		lea	eax, dword ptr .literal$+32
0000
50           0014		push	eax
000000E8     0015		call	_for_set_fpe_@4
00
001C058D     001A		lea	eax, dword ptr .literal$+28
0000
50           0020		push	eax
000000E8     0021		call	_for_set_reentrancy@4
00
04C483       0026		add	esp, 4
001805D9     0029		fld	dword ptr .literal$+24			; 000029
0000
00000DD8     002F		fmul	dword ptr .literal$
0000
9B           0035		fwait
00000DD8     0036		fmul	dword ptr .literal$
0000
9B           003C		fwait
00000DD8     003D		fmul	dword ptr .literal$
0000
9B           0043		fwait
00000DD8     0044		fmul	dword ptr .literal$
0000
9B           004A		fwait
00000DD8     004B		fmul	dword ptr .literal$
0000
9B           0051		fwait
00000DD8     0052		fmul	dword ptr .literal$
0000
9B           0058		fwait
00000DD8     0059		fmul	dword ptr .literal$
0000
9B           005F		fwait
00000DD8     0060		fmul	dword ptr .literal$
0000
9B           0066		fwait
00000DD8     0067		fmul	dword ptr .literal$
0000
FC5DD9       006D		fstp	dword ptr -4[ebp]
9B           0070		fwait
D233         0071		xor	edx, edx					    ; 000009
0014058D     0073		lea	eax, dword ptr .literal$+20
0000
03D045C7     0079		mov	dword ptr -48[ebp], 3
000000
D44589       0080		mov	dword ptr -44[ebp], eax
000C0D8D     0083		lea	ecx, dword ptr .literal$+12
0000
DC458D       0089		lea	eax, .T1_		; eax, dword ptr -36[ebp]
DC5589       008C		mov	.T1_, edx		; dword ptr -36[ebp], edx
04EC83       008F		sub	esp, 4
D0558D       0092		lea	edx, dword ptr -48[ebp]
52           0095		push	edx
51           0096		push	ecx
84FF0068     0097		push	126156544
07
FFFFFF68     009C		push	-1
FF
50           00A1		push	eax
000000E8     00A2		call	_for_write_seq_lis
00
18C483       00A7		add	esp, 24
FC458B       00AA		mov	eax, dword ptr -4[ebp]
D04589       00AD		mov	dword ptr -48[ebp], eax
04EC83       00B0		sub	esp, 4
D0558D       00B3		lea	edx, dword ptr -48[ebp]
00040D8D     00B6		lea	ecx, dword ptr .literal$+4
0000
DC458D       00BC		lea	eax, .T1_			; eax, dword ptr -36[ebp]
52           00BF		push	edx
51           00C0		push	ecx
50           00C1		push	eax
000000E8     00C2		call	_for_write_seq_lis_xmit
00
10C483       00C7		add	esp, 16
E58B         00CA		mov	esp, ebp					   ; 000010
000001B8     00CC		mov	eax, 1
00
5D           00D1		pop	ebp
C3           00D2		ret
_MAIN__				ENDP

...

The main program, OVF, no longer calls routine HEY. While the output is not quite what one might have expected intuitively, it is still entirely correct. You need to keep in mind the effects of compiler optimization when you interpret the diagnostic information reported for a failure in a release image.

If the same image were executed again but with environment variable FOR_ENABLE_VERBOSE_STACK_TRACE set to true, you would also see a dump of the exception context record at the time of the error. Here is an excerpt of how that would appear on an ia32 system:

forrtl: error (72): floating overflow

Hex Dump Of Exception Record Context Information:

Exception Context:  Processor Control and Status Registers.

EFlags:  00010212
CS:  0000001B  EIP:  00401161  SS:   00000023  ESP:  0012FE38  EBP:  0012FE60

Exception Context:  Processor Integer Registers.

EAX: 00444488  EBX:  00000009  ECX:  00444488  EDX:  00000002
ESI: 0012FBBC  EDI:  F9A70030

Exception Context:  Processor Segment Registers.

DS:  00000023  ES:   00000023  FS:   00000038  GS:   00000000

Exception Context:  Floating Point Control and Status Registers.

ControlWord:  FFFF0262  ErrorOffset:    0040115E  DataOffset:    0012FE5C
StatusWord:   FFFFF8A8  ErrorSelector:  015D001B  DataSelector:  FFFF0023
TagWord:      FFFF3FFF  Cr0NpxState:    00000000

Exception Context:  Floating Point RegisterArea.

RegisterArea[00]:  4080BC143F4000000000  RegisterArea[10]:  F7A0FFFFFFFF77F9D860
RegisterArea[20]:  00131EF0000800060012  RegisterArea[30]:  00000012F7C002080006
RegisterArea[40]:  02080006000000000000  RegisterArea[50]:  0000000000000012F7D0
RegisterArea[60]:  00000000000000300000  RegisterArea[70]:  FBBC000000300137D9EF
...

Example: Using Traceback in Mixed Fortran/C Applications, Program FPING and CPONG

Consider the following example that shows how the traceback output might appear in a mixed Fortran/C application. The main program is a Fortran program named FPING. Program FPING triggers a chain of function calls which are alternately Fortran and C code. Eventually, the C routine named Unlucky is called, which produces a floating divide by zero error.

Source module FPING.FOR contains the Fortran function definitions, each of which calls a C routine from source module CPONG.C. FPING.FOR is compiled with the /fpe:0 /optimize:0 /traceback options enabled, on the ia32 platform. Here's the program traceback output:

forrtl: error (73): floating divide by zero
Image            PC        Routine       Line     Source
fping.exe        00401161  Unknown       Unknown  Unknown
fping.exe        004010DC  DOWN4              58  fping.for
fping.exe        0040118F  Unknown       Unknown  Unknown
fping.exe        004010B6  DOWN3              44  fping.for
fping.exe        00401181  Unknown       Unknown  Unknown
fping.exe        00401094  DOWN2              31  fping.for
fping.exe        00401173  Unknown       Unknown  Unknown
fping.exe        00401072  DOWN1              18  fping.for
fping.exe        0040104B  FPING               5  fping.for
fping.exe        004013B9  Unknown       Unknown  Unknown
fping.exe        004012AF  Unknown       Unknown  Unknown
KERNEL32.dll     77F1B304  Unknown       Unknown  Unknown

Notice that the stack frames contributed by Fortran routines can be correlated to a routine name, line number, and source module but those frames contributed by C routines cannot be correlated. Remember, even though the stack can be walked in reverse, and PC's reported, the information necessary to correlate the PC to a routine name, line number, and so on, is contributed to the image from the objects generated by the Fortran compiler. The C compiler does not have this capability. Also remember that you only get the correlation information if you specify the /traceback option for your Fortran compiles.

The top stack frame cannot be correlated to a routine name because it is in C code. By examining the map file for the application, we can see that the reported PC, 00401161, is greater than the start of routine _Unlucky, but less than the start of routine _down1_C, so we at least know the error occurred in routine _Unlucky. Here is the pertinent section of the map file:

  Address         Publics by Value        Rva+Base   Lib:Object

 0001:00000000       _FPING               00401000 f fping.obj
 0001:00000000       _FPING@0             00401000 f fping.obj
 0001:00000000       _MAIN__              00401000 f fping.obj
 0001:0000005f       _DOWN1               0040105f f fping.obj
 0001:0000005f       _DOWN1@4             0040105f f fping.obj
 0001:00000083       _DOWN2@4             00401083 f fping.obj
 0001:00000083       _DOWN2               00401083 f fping.obj
 0001:000000a5       _DOWN3               004010a5 f fping.obj
 0001:000000a5       _DOWN3@4             004010a5 f fping.obj
 0001:000000c7       _DOWN4@4             004010c7 f fping.obj
 0001:000000c7       _DOWN4               004010c7 f fping.obj
 0001:00000100       _Fact                00401100 f cpong.obj
 0001:00000127       _Pythagoras          00401127 f cpong.obj

******************************************************
The reported PC lies between the start of _Unlucky and
the start of _down1_C...
******************************************************

 0001:0000014d       _Unlucky             0040114d f cpong.obj
 0001:00000167       _down1_C             00401167 f cpong.obj

 0001:00000175       _down2_C             00401175 f cpong.obj
 0001:00000183       _down3_C             00401183 f cpong.obj
 0001:00000192       _for_check_flawed_pentium@0 00401192 f dfordll:DFORRT.dll
 0001:00000198       _for_set_fpe_@4       00401198 f dfordll:DFORRT.dll
 0001:0000019e       _for_set_reentrancy@4 0040119e f dfordll:DFORRT.dll
 etc...

In a similar manner, the other PC's reported as "Unknown" can be correlated to a routine name using the map file.

When examining traceback output (or any type of diagnostic output for that matter), it is always important to keep in mind the affects of compiler optimization. The Fortran source module in the above example was built with optimization turned off, /optimize:0. Look at the output when optimizations are enabled, /optimize:4:

forrtl: error (73): floating divide by zero
Image           PC        Routine     Line     Source
fping.exe       00401111  Unknown     Unknown  Unknown
fping.exe       0040109D  DOWN4            58  fping.for
fping.exe       0040113F  Unknown     Unknown  Unknown
fping.exe       00401082  DOWN3            44  fping.for
fping.exe       00401131  Unknown     Unknown  Unknown
fping.exe       0040106B  DOWN2            31  fping.for
fping.exe       00401123  Unknown     Unknown  Unknown
fping.exe       00401032  FPING            18  fping.for
fping.exe       00401369  Unknown     Unknown  Unknown
fping.exe       0040125F  Unknown     Unknown  Unknown
KERNEL32.dll    77F1B304  Unknown     Unknown  Unknown

From the traceback output, it would appear that routine DOWN1 was never called. In fact, it has not been called. At the higher optimization level, the compiler has inlined function DOWN1 so that the call to routine down1_C is now made from FPING. The correlated line number still points to the correct line in the source code. You can see that DOWN1 was inlined by looking in the listing file, FPING.LST:

                                .CODE
                                PUBLIC  _MAIN__
             0000       _MAIN__ PROC
55           0000               push    ebp
EC8B         0001               mov     ebp, esp
04EC83       0003               sub     esp, 4
53           0006               push    ebx
000000E8     0007               call    _for_check_flawed_pentium@0
00
04EC83       000C               sub     esp, 4
0008058D     000F               lea     eax, dword ptr .literal$+8
0002
50           0015               push    eax
000000E8     0016               call    _for_set_fpe_@4
00
0004058D     001B               lea     eax, dword ptr .literal$+4
0002
50           0021               push    eax
000000E8     0022               call    _for_set_reentrancy@4
00
000035FF     0027               push    dword ptr .literal$           ; 000018
0000
000035FF     0027               push    dword ptr .literal$           ; 000018
0000

*******************************************************************
Call _down1_C from MAIN__ here, no call to DOWN1 Fortran routine...
*******************************************************************

000000E8     002D               call    _down1_C
00
C0DD         0032               ffree   st(0)
F7D9         0034               fincstp
08C483       0036               add     esp, 8
000001B8     0039               mov     eax, 1                        ; 000006
A0
5B           003E               pop     ebx
E58B         003F               mov     esp, ebp
5D           0041               pop     ebp
C3           0042               ret
_MAIN__                        ENDP

Finally, suppose the example Fortran code is redesigned with each of the Fortran routines split into separate source modules. Here is what the traceback output would look like with the redesigned code:

forrtl: error (73): floating divide by zero
Image            PC        Routine      Line     Source
fpingmain.exe    00401171  Unknown      Unknown  Unknown
fpingmain.exe    004010ED  DOWN4             12  fping4.for
fpingmain.exe    0040119F  Unknown      Unknown  Unknown
fpingmain.exe    004010C1  DOWN3             11  fping3.for
fpingmain.exe    00401191  Unknown      Unknown  Unknown
fpingmain.exe    00401099  DOWN2             11  fping2.for
fpingmain.exe    00401183  Unknown      Unknown  Unknown
fpingmain.exe    00401073  DOWN1             11  fping1.for
fpingmain.exe    0040104B  FPING              5  fpingmain.for
fpingmain.exe    004013C9  Unknown      Unknown  Unknown
fpingmain.exe    004012BF  Unknown      Unknown  Unknown
KERNEL32.dll     77F1B304  Unknown      Unknown  Unknown

Notice that the line number and source file correlation information has changed to reflect the new design of the code.

Here are the sources used in the above examples:

************************************
FPING.FOR
************************************
	program fping

	real*4 a,b
	a=-10.0
	b=down1(a)
	end

	real*4 function down1(b)
	real*4 b
!DEC$ IF DEFINED(_X86_)
	INTERFACE TO REAL*4 FUNCTION down1_C [C,ALIAS:'_down1_C'] (n)
!DEC$ ELSE
	INTERFACE TO REAL*4 FUNCTION down1_C [C,ALIAS:'down1_C'] (n)
!DEC$ ENDIF
	REAL*4 n [VALUE]
	END
	real*4 down1_C
	down1 = down1_C(b)
	end

	real*4 function down2(b)
	real*4 b [VALUE]
!DEC$ IF DEFINED(_X86_)
	INTERFACE TO REAL*4 FUNCTION down2_C [C,ALIAS:'_down2_C'] (n)
!DEC$ ELSE
	INTERFACE TO REAL*4 FUNCTION down2_C [C,ALIAS:'down2_C'] (n)
!DEC$ ENDIF
	REAL*4 n [VALUE]
	END
	real*4 down2_C
	down2 = down2_C(b)
	end

	real*4 function down3(b)
	real*4 b [VALUE]
!DEC$ IF DEFINED(_X86_)
	INTERFACE TO REAL*4 FUNCTION down3_C [C,ALIAS:'_down3_C'] (n)
!DEC$ ELSE
	INTERFACE TO REAL*4 FUNCTION down3_C [C,ALIAS:'down3_C'] (n)
!DEC$ ENDIF
	REAL*4 n [VALUE]
	END
	real*4 down3_C
	down3 = down3_C(b)
	end

	real*4 function down4(b)
	real*4 b [VALUE]
!DEC$ IF DEFINED(_X86_)
	INTERFACE TO SUBROUTINE Unlucky [C,ALIAS:'_Unlucky'] (a,c)
!DEC$ ELSE
	INTERFACE TO SUBROUTINE Unlucky [C,ALIAS:'Unlucky'] (a,c)
!DEC$ ENDIF
	REAL*4 a [VALUE]
	REAL*4 c [REFERENCE]
	END
	real*4 a
	call Unlucky(b,a)
	down4 = a
	end

************************************
CPONG.C
************************************
#include <math.h>

extern float __stdcall DOWN2 (float n);
extern float __stdcall DOWN3 (float n);
extern float __stdcall DOWN4 (float n);

int Fact( int n )
{
    if (n > 1)
        return( n * Fact( n - 1 ));
    return 1;
}

void Pythagoras( float a, float b, float *c)
{
    *c = sqrt( a * a + b * b );
}

void Unlucky( float a, float *c)
{
float b=0.0;
    *c = a/b;
}

float down1_C( float a )
{
    return( DOWN2( a ));
}

float down2_C( float a )
{
    return( DOWN3( a ));
}

float down3_C( float a )
{
    return( DOWN4( a ));
}

************************************
FPINGMAIN.FOR
************************************
	program fping

	real*4 a,b
	a=-10.0
	b=down1(a)
	end

************************************
FPING1.FOR
************************************
	real*4 function down1(b)
	real*4 b
!DEC$ IF DEFINED(_X86_)
	INTERFACE TO REAL*4 FUNCTION down1_C [C,ALIAS:'_down1_C'] (n)
!DEC$ ELSE
	INTERFACE TO REAL*4 FUNCTION down1_C [C,ALIAS:'down1_C'] (n)
!DEC$ ENDIF
	REAL*4 n [VALUE]
	END
	real*4 down1_C
	down1 = down1_C(b)
	end

************************************
FPING2.FOR
************************************
	real*4 function down2(b)
	real*4 b [VALUE]
!DEC$ IF DEFINED(_X86_)
	INTERFACE TO REAL*4 FUNCTION down2_C [C,ALIAS:'_down2_C'] (n)
!DEC$ ELSE
	INTERFACE TO REAL*4 FUNCTION down2_C [C,ALIAS:'down2_C'] (n)
!DEC$ ENDIF
	REAL*4 n [VALUE]
	END
	real*4 down2_C
	down2 = down2_C(b)
	end

************************************
FPING3.FOR
************************************
	real*4 function down3(b)
	real*4 b [VALUE]
!DEC$ IF DEFINED(_X86_)
	INTERFACE TO REAL*4 FUNCTION down3_C [C,ALIAS:'_down3_C'] (n)
!DEC$ ELSE
	INTERFACE TO REAL*4 FUNCTION down3_C [C,ALIAS:'down3_C'] (n)
!DEC$ ENDIF
	REAL*4 n [VALUE]
	END
	real*4 down3_C
	down3 = down3_C(b)
	end

************************************
FPING4.FOR
************************************
	real*4 function down4(b)
	real*4 b [VALUE]
!DEC$ IF DEFINED(_X86_)
	INTERFACE TO SUBROUTINE Unlucky [C,ALIAS:'_Unlucky'] (a,c)
!DEC$ ELSE
	INTERFACE TO SUBROUTINE Unlucky [C,ALIAS:'Unlucky'] (a,c)
!DEC$ ENDIF
	REAL*4 a [VALUE]
	REAL*4 c [REFERENCE]
	END
	real*4 a
	call Unlucky(b,a)
	down4 = a
	end