cantera/src/fortran/genf.py
Ray Speth 2528df0f75 Reorganized source tree structure
These changes make it unnecessary to copy header files around during
the build process, which tends to confuse IDEs and debuggers. The
headers which comprise Cantera's external C++ interface are now in
the 'include' directory.

All of the samples and demos are now in the 'samples' subdirectory.
2012-02-12 02:27:14 +00:00

205 lines
5.4 KiB
Python

""" Python script to generate a Python extension module from a clib
header file. """
import sys
_class = ''
_newclass = 1
def getargs(line):
"""Get the function name and arguments."""
i1 = line.find('(')
i2 = line.find(')')
if (i1 < 0 or i2 < 0):
raise 'syntax error: missing open or close quote'
nm = line[:i1].split()
nm = nm[-1]
argline = line[i1+1:i2]
args = argline.split(',')
for n in range(len(args)): args[n] = args[n].split()
v = []
for a in args:
if len(a) <= 1:
pass
elif len(a) == 2:
v.append(a)
elif len(a) == 3 and a[0] == 'const':
v.append([a[0]+' '+a[1],a[2]])
else:
print 'a = ',a, args
print 'line = ',line
raise 'malformed argument: '
return nm, v
_c2fout = {'int*':'integer', 'integer*':'integer',
'double*':'double precision', 'doublereal*':'double precision',
'char*':'character*(*)'}
_c2fin = {'const int*':'integer', 'const integer*':'integer',
'const double*':'double precision',
'const doublereal*':'double precision',
'const char*':'character*(*)'}
_c2fret = {'int':'integer', 'integer':'integer',
'double':'double precision',
'status_t':'integer',
'doublereal':'double precision'}
def writeinterface(fint, rtype, name, args):
s = ' '+_c2fret[rtype] + ' function '
if name[-1] == '_':
name = name[:-1]
s += name + '('
argstr=''
for a in args:
if a[0] <> 'ftnlen':
argstr += a[1] + ', '
if len(argstr) > 0:
argstr = argstr[:-2]
s += argstr+')\n'
fint.write(s)
for a in args:
if a[0][0] == 'd':
arr = '(*)'
else:
arr = ''
if a[0] in _c2fin:
fint.write(' '+_c2fin[a[0]]+', intent(in) :: '+a[1]+arr+'\n')
elif a[0] in _c2fout:
fint.write(' '+_c2fout[a[0]]+', intent(out) :: '+a[1]+arr+'\n')
fint.write(' end function '+name+'\n\n')
def writef90(fmod, rtype, otype, hndl, name, args):
subroutine = 0
if rtype == 'status_t':
subroutine = 1
if subroutine:
s = ' subroutine '
else:
s = ' '+_c2fret[rtype] + ' function '
if name[-1] == '_':
name = name[:-1]
wname = 'ct'+name[1:]
s += wname + '('
argstr='self, '
for a in args[1:]:
if a[0] <> 'ftnlen':
argstr += a[1] + ', '
if len(argstr) > 0:
argstr = argstr[:-2]
s += argstr+')\n'
fmod.write(s)
fmod.write(""" implicit none
type("""+otype+'), intent(inout) :: self\n')
for a in args[1:]:
if a[0][0] == 'd':
arr = '(*)'
else:
arr = ''
if a[0] in _c2fin:
fmod.write(' '+_c2fin[a[0]]+', intent(in) :: '+a[1]+arr+'\n')
elif a[0] in _c2fout:
fmod.write(' '+_c2fout[a[0]]+', intent(out) :: '+a[1]+arr+'\n')
if subroutine:
s = ' self%err = '+name+'(self%'+hndl+', '
else:
s = ' '+wname+' = '+name+'(self%'+hndl+', '
argstr = ''
for a in args[1:]:
if a[0] <> 'ftnlen':
argstr += a[1] + ', '
argstr = argstr[:-2]
s += argstr+')'
if subroutine:
fmod.write(s+'\n end subroutine '+wname+'\n\n')
else:
fmod.write(s+'\n end function '+wname+'\n\n')
fname = sys.argv[1] # fctxml
otype = sys.argv[2] # XML_Node
hndl = sys.argv[3] # xml_id
base, ext = fname.split('.')
modname = base
f = open(fname,'r')
fint = open(base+'_interface.f90','w')
#fmod = open(modname+'.f90','w')
fmod = open('cantera_'+modname+'.f90','w')
lines = f.readlines()
f.close()
#_rtypes = ['int', 'double', 'integer']
infunc = 0
funcline = ''
extern = 0
fint.write('module '+base+'\n')
fint.write('interface\n')
for line in lines:
toks = line.split()
if len(toks) > 0 and toks[0][:2] <> '//':
if toks[0] == 'extern':
extern = 1
if extern:
if not infunc:
if line.find('DLL_EXPORT') > 0:
infunc = 1
funcline = line
elif infunc:
funcline += line
last = toks[-1]
if infunc and last[-1] == '{':
infunc = 0
name, args = getargs(funcline)
toks = funcline.split()
a = writeinterface(fint, toks[0], name, args)
funcline = ''
fint.write('end interface\n')
fint.write('end module '+base+'\n')
fint.close()
fmod.write('module '+modname+'\n')
fmod.write(' use '+base+"""
type """+otype+"""
integer :: """+hndl+"""
end type """+otype+"""
contains
""")
for line in lines:
toks = line.split()
if len(toks) > 0 and toks[0][:2] <> '//':
if toks[0] == 'extern':
extern = 1
if extern:
if not infunc:
if line.find('DLL_EXPORT') > 0:
infunc = 1
funcline = line
elif infunc:
funcline += line
last = toks[-1]
if infunc and last[-1] == '{':
infunc = 0
name, args = getargs(funcline)
toks = funcline.split()
a = writef90(fmod, toks[0], otype, hndl, name, args)
funcline = ''
fmod.write('end module '+base+'\n')
fmod.close()