Arjen Markus (30 september 2016) A few days ago I started a revised interface between Fortran and Tcl (the old one is at [L1 ]). This revised version relies on the standardised C binding that became available with the introduction of the Fortran 2003 standard. It is exemplified by the ISO_C_BINDING module. The great advantage is that the full interface can be implemented in Fortran, rather than via an intermediate layer in C that translates the various data types from one language to the other.
I specifically target the Tcl stub interface. But that consists of about 630 functions. Not all of these will be useful for a typical extension, but you never know. So, generating the Fortran code to describe the interface requires automation - or extreme patience.
To sketch the task, here is an abstract from the current code (it is limited to a handful of functions to get the Example of a Tcl extension in Fortran going:
abstract interface integer function tcl_pkgprovide_api( interp, name, version, clientdata ) bind(c) import :: tcl_interp, c_ptr type(tcl_interp), value :: interp character(len=1), dimension(*) :: name character(len=1), dimension(*) :: version type(c_ptr), value :: clientdata end function tcl_pkgprovide_api end interface
procedure(tcl_pkgprovide_api), pointer, public :: tcl_pkgprovide ... call c_f_procpointer( tcl_stubs%f0, tcl_pkgprovide )
With this in place I can call the Tcl C function Tcl_PkgProvide as if it were an ordinary function/subroutine. (I cannot rely on C preprocessor macros)
Now the full Tcl stub table: the C code is generated from the file tcl.decls. And that is actually a Tcl script. That makes it easy to transform the API into the style required by Fortran. Here is the first part - pick the C interface code apart and transform it into a list of names and types:
# mktclstub.tcl -- # Use the file tcl.decls to generate the interfaces to the various # C functions in the Tcl API # set ::api {} set ::generate 1 set ::uniqueTypes {} # dummy commands -- # We only need "declare" # foreach name {library interface hooks scspec} { proc $name {args} {} } # interface -- # Do only do "tcl" # proc interface {name} { if { $name != "tcl" } { set ::generate 0 } } # export -- # Perhaps needed as well # proc export {signature} {} # declare -- # Define the stub entry # proc declare {index signature {extra {}}} { global api if { $extra != "" } { set signature $extra } if { $::generate } { set nameTypeList [getNamesTypes $signature] getUniqueTypes $nameTypeList puts $nameTypeList lappend api $index $nameTypeList } } # getNamesTypes -- # Transform the C signature # # Arguments: # signature The C code defining the signature # proc getNamesTypes {signature} { set namesTypes {} set signature [lrange [split [string trim $signature] (,)] 0 end-1] foreach element $signature { set element [string trim $element] regexp {[A-Za-z0-9_\[\]]+$} $element name set length [string length $name] set type [string trim [string range $element 0 end-$length]] lappend namesTypes $name $type } return $namesTypes } # getUniqueTypes -- # Determine what types are required # # Arguments: # namesTypes List of names and types # proc getUniqueTypes {namesTypes} { global uniqueTypes foreach {name type} $namesTypes { if { [lsearch $uniqueTypes $type] < 0 } { lappend uniqueTypes $type } } } # analyse and transform # source tcl.decls puts "Types:" puts [join $uniqueTypes \n]
This code is independent of the target language, so a second part (not finished yet) is to take the result of the analysis and generate the Fortran interfaces from that.
Because it is independent of the target language, it can be useful if you have similar requirements for your programming language.