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