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