Mercurial > hg > vamp-build-and-test
diff DEPENDENCIES/mingw32/Python27/Lib/site-packages/numpy/f2py/crackfortran.py @ 87:2a2c65a20a8b
Add Python libs and headers
author | Chris Cannam |
---|---|
date | Wed, 25 Feb 2015 14:05:22 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DEPENDENCIES/mingw32/Python27/Lib/site-packages/numpy/f2py/crackfortran.py Wed Feb 25 14:05:22 2015 +0000 @@ -0,0 +1,2870 @@ +#!/usr/bin/env python +""" +crackfortran --- read fortran (77,90) code and extract declaration information. + +Copyright 1999-2004 Pearu Peterson all rights reserved, +Pearu Peterson <pearu@ioc.ee> +Permission to use, modify, and distribute this software is given under the +terms of the NumPy License. + +NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. +$Date: 2005/09/27 07:13:49 $ +Pearu Peterson + + +Usage of crackfortran: +====================== +Command line keys: -quiet,-verbose,-fix,-f77,-f90,-show,-h <pyffilename> + -m <module name for f77 routines>,--ignore-contains +Functions: crackfortran, crack2fortran +The following Fortran statements/constructions are supported +(or will be if needed): + block data,byte,call,character,common,complex,contains,data, + dimension,double complex,double precision,end,external,function, + implicit,integer,intent,interface,intrinsic, + logical,module,optional,parameter,private,public, + program,real,(sequence?),subroutine,type,use,virtual, + include,pythonmodule +Note: 'virtual' is mapped to 'dimension'. +Note: 'implicit integer (z) static (z)' is 'implicit static (z)' (this is minor bug). +Note: code after 'contains' will be ignored until its scope ends. +Note: 'common' statement is extended: dimensions are moved to variable definitions +Note: f2py directive: <commentchar>f2py<line> is read as <line> +Note: pythonmodule is introduced to represent Python module + +Usage: + `postlist=crackfortran(files,funcs)` + `postlist` contains declaration information read from the list of files `files`. + `crack2fortran(postlist)` returns a fortran code to be saved to pyf-file + + `postlist` has the following structure: + *** it is a list of dictionaries containing `blocks': + B = {'block','body','vars','parent_block'[,'name','prefix','args','result', + 'implicit','externals','interfaced','common','sortvars', + 'commonvars','note']} + B['block'] = 'interface' | 'function' | 'subroutine' | 'module' | + 'program' | 'block data' | 'type' | 'pythonmodule' + B['body'] --- list containing `subblocks' with the same structure as `blocks' + B['parent_block'] --- dictionary of a parent block: + C['body'][<index>]['parent_block'] is C + B['vars'] --- dictionary of variable definitions + B['sortvars'] --- dictionary of variable definitions sorted by dependence (independent first) + B['name'] --- name of the block (not if B['block']=='interface') + B['prefix'] --- prefix string (only if B['block']=='function') + B['args'] --- list of argument names if B['block']== 'function' | 'subroutine' + B['result'] --- name of the return value (only if B['block']=='function') + B['implicit'] --- dictionary {'a':<variable definition>,'b':...} | None + B['externals'] --- list of variables being external + B['interfaced'] --- list of variables being external and defined + B['common'] --- dictionary of common blocks (list of objects) + B['commonvars'] --- list of variables used in common blocks (dimensions are moved to variable definitions) + B['from'] --- string showing the 'parents' of the current block + B['use'] --- dictionary of modules used in current block: + {<modulename>:{['only':<0|1>],['map':{<local_name1>:<use_name1>,...}]}} + B['note'] --- list of LaTeX comments on the block + B['f2pyenhancements'] --- optional dictionary + {'threadsafe':'','fortranname':<name>, + 'callstatement':<C-expr>|<multi-line block>, + 'callprotoargument':<C-expr-list>, + 'usercode':<multi-line block>|<list of multi-line blocks>, + 'pymethoddef:<multi-line block>' + } + B['entry'] --- dictionary {entryname:argslist,..} + B['varnames'] --- list of variable names given in the order of reading the + Fortran code, useful for derived types. + B['saved_interface'] --- a string of scanned routine signature, defines explicit interface + *** Variable definition is a dictionary + D = B['vars'][<variable name>] = + {'typespec'[,'attrspec','kindselector','charselector','=','typename']} + D['typespec'] = 'byte' | 'character' | 'complex' | 'double complex' | + 'double precision' | 'integer' | 'logical' | 'real' | 'type' + D['attrspec'] --- list of attributes (e.g. 'dimension(<arrayspec>)', + 'external','intent(in|out|inout|hide|c|callback|cache|aligned4|aligned8|aligned16)', + 'optional','required', etc) + K = D['kindselector'] = {['*','kind']} (only if D['typespec'] = + 'complex' | 'integer' | 'logical' | 'real' ) + C = D['charselector'] = {['*','len','kind']} + (only if D['typespec']=='character') + D['='] --- initialization expression string + D['typename'] --- name of the type if D['typespec']=='type' + D['dimension'] --- list of dimension bounds + D['intent'] --- list of intent specifications + D['depend'] --- list of variable names on which current variable depends on + D['check'] --- list of C-expressions; if C-expr returns zero, exception is raised + D['note'] --- list of LaTeX comments on the variable + *** Meaning of kind/char selectors (few examples): + D['typespec>']*K['*'] + D['typespec'](kind=K['kind']) + character*C['*'] + character(len=C['len'],kind=C['kind']) + (see also fortran type declaration statement formats below) + +Fortran 90 type declaration statement format (F77 is subset of F90) +==================================================================== +(Main source: IBM XL Fortran 5.1 Language Reference Manual) +type declaration = <typespec> [[<attrspec>]::] <entitydecl> +<typespec> = byte | + character[<charselector>] | + complex[<kindselector>] | + double complex | + double precision | + integer[<kindselector>] | + logical[<kindselector>] | + real[<kindselector>] | + type(<typename>) +<charselector> = * <charlen> | + ([len=]<len>[,[kind=]<kind>]) | + (kind=<kind>[,len=<len>]) +<kindselector> = * <intlen> | + ([kind=]<kind>) +<attrspec> = comma separated list of attributes. + Only the following attributes are used in + building up the interface: + external + (parameter --- affects '=' key) + optional + intent + Other attributes are ignored. +<intentspec> = in | out | inout +<arrayspec> = comma separated list of dimension bounds. +<entitydecl> = <name> [[*<charlen>][(<arrayspec>)] | [(<arrayspec>)]*<charlen>] + [/<init_expr>/ | =<init_expr>] [,<entitydecl>] + +In addition, the following attributes are used: check,depend,note + +TODO: + * Apply 'parameter' attribute (e.g. 'integer parameter :: i=2' 'real x(i)' + -> 'real x(2)') + The above may be solved by creating appropriate preprocessor program, for example. + +""" +from __future__ import division, absolute_import, print_function + +import sys +import string +import fileinput +import re +import pprint +import os +import copy +import platform + +from . import __version__ +from .auxfuncs import * + +f2py_version = __version__.version + +# Global flags: +strictf77=1 # Ignore `!' comments unless line[0]=='!' +sourcecodeform='fix' # 'fix','free' +quiet=0 # Be verbose if 0 (Obsolete: not used any more) +verbose=1 # Be quiet if 0, extra verbose if > 1. +tabchar=4*' ' +pyffilename='' +f77modulename='' +skipemptyends=0 # for old F77 programs without 'program' statement +ignorecontains=1 +dolowercase=1 +debug=[] + +# Global variables +groupcounter=0 +grouplist={groupcounter:[]} +neededmodule=-1 +expectbegin=1 +skipblocksuntil=-1 +usermodules=[] +f90modulevars={} +gotnextfile=1 +filepositiontext='' +currentfilename='' +skipfunctions=[] +skipfuncs=[] +onlyfuncs=[] +include_paths=[] +previous_context = None + + +def reset_global_f2py_vars(): + global groupcounter, grouplist, neededmodule, expectbegin, \ + skipblocksuntil, usermodules, f90modulevars, gotnextfile, \ + filepositiontext, currentfilename, skipfunctions, skipfuncs, \ + onlyfuncs, include_paths, previous_context, \ + strictf77, sourcecodeform, quiet, verbose, tabchar, pyffilename, \ + f77modulename, skipemptyends, ignorecontains, dolowercase, debug + + # flags + strictf77 = 1 + sourcecodeform = 'fix' + quiet = 0 + verbose = 1 + tabchar = 4*' ' + pyffilename = '' + f77modulename = '' + skipemptyends = 0 + ignorecontains = 1 + dolowercase = 1 + debug = [] + # variables + groupcounter = 0 + grouplist = {groupcounter:[]} + neededmodule =-1 + expectbegin = 1 + skipblocksuntil = -1 + usermodules = [] + f90modulevars = {} + gotnextfile = 1 + filepositiontext = '' + currentfilename = '' + skipfunctions = [] + skipfuncs = [] + onlyfuncs = [] + include_paths = [] + previous_context = None + + +###### Some helper functions +def show(o,f=0):pprint.pprint(o) +errmess=sys.stderr.write +def outmess(line,flag=1): + global filepositiontext + if not verbose: return + if not quiet: + if flag:sys.stdout.write(filepositiontext) + sys.stdout.write(line) +re._MAXCACHE=50 +defaultimplicitrules={} +for c in "abcdefghopqrstuvwxyz$_": defaultimplicitrules[c]={'typespec':'real'} +for c in "ijklmn": defaultimplicitrules[c]={'typespec':'integer'} +del c +badnames={} +invbadnames={} +for n in ['int', 'double', 'float', 'char', 'short', 'long', 'void', 'case', 'while', + 'return', 'signed', 'unsigned', 'if', 'for', 'typedef', 'sizeof', 'union', + 'struct', 'static', 'register', 'new', 'break', 'do', 'goto', 'switch', + 'continue', 'else', 'inline', 'extern', 'delete', 'const', 'auto', + 'len', 'rank', 'shape', 'index', 'slen', 'size', '_i', + 'max', 'min', + 'flen', 'fshape', + 'string', 'complex_double', 'float_double', 'stdin', 'stderr', 'stdout', + 'type', 'default']: + badnames[n]=n+'_bn' + invbadnames[n+'_bn']=n + +def rmbadname1(name): + if name in badnames: + errmess('rmbadname1: Replacing "%s" with "%s".\n'%(name, badnames[name])) + return badnames[name] + return name + +def rmbadname(names): return [rmbadname1(_m) for _m in names] + +def undo_rmbadname1(name): + if name in invbadnames: + errmess('undo_rmbadname1: Replacing "%s" with "%s".\n'\ + %(name, invbadnames[name])) + return invbadnames[name] + return name + +def undo_rmbadname(names): return [undo_rmbadname1(_m) for _m in names] + +def getextension(name): + i=name.rfind('.') + if i==-1: return '' + if '\\' in name[i:]: return '' + if '/' in name[i:]: return '' + return name[i+1:] + +is_f_file = re.compile(r'.*[.](for|ftn|f77|f)\Z', re.I).match +_has_f_header = re.compile(r'-[*]-\s*fortran\s*-[*]-', re.I).search +_has_f90_header = re.compile(r'-[*]-\s*f90\s*-[*]-', re.I).search +_has_fix_header = re.compile(r'-[*]-\s*fix\s*-[*]-', re.I).search +_free_f90_start = re.compile(r'[^c*]\s*[^\s\d\t]', re.I).match +def is_free_format(file): + """Check if file is in free format Fortran.""" + # f90 allows both fixed and free format, assuming fixed unless + # signs of free format are detected. + result = 0 + f = open(file, 'r') + line = f.readline() + n = 15 # the number of non-comment lines to scan for hints + if _has_f_header(line): + n = 0 + elif _has_f90_header(line): + n = 0 + result = 1 + while n>0 and line: + if line[0]!='!' and line.strip(): + n -= 1 + if (line[0]!='\t' and _free_f90_start(line[:5])) or line[-2:-1]=='&': + result = 1 + break + line = f.readline() + f.close() + return result + + +####### Read fortran (77,90) code +def readfortrancode(ffile,dowithline=show,istop=1): + """ + Read fortran codes from files and + 1) Get rid of comments, line continuations, and empty lines; lower cases. + 2) Call dowithline(line) on every line. + 3) Recursively call itself when statement \"include '<filename>'\" is met. + """ + global gotnextfile, filepositiontext, currentfilename, sourcecodeform, strictf77,\ + beginpattern, quiet, verbose, dolowercase, include_paths + if not istop: + saveglobals=gotnextfile, filepositiontext, currentfilename, sourcecodeform, strictf77,\ + beginpattern, quiet, verbose, dolowercase + if ffile==[]: return + localdolowercase = dolowercase + cont=0 + finalline='' + ll='' + commentline=re.compile(r'(?P<line>([^"]*["][^"]*["][^"!]*|[^\']*\'[^\']*\'[^\'!]*|[^!\'"]*))!{1}(?P<rest>.*)') + includeline=re.compile(r'\s*include\s*(\'|")(?P<name>[^\'"]*)(\'|")', re.I) + cont1=re.compile(r'(?P<line>.*)&\s*\Z') + cont2=re.compile(r'(\s*&|)(?P<line>.*)') + mline_mark = re.compile(r".*?'''") + if istop: dowithline('', -1) + ll, l1='', '' + spacedigits=[' '] + [str(_m) for _m in range(10)] + filepositiontext='' + fin=fileinput.FileInput(ffile) + while True: + l=fin.readline() + if not l: break + if fin.isfirstline(): + filepositiontext='' + currentfilename=fin.filename() + gotnextfile=1 + l1=l + strictf77=0 + sourcecodeform='fix' + ext = os.path.splitext(currentfilename)[1] + if is_f_file(currentfilename) and \ + not (_has_f90_header(l) or _has_fix_header(l)): + strictf77=1 + elif is_free_format(currentfilename) and not _has_fix_header(l): + sourcecodeform='free' + if strictf77: beginpattern=beginpattern77 + else: beginpattern=beginpattern90 + outmess('\tReading file %s (format:%s%s)\n'\ + %(repr(currentfilename), sourcecodeform, + strictf77 and ',strict' or '')) + + l=l.expandtabs().replace('\xa0', ' ') + while not l=='': # Get rid of newline characters + if l[-1] not in "\n\r\f": break + l=l[:-1] + if not strictf77: + r=commentline.match(l) + if r: + l=r.group('line')+' ' # Strip comments starting with `!' + rl=r.group('rest') + if rl[:4].lower()=='f2py': # f2py directive + l = l + 4*' ' + r=commentline.match(rl[4:]) + if r: l=l+r.group('line') + else: l = l + rl[4:] + if l.strip()=='': # Skip empty line + cont=0 + continue + if sourcecodeform=='fix': + if l[0] in ['*', 'c', '!', 'C', '#']: + if l[1:5].lower()=='f2py': # f2py directive + l=' '+l[5:] + else: # Skip comment line + cont=0 + continue + elif strictf77: + if len(l)>72: l=l[:72] + if not (l[0] in spacedigits): + raise Exception('readfortrancode: Found non-(space,digit) char ' + 'in the first column.\n\tAre you sure that ' + 'this code is in fix form?\n\tline=%s' % repr(l)) + + if (not cont or strictf77) and (len(l)>5 and not l[5]==' '): + # Continuation of a previous line + ll=ll+l[6:] + finalline='' + origfinalline='' + else: + if not strictf77: + # F90 continuation + r=cont1.match(l) + if r: l=r.group('line') # Continuation follows .. + if cont: + ll=ll+cont2.match(l).group('line') + finalline='' + origfinalline='' + else: + l=' '+l[5:] # clean up line beginning from possible digits. + if localdolowercase: finalline=ll.lower() + else: finalline=ll + origfinalline=ll + ll=l + cont=(r is not None) + else: + l=' '+l[5:] # clean up line beginning from possible digits. + if localdolowercase: finalline=ll.lower() + else: finalline=ll + origfinalline =ll + ll=l + + elif sourcecodeform=='free': + if not cont and ext=='.pyf' and mline_mark.match(l): + l = l + '\n' + while True: + lc = fin.readline() + if not lc: + errmess('Unexpected end of file when reading multiline\n') + break + l = l + lc + if mline_mark.match(lc): + break + l = l.rstrip() + r=cont1.match(l) + if r: l=r.group('line') # Continuation follows .. + if cont: + ll=ll+cont2.match(l).group('line') + finalline='' + origfinalline='' + else: + if localdolowercase: finalline=ll.lower() + else: finalline=ll + origfinalline =ll + ll=l + cont=(r is not None) + else: + raise ValueError("Flag sourcecodeform must be either 'fix' or 'free': %s"%repr(sourcecodeform)) + filepositiontext='Line #%d in %s:"%s"\n\t' % (fin.filelineno()-1, currentfilename, l1) + m=includeline.match(origfinalline) + if m: + fn=m.group('name') + if os.path.isfile(fn): + readfortrancode(fn, dowithline=dowithline, istop=0) + else: + include_dirs = [os.path.dirname(currentfilename)] + include_paths + foundfile = 0 + for inc_dir in include_dirs: + fn1 = os.path.join(inc_dir, fn) + if os.path.isfile(fn1): + foundfile = 1 + readfortrancode(fn1, dowithline=dowithline, istop=0) + break + if not foundfile: + outmess('readfortrancode: could not find include file %s in %s. Ignoring.\n'%(repr(fn), os.pathsep.join(include_dirs))) + else: + dowithline(finalline) + l1=ll + if localdolowercase: + finalline=ll.lower() + else: finalline=ll + origfinalline = ll + filepositiontext='Line #%d in %s:"%s"\n\t' % (fin.filelineno()-1, currentfilename, l1) + m=includeline.match(origfinalline) + if m: + fn=m.group('name') + if os.path.isfile(fn): + readfortrancode(fn, dowithline=dowithline, istop=0) + else: + include_dirs = [os.path.dirname(currentfilename)] + include_paths + foundfile = 0 + for inc_dir in include_dirs: + fn1 = os.path.join(inc_dir, fn) + if os.path.isfile(fn1): + foundfile = 1 + readfortrancode(fn1, dowithline=dowithline, istop=0) + break + if not foundfile: + outmess('readfortrancode: could not find include file %s in %s. Ignoring.\n'%(repr(fn), os.pathsep.join(include_dirs))) + else: + dowithline(finalline) + filepositiontext='' + fin.close() + if istop: dowithline('', 1) + else: + gotnextfile, filepositiontext, currentfilename, sourcecodeform, strictf77,\ + beginpattern, quiet, verbose, dolowercase=saveglobals + +########### Crack line +beforethisafter=r'\s*(?P<before>%s(?=\s*(\b(%s)\b)))'+ \ + r'\s*(?P<this>(\b(%s)\b))'+ \ + r'\s*(?P<after>%s)\s*\Z' +## +fortrantypes='character|logical|integer|real|complex|double\s*(precision\s*(complex|)|complex)|type(?=\s*\([\w\s,=(*)]*\))|byte' +typespattern=re.compile(beforethisafter%('', fortrantypes, fortrantypes, '.*'), re.I), 'type' +typespattern4implicit=re.compile(beforethisafter%('', fortrantypes+'|static|automatic|undefined', fortrantypes+'|static|automatic|undefined', '.*'), re.I) +# +functionpattern=re.compile(beforethisafter%('([a-z]+[\w\s(=*+-/)]*?|)', 'function', 'function', '.*'), re.I), 'begin' +subroutinepattern=re.compile(beforethisafter%('[a-z\s]*?', 'subroutine', 'subroutine', '.*'), re.I), 'begin' +#modulepattern=re.compile(beforethisafter%('[a-z\s]*?','module','module','.*'),re.I),'begin' +# +groupbegins77=r'program|block\s*data' +beginpattern77=re.compile(beforethisafter%('', groupbegins77, groupbegins77, '.*'), re.I), 'begin' +groupbegins90=groupbegins77+r'|module(?!\s*procedure)|python\s*module|interface|type(?!\s*\()' +beginpattern90=re.compile(beforethisafter%('', groupbegins90, groupbegins90, '.*'), re.I), 'begin' +groupends=r'end|endprogram|endblockdata|endmodule|endpythonmodule|endinterface' +endpattern=re.compile(beforethisafter%('', groupends, groupends, '[\w\s]*'), re.I), 'end' +#endifs='end\s*(if|do|where|select|while|forall)' +endifs='(end\s*(if|do|where|select|while|forall))|(module\s*procedure)' +endifpattern=re.compile(beforethisafter%('[\w]*?', endifs, endifs, '[\w\s]*'), re.I), 'endif' +# +implicitpattern=re.compile(beforethisafter%('', 'implicit', 'implicit', '.*'), re.I), 'implicit' +dimensionpattern=re.compile(beforethisafter%('', 'dimension|virtual', 'dimension|virtual', '.*'), re.I), 'dimension' +externalpattern=re.compile(beforethisafter%('', 'external', 'external', '.*'), re.I), 'external' +optionalpattern=re.compile(beforethisafter%('', 'optional', 'optional', '.*'), re.I), 'optional' +requiredpattern=re.compile(beforethisafter%('', 'required', 'required', '.*'), re.I), 'required' +publicpattern=re.compile(beforethisafter%('', 'public', 'public', '.*'), re.I), 'public' +privatepattern=re.compile(beforethisafter%('', 'private', 'private', '.*'), re.I), 'private' +intrisicpattern=re.compile(beforethisafter%('', 'intrisic', 'intrisic', '.*'), re.I), 'intrisic' +intentpattern=re.compile(beforethisafter%('', 'intent|depend|note|check', 'intent|depend|note|check', '\s*\(.*?\).*'), re.I), 'intent' +parameterpattern=re.compile(beforethisafter%('', 'parameter', 'parameter', '\s*\(.*'), re.I), 'parameter' +datapattern=re.compile(beforethisafter%('', 'data', 'data', '.*'), re.I), 'data' +callpattern=re.compile(beforethisafter%('', 'call', 'call', '.*'), re.I), 'call' +entrypattern=re.compile(beforethisafter%('', 'entry', 'entry', '.*'), re.I), 'entry' +callfunpattern=re.compile(beforethisafter%('', 'callfun', 'callfun', '.*'), re.I), 'callfun' +commonpattern=re.compile(beforethisafter%('', 'common', 'common', '.*'), re.I), 'common' +usepattern=re.compile(beforethisafter%('', 'use', 'use', '.*'), re.I), 'use' +containspattern=re.compile(beforethisafter%('', 'contains', 'contains', ''), re.I), 'contains' +formatpattern=re.compile(beforethisafter%('', 'format', 'format', '.*'), re.I), 'format' +## Non-fortran and f2py-specific statements +f2pyenhancementspattern=re.compile(beforethisafter%('', 'threadsafe|fortranname|callstatement|callprotoargument|usercode|pymethoddef', 'threadsafe|fortranname|callstatement|callprotoargument|usercode|pymethoddef', '.*'), re.I|re.S), 'f2pyenhancements' +multilinepattern = re.compile(r"\s*(?P<before>''')(?P<this>.*?)(?P<after>''')\s*\Z", re.S), 'multiline' +## + +def _simplifyargs(argsline): + a = [] + for n in markoutercomma(argsline).split('@,@'): + for r in '(),': + n = n.replace(r, '_') + a.append(n) + return ','.join(a) + +crackline_re_1 = re.compile(r'\s*(?P<result>\b[a-z]+[\w]*\b)\s*[=].*', re.I) +def crackline(line,reset=0): + """ + reset=-1 --- initialize + reset=0 --- crack the line + reset=1 --- final check if mismatch of blocks occured + + Cracked data is saved in grouplist[0]. + """ + global beginpattern, groupcounter, groupname, groupcache, grouplist, gotnextfile,\ + filepositiontext, currentfilename, neededmodule, expectbegin, skipblocksuntil,\ + skipemptyends, previous_context + if ';' in line and not (f2pyenhancementspattern[0].match(line) or + multilinepattern[0].match(line)): + for l in line.split(';'): + assert reset==0, repr(reset) # XXX: non-zero reset values need testing + crackline(l, reset) + return + if reset<0: + groupcounter=0 + groupname={groupcounter:''} + groupcache={groupcounter:{}} + grouplist={groupcounter:[]} + groupcache[groupcounter]['body']=[] + groupcache[groupcounter]['vars']={} + groupcache[groupcounter]['block']='' + groupcache[groupcounter]['name']='' + neededmodule=-1 + skipblocksuntil=-1 + return + if reset>0: + fl=0 + if f77modulename and neededmodule==groupcounter: fl=2 + while groupcounter>fl: + outmess('crackline: groupcounter=%s groupname=%s\n'%(repr(groupcounter), repr(groupname))) + outmess('crackline: Mismatch of blocks encountered. Trying to fix it by assuming "end" statement.\n') + grouplist[groupcounter-1].append(groupcache[groupcounter]) + grouplist[groupcounter-1][-1]['body']=grouplist[groupcounter] + del grouplist[groupcounter] + groupcounter=groupcounter-1 + if f77modulename and neededmodule==groupcounter: + grouplist[groupcounter-1].append(groupcache[groupcounter]) + grouplist[groupcounter-1][-1]['body']=grouplist[groupcounter] + del grouplist[groupcounter] + groupcounter=groupcounter-1 # end interface + grouplist[groupcounter-1].append(groupcache[groupcounter]) + grouplist[groupcounter-1][-1]['body']=grouplist[groupcounter] + del grouplist[groupcounter] + groupcounter=groupcounter-1 # end module + neededmodule=-1 + return + if line=='': return + flag=0 + for pat in [dimensionpattern, externalpattern, intentpattern, optionalpattern, + requiredpattern, + parameterpattern, datapattern, publicpattern, privatepattern, + intrisicpattern, + endifpattern, endpattern, + formatpattern, + beginpattern, functionpattern, subroutinepattern, + implicitpattern, typespattern, commonpattern, + callpattern, usepattern, containspattern, + entrypattern, + f2pyenhancementspattern, + multilinepattern + ]: + m = pat[0].match(line) + if m: + break + flag=flag+1 + if not m: + re_1 = crackline_re_1 + if 0<=skipblocksuntil<=groupcounter:return + if 'externals' in groupcache[groupcounter]: + for name in groupcache[groupcounter]['externals']: + if name in invbadnames: + name=invbadnames[name] + if 'interfaced' in groupcache[groupcounter] and name in groupcache[groupcounter]['interfaced']: + continue + m1=re.match(r'(?P<before>[^"]*)\b%s\b\s*@\(@(?P<args>[^@]*)@\)@.*\Z'%name, markouterparen(line), re.I) + if m1: + m2 = re_1.match(m1.group('before')) + a = _simplifyargs(m1.group('args')) + if m2: + line='callfun %s(%s) result (%s)'%(name, a, m2.group('result')) + else: line='callfun %s(%s)'%(name, a) + m = callfunpattern[0].match(line) + if not m: + outmess('crackline: could not resolve function call for line=%s.\n'%repr(line)) + return + analyzeline(m, 'callfun', line) + return + if verbose>1 or (verbose==1 and currentfilename.lower().endswith('.pyf')): + previous_context = None + outmess('crackline:%d: No pattern for line\n'%(groupcounter)) + return + elif pat[1]=='end': + if 0<=skipblocksuntil<groupcounter: + groupcounter=groupcounter-1 + if skipblocksuntil<=groupcounter: return + if groupcounter<=0: + raise Exception('crackline: groupcounter(=%s) is nonpositive. ' + 'Check the blocks.' \ + % (groupcounter)) + m1 = beginpattern[0].match((line)) + if (m1) and (not m1.group('this')==groupname[groupcounter]): + raise Exception('crackline: End group %s does not match with ' + 'previous Begin group %s\n\t%s' % \ + (repr(m1.group('this')), repr(groupname[groupcounter]), + filepositiontext) + ) + if skipblocksuntil==groupcounter: + skipblocksuntil=-1 + grouplist[groupcounter-1].append(groupcache[groupcounter]) + grouplist[groupcounter-1][-1]['body']=grouplist[groupcounter] + del grouplist[groupcounter] + groupcounter=groupcounter-1 + if not skipemptyends: + expectbegin=1 + elif pat[1] == 'begin': + if 0<=skipblocksuntil<=groupcounter: + groupcounter=groupcounter+1 + return + gotnextfile=0 + analyzeline(m, pat[1], line) + expectbegin=0 + elif pat[1]=='endif': + pass + elif pat[1]=='contains': + if ignorecontains: return + if 0<=skipblocksuntil<=groupcounter: return + skipblocksuntil=groupcounter + else: + if 0<=skipblocksuntil<=groupcounter:return + analyzeline(m, pat[1], line) + +def markouterparen(line): + l='';f=0 + for c in line: + if c=='(': + f=f+1 + if f==1: l=l+'@(@'; continue + elif c==')': + f=f-1 + if f==0: l=l+'@)@'; continue + l=l+c + return l +def markoutercomma(line,comma=','): + l='';f=0 + cc='' + for c in line: + if (not cc or cc==')') and c=='(': + f=f+1 + cc = ')' + elif not cc and c=='\'' and (not l or l[-1]!='\\'): + f=f+1 + cc = '\'' + elif c==cc: + f=f-1 + if f==0: + cc='' + elif c==comma and f==0: + l=l+'@'+comma+'@' + continue + l=l+c + assert not f, repr((f, line, l, cc)) + return l +def unmarkouterparen(line): + r = line.replace('@(@', '(').replace('@)@', ')') + return r +def appenddecl(decl,decl2,force=1): + if not decl: decl={} + if not decl2: return decl + if decl is decl2: return decl + for k in list(decl2.keys()): + if k=='typespec': + if force or k not in decl: + decl[k]=decl2[k] + elif k=='attrspec': + for l in decl2[k]: + decl=setattrspec(decl, l, force) + elif k=='kindselector': + decl=setkindselector(decl, decl2[k], force) + elif k=='charselector': + decl=setcharselector(decl, decl2[k], force) + elif k in ['=', 'typename']: + if force or k not in decl: + decl[k]=decl2[k] + elif k=='note': + pass + elif k in ['intent', 'check', 'dimension', 'optional', 'required']: + errmess('appenddecl: "%s" not implemented.\n'%k) + else: + raise Exception('appenddecl: Unknown variable definition key:' + \ + str(k)) + return decl + +selectpattern=re.compile(r'\s*(?P<this>(@\(@.*?@\)@|[*][\d*]+|[*]\s*@\(@.*?@\)@|))(?P<after>.*)\Z', re.I) +nameargspattern=re.compile(r'\s*(?P<name>\b[\w$]+\b)\s*(@\(@\s*(?P<args>[\w\s,]*)\s*@\)@|)\s*((result(\s*@\(@\s*(?P<result>\b[\w$]+\b)\s*@\)@|))|(bind\s*@\(@\s*(?P<bind>.*)\s*@\)@))*\s*\Z', re.I) +callnameargspattern=re.compile(r'\s*(?P<name>\b[\w$]+\b)\s*@\(@\s*(?P<args>.*)\s*@\)@\s*\Z', re.I) +real16pattern = re.compile(r'([-+]?(?:\d+(?:\.\d*)?|\d*\.\d+))[dD]((?:[-+]?\d+)?)') +real8pattern = re.compile(r'([-+]?((?:\d+(?:\.\d*)?|\d*\.\d+))[eE]((?:[-+]?\d+)?)|(\d+\.\d*))') + +_intentcallbackpattern = re.compile(r'intent\s*\(.*?\bcallback\b', re.I) +def _is_intent_callback(vdecl): + for a in vdecl.get('attrspec', []): + if _intentcallbackpattern.match(a): + return 1 + return 0 + +def _resolvenameargspattern(line): + line = markouterparen(line) + m1=nameargspattern.match(line) + if m1: + return m1.group('name'), m1.group('args'), m1.group('result'), m1.group('bind') + m1=callnameargspattern.match(line) + if m1: + return m1.group('name'), m1.group('args'), None, None + return None, [], None, None + +def analyzeline(m, case, line): + global groupcounter, groupname, groupcache, grouplist, filepositiontext,\ + currentfilename, f77modulename, neededinterface, neededmodule, expectbegin,\ + gotnextfile, previous_context + block=m.group('this') + if case != 'multiline': + previous_context = None + if expectbegin and case not in ['begin', 'call', 'callfun', 'type'] \ + and not skipemptyends and groupcounter<1: + newname=os.path.basename(currentfilename).split('.')[0] + outmess('analyzeline: no group yet. Creating program group with name "%s".\n'%newname) + gotnextfile=0 + groupcounter=groupcounter+1 + groupname[groupcounter]='program' + groupcache[groupcounter]={} + grouplist[groupcounter]=[] + groupcache[groupcounter]['body']=[] + groupcache[groupcounter]['vars']={} + groupcache[groupcounter]['block']='program' + groupcache[groupcounter]['name']=newname + groupcache[groupcounter]['from']='fromsky' + expectbegin=0 + if case in ['begin', 'call', 'callfun']: + # Crack line => block,name,args,result + block = block.lower() + if re.match(r'block\s*data', block, re.I): block='block data' + if re.match(r'python\s*module', block, re.I): block='python module' + name, args, result, bind = _resolvenameargspattern(m.group('after')) + if name is None: + if block=='block data': + name = '_BLOCK_DATA_' + else: + name = '' + if block not in ['interface', 'block data']: + outmess('analyzeline: No name/args pattern found for line.\n') + + previous_context = (block, name, groupcounter) + if args: args=rmbadname([x.strip() for x in markoutercomma(args).split('@,@')]) + else: args=[] + if '' in args: + while '' in args: + args.remove('') + outmess('analyzeline: argument list is malformed (missing argument).\n') + + # end of crack line => block,name,args,result + needmodule=0 + needinterface=0 + + if case in ['call', 'callfun']: + needinterface=1 + if 'args' not in groupcache[groupcounter]: + return + if name not in groupcache[groupcounter]['args']: + return + for it in grouplist[groupcounter]: + if it['name']==name: + return + if name in groupcache[groupcounter]['interfaced']: + return + block={'call':'subroutine','callfun':'function'}[case] + if f77modulename and neededmodule==-1 and groupcounter<=1: + neededmodule=groupcounter+2 + needmodule=1 + if block != 'interface': + needinterface=1 + # Create new block(s) + groupcounter=groupcounter+1 + groupcache[groupcounter]={} + grouplist[groupcounter]=[] + if needmodule: + if verbose>1: + outmess('analyzeline: Creating module block %s\n'%repr(f77modulename), 0) + groupname[groupcounter]='module' + groupcache[groupcounter]['block']='python module' + groupcache[groupcounter]['name']=f77modulename + groupcache[groupcounter]['from']='' + groupcache[groupcounter]['body']=[] + groupcache[groupcounter]['externals']=[] + groupcache[groupcounter]['interfaced']=[] + groupcache[groupcounter]['vars']={} + groupcounter=groupcounter+1 + groupcache[groupcounter]={} + grouplist[groupcounter]=[] + if needinterface: + if verbose>1: + outmess('analyzeline: Creating additional interface block (groupcounter=%s).\n' % (groupcounter), 0) + groupname[groupcounter]='interface' + groupcache[groupcounter]['block']='interface' + groupcache[groupcounter]['name']='unknown_interface' + groupcache[groupcounter]['from']='%s:%s'%(groupcache[groupcounter-1]['from'], groupcache[groupcounter-1]['name']) + groupcache[groupcounter]['body']=[] + groupcache[groupcounter]['externals']=[] + groupcache[groupcounter]['interfaced']=[] + groupcache[groupcounter]['vars']={} + groupcounter=groupcounter+1 + groupcache[groupcounter]={} + grouplist[groupcounter]=[] + groupname[groupcounter]=block + groupcache[groupcounter]['block']=block + if not name: name='unknown_'+block + groupcache[groupcounter]['prefix']=m.group('before') + groupcache[groupcounter]['name']=rmbadname1(name) + groupcache[groupcounter]['result']=result + if groupcounter==1: + groupcache[groupcounter]['from']=currentfilename + else: + if f77modulename and groupcounter==3: + groupcache[groupcounter]['from']='%s:%s'%(groupcache[groupcounter-1]['from'], currentfilename) + else: + groupcache[groupcounter]['from']='%s:%s'%(groupcache[groupcounter-1]['from'], groupcache[groupcounter-1]['name']) + for k in list(groupcache[groupcounter].keys()): + if not groupcache[groupcounter][k]: + del groupcache[groupcounter][k] + + groupcache[groupcounter]['args']=args + groupcache[groupcounter]['body']=[] + groupcache[groupcounter]['externals']=[] + groupcache[groupcounter]['interfaced']=[] + groupcache[groupcounter]['vars']={} + groupcache[groupcounter]['entry']={} + # end of creation + if block=='type': + groupcache[groupcounter]['varnames'] = [] + + if case in ['call', 'callfun']: # set parents variables + if name not in groupcache[groupcounter-2]['externals']: + groupcache[groupcounter-2]['externals'].append(name) + groupcache[groupcounter]['vars']=copy.deepcopy(groupcache[groupcounter-2]['vars']) + #try: del groupcache[groupcounter]['vars'][groupcache[groupcounter-2]['name']] + #except: pass + try: del groupcache[groupcounter]['vars'][name][groupcache[groupcounter]['vars'][name]['attrspec'].index('external')] + except: pass + if block in ['function', 'subroutine']: # set global attributes + try: groupcache[groupcounter]['vars'][name]=appenddecl(groupcache[groupcounter]['vars'][name], groupcache[groupcounter-2]['vars']['']) + except: pass + if case=='callfun': # return type + if result and result in groupcache[groupcounter]['vars']: + if not name==result: + groupcache[groupcounter]['vars'][name]=appenddecl(groupcache[groupcounter]['vars'][name], groupcache[groupcounter]['vars'][result]) + #if groupcounter>1: # name is interfaced + try: groupcache[groupcounter-2]['interfaced'].append(name) + except: pass + if block=='function': + t=typespattern[0].match(m.group('before')+' '+name) + if t: + typespec, selector, attr, edecl=cracktypespec0(t.group('this'), t.group('after')) + updatevars(typespec, selector, attr, edecl) + + if case in ['call', 'callfun']: + grouplist[groupcounter-1].append(groupcache[groupcounter]) + grouplist[groupcounter-1][-1]['body']=grouplist[groupcounter] + del grouplist[groupcounter] + groupcounter=groupcounter-1 # end routine + grouplist[groupcounter-1].append(groupcache[groupcounter]) + grouplist[groupcounter-1][-1]['body']=grouplist[groupcounter] + del grouplist[groupcounter] + groupcounter=groupcounter-1 # end interface + + elif case=='entry': + name, args, result, bind=_resolvenameargspattern(m.group('after')) + if name is not None: + if args: + args=rmbadname([x.strip() for x in markoutercomma(args).split('@,@')]) + else: args=[] + assert result is None, repr(result) + groupcache[groupcounter]['entry'][name] = args + previous_context = ('entry', name, groupcounter) + elif case=='type': + typespec, selector, attr, edecl=cracktypespec0(block, m.group('after')) + last_name = updatevars(typespec, selector, attr, edecl) + if last_name is not None: + previous_context = ('variable', last_name, groupcounter) + elif case in ['dimension', 'intent', 'optional', 'required', 'external', 'public', 'private', 'intrisic']: + edecl=groupcache[groupcounter]['vars'] + ll=m.group('after').strip() + i=ll.find('::') + if i<0 and case=='intent': + i=markouterparen(ll).find('@)@')-2 + ll=ll[:i+1]+'::'+ll[i+1:] + i=ll.find('::') + if ll[i:]=='::' and 'args' in groupcache[groupcounter]: + outmess('All arguments will have attribute %s%s\n'%(m.group('this'), ll[:i])) + ll = ll + ','.join(groupcache[groupcounter]['args']) + if i<0:i=0;pl='' + else: pl=ll[:i].strip();ll=ll[i+2:] + ch = markoutercomma(pl).split('@,@') + if len(ch)>1: + pl = ch[0] + outmess('analyzeline: cannot handle multiple attributes without type specification. Ignoring %r.\n' % (','.join(ch[1:]))) + last_name = None + + for e in [x.strip() for x in markoutercomma(ll).split('@,@')]: + m1=namepattern.match(e) + if not m1: + if case in ['public', 'private']: k='' + else: + print(m.groupdict()) + outmess('analyzeline: no name pattern found in %s statement for %s. Skipping.\n'%(case, repr(e))) + continue + else: + k=rmbadname1(m1.group('name')) + if k not in edecl: + edecl[k]={} + if case=='dimension': + ap=case+m1.group('after') + if case=='intent': + ap=m.group('this')+pl + if _intentcallbackpattern.match(ap): + if k not in groupcache[groupcounter]['args']: + if groupcounter>1: + if '__user__' not in groupcache[groupcounter-2]['name']: + outmess('analyzeline: missing __user__ module (could be nothing)\n') + if k!=groupcache[groupcounter]['name']: # fixes ticket 1693 + outmess('analyzeline: appending intent(callback) %s'\ + ' to %s arguments\n' % (k, groupcache[groupcounter]['name'])) + groupcache[groupcounter]['args'].append(k) + else: + errmess('analyzeline: intent(callback) %s is ignored' % (k)) + else: + errmess('analyzeline: intent(callback) %s is already'\ + ' in argument list' % (k)) + if case in ['optional', 'required', 'public', 'external', 'private', 'intrisic']: + ap=case + if 'attrspec' in edecl[k]: + edecl[k]['attrspec'].append(ap) + else: + edecl[k]['attrspec']=[ap] + if case=='external': + if groupcache[groupcounter]['block']=='program': + outmess('analyzeline: ignoring program arguments\n') + continue + if k not in groupcache[groupcounter]['args']: + #outmess('analyzeline: ignoring external %s (not in arguments list)\n'%(`k`)) + continue + if 'externals' not in groupcache[groupcounter]: + groupcache[groupcounter]['externals']=[] + groupcache[groupcounter]['externals'].append(k) + last_name = k + groupcache[groupcounter]['vars']=edecl + if last_name is not None: + previous_context = ('variable', last_name, groupcounter) + elif case=='parameter': + edecl=groupcache[groupcounter]['vars'] + ll=m.group('after').strip()[1:-1] + last_name = None + for e in markoutercomma(ll).split('@,@'): + try: + k, initexpr=[x.strip() for x in e.split('=')] + except: + outmess('analyzeline: could not extract name,expr in parameter statement "%s" of "%s"\n'%(e, ll));continue + params = get_parameters(edecl) + k=rmbadname1(k) + if k not in edecl: + edecl[k]={} + if '=' in edecl[k] and (not edecl[k]['=']==initexpr): + outmess('analyzeline: Overwriting the value of parameter "%s" ("%s") with "%s".\n'%(k, edecl[k]['='], initexpr)) + t = determineexprtype(initexpr, params) + if t: + if t.get('typespec')=='real': + tt = list(initexpr) + for m in real16pattern.finditer(initexpr): + tt[m.start():m.end()] = list(\ + initexpr[m.start():m.end()].lower().replace('d', 'e')) + initexpr = ''.join(tt) + elif t.get('typespec')=='complex': + initexpr = initexpr[1:].lower().replace('d', 'e').\ + replace(',', '+1j*(') + try: + v = eval(initexpr, {}, params) + except (SyntaxError, NameError, TypeError) as msg: + errmess('analyzeline: Failed to evaluate %r. Ignoring: %s\n'\ + % (initexpr, msg)) + continue + edecl[k]['='] = repr(v) + if 'attrspec' in edecl[k]: + edecl[k]['attrspec'].append('parameter') + else: edecl[k]['attrspec']=['parameter'] + last_name = k + groupcache[groupcounter]['vars']=edecl + if last_name is not None: + previous_context = ('variable', last_name, groupcounter) + elif case=='implicit': + if m.group('after').strip().lower()=='none': + groupcache[groupcounter]['implicit']=None + elif m.group('after'): + if 'implicit' in groupcache[groupcounter]: + impl=groupcache[groupcounter]['implicit'] + else: impl={} + if impl is None: + outmess('analyzeline: Overwriting earlier "implicit none" statement.\n') + impl={} + for e in markoutercomma(m.group('after')).split('@,@'): + decl={} + m1=re.match(r'\s*(?P<this>.*?)\s*(\(\s*(?P<after>[a-z-, ]+)\s*\)\s*|)\Z', e, re.I) + if not m1: + outmess('analyzeline: could not extract info of implicit statement part "%s"\n'%(e));continue + m2=typespattern4implicit.match(m1.group('this')) + if not m2: + outmess('analyzeline: could not extract types pattern of implicit statement part "%s"\n'%(e));continue + typespec, selector, attr, edecl=cracktypespec0(m2.group('this'), m2.group('after')) + kindselect, charselect, typename=cracktypespec(typespec, selector) + decl['typespec']=typespec + decl['kindselector']=kindselect + decl['charselector']=charselect + decl['typename']=typename + for k in list(decl.keys()): + if not decl[k]: del decl[k] + for r in markoutercomma(m1.group('after')).split('@,@'): + if '-' in r: + try: begc, endc=[x.strip() for x in r.split('-')] + except: + outmess('analyzeline: expected "<char>-<char>" instead of "%s" in range list of implicit statement\n'%r);continue + else: begc=endc=r.strip() + if not len(begc)==len(endc)==1: + outmess('analyzeline: expected "<char>-<char>" instead of "%s" in range list of implicit statement (2)\n'%r);continue + for o in range(ord(begc), ord(endc)+1): + impl[chr(o)]=decl + groupcache[groupcounter]['implicit']=impl + elif case=='data': + ll=[] + dl='';il='';f=0;fc=1;inp=0 + for c in m.group('after'): + if not inp: + if c=="'": fc=not fc + if c=='/' and fc: f=f+1;continue + if c=='(': inp = inp + 1 + elif c==')': inp = inp - 1 + if f==0: dl=dl+c + elif f==1: il=il+c + elif f==2: + dl = dl.strip() + if dl.startswith(','): + dl = dl[1:].strip() + ll.append([dl, il]) + dl=c;il='';f=0 + if f==2: + dl = dl.strip() + if dl.startswith(','): + dl = dl[1:].strip() + ll.append([dl, il]) + vars={} + if 'vars' in groupcache[groupcounter]: + vars=groupcache[groupcounter]['vars'] + last_name = None + for l in ll: + l=[x.strip() for x in l] + if l[0][0]==',':l[0]=l[0][1:] + if l[0][0]=='(': + outmess('analyzeline: implied-DO list "%s" is not supported. Skipping.\n'%l[0]) + continue + #if '(' in l[0]: + # #outmess('analyzeline: ignoring this data statement.\n') + # continue + i=0;j=0;llen=len(l[1]) + for v in rmbadname([x.strip() for x in markoutercomma(l[0]).split('@,@')]): + if v[0]=='(': + outmess('analyzeline: implied-DO list "%s" is not supported. Skipping.\n'%v) + # XXX: subsequent init expressions may get wrong values. + # Ignoring since data statements are irrelevant for wrapping. + continue + fc=0 + while (i<llen) and (fc or not l[1][i]==','): + if l[1][i]=="'": fc=not fc + i=i+1 + i=i+1 + #v,l[1][j:i-1]=name,initvalue + if v not in vars: + vars[v]={} + if '=' in vars[v] and not vars[v]['=']==l[1][j:i-1]: + outmess('analyzeline: changing init expression of "%s" ("%s") to "%s"\n'%(v, vars[v]['='], l[1][j:i-1])) + vars[v]['=']=l[1][j:i-1] + j=i + last_name = v + groupcache[groupcounter]['vars']=vars + if last_name is not None: + previous_context = ('variable', last_name, groupcounter) + elif case=='common': + line=m.group('after').strip() + if not line[0]=='/':line='//'+line + cl=[] + f=0;bn='';ol='' + for c in line: + if c=='/':f=f+1;continue + if f>=3: + bn = bn.strip() + if not bn: bn='_BLNK_' + cl.append([bn, ol]) + f=f-2;bn='';ol='' + if f%2: bn=bn+c + else: ol=ol+c + bn = bn.strip() + if not bn: bn='_BLNK_' + cl.append([bn, ol]) + commonkey={} + if 'common' in groupcache[groupcounter]: + commonkey=groupcache[groupcounter]['common'] + for c in cl: + if c[0] in commonkey: + outmess('analyzeline: previously defined common block encountered. Skipping.\n') + continue + commonkey[c[0]]=[] + for i in [x.strip() for x in markoutercomma(c[1]).split('@,@')]: + if i: commonkey[c[0]].append(i) + groupcache[groupcounter]['common']=commonkey + previous_context = ('common', bn, groupcounter) + elif case=='use': + m1=re.match(r'\A\s*(?P<name>\b[\w]+\b)\s*((,(\s*\bonly\b\s*:|(?P<notonly>))\s*(?P<list>.*))|)\s*\Z', m.group('after'), re.I) + if m1: + mm=m1.groupdict() + if 'use' not in groupcache[groupcounter]: + groupcache[groupcounter]['use']={} + name=m1.group('name') + groupcache[groupcounter]['use'][name]={} + isonly=0 + if 'list' in mm and mm['list'] is not None: + if 'notonly' in mm and mm['notonly'] is None: + isonly=1 + groupcache[groupcounter]['use'][name]['only']=isonly + ll=[x.strip() for x in mm['list'].split(',')] + rl={} + for l in ll: + if '=' in l: + m2=re.match(r'\A\s*(?P<local>\b[\w]+\b)\s*=\s*>\s*(?P<use>\b[\w]+\b)\s*\Z', l, re.I) + if m2: rl[m2.group('local').strip()]=m2.group('use').strip() + else: + outmess('analyzeline: Not local=>use pattern found in %s\n'%repr(l)) + else: + rl[l]=l + groupcache[groupcounter]['use'][name]['map']=rl + else: + pass + else: + print(m.groupdict()) + outmess('analyzeline: Could not crack the use statement.\n') + elif case in ['f2pyenhancements']: + if 'f2pyenhancements' not in groupcache[groupcounter]: + groupcache[groupcounter]['f2pyenhancements'] = {} + d = groupcache[groupcounter]['f2pyenhancements'] + if m.group('this')=='usercode' and 'usercode' in d: + if isinstance(d['usercode'], str): + d['usercode'] = [d['usercode']] + d['usercode'].append(m.group('after')) + else: + d[m.group('this')] = m.group('after') + elif case=='multiline': + if previous_context is None: + if verbose: + outmess('analyzeline: No context for multiline block.\n') + return + gc = groupcounter + #gc = previous_context[2] + appendmultiline(groupcache[gc], + previous_context[:2], + m.group('this')) + else: + if verbose>1: + print(m.groupdict()) + outmess('analyzeline: No code implemented for line.\n') + +def appendmultiline(group, context_name, ml): + if 'f2pymultilines' not in group: + group['f2pymultilines'] = {} + d = group['f2pymultilines'] + if context_name not in d: + d[context_name] = [] + d[context_name].append(ml) + return + +def cracktypespec0(typespec, ll): + selector=None + attr=None + if re.match(r'double\s*complex', typespec, re.I): typespec='double complex' + elif re.match(r'double\s*precision', typespec, re.I): typespec='double precision' + else: typespec=typespec.strip().lower() + m1=selectpattern.match(markouterparen(ll)) + if not m1: + outmess('cracktypespec0: no kind/char_selector pattern found for line.\n') + return + d=m1.groupdict() + for k in list(d.keys()): d[k]=unmarkouterparen(d[k]) + if typespec in ['complex', 'integer', 'logical', 'real', 'character', 'type']: + selector=d['this'] + ll=d['after'] + i=ll.find('::') + if i>=0: + attr=ll[:i].strip() + ll=ll[i+2:] + return typespec, selector, attr, ll +##### +namepattern=re.compile(r'\s*(?P<name>\b[\w]+\b)\s*(?P<after>.*)\s*\Z', re.I) +kindselector=re.compile(r'\s*(\(\s*(kind\s*=)?\s*(?P<kind>.*)\s*\)|[*]\s*(?P<kind2>.*?))\s*\Z', re.I) +charselector=re.compile(r'\s*(\((?P<lenkind>.*)\)|[*]\s*(?P<charlen>.*))\s*\Z', re.I) +lenkindpattern=re.compile(r'\s*(kind\s*=\s*(?P<kind>.*?)\s*(@,@\s*len\s*=\s*(?P<len>.*)|)|(len\s*=\s*|)(?P<len2>.*?)\s*(@,@\s*(kind\s*=\s*|)(?P<kind2>.*)|))\s*\Z', re.I) +lenarraypattern=re.compile(r'\s*(@\(@\s*(?!/)\s*(?P<array>.*?)\s*@\)@\s*[*]\s*(?P<len>.*?)|([*]\s*(?P<len2>.*?)|)\s*(@\(@\s*(?!/)\s*(?P<array2>.*?)\s*@\)@|))\s*(=\s*(?P<init>.*?)|(@\(@|)/\s*(?P<init2>.*?)\s*/(@\)@|)|)\s*\Z', re.I) +def removespaces(expr): + expr=expr.strip() + if len(expr)<=1: return expr + expr2=expr[0] + for i in range(1, len(expr)-1): + if expr[i]==' ' and \ + ((expr[i+1] in "()[]{}=+-/* ") or (expr[i-1] in "()[]{}=+-/* ")): continue + expr2=expr2+expr[i] + expr2=expr2+expr[-1] + return expr2 +def markinnerspaces(line): + l='';f=0 + cc='\'' + cc1='"' + cb='' + for c in line: + if cb=='\\' and c in ['\\', '\'', '"']: + l=l+c + cb=c + continue + if f==0 and c in ['\'', '"']: cc=c; cc1={'\'':'"','"':'\''}[c] + if c==cc:f=f+1 + elif c==cc:f=f-1 + elif c==' ' and f==1: l=l+'@_@'; continue + l=l+c;cb=c + return l +def updatevars(typespec, selector, attrspec, entitydecl): + global groupcache, groupcounter + last_name = None + kindselect, charselect, typename=cracktypespec(typespec, selector) + if attrspec: + attrspec=[x.strip() for x in markoutercomma(attrspec).split('@,@')] + l = [] + c = re.compile(r'(?P<start>[a-zA-Z]+)') + for a in attrspec: + if not a: + continue + m = c.match(a) + if m: + s = m.group('start').lower() + a = s + a[len(s):] + l.append(a) + attrspec = l + el=[x.strip() for x in markoutercomma(entitydecl).split('@,@')] + el1=[] + for e in el: + for e1 in [x.strip() for x in markoutercomma(removespaces(markinnerspaces(e)), comma=' ').split('@ @')]: + if e1: el1.append(e1.replace('@_@', ' ')) + for e in el1: + m=namepattern.match(e) + if not m: + outmess('updatevars: no name pattern found for entity=%s. Skipping.\n'%(repr(e))) + continue + ename=rmbadname1(m.group('name')) + edecl={} + if ename in groupcache[groupcounter]['vars']: + edecl=groupcache[groupcounter]['vars'][ename].copy() + not_has_typespec = 'typespec' not in edecl + if not_has_typespec: + edecl['typespec']=typespec + elif typespec and (not typespec==edecl['typespec']): + outmess('updatevars: attempt to change the type of "%s" ("%s") to "%s". Ignoring.\n' % (ename, edecl['typespec'], typespec)) + if 'kindselector' not in edecl: + edecl['kindselector']=copy.copy(kindselect) + elif kindselect: + for k in list(kindselect.keys()): + if k in edecl['kindselector'] and (not kindselect[k]==edecl['kindselector'][k]): + outmess('updatevars: attempt to change the kindselector "%s" of "%s" ("%s") to "%s". Ignoring.\n' % (k, ename, edecl['kindselector'][k], kindselect[k])) + else: edecl['kindselector'][k]=copy.copy(kindselect[k]) + if 'charselector' not in edecl and charselect: + if not_has_typespec: + edecl['charselector']=charselect + else: + errmess('updatevars:%s: attempt to change empty charselector to %r. Ignoring.\n' \ + %(ename, charselect)) + elif charselect: + for k in list(charselect.keys()): + if k in edecl['charselector'] and (not charselect[k]==edecl['charselector'][k]): + outmess('updatevars: attempt to change the charselector "%s" of "%s" ("%s") to "%s". Ignoring.\n' % (k, ename, edecl['charselector'][k], charselect[k])) + else: edecl['charselector'][k]=copy.copy(charselect[k]) + if 'typename' not in edecl: + edecl['typename']=typename + elif typename and (not edecl['typename']==typename): + outmess('updatevars: attempt to change the typename of "%s" ("%s") to "%s". Ignoring.\n' % (ename, edecl['typename'], typename)) + if 'attrspec' not in edecl: + edecl['attrspec']=copy.copy(attrspec) + elif attrspec: + for a in attrspec: + if a not in edecl['attrspec']: + edecl['attrspec'].append(a) + else: + edecl['typespec']=copy.copy(typespec) + edecl['kindselector']=copy.copy(kindselect) + edecl['charselector']=copy.copy(charselect) + edecl['typename']=typename + edecl['attrspec']=copy.copy(attrspec) + if m.group('after'): + m1=lenarraypattern.match(markouterparen(m.group('after'))) + if m1: + d1=m1.groupdict() + for lk in ['len', 'array', 'init']: + if d1[lk+'2'] is not None: d1[lk]=d1[lk+'2']; del d1[lk+'2'] + for k in list(d1.keys()): + if d1[k] is not None: d1[k]=unmarkouterparen(d1[k]) + else: del d1[k] + if 'len' in d1 and 'array' in d1: + if d1['len']=='': + d1['len']=d1['array'] + del d1['array'] + else: + d1['array']=d1['array']+','+d1['len'] + del d1['len'] + errmess('updatevars: "%s %s" is mapped to "%s %s(%s)"\n'%(typespec, e, typespec, ename, d1['array'])) + if 'array' in d1: + dm = 'dimension(%s)'%d1['array'] + if 'attrspec' not in edecl or (not edecl['attrspec']): + edecl['attrspec']=[dm] + else: + edecl['attrspec'].append(dm) + for dm1 in edecl['attrspec']: + if dm1[:9]=='dimension' and dm1!=dm: + del edecl['attrspec'][-1] + errmess('updatevars:%s: attempt to change %r to %r. Ignoring.\n' \ + % (ename, dm1, dm)) + break + + if 'len' in d1: + if typespec in ['complex', 'integer', 'logical', 'real']: + if ('kindselector' not in edecl) or (not edecl['kindselector']): + edecl['kindselector']={} + edecl['kindselector']['*']=d1['len'] + elif typespec == 'character': + if ('charselector' not in edecl) or (not edecl['charselector']): + edecl['charselector']={} + if 'len' in edecl['charselector']: + del edecl['charselector']['len'] + edecl['charselector']['*']=d1['len'] + if 'init' in d1: + if '=' in edecl and (not edecl['=']==d1['init']): + outmess('updatevars: attempt to change the init expression of "%s" ("%s") to "%s". Ignoring.\n' % (ename, edecl['='], d1['init'])) + else: + edecl['=']=d1['init'] + else: + outmess('updatevars: could not crack entity declaration "%s". Ignoring.\n'%(ename+m.group('after'))) + for k in list(edecl.keys()): + if not edecl[k]: + del edecl[k] + groupcache[groupcounter]['vars'][ename]=edecl + if 'varnames' in groupcache[groupcounter]: + groupcache[groupcounter]['varnames'].append(ename) + last_name = ename + return last_name + +def cracktypespec(typespec, selector): + kindselect=None + charselect=None + typename=None + if selector: + if typespec in ['complex', 'integer', 'logical', 'real']: + kindselect=kindselector.match(selector) + if not kindselect: + outmess('cracktypespec: no kindselector pattern found for %s\n'%(repr(selector))) + return + kindselect=kindselect.groupdict() + kindselect['*']=kindselect['kind2'] + del kindselect['kind2'] + for k in list(kindselect.keys()): + if not kindselect[k]: del kindselect[k] + for k, i in list(kindselect.items()): + kindselect[k] = rmbadname1(i) + elif typespec=='character': + charselect=charselector.match(selector) + if not charselect: + outmess('cracktypespec: no charselector pattern found for %s\n'%(repr(selector))) + return + charselect=charselect.groupdict() + charselect['*']=charselect['charlen'] + del charselect['charlen'] + if charselect['lenkind']: + lenkind=lenkindpattern.match(markoutercomma(charselect['lenkind'])) + lenkind=lenkind.groupdict() + for lk in ['len', 'kind']: + if lenkind[lk+'2']: + lenkind[lk]=lenkind[lk+'2'] + charselect[lk]=lenkind[lk] + del lenkind[lk+'2'] + del charselect['lenkind'] + for k in list(charselect.keys()): + if not charselect[k]: del charselect[k] + for k, i in list(charselect.items()): + charselect[k] = rmbadname1(i) + elif typespec=='type': + typename=re.match(r'\s*\(\s*(?P<name>\w+)\s*\)', selector, re.I) + if typename: typename=typename.group('name') + else: outmess('cracktypespec: no typename found in %s\n'%(repr(typespec+selector))) + else: + outmess('cracktypespec: no selector used for %s\n'%(repr(selector))) + return kindselect, charselect, typename +###### +def setattrspec(decl,attr,force=0): + if not decl: + decl={} + if not attr: + return decl + if 'attrspec' not in decl: + decl['attrspec']=[attr] + return decl + if force: decl['attrspec'].append(attr) + if attr in decl['attrspec']: return decl + if attr=='static' and 'automatic' not in decl['attrspec']: + decl['attrspec'].append(attr) + elif attr=='automatic' and 'static' not in decl['attrspec']: + decl['attrspec'].append(attr) + elif attr=='public' and 'private' not in decl['attrspec']: + decl['attrspec'].append(attr) + elif attr=='private' and 'public' not in decl['attrspec']: + decl['attrspec'].append(attr) + else: + decl['attrspec'].append(attr) + return decl + +def setkindselector(decl,sel,force=0): + if not decl: + decl={} + if not sel: + return decl + if 'kindselector' not in decl: + decl['kindselector']=sel + return decl + for k in list(sel.keys()): + if force or k not in decl['kindselector']: + decl['kindselector'][k]=sel[k] + return decl + +def setcharselector(decl,sel,force=0): + if not decl: + decl={} + if not sel: + return decl + if 'charselector' not in decl: + decl['charselector']=sel + return decl + for k in list(sel.keys()): + if force or k not in decl['charselector']: + decl['charselector'][k]=sel[k] + return decl + +def getblockname(block,unknown='unknown'): + if 'name' in block: + return block['name'] + return unknown + +###### post processing + +def setmesstext(block): + global filepositiontext + try: + filepositiontext='In: %s:%s\n'%(block['from'], block['name']) + except: + pass + +def get_usedict(block): + usedict = {} + if 'parent_block' in block: + usedict = get_usedict(block['parent_block']) + if 'use' in block: + usedict.update(block['use']) + return usedict + +def get_useparameters(block, param_map=None): + global f90modulevars + if param_map is None: + param_map = {} + usedict = get_usedict(block) + if not usedict: + return param_map + for usename, mapping in list(usedict.items()): + usename = usename.lower() + if usename not in f90modulevars: + outmess('get_useparameters: no module %s info used by %s\n' % (usename, block.get('name'))) + continue + mvars = f90modulevars[usename] + params = get_parameters(mvars) + if not params: + continue + # XXX: apply mapping + if mapping: + errmess('get_useparameters: mapping for %s not impl.' % (mapping)) + for k, v in list(params.items()): + if k in param_map: + outmess('get_useparameters: overriding parameter %s with'\ + ' value from module %s' % (repr(k), repr(usename))) + param_map[k] = v + + return param_map + +def postcrack2(block,tab='',param_map=None): + global f90modulevars + if not f90modulevars: + return block + if isinstance(block, list): + ret = [] + for g in block: + g = postcrack2(g, tab=tab+'\t', param_map=param_map) + ret.append(g) + return ret + setmesstext(block) + outmess('%sBlock: %s\n'%(tab, block['name']), 0) + + if param_map is None: + param_map = get_useparameters(block) + + if param_map is not None and 'vars' in block: + vars = block['vars'] + for n in list(vars.keys()): + var = vars[n] + if 'kindselector' in var: + kind = var['kindselector'] + if 'kind' in kind: + val = kind['kind'] + if val in param_map: + kind['kind'] = param_map[val] + new_body = [] + for b in block['body']: + b = postcrack2(b, tab=tab+'\t', param_map=param_map) + new_body.append(b) + block['body'] = new_body + + return block + +def postcrack(block,args=None,tab=''): + """ + TODO: + function return values + determine expression types if in argument list + """ + global usermodules, onlyfunctions + if isinstance(block, list): + gret=[] + uret=[] + for g in block: + setmesstext(g) + g=postcrack(g, tab=tab+'\t') + if 'name' in g and '__user__' in g['name']: # sort user routines to appear first + uret.append(g) + else: + gret.append(g) + return uret+gret + setmesstext(block) + if not isinstance(block, dict) and 'block' not in block: + raise Exception('postcrack: Expected block dictionary instead of ' + \ + str(block)) + if 'name' in block and not block['name']=='unknown_interface': + outmess('%sBlock: %s\n'%(tab, block['name']), 0) + blocktype=block['block'] + block=analyzeargs(block) + block=analyzecommon(block) + block['vars']=analyzevars(block) + block['sortvars']=sortvarnames(block['vars']) + if 'args' in block and block['args']: + args=block['args'] + block['body']=analyzebody(block, args, tab=tab) + + userisdefined=[] +## fromuser = [] + if 'use' in block: + useblock=block['use'] + for k in list(useblock.keys()): + if '__user__' in k: + userisdefined.append(k) +## if 'map' in useblock[k]: +## for n in useblock[k]['map'].itervalues(): +## if n not in fromuser: fromuser.append(n) + else: useblock={} + name='' + if 'name' in block: + name=block['name'] + if 'externals' in block and block['externals']:# and not userisdefined: # Build a __user__ module + interfaced=[] + if 'interfaced' in block: + interfaced=block['interfaced'] + mvars=copy.copy(block['vars']) + if name: + mname=name+'__user__routines' + else: + mname='unknown__user__routines' + if mname in userisdefined: + i=1 + while '%s_%i'%(mname, i) in userisdefined: i=i+1 + mname='%s_%i'%(mname, i) + interface={'block':'interface','body':[],'vars':{},'name':name+'_user_interface'} + for e in block['externals']: +## if e in fromuser: +## outmess(' Skipping %s that is defined explicitly in another use statement\n'%(`e`)) +## continue + if e in interfaced: + edef=[] + j=-1 + for b in block['body']: + j=j+1 + if b['block']=='interface': + i=-1 + for bb in b['body']: + i=i+1 + if 'name' in bb and bb['name']==e: + edef=copy.copy(bb) + del b['body'][i] + break + if edef: + if not b['body']: del block['body'][j] + del interfaced[interfaced.index(e)] + break + interface['body'].append(edef) + else: + if e in mvars and not isexternal(mvars[e]): + interface['vars'][e]=mvars[e] + if interface['vars'] or interface['body']: + block['interfaced']=interfaced + mblock={'block':'python module','body':[interface],'vars':{},'name':mname,'interfaced':block['externals']} + useblock[mname]={} + usermodules.append(mblock) + if useblock: + block['use']=useblock + return block + +def sortvarnames(vars): + indep = [] + dep = [] + for v in list(vars.keys()): + if 'depend' in vars[v] and vars[v]['depend']: + dep.append(v) + #print '%s depends on %s'%(v,vars[v]['depend']) + else: indep.append(v) + n = len(dep) + i = 0 + while dep: #XXX: How to catch dependence cycles correctly? + v = dep[0] + fl = 0 + for w in dep[1:]: + if w in vars[v]['depend']: + fl = 1 + break + if fl: + dep = dep[1:]+[v] + i = i + 1 + if i>n: + errmess('sortvarnames: failed to compute dependencies because' + ' of cyclic dependencies between ' + +', '.join(dep)+'\n') + indep = indep + dep + break + else: + indep.append(v) + dep = dep[1:] + n = len(dep) + i = 0 + #print indep + return indep + +def analyzecommon(block): + if not hascommon(block): return block + commonvars=[] + for k in list(block['common'].keys()): + comvars=[] + for e in block['common'][k]: + m=re.match(r'\A\s*\b(?P<name>.*?)\b\s*(\((?P<dims>.*?)\)|)\s*\Z', e, re.I) + if m: + dims=[] + if m.group('dims'): + dims=[x.strip() for x in markoutercomma(m.group('dims')).split('@,@')] + n=m.group('name').strip() + if n in block['vars']: + if 'attrspec' in block['vars'][n]: + block['vars'][n]['attrspec'].append('dimension(%s)'%(','.join(dims))) + else: + block['vars'][n]['attrspec']=['dimension(%s)'%(','.join(dims))] + else: + if dims: + block['vars'][n]={'attrspec':['dimension(%s)'%(','.join(dims))]} + else: block['vars'][n]={} + if n not in commonvars: commonvars.append(n) + else: + n=e + errmess('analyzecommon: failed to extract "<name>[(<dims>)]" from "%s" in common /%s/.\n'%(e, k)) + comvars.append(n) + block['common'][k]=comvars + if 'commonvars' not in block: + block['commonvars']=commonvars + else: + block['commonvars']=block['commonvars']+commonvars + return block + +def analyzebody(block,args,tab=''): + global usermodules, skipfuncs, onlyfuncs, f90modulevars + setmesstext(block) + body=[] + for b in block['body']: + b['parent_block'] = block + if b['block'] in ['function', 'subroutine']: + if args is not None and b['name'] not in args: + continue + else: + as_=b['args'] + if b['name'] in skipfuncs: + continue + if onlyfuncs and b['name'] not in onlyfuncs: + continue + b['saved_interface'] = crack2fortrangen(b, '\n'+' '*6, as_interface=True) + + else: as_=args + b=postcrack(b, as_, tab=tab+'\t') + if b['block']=='interface' and not b['body']: + if 'f2pyenhancements' not in b: + continue + if b['block'].replace(' ', '')=='pythonmodule': + usermodules.append(b) + else: + if b['block']=='module': + f90modulevars[b['name']] = b['vars'] + body.append(b) + return body + +def buildimplicitrules(block): + setmesstext(block) + implicitrules=defaultimplicitrules + attrrules={} + if 'implicit' in block: + if block['implicit'] is None: + implicitrules=None + if verbose>1: + outmess('buildimplicitrules: no implicit rules for routine %s.\n'%repr(block['name'])) + else: + for k in list(block['implicit'].keys()): + if block['implicit'][k].get('typespec') not in ['static', 'automatic']: + implicitrules[k]=block['implicit'][k] + else: + attrrules[k]=block['implicit'][k]['typespec'] + return implicitrules, attrrules + +def myeval(e,g=None,l=None): + r = eval(e, g, l) + if type(r) in [type(0), type(0.0)]: + return r + raise ValueError('r=%r' % (r)) + +getlincoef_re_1 = re.compile(r'\A\b\w+\b\Z', re.I) +def getlincoef(e, xset): # e = a*x+b ; x in xset + try: + c = int(myeval(e, {}, {})) + return 0, c, None + except: pass + if getlincoef_re_1.match(e): + return 1, 0, e + len_e = len(e) + for x in xset: + if len(x)>len_e: continue + if re.search(r'\w\s*\([^)]*\b'+x+r'\b', e): + # skip function calls having x as an argument, e.g max(1, x) + continue + re_1 = re.compile(r'(?P<before>.*?)\b'+x+r'\b(?P<after>.*)', re.I) + m = re_1.match(e) + if m: + try: + m1 = re_1.match(e) + while m1: + ee = '%s(%s)%s'%(m1.group('before'), 0, m1.group('after')) + m1 = re_1.match(ee) + b = myeval(ee, {}, {}) + m1 = re_1.match(e) + while m1: + ee = '%s(%s)%s'%(m1.group('before'), 1, m1.group('after')) + m1 = re_1.match(ee) + a = myeval(ee, {}, {}) - b + m1 = re_1.match(e) + while m1: + ee = '%s(%s)%s'%(m1.group('before'), 0.5, m1.group('after')) + m1 = re_1.match(ee) + c = myeval(ee, {}, {}) + # computing another point to be sure that expression is linear + m1 = re_1.match(e) + while m1: + ee = '%s(%s)%s'%(m1.group('before'), 1.5, m1.group('after')) + m1 = re_1.match(ee) + c2 = myeval(ee, {}, {}) + if (a*0.5+b==c and a*1.5+b==c2): + return a, b, x + except: pass + break + return None, None, None + +_varname_match = re.compile(r'\A[a-z]\w*\Z').match +def getarrlen(dl,args,star='*'): + edl = [] + try: edl.append(myeval(dl[0], {}, {})) + except: edl.append(dl[0]) + try: edl.append(myeval(dl[1], {}, {})) + except: edl.append(dl[1]) + if isinstance(edl[0], int): + p1 = 1-edl[0] + if p1==0: d = str(dl[1]) + elif p1<0: d = '%s-%s'%(dl[1], -p1) + else: d = '%s+%s'%(dl[1], p1) + elif isinstance(edl[1], int): + p1 = 1+edl[1] + if p1==0: d='-(%s)' % (dl[0]) + else: d='%s-(%s)' % (p1, dl[0]) + else: d = '%s-(%s)+1'%(dl[1], dl[0]) + try: return repr(myeval(d, {}, {})), None, None + except: pass + d1, d2=getlincoef(dl[0], args), getlincoef(dl[1], args) + if None not in [d1[0], d2[0]]: + if (d1[0], d2[0])==(0, 0): + return repr(d2[1]-d1[1]+1), None, None + b = d2[1] - d1[1] + 1 + d1 = (d1[0], 0, d1[2]) + d2 = (d2[0], b, d2[2]) + if d1[0]==0 and d2[2] in args: + if b<0: return '%s * %s - %s'%(d2[0], d2[2], -b), d2[2], '+%s)/(%s)'%(-b, d2[0]) + elif b: return '%s * %s + %s'%(d2[0], d2[2], b), d2[2], '-%s)/(%s)'%(b, d2[0]) + else: return '%s * %s'%(d2[0], d2[2]), d2[2], ')/(%s)'%(d2[0]) + if d2[0]==0 and d1[2] in args: + + if b<0: return '%s * %s - %s'%(-d1[0], d1[2], -b), d1[2], '+%s)/(%s)'%(-b, -d1[0]) + elif b: return '%s * %s + %s'%(-d1[0], d1[2], b), d1[2], '-%s)/(%s)'%(b, -d1[0]) + else: return '%s * %s'%(-d1[0], d1[2]), d1[2], ')/(%s)'%(-d1[0]) + if d1[2]==d2[2] and d1[2] in args: + a = d2[0] - d1[0] + if not a: return repr(b), None, None + if b<0: return '%s * %s - %s'%(a, d1[2], -b), d2[2], '+%s)/(%s)'%(-b, a) + elif b: return '%s * %s + %s'%(a, d1[2], b), d2[2], '-%s)/(%s)'%(b, a) + else: return '%s * %s'%(a, d1[2]), d2[2], ')/(%s)'%(a) + if d1[0]==d2[0]==1: + c = str(d1[2]) + if c not in args: + if _varname_match(c): + outmess('\tgetarrlen:variable "%s" undefined\n' % (c)) + c = '(%s)'%c + if b==0: d='%s-%s' % (d2[2], c) + elif b<0: d='%s-%s-%s' % (d2[2], c, -b) + else: d='%s-%s+%s' % (d2[2], c, b) + elif d1[0]==0: + c2 = str(d2[2]) + if c2 not in args: + if _varname_match(c2): + outmess('\tgetarrlen:variable "%s" undefined\n' % (c2)) + c2 = '(%s)'%c2 + if d2[0]==1: pass + elif d2[0]==-1: c2='-%s' %c2 + else: c2='%s*%s'%(d2[0], c2) + + if b==0: d=c2 + elif b<0: d='%s-%s' % (c2, -b) + else: d='%s+%s' % (c2, b) + elif d2[0]==0: + c1 = str(d1[2]) + if c1 not in args: + if _varname_match(c1): + outmess('\tgetarrlen:variable "%s" undefined\n' % (c1)) + c1 = '(%s)'%c1 + if d1[0]==1: c1='-%s'%c1 + elif d1[0]==-1: c1='+%s'%c1 + elif d1[0]<0: c1='+%s*%s'%(-d1[0], c1) + else: c1 = '-%s*%s' % (d1[0], c1) + + if b==0: d=c1 + elif b<0: d='%s-%s' % (c1, -b) + else: d='%s+%s' % (c1, b) + else: + c1 = str(d1[2]) + if c1 not in args: + if _varname_match(c1): + outmess('\tgetarrlen:variable "%s" undefined\n' % (c1)) + c1 = '(%s)'%c1 + if d1[0]==1: c1='-%s'%c1 + elif d1[0]==-1: c1='+%s'%c1 + elif d1[0]<0: c1='+%s*%s'%(-d1[0], c1) + else: c1 = '-%s*%s' % (d1[0], c1) + + c2 = str(d2[2]) + if c2 not in args: + if _varname_match(c2): + outmess('\tgetarrlen:variable "%s" undefined\n' % (c2)) + c2 = '(%s)'%c2 + if d2[0]==1: pass + elif d2[0]==-1: c2='-%s' %c2 + else: c2='%s*%s'%(d2[0], c2) + + if b==0: d='%s%s' % (c2, c1) + elif b<0: d='%s%s-%s' % (c2, c1, -b) + else: d='%s%s+%s' % (c2, c1, b) + return d, None, None + +word_pattern = re.compile(r'\b[a-z][\w$]*\b', re.I) + +def _get_depend_dict(name, vars, deps): + if name in vars: + words = vars[name].get('depend', []) + + if '=' in vars[name] and not isstring(vars[name]): + for word in word_pattern.findall(vars[name]['=']): + if word not in words and word in vars: + words.append(word) + for word in words[:]: + for w in deps.get(word, []) \ + or _get_depend_dict(word, vars, deps): + if w not in words: + words.append(w) + else: + outmess('_get_depend_dict: no dependence info for %s\n' % (repr(name))) + words = [] + deps[name] = words + return words + +def _calc_depend_dict(vars): + names = list(vars.keys()) + depend_dict = {} + for n in names: + _get_depend_dict(n, vars, depend_dict) + return depend_dict + +def get_sorted_names(vars): + """ + """ + depend_dict = _calc_depend_dict(vars) + names = [] + for name in list(depend_dict.keys()): + if not depend_dict[name]: + names.append(name) + del depend_dict[name] + while depend_dict: + for name, lst in list(depend_dict.items()): + new_lst = [n for n in lst if n in depend_dict] + if not new_lst: + names.append(name) + del depend_dict[name] + else: + depend_dict[name] = new_lst + return [name for name in names if name in vars] + +def _kind_func(string): + #XXX: return something sensible. + if string[0] in "'\"": + string = string[1:-1] + if real16pattern.match(string): + return 8 + elif real8pattern.match(string): + return 4 + return 'kind('+string+')' + +def _selected_int_kind_func(r): + #XXX: This should be processor dependent + m = 10**r + if m<=2**8: return 1 + if m<=2**16: return 2 + if m<=2**32: return 4 + if m<=2**63: return 8 + if m<=2**128: return 16 + return -1 + +def _selected_real_kind_func(p, r=0, radix=0): + #XXX: This should be processor dependent + # This is only good for 0 <= p <= 20 + if p < 7: return 4 + if p < 16: return 8 + if platform.machine().lower().startswith('power'): + if p <= 20: + return 16 + else: + if p < 19: + return 10 + elif p <= 20: + return 16 + return -1 + +def get_parameters(vars, global_params={}): + params = copy.copy(global_params) + g_params = copy.copy(global_params) + for name, func in [('kind', _kind_func), + ('selected_int_kind', _selected_int_kind_func), + ('selected_real_kind', _selected_real_kind_func), + ]: + if name not in g_params: + g_params[name] = func + param_names = [] + for n in get_sorted_names(vars): + if 'attrspec' in vars[n] and 'parameter' in vars[n]['attrspec']: + param_names.append(n) + kind_re = re.compile(r'\bkind\s*\(\s*(?P<value>.*)\s*\)', re.I) + selected_int_kind_re = re.compile(r'\bselected_int_kind\s*\(\s*(?P<value>.*)\s*\)', re.I) + selected_kind_re = re.compile(r'\bselected_(int|real)_kind\s*\(\s*(?P<value>.*)\s*\)', re.I) + for n in param_names: + if '=' in vars[n]: + v = vars[n]['='] + if islogical(vars[n]): + v = v.lower() + for repl in [ + ('.false.', 'False'), + ('.true.', 'True'), + #TODO: test .eq., .neq., etc replacements. + ]: + v = v.replace(*repl) + v = kind_re.sub(r'kind("\1")', v) + v = selected_int_kind_re.sub(r'selected_int_kind(\1)', v) + if isinteger(vars[n]) and not selected_kind_re.match(v): + v = v.split('_')[0] + if isdouble(vars[n]): + tt = list(v) + for m in real16pattern.finditer(v): + tt[m.start():m.end()] = list(\ + v[m.start():m.end()].lower().replace('d', 'e')) + v = ''.join(tt) + if iscomplex(vars[n]): + if v[0]=='(' and v[-1]==')': + l = markoutercomma(v[1:-1]).split('@,@') + try: + params[n] = eval(v, g_params, params) + except Exception as msg: + params[n] = v + #print params + outmess('get_parameters: got "%s" on %s\n' % (msg, repr(v))) + if isstring(vars[n]) and isinstance(params[n], int): + params[n] = chr(params[n]) + nl = n.lower() + if nl!=n: + params[nl] = params[n] + else: + print(vars[n]) + outmess('get_parameters:parameter %s does not have value?!\n'%(repr(n))) + return params + +def _eval_length(length, params): + if length in ['(:)', '(*)', '*']: + return '(*)' + return _eval_scalar(length, params) + +_is_kind_number = re.compile(r'\d+_').match + +def _eval_scalar(value, params): + if _is_kind_number(value): + value = value.split('_')[0] + try: + value = str(eval(value, {}, params)) + except (NameError, SyntaxError): + return value + except Exception as msg: + errmess('"%s" in evaluating %r '\ + '(available names: %s)\n' \ + % (msg, value, list(params.keys()))) + return value + +def analyzevars(block): + global f90modulevars + setmesstext(block) + implicitrules, attrrules=buildimplicitrules(block) + vars=copy.copy(block['vars']) + if block['block']=='function' and block['name'] not in vars: + vars[block['name']]={} + if '' in block['vars']: + del vars[''] + if 'attrspec' in block['vars']['']: + gen=block['vars']['']['attrspec'] + for n in list(vars.keys()): + for k in ['public', 'private']: + if k in gen: + vars[n]=setattrspec(vars[n], k) + svars=[] + args = block['args'] + for a in args: + try: + vars[a] + svars.append(a) + except KeyError: + pass + for n in list(vars.keys()): + if n not in args: svars.append(n) + + params = get_parameters(vars, get_useparameters(block)) + + dep_matches = {} + name_match = re.compile(r'\w[\w\d_$]*').match + for v in list(vars.keys()): + m = name_match(v) + if m: + n = v[m.start():m.end()] + try: + dep_matches[n] + except KeyError: + dep_matches[n] = re.compile(r'.*\b%s\b'%(v), re.I).match + for n in svars: + if n[0] in list(attrrules.keys()): + vars[n]=setattrspec(vars[n], attrrules[n[0]]) + if 'typespec' not in vars[n]: + if not('attrspec' in vars[n] and 'external' in vars[n]['attrspec']): + if implicitrules: + ln0 = n[0].lower() + for k in list(implicitrules[ln0].keys()): + if k=='typespec' and implicitrules[ln0][k]=='undefined': + continue + if k not in vars[n]: + vars[n][k]=implicitrules[ln0][k] + elif k=='attrspec': + for l in implicitrules[ln0][k]: + vars[n]=setattrspec(vars[n], l) + elif n in block['args']: + outmess('analyzevars: typespec of variable %s is not defined in routine %s.\n'%(repr(n), block['name'])) + + if 'charselector' in vars[n]: + if 'len' in vars[n]['charselector']: + l = vars[n]['charselector']['len'] + try: + l = str(eval(l, {}, params)) + except: + pass + vars[n]['charselector']['len'] = l + + if 'kindselector' in vars[n]: + if 'kind' in vars[n]['kindselector']: + l = vars[n]['kindselector']['kind'] + try: + l = str(eval(l, {}, params)) + except: + pass + vars[n]['kindselector']['kind'] = l + + savelindims = {} + if 'attrspec' in vars[n]: + attr=vars[n]['attrspec'] + attr.reverse() + vars[n]['attrspec']=[] + dim, intent, depend, check, note=None, None, None, None, None + for a in attr: + if a[:9]=='dimension': dim=(a[9:].strip())[1:-1] + elif a[:6]=='intent': intent=(a[6:].strip())[1:-1] + elif a[:6]=='depend': depend=(a[6:].strip())[1:-1] + elif a[:5]=='check': check=(a[5:].strip())[1:-1] + elif a[:4]=='note': note=(a[4:].strip())[1:-1] + else: vars[n]=setattrspec(vars[n], a) + if intent: + if 'intent' not in vars[n]: + vars[n]['intent']=[] + for c in [x.strip() for x in markoutercomma(intent).split('@,@')]: + # Remove spaces so that 'in out' becomes 'inout' + tmp = c.replace(' ', '') + if tmp not in vars[n]['intent']: + vars[n]['intent'].append(tmp) + intent=None + if note: + note=note.replace('\\n\\n', '\n\n') + note=note.replace('\\n ', '\n') + if 'note' not in vars[n]: + vars[n]['note']=[note] + else: + vars[n]['note'].append(note) + note=None + if depend is not None: + if 'depend' not in vars[n]: + vars[n]['depend']=[] + for c in rmbadname([x.strip() for x in markoutercomma(depend).split('@,@')]): + if c not in vars[n]['depend']: + vars[n]['depend'].append(c) + depend=None + if check is not None: + if 'check' not in vars[n]: + vars[n]['check']=[] + for c in [x.strip() for x in markoutercomma(check).split('@,@')]: + if c not in vars[n]['check']: + vars[n]['check'].append(c) + check=None + if dim and 'dimension' not in vars[n]: + vars[n]['dimension']=[] + for d in rmbadname([x.strip() for x in markoutercomma(dim).split('@,@')]): + star = '*' + if d==':': + star=':' + if d in params: + d = str(params[d]) + for p in list(params.keys()): + m = re.match(r'(?P<before>.*?)\b'+p+r'\b(?P<after>.*)', d, re.I) + if m: + #outmess('analyzevars:replacing parameter %s in %s (dimension of %s) with %s\n'%(`p`,`d`,`n`,`params[p]`)) + d = m.group('before')+str(params[p])+m.group('after') + if d==star: + dl = [star] + else: + dl=markoutercomma(d, ':').split('@:@') + if len(dl)==2 and '*' in dl: # e.g. dimension(5:*) + dl = ['*'] + d = '*' + if len(dl)==1 and not dl[0]==star: dl = ['1', dl[0]] + if len(dl)==2: + d, v, di = getarrlen(dl, list(block['vars'].keys())) + if d[:4] == '1 * ': d = d[4:] + if di and di[-4:] == '/(1)': di = di[:-4] + if v: savelindims[d] = v, di + vars[n]['dimension'].append(d) + if 'dimension' in vars[n]: + if isintent_c(vars[n]): + shape_macro = 'shape' + else: + shape_macro = 'shape'#'fshape' + if isstringarray(vars[n]): + if 'charselector' in vars[n]: + d = vars[n]['charselector'] + if '*' in d: + d = d['*'] + errmess('analyzevars: character array "character*%s %s(%s)" is considered as "character %s(%s)"; "intent(c)" is forced.\n'\ + %(d, n, + ','.join(vars[n]['dimension']), + n, ','.join(vars[n]['dimension']+[d]))) + vars[n]['dimension'].append(d) + del vars[n]['charselector'] + if 'intent' not in vars[n]: + vars[n]['intent'] = [] + if 'c' not in vars[n]['intent']: + vars[n]['intent'].append('c') + else: + errmess("analyzevars: charselector=%r unhandled." % (d)) + if 'check' not in vars[n] and 'args' in block and n in block['args']: + flag = 'depend' not in vars[n] + if flag: + vars[n]['depend']=[] + vars[n]['check']=[] + if 'dimension' in vars[n]: + #/----< no check + #vars[n]['check'].append('rank(%s)==%s'%(n,len(vars[n]['dimension']))) + i=-1; ni=len(vars[n]['dimension']) + for d in vars[n]['dimension']: + ddeps=[] # dependecies of 'd' + ad='' + pd='' + #origd = d + if d not in vars: + if d in savelindims: + pd, ad='(', savelindims[d][1] + d = savelindims[d][0] + else: + for r in block['args']: + #for r in block['vars'].iterkeys(): + if r not in vars: + continue + if re.match(r'.*?\b'+r+r'\b', d, re.I): + ddeps.append(r) + if d in vars: + if 'attrspec' in vars[d]: + for aa in vars[d]['attrspec']: + if aa[:6]=='depend': + ddeps += aa[6:].strip()[1:-1].split(',') + if 'depend' in vars[d]: + ddeps=ddeps+vars[d]['depend'] + i=i+1 + if d in vars and ('depend' not in vars[d]) \ + and ('=' not in vars[d]) and (d not in vars[n]['depend']) \ + and l_or(isintent_in, isintent_inout, isintent_inplace)(vars[n]): + vars[d]['depend']=[n] + if ni>1: + vars[d]['=']='%s%s(%s,%s)%s'% (pd, shape_macro, n, i, ad) + else: + vars[d]['=']='%slen(%s)%s'% (pd, n, ad) + # /---< no check + if 1 and 'check' not in vars[d]: + if ni>1: + vars[d]['check']=['%s%s(%s,%i)%s==%s'\ + %(pd, shape_macro, n, i, ad, d)] + else: + vars[d]['check']=['%slen(%s)%s>=%s'%(pd, n, ad, d)] + if 'attrspec' not in vars[d]: + vars[d]['attrspec']=['optional'] + if ('optional' not in vars[d]['attrspec']) and\ + ('required' not in vars[d]['attrspec']): + vars[d]['attrspec'].append('optional') + elif d not in ['*', ':']: + #/----< no check + #if ni>1: vars[n]['check'].append('shape(%s,%i)==%s'%(n,i,d)) + #else: vars[n]['check'].append('len(%s)>=%s'%(n,d)) + if flag: + if d in vars: + if n not in ddeps: + vars[n]['depend'].append(d) + else: + vars[n]['depend'] = vars[n]['depend'] + ddeps + elif isstring(vars[n]): + length='1' + if 'charselector' in vars[n]: + if '*' in vars[n]['charselector']: + length = _eval_length(vars[n]['charselector']['*'], + params) + vars[n]['charselector']['*']=length + elif 'len' in vars[n]['charselector']: + length = _eval_length(vars[n]['charselector']['len'], + params) + del vars[n]['charselector']['len'] + vars[n]['charselector']['*']=length + + if not vars[n]['check']: + del vars[n]['check'] + if flag and not vars[n]['depend']: + del vars[n]['depend'] + if '=' in vars[n]: + if 'attrspec' not in vars[n]: + vars[n]['attrspec']=[] + if ('optional' not in vars[n]['attrspec']) and \ + ('required' not in vars[n]['attrspec']): + vars[n]['attrspec'].append('optional') + if 'depend' not in vars[n]: + vars[n]['depend']=[] + for v, m in list(dep_matches.items()): + if m(vars[n]['=']): vars[n]['depend'].append(v) + if not vars[n]['depend']: del vars[n]['depend'] + if isscalar(vars[n]): + vars[n]['='] = _eval_scalar(vars[n]['='], params) + + for n in list(vars.keys()): + if n==block['name']: # n is block name + if 'note' in vars[n]: + block['note']=vars[n]['note'] + if block['block']=='function': + if 'result' in block and block['result'] in vars: + vars[n]=appenddecl(vars[n], vars[block['result']]) + if 'prefix' in block: + pr=block['prefix']; ispure=0; isrec=1 + pr1=pr.replace('pure', '') + ispure=(not pr==pr1) + pr=pr1.replace('recursive', '') + isrec=(not pr==pr1) + m=typespattern[0].match(pr) + if m: + typespec, selector, attr, edecl=cracktypespec0(m.group('this'), m.group('after')) + kindselect, charselect, typename=cracktypespec(typespec, selector) + vars[n]['typespec']=typespec + if kindselect: + if 'kind' in kindselect: + try: + kindselect['kind'] = eval(kindselect['kind'], {}, params) + except: + pass + vars[n]['kindselector']=kindselect + if charselect: vars[n]['charselector']=charselect + if typename: vars[n]['typename']=typename + if ispure: vars[n]=setattrspec(vars[n], 'pure') + if isrec: vars[n]=setattrspec(vars[n], 'recursive') + else: + outmess('analyzevars: prefix (%s) were not used\n'%repr(block['prefix'])) + if not block['block'] in ['module', 'pythonmodule', 'python module', 'block data']: + if 'commonvars' in block: + neededvars=copy.copy(block['args']+block['commonvars']) + else: + neededvars=copy.copy(block['args']) + for n in list(vars.keys()): + if l_or(isintent_callback, isintent_aux)(vars[n]): + neededvars.append(n) + if 'entry' in block: + neededvars.extend(list(block['entry'].keys())) + for k in list(block['entry'].keys()): + for n in block['entry'][k]: + if n not in neededvars: + neededvars.append(n) + if block['block']=='function': + if 'result' in block: + neededvars.append(block['result']) + else: + neededvars.append(block['name']) + if block['block'] in ['subroutine', 'function']: + name = block['name'] + if name in vars and 'intent' in vars[name]: + block['intent'] = vars[name]['intent'] + if block['block'] == 'type': + neededvars.extend(list(vars.keys())) + for n in list(vars.keys()): + if n not in neededvars: + del vars[n] + return vars + +analyzeargs_re_1 = re.compile(r'\A[a-z]+[\w$]*\Z', re.I) +def expr2name(a, block, args=[]): + orig_a = a + a_is_expr = not analyzeargs_re_1.match(a) + if a_is_expr: # `a` is an expression + implicitrules, attrrules=buildimplicitrules(block) + at=determineexprtype(a, block['vars'], implicitrules) + na='e_' + for c in a: + c = c.lower() + if c not in string.ascii_lowercase+string.digits: c='_' + na=na+c + if na[-1]=='_': na=na+'e' + else: na=na+'_e' + a=na + while a in block['vars'] or a in block['args']: + a=a+'r' + if a in args: + k = 1 + while a + str(k) in args: + k = k + 1 + a = a + str(k) + if a_is_expr: + block['vars'][a]=at + else: + if a not in block['vars']: + if orig_a in block['vars']: + block['vars'][a] = block['vars'][orig_a] + else: + block['vars'][a]={} + if 'externals' in block and orig_a in block['externals']+block['interfaced']: + block['vars'][a]=setattrspec(block['vars'][a], 'external') + return a + +def analyzeargs(block): + setmesstext(block) + implicitrules, attrrules=buildimplicitrules(block) + if 'args' not in block: + block['args']=[] + args=[] + for a in block['args']: + a = expr2name(a, block, args) + args.append(a) + block['args']=args + if 'entry' in block: + for k, args1 in list(block['entry'].items()): + for a in args1: + if a not in block['vars']: + block['vars'][a]={} + + for b in block['body']: + if b['name'] in args: + if 'externals' not in block: + block['externals']=[] + if b['name'] not in block['externals']: + block['externals'].append(b['name']) + if 'result' in block and block['result'] not in block['vars']: + block['vars'][block['result']]={} + return block + +determineexprtype_re_1 = re.compile(r'\A\(.+?[,].+?\)\Z', re.I) +determineexprtype_re_2 = re.compile(r'\A[+-]?\d+(_(P<name>[\w]+)|)\Z', re.I) +determineexprtype_re_3 = re.compile(r'\A[+-]?[\d.]+[\d+-de.]*(_(P<name>[\w]+)|)\Z', re.I) +determineexprtype_re_4 = re.compile(r'\A\(.*\)\Z', re.I) +determineexprtype_re_5 = re.compile(r'\A(?P<name>\w+)\s*\(.*?\)\s*\Z', re.I) +def _ensure_exprdict(r): + if isinstance(r, int): + return {'typespec':'integer'} + if isinstance(r, float): + return {'typespec':'real'} + if isinstance(r, complex): + return {'typespec':'complex'} + if isinstance(r, dict): + return r + raise AssertionError(repr(r)) + +def determineexprtype(expr,vars,rules={}): + if expr in vars: + return _ensure_exprdict(vars[expr]) + expr=expr.strip() + if determineexprtype_re_1.match(expr): + return {'typespec':'complex'} + m=determineexprtype_re_2.match(expr) + if m: + if 'name' in m.groupdict() and m.group('name'): + outmess('determineexprtype: selected kind types not supported (%s)\n'%repr(expr)) + return {'typespec':'integer'} + m = determineexprtype_re_3.match(expr) + if m: + if 'name' in m.groupdict() and m.group('name'): + outmess('determineexprtype: selected kind types not supported (%s)\n'%repr(expr)) + return {'typespec':'real'} + for op in ['+', '-', '*', '/']: + for e in [x.strip() for x in markoutercomma(expr, comma=op).split('@'+op+'@')]: + if e in vars: + return _ensure_exprdict(vars[e]) + t={} + if determineexprtype_re_4.match(expr): # in parenthesis + t=determineexprtype(expr[1:-1], vars, rules) + else: + m = determineexprtype_re_5.match(expr) + if m: + rn=m.group('name') + t=determineexprtype(m.group('name'), vars, rules) + if t and 'attrspec' in t: + del t['attrspec'] + if not t: + if rn[0] in rules: + return _ensure_exprdict(rules[rn[0]]) + if expr[0] in '\'"': + return {'typespec':'character','charselector':{'*':'*'}} + if not t: + outmess('determineexprtype: could not determine expressions (%s) type.\n'%(repr(expr))) + return t + +###### +def crack2fortrangen(block,tab='\n', as_interface=False): + global skipfuncs, onlyfuncs + setmesstext(block) + ret='' + if isinstance(block, list): + for g in block: + if g and g['block'] in ['function', 'subroutine']: + if g['name'] in skipfuncs: + continue + if onlyfuncs and g['name'] not in onlyfuncs: + continue + ret=ret+crack2fortrangen(g, tab, as_interface=as_interface) + return ret + prefix='' + name='' + args='' + blocktype=block['block'] + if blocktype=='program': return '' + argsl = [] + if 'name' in block: + name=block['name'] + if 'args' in block: + vars = block['vars'] + for a in block['args']: + a = expr2name(a, block, argsl) + if not isintent_callback(vars[a]): + argsl.append(a) + if block['block']=='function' or argsl: + args='(%s)'%','.join(argsl) + f2pyenhancements = '' + if 'f2pyenhancements' in block: + for k in list(block['f2pyenhancements'].keys()): + f2pyenhancements = '%s%s%s %s'%(f2pyenhancements, tab+tabchar, k, block['f2pyenhancements'][k]) + intent_lst = block.get('intent', [])[:] + if blocktype=='function' and 'callback' in intent_lst: + intent_lst.remove('callback') + if intent_lst: + f2pyenhancements = '%s%sintent(%s) %s'%\ + (f2pyenhancements, tab+tabchar, + ','.join(intent_lst), name) + use='' + if 'use' in block: + use=use2fortran(block['use'], tab+tabchar) + common='' + if 'common' in block: + common=common2fortran(block['common'], tab+tabchar) + if name=='unknown_interface': name='' + result='' + if 'result' in block: + result=' result (%s)'%block['result'] + if block['result'] not in argsl: + argsl.append(block['result']) + #if 'prefix' in block: + # prefix=block['prefix']+' ' + body=crack2fortrangen(block['body'], tab+tabchar) + vars=vars2fortran(block, block['vars'], argsl, tab+tabchar, as_interface=as_interface) + mess='' + if 'from' in block and not as_interface: + mess='! in %s'%block['from'] + if 'entry' in block: + entry_stmts = '' + for k, i in list(block['entry'].items()): + entry_stmts = '%s%sentry %s(%s)' \ + % (entry_stmts, tab+tabchar, k, ','.join(i)) + body = body + entry_stmts + if blocktype=='block data' and name=='_BLOCK_DATA_': + name = '' + ret='%s%s%s %s%s%s %s%s%s%s%s%s%send %s %s'%(tab, prefix, blocktype, name, args, result, mess, f2pyenhancements, use, vars, common, body, tab, blocktype, name) + return ret + +def common2fortran(common,tab=''): + ret='' + for k in list(common.keys()): + if k=='_BLNK_': + ret='%s%scommon %s'%(ret, tab, ','.join(common[k])) + else: + ret='%s%scommon /%s/ %s'%(ret, tab, k, ','.join(common[k])) + return ret + +def use2fortran(use,tab=''): + ret='' + for m in list(use.keys()): + ret='%s%suse %s,'%(ret, tab, m) + if use[m]=={}: + if ret and ret[-1]==',': ret=ret[:-1] + continue + if 'only' in use[m] and use[m]['only']: + ret='%s only:'%(ret) + if 'map' in use[m] and use[m]['map']: + c=' ' + for k in list(use[m]['map'].keys()): + if k==use[m]['map'][k]: + ret='%s%s%s'%(ret, c, k); c=',' + else: + ret='%s%s%s=>%s'%(ret, c, k, use[m]['map'][k]); c=',' + if ret and ret[-1]==',': ret=ret[:-1] + return ret + +def true_intent_list(var): + lst = var['intent'] + ret = [] + for intent in lst: + try: + c = eval('isintent_%s(var)' % intent) + except NameError: + c = 0 + if c: + ret.append(intent) + return ret + +def vars2fortran(block,vars,args,tab='', as_interface=False): + """ + TODO: + public sub + ... + """ + setmesstext(block) + ret='' + nout=[] + for a in args: + if a in block['vars']: + nout.append(a) + if 'commonvars' in block: + for a in block['commonvars']: + if a in vars: + if a not in nout: + nout.append(a) + else: + errmess('vars2fortran: Confused?!: "%s" is not defined in vars.\n'%a) + if 'varnames' in block: + nout.extend(block['varnames']) + if not as_interface: + for a in list(vars.keys()): + if a not in nout: + nout.append(a) + for a in nout: + if 'depend' in vars[a]: + for d in vars[a]['depend']: + if d in vars and 'depend' in vars[d] and a in vars[d]['depend']: + errmess('vars2fortran: Warning: cross-dependence between variables "%s" and "%s"\n'%(a, d)) + if 'externals' in block and a in block['externals']: + if isintent_callback(vars[a]): + ret='%s%sintent(callback) %s'%(ret, tab, a) + ret='%s%sexternal %s'%(ret, tab, a) + if isoptional(vars[a]): + ret='%s%soptional %s'%(ret, tab, a) + if a in vars and 'typespec' not in vars[a]: + continue + cont=1 + for b in block['body']: + if a==b['name'] and b['block']=='function': + cont=0;break + if cont: + continue + if a not in vars: + show(vars) + outmess('vars2fortran: No definition for argument "%s".\n'%a) + continue + if a==block['name'] and not block['block']=='function': + continue + if 'typespec' not in vars[a]: + if 'attrspec' in vars[a] and 'external' in vars[a]['attrspec']: + if a in args: + ret='%s%sexternal %s'%(ret, tab, a) + continue + show(vars[a]) + outmess('vars2fortran: No typespec for argument "%s".\n'%a) + continue + vardef=vars[a]['typespec'] + if vardef=='type' and 'typename' in vars[a]: + vardef='%s(%s)'%(vardef, vars[a]['typename']) + selector={} + if 'kindselector' in vars[a]: + selector=vars[a]['kindselector'] + elif 'charselector' in vars[a]: + selector=vars[a]['charselector'] + if '*' in selector: + if selector['*'] in ['*', ':']: + vardef='%s*(%s)'%(vardef, selector['*']) + else: + vardef='%s*%s'%(vardef, selector['*']) + else: + if 'len' in selector: + vardef='%s(len=%s'%(vardef, selector['len']) + if 'kind' in selector: + vardef='%s,kind=%s)'%(vardef, selector['kind']) + else: + vardef='%s)'%(vardef) + elif 'kind' in selector: + vardef='%s(kind=%s)'%(vardef, selector['kind']) + c=' ' + if 'attrspec' in vars[a]: + attr=[] + for l in vars[a]['attrspec']: + if l not in ['external']: + attr.append(l) + if attr: + vardef='%s, %s'%(vardef, ','.join(attr)) + c=',' + if 'dimension' in vars[a]: +# if not isintent_c(vars[a]): +# vars[a]['dimension'].reverse() + vardef='%s%sdimension(%s)'%(vardef, c, ','.join(vars[a]['dimension'])) + c=',' + if 'intent' in vars[a]: + lst = true_intent_list(vars[a]) + if lst: + vardef='%s%sintent(%s)'%(vardef, c, ','.join(lst)) + c=',' + if 'check' in vars[a]: + vardef='%s%scheck(%s)'%(vardef, c, ','.join(vars[a]['check'])) + c=',' + if 'depend' in vars[a]: + vardef='%s%sdepend(%s)'%(vardef, c, ','.join(vars[a]['depend'])) + c=',' + if '=' in vars[a]: + v = vars[a]['='] + if vars[a]['typespec'] in ['complex', 'double complex']: + try: + v = eval(v) + v = '(%s,%s)' % (v.real, v.imag) + except: + pass + vardef='%s :: %s=%s'%(vardef, a, v) + else: + vardef='%s :: %s'%(vardef, a) + ret='%s%s%s'%(ret, tab, vardef) + return ret +###### + +def crackfortran(files): + global usermodules + outmess('Reading fortran codes...\n', 0) + readfortrancode(files, crackline) + outmess('Post-processing...\n', 0) + usermodules=[] + postlist=postcrack(grouplist[0]) + outmess('Post-processing (stage 2)...\n', 0) + postlist=postcrack2(postlist) + return usermodules+postlist + +def crack2fortran(block): + global f2py_version + pyf=crack2fortrangen(block)+'\n' + header="""! -*- f90 -*- +! Note: the context of this file is case sensitive. +""" + footer=""" +! This file was auto-generated with f2py (version:%s). +! See http://cens.ioc.ee/projects/f2py2e/ +"""%(f2py_version) + return header+pyf+footer + +if __name__ == "__main__": + files=[] + funcs=[] + f=1;f2=0;f3=0 + showblocklist=0 + for l in sys.argv[1:]: + if l=='': pass + elif l[0]==':': + f=0 + elif l=='-quiet': + quiet=1 + verbose=0 + elif l=='-verbose': + verbose=2 + quiet=0 + elif l=='-fix': + if strictf77: + outmess('Use option -f90 before -fix if Fortran 90 code is in fix form.\n', 0) + skipemptyends=1 + sourcecodeform='fix' + elif l=='-skipemptyends': + skipemptyends=1 + elif l=='--ignore-contains': + ignorecontains=1 + elif l=='-f77': + strictf77=1 + sourcecodeform='fix' + elif l=='-f90': + strictf77=0 + sourcecodeform='free' + skipemptyends=1 + elif l=='-h': + f2=1 + elif l=='-show': + showblocklist=1 + elif l=='-m': + f3=1 + elif l[0]=='-': + errmess('Unknown option %s\n'%repr(l)) + elif f2: + f2=0 + pyffilename=l + elif f3: + f3=0 + f77modulename=l + elif f: + try: + open(l).close() + files.append(l) + except IOError as detail: + errmess('IOError: %s\n'%str(detail)) + else: + funcs.append(l) + if not strictf77 and f77modulename and not skipemptyends: + outmess("""\ + Warning: You have specifyied module name for non Fortran 77 code + that should not need one (expect if you are scanning F90 code + for non module blocks but then you should use flag -skipemptyends + and also be sure that the files do not contain programs without program statement). +""", 0) + + postlist=crackfortran(files, funcs) + if pyffilename: + outmess('Writing fortran code to file %s\n'%repr(pyffilename), 0) + pyf=crack2fortran(postlist) + f=open(pyffilename, 'w') + f.write(pyf) + f.close() + if showblocklist: + show(postlist)