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