PageRenderTime 72ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 1ms

/numpy/f2py/crackfortran.py

http://github.com/teoliphant/numpy-refactor
Python | 2772 lines | 2740 code | 3 blank | 29 comment | 46 complexity | 59ccaabaeae73b4448840d2be3087c65 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. #!/usr/bin/env python
  2. """
  3. crackfortran --- read fortran (77,90) code and extract declaration information.
  4. Usage is explained in the comment block below.
  5. Copyright 1999-2004 Pearu Peterson all rights reserved,
  6. Pearu Peterson <pearu@ioc.ee>
  7. Permission to use, modify, and distribute this software is given under the
  8. terms of the NumPy License.
  9. NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
  10. $Date: 2005/09/27 07:13:49 $
  11. Pearu Peterson
  12. """
  13. __version__ = "$Revision: 1.177 $"[10:-1]
  14. import __version__
  15. f2py_version = __version__.version
  16. """
  17. Usage of crackfortran:
  18. ======================
  19. Command line keys: -quiet,-verbose,-fix,-f77,-f90,-show,-h <pyffilename>
  20. -m <module name for f77 routines>,--ignore-contains
  21. Functions: crackfortran, crack2fortran
  22. The following Fortran statements/constructions are supported
  23. (or will be if needed):
  24. block data,byte,call,character,common,complex,contains,data,
  25. dimension,double complex,double precision,end,external,function,
  26. implicit,integer,intent,interface,intrinsic,
  27. logical,module,optional,parameter,private,public,
  28. program,real,(sequence?),subroutine,type,use,virtual,
  29. include,pythonmodule
  30. Note: 'virtual' is mapped to 'dimension'.
  31. Note: 'implicit integer (z) static (z)' is 'implicit static (z)' (this is minor bug).
  32. Note: code after 'contains' will be ignored until its scope ends.
  33. Note: 'common' statement is extended: dimensions are moved to variable definitions
  34. Note: f2py directive: <commentchar>f2py<line> is read as <line>
  35. Note: pythonmodule is introduced to represent Python module
  36. Usage:
  37. `postlist=crackfortran(files,funcs)`
  38. `postlist` contains declaration information read from the list of files `files`.
  39. `crack2fortran(postlist)` returns a fortran code to be saved to pyf-file
  40. `postlist` has the following structure:
  41. *** it is a list of dictionaries containing `blocks':
  42. B = {'block','body','vars','parent_block'[,'name','prefix','args','result',
  43. 'implicit','externals','interfaced','common','sortvars',
  44. 'commonvars','note']}
  45. B['block'] = 'interface' | 'function' | 'subroutine' | 'module' |
  46. 'program' | 'block data' | 'type' | 'pythonmodule'
  47. B['body'] --- list containing `subblocks' with the same structure as `blocks'
  48. B['parent_block'] --- dictionary of a parent block:
  49. C['body'][<index>]['parent_block'] is C
  50. B['vars'] --- dictionary of variable definitions
  51. B['sortvars'] --- dictionary of variable definitions sorted by dependence (independent first)
  52. B['name'] --- name of the block (not if B['block']=='interface')
  53. B['prefix'] --- prefix string (only if B['block']=='function')
  54. B['args'] --- list of argument names if B['block']== 'function' | 'subroutine'
  55. B['result'] --- name of the return value (only if B['block']=='function')
  56. B['implicit'] --- dictionary {'a':<variable definition>,'b':...} | None
  57. B['externals'] --- list of variables being external
  58. B['interfaced'] --- list of variables being external and defined
  59. B['common'] --- dictionary of common blocks (list of objects)
  60. B['commonvars'] --- list of variables used in common blocks (dimensions are moved to variable definitions)
  61. B['from'] --- string showing the 'parents' of the current block
  62. B['use'] --- dictionary of modules used in current block:
  63. {<modulename>:{['only':<0|1>],['map':{<local_name1>:<use_name1>,...}]}}
  64. B['note'] --- list of LaTeX comments on the block
  65. B['f2pyenhancements'] --- optional dictionary
  66. {'threadsafe':'','fortranname':<name>,
  67. 'callstatement':<C-expr>|<multi-line block>,
  68. 'callprotoargument':<C-expr-list>,
  69. 'usercode':<multi-line block>|<list of multi-line blocks>,
  70. 'pymethoddef:<multi-line block>'
  71. }
  72. B['entry'] --- dictionary {entryname:argslist,..}
  73. B['varnames'] --- list of variable names given in the order of reading the
  74. Fortran code, useful for derived types.
  75. *** Variable definition is a dictionary
  76. D = B['vars'][<variable name>] =
  77. {'typespec'[,'attrspec','kindselector','charselector','=','typename']}
  78. D['typespec'] = 'byte' | 'character' | 'complex' | 'double complex' |
  79. 'double precision' | 'integer' | 'logical' | 'real' | 'type'
  80. D['attrspec'] --- list of attributes (e.g. 'dimension(<arrayspec>)',
  81. 'external','intent(in|out|inout|hide|c|callback|cache|aligned4|aligned8|aligned16)',
  82. 'optional','required', etc)
  83. K = D['kindselector'] = {['*','kind']} (only if D['typespec'] =
  84. 'complex' | 'integer' | 'logical' | 'real' )
  85. C = D['charselector'] = {['*','len','kind']}
  86. (only if D['typespec']=='character')
  87. D['='] --- initialization expression string
  88. D['typename'] --- name of the type if D['typespec']=='type'
  89. D['dimension'] --- list of dimension bounds
  90. D['intent'] --- list of intent specifications
  91. D['depend'] --- list of variable names on which current variable depends on
  92. D['check'] --- list of C-expressions; if C-expr returns zero, exception is raised
  93. D['note'] --- list of LaTeX comments on the variable
  94. *** Meaning of kind/char selectors (few examples):
  95. D['typespec>']*K['*']
  96. D['typespec'](kind=K['kind'])
  97. character*C['*']
  98. character(len=C['len'],kind=C['kind'])
  99. (see also fortran type declaration statement formats below)
  100. Fortran 90 type declaration statement format (F77 is subset of F90)
  101. ====================================================================
  102. (Main source: IBM XL Fortran 5.1 Language Reference Manual)
  103. type declaration = <typespec> [[<attrspec>]::] <entitydecl>
  104. <typespec> = byte |
  105. character[<charselector>] |
  106. complex[<kindselector>] |
  107. double complex |
  108. double precision |
  109. integer[<kindselector>] |
  110. logical[<kindselector>] |
  111. real[<kindselector>] |
  112. type(<typename>)
  113. <charselector> = * <charlen> |
  114. ([len=]<len>[,[kind=]<kind>]) |
  115. (kind=<kind>[,len=<len>])
  116. <kindselector> = * <intlen> |
  117. ([kind=]<kind>)
  118. <attrspec> = comma separated list of attributes.
  119. Only the following attributes are used in
  120. building up the interface:
  121. external
  122. (parameter --- affects '=' key)
  123. optional
  124. intent
  125. Other attributes are ignored.
  126. <intentspec> = in | out | inout
  127. <arrayspec> = comma separated list of dimension bounds.
  128. <entitydecl> = <name> [[*<charlen>][(<arrayspec>)] | [(<arrayspec>)]*<charlen>]
  129. [/<init_expr>/ | =<init_expr>] [,<entitydecl>]
  130. In addition, the following attributes are used: check,depend,note
  131. TODO:
  132. * Apply 'parameter' attribute (e.g. 'integer parameter :: i=2' 'real x(i)'
  133. -> 'real x(2)')
  134. The above may be solved by creating appropriate preprocessor program, for example.
  135. """
  136. #
  137. import sys
  138. import string
  139. import fileinput
  140. import re
  141. import pprint
  142. import os
  143. import copy
  144. from auxfuncs import *
  145. # Global flags:
  146. strictf77=1 # Ignore `!' comments unless line[0]=='!'
  147. sourcecodeform='fix' # 'fix','free'
  148. quiet=0 # Be verbose if 0 (Obsolete: not used any more)
  149. verbose=1 # Be quiet if 0, extra verbose if > 1.
  150. tabchar=4*' '
  151. pyffilename=''
  152. f77modulename=''
  153. skipemptyends=0 # for old F77 programs without 'program' statement
  154. ignorecontains=1
  155. dolowercase=1
  156. debug=[]
  157. ## do_analyze = 1
  158. ###### global variables
  159. ## use reload(crackfortran) to reset these variables
  160. groupcounter=0
  161. grouplist={groupcounter:[]}
  162. neededmodule=-1
  163. expectbegin=1
  164. skipblocksuntil=-1
  165. usermodules=[]
  166. f90modulevars={}
  167. gotnextfile=1
  168. filepositiontext=''
  169. currentfilename=''
  170. skipfunctions=[]
  171. skipfuncs=[]
  172. onlyfuncs=[]
  173. include_paths=[]
  174. previous_context = None
  175. ###### Some helper functions
  176. def show(o,f=0):pprint.pprint(o)
  177. errmess=sys.stderr.write
  178. def outmess(line,flag=1):
  179. global filepositiontext
  180. if not verbose: return
  181. if not quiet:
  182. if flag:sys.stdout.write(filepositiontext)
  183. sys.stdout.write(line)
  184. re._MAXCACHE=50
  185. defaultimplicitrules={}
  186. for c in "abcdefghopqrstuvwxyz$_": defaultimplicitrules[c]={'typespec':'real'}
  187. for c in "ijklmn": defaultimplicitrules[c]={'typespec':'integer'}
  188. del c
  189. badnames={}
  190. invbadnames={}
  191. for n in ['int','double','float','char','short','long','void','case','while',
  192. 'return','signed','unsigned','if','for','typedef','sizeof','union',
  193. 'struct','static','register','new','break','do','goto','switch',
  194. 'continue','else','inline','extern','delete','const','auto',
  195. 'len','rank','shape','index','slen','size','_i',
  196. 'max', 'min',
  197. 'flen','fshape',
  198. 'string','complex_double','float_double','stdin','stderr','stdout',
  199. 'type','default']:
  200. badnames[n]=n+'_bn'
  201. invbadnames[n+'_bn']=n
  202. def rmbadname1(name):
  203. if name in badnames:
  204. errmess('rmbadname1: Replacing "%s" with "%s".\n'%(name,badnames[name]))
  205. return badnames[name]
  206. return name
  207. def rmbadname(names): return map(rmbadname1,names)
  208. def undo_rmbadname1(name):
  209. if name in invbadnames:
  210. errmess('undo_rmbadname1: Replacing "%s" with "%s".\n'\
  211. %(name,invbadnames[name]))
  212. return invbadnames[name]
  213. return name
  214. def undo_rmbadname(names): return map(undo_rmbadname1,names)
  215. def getextension(name):
  216. i=name.rfind('.')
  217. if i==-1: return ''
  218. if '\\' in name[i:]: return ''
  219. if '/' in name[i:]: return ''
  220. return name[i+1:]
  221. is_f_file = re.compile(r'.*[.](for|ftn|f77|f)\Z',re.I).match
  222. _has_f_header = re.compile(r'-[*]-\s*fortran\s*-[*]-',re.I).search
  223. _has_f90_header = re.compile(r'-[*]-\s*f90\s*-[*]-',re.I).search
  224. _has_fix_header = re.compile(r'-[*]-\s*fix\s*-[*]-',re.I).search
  225. _free_f90_start = re.compile(r'[^c*]\s*[^\s\d\t]',re.I).match
  226. def is_free_format(file):
  227. """Check if file is in free format Fortran."""
  228. # f90 allows both fixed and free format, assuming fixed unless
  229. # signs of free format are detected.
  230. result = 0
  231. f = open(file,'r')
  232. line = f.readline()
  233. n = 15 # the number of non-comment lines to scan for hints
  234. if _has_f_header(line):
  235. n = 0
  236. elif _has_f90_header(line):
  237. n = 0
  238. result = 1
  239. while n>0 and line:
  240. if line[0]!='!' and line.strip():
  241. n -= 1
  242. if (line[0]!='\t' and _free_f90_start(line[:5])) or line[-2:-1]=='&':
  243. result = 1
  244. break
  245. line = f.readline()
  246. f.close()
  247. return result
  248. ####### Read fortran (77,90) code
  249. def readfortrancode(ffile,dowithline=show,istop=1):
  250. """
  251. Read fortran codes from files and
  252. 1) Get rid of comments, line continuations, and empty lines; lower cases.
  253. 2) Call dowithline(line) on every line.
  254. 3) Recursively call itself when statement \"include '<filename>'\" is met.
  255. """
  256. global gotnextfile,filepositiontext,currentfilename,sourcecodeform,strictf77,\
  257. beginpattern,quiet,verbose,dolowercase,include_paths
  258. if not istop:
  259. saveglobals=gotnextfile,filepositiontext,currentfilename,sourcecodeform,strictf77,\
  260. beginpattern,quiet,verbose,dolowercase
  261. if ffile==[]: return
  262. localdolowercase = dolowercase
  263. cont=0
  264. finalline=''
  265. ll=''
  266. commentline=re.compile(r'(?P<line>([^"]*"[^"]*"[^"!]*|[^\']*\'[^\']*\'[^\'!]*|[^!]*))!{1}(?P<rest>.*)')
  267. includeline=re.compile(r'\s*include\s*(\'|")(?P<name>[^\'"]*)(\'|")',re.I)
  268. cont1=re.compile(r'(?P<line>.*)&\s*\Z')
  269. cont2=re.compile(r'(\s*&|)(?P<line>.*)')
  270. mline_mark = re.compile(r".*?'''")
  271. if istop: dowithline('',-1)
  272. ll,l1='',''
  273. spacedigits=[' ']+map(str,range(10))
  274. filepositiontext=''
  275. fin=fileinput.FileInput(ffile)
  276. while 1:
  277. l=fin.readline()
  278. if not l: break
  279. if fin.isfirstline():
  280. filepositiontext=''
  281. currentfilename=fin.filename()
  282. gotnextfile=1
  283. l1=l
  284. strictf77=0
  285. sourcecodeform='fix'
  286. ext = os.path.splitext(currentfilename)[1]
  287. if is_f_file(currentfilename) and \
  288. not (_has_f90_header(l) or _has_fix_header(l)):
  289. strictf77=1
  290. elif is_free_format(currentfilename) and not _has_fix_header(l):
  291. sourcecodeform='free'
  292. if strictf77: beginpattern=beginpattern77
  293. else: beginpattern=beginpattern90
  294. outmess('\tReading file %s (format:%s%s)\n'\
  295. %(`currentfilename`,sourcecodeform,
  296. strictf77 and ',strict' or ''))
  297. l=l.expandtabs().replace('\xa0',' ')
  298. while not l=='': # Get rid of newline characters
  299. if l[-1] not in "\n\r\f": break
  300. l=l[:-1]
  301. if not strictf77:
  302. r=commentline.match(l)
  303. if r:
  304. l=r.group('line')+' ' # Strip comments starting with `!'
  305. rl=r.group('rest')
  306. if rl[:4].lower()=='f2py': # f2py directive
  307. l = l + 4*' '
  308. r=commentline.match(rl[4:])
  309. if r: l=l+r.group('line')
  310. else: l = l + rl[4:]
  311. if l.strip()=='': # Skip empty line
  312. cont=0
  313. continue
  314. if sourcecodeform=='fix':
  315. if l[0] in ['*','c','!','C','#']:
  316. if l[1:5].lower()=='f2py': # f2py directive
  317. l=' '+l[5:]
  318. else: # Skip comment line
  319. cont=0
  320. continue
  321. elif strictf77:
  322. if len(l)>72: l=l[:72]
  323. if not (l[0] in spacedigits):
  324. raise Exception('readfortrancode: Found non-(space,digit) char '
  325. 'in the first column.\n\tAre you sure that '
  326. 'this code is in fix form?\n\tline=%s' % `l`)
  327. if (not cont or strictf77) and (len(l)>5 and not l[5]==' '):
  328. # Continuation of a previous line
  329. ll=ll+l[6:]
  330. finalline=''
  331. origfinalline=''
  332. else:
  333. if not strictf77:
  334. # F90 continuation
  335. r=cont1.match(l)
  336. if r: l=r.group('line') # Continuation follows ..
  337. if cont:
  338. ll=ll+cont2.match(l).group('line')
  339. finalline=''
  340. origfinalline=''
  341. else:
  342. l=' '+l[5:] # clean up line beginning from possible digits.
  343. if localdolowercase: finalline=ll.lower()
  344. else: finalline=ll
  345. origfinalline=ll
  346. ll=l
  347. cont=(r is not None)
  348. else:
  349. l=' '+l[5:] # clean up line beginning from possible digits.
  350. if localdolowercase: finalline=ll.lower()
  351. else: finalline=ll
  352. origfinalline =ll
  353. ll=l
  354. elif sourcecodeform=='free':
  355. if not cont and ext=='.pyf' and mline_mark.match(l):
  356. l = l + '\n'
  357. while 1:
  358. lc = fin.readline()
  359. if not lc:
  360. errmess('Unexpected end of file when reading multiline\n')
  361. break
  362. l = l + lc
  363. if mline_mark.match(lc):
  364. break
  365. l = l.rstrip()
  366. r=cont1.match(l)
  367. if r: l=r.group('line') # Continuation follows ..
  368. if cont:
  369. ll=ll+cont2.match(l).group('line')
  370. finalline=''
  371. origfinalline=''
  372. else:
  373. if localdolowercase: finalline=ll.lower()
  374. else: finalline=ll
  375. origfinalline =ll
  376. ll=l
  377. cont=(r is not None)
  378. else:
  379. raise ValueError,"Flag sourcecodeform must be either 'fix' or 'free': %s"%`sourcecodeform`
  380. filepositiontext='Line #%d in %s:"%s"\n\t' % (fin.filelineno()-1,currentfilename,l1)
  381. m=includeline.match(origfinalline)
  382. if m:
  383. fn=m.group('name')
  384. if os.path.isfile(fn):
  385. readfortrancode(fn,dowithline=dowithline,istop=0)
  386. else:
  387. include_dirs = [os.path.dirname(currentfilename)] + include_paths
  388. foundfile = 0
  389. for inc_dir in include_dirs:
  390. fn1 = os.path.join(inc_dir,fn)
  391. if os.path.isfile(fn1):
  392. foundfile = 1
  393. readfortrancode(fn1,dowithline=dowithline,istop=0)
  394. break
  395. if not foundfile:
  396. outmess('readfortrancode: could not find include file %s. Ignoring.\n'%(`fn`))
  397. else:
  398. dowithline(finalline)
  399. l1=ll
  400. if localdolowercase:
  401. finalline=ll.lower()
  402. else: finalline=ll
  403. origfinalline = ll
  404. filepositiontext='Line #%d in %s:"%s"\n\t' % (fin.filelineno()-1,currentfilename,l1)
  405. m=includeline.match(origfinalline)
  406. if m:
  407. fn=m.group('name')
  408. fn1=os.path.join(os.path.dirname(currentfilename),fn)
  409. if os.path.isfile(fn):
  410. readfortrancode(fn,dowithline=dowithline,istop=0)
  411. elif os.path.isfile(fn1):
  412. readfortrancode(fn1,dowithline=dowithline,istop=0)
  413. else:
  414. outmess('readfortrancode: could not find include file %s. Ignoring.\n'%(`fn`))
  415. else:
  416. dowithline(finalline)
  417. filepositiontext=''
  418. fin.close()
  419. if istop: dowithline('',1)
  420. else:
  421. gotnextfile,filepositiontext,currentfilename,sourcecodeform,strictf77,\
  422. beginpattern,quiet,verbose,dolowercase=saveglobals
  423. ########### Crack line
  424. beforethisafter=r'\s*(?P<before>%s(?=\s*(\b(%s)\b)))'+ \
  425. r'\s*(?P<this>(\b(%s)\b))'+ \
  426. r'\s*(?P<after>%s)\s*\Z'
  427. ##
  428. fortrantypes='character|logical|integer|real|complex|double\s*(precision\s*(complex|)|complex)|type(?=\s*\([\w\s,=(*)]*\))|byte'
  429. typespattern=re.compile(beforethisafter%('',fortrantypes,fortrantypes,'.*'),re.I),'type'
  430. typespattern4implicit=re.compile(beforethisafter%('',fortrantypes+'|static|automatic|undefined',fortrantypes+'|static|automatic|undefined','.*'),re.I)
  431. #
  432. functionpattern=re.compile(beforethisafter%('([a-z]+[\w\s(=*+-/)]*?|)','function','function','.*'),re.I),'begin'
  433. subroutinepattern=re.compile(beforethisafter%('[a-z\s]*?','subroutine','subroutine','.*'),re.I),'begin'
  434. #modulepattern=re.compile(beforethisafter%('[a-z\s]*?','module','module','.*'),re.I),'begin'
  435. #
  436. groupbegins77=r'program|block\s*data'
  437. beginpattern77=re.compile(beforethisafter%('',groupbegins77,groupbegins77,'.*'),re.I),'begin'
  438. groupbegins90=groupbegins77+r'|module(?!\s*procedure)|python\s*module|interface|type(?!\s*\()'
  439. beginpattern90=re.compile(beforethisafter%('',groupbegins90,groupbegins90,'.*'),re.I),'begin'
  440. groupends=r'end|endprogram|endblockdata|endmodule|endpythonmodule|endinterface'
  441. endpattern=re.compile(beforethisafter%('',groupends,groupends,'[\w\s]*'),re.I),'end'
  442. #endifs='end\s*(if|do|where|select|while|forall)'
  443. endifs='(end\s*(if|do|where|select|while|forall))|(module\s*procedure)'
  444. endifpattern=re.compile(beforethisafter%('[\w]*?',endifs,endifs,'[\w\s]*'),re.I),'endif'
  445. #
  446. implicitpattern=re.compile(beforethisafter%('','implicit','implicit','.*'),re.I),'implicit'
  447. dimensionpattern=re.compile(beforethisafter%('','dimension|virtual','dimension|virtual','.*'),re.I),'dimension'
  448. externalpattern=re.compile(beforethisafter%('','external','external','.*'),re.I),'external'
  449. optionalpattern=re.compile(beforethisafter%('','optional','optional','.*'),re.I),'optional'
  450. requiredpattern=re.compile(beforethisafter%('','required','required','.*'),re.I),'required'
  451. publicpattern=re.compile(beforethisafter%('','public','public','.*'),re.I),'public'
  452. privatepattern=re.compile(beforethisafter%('','private','private','.*'),re.I),'private'
  453. intrisicpattern=re.compile(beforethisafter%('','intrisic','intrisic','.*'),re.I),'intrisic'
  454. intentpattern=re.compile(beforethisafter%('','intent|depend|note|check','intent|depend|note|check','\s*\(.*?\).*'),re.I),'intent'
  455. parameterpattern=re.compile(beforethisafter%('','parameter','parameter','\s*\(.*'),re.I),'parameter'
  456. datapattern=re.compile(beforethisafter%('','data','data','.*'),re.I),'data'
  457. callpattern=re.compile(beforethisafter%('','call','call','.*'),re.I),'call'
  458. entrypattern=re.compile(beforethisafter%('','entry','entry','.*'),re.I),'entry'
  459. callfunpattern=re.compile(beforethisafter%('','callfun','callfun','.*'),re.I),'callfun'
  460. commonpattern=re.compile(beforethisafter%('','common','common','.*'),re.I),'common'
  461. usepattern=re.compile(beforethisafter%('','use','use','.*'),re.I),'use'
  462. containspattern=re.compile(beforethisafter%('','contains','contains',''),re.I),'contains'
  463. formatpattern=re.compile(beforethisafter%('','format','format','.*'),re.I),'format'
  464. ## Non-fortran and f2py-specific statements
  465. f2pyenhancementspattern=re.compile(beforethisafter%('','threadsafe|fortranname|callstatement|callprotoargument|usercode|pymethoddef','threadsafe|fortranname|callstatement|callprotoargument|usercode|pymethoddef','.*'),re.I|re.S),'f2pyenhancements'
  466. multilinepattern = re.compile(r"\s*(?P<before>''')(?P<this>.*?)(?P<after>''')\s*\Z",re.S),'multiline'
  467. ##
  468. def _simplifyargs(argsline):
  469. a = []
  470. for n in markoutercomma(argsline).split('@,@'):
  471. for r in '(),':
  472. n = n.replace(r,'_')
  473. a.append(n)
  474. return ','.join(a)
  475. crackline_re_1 = re.compile(r'\s*(?P<result>\b[a-z]+[\w]*\b)\s*[=].*',re.I)
  476. def crackline(line,reset=0):
  477. """
  478. reset=-1 --- initialize
  479. reset=0 --- crack the line
  480. reset=1 --- final check if mismatch of blocks occured
  481. Cracked data is saved in grouplist[0].
  482. """
  483. global beginpattern,groupcounter,groupname,groupcache,grouplist,gotnextfile,\
  484. filepositiontext,currentfilename,neededmodule,expectbegin,skipblocksuntil,\
  485. skipemptyends,previous_context
  486. if ';' in line and not (f2pyenhancementspattern[0].match(line) or
  487. multilinepattern[0].match(line)):
  488. for l in line.split(';'):
  489. assert reset==0,`reset` # XXX: non-zero reset values need testing
  490. crackline(l,reset)
  491. return
  492. if reset<0:
  493. groupcounter=0
  494. groupname={groupcounter:''}
  495. groupcache={groupcounter:{}}
  496. grouplist={groupcounter:[]}
  497. groupcache[groupcounter]['body']=[]
  498. groupcache[groupcounter]['vars']={}
  499. groupcache[groupcounter]['block']=''
  500. groupcache[groupcounter]['name']=''
  501. neededmodule=-1
  502. skipblocksuntil=-1
  503. return
  504. if reset>0:
  505. fl=0
  506. if f77modulename and neededmodule==groupcounter: fl=2
  507. while groupcounter>fl:
  508. outmess('crackline: groupcounter=%s groupname=%s\n'%(`groupcounter`,`groupname`))
  509. outmess('crackline: Mismatch of blocks encountered. Trying to fix it by assuming "end" statement.\n')
  510. grouplist[groupcounter-1].append(groupcache[groupcounter])
  511. grouplist[groupcounter-1][-1]['body']=grouplist[groupcounter]
  512. del grouplist[groupcounter]
  513. groupcounter=groupcounter-1
  514. if f77modulename and neededmodule==groupcounter:
  515. grouplist[groupcounter-1].append(groupcache[groupcounter])
  516. grouplist[groupcounter-1][-1]['body']=grouplist[groupcounter]
  517. del grouplist[groupcounter]
  518. groupcounter=groupcounter-1 # end interface
  519. grouplist[groupcounter-1].append(groupcache[groupcounter])
  520. grouplist[groupcounter-1][-1]['body']=grouplist[groupcounter]
  521. del grouplist[groupcounter]
  522. groupcounter=groupcounter-1 # end module
  523. neededmodule=-1
  524. return
  525. if line=='': return
  526. flag=0
  527. for pat in [dimensionpattern,externalpattern,intentpattern,optionalpattern,
  528. requiredpattern,
  529. parameterpattern,datapattern,publicpattern,privatepattern,
  530. intrisicpattern,
  531. endifpattern,endpattern,
  532. formatpattern,
  533. beginpattern,functionpattern,subroutinepattern,
  534. implicitpattern,typespattern,commonpattern,
  535. callpattern,usepattern,containspattern,
  536. entrypattern,
  537. f2pyenhancementspattern,
  538. multilinepattern
  539. ]:
  540. m = pat[0].match(line)
  541. if m:
  542. break
  543. flag=flag+1
  544. if not m:
  545. re_1 = crackline_re_1
  546. if 0<=skipblocksuntil<=groupcounter:return
  547. if 'externals' in groupcache[groupcounter]:
  548. for name in groupcache[groupcounter]['externals']:
  549. if name in invbadnames:
  550. name=invbadnames[name]
  551. if 'interfaced' in groupcache[groupcounter] and name in groupcache[groupcounter]['interfaced']:
  552. continue
  553. m1=re.match(r'(?P<before>[^"]*)\b%s\b\s*@\(@(?P<args>[^@]*)@\)@.*\Z'%name,markouterparen(line),re.I)
  554. if m1:
  555. m2 = re_1.match(m1.group('before'))
  556. a = _simplifyargs(m1.group('args'))
  557. if m2:
  558. line='callfun %s(%s) result (%s)'%(name,a,m2.group('result'))
  559. else: line='callfun %s(%s)'%(name,a)
  560. m = callfunpattern[0].match(line)
  561. if not m:
  562. outmess('crackline: could not resolve function call for line=%s.\n'%`line`)
  563. return
  564. analyzeline(m,'callfun',line)
  565. return
  566. if verbose>1:
  567. previous_context = None
  568. outmess('crackline:%d: No pattern for line\n'%(groupcounter))
  569. return
  570. elif pat[1]=='end':
  571. if 0<=skipblocksuntil<groupcounter:
  572. groupcounter=groupcounter-1
  573. if skipblocksuntil<=groupcounter: return
  574. if groupcounter<=0:
  575. raise Exception('crackline: groupcounter(=%s) is nonpositive. '
  576. 'Check the blocks.' \
  577. % (groupcounter))
  578. m1 = beginpattern[0].match((line))
  579. if (m1) and (not m1.group('this')==groupname[groupcounter]):
  580. raise Exception('crackline: End group %s does not match with '
  581. 'previous Begin group %s\n\t%s' % \
  582. (`m1.group('this')`, `groupname[groupcounter]`,
  583. filepositiontext)
  584. )
  585. if skipblocksuntil==groupcounter:
  586. skipblocksuntil=-1
  587. grouplist[groupcounter-1].append(groupcache[groupcounter])
  588. grouplist[groupcounter-1][-1]['body']=grouplist[groupcounter]
  589. del grouplist[groupcounter]
  590. groupcounter=groupcounter-1
  591. if not skipemptyends:
  592. expectbegin=1
  593. elif pat[1] == 'begin':
  594. if 0<=skipblocksuntil<=groupcounter:
  595. groupcounter=groupcounter+1
  596. return
  597. gotnextfile=0
  598. analyzeline(m,pat[1],line)
  599. expectbegin=0
  600. elif pat[1]=='endif':
  601. pass
  602. elif pat[1]=='contains':
  603. if ignorecontains: return
  604. if 0<=skipblocksuntil<=groupcounter: return
  605. skipblocksuntil=groupcounter
  606. else:
  607. if 0<=skipblocksuntil<=groupcounter:return
  608. analyzeline(m,pat[1],line)
  609. def markouterparen(line):
  610. l='';f=0
  611. for c in line:
  612. if c=='(':
  613. f=f+1
  614. if f==1: l=l+'@(@'; continue
  615. elif c==')':
  616. f=f-1
  617. if f==0: l=l+'@)@'; continue
  618. l=l+c
  619. return l
  620. def markoutercomma(line,comma=','):
  621. l='';f=0
  622. cc=''
  623. for c in line:
  624. if (not cc or cc==')') and c=='(':
  625. f=f+1
  626. cc = ')'
  627. elif not cc and c=='\'' and (not l or l[-1]!='\\'):
  628. f=f+1
  629. cc = '\''
  630. elif c==cc:
  631. f=f-1
  632. if f==0:
  633. cc=''
  634. elif c==comma and f==0:
  635. l=l+'@'+comma+'@'
  636. continue
  637. l=l+c
  638. assert not f,`f,line,l,cc`
  639. return l
  640. def unmarkouterparen(line):
  641. r = line.replace('@(@','(').replace('@)@',')')
  642. return r
  643. def appenddecl(decl,decl2,force=1):
  644. if not decl: decl={}
  645. if not decl2: return decl
  646. if decl is decl2: return decl
  647. for k in decl2.keys():
  648. if k=='typespec':
  649. if force or k not in decl:
  650. decl[k]=decl2[k]
  651. elif k=='attrspec':
  652. for l in decl2[k]:
  653. decl=setattrspec(decl,l,force)
  654. elif k=='kindselector':
  655. decl=setkindselector(decl,decl2[k],force)
  656. elif k=='charselector':
  657. decl=setcharselector(decl,decl2[k],force)
  658. elif k in ['=','typename']:
  659. if force or k not in decl:
  660. decl[k]=decl2[k]
  661. elif k=='note':
  662. pass
  663. elif k in ['intent','check','dimension','optional','required']:
  664. errmess('appenddecl: "%s" not implemented.\n'%k)
  665. else:
  666. raise Exception('appenddecl: Unknown variable definition key:' + \
  667. str(k))
  668. return decl
  669. selectpattern=re.compile(r'\s*(?P<this>(@\(@.*?@\)@|[*][\d*]+|[*]\s*@\(@.*?@\)@|))(?P<after>.*)\Z',re.I)
  670. 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*@\)@|))*\s*\Z',re.I)
  671. callnameargspattern=re.compile(r'\s*(?P<name>\b[\w$]+\b)\s*@\(@\s*(?P<args>.*)\s*@\)@\s*\Z',re.I)
  672. real16pattern = re.compile(r'([-+]?(?:\d+(?:\.\d*)?|\d*\.\d+))[dD]((?:[-+]?\d+)?)')
  673. real8pattern = re.compile(r'([-+]?((?:\d+(?:\.\d*)?|\d*\.\d+))[eE]((?:[-+]?\d+)?)|(\d+\.\d*))')
  674. _intentcallbackpattern = re.compile(r'intent\s*\(.*?\bcallback\b',re.I)
  675. def _is_intent_callback(vdecl):
  676. for a in vdecl.get('attrspec',[]):
  677. if _intentcallbackpattern.match(a):
  678. return 1
  679. return 0
  680. def _resolvenameargspattern(line):
  681. line = markouterparen(line)
  682. m1=nameargspattern.match(line)
  683. if m1: return m1.group('name'),m1.group('args'),m1.group('result')
  684. m1=callnameargspattern.match(line)
  685. if m1: return m1.group('name'),m1.group('args'),None
  686. return None,[],None
  687. def analyzeline(m,case,line):
  688. global groupcounter,groupname,groupcache,grouplist,filepositiontext,\
  689. currentfilename,f77modulename,neededinterface,neededmodule,expectbegin,\
  690. gotnextfile,previous_context
  691. block=m.group('this')
  692. if case != 'multiline':
  693. previous_context = None
  694. if expectbegin and case not in ['begin','call','callfun','type'] \
  695. and not skipemptyends and groupcounter<1:
  696. newname=os.path.basename(currentfilename).split('.')[0]
  697. outmess('analyzeline: no group yet. Creating program group with name "%s".\n'%newname)
  698. gotnextfile=0
  699. groupcounter=groupcounter+1
  700. groupname[groupcounter]='program'
  701. groupcache[groupcounter]={}
  702. grouplist[groupcounter]=[]
  703. groupcache[groupcounter]['body']=[]
  704. groupcache[groupcounter]['vars']={}
  705. groupcache[groupcounter]['block']='program'
  706. groupcache[groupcounter]['name']=newname
  707. groupcache[groupcounter]['from']='fromsky'
  708. expectbegin=0
  709. if case in ['begin','call','callfun']:
  710. # Crack line => block,name,args,result
  711. block = block.lower()
  712. if re.match(r'block\s*data',block,re.I): block='block data'
  713. if re.match(r'python\s*module',block,re.I): block='python module'
  714. name,args,result = _resolvenameargspattern(m.group('after'))
  715. if name is None:
  716. if block=='block data':
  717. name = '_BLOCK_DATA_'
  718. else:
  719. name = ''
  720. if block not in ['interface','block data']:
  721. outmess('analyzeline: No name/args pattern found for line.\n')
  722. previous_context = (block,name,groupcounter)
  723. if args: args=rmbadname([x.strip() for x in markoutercomma(args).split('@,@')])
  724. else: args=[]
  725. if '' in args:
  726. while '' in args:
  727. args.remove('')
  728. outmess('analyzeline: argument list is malformed (missing argument).\n')
  729. # end of crack line => block,name,args,result
  730. needmodule=0
  731. needinterface=0
  732. if case in ['call','callfun']:
  733. needinterface=1
  734. if 'args' not in groupcache[groupcounter]:
  735. return
  736. if name not in groupcache[groupcounter]['args']:
  737. return
  738. for it in grouplist[groupcounter]:
  739. if it['name']==name:
  740. return
  741. if name in groupcache[groupcounter]['interfaced']:
  742. return
  743. block={'call':'subroutine','callfun':'function'}[case]
  744. if f77modulename and neededmodule==-1 and groupcounter<=1:
  745. neededmodule=groupcounter+2
  746. needmodule=1
  747. needinterface=1
  748. # Create new block(s)
  749. groupcounter=groupcounter+1
  750. groupcache[groupcounter]={}
  751. grouplist[groupcounter]=[]
  752. if needmodule:
  753. if verbose>1:
  754. outmess('analyzeline: Creating module block %s\n'%`f77modulename`,0)
  755. groupname[groupcounter]='module'
  756. groupcache[groupcounter]['block']='python module'
  757. groupcache[groupcounter]['name']=f77modulename
  758. groupcache[groupcounter]['from']=''
  759. groupcache[groupcounter]['body']=[]
  760. groupcache[groupcounter]['externals']=[]
  761. groupcache[groupcounter]['interfaced']=[]
  762. groupcache[groupcounter]['vars']={}
  763. groupcounter=groupcounter+1
  764. groupcache[groupcounter]={}
  765. grouplist[groupcounter]=[]
  766. if needinterface:
  767. if verbose>1:
  768. outmess('analyzeline: Creating additional interface block (groupcounter=%s).\n' % (groupcounter),0)
  769. groupname[groupcounter]='interface'
  770. groupcache[groupcounter]['block']='interface'
  771. groupcache[groupcounter]['name']='unknown_interface'
  772. groupcache[groupcounter]['from']='%s:%s'%(groupcache[groupcounter-1]['from'],groupcache[groupcounter-1]['name'])
  773. groupcache[groupcounter]['body']=[]
  774. groupcache[groupcounter]['externals']=[]
  775. groupcache[groupcounter]['interfaced']=[]
  776. groupcache[groupcounter]['vars']={}
  777. groupcounter=groupcounter+1
  778. groupcache[groupcounter]={}
  779. grouplist[groupcounter]=[]
  780. groupname[groupcounter]=block
  781. groupcache[groupcounter]['block']=block
  782. if not name: name='unknown_'+block
  783. groupcache[groupcounter]['prefix']=m.group('before')
  784. groupcache[groupcounter]['name']=rmbadname1(name)
  785. groupcache[groupcounter]['result']=result
  786. if groupcounter==1:
  787. groupcache[groupcounter]['from']=currentfilename
  788. else:
  789. if f77modulename and groupcounter==3:
  790. groupcache[groupcounter]['from']='%s:%s'%(groupcache[groupcounter-1]['from'],currentfilename)
  791. else:
  792. groupcache[groupcounter]['from']='%s:%s'%(groupcache[groupcounter-1]['from'],groupcache[groupcounter-1]['name'])
  793. for k in groupcache[groupcounter].keys():
  794. if not groupcache[groupcounter][k]: del groupcache[groupcounter][k]
  795. groupcache[groupcounter]['args']=args
  796. groupcache[groupcounter]['body']=[]
  797. groupcache[groupcounter]['externals']=[]
  798. groupcache[groupcounter]['interfaced']=[]
  799. groupcache[groupcounter]['vars']={}
  800. groupcache[groupcounter]['entry']={}
  801. # end of creation
  802. if block=='type':
  803. groupcache[groupcounter]['varnames'] = []
  804. if case in ['call','callfun']: # set parents variables
  805. if name not in groupcache[groupcounter-2]['externals']:
  806. groupcache[groupcounter-2]['externals'].append(name)
  807. groupcache[groupcounter]['vars']=copy.deepcopy(groupcache[groupcounter-2]['vars'])
  808. #try: del groupcache[groupcounter]['vars'][groupcache[groupcounter-2]['name']]
  809. #except: pass
  810. try: del groupcache[groupcounter]['vars'][name][groupcache[groupcounter]['vars'][name]['attrspec'].index('external')]
  811. except: pass
  812. if block in ['function','subroutine']: # set global attributes
  813. try: groupcache[groupcounter]['vars'][name]=appenddecl(groupcache[groupcounter]['vars'][name],groupcache[groupcounter-2]['vars'][''])
  814. except: pass
  815. if case=='callfun': # return type
  816. if result and result in groupcache[groupcounter]['vars']:
  817. if not name==result:
  818. groupcache[groupcounter]['vars'][name]=appenddecl(groupcache[groupcounter]['vars'][name],groupcache[groupcounter]['vars'][result])
  819. #if groupcounter>1: # name is interfaced
  820. try: groupcache[groupcounter-2]['interfaced'].append(name)
  821. except: pass
  822. if block=='function':
  823. t=typespattern[0].match(m.group('before')+' '+name)
  824. if t:
  825. typespec,selector,attr,edecl=cracktypespec0(t.group('this'),t.group('after'))
  826. updatevars(typespec,selector,attr,edecl)
  827. if case in ['call','callfun']:
  828. grouplist[groupcounter-1].append(groupcache[groupcounter])
  829. grouplist[groupcounter-1][-1]['body']=grouplist[groupcounter]
  830. del grouplist[groupcounter]
  831. groupcounter=groupcounter-1 # end routine
  832. grouplist[groupcounter-1].append(groupcache[groupcounter])
  833. grouplist[groupcounter-1][-1]['body']=grouplist[groupcounter]
  834. del grouplist[groupcounter]
  835. groupcounter=groupcounter-1 # end interface
  836. elif case=='entry':
  837. name,args,result=_resolvenameargspattern(m.group('after'))
  838. if name is not None:
  839. if args:
  840. args=rmbadname([x.strip() for x in markoutercomma(args).split('@,@')])
  841. else: args=[]
  842. assert result is None,`result`
  843. groupcache[groupcounter]['entry'][name] = args
  844. previous_context = ('entry',name,groupcounter)
  845. elif case=='type':
  846. typespec,selector,attr,edecl=cracktypespec0(block,m.group('after'))
  847. last_name = updatevars(typespec,selector,attr,edecl)
  848. if last_name is not None:
  849. previous_context = ('variable',last_name,groupcounter)
  850. elif case in ['dimension','intent','optional','required','external','public','private','intrisic']:
  851. edecl=groupcache[groupcounter]['vars']
  852. ll=m.group('after').strip()
  853. i=ll.find('::')
  854. if i<0 and case=='intent':
  855. i=markouterparen(ll).find('@)@')-2
  856. ll=ll[:i+1]+'::'+ll[i+1:]
  857. i=ll.find('::')
  858. if ll[i:]=='::' and 'args' in groupcache[groupcounter]:
  859. outmess('All arguments will have attribute %s%s\n'%(m.group('this'),ll[:i]))
  860. ll = ll + ','.join(groupcache[groupcounter]['args'])
  861. if i<0:i=0;pl=''
  862. else: pl=ll[:i].strip();ll=ll[i+2:]
  863. ch = markoutercomma(pl).split('@,@')
  864. if len(ch)>1:
  865. pl = ch[0]
  866. outmess('analyzeline: cannot handle multiple attributes without type specification. Ignoring %r.\n' % (','.join(ch[1:])))
  867. last_name = None
  868. for e in [x.strip() for x in markoutercomma(ll).split('@,@')]:
  869. m1=namepattern.match(e)
  870. if not m1:
  871. if case in ['public','private']: k=''
  872. else:
  873. print m.groupdict()
  874. outmess('analyzeline: no name pattern found in %s statement for %s. Skipping.\n'%(case,`e`))
  875. continue
  876. else:
  877. k=rmbadname1(m1.group('name'))
  878. if k not in edecl:
  879. edecl[k]={}
  880. if case=='dimension':
  881. ap=case+m1.group('after')
  882. if case=='intent':
  883. ap=m.group('this')+pl
  884. if _intentcallbackpattern.match(ap):
  885. if k not in groupcache[groupcounter]['args']:
  886. if groupcounter>1:
  887. outmess('analyzeline: appending intent(callback) %s'\
  888. ' to %s arguments\n' % (k,groupcache[groupcounter]['name']))
  889. if '__user__' not in groupcache[groupcounter-2]['name']:
  890. outmess('analyzeline: missing __user__ module (could be nothing)\n')
  891. groupcache[groupcounter]['args'].append(k)
  892. else:
  893. errmess('analyzeline: intent(callback) %s is ignored' % (k))
  894. else:
  895. errmess('analyzeline: intent(callback) %s is already'\
  896. ' in argument list' % (k))
  897. if case in ['optional','required','public','external','private','intrisic']:
  898. ap=case
  899. if 'attrspec' in edecl[k]:
  900. edecl[k]['attrspec'].append(ap)
  901. else:
  902. edecl[k]['attrspec']=[ap]
  903. if case=='external':
  904. if groupcache[groupcounter]['block']=='program':
  905. outmess('analyzeline: ignoring program arguments\n')
  906. continue
  907. if k not in groupcache[groupcounter]['args']:
  908. #outmess('analyzeline: ignoring external %s (not in arguments list)\n'%(`k`))
  909. continue
  910. if 'externals' not in groupcache[groupcounter]:
  911. groupcache[groupcounter]['externals']=[]
  912. groupcache[groupcounter]['externals'].append(k)
  913. last_name = k
  914. groupcache[groupcounter]['vars']=edecl
  915. if last_name is not None:
  916. previous_context = ('variable',last_name,groupcounter)
  917. elif case=='parameter':
  918. edecl=groupcache[groupcounter]['vars']
  919. ll=m.group('after').strip()[1:-1]
  920. last_name = None
  921. for e in markoutercomma(ll).split('@,@'):
  922. try:
  923. k,initexpr=[x.strip() for x in e.split('=')]
  924. except:
  925. outmess('analyzeline: could not extract name,expr in parameter statement "%s" of "%s"\n'%(e,ll));continue
  926. params = get_parameters(edecl)
  927. k=rmbadname1(k)
  928. if k not in edecl:
  929. edecl[k]={}
  930. if '=' in edecl[k] and (not edecl[k]['=']==initexpr):
  931. outmess('analyzeline: Overwriting the value of parameter "%s" ("%s") with "%s".\n'%(k,edecl[k]['='],initexpr))
  932. t = determineexprtype(initexpr,params)
  933. if t:
  934. if t.get('typespec')=='real':
  935. tt = list(initexpr)
  936. for m in real16pattern.finditer(initexpr):
  937. tt[m.start():m.end()] = list(\
  938. initexpr[m.start():m.end()].lower().replace('d', 'e'))
  939. initexpr = ''.join(tt)
  940. elif t.get('typespec')=='complex':
  941. initexpr = initexpr[1:].lower().replace('d','e').\
  942. replace(',','+1j*(')
  943. try:
  944. v = eval(initexpr,{},params)
  945. except (SyntaxError,NameError,TypeError),msg:
  946. errmess('analyzeline: Failed to evaluate %r. Ignoring: %s\n'\
  947. % (initexpr, msg))
  948. continue
  949. edecl[k]['='] = repr(v)
  950. if 'attrspec' in edecl[k]:
  951. edecl[k]['attrspec'].append('parameter')
  952. else: edecl[k]['attrspec']=['parameter']
  953. last_name = k
  954. groupcache[groupcounter]['vars']=edecl
  955. if last_name is not None:
  956. previous_context = ('variable',last_name,groupcounter)
  957. elif case=='implicit':
  958. if m.group('after').strip().lower()=='none':
  959. groupcache[groupcounter]['implicit']=None
  960. elif m.group('after'):
  961. if 'implicit' in groupcache[groupcounter]:
  962. impl=groupcache[groupcounter]['implicit']
  963. else: impl={}
  964. if impl is None:
  965. outmess('analyzeline: Overwriting earlier "implicit none" statement.\n')
  966. impl={}
  967. for e in markoutercomma(m.group('after')).split('@,@'):
  968. decl={}
  969. m1=re.match(r'\s*(?P<this>.*?)\s*(\(\s*(?P<after>[a-z-, ]+)\s*\)\s*|)\Z',e,re.I)
  970. if not m1:
  971. outmess('analyzeline: could not extract info of implicit statement part "%s"\n'%(e));continue
  972. m2=typespattern4implicit.match(m1.group('this'))
  973. if not m2:
  974. outmess('analyzeline: could not extract types pattern of implicit statement part "%s"\n'%(e));continue
  975. typespec,selector,attr,edecl=cracktypespec0(m2.group('this'),m2.group('after'))
  976. kindselect,charselect,typename=cracktypespec(typespec,selector)
  977. decl['typespec']=typespec
  978. decl['kindselector']=kindselect
  979. decl['charselector']=charselect
  980. decl['typename']=typename
  981. for k in decl.keys():
  982. if not decl[k]: del decl[k]
  983. for r in markoutercomma(m1.group('after')).split('@,@'):
  984. if '-' in r:
  985. try: begc,endc=[x.strip() for x in r.split('-')]
  986. except:
  987. outmess('analyzeline: expected "<char>-<char>" instead of "%s" in range list of implicit statement\n'%r);continue
  988. else: begc=endc=r.strip()
  989. if not len(begc)==len(endc)==1:
  990. outmess('analyzeline: expected "<char>-<char>" instead of "%s" in range list of implicit statement (2)\n'%r);continue
  991. for o in range(ord(begc),ord(endc)+1):
  992. impl[chr(o)]=decl
  993. groupcache[groupcounter]['implicit']=impl
  994. elif case=='data':
  995. ll=[]
  996. dl='';il='';f=0;fc=1;inp=0
  997. for c in m.group('after'):
  998. if not inp:
  999. if c=="'": fc=not fc
  1000. if c=='/' and fc: f=f+1;continue
  1001. if c=='(': inp = inp + 1
  1002. elif c==')': inp = inp - 1
  1003. if f==0: dl=dl+c
  1004. elif f==1: il=il+c
  1005. elif f==2:
  1006. dl = dl.strip()
  1007. if dl.startswith(','):
  1008. dl = dl[1:].strip()
  1009. ll.append([dl,il])
  1010. dl=c;il='';f=0
  1011. if f==2:
  1012. dl = dl.strip()
  1013. if dl.startswith(','):
  1014. dl = dl[1:].strip()
  1015. ll.append([dl,il])
  1016. vars={}
  1017. if 'vars' in groupcache[groupcounter]:
  1018. vars=groupcache[groupcounter]['vars']
  1019. last_name = None
  1020. for l in ll:
  1021. l=[x.strip() for x in l]
  1022. if l[0][0]==',':l[0]=l[0][1:]
  1023. if l[0][0]=='(':
  1024. outmess('analyzeline: implied-DO list "%s" is not supported. Skipping.\n'%l[0])
  1025. continue
  1026. #if '(' in l[0]:
  1027. # #outmess('analyzeline: ignoring this data statement.\n')
  1028. # continue
  1029. i=0;j=0;llen=len(l[1])
  1030. for v in rmbadname([x.strip() for x in markoutercomma(l[0]).split('@,@')]):
  1031. if v[0]=='(':
  1032. outmess('analyzeline: implied-DO list "%s" is not supported. Skipping.\n'%v)
  1033. # XXX: subsequent init expressions may get wrong values.
  1034. # Ignoring since data statements are irrelevant for wrapping.
  1035. continue
  1036. fc=0
  1037. while (i<llen) and (fc or not l[1][i]==','):
  1038. if l[1][i]=="'": fc=not fc
  1039. i=i+1
  1040. i=i+1
  1041. #v,l[1][j:i-1]=name,initvalue
  1042. if v not in vars:
  1043. vars[v]={}
  1044. if '=' in vars[v] and not vars[v]['=']==l[1][j:i-1]:
  1045. outmess('analyzeline: changing init expression of "%s" ("%s") to "%s"\n'%(v,vars[v]['='],l[1][j:i-1]))
  1046. vars[v]['=']=l[1][j:i-1]
  1047. j=i
  1048. last_name = v
  1049. groupcache[groupcounter]['vars']=vars
  1050. if last_name is not None:
  1051. previous_context = ('variable',last_name,groupcounter)
  1052. elif case=='common':
  1053. line=m.group('after').strip()
  1054. if not line[0]=='/':line='//'+line
  1055. cl=[]
  1056. f=0;bn='';ol=''
  1057. for c in line:
  1058. if c=='/':f=f+1;continue
  1059. if f>=3:
  1060. bn = bn.strip()
  1061. if not bn: bn='_BLNK_'
  1062. cl.append([bn,ol])
  1063. f=f-2;bn='';ol=''
  1064. if f%2: bn=bn+c
  1065. else: ol=ol+c
  1066. bn = bn.strip()
  1067. if not bn: bn='_BLNK_'
  1068. cl.append([bn,ol])
  1069. commonkey={}
  1070. if 'common' in groupcache[groupcounter]:
  1071. commonkey=groupcache[groupcounter]['common']
  1072. for c in cl:
  1073. if c[0] in commonkey:
  1074. outmess('analyzeline: previously defined common block encountered. Skipping.\n')
  1075. continue
  1076. commonkey[c[0]]=[]
  1077. for i in [x.strip() for x in markoutercomma(c[1]).split('@,@')]:
  1078. if i: common

Large files files are truncated, but you can click here to view the full file