Silverfrost Forums

Welcome to our forums

Can a function access the name of the referencing routine?

12 Jul 2013 8:22 #12595

I have an external function that is used extensively throughout my model. It is held in a separate .FOR file to all the program subunits that might reference it. Under certain conditions the function will print a warning to the screen, and what I'd like to be able to do is discover which particular function reference generated the warning, or even just which program subunit contained the reference.

Is there any way that the function can access and print the name of the referencing subunit within the warning? I know that I could add a flag to the list of arguments that is set by the presence of the warning, and then test this flag immediately following every use of the function within the model, but this would be very labour intensive so I'm keen to find out if there is a more elegant solution that can simply be inserted into the function itself.

Many thanks

12 Jul 2013 8:45 #12596

Not in standerd fortran. It lacks a COMEFROM statement 😉 You may find this amusing: http://en.wikipedia.org/wiki/COMEFROM

12 Jul 2013 12:42 (Edited: 12 Jul 2013 12:46) #12597

What you want is a traceback that can be initiated from your code rather than a standard Fortran 'exception'. Such a traceback is not implementable within Fortran, but FTN95 can be induced to give you such a traceback. Other compilers provide a function (e.g., Intel Fortran provides TRACEBACKQQ()) to do this directly, but with a compiler that does not, you need to use the cuckoo's strategy.

The following example illustrates how to do this. Let us suppose that in SUB2 you want to use y==58 as the condition to print a traceback. When the condition is met, you do something that triggers a standard Fortran traceback, such as floating division by zero. Compile and link with the /DEBUG option, and run the program.

Unfortunately, there is no recovery from the exception, so you can only do one traceback per run. To print a traceback and continue, you need a more elaborate modification of your sources.

Another method is to run in the debugger, setting conditional breakpoints at the places of interest.

program tst
integer ijk
!
ijk=29
call sub1(ijk)
stop
end program tst
!
subroutine sub1(x)
integer x
call sub2(x+x)
return
end subroutine sub1
!
subroutine sub2(y)
integer y
if(y == 58)y=nint(y/0d0)
return
end subroutine sub2
12 Jul 2013 12:45 #12598

To identify where the function was called from, you could declare a global variable ( in COMMON or a MODULE) and set it to a 'location identifier value'. This could be an alternative to changing the argument list of your function. This way you could judge for yourself how carefully you would need to implement the location identifier update. Alternatively, I do not know of a way to obtain a call trace-back, which is what you realy want.

Doing a global search of the function call should not be too hard to do. The following DOS command would help: find /i /n '%1' *.f95 >%1.tce

John

13 Jul 2013 11:31 #12604

With Silverfrost's FTN95 you can supply your own version of the RUN_TRACE@ subroutine to do what you want. You enable this using the compile option /RUNTRACE (its also in Plato's project properties).

You just need to store the last subroutine/function visited in a variable.

A simple RUN_TRACE@ would look look like:

SUBROUTINE RUN_TRACE@(line_num, fun_name, file_name)
INTEGER(3) line_num
CHARACTER(*) fun_name, file_name

INTEGER(3), SAVE :: last_line_num
CHARACTER(len=32), SAVE :: last_fun_name

print *, 'Came from : Line, ' last_line_num, ' of routine ', last_fun_name

last_fun_name = fun_name
last_line_num = line_num
END
Please login to reply.