Mercurial > hg > vamp-build-and-test
comparison DEPENDENCIES/mingw32/Python27/Lib/site-packages/numpy/f2py/crackfortran.py @ 87:2a2c65a20a8b
Add Python libs and headers
author | Chris Cannam |
---|---|
date | Wed, 25 Feb 2015 14:05:22 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
86:413a9d26189e | 87:2a2c65a20a8b |
---|---|
1 #!/usr/bin/env python | |
2 """ | |
3 crackfortran --- read fortran (77,90) code and extract declaration information. | |
4 | |
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 | |
10 NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. | |
11 $Date: 2005/09/27 07:13:49 $ | |
12 Pearu Peterson | |
13 | |
14 | |
15 Usage of crackfortran: | |
16 ====================== | |
17 Command line keys: -quiet,-verbose,-fix,-f77,-f90,-show,-h <pyffilename> | |
18 -m <module name for f77 routines>,--ignore-contains | |
19 Functions: crackfortran, crack2fortran | |
20 The following Fortran statements/constructions are supported | |
21 (or will be if needed): | |
22 block data,byte,call,character,common,complex,contains,data, | |
23 dimension,double complex,double precision,end,external,function, | |
24 implicit,integer,intent,interface,intrinsic, | |
25 logical,module,optional,parameter,private,public, | |
26 program,real,(sequence?),subroutine,type,use,virtual, | |
27 include,pythonmodule | |
28 Note: 'virtual' is mapped to 'dimension'. | |
29 Note: 'implicit integer (z) static (z)' is 'implicit static (z)' (this is minor bug). | |
30 Note: code after 'contains' will be ignored until its scope ends. | |
31 Note: 'common' statement is extended: dimensions are moved to variable definitions | |
32 Note: f2py directive: <commentchar>f2py<line> is read as <line> | |
33 Note: pythonmodule is introduced to represent Python module | |
34 | |
35 Usage: | |
36 `postlist=crackfortran(files,funcs)` | |
37 `postlist` contains declaration information read from the list of files `files`. | |
38 `crack2fortran(postlist)` returns a fortran code to be saved to pyf-file | |
39 | |
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 B['saved_interface'] --- a string of scanned routine signature, defines explicit interface | |
76 *** Variable definition is a dictionary | |
77 D = B['vars'][<variable name>] = | |
78 {'typespec'[,'attrspec','kindselector','charselector','=','typename']} | |
79 D['typespec'] = 'byte' | 'character' | 'complex' | 'double complex' | | |
80 'double precision' | 'integer' | 'logical' | 'real' | 'type' | |
81 D['attrspec'] --- list of attributes (e.g. 'dimension(<arrayspec>)', | |
82 'external','intent(in|out|inout|hide|c|callback|cache|aligned4|aligned8|aligned16)', | |
83 'optional','required', etc) | |
84 K = D['kindselector'] = {['*','kind']} (only if D['typespec'] = | |
85 'complex' | 'integer' | 'logical' | 'real' ) | |
86 C = D['charselector'] = {['*','len','kind']} | |
87 (only if D['typespec']=='character') | |
88 D['='] --- initialization expression string | |
89 D['typename'] --- name of the type if D['typespec']=='type' | |
90 D['dimension'] --- list of dimension bounds | |
91 D['intent'] --- list of intent specifications | |
92 D['depend'] --- list of variable names on which current variable depends on | |
93 D['check'] --- list of C-expressions; if C-expr returns zero, exception is raised | |
94 D['note'] --- list of LaTeX comments on the variable | |
95 *** Meaning of kind/char selectors (few examples): | |
96 D['typespec>']*K['*'] | |
97 D['typespec'](kind=K['kind']) | |
98 character*C['*'] | |
99 character(len=C['len'],kind=C['kind']) | |
100 (see also fortran type declaration statement formats below) | |
101 | |
102 Fortran 90 type declaration statement format (F77 is subset of F90) | |
103 ==================================================================== | |
104 (Main source: IBM XL Fortran 5.1 Language Reference Manual) | |
105 type declaration = <typespec> [[<attrspec>]::] <entitydecl> | |
106 <typespec> = byte | | |
107 character[<charselector>] | | |
108 complex[<kindselector>] | | |
109 double complex | | |
110 double precision | | |
111 integer[<kindselector>] | | |
112 logical[<kindselector>] | | |
113 real[<kindselector>] | | |
114 type(<typename>) | |
115 <charselector> = * <charlen> | | |
116 ([len=]<len>[,[kind=]<kind>]) | | |
117 (kind=<kind>[,len=<len>]) | |
118 <kindselector> = * <intlen> | | |
119 ([kind=]<kind>) | |
120 <attrspec> = comma separated list of attributes. | |
121 Only the following attributes are used in | |
122 building up the interface: | |
123 external | |
124 (parameter --- affects '=' key) | |
125 optional | |
126 intent | |
127 Other attributes are ignored. | |
128 <intentspec> = in | out | inout | |
129 <arrayspec> = comma separated list of dimension bounds. | |
130 <entitydecl> = <name> [[*<charlen>][(<arrayspec>)] | [(<arrayspec>)]*<charlen>] | |
131 [/<init_expr>/ | =<init_expr>] [,<entitydecl>] | |
132 | |
133 In addition, the following attributes are used: check,depend,note | |
134 | |
135 TODO: | |
136 * Apply 'parameter' attribute (e.g. 'integer parameter :: i=2' 'real x(i)' | |
137 -> 'real x(2)') | |
138 The above may be solved by creating appropriate preprocessor program, for example. | |
139 | |
140 """ | |
141 from __future__ import division, absolute_import, print_function | |
142 | |
143 import sys | |
144 import string | |
145 import fileinput | |
146 import re | |
147 import pprint | |
148 import os | |
149 import copy | |
150 import platform | |
151 | |
152 from . import __version__ | |
153 from .auxfuncs import * | |
154 | |
155 f2py_version = __version__.version | |
156 | |
157 # Global flags: | |
158 strictf77=1 # Ignore `!' comments unless line[0]=='!' | |
159 sourcecodeform='fix' # 'fix','free' | |
160 quiet=0 # Be verbose if 0 (Obsolete: not used any more) | |
161 verbose=1 # Be quiet if 0, extra verbose if > 1. | |
162 tabchar=4*' ' | |
163 pyffilename='' | |
164 f77modulename='' | |
165 skipemptyends=0 # for old F77 programs without 'program' statement | |
166 ignorecontains=1 | |
167 dolowercase=1 | |
168 debug=[] | |
169 | |
170 # Global variables | |
171 groupcounter=0 | |
172 grouplist={groupcounter:[]} | |
173 neededmodule=-1 | |
174 expectbegin=1 | |
175 skipblocksuntil=-1 | |
176 usermodules=[] | |
177 f90modulevars={} | |
178 gotnextfile=1 | |
179 filepositiontext='' | |
180 currentfilename='' | |
181 skipfunctions=[] | |
182 skipfuncs=[] | |
183 onlyfuncs=[] | |
184 include_paths=[] | |
185 previous_context = None | |
186 | |
187 | |
188 def reset_global_f2py_vars(): | |
189 global groupcounter, grouplist, neededmodule, expectbegin, \ | |
190 skipblocksuntil, usermodules, f90modulevars, gotnextfile, \ | |
191 filepositiontext, currentfilename, skipfunctions, skipfuncs, \ | |
192 onlyfuncs, include_paths, previous_context, \ | |
193 strictf77, sourcecodeform, quiet, verbose, tabchar, pyffilename, \ | |
194 f77modulename, skipemptyends, ignorecontains, dolowercase, debug | |
195 | |
196 # flags | |
197 strictf77 = 1 | |
198 sourcecodeform = 'fix' | |
199 quiet = 0 | |
200 verbose = 1 | |
201 tabchar = 4*' ' | |
202 pyffilename = '' | |
203 f77modulename = '' | |
204 skipemptyends = 0 | |
205 ignorecontains = 1 | |
206 dolowercase = 1 | |
207 debug = [] | |
208 # variables | |
209 groupcounter = 0 | |
210 grouplist = {groupcounter:[]} | |
211 neededmodule =-1 | |
212 expectbegin = 1 | |
213 skipblocksuntil = -1 | |
214 usermodules = [] | |
215 f90modulevars = {} | |
216 gotnextfile = 1 | |
217 filepositiontext = '' | |
218 currentfilename = '' | |
219 skipfunctions = [] | |
220 skipfuncs = [] | |
221 onlyfuncs = [] | |
222 include_paths = [] | |
223 previous_context = None | |
224 | |
225 | |
226 ###### Some helper functions | |
227 def show(o,f=0):pprint.pprint(o) | |
228 errmess=sys.stderr.write | |
229 def outmess(line,flag=1): | |
230 global filepositiontext | |
231 if not verbose: return | |
232 if not quiet: | |
233 if flag:sys.stdout.write(filepositiontext) | |
234 sys.stdout.write(line) | |
235 re._MAXCACHE=50 | |
236 defaultimplicitrules={} | |
237 for c in "abcdefghopqrstuvwxyz$_": defaultimplicitrules[c]={'typespec':'real'} | |
238 for c in "ijklmn": defaultimplicitrules[c]={'typespec':'integer'} | |
239 del c | |
240 badnames={} | |
241 invbadnames={} | |
242 for n in ['int', 'double', 'float', 'char', 'short', 'long', 'void', 'case', 'while', | |
243 'return', 'signed', 'unsigned', 'if', 'for', 'typedef', 'sizeof', 'union', | |
244 'struct', 'static', 'register', 'new', 'break', 'do', 'goto', 'switch', | |
245 'continue', 'else', 'inline', 'extern', 'delete', 'const', 'auto', | |
246 'len', 'rank', 'shape', 'index', 'slen', 'size', '_i', | |
247 'max', 'min', | |
248 'flen', 'fshape', | |
249 'string', 'complex_double', 'float_double', 'stdin', 'stderr', 'stdout', | |
250 'type', 'default']: | |
251 badnames[n]=n+'_bn' | |
252 invbadnames[n+'_bn']=n | |
253 | |
254 def rmbadname1(name): | |
255 if name in badnames: | |
256 errmess('rmbadname1: Replacing "%s" with "%s".\n'%(name, badnames[name])) | |
257 return badnames[name] | |
258 return name | |
259 | |
260 def rmbadname(names): return [rmbadname1(_m) for _m in names] | |
261 | |
262 def undo_rmbadname1(name): | |
263 if name in invbadnames: | |
264 errmess('undo_rmbadname1: Replacing "%s" with "%s".\n'\ | |
265 %(name, invbadnames[name])) | |
266 return invbadnames[name] | |
267 return name | |
268 | |
269 def undo_rmbadname(names): return [undo_rmbadname1(_m) for _m in names] | |
270 | |
271 def getextension(name): | |
272 i=name.rfind('.') | |
273 if i==-1: return '' | |
274 if '\\' in name[i:]: return '' | |
275 if '/' in name[i:]: return '' | |
276 return name[i+1:] | |
277 | |
278 is_f_file = re.compile(r'.*[.](for|ftn|f77|f)\Z', re.I).match | |
279 _has_f_header = re.compile(r'-[*]-\s*fortran\s*-[*]-', re.I).search | |
280 _has_f90_header = re.compile(r'-[*]-\s*f90\s*-[*]-', re.I).search | |
281 _has_fix_header = re.compile(r'-[*]-\s*fix\s*-[*]-', re.I).search | |
282 _free_f90_start = re.compile(r'[^c*]\s*[^\s\d\t]', re.I).match | |
283 def is_free_format(file): | |
284 """Check if file is in free format Fortran.""" | |
285 # f90 allows both fixed and free format, assuming fixed unless | |
286 # signs of free format are detected. | |
287 result = 0 | |
288 f = open(file, 'r') | |
289 line = f.readline() | |
290 n = 15 # the number of non-comment lines to scan for hints | |
291 if _has_f_header(line): | |
292 n = 0 | |
293 elif _has_f90_header(line): | |
294 n = 0 | |
295 result = 1 | |
296 while n>0 and line: | |
297 if line[0]!='!' and line.strip(): | |
298 n -= 1 | |
299 if (line[0]!='\t' and _free_f90_start(line[:5])) or line[-2:-1]=='&': | |
300 result = 1 | |
301 break | |
302 line = f.readline() | |
303 f.close() | |
304 return result | |
305 | |
306 | |
307 ####### Read fortran (77,90) code | |
308 def readfortrancode(ffile,dowithline=show,istop=1): | |
309 """ | |
310 Read fortran codes from files and | |
311 1) Get rid of comments, line continuations, and empty lines; lower cases. | |
312 2) Call dowithline(line) on every line. | |
313 3) Recursively call itself when statement \"include '<filename>'\" is met. | |
314 """ | |
315 global gotnextfile, filepositiontext, currentfilename, sourcecodeform, strictf77,\ | |
316 beginpattern, quiet, verbose, dolowercase, include_paths | |
317 if not istop: | |
318 saveglobals=gotnextfile, filepositiontext, currentfilename, sourcecodeform, strictf77,\ | |
319 beginpattern, quiet, verbose, dolowercase | |
320 if ffile==[]: return | |
321 localdolowercase = dolowercase | |
322 cont=0 | |
323 finalline='' | |
324 ll='' | |
325 commentline=re.compile(r'(?P<line>([^"]*["][^"]*["][^"!]*|[^\']*\'[^\']*\'[^\'!]*|[^!\'"]*))!{1}(?P<rest>.*)') | |
326 includeline=re.compile(r'\s*include\s*(\'|")(?P<name>[^\'"]*)(\'|")', re.I) | |
327 cont1=re.compile(r'(?P<line>.*)&\s*\Z') | |
328 cont2=re.compile(r'(\s*&|)(?P<line>.*)') | |
329 mline_mark = re.compile(r".*?'''") | |
330 if istop: dowithline('', -1) | |
331 ll, l1='', '' | |
332 spacedigits=[' '] + [str(_m) for _m in range(10)] | |
333 filepositiontext='' | |
334 fin=fileinput.FileInput(ffile) | |
335 while True: | |
336 l=fin.readline() | |
337 if not l: break | |
338 if fin.isfirstline(): | |
339 filepositiontext='' | |
340 currentfilename=fin.filename() | |
341 gotnextfile=1 | |
342 l1=l | |
343 strictf77=0 | |
344 sourcecodeform='fix' | |
345 ext = os.path.splitext(currentfilename)[1] | |
346 if is_f_file(currentfilename) and \ | |
347 not (_has_f90_header(l) or _has_fix_header(l)): | |
348 strictf77=1 | |
349 elif is_free_format(currentfilename) and not _has_fix_header(l): | |
350 sourcecodeform='free' | |
351 if strictf77: beginpattern=beginpattern77 | |
352 else: beginpattern=beginpattern90 | |
353 outmess('\tReading file %s (format:%s%s)\n'\ | |
354 %(repr(currentfilename), sourcecodeform, | |
355 strictf77 and ',strict' or '')) | |
356 | |
357 l=l.expandtabs().replace('\xa0', ' ') | |
358 while not l=='': # Get rid of newline characters | |
359 if l[-1] not in "\n\r\f": break | |
360 l=l[:-1] | |
361 if not strictf77: | |
362 r=commentline.match(l) | |
363 if r: | |
364 l=r.group('line')+' ' # Strip comments starting with `!' | |
365 rl=r.group('rest') | |
366 if rl[:4].lower()=='f2py': # f2py directive | |
367 l = l + 4*' ' | |
368 r=commentline.match(rl[4:]) | |
369 if r: l=l+r.group('line') | |
370 else: l = l + rl[4:] | |
371 if l.strip()=='': # Skip empty line | |
372 cont=0 | |
373 continue | |
374 if sourcecodeform=='fix': | |
375 if l[0] in ['*', 'c', '!', 'C', '#']: | |
376 if l[1:5].lower()=='f2py': # f2py directive | |
377 l=' '+l[5:] | |
378 else: # Skip comment line | |
379 cont=0 | |
380 continue | |
381 elif strictf77: | |
382 if len(l)>72: l=l[:72] | |
383 if not (l[0] in spacedigits): | |
384 raise Exception('readfortrancode: Found non-(space,digit) char ' | |
385 'in the first column.\n\tAre you sure that ' | |
386 'this code is in fix form?\n\tline=%s' % repr(l)) | |
387 | |
388 if (not cont or strictf77) and (len(l)>5 and not l[5]==' '): | |
389 # Continuation of a previous line | |
390 ll=ll+l[6:] | |
391 finalline='' | |
392 origfinalline='' | |
393 else: | |
394 if not strictf77: | |
395 # F90 continuation | |
396 r=cont1.match(l) | |
397 if r: l=r.group('line') # Continuation follows .. | |
398 if cont: | |
399 ll=ll+cont2.match(l).group('line') | |
400 finalline='' | |
401 origfinalline='' | |
402 else: | |
403 l=' '+l[5:] # clean up line beginning from possible digits. | |
404 if localdolowercase: finalline=ll.lower() | |
405 else: finalline=ll | |
406 origfinalline=ll | |
407 ll=l | |
408 cont=(r is not None) | |
409 else: | |
410 l=' '+l[5:] # clean up line beginning from possible digits. | |
411 if localdolowercase: finalline=ll.lower() | |
412 else: finalline=ll | |
413 origfinalline =ll | |
414 ll=l | |
415 | |
416 elif sourcecodeform=='free': | |
417 if not cont and ext=='.pyf' and mline_mark.match(l): | |
418 l = l + '\n' | |
419 while True: | |
420 lc = fin.readline() | |
421 if not lc: | |
422 errmess('Unexpected end of file when reading multiline\n') | |
423 break | |
424 l = l + lc | |
425 if mline_mark.match(lc): | |
426 break | |
427 l = l.rstrip() | |
428 r=cont1.match(l) | |
429 if r: l=r.group('line') # Continuation follows .. | |
430 if cont: | |
431 ll=ll+cont2.match(l).group('line') | |
432 finalline='' | |
433 origfinalline='' | |
434 else: | |
435 if localdolowercase: finalline=ll.lower() | |
436 else: finalline=ll | |
437 origfinalline =ll | |
438 ll=l | |
439 cont=(r is not None) | |
440 else: | |
441 raise ValueError("Flag sourcecodeform must be either 'fix' or 'free': %s"%repr(sourcecodeform)) | |
442 filepositiontext='Line #%d in %s:"%s"\n\t' % (fin.filelineno()-1, currentfilename, l1) | |
443 m=includeline.match(origfinalline) | |
444 if m: | |
445 fn=m.group('name') | |
446 if os.path.isfile(fn): | |
447 readfortrancode(fn, dowithline=dowithline, istop=0) | |
448 else: | |
449 include_dirs = [os.path.dirname(currentfilename)] + include_paths | |
450 foundfile = 0 | |
451 for inc_dir in include_dirs: | |
452 fn1 = os.path.join(inc_dir, fn) | |
453 if os.path.isfile(fn1): | |
454 foundfile = 1 | |
455 readfortrancode(fn1, dowithline=dowithline, istop=0) | |
456 break | |
457 if not foundfile: | |
458 outmess('readfortrancode: could not find include file %s in %s. Ignoring.\n'%(repr(fn), os.pathsep.join(include_dirs))) | |
459 else: | |
460 dowithline(finalline) | |
461 l1=ll | |
462 if localdolowercase: | |
463 finalline=ll.lower() | |
464 else: finalline=ll | |
465 origfinalline = ll | |
466 filepositiontext='Line #%d in %s:"%s"\n\t' % (fin.filelineno()-1, currentfilename, l1) | |
467 m=includeline.match(origfinalline) | |
468 if m: | |
469 fn=m.group('name') | |
470 if os.path.isfile(fn): | |
471 readfortrancode(fn, dowithline=dowithline, istop=0) | |
472 else: | |
473 include_dirs = [os.path.dirname(currentfilename)] + include_paths | |
474 foundfile = 0 | |
475 for inc_dir in include_dirs: | |
476 fn1 = os.path.join(inc_dir, fn) | |
477 if os.path.isfile(fn1): | |
478 foundfile = 1 | |
479 readfortrancode(fn1, dowithline=dowithline, istop=0) | |
480 break | |
481 if not foundfile: | |
482 outmess('readfortrancode: could not find include file %s in %s. Ignoring.\n'%(repr(fn), os.pathsep.join(include_dirs))) | |
483 else: | |
484 dowithline(finalline) | |
485 filepositiontext='' | |
486 fin.close() | |
487 if istop: dowithline('', 1) | |
488 else: | |
489 gotnextfile, filepositiontext, currentfilename, sourcecodeform, strictf77,\ | |
490 beginpattern, quiet, verbose, dolowercase=saveglobals | |
491 | |
492 ########### Crack line | |
493 beforethisafter=r'\s*(?P<before>%s(?=\s*(\b(%s)\b)))'+ \ | |
494 r'\s*(?P<this>(\b(%s)\b))'+ \ | |
495 r'\s*(?P<after>%s)\s*\Z' | |
496 ## | |
497 fortrantypes='character|logical|integer|real|complex|double\s*(precision\s*(complex|)|complex)|type(?=\s*\([\w\s,=(*)]*\))|byte' | |
498 typespattern=re.compile(beforethisafter%('', fortrantypes, fortrantypes, '.*'), re.I), 'type' | |
499 typespattern4implicit=re.compile(beforethisafter%('', fortrantypes+'|static|automatic|undefined', fortrantypes+'|static|automatic|undefined', '.*'), re.I) | |
500 # | |
501 functionpattern=re.compile(beforethisafter%('([a-z]+[\w\s(=*+-/)]*?|)', 'function', 'function', '.*'), re.I), 'begin' | |
502 subroutinepattern=re.compile(beforethisafter%('[a-z\s]*?', 'subroutine', 'subroutine', '.*'), re.I), 'begin' | |
503 #modulepattern=re.compile(beforethisafter%('[a-z\s]*?','module','module','.*'),re.I),'begin' | |
504 # | |
505 groupbegins77=r'program|block\s*data' | |
506 beginpattern77=re.compile(beforethisafter%('', groupbegins77, groupbegins77, '.*'), re.I), 'begin' | |
507 groupbegins90=groupbegins77+r'|module(?!\s*procedure)|python\s*module|interface|type(?!\s*\()' | |
508 beginpattern90=re.compile(beforethisafter%('', groupbegins90, groupbegins90, '.*'), re.I), 'begin' | |
509 groupends=r'end|endprogram|endblockdata|endmodule|endpythonmodule|endinterface' | |
510 endpattern=re.compile(beforethisafter%('', groupends, groupends, '[\w\s]*'), re.I), 'end' | |
511 #endifs='end\s*(if|do|where|select|while|forall)' | |
512 endifs='(end\s*(if|do|where|select|while|forall))|(module\s*procedure)' | |
513 endifpattern=re.compile(beforethisafter%('[\w]*?', endifs, endifs, '[\w\s]*'), re.I), 'endif' | |
514 # | |
515 implicitpattern=re.compile(beforethisafter%('', 'implicit', 'implicit', '.*'), re.I), 'implicit' | |
516 dimensionpattern=re.compile(beforethisafter%('', 'dimension|virtual', 'dimension|virtual', '.*'), re.I), 'dimension' | |
517 externalpattern=re.compile(beforethisafter%('', 'external', 'external', '.*'), re.I), 'external' | |
518 optionalpattern=re.compile(beforethisafter%('', 'optional', 'optional', '.*'), re.I), 'optional' | |
519 requiredpattern=re.compile(beforethisafter%('', 'required', 'required', '.*'), re.I), 'required' | |
520 publicpattern=re.compile(beforethisafter%('', 'public', 'public', '.*'), re.I), 'public' | |
521 privatepattern=re.compile(beforethisafter%('', 'private', 'private', '.*'), re.I), 'private' | |
522 intrisicpattern=re.compile(beforethisafter%('', 'intrisic', 'intrisic', '.*'), re.I), 'intrisic' | |
523 intentpattern=re.compile(beforethisafter%('', 'intent|depend|note|check', 'intent|depend|note|check', '\s*\(.*?\).*'), re.I), 'intent' | |
524 parameterpattern=re.compile(beforethisafter%('', 'parameter', 'parameter', '\s*\(.*'), re.I), 'parameter' | |
525 datapattern=re.compile(beforethisafter%('', 'data', 'data', '.*'), re.I), 'data' | |
526 callpattern=re.compile(beforethisafter%('', 'call', 'call', '.*'), re.I), 'call' | |
527 entrypattern=re.compile(beforethisafter%('', 'entry', 'entry', '.*'), re.I), 'entry' | |
528 callfunpattern=re.compile(beforethisafter%('', 'callfun', 'callfun', '.*'), re.I), 'callfun' | |
529 commonpattern=re.compile(beforethisafter%('', 'common', 'common', '.*'), re.I), 'common' | |
530 usepattern=re.compile(beforethisafter%('', 'use', 'use', '.*'), re.I), 'use' | |
531 containspattern=re.compile(beforethisafter%('', 'contains', 'contains', ''), re.I), 'contains' | |
532 formatpattern=re.compile(beforethisafter%('', 'format', 'format', '.*'), re.I), 'format' | |
533 ## Non-fortran and f2py-specific statements | |
534 f2pyenhancementspattern=re.compile(beforethisafter%('', 'threadsafe|fortranname|callstatement|callprotoargument|usercode|pymethoddef', 'threadsafe|fortranname|callstatement|callprotoargument|usercode|pymethoddef', '.*'), re.I|re.S), 'f2pyenhancements' | |
535 multilinepattern = re.compile(r"\s*(?P<before>''')(?P<this>.*?)(?P<after>''')\s*\Z", re.S), 'multiline' | |
536 ## | |
537 | |
538 def _simplifyargs(argsline): | |
539 a = [] | |
540 for n in markoutercomma(argsline).split('@,@'): | |
541 for r in '(),': | |
542 n = n.replace(r, '_') | |
543 a.append(n) | |
544 return ','.join(a) | |
545 | |
546 crackline_re_1 = re.compile(r'\s*(?P<result>\b[a-z]+[\w]*\b)\s*[=].*', re.I) | |
547 def crackline(line,reset=0): | |
548 """ | |
549 reset=-1 --- initialize | |
550 reset=0 --- crack the line | |
551 reset=1 --- final check if mismatch of blocks occured | |
552 | |
553 Cracked data is saved in grouplist[0]. | |
554 """ | |
555 global beginpattern, groupcounter, groupname, groupcache, grouplist, gotnextfile,\ | |
556 filepositiontext, currentfilename, neededmodule, expectbegin, skipblocksuntil,\ | |
557 skipemptyends, previous_context | |
558 if ';' in line and not (f2pyenhancementspattern[0].match(line) or | |
559 multilinepattern[0].match(line)): | |
560 for l in line.split(';'): | |
561 assert reset==0, repr(reset) # XXX: non-zero reset values need testing | |
562 crackline(l, reset) | |
563 return | |
564 if reset<0: | |
565 groupcounter=0 | |
566 groupname={groupcounter:''} | |
567 groupcache={groupcounter:{}} | |
568 grouplist={groupcounter:[]} | |
569 groupcache[groupcounter]['body']=[] | |
570 groupcache[groupcounter]['vars']={} | |
571 groupcache[groupcounter]['block']='' | |
572 groupcache[groupcounter]['name']='' | |
573 neededmodule=-1 | |
574 skipblocksuntil=-1 | |
575 return | |
576 if reset>0: | |
577 fl=0 | |
578 if f77modulename and neededmodule==groupcounter: fl=2 | |
579 while groupcounter>fl: | |
580 outmess('crackline: groupcounter=%s groupname=%s\n'%(repr(groupcounter), repr(groupname))) | |
581 outmess('crackline: Mismatch of blocks encountered. Trying to fix it by assuming "end" statement.\n') | |
582 grouplist[groupcounter-1].append(groupcache[groupcounter]) | |
583 grouplist[groupcounter-1][-1]['body']=grouplist[groupcounter] | |
584 del grouplist[groupcounter] | |
585 groupcounter=groupcounter-1 | |
586 if f77modulename and neededmodule==groupcounter: | |
587 grouplist[groupcounter-1].append(groupcache[groupcounter]) | |
588 grouplist[groupcounter-1][-1]['body']=grouplist[groupcounter] | |
589 del grouplist[groupcounter] | |
590 groupcounter=groupcounter-1 # end interface | |
591 grouplist[groupcounter-1].append(groupcache[groupcounter]) | |
592 grouplist[groupcounter-1][-1]['body']=grouplist[groupcounter] | |
593 del grouplist[groupcounter] | |
594 groupcounter=groupcounter-1 # end module | |
595 neededmodule=-1 | |
596 return | |
597 if line=='': return | |
598 flag=0 | |
599 for pat in [dimensionpattern, externalpattern, intentpattern, optionalpattern, | |
600 requiredpattern, | |
601 parameterpattern, datapattern, publicpattern, privatepattern, | |
602 intrisicpattern, | |
603 endifpattern, endpattern, | |
604 formatpattern, | |
605 beginpattern, functionpattern, subroutinepattern, | |
606 implicitpattern, typespattern, commonpattern, | |
607 callpattern, usepattern, containspattern, | |
608 entrypattern, | |
609 f2pyenhancementspattern, | |
610 multilinepattern | |
611 ]: | |
612 m = pat[0].match(line) | |
613 if m: | |
614 break | |
615 flag=flag+1 | |
616 if not m: | |
617 re_1 = crackline_re_1 | |
618 if 0<=skipblocksuntil<=groupcounter:return | |
619 if 'externals' in groupcache[groupcounter]: | |
620 for name in groupcache[groupcounter]['externals']: | |
621 if name in invbadnames: | |
622 name=invbadnames[name] | |
623 if 'interfaced' in groupcache[groupcounter] and name in groupcache[groupcounter]['interfaced']: | |
624 continue | |
625 m1=re.match(r'(?P<before>[^"]*)\b%s\b\s*@\(@(?P<args>[^@]*)@\)@.*\Z'%name, markouterparen(line), re.I) | |
626 if m1: | |
627 m2 = re_1.match(m1.group('before')) | |
628 a = _simplifyargs(m1.group('args')) | |
629 if m2: | |
630 line='callfun %s(%s) result (%s)'%(name, a, m2.group('result')) | |
631 else: line='callfun %s(%s)'%(name, a) | |
632 m = callfunpattern[0].match(line) | |
633 if not m: | |
634 outmess('crackline: could not resolve function call for line=%s.\n'%repr(line)) | |
635 return | |
636 analyzeline(m, 'callfun', line) | |
637 return | |
638 if verbose>1 or (verbose==1 and currentfilename.lower().endswith('.pyf')): | |
639 previous_context = None | |
640 outmess('crackline:%d: No pattern for line\n'%(groupcounter)) | |
641 return | |
642 elif pat[1]=='end': | |
643 if 0<=skipblocksuntil<groupcounter: | |
644 groupcounter=groupcounter-1 | |
645 if skipblocksuntil<=groupcounter: return | |
646 if groupcounter<=0: | |
647 raise Exception('crackline: groupcounter(=%s) is nonpositive. ' | |
648 'Check the blocks.' \ | |
649 % (groupcounter)) | |
650 m1 = beginpattern[0].match((line)) | |
651 if (m1) and (not m1.group('this')==groupname[groupcounter]): | |
652 raise Exception('crackline: End group %s does not match with ' | |
653 'previous Begin group %s\n\t%s' % \ | |
654 (repr(m1.group('this')), repr(groupname[groupcounter]), | |
655 filepositiontext) | |
656 ) | |
657 if skipblocksuntil==groupcounter: | |
658 skipblocksuntil=-1 | |
659 grouplist[groupcounter-1].append(groupcache[groupcounter]) | |
660 grouplist[groupcounter-1][-1]['body']=grouplist[groupcounter] | |
661 del grouplist[groupcounter] | |
662 groupcounter=groupcounter-1 | |
663 if not skipemptyends: | |
664 expectbegin=1 | |
665 elif pat[1] == 'begin': | |
666 if 0<=skipblocksuntil<=groupcounter: | |
667 groupcounter=groupcounter+1 | |
668 return | |
669 gotnextfile=0 | |
670 analyzeline(m, pat[1], line) | |
671 expectbegin=0 | |
672 elif pat[1]=='endif': | |
673 pass | |
674 elif pat[1]=='contains': | |
675 if ignorecontains: return | |
676 if 0<=skipblocksuntil<=groupcounter: return | |
677 skipblocksuntil=groupcounter | |
678 else: | |
679 if 0<=skipblocksuntil<=groupcounter:return | |
680 analyzeline(m, pat[1], line) | |
681 | |
682 def markouterparen(line): | |
683 l='';f=0 | |
684 for c in line: | |
685 if c=='(': | |
686 f=f+1 | |
687 if f==1: l=l+'@(@'; continue | |
688 elif c==')': | |
689 f=f-1 | |
690 if f==0: l=l+'@)@'; continue | |
691 l=l+c | |
692 return l | |
693 def markoutercomma(line,comma=','): | |
694 l='';f=0 | |
695 cc='' | |
696 for c in line: | |
697 if (not cc or cc==')') and c=='(': | |
698 f=f+1 | |
699 cc = ')' | |
700 elif not cc and c=='\'' and (not l or l[-1]!='\\'): | |
701 f=f+1 | |
702 cc = '\'' | |
703 elif c==cc: | |
704 f=f-1 | |
705 if f==0: | |
706 cc='' | |
707 elif c==comma and f==0: | |
708 l=l+'@'+comma+'@' | |
709 continue | |
710 l=l+c | |
711 assert not f, repr((f, line, l, cc)) | |
712 return l | |
713 def unmarkouterparen(line): | |
714 r = line.replace('@(@', '(').replace('@)@', ')') | |
715 return r | |
716 def appenddecl(decl,decl2,force=1): | |
717 if not decl: decl={} | |
718 if not decl2: return decl | |
719 if decl is decl2: return decl | |
720 for k in list(decl2.keys()): | |
721 if k=='typespec': | |
722 if force or k not in decl: | |
723 decl[k]=decl2[k] | |
724 elif k=='attrspec': | |
725 for l in decl2[k]: | |
726 decl=setattrspec(decl, l, force) | |
727 elif k=='kindselector': | |
728 decl=setkindselector(decl, decl2[k], force) | |
729 elif k=='charselector': | |
730 decl=setcharselector(decl, decl2[k], force) | |
731 elif k in ['=', 'typename']: | |
732 if force or k not in decl: | |
733 decl[k]=decl2[k] | |
734 elif k=='note': | |
735 pass | |
736 elif k in ['intent', 'check', 'dimension', 'optional', 'required']: | |
737 errmess('appenddecl: "%s" not implemented.\n'%k) | |
738 else: | |
739 raise Exception('appenddecl: Unknown variable definition key:' + \ | |
740 str(k)) | |
741 return decl | |
742 | |
743 selectpattern=re.compile(r'\s*(?P<this>(@\(@.*?@\)@|[*][\d*]+|[*]\s*@\(@.*?@\)@|))(?P<after>.*)\Z', re.I) | |
744 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) | |
745 callnameargspattern=re.compile(r'\s*(?P<name>\b[\w$]+\b)\s*@\(@\s*(?P<args>.*)\s*@\)@\s*\Z', re.I) | |
746 real16pattern = re.compile(r'([-+]?(?:\d+(?:\.\d*)?|\d*\.\d+))[dD]((?:[-+]?\d+)?)') | |
747 real8pattern = re.compile(r'([-+]?((?:\d+(?:\.\d*)?|\d*\.\d+))[eE]((?:[-+]?\d+)?)|(\d+\.\d*))') | |
748 | |
749 _intentcallbackpattern = re.compile(r'intent\s*\(.*?\bcallback\b', re.I) | |
750 def _is_intent_callback(vdecl): | |
751 for a in vdecl.get('attrspec', []): | |
752 if _intentcallbackpattern.match(a): | |
753 return 1 | |
754 return 0 | |
755 | |
756 def _resolvenameargspattern(line): | |
757 line = markouterparen(line) | |
758 m1=nameargspattern.match(line) | |
759 if m1: | |
760 return m1.group('name'), m1.group('args'), m1.group('result'), m1.group('bind') | |
761 m1=callnameargspattern.match(line) | |
762 if m1: | |
763 return m1.group('name'), m1.group('args'), None, None | |
764 return None, [], None, None | |
765 | |
766 def analyzeline(m, case, line): | |
767 global groupcounter, groupname, groupcache, grouplist, filepositiontext,\ | |
768 currentfilename, f77modulename, neededinterface, neededmodule, expectbegin,\ | |
769 gotnextfile, previous_context | |
770 block=m.group('this') | |
771 if case != 'multiline': | |
772 previous_context = None | |
773 if expectbegin and case not in ['begin', 'call', 'callfun', 'type'] \ | |
774 and not skipemptyends and groupcounter<1: | |
775 newname=os.path.basename(currentfilename).split('.')[0] | |
776 outmess('analyzeline: no group yet. Creating program group with name "%s".\n'%newname) | |
777 gotnextfile=0 | |
778 groupcounter=groupcounter+1 | |
779 groupname[groupcounter]='program' | |
780 groupcache[groupcounter]={} | |
781 grouplist[groupcounter]=[] | |
782 groupcache[groupcounter]['body']=[] | |
783 groupcache[groupcounter]['vars']={} | |
784 groupcache[groupcounter]['block']='program' | |
785 groupcache[groupcounter]['name']=newname | |
786 groupcache[groupcounter]['from']='fromsky' | |
787 expectbegin=0 | |
788 if case in ['begin', 'call', 'callfun']: | |
789 # Crack line => block,name,args,result | |
790 block = block.lower() | |
791 if re.match(r'block\s*data', block, re.I): block='block data' | |
792 if re.match(r'python\s*module', block, re.I): block='python module' | |
793 name, args, result, bind = _resolvenameargspattern(m.group('after')) | |
794 if name is None: | |
795 if block=='block data': | |
796 name = '_BLOCK_DATA_' | |
797 else: | |
798 name = '' | |
799 if block not in ['interface', 'block data']: | |
800 outmess('analyzeline: No name/args pattern found for line.\n') | |
801 | |
802 previous_context = (block, name, groupcounter) | |
803 if args: args=rmbadname([x.strip() for x in markoutercomma(args).split('@,@')]) | |
804 else: args=[] | |
805 if '' in args: | |
806 while '' in args: | |
807 args.remove('') | |
808 outmess('analyzeline: argument list is malformed (missing argument).\n') | |
809 | |
810 # end of crack line => block,name,args,result | |
811 needmodule=0 | |
812 needinterface=0 | |
813 | |
814 if case in ['call', 'callfun']: | |
815 needinterface=1 | |
816 if 'args' not in groupcache[groupcounter]: | |
817 return | |
818 if name not in groupcache[groupcounter]['args']: | |
819 return | |
820 for it in grouplist[groupcounter]: | |
821 if it['name']==name: | |
822 return | |
823 if name in groupcache[groupcounter]['interfaced']: | |
824 return | |
825 block={'call':'subroutine','callfun':'function'}[case] | |
826 if f77modulename and neededmodule==-1 and groupcounter<=1: | |
827 neededmodule=groupcounter+2 | |
828 needmodule=1 | |
829 if block != 'interface': | |
830 needinterface=1 | |
831 # Create new block(s) | |
832 groupcounter=groupcounter+1 | |
833 groupcache[groupcounter]={} | |
834 grouplist[groupcounter]=[] | |
835 if needmodule: | |
836 if verbose>1: | |
837 outmess('analyzeline: Creating module block %s\n'%repr(f77modulename), 0) | |
838 groupname[groupcounter]='module' | |
839 groupcache[groupcounter]['block']='python module' | |
840 groupcache[groupcounter]['name']=f77modulename | |
841 groupcache[groupcounter]['from']='' | |
842 groupcache[groupcounter]['body']=[] | |
843 groupcache[groupcounter]['externals']=[] | |
844 groupcache[groupcounter]['interfaced']=[] | |
845 groupcache[groupcounter]['vars']={} | |
846 groupcounter=groupcounter+1 | |
847 groupcache[groupcounter]={} | |
848 grouplist[groupcounter]=[] | |
849 if needinterface: | |
850 if verbose>1: | |
851 outmess('analyzeline: Creating additional interface block (groupcounter=%s).\n' % (groupcounter), 0) | |
852 groupname[groupcounter]='interface' | |
853 groupcache[groupcounter]['block']='interface' | |
854 groupcache[groupcounter]['name']='unknown_interface' | |
855 groupcache[groupcounter]['from']='%s:%s'%(groupcache[groupcounter-1]['from'], groupcache[groupcounter-1]['name']) | |
856 groupcache[groupcounter]['body']=[] | |
857 groupcache[groupcounter]['externals']=[] | |
858 groupcache[groupcounter]['interfaced']=[] | |
859 groupcache[groupcounter]['vars']={} | |
860 groupcounter=groupcounter+1 | |
861 groupcache[groupcounter]={} | |
862 grouplist[groupcounter]=[] | |
863 groupname[groupcounter]=block | |
864 groupcache[groupcounter]['block']=block | |
865 if not name: name='unknown_'+block | |
866 groupcache[groupcounter]['prefix']=m.group('before') | |
867 groupcache[groupcounter]['name']=rmbadname1(name) | |
868 groupcache[groupcounter]['result']=result | |
869 if groupcounter==1: | |
870 groupcache[groupcounter]['from']=currentfilename | |
871 else: | |
872 if f77modulename and groupcounter==3: | |
873 groupcache[groupcounter]['from']='%s:%s'%(groupcache[groupcounter-1]['from'], currentfilename) | |
874 else: | |
875 groupcache[groupcounter]['from']='%s:%s'%(groupcache[groupcounter-1]['from'], groupcache[groupcounter-1]['name']) | |
876 for k in list(groupcache[groupcounter].keys()): | |
877 if not groupcache[groupcounter][k]: | |
878 del groupcache[groupcounter][k] | |
879 | |
880 groupcache[groupcounter]['args']=args | |
881 groupcache[groupcounter]['body']=[] | |
882 groupcache[groupcounter]['externals']=[] | |
883 groupcache[groupcounter]['interfaced']=[] | |
884 groupcache[groupcounter]['vars']={} | |
885 groupcache[groupcounter]['entry']={} | |
886 # end of creation | |
887 if block=='type': | |
888 groupcache[groupcounter]['varnames'] = [] | |
889 | |
890 if case in ['call', 'callfun']: # set parents variables | |
891 if name not in groupcache[groupcounter-2]['externals']: | |
892 groupcache[groupcounter-2]['externals'].append(name) | |
893 groupcache[groupcounter]['vars']=copy.deepcopy(groupcache[groupcounter-2]['vars']) | |
894 #try: del groupcache[groupcounter]['vars'][groupcache[groupcounter-2]['name']] | |
895 #except: pass | |
896 try: del groupcache[groupcounter]['vars'][name][groupcache[groupcounter]['vars'][name]['attrspec'].index('external')] | |
897 except: pass | |
898 if block in ['function', 'subroutine']: # set global attributes | |
899 try: groupcache[groupcounter]['vars'][name]=appenddecl(groupcache[groupcounter]['vars'][name], groupcache[groupcounter-2]['vars']['']) | |
900 except: pass | |
901 if case=='callfun': # return type | |
902 if result and result in groupcache[groupcounter]['vars']: | |
903 if not name==result: | |
904 groupcache[groupcounter]['vars'][name]=appenddecl(groupcache[groupcounter]['vars'][name], groupcache[groupcounter]['vars'][result]) | |
905 #if groupcounter>1: # name is interfaced | |
906 try: groupcache[groupcounter-2]['interfaced'].append(name) | |
907 except: pass | |
908 if block=='function': | |
909 t=typespattern[0].match(m.group('before')+' '+name) | |
910 if t: | |
911 typespec, selector, attr, edecl=cracktypespec0(t.group('this'), t.group('after')) | |
912 updatevars(typespec, selector, attr, edecl) | |
913 | |
914 if case in ['call', 'callfun']: | |
915 grouplist[groupcounter-1].append(groupcache[groupcounter]) | |
916 grouplist[groupcounter-1][-1]['body']=grouplist[groupcounter] | |
917 del grouplist[groupcounter] | |
918 groupcounter=groupcounter-1 # end routine | |
919 grouplist[groupcounter-1].append(groupcache[groupcounter]) | |
920 grouplist[groupcounter-1][-1]['body']=grouplist[groupcounter] | |
921 del grouplist[groupcounter] | |
922 groupcounter=groupcounter-1 # end interface | |
923 | |
924 elif case=='entry': | |
925 name, args, result, bind=_resolvenameargspattern(m.group('after')) | |
926 if name is not None: | |
927 if args: | |
928 args=rmbadname([x.strip() for x in markoutercomma(args).split('@,@')]) | |
929 else: args=[] | |
930 assert result is None, repr(result) | |
931 groupcache[groupcounter]['entry'][name] = args | |
932 previous_context = ('entry', name, groupcounter) | |
933 elif case=='type': | |
934 typespec, selector, attr, edecl=cracktypespec0(block, m.group('after')) | |
935 last_name = updatevars(typespec, selector, attr, edecl) | |
936 if last_name is not None: | |
937 previous_context = ('variable', last_name, groupcounter) | |
938 elif case in ['dimension', 'intent', 'optional', 'required', 'external', 'public', 'private', 'intrisic']: | |
939 edecl=groupcache[groupcounter]['vars'] | |
940 ll=m.group('after').strip() | |
941 i=ll.find('::') | |
942 if i<0 and case=='intent': | |
943 i=markouterparen(ll).find('@)@')-2 | |
944 ll=ll[:i+1]+'::'+ll[i+1:] | |
945 i=ll.find('::') | |
946 if ll[i:]=='::' and 'args' in groupcache[groupcounter]: | |
947 outmess('All arguments will have attribute %s%s\n'%(m.group('this'), ll[:i])) | |
948 ll = ll + ','.join(groupcache[groupcounter]['args']) | |
949 if i<0:i=0;pl='' | |
950 else: pl=ll[:i].strip();ll=ll[i+2:] | |
951 ch = markoutercomma(pl).split('@,@') | |
952 if len(ch)>1: | |
953 pl = ch[0] | |
954 outmess('analyzeline: cannot handle multiple attributes without type specification. Ignoring %r.\n' % (','.join(ch[1:]))) | |
955 last_name = None | |
956 | |
957 for e in [x.strip() for x in markoutercomma(ll).split('@,@')]: | |
958 m1=namepattern.match(e) | |
959 if not m1: | |
960 if case in ['public', 'private']: k='' | |
961 else: | |
962 print(m.groupdict()) | |
963 outmess('analyzeline: no name pattern found in %s statement for %s. Skipping.\n'%(case, repr(e))) | |
964 continue | |
965 else: | |
966 k=rmbadname1(m1.group('name')) | |
967 if k not in edecl: | |
968 edecl[k]={} | |
969 if case=='dimension': | |
970 ap=case+m1.group('after') | |
971 if case=='intent': | |
972 ap=m.group('this')+pl | |
973 if _intentcallbackpattern.match(ap): | |
974 if k not in groupcache[groupcounter]['args']: | |
975 if groupcounter>1: | |
976 if '__user__' not in groupcache[groupcounter-2]['name']: | |
977 outmess('analyzeline: missing __user__ module (could be nothing)\n') | |
978 if k!=groupcache[groupcounter]['name']: # fixes ticket 1693 | |
979 outmess('analyzeline: appending intent(callback) %s'\ | |
980 ' to %s arguments\n' % (k, groupcache[groupcounter]['name'])) | |
981 groupcache[groupcounter]['args'].append(k) | |
982 else: | |
983 errmess('analyzeline: intent(callback) %s is ignored' % (k)) | |
984 else: | |
985 errmess('analyzeline: intent(callback) %s is already'\ | |
986 ' in argument list' % (k)) | |
987 if case in ['optional', 'required', 'public', 'external', 'private', 'intrisic']: | |
988 ap=case | |
989 if 'attrspec' in edecl[k]: | |
990 edecl[k]['attrspec'].append(ap) | |
991 else: | |
992 edecl[k]['attrspec']=[ap] | |
993 if case=='external': | |
994 if groupcache[groupcounter]['block']=='program': | |
995 outmess('analyzeline: ignoring program arguments\n') | |
996 continue | |
997 if k not in groupcache[groupcounter]['args']: | |
998 #outmess('analyzeline: ignoring external %s (not in arguments list)\n'%(`k`)) | |
999 continue | |
1000 if 'externals' not in groupcache[groupcounter]: | |
1001 groupcache[groupcounter]['externals']=[] | |
1002 groupcache[groupcounter]['externals'].append(k) | |
1003 last_name = k | |
1004 groupcache[groupcounter]['vars']=edecl | |
1005 if last_name is not None: | |
1006 previous_context = ('variable', last_name, groupcounter) | |
1007 elif case=='parameter': | |
1008 edecl=groupcache[groupcounter]['vars'] | |
1009 ll=m.group('after').strip()[1:-1] | |
1010 last_name = None | |
1011 for e in markoutercomma(ll).split('@,@'): | |
1012 try: | |
1013 k, initexpr=[x.strip() for x in e.split('=')] | |
1014 except: | |
1015 outmess('analyzeline: could not extract name,expr in parameter statement "%s" of "%s"\n'%(e, ll));continue | |
1016 params = get_parameters(edecl) | |
1017 k=rmbadname1(k) | |
1018 if k not in edecl: | |
1019 edecl[k]={} | |
1020 if '=' in edecl[k] and (not edecl[k]['=']==initexpr): | |
1021 outmess('analyzeline: Overwriting the value of parameter "%s" ("%s") with "%s".\n'%(k, edecl[k]['='], initexpr)) | |
1022 t = determineexprtype(initexpr, params) | |
1023 if t: | |
1024 if t.get('typespec')=='real': | |
1025 tt = list(initexpr) | |
1026 for m in real16pattern.finditer(initexpr): | |
1027 tt[m.start():m.end()] = list(\ | |
1028 initexpr[m.start():m.end()].lower().replace('d', 'e')) | |
1029 initexpr = ''.join(tt) | |
1030 elif t.get('typespec')=='complex': | |
1031 initexpr = initexpr[1:].lower().replace('d', 'e').\ | |
1032 replace(',', '+1j*(') | |
1033 try: | |
1034 v = eval(initexpr, {}, params) | |
1035 except (SyntaxError, NameError, TypeError) as msg: | |
1036 errmess('analyzeline: Failed to evaluate %r. Ignoring: %s\n'\ | |
1037 % (initexpr, msg)) | |
1038 continue | |
1039 edecl[k]['='] = repr(v) | |
1040 if 'attrspec' in edecl[k]: | |
1041 edecl[k]['attrspec'].append('parameter') | |
1042 else: edecl[k]['attrspec']=['parameter'] | |
1043 last_name = k | |
1044 groupcache[groupcounter]['vars']=edecl | |
1045 if last_name is not None: | |
1046 previous_context = ('variable', last_name, groupcounter) | |
1047 elif case=='implicit': | |
1048 if m.group('after').strip().lower()=='none': | |
1049 groupcache[groupcounter]['implicit']=None | |
1050 elif m.group('after'): | |
1051 if 'implicit' in groupcache[groupcounter]: | |
1052 impl=groupcache[groupcounter]['implicit'] | |
1053 else: impl={} | |
1054 if impl is None: | |
1055 outmess('analyzeline: Overwriting earlier "implicit none" statement.\n') | |
1056 impl={} | |
1057 for e in markoutercomma(m.group('after')).split('@,@'): | |
1058 decl={} | |
1059 m1=re.match(r'\s*(?P<this>.*?)\s*(\(\s*(?P<after>[a-z-, ]+)\s*\)\s*|)\Z', e, re.I) | |
1060 if not m1: | |
1061 outmess('analyzeline: could not extract info of implicit statement part "%s"\n'%(e));continue | |
1062 m2=typespattern4implicit.match(m1.group('this')) | |
1063 if not m2: | |
1064 outmess('analyzeline: could not extract types pattern of implicit statement part "%s"\n'%(e));continue | |
1065 typespec, selector, attr, edecl=cracktypespec0(m2.group('this'), m2.group('after')) | |
1066 kindselect, charselect, typename=cracktypespec(typespec, selector) | |
1067 decl['typespec']=typespec | |
1068 decl['kindselector']=kindselect | |
1069 decl['charselector']=charselect | |
1070 decl['typename']=typename | |
1071 for k in list(decl.keys()): | |
1072 if not decl[k]: del decl[k] | |
1073 for r in markoutercomma(m1.group('after')).split('@,@'): | |
1074 if '-' in r: | |
1075 try: begc, endc=[x.strip() for x in r.split('-')] | |
1076 except: | |
1077 outmess('analyzeline: expected "<char>-<char>" instead of "%s" in range list of implicit statement\n'%r);continue | |
1078 else: begc=endc=r.strip() | |
1079 if not len(begc)==len(endc)==1: | |
1080 outmess('analyzeline: expected "<char>-<char>" instead of "%s" in range list of implicit statement (2)\n'%r);continue | |
1081 for o in range(ord(begc), ord(endc)+1): | |
1082 impl[chr(o)]=decl | |
1083 groupcache[groupcounter]['implicit']=impl | |
1084 elif case=='data': | |
1085 ll=[] | |
1086 dl='';il='';f=0;fc=1;inp=0 | |
1087 for c in m.group('after'): | |
1088 if not inp: | |
1089 if c=="'": fc=not fc | |
1090 if c=='/' and fc: f=f+1;continue | |
1091 if c=='(': inp = inp + 1 | |
1092 elif c==')': inp = inp - 1 | |
1093 if f==0: dl=dl+c | |
1094 elif f==1: il=il+c | |
1095 elif f==2: | |
1096 dl = dl.strip() | |
1097 if dl.startswith(','): | |
1098 dl = dl[1:].strip() | |
1099 ll.append([dl, il]) | |
1100 dl=c;il='';f=0 | |
1101 if f==2: | |
1102 dl = dl.strip() | |
1103 if dl.startswith(','): | |
1104 dl = dl[1:].strip() | |
1105 ll.append([dl, il]) | |
1106 vars={} | |
1107 if 'vars' in groupcache[groupcounter]: | |
1108 vars=groupcache[groupcounter]['vars'] | |
1109 last_name = None | |
1110 for l in ll: | |
1111 l=[x.strip() for x in l] | |
1112 if l[0][0]==',':l[0]=l[0][1:] | |
1113 if l[0][0]=='(': | |
1114 outmess('analyzeline: implied-DO list "%s" is not supported. Skipping.\n'%l[0]) | |
1115 continue | |
1116 #if '(' in l[0]: | |
1117 # #outmess('analyzeline: ignoring this data statement.\n') | |
1118 # continue | |
1119 i=0;j=0;llen=len(l[1]) | |
1120 for v in rmbadname([x.strip() for x in markoutercomma(l[0]).split('@,@')]): | |
1121 if v[0]=='(': | |
1122 outmess('analyzeline: implied-DO list "%s" is not supported. Skipping.\n'%v) | |
1123 # XXX: subsequent init expressions may get wrong values. | |
1124 # Ignoring since data statements are irrelevant for wrapping. | |
1125 continue | |
1126 fc=0 | |
1127 while (i<llen) and (fc or not l[1][i]==','): | |
1128 if l[1][i]=="'": fc=not fc | |
1129 i=i+1 | |
1130 i=i+1 | |
1131 #v,l[1][j:i-1]=name,initvalue | |
1132 if v not in vars: | |
1133 vars[v]={} | |
1134 if '=' in vars[v] and not vars[v]['=']==l[1][j:i-1]: | |
1135 outmess('analyzeline: changing init expression of "%s" ("%s") to "%s"\n'%(v, vars[v]['='], l[1][j:i-1])) | |
1136 vars[v]['=']=l[1][j:i-1] | |
1137 j=i | |
1138 last_name = v | |
1139 groupcache[groupcounter]['vars']=vars | |
1140 if last_name is not None: | |
1141 previous_context = ('variable', last_name, groupcounter) | |
1142 elif case=='common': | |
1143 line=m.group('after').strip() | |
1144 if not line[0]=='/':line='//'+line | |
1145 cl=[] | |
1146 f=0;bn='';ol='' | |
1147 for c in line: | |
1148 if c=='/':f=f+1;continue | |
1149 if f>=3: | |
1150 bn = bn.strip() | |
1151 if not bn: bn='_BLNK_' | |
1152 cl.append([bn, ol]) | |
1153 f=f-2;bn='';ol='' | |
1154 if f%2: bn=bn+c | |
1155 else: ol=ol+c | |
1156 bn = bn.strip() | |
1157 if not bn: bn='_BLNK_' | |
1158 cl.append([bn, ol]) | |
1159 commonkey={} | |
1160 if 'common' in groupcache[groupcounter]: | |
1161 commonkey=groupcache[groupcounter]['common'] | |
1162 for c in cl: | |
1163 if c[0] in commonkey: | |
1164 outmess('analyzeline: previously defined common block encountered. Skipping.\n') | |
1165 continue | |
1166 commonkey[c[0]]=[] | |
1167 for i in [x.strip() for x in markoutercomma(c[1]).split('@,@')]: | |
1168 if i: commonkey[c[0]].append(i) | |
1169 groupcache[groupcounter]['common']=commonkey | |
1170 previous_context = ('common', bn, groupcounter) | |
1171 elif case=='use': | |
1172 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) | |
1173 if m1: | |
1174 mm=m1.groupdict() | |
1175 if 'use' not in groupcache[groupcounter]: | |
1176 groupcache[groupcounter]['use']={} | |
1177 name=m1.group('name') | |
1178 groupcache[groupcounter]['use'][name]={} | |
1179 isonly=0 | |
1180 if 'list' in mm and mm['list'] is not None: | |
1181 if 'notonly' in mm and mm['notonly'] is None: | |
1182 isonly=1 | |
1183 groupcache[groupcounter]['use'][name]['only']=isonly | |
1184 ll=[x.strip() for x in mm['list'].split(',')] | |
1185 rl={} | |
1186 for l in ll: | |
1187 if '=' in l: | |
1188 m2=re.match(r'\A\s*(?P<local>\b[\w]+\b)\s*=\s*>\s*(?P<use>\b[\w]+\b)\s*\Z', l, re.I) | |
1189 if m2: rl[m2.group('local').strip()]=m2.group('use').strip() | |
1190 else: | |
1191 outmess('analyzeline: Not local=>use pattern found in %s\n'%repr(l)) | |
1192 else: | |
1193 rl[l]=l | |
1194 groupcache[groupcounter]['use'][name]['map']=rl | |
1195 else: | |
1196 pass | |
1197 else: | |
1198 print(m.groupdict()) | |
1199 outmess('analyzeline: Could not crack the use statement.\n') | |
1200 elif case in ['f2pyenhancements']: | |
1201 if 'f2pyenhancements' not in groupcache[groupcounter]: | |
1202 groupcache[groupcounter]['f2pyenhancements'] = {} | |
1203 d = groupcache[groupcounter]['f2pyenhancements'] | |
1204 if m.group('this')=='usercode' and 'usercode' in d: | |
1205 if isinstance(d['usercode'], str): | |
1206 d['usercode'] = [d['usercode']] | |
1207 d['usercode'].append(m.group('after')) | |
1208 else: | |
1209 d[m.group('this')] = m.group('after') | |
1210 elif case=='multiline': | |
1211 if previous_context is None: | |
1212 if verbose: | |
1213 outmess('analyzeline: No context for multiline block.\n') | |
1214 return | |
1215 gc = groupcounter | |
1216 #gc = previous_context[2] | |
1217 appendmultiline(groupcache[gc], | |
1218 previous_context[:2], | |
1219 m.group('this')) | |
1220 else: | |
1221 if verbose>1: | |
1222 print(m.groupdict()) | |
1223 outmess('analyzeline: No code implemented for line.\n') | |
1224 | |
1225 def appendmultiline(group, context_name, ml): | |
1226 if 'f2pymultilines' not in group: | |
1227 group['f2pymultilines'] = {} | |
1228 d = group['f2pymultilines'] | |
1229 if context_name not in d: | |
1230 d[context_name] = [] | |
1231 d[context_name].append(ml) | |
1232 return | |
1233 | |
1234 def cracktypespec0(typespec, ll): | |
1235 selector=None | |
1236 attr=None | |
1237 if re.match(r'double\s*complex', typespec, re.I): typespec='double complex' | |
1238 elif re.match(r'double\s*precision', typespec, re.I): typespec='double precision' | |
1239 else: typespec=typespec.strip().lower() | |
1240 m1=selectpattern.match(markouterparen(ll)) | |
1241 if not m1: | |
1242 outmess('cracktypespec0: no kind/char_selector pattern found for line.\n') | |
1243 return | |
1244 d=m1.groupdict() | |
1245 for k in list(d.keys()): d[k]=unmarkouterparen(d[k]) | |
1246 if typespec in ['complex', 'integer', 'logical', 'real', 'character', 'type']: | |
1247 selector=d['this'] | |
1248 ll=d['after'] | |
1249 i=ll.find('::') | |
1250 if i>=0: | |
1251 attr=ll[:i].strip() | |
1252 ll=ll[i+2:] | |
1253 return typespec, selector, attr, ll | |
1254 ##### | |
1255 namepattern=re.compile(r'\s*(?P<name>\b[\w]+\b)\s*(?P<after>.*)\s*\Z', re.I) | |
1256 kindselector=re.compile(r'\s*(\(\s*(kind\s*=)?\s*(?P<kind>.*)\s*\)|[*]\s*(?P<kind2>.*?))\s*\Z', re.I) | |
1257 charselector=re.compile(r'\s*(\((?P<lenkind>.*)\)|[*]\s*(?P<charlen>.*))\s*\Z', re.I) | |
1258 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) | |
1259 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) | |
1260 def removespaces(expr): | |
1261 expr=expr.strip() | |
1262 if len(expr)<=1: return expr | |
1263 expr2=expr[0] | |
1264 for i in range(1, len(expr)-1): | |
1265 if expr[i]==' ' and \ | |
1266 ((expr[i+1] in "()[]{}=+-/* ") or (expr[i-1] in "()[]{}=+-/* ")): continue | |
1267 expr2=expr2+expr[i] | |
1268 expr2=expr2+expr[-1] | |
1269 return expr2 | |
1270 def markinnerspaces(line): | |
1271 l='';f=0 | |
1272 cc='\'' | |
1273 cc1='"' | |
1274 cb='' | |
1275 for c in line: | |
1276 if cb=='\\' and c in ['\\', '\'', '"']: | |
1277 l=l+c | |
1278 cb=c | |
1279 continue | |
1280 if f==0 and c in ['\'', '"']: cc=c; cc1={'\'':'"','"':'\''}[c] | |
1281 if c==cc:f=f+1 | |
1282 elif c==cc:f=f-1 | |
1283 elif c==' ' and f==1: l=l+'@_@'; continue | |
1284 l=l+c;cb=c | |
1285 return l | |
1286 def updatevars(typespec, selector, attrspec, entitydecl): | |
1287 global groupcache, groupcounter | |
1288 last_name = None | |
1289 kindselect, charselect, typename=cracktypespec(typespec, selector) | |
1290 if attrspec: | |
1291 attrspec=[x.strip() for x in markoutercomma(attrspec).split('@,@')] | |
1292 l = [] | |
1293 c = re.compile(r'(?P<start>[a-zA-Z]+)') | |
1294 for a in attrspec: | |
1295 if not a: | |
1296 continue | |
1297 m = c.match(a) | |
1298 if m: | |
1299 s = m.group('start').lower() | |
1300 a = s + a[len(s):] | |
1301 l.append(a) | |
1302 attrspec = l | |
1303 el=[x.strip() for x in markoutercomma(entitydecl).split('@,@')] | |
1304 el1=[] | |
1305 for e in el: | |
1306 for e1 in [x.strip() for x in markoutercomma(removespaces(markinnerspaces(e)), comma=' ').split('@ @')]: | |
1307 if e1: el1.append(e1.replace('@_@', ' ')) | |
1308 for e in el1: | |
1309 m=namepattern.match(e) | |
1310 if not m: | |
1311 outmess('updatevars: no name pattern found for entity=%s. Skipping.\n'%(repr(e))) | |
1312 continue | |
1313 ename=rmbadname1(m.group('name')) | |
1314 edecl={} | |
1315 if ename in groupcache[groupcounter]['vars']: | |
1316 edecl=groupcache[groupcounter]['vars'][ename].copy() | |
1317 not_has_typespec = 'typespec' not in edecl | |
1318 if not_has_typespec: | |
1319 edecl['typespec']=typespec | |
1320 elif typespec and (not typespec==edecl['typespec']): | |
1321 outmess('updatevars: attempt to change the type of "%s" ("%s") to "%s". Ignoring.\n' % (ename, edecl['typespec'], typespec)) | |
1322 if 'kindselector' not in edecl: | |
1323 edecl['kindselector']=copy.copy(kindselect) | |
1324 elif kindselect: | |
1325 for k in list(kindselect.keys()): | |
1326 if k in edecl['kindselector'] and (not kindselect[k]==edecl['kindselector'][k]): | |
1327 outmess('updatevars: attempt to change the kindselector "%s" of "%s" ("%s") to "%s". Ignoring.\n' % (k, ename, edecl['kindselector'][k], kindselect[k])) | |
1328 else: edecl['kindselector'][k]=copy.copy(kindselect[k]) | |
1329 if 'charselector' not in edecl and charselect: | |
1330 if not_has_typespec: | |
1331 edecl['charselector']=charselect | |
1332 else: | |
1333 errmess('updatevars:%s: attempt to change empty charselector to %r. Ignoring.\n' \ | |
1334 %(ename, charselect)) | |
1335 elif charselect: | |
1336 for k in list(charselect.keys()): | |
1337 if k in edecl['charselector'] and (not charselect[k]==edecl['charselector'][k]): | |
1338 outmess('updatevars: attempt to change the charselector "%s" of "%s" ("%s") to "%s". Ignoring.\n' % (k, ename, edecl['charselector'][k], charselect[k])) | |
1339 else: edecl['charselector'][k]=copy.copy(charselect[k]) | |
1340 if 'typename' not in edecl: | |
1341 edecl['typename']=typename | |
1342 elif typename and (not edecl['typename']==typename): | |
1343 outmess('updatevars: attempt to change the typename of "%s" ("%s") to "%s". Ignoring.\n' % (ename, edecl['typename'], typename)) | |
1344 if 'attrspec' not in edecl: | |
1345 edecl['attrspec']=copy.copy(attrspec) | |
1346 elif attrspec: | |
1347 for a in attrspec: | |
1348 if a not in edecl['attrspec']: | |
1349 edecl['attrspec'].append(a) | |
1350 else: | |
1351 edecl['typespec']=copy.copy(typespec) | |
1352 edecl['kindselector']=copy.copy(kindselect) | |
1353 edecl['charselector']=copy.copy(charselect) | |
1354 edecl['typename']=typename | |
1355 edecl['attrspec']=copy.copy(attrspec) | |
1356 if m.group('after'): | |
1357 m1=lenarraypattern.match(markouterparen(m.group('after'))) | |
1358 if m1: | |
1359 d1=m1.groupdict() | |
1360 for lk in ['len', 'array', 'init']: | |
1361 if d1[lk+'2'] is not None: d1[lk]=d1[lk+'2']; del d1[lk+'2'] | |
1362 for k in list(d1.keys()): | |
1363 if d1[k] is not None: d1[k]=unmarkouterparen(d1[k]) | |
1364 else: del d1[k] | |
1365 if 'len' in d1 and 'array' in d1: | |
1366 if d1['len']=='': | |
1367 d1['len']=d1['array'] | |
1368 del d1['array'] | |
1369 else: | |
1370 d1['array']=d1['array']+','+d1['len'] | |
1371 del d1['len'] | |
1372 errmess('updatevars: "%s %s" is mapped to "%s %s(%s)"\n'%(typespec, e, typespec, ename, d1['array'])) | |
1373 if 'array' in d1: | |
1374 dm = 'dimension(%s)'%d1['array'] | |
1375 if 'attrspec' not in edecl or (not edecl['attrspec']): | |
1376 edecl['attrspec']=[dm] | |
1377 else: | |
1378 edecl['attrspec'].append(dm) | |
1379 for dm1 in edecl['attrspec']: | |
1380 if dm1[:9]=='dimension' and dm1!=dm: | |
1381 del edecl['attrspec'][-1] | |
1382 errmess('updatevars:%s: attempt to change %r to %r. Ignoring.\n' \ | |
1383 % (ename, dm1, dm)) | |
1384 break | |
1385 | |
1386 if 'len' in d1: | |
1387 if typespec in ['complex', 'integer', 'logical', 'real']: | |
1388 if ('kindselector' not in edecl) or (not edecl['kindselector']): | |
1389 edecl['kindselector']={} | |
1390 edecl['kindselector']['*']=d1['len'] | |
1391 elif typespec == 'character': | |
1392 if ('charselector' not in edecl) or (not edecl['charselector']): | |
1393 edecl['charselector']={} | |
1394 if 'len' in edecl['charselector']: | |
1395 del edecl['charselector']['len'] | |
1396 edecl['charselector']['*']=d1['len'] | |
1397 if 'init' in d1: | |
1398 if '=' in edecl and (not edecl['=']==d1['init']): | |
1399 outmess('updatevars: attempt to change the init expression of "%s" ("%s") to "%s". Ignoring.\n' % (ename, edecl['='], d1['init'])) | |
1400 else: | |
1401 edecl['=']=d1['init'] | |
1402 else: | |
1403 outmess('updatevars: could not crack entity declaration "%s". Ignoring.\n'%(ename+m.group('after'))) | |
1404 for k in list(edecl.keys()): | |
1405 if not edecl[k]: | |
1406 del edecl[k] | |
1407 groupcache[groupcounter]['vars'][ename]=edecl | |
1408 if 'varnames' in groupcache[groupcounter]: | |
1409 groupcache[groupcounter]['varnames'].append(ename) | |
1410 last_name = ename | |
1411 return last_name | |
1412 | |
1413 def cracktypespec(typespec, selector): | |
1414 kindselect=None | |
1415 charselect=None | |
1416 typename=None | |
1417 if selector: | |
1418 if typespec in ['complex', 'integer', 'logical', 'real']: | |
1419 kindselect=kindselector.match(selector) | |
1420 if not kindselect: | |
1421 outmess('cracktypespec: no kindselector pattern found for %s\n'%(repr(selector))) | |
1422 return | |
1423 kindselect=kindselect.groupdict() | |
1424 kindselect['*']=kindselect['kind2'] | |
1425 del kindselect['kind2'] | |
1426 for k in list(kindselect.keys()): | |
1427 if not kindselect[k]: del kindselect[k] | |
1428 for k, i in list(kindselect.items()): | |
1429 kindselect[k] = rmbadname1(i) | |
1430 elif typespec=='character': | |
1431 charselect=charselector.match(selector) | |
1432 if not charselect: | |
1433 outmess('cracktypespec: no charselector pattern found for %s\n'%(repr(selector))) | |
1434 return | |
1435 charselect=charselect.groupdict() | |
1436 charselect['*']=charselect['charlen'] | |
1437 del charselect['charlen'] | |
1438 if charselect['lenkind']: | |
1439 lenkind=lenkindpattern.match(markoutercomma(charselect['lenkind'])) | |
1440 lenkind=lenkind.groupdict() | |
1441 for lk in ['len', 'kind']: | |
1442 if lenkind[lk+'2']: | |
1443 lenkind[lk]=lenkind[lk+'2'] | |
1444 charselect[lk]=lenkind[lk] | |
1445 del lenkind[lk+'2'] | |
1446 del charselect['lenkind'] | |
1447 for k in list(charselect.keys()): | |
1448 if not charselect[k]: del charselect[k] | |
1449 for k, i in list(charselect.items()): | |
1450 charselect[k] = rmbadname1(i) | |
1451 elif typespec=='type': | |
1452 typename=re.match(r'\s*\(\s*(?P<name>\w+)\s*\)', selector, re.I) | |
1453 if typename: typename=typename.group('name') | |
1454 else: outmess('cracktypespec: no typename found in %s\n'%(repr(typespec+selector))) | |
1455 else: | |
1456 outmess('cracktypespec: no selector used for %s\n'%(repr(selector))) | |
1457 return kindselect, charselect, typename | |
1458 ###### | |
1459 def setattrspec(decl,attr,force=0): | |
1460 if not decl: | |
1461 decl={} | |
1462 if not attr: | |
1463 return decl | |
1464 if 'attrspec' not in decl: | |
1465 decl['attrspec']=[attr] | |
1466 return decl | |
1467 if force: decl['attrspec'].append(attr) | |
1468 if attr in decl['attrspec']: return decl | |
1469 if attr=='static' and 'automatic' not in decl['attrspec']: | |
1470 decl['attrspec'].append(attr) | |
1471 elif attr=='automatic' and 'static' not in decl['attrspec']: | |
1472 decl['attrspec'].append(attr) | |
1473 elif attr=='public' and 'private' not in decl['attrspec']: | |
1474 decl['attrspec'].append(attr) | |
1475 elif attr=='private' and 'public' not in decl['attrspec']: | |
1476 decl['attrspec'].append(attr) | |
1477 else: | |
1478 decl['attrspec'].append(attr) | |
1479 return decl | |
1480 | |
1481 def setkindselector(decl,sel,force=0): | |
1482 if not decl: | |
1483 decl={} | |
1484 if not sel: | |
1485 return decl | |
1486 if 'kindselector' not in decl: | |
1487 decl['kindselector']=sel | |
1488 return decl | |
1489 for k in list(sel.keys()): | |
1490 if force or k not in decl['kindselector']: | |
1491 decl['kindselector'][k]=sel[k] | |
1492 return decl | |
1493 | |
1494 def setcharselector(decl,sel,force=0): | |
1495 if not decl: | |
1496 decl={} | |
1497 if not sel: | |
1498 return decl | |
1499 if 'charselector' not in decl: | |
1500 decl['charselector']=sel | |
1501 return decl | |
1502 for k in list(sel.keys()): | |
1503 if force or k not in decl['charselector']: | |
1504 decl['charselector'][k]=sel[k] | |
1505 return decl | |
1506 | |
1507 def getblockname(block,unknown='unknown'): | |
1508 if 'name' in block: | |
1509 return block['name'] | |
1510 return unknown | |
1511 | |
1512 ###### post processing | |
1513 | |
1514 def setmesstext(block): | |
1515 global filepositiontext | |
1516 try: | |
1517 filepositiontext='In: %s:%s\n'%(block['from'], block['name']) | |
1518 except: | |
1519 pass | |
1520 | |
1521 def get_usedict(block): | |
1522 usedict = {} | |
1523 if 'parent_block' in block: | |
1524 usedict = get_usedict(block['parent_block']) | |
1525 if 'use' in block: | |
1526 usedict.update(block['use']) | |
1527 return usedict | |
1528 | |
1529 def get_useparameters(block, param_map=None): | |
1530 global f90modulevars | |
1531 if param_map is None: | |
1532 param_map = {} | |
1533 usedict = get_usedict(block) | |
1534 if not usedict: | |
1535 return param_map | |
1536 for usename, mapping in list(usedict.items()): | |
1537 usename = usename.lower() | |
1538 if usename not in f90modulevars: | |
1539 outmess('get_useparameters: no module %s info used by %s\n' % (usename, block.get('name'))) | |
1540 continue | |
1541 mvars = f90modulevars[usename] | |
1542 params = get_parameters(mvars) | |
1543 if not params: | |
1544 continue | |
1545 # XXX: apply mapping | |
1546 if mapping: | |
1547 errmess('get_useparameters: mapping for %s not impl.' % (mapping)) | |
1548 for k, v in list(params.items()): | |
1549 if k in param_map: | |
1550 outmess('get_useparameters: overriding parameter %s with'\ | |
1551 ' value from module %s' % (repr(k), repr(usename))) | |
1552 param_map[k] = v | |
1553 | |
1554 return param_map | |
1555 | |
1556 def postcrack2(block,tab='',param_map=None): | |
1557 global f90modulevars | |
1558 if not f90modulevars: | |
1559 return block | |
1560 if isinstance(block, list): | |
1561 ret = [] | |
1562 for g in block: | |
1563 g = postcrack2(g, tab=tab+'\t', param_map=param_map) | |
1564 ret.append(g) | |
1565 return ret | |
1566 setmesstext(block) | |
1567 outmess('%sBlock: %s\n'%(tab, block['name']), 0) | |
1568 | |
1569 if param_map is None: | |
1570 param_map = get_useparameters(block) | |
1571 | |
1572 if param_map is not None and 'vars' in block: | |
1573 vars = block['vars'] | |
1574 for n in list(vars.keys()): | |
1575 var = vars[n] | |
1576 if 'kindselector' in var: | |
1577 kind = var['kindselector'] | |
1578 if 'kind' in kind: | |
1579 val = kind['kind'] | |
1580 if val in param_map: | |
1581 kind['kind'] = param_map[val] | |
1582 new_body = [] | |
1583 for b in block['body']: | |
1584 b = postcrack2(b, tab=tab+'\t', param_map=param_map) | |
1585 new_body.append(b) | |
1586 block['body'] = new_body | |
1587 | |
1588 return block | |
1589 | |
1590 def postcrack(block,args=None,tab=''): | |
1591 """ | |
1592 TODO: | |
1593 function return values | |
1594 determine expression types if in argument list | |
1595 """ | |
1596 global usermodules, onlyfunctions | |
1597 if isinstance(block, list): | |
1598 gret=[] | |
1599 uret=[] | |
1600 for g in block: | |
1601 setmesstext(g) | |
1602 g=postcrack(g, tab=tab+'\t') | |
1603 if 'name' in g and '__user__' in g['name']: # sort user routines to appear first | |
1604 uret.append(g) | |
1605 else: | |
1606 gret.append(g) | |
1607 return uret+gret | |
1608 setmesstext(block) | |
1609 if not isinstance(block, dict) and 'block' not in block: | |
1610 raise Exception('postcrack: Expected block dictionary instead of ' + \ | |
1611 str(block)) | |
1612 if 'name' in block and not block['name']=='unknown_interface': | |
1613 outmess('%sBlock: %s\n'%(tab, block['name']), 0) | |
1614 blocktype=block['block'] | |
1615 block=analyzeargs(block) | |
1616 block=analyzecommon(block) | |
1617 block['vars']=analyzevars(block) | |
1618 block['sortvars']=sortvarnames(block['vars']) | |
1619 if 'args' in block and block['args']: | |
1620 args=block['args'] | |
1621 block['body']=analyzebody(block, args, tab=tab) | |
1622 | |
1623 userisdefined=[] | |
1624 ## fromuser = [] | |
1625 if 'use' in block: | |
1626 useblock=block['use'] | |
1627 for k in list(useblock.keys()): | |
1628 if '__user__' in k: | |
1629 userisdefined.append(k) | |
1630 ## if 'map' in useblock[k]: | |
1631 ## for n in useblock[k]['map'].itervalues(): | |
1632 ## if n not in fromuser: fromuser.append(n) | |
1633 else: useblock={} | |
1634 name='' | |
1635 if 'name' in block: | |
1636 name=block['name'] | |
1637 if 'externals' in block and block['externals']:# and not userisdefined: # Build a __user__ module | |
1638 interfaced=[] | |
1639 if 'interfaced' in block: | |
1640 interfaced=block['interfaced'] | |
1641 mvars=copy.copy(block['vars']) | |
1642 if name: | |
1643 mname=name+'__user__routines' | |
1644 else: | |
1645 mname='unknown__user__routines' | |
1646 if mname in userisdefined: | |
1647 i=1 | |
1648 while '%s_%i'%(mname, i) in userisdefined: i=i+1 | |
1649 mname='%s_%i'%(mname, i) | |
1650 interface={'block':'interface','body':[],'vars':{},'name':name+'_user_interface'} | |
1651 for e in block['externals']: | |
1652 ## if e in fromuser: | |
1653 ## outmess(' Skipping %s that is defined explicitly in another use statement\n'%(`e`)) | |
1654 ## continue | |
1655 if e in interfaced: | |
1656 edef=[] | |
1657 j=-1 | |
1658 for b in block['body']: | |
1659 j=j+1 | |
1660 if b['block']=='interface': | |
1661 i=-1 | |
1662 for bb in b['body']: | |
1663 i=i+1 | |
1664 if 'name' in bb and bb['name']==e: | |
1665 edef=copy.copy(bb) | |
1666 del b['body'][i] | |
1667 break | |
1668 if edef: | |
1669 if not b['body']: del block['body'][j] | |
1670 del interfaced[interfaced.index(e)] | |
1671 break | |
1672 interface['body'].append(edef) | |
1673 else: | |
1674 if e in mvars and not isexternal(mvars[e]): | |
1675 interface['vars'][e]=mvars[e] | |
1676 if interface['vars'] or interface['body']: | |
1677 block['interfaced']=interfaced | |
1678 mblock={'block':'python module','body':[interface],'vars':{},'name':mname,'interfaced':block['externals']} | |
1679 useblock[mname]={} | |
1680 usermodules.append(mblock) | |
1681 if useblock: | |
1682 block['use']=useblock | |
1683 return block | |
1684 | |
1685 def sortvarnames(vars): | |
1686 indep = [] | |
1687 dep = [] | |
1688 for v in list(vars.keys()): | |
1689 if 'depend' in vars[v] and vars[v]['depend']: | |
1690 dep.append(v) | |
1691 #print '%s depends on %s'%(v,vars[v]['depend']) | |
1692 else: indep.append(v) | |
1693 n = len(dep) | |
1694 i = 0 | |
1695 while dep: #XXX: How to catch dependence cycles correctly? | |
1696 v = dep[0] | |
1697 fl = 0 | |
1698 for w in dep[1:]: | |
1699 if w in vars[v]['depend']: | |
1700 fl = 1 | |
1701 break | |
1702 if fl: | |
1703 dep = dep[1:]+[v] | |
1704 i = i + 1 | |
1705 if i>n: | |
1706 errmess('sortvarnames: failed to compute dependencies because' | |
1707 ' of cyclic dependencies between ' | |
1708 +', '.join(dep)+'\n') | |
1709 indep = indep + dep | |
1710 break | |
1711 else: | |
1712 indep.append(v) | |
1713 dep = dep[1:] | |
1714 n = len(dep) | |
1715 i = 0 | |
1716 #print indep | |
1717 return indep | |
1718 | |
1719 def analyzecommon(block): | |
1720 if not hascommon(block): return block | |
1721 commonvars=[] | |
1722 for k in list(block['common'].keys()): | |
1723 comvars=[] | |
1724 for e in block['common'][k]: | |
1725 m=re.match(r'\A\s*\b(?P<name>.*?)\b\s*(\((?P<dims>.*?)\)|)\s*\Z', e, re.I) | |
1726 if m: | |
1727 dims=[] | |
1728 if m.group('dims'): | |
1729 dims=[x.strip() for x in markoutercomma(m.group('dims')).split('@,@')] | |
1730 n=m.group('name').strip() | |
1731 if n in block['vars']: | |
1732 if 'attrspec' in block['vars'][n]: | |
1733 block['vars'][n]['attrspec'].append('dimension(%s)'%(','.join(dims))) | |
1734 else: | |
1735 block['vars'][n]['attrspec']=['dimension(%s)'%(','.join(dims))] | |
1736 else: | |
1737 if dims: | |
1738 block['vars'][n]={'attrspec':['dimension(%s)'%(','.join(dims))]} | |
1739 else: block['vars'][n]={} | |
1740 if n not in commonvars: commonvars.append(n) | |
1741 else: | |
1742 n=e | |
1743 errmess('analyzecommon: failed to extract "<name>[(<dims>)]" from "%s" in common /%s/.\n'%(e, k)) | |
1744 comvars.append(n) | |
1745 block['common'][k]=comvars | |
1746 if 'commonvars' not in block: | |
1747 block['commonvars']=commonvars | |
1748 else: | |
1749 block['commonvars']=block['commonvars']+commonvars | |
1750 return block | |
1751 | |
1752 def analyzebody(block,args,tab=''): | |
1753 global usermodules, skipfuncs, onlyfuncs, f90modulevars | |
1754 setmesstext(block) | |
1755 body=[] | |
1756 for b in block['body']: | |
1757 b['parent_block'] = block | |
1758 if b['block'] in ['function', 'subroutine']: | |
1759 if args is not None and b['name'] not in args: | |
1760 continue | |
1761 else: | |
1762 as_=b['args'] | |
1763 if b['name'] in skipfuncs: | |
1764 continue | |
1765 if onlyfuncs and b['name'] not in onlyfuncs: | |
1766 continue | |
1767 b['saved_interface'] = crack2fortrangen(b, '\n'+' '*6, as_interface=True) | |
1768 | |
1769 else: as_=args | |
1770 b=postcrack(b, as_, tab=tab+'\t') | |
1771 if b['block']=='interface' and not b['body']: | |
1772 if 'f2pyenhancements' not in b: | |
1773 continue | |
1774 if b['block'].replace(' ', '')=='pythonmodule': | |
1775 usermodules.append(b) | |
1776 else: | |
1777 if b['block']=='module': | |
1778 f90modulevars[b['name']] = b['vars'] | |
1779 body.append(b) | |
1780 return body | |
1781 | |
1782 def buildimplicitrules(block): | |
1783 setmesstext(block) | |
1784 implicitrules=defaultimplicitrules | |
1785 attrrules={} | |
1786 if 'implicit' in block: | |
1787 if block['implicit'] is None: | |
1788 implicitrules=None | |
1789 if verbose>1: | |
1790 outmess('buildimplicitrules: no implicit rules for routine %s.\n'%repr(block['name'])) | |
1791 else: | |
1792 for k in list(block['implicit'].keys()): | |
1793 if block['implicit'][k].get('typespec') not in ['static', 'automatic']: | |
1794 implicitrules[k]=block['implicit'][k] | |
1795 else: | |
1796 attrrules[k]=block['implicit'][k]['typespec'] | |
1797 return implicitrules, attrrules | |
1798 | |
1799 def myeval(e,g=None,l=None): | |
1800 r = eval(e, g, l) | |
1801 if type(r) in [type(0), type(0.0)]: | |
1802 return r | |
1803 raise ValueError('r=%r' % (r)) | |
1804 | |
1805 getlincoef_re_1 = re.compile(r'\A\b\w+\b\Z', re.I) | |
1806 def getlincoef(e, xset): # e = a*x+b ; x in xset | |
1807 try: | |
1808 c = int(myeval(e, {}, {})) | |
1809 return 0, c, None | |
1810 except: pass | |
1811 if getlincoef_re_1.match(e): | |
1812 return 1, 0, e | |
1813 len_e = len(e) | |
1814 for x in xset: | |
1815 if len(x)>len_e: continue | |
1816 if re.search(r'\w\s*\([^)]*\b'+x+r'\b', e): | |
1817 # skip function calls having x as an argument, e.g max(1, x) | |
1818 continue | |
1819 re_1 = re.compile(r'(?P<before>.*?)\b'+x+r'\b(?P<after>.*)', re.I) | |
1820 m = re_1.match(e) | |
1821 if m: | |
1822 try: | |
1823 m1 = re_1.match(e) | |
1824 while m1: | |
1825 ee = '%s(%s)%s'%(m1.group('before'), 0, m1.group('after')) | |
1826 m1 = re_1.match(ee) | |
1827 b = myeval(ee, {}, {}) | |
1828 m1 = re_1.match(e) | |
1829 while m1: | |
1830 ee = '%s(%s)%s'%(m1.group('before'), 1, m1.group('after')) | |
1831 m1 = re_1.match(ee) | |
1832 a = myeval(ee, {}, {}) - b | |
1833 m1 = re_1.match(e) | |
1834 while m1: | |
1835 ee = '%s(%s)%s'%(m1.group('before'), 0.5, m1.group('after')) | |
1836 m1 = re_1.match(ee) | |
1837 c = myeval(ee, {}, {}) | |
1838 # computing another point to be sure that expression is linear | |
1839 m1 = re_1.match(e) | |
1840 while m1: | |
1841 ee = '%s(%s)%s'%(m1.group('before'), 1.5, m1.group('after')) | |
1842 m1 = re_1.match(ee) | |
1843 c2 = myeval(ee, {}, {}) | |
1844 if (a*0.5+b==c and a*1.5+b==c2): | |
1845 return a, b, x | |
1846 except: pass | |
1847 break | |
1848 return None, None, None | |
1849 | |
1850 _varname_match = re.compile(r'\A[a-z]\w*\Z').match | |
1851 def getarrlen(dl,args,star='*'): | |
1852 edl = [] | |
1853 try: edl.append(myeval(dl[0], {}, {})) | |
1854 except: edl.append(dl[0]) | |
1855 try: edl.append(myeval(dl[1], {}, {})) | |
1856 except: edl.append(dl[1]) | |
1857 if isinstance(edl[0], int): | |
1858 p1 = 1-edl[0] | |
1859 if p1==0: d = str(dl[1]) | |
1860 elif p1<0: d = '%s-%s'%(dl[1], -p1) | |
1861 else: d = '%s+%s'%(dl[1], p1) | |
1862 elif isinstance(edl[1], int): | |
1863 p1 = 1+edl[1] | |
1864 if p1==0: d='-(%s)' % (dl[0]) | |
1865 else: d='%s-(%s)' % (p1, dl[0]) | |
1866 else: d = '%s-(%s)+1'%(dl[1], dl[0]) | |
1867 try: return repr(myeval(d, {}, {})), None, None | |
1868 except: pass | |
1869 d1, d2=getlincoef(dl[0], args), getlincoef(dl[1], args) | |
1870 if None not in [d1[0], d2[0]]: | |
1871 if (d1[0], d2[0])==(0, 0): | |
1872 return repr(d2[1]-d1[1]+1), None, None | |
1873 b = d2[1] - d1[1] + 1 | |
1874 d1 = (d1[0], 0, d1[2]) | |
1875 d2 = (d2[0], b, d2[2]) | |
1876 if d1[0]==0 and d2[2] in args: | |
1877 if b<0: return '%s * %s - %s'%(d2[0], d2[2], -b), d2[2], '+%s)/(%s)'%(-b, d2[0]) | |
1878 elif b: return '%s * %s + %s'%(d2[0], d2[2], b), d2[2], '-%s)/(%s)'%(b, d2[0]) | |
1879 else: return '%s * %s'%(d2[0], d2[2]), d2[2], ')/(%s)'%(d2[0]) | |
1880 if d2[0]==0 and d1[2] in args: | |
1881 | |
1882 if b<0: return '%s * %s - %s'%(-d1[0], d1[2], -b), d1[2], '+%s)/(%s)'%(-b, -d1[0]) | |
1883 elif b: return '%s * %s + %s'%(-d1[0], d1[2], b), d1[2], '-%s)/(%s)'%(b, -d1[0]) | |
1884 else: return '%s * %s'%(-d1[0], d1[2]), d1[2], ')/(%s)'%(-d1[0]) | |
1885 if d1[2]==d2[2] and d1[2] in args: | |
1886 a = d2[0] - d1[0] | |
1887 if not a: return repr(b), None, None | |
1888 if b<0: return '%s * %s - %s'%(a, d1[2], -b), d2[2], '+%s)/(%s)'%(-b, a) | |
1889 elif b: return '%s * %s + %s'%(a, d1[2], b), d2[2], '-%s)/(%s)'%(b, a) | |
1890 else: return '%s * %s'%(a, d1[2]), d2[2], ')/(%s)'%(a) | |
1891 if d1[0]==d2[0]==1: | |
1892 c = str(d1[2]) | |
1893 if c not in args: | |
1894 if _varname_match(c): | |
1895 outmess('\tgetarrlen:variable "%s" undefined\n' % (c)) | |
1896 c = '(%s)'%c | |
1897 if b==0: d='%s-%s' % (d2[2], c) | |
1898 elif b<0: d='%s-%s-%s' % (d2[2], c, -b) | |
1899 else: d='%s-%s+%s' % (d2[2], c, b) | |
1900 elif d1[0]==0: | |
1901 c2 = str(d2[2]) | |
1902 if c2 not in args: | |
1903 if _varname_match(c2): | |
1904 outmess('\tgetarrlen:variable "%s" undefined\n' % (c2)) | |
1905 c2 = '(%s)'%c2 | |
1906 if d2[0]==1: pass | |
1907 elif d2[0]==-1: c2='-%s' %c2 | |
1908 else: c2='%s*%s'%(d2[0], c2) | |
1909 | |
1910 if b==0: d=c2 | |
1911 elif b<0: d='%s-%s' % (c2, -b) | |
1912 else: d='%s+%s' % (c2, b) | |
1913 elif d2[0]==0: | |
1914 c1 = str(d1[2]) | |
1915 if c1 not in args: | |
1916 if _varname_match(c1): | |
1917 outmess('\tgetarrlen:variable "%s" undefined\n' % (c1)) | |
1918 c1 = '(%s)'%c1 | |
1919 if d1[0]==1: c1='-%s'%c1 | |
1920 elif d1[0]==-1: c1='+%s'%c1 | |
1921 elif d1[0]<0: c1='+%s*%s'%(-d1[0], c1) | |
1922 else: c1 = '-%s*%s' % (d1[0], c1) | |
1923 | |
1924 if b==0: d=c1 | |
1925 elif b<0: d='%s-%s' % (c1, -b) | |
1926 else: d='%s+%s' % (c1, b) | |
1927 else: | |
1928 c1 = str(d1[2]) | |
1929 if c1 not in args: | |
1930 if _varname_match(c1): | |
1931 outmess('\tgetarrlen:variable "%s" undefined\n' % (c1)) | |
1932 c1 = '(%s)'%c1 | |
1933 if d1[0]==1: c1='-%s'%c1 | |
1934 elif d1[0]==-1: c1='+%s'%c1 | |
1935 elif d1[0]<0: c1='+%s*%s'%(-d1[0], c1) | |
1936 else: c1 = '-%s*%s' % (d1[0], c1) | |
1937 | |
1938 c2 = str(d2[2]) | |
1939 if c2 not in args: | |
1940 if _varname_match(c2): | |
1941 outmess('\tgetarrlen:variable "%s" undefined\n' % (c2)) | |
1942 c2 = '(%s)'%c2 | |
1943 if d2[0]==1: pass | |
1944 elif d2[0]==-1: c2='-%s' %c2 | |
1945 else: c2='%s*%s'%(d2[0], c2) | |
1946 | |
1947 if b==0: d='%s%s' % (c2, c1) | |
1948 elif b<0: d='%s%s-%s' % (c2, c1, -b) | |
1949 else: d='%s%s+%s' % (c2, c1, b) | |
1950 return d, None, None | |
1951 | |
1952 word_pattern = re.compile(r'\b[a-z][\w$]*\b', re.I) | |
1953 | |
1954 def _get_depend_dict(name, vars, deps): | |
1955 if name in vars: | |
1956 words = vars[name].get('depend', []) | |
1957 | |
1958 if '=' in vars[name] and not isstring(vars[name]): | |
1959 for word in word_pattern.findall(vars[name]['=']): | |
1960 if word not in words and word in vars: | |
1961 words.append(word) | |
1962 for word in words[:]: | |
1963 for w in deps.get(word, []) \ | |
1964 or _get_depend_dict(word, vars, deps): | |
1965 if w not in words: | |
1966 words.append(w) | |
1967 else: | |
1968 outmess('_get_depend_dict: no dependence info for %s\n' % (repr(name))) | |
1969 words = [] | |
1970 deps[name] = words | |
1971 return words | |
1972 | |
1973 def _calc_depend_dict(vars): | |
1974 names = list(vars.keys()) | |
1975 depend_dict = {} | |
1976 for n in names: | |
1977 _get_depend_dict(n, vars, depend_dict) | |
1978 return depend_dict | |
1979 | |
1980 def get_sorted_names(vars): | |
1981 """ | |
1982 """ | |
1983 depend_dict = _calc_depend_dict(vars) | |
1984 names = [] | |
1985 for name in list(depend_dict.keys()): | |
1986 if not depend_dict[name]: | |
1987 names.append(name) | |
1988 del depend_dict[name] | |
1989 while depend_dict: | |
1990 for name, lst in list(depend_dict.items()): | |
1991 new_lst = [n for n in lst if n in depend_dict] | |
1992 if not new_lst: | |
1993 names.append(name) | |
1994 del depend_dict[name] | |
1995 else: | |
1996 depend_dict[name] = new_lst | |
1997 return [name for name in names if name in vars] | |
1998 | |
1999 def _kind_func(string): | |
2000 #XXX: return something sensible. | |
2001 if string[0] in "'\"": | |
2002 string = string[1:-1] | |
2003 if real16pattern.match(string): | |
2004 return 8 | |
2005 elif real8pattern.match(string): | |
2006 return 4 | |
2007 return 'kind('+string+')' | |
2008 | |
2009 def _selected_int_kind_func(r): | |
2010 #XXX: This should be processor dependent | |
2011 m = 10**r | |
2012 if m<=2**8: return 1 | |
2013 if m<=2**16: return 2 | |
2014 if m<=2**32: return 4 | |
2015 if m<=2**63: return 8 | |
2016 if m<=2**128: return 16 | |
2017 return -1 | |
2018 | |
2019 def _selected_real_kind_func(p, r=0, radix=0): | |
2020 #XXX: This should be processor dependent | |
2021 # This is only good for 0 <= p <= 20 | |
2022 if p < 7: return 4 | |
2023 if p < 16: return 8 | |
2024 if platform.machine().lower().startswith('power'): | |
2025 if p <= 20: | |
2026 return 16 | |
2027 else: | |
2028 if p < 19: | |
2029 return 10 | |
2030 elif p <= 20: | |
2031 return 16 | |
2032 return -1 | |
2033 | |
2034 def get_parameters(vars, global_params={}): | |
2035 params = copy.copy(global_params) | |
2036 g_params = copy.copy(global_params) | |
2037 for name, func in [('kind', _kind_func), | |
2038 ('selected_int_kind', _selected_int_kind_func), | |
2039 ('selected_real_kind', _selected_real_kind_func), | |
2040 ]: | |
2041 if name not in g_params: | |
2042 g_params[name] = func | |
2043 param_names = [] | |
2044 for n in get_sorted_names(vars): | |
2045 if 'attrspec' in vars[n] and 'parameter' in vars[n]['attrspec']: | |
2046 param_names.append(n) | |
2047 kind_re = re.compile(r'\bkind\s*\(\s*(?P<value>.*)\s*\)', re.I) | |
2048 selected_int_kind_re = re.compile(r'\bselected_int_kind\s*\(\s*(?P<value>.*)\s*\)', re.I) | |
2049 selected_kind_re = re.compile(r'\bselected_(int|real)_kind\s*\(\s*(?P<value>.*)\s*\)', re.I) | |
2050 for n in param_names: | |
2051 if '=' in vars[n]: | |
2052 v = vars[n]['='] | |
2053 if islogical(vars[n]): | |
2054 v = v.lower() | |
2055 for repl in [ | |
2056 ('.false.', 'False'), | |
2057 ('.true.', 'True'), | |
2058 #TODO: test .eq., .neq., etc replacements. | |
2059 ]: | |
2060 v = v.replace(*repl) | |
2061 v = kind_re.sub(r'kind("\1")', v) | |
2062 v = selected_int_kind_re.sub(r'selected_int_kind(\1)', v) | |
2063 if isinteger(vars[n]) and not selected_kind_re.match(v): | |
2064 v = v.split('_')[0] | |
2065 if isdouble(vars[n]): | |
2066 tt = list(v) | |
2067 for m in real16pattern.finditer(v): | |
2068 tt[m.start():m.end()] = list(\ | |
2069 v[m.start():m.end()].lower().replace('d', 'e')) | |
2070 v = ''.join(tt) | |
2071 if iscomplex(vars[n]): | |
2072 if v[0]=='(' and v[-1]==')': | |
2073 l = markoutercomma(v[1:-1]).split('@,@') | |
2074 try: | |
2075 params[n] = eval(v, g_params, params) | |
2076 except Exception as msg: | |
2077 params[n] = v | |
2078 #print params | |
2079 outmess('get_parameters: got "%s" on %s\n' % (msg, repr(v))) | |
2080 if isstring(vars[n]) and isinstance(params[n], int): | |
2081 params[n] = chr(params[n]) | |
2082 nl = n.lower() | |
2083 if nl!=n: | |
2084 params[nl] = params[n] | |
2085 else: | |
2086 print(vars[n]) | |
2087 outmess('get_parameters:parameter %s does not have value?!\n'%(repr(n))) | |
2088 return params | |
2089 | |
2090 def _eval_length(length, params): | |
2091 if length in ['(:)', '(*)', '*']: | |
2092 return '(*)' | |
2093 return _eval_scalar(length, params) | |
2094 | |
2095 _is_kind_number = re.compile(r'\d+_').match | |
2096 | |
2097 def _eval_scalar(value, params): | |
2098 if _is_kind_number(value): | |
2099 value = value.split('_')[0] | |
2100 try: | |
2101 value = str(eval(value, {}, params)) | |
2102 except (NameError, SyntaxError): | |
2103 return value | |
2104 except Exception as msg: | |
2105 errmess('"%s" in evaluating %r '\ | |
2106 '(available names: %s)\n' \ | |
2107 % (msg, value, list(params.keys()))) | |
2108 return value | |
2109 | |
2110 def analyzevars(block): | |
2111 global f90modulevars | |
2112 setmesstext(block) | |
2113 implicitrules, attrrules=buildimplicitrules(block) | |
2114 vars=copy.copy(block['vars']) | |
2115 if block['block']=='function' and block['name'] not in vars: | |
2116 vars[block['name']]={} | |
2117 if '' in block['vars']: | |
2118 del vars[''] | |
2119 if 'attrspec' in block['vars']['']: | |
2120 gen=block['vars']['']['attrspec'] | |
2121 for n in list(vars.keys()): | |
2122 for k in ['public', 'private']: | |
2123 if k in gen: | |
2124 vars[n]=setattrspec(vars[n], k) | |
2125 svars=[] | |
2126 args = block['args'] | |
2127 for a in args: | |
2128 try: | |
2129 vars[a] | |
2130 svars.append(a) | |
2131 except KeyError: | |
2132 pass | |
2133 for n in list(vars.keys()): | |
2134 if n not in args: svars.append(n) | |
2135 | |
2136 params = get_parameters(vars, get_useparameters(block)) | |
2137 | |
2138 dep_matches = {} | |
2139 name_match = re.compile(r'\w[\w\d_$]*').match | |
2140 for v in list(vars.keys()): | |
2141 m = name_match(v) | |
2142 if m: | |
2143 n = v[m.start():m.end()] | |
2144 try: | |
2145 dep_matches[n] | |
2146 except KeyError: | |
2147 dep_matches[n] = re.compile(r'.*\b%s\b'%(v), re.I).match | |
2148 for n in svars: | |
2149 if n[0] in list(attrrules.keys()): | |
2150 vars[n]=setattrspec(vars[n], attrrules[n[0]]) | |
2151 if 'typespec' not in vars[n]: | |
2152 if not('attrspec' in vars[n] and 'external' in vars[n]['attrspec']): | |
2153 if implicitrules: | |
2154 ln0 = n[0].lower() | |
2155 for k in list(implicitrules[ln0].keys()): | |
2156 if k=='typespec' and implicitrules[ln0][k]=='undefined': | |
2157 continue | |
2158 if k not in vars[n]: | |
2159 vars[n][k]=implicitrules[ln0][k] | |
2160 elif k=='attrspec': | |
2161 for l in implicitrules[ln0][k]: | |
2162 vars[n]=setattrspec(vars[n], l) | |
2163 elif n in block['args']: | |
2164 outmess('analyzevars: typespec of variable %s is not defined in routine %s.\n'%(repr(n), block['name'])) | |
2165 | |
2166 if 'charselector' in vars[n]: | |
2167 if 'len' in vars[n]['charselector']: | |
2168 l = vars[n]['charselector']['len'] | |
2169 try: | |
2170 l = str(eval(l, {}, params)) | |
2171 except: | |
2172 pass | |
2173 vars[n]['charselector']['len'] = l | |
2174 | |
2175 if 'kindselector' in vars[n]: | |
2176 if 'kind' in vars[n]['kindselector']: | |
2177 l = vars[n]['kindselector']['kind'] | |
2178 try: | |
2179 l = str(eval(l, {}, params)) | |
2180 except: | |
2181 pass | |
2182 vars[n]['kindselector']['kind'] = l | |
2183 | |
2184 savelindims = {} | |
2185 if 'attrspec' in vars[n]: | |
2186 attr=vars[n]['attrspec'] | |
2187 attr.reverse() | |
2188 vars[n]['attrspec']=[] | |
2189 dim, intent, depend, check, note=None, None, None, None, None | |
2190 for a in attr: | |
2191 if a[:9]=='dimension': dim=(a[9:].strip())[1:-1] | |
2192 elif a[:6]=='intent': intent=(a[6:].strip())[1:-1] | |
2193 elif a[:6]=='depend': depend=(a[6:].strip())[1:-1] | |
2194 elif a[:5]=='check': check=(a[5:].strip())[1:-1] | |
2195 elif a[:4]=='note': note=(a[4:].strip())[1:-1] | |
2196 else: vars[n]=setattrspec(vars[n], a) | |
2197 if intent: | |
2198 if 'intent' not in vars[n]: | |
2199 vars[n]['intent']=[] | |
2200 for c in [x.strip() for x in markoutercomma(intent).split('@,@')]: | |
2201 # Remove spaces so that 'in out' becomes 'inout' | |
2202 tmp = c.replace(' ', '') | |
2203 if tmp not in vars[n]['intent']: | |
2204 vars[n]['intent'].append(tmp) | |
2205 intent=None | |
2206 if note: | |
2207 note=note.replace('\\n\\n', '\n\n') | |
2208 note=note.replace('\\n ', '\n') | |
2209 if 'note' not in vars[n]: | |
2210 vars[n]['note']=[note] | |
2211 else: | |
2212 vars[n]['note'].append(note) | |
2213 note=None | |
2214 if depend is not None: | |
2215 if 'depend' not in vars[n]: | |
2216 vars[n]['depend']=[] | |
2217 for c in rmbadname([x.strip() for x in markoutercomma(depend).split('@,@')]): | |
2218 if c not in vars[n]['depend']: | |
2219 vars[n]['depend'].append(c) | |
2220 depend=None | |
2221 if check is not None: | |
2222 if 'check' not in vars[n]: | |
2223 vars[n]['check']=[] | |
2224 for c in [x.strip() for x in markoutercomma(check).split('@,@')]: | |
2225 if c not in vars[n]['check']: | |
2226 vars[n]['check'].append(c) | |
2227 check=None | |
2228 if dim and 'dimension' not in vars[n]: | |
2229 vars[n]['dimension']=[] | |
2230 for d in rmbadname([x.strip() for x in markoutercomma(dim).split('@,@')]): | |
2231 star = '*' | |
2232 if d==':': | |
2233 star=':' | |
2234 if d in params: | |
2235 d = str(params[d]) | |
2236 for p in list(params.keys()): | |
2237 m = re.match(r'(?P<before>.*?)\b'+p+r'\b(?P<after>.*)', d, re.I) | |
2238 if m: | |
2239 #outmess('analyzevars:replacing parameter %s in %s (dimension of %s) with %s\n'%(`p`,`d`,`n`,`params[p]`)) | |
2240 d = m.group('before')+str(params[p])+m.group('after') | |
2241 if d==star: | |
2242 dl = [star] | |
2243 else: | |
2244 dl=markoutercomma(d, ':').split('@:@') | |
2245 if len(dl)==2 and '*' in dl: # e.g. dimension(5:*) | |
2246 dl = ['*'] | |
2247 d = '*' | |
2248 if len(dl)==1 and not dl[0]==star: dl = ['1', dl[0]] | |
2249 if len(dl)==2: | |
2250 d, v, di = getarrlen(dl, list(block['vars'].keys())) | |
2251 if d[:4] == '1 * ': d = d[4:] | |
2252 if di and di[-4:] == '/(1)': di = di[:-4] | |
2253 if v: savelindims[d] = v, di | |
2254 vars[n]['dimension'].append(d) | |
2255 if 'dimension' in vars[n]: | |
2256 if isintent_c(vars[n]): | |
2257 shape_macro = 'shape' | |
2258 else: | |
2259 shape_macro = 'shape'#'fshape' | |
2260 if isstringarray(vars[n]): | |
2261 if 'charselector' in vars[n]: | |
2262 d = vars[n]['charselector'] | |
2263 if '*' in d: | |
2264 d = d['*'] | |
2265 errmess('analyzevars: character array "character*%s %s(%s)" is considered as "character %s(%s)"; "intent(c)" is forced.\n'\ | |
2266 %(d, n, | |
2267 ','.join(vars[n]['dimension']), | |
2268 n, ','.join(vars[n]['dimension']+[d]))) | |
2269 vars[n]['dimension'].append(d) | |
2270 del vars[n]['charselector'] | |
2271 if 'intent' not in vars[n]: | |
2272 vars[n]['intent'] = [] | |
2273 if 'c' not in vars[n]['intent']: | |
2274 vars[n]['intent'].append('c') | |
2275 else: | |
2276 errmess("analyzevars: charselector=%r unhandled." % (d)) | |
2277 if 'check' not in vars[n] and 'args' in block and n in block['args']: | |
2278 flag = 'depend' not in vars[n] | |
2279 if flag: | |
2280 vars[n]['depend']=[] | |
2281 vars[n]['check']=[] | |
2282 if 'dimension' in vars[n]: | |
2283 #/----< no check | |
2284 #vars[n]['check'].append('rank(%s)==%s'%(n,len(vars[n]['dimension']))) | |
2285 i=-1; ni=len(vars[n]['dimension']) | |
2286 for d in vars[n]['dimension']: | |
2287 ddeps=[] # dependecies of 'd' | |
2288 ad='' | |
2289 pd='' | |
2290 #origd = d | |
2291 if d not in vars: | |
2292 if d in savelindims: | |
2293 pd, ad='(', savelindims[d][1] | |
2294 d = savelindims[d][0] | |
2295 else: | |
2296 for r in block['args']: | |
2297 #for r in block['vars'].iterkeys(): | |
2298 if r not in vars: | |
2299 continue | |
2300 if re.match(r'.*?\b'+r+r'\b', d, re.I): | |
2301 ddeps.append(r) | |
2302 if d in vars: | |
2303 if 'attrspec' in vars[d]: | |
2304 for aa in vars[d]['attrspec']: | |
2305 if aa[:6]=='depend': | |
2306 ddeps += aa[6:].strip()[1:-1].split(',') | |
2307 if 'depend' in vars[d]: | |
2308 ddeps=ddeps+vars[d]['depend'] | |
2309 i=i+1 | |
2310 if d in vars and ('depend' not in vars[d]) \ | |
2311 and ('=' not in vars[d]) and (d not in vars[n]['depend']) \ | |
2312 and l_or(isintent_in, isintent_inout, isintent_inplace)(vars[n]): | |
2313 vars[d]['depend']=[n] | |
2314 if ni>1: | |
2315 vars[d]['=']='%s%s(%s,%s)%s'% (pd, shape_macro, n, i, ad) | |
2316 else: | |
2317 vars[d]['=']='%slen(%s)%s'% (pd, n, ad) | |
2318 # /---< no check | |
2319 if 1 and 'check' not in vars[d]: | |
2320 if ni>1: | |
2321 vars[d]['check']=['%s%s(%s,%i)%s==%s'\ | |
2322 %(pd, shape_macro, n, i, ad, d)] | |
2323 else: | |
2324 vars[d]['check']=['%slen(%s)%s>=%s'%(pd, n, ad, d)] | |
2325 if 'attrspec' not in vars[d]: | |
2326 vars[d]['attrspec']=['optional'] | |
2327 if ('optional' not in vars[d]['attrspec']) and\ | |
2328 ('required' not in vars[d]['attrspec']): | |
2329 vars[d]['attrspec'].append('optional') | |
2330 elif d not in ['*', ':']: | |
2331 #/----< no check | |
2332 #if ni>1: vars[n]['check'].append('shape(%s,%i)==%s'%(n,i,d)) | |
2333 #else: vars[n]['check'].append('len(%s)>=%s'%(n,d)) | |
2334 if flag: | |
2335 if d in vars: | |
2336 if n not in ddeps: | |
2337 vars[n]['depend'].append(d) | |
2338 else: | |
2339 vars[n]['depend'] = vars[n]['depend'] + ddeps | |
2340 elif isstring(vars[n]): | |
2341 length='1' | |
2342 if 'charselector' in vars[n]: | |
2343 if '*' in vars[n]['charselector']: | |
2344 length = _eval_length(vars[n]['charselector']['*'], | |
2345 params) | |
2346 vars[n]['charselector']['*']=length | |
2347 elif 'len' in vars[n]['charselector']: | |
2348 length = _eval_length(vars[n]['charselector']['len'], | |
2349 params) | |
2350 del vars[n]['charselector']['len'] | |
2351 vars[n]['charselector']['*']=length | |
2352 | |
2353 if not vars[n]['check']: | |
2354 del vars[n]['check'] | |
2355 if flag and not vars[n]['depend']: | |
2356 del vars[n]['depend'] | |
2357 if '=' in vars[n]: | |
2358 if 'attrspec' not in vars[n]: | |
2359 vars[n]['attrspec']=[] | |
2360 if ('optional' not in vars[n]['attrspec']) and \ | |
2361 ('required' not in vars[n]['attrspec']): | |
2362 vars[n]['attrspec'].append('optional') | |
2363 if 'depend' not in vars[n]: | |
2364 vars[n]['depend']=[] | |
2365 for v, m in list(dep_matches.items()): | |
2366 if m(vars[n]['=']): vars[n]['depend'].append(v) | |
2367 if not vars[n]['depend']: del vars[n]['depend'] | |
2368 if isscalar(vars[n]): | |
2369 vars[n]['='] = _eval_scalar(vars[n]['='], params) | |
2370 | |
2371 for n in list(vars.keys()): | |
2372 if n==block['name']: # n is block name | |
2373 if 'note' in vars[n]: | |
2374 block['note']=vars[n]['note'] | |
2375 if block['block']=='function': | |
2376 if 'result' in block and block['result'] in vars: | |
2377 vars[n]=appenddecl(vars[n], vars[block['result']]) | |
2378 if 'prefix' in block: | |
2379 pr=block['prefix']; ispure=0; isrec=1 | |
2380 pr1=pr.replace('pure', '') | |
2381 ispure=(not pr==pr1) | |
2382 pr=pr1.replace('recursive', '') | |
2383 isrec=(not pr==pr1) | |
2384 m=typespattern[0].match(pr) | |
2385 if m: | |
2386 typespec, selector, attr, edecl=cracktypespec0(m.group('this'), m.group('after')) | |
2387 kindselect, charselect, typename=cracktypespec(typespec, selector) | |
2388 vars[n]['typespec']=typespec | |
2389 if kindselect: | |
2390 if 'kind' in kindselect: | |
2391 try: | |
2392 kindselect['kind'] = eval(kindselect['kind'], {}, params) | |
2393 except: | |
2394 pass | |
2395 vars[n]['kindselector']=kindselect | |
2396 if charselect: vars[n]['charselector']=charselect | |
2397 if typename: vars[n]['typename']=typename | |
2398 if ispure: vars[n]=setattrspec(vars[n], 'pure') | |
2399 if isrec: vars[n]=setattrspec(vars[n], 'recursive') | |
2400 else: | |
2401 outmess('analyzevars: prefix (%s) were not used\n'%repr(block['prefix'])) | |
2402 if not block['block'] in ['module', 'pythonmodule', 'python module', 'block data']: | |
2403 if 'commonvars' in block: | |
2404 neededvars=copy.copy(block['args']+block['commonvars']) | |
2405 else: | |
2406 neededvars=copy.copy(block['args']) | |
2407 for n in list(vars.keys()): | |
2408 if l_or(isintent_callback, isintent_aux)(vars[n]): | |
2409 neededvars.append(n) | |
2410 if 'entry' in block: | |
2411 neededvars.extend(list(block['entry'].keys())) | |
2412 for k in list(block['entry'].keys()): | |
2413 for n in block['entry'][k]: | |
2414 if n not in neededvars: | |
2415 neededvars.append(n) | |
2416 if block['block']=='function': | |
2417 if 'result' in block: | |
2418 neededvars.append(block['result']) | |
2419 else: | |
2420 neededvars.append(block['name']) | |
2421 if block['block'] in ['subroutine', 'function']: | |
2422 name = block['name'] | |
2423 if name in vars and 'intent' in vars[name]: | |
2424 block['intent'] = vars[name]['intent'] | |
2425 if block['block'] == 'type': | |
2426 neededvars.extend(list(vars.keys())) | |
2427 for n in list(vars.keys()): | |
2428 if n not in neededvars: | |
2429 del vars[n] | |
2430 return vars | |
2431 | |
2432 analyzeargs_re_1 = re.compile(r'\A[a-z]+[\w$]*\Z', re.I) | |
2433 def expr2name(a, block, args=[]): | |
2434 orig_a = a | |
2435 a_is_expr = not analyzeargs_re_1.match(a) | |
2436 if a_is_expr: # `a` is an expression | |
2437 implicitrules, attrrules=buildimplicitrules(block) | |
2438 at=determineexprtype(a, block['vars'], implicitrules) | |
2439 na='e_' | |
2440 for c in a: | |
2441 c = c.lower() | |
2442 if c not in string.ascii_lowercase+string.digits: c='_' | |
2443 na=na+c | |
2444 if na[-1]=='_': na=na+'e' | |
2445 else: na=na+'_e' | |
2446 a=na | |
2447 while a in block['vars'] or a in block['args']: | |
2448 a=a+'r' | |
2449 if a in args: | |
2450 k = 1 | |
2451 while a + str(k) in args: | |
2452 k = k + 1 | |
2453 a = a + str(k) | |
2454 if a_is_expr: | |
2455 block['vars'][a]=at | |
2456 else: | |
2457 if a not in block['vars']: | |
2458 if orig_a in block['vars']: | |
2459 block['vars'][a] = block['vars'][orig_a] | |
2460 else: | |
2461 block['vars'][a]={} | |
2462 if 'externals' in block and orig_a in block['externals']+block['interfaced']: | |
2463 block['vars'][a]=setattrspec(block['vars'][a], 'external') | |
2464 return a | |
2465 | |
2466 def analyzeargs(block): | |
2467 setmesstext(block) | |
2468 implicitrules, attrrules=buildimplicitrules(block) | |
2469 if 'args' not in block: | |
2470 block['args']=[] | |
2471 args=[] | |
2472 for a in block['args']: | |
2473 a = expr2name(a, block, args) | |
2474 args.append(a) | |
2475 block['args']=args | |
2476 if 'entry' in block: | |
2477 for k, args1 in list(block['entry'].items()): | |
2478 for a in args1: | |
2479 if a not in block['vars']: | |
2480 block['vars'][a]={} | |
2481 | |
2482 for b in block['body']: | |
2483 if b['name'] in args: | |
2484 if 'externals' not in block: | |
2485 block['externals']=[] | |
2486 if b['name'] not in block['externals']: | |
2487 block['externals'].append(b['name']) | |
2488 if 'result' in block and block['result'] not in block['vars']: | |
2489 block['vars'][block['result']]={} | |
2490 return block | |
2491 | |
2492 determineexprtype_re_1 = re.compile(r'\A\(.+?[,].+?\)\Z', re.I) | |
2493 determineexprtype_re_2 = re.compile(r'\A[+-]?\d+(_(P<name>[\w]+)|)\Z', re.I) | |
2494 determineexprtype_re_3 = re.compile(r'\A[+-]?[\d.]+[\d+-de.]*(_(P<name>[\w]+)|)\Z', re.I) | |
2495 determineexprtype_re_4 = re.compile(r'\A\(.*\)\Z', re.I) | |
2496 determineexprtype_re_5 = re.compile(r'\A(?P<name>\w+)\s*\(.*?\)\s*\Z', re.I) | |
2497 def _ensure_exprdict(r): | |
2498 if isinstance(r, int): | |
2499 return {'typespec':'integer'} | |
2500 if isinstance(r, float): | |
2501 return {'typespec':'real'} | |
2502 if isinstance(r, complex): | |
2503 return {'typespec':'complex'} | |
2504 if isinstance(r, dict): | |
2505 return r | |
2506 raise AssertionError(repr(r)) | |
2507 | |
2508 def determineexprtype(expr,vars,rules={}): | |
2509 if expr in vars: | |
2510 return _ensure_exprdict(vars[expr]) | |
2511 expr=expr.strip() | |
2512 if determineexprtype_re_1.match(expr): | |
2513 return {'typespec':'complex'} | |
2514 m=determineexprtype_re_2.match(expr) | |
2515 if m: | |
2516 if 'name' in m.groupdict() and m.group('name'): | |
2517 outmess('determineexprtype: selected kind types not supported (%s)\n'%repr(expr)) | |
2518 return {'typespec':'integer'} | |
2519 m = determineexprtype_re_3.match(expr) | |
2520 if m: | |
2521 if 'name' in m.groupdict() and m.group('name'): | |
2522 outmess('determineexprtype: selected kind types not supported (%s)\n'%repr(expr)) | |
2523 return {'typespec':'real'} | |
2524 for op in ['+', '-', '*', '/']: | |
2525 for e in [x.strip() for x in markoutercomma(expr, comma=op).split('@'+op+'@')]: | |
2526 if e in vars: | |
2527 return _ensure_exprdict(vars[e]) | |
2528 t={} | |
2529 if determineexprtype_re_4.match(expr): # in parenthesis | |
2530 t=determineexprtype(expr[1:-1], vars, rules) | |
2531 else: | |
2532 m = determineexprtype_re_5.match(expr) | |
2533 if m: | |
2534 rn=m.group('name') | |
2535 t=determineexprtype(m.group('name'), vars, rules) | |
2536 if t and 'attrspec' in t: | |
2537 del t['attrspec'] | |
2538 if not t: | |
2539 if rn[0] in rules: | |
2540 return _ensure_exprdict(rules[rn[0]]) | |
2541 if expr[0] in '\'"': | |
2542 return {'typespec':'character','charselector':{'*':'*'}} | |
2543 if not t: | |
2544 outmess('determineexprtype: could not determine expressions (%s) type.\n'%(repr(expr))) | |
2545 return t | |
2546 | |
2547 ###### | |
2548 def crack2fortrangen(block,tab='\n', as_interface=False): | |
2549 global skipfuncs, onlyfuncs | |
2550 setmesstext(block) | |
2551 ret='' | |
2552 if isinstance(block, list): | |
2553 for g in block: | |
2554 if g and g['block'] in ['function', 'subroutine']: | |
2555 if g['name'] in skipfuncs: | |
2556 continue | |
2557 if onlyfuncs and g['name'] not in onlyfuncs: | |
2558 continue | |
2559 ret=ret+crack2fortrangen(g, tab, as_interface=as_interface) | |
2560 return ret | |
2561 prefix='' | |
2562 name='' | |
2563 args='' | |
2564 blocktype=block['block'] | |
2565 if blocktype=='program': return '' | |
2566 argsl = [] | |
2567 if 'name' in block: | |
2568 name=block['name'] | |
2569 if 'args' in block: | |
2570 vars = block['vars'] | |
2571 for a in block['args']: | |
2572 a = expr2name(a, block, argsl) | |
2573 if not isintent_callback(vars[a]): | |
2574 argsl.append(a) | |
2575 if block['block']=='function' or argsl: | |
2576 args='(%s)'%','.join(argsl) | |
2577 f2pyenhancements = '' | |
2578 if 'f2pyenhancements' in block: | |
2579 for k in list(block['f2pyenhancements'].keys()): | |
2580 f2pyenhancements = '%s%s%s %s'%(f2pyenhancements, tab+tabchar, k, block['f2pyenhancements'][k]) | |
2581 intent_lst = block.get('intent', [])[:] | |
2582 if blocktype=='function' and 'callback' in intent_lst: | |
2583 intent_lst.remove('callback') | |
2584 if intent_lst: | |
2585 f2pyenhancements = '%s%sintent(%s) %s'%\ | |
2586 (f2pyenhancements, tab+tabchar, | |
2587 ','.join(intent_lst), name) | |
2588 use='' | |
2589 if 'use' in block: | |
2590 use=use2fortran(block['use'], tab+tabchar) | |
2591 common='' | |
2592 if 'common' in block: | |
2593 common=common2fortran(block['common'], tab+tabchar) | |
2594 if name=='unknown_interface': name='' | |
2595 result='' | |
2596 if 'result' in block: | |
2597 result=' result (%s)'%block['result'] | |
2598 if block['result'] not in argsl: | |
2599 argsl.append(block['result']) | |
2600 #if 'prefix' in block: | |
2601 # prefix=block['prefix']+' ' | |
2602 body=crack2fortrangen(block['body'], tab+tabchar) | |
2603 vars=vars2fortran(block, block['vars'], argsl, tab+tabchar, as_interface=as_interface) | |
2604 mess='' | |
2605 if 'from' in block and not as_interface: | |
2606 mess='! in %s'%block['from'] | |
2607 if 'entry' in block: | |
2608 entry_stmts = '' | |
2609 for k, i in list(block['entry'].items()): | |
2610 entry_stmts = '%s%sentry %s(%s)' \ | |
2611 % (entry_stmts, tab+tabchar, k, ','.join(i)) | |
2612 body = body + entry_stmts | |
2613 if blocktype=='block data' and name=='_BLOCK_DATA_': | |
2614 name = '' | |
2615 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) | |
2616 return ret | |
2617 | |
2618 def common2fortran(common,tab=''): | |
2619 ret='' | |
2620 for k in list(common.keys()): | |
2621 if k=='_BLNK_': | |
2622 ret='%s%scommon %s'%(ret, tab, ','.join(common[k])) | |
2623 else: | |
2624 ret='%s%scommon /%s/ %s'%(ret, tab, k, ','.join(common[k])) | |
2625 return ret | |
2626 | |
2627 def use2fortran(use,tab=''): | |
2628 ret='' | |
2629 for m in list(use.keys()): | |
2630 ret='%s%suse %s,'%(ret, tab, m) | |
2631 if use[m]=={}: | |
2632 if ret and ret[-1]==',': ret=ret[:-1] | |
2633 continue | |
2634 if 'only' in use[m] and use[m]['only']: | |
2635 ret='%s only:'%(ret) | |
2636 if 'map' in use[m] and use[m]['map']: | |
2637 c=' ' | |
2638 for k in list(use[m]['map'].keys()): | |
2639 if k==use[m]['map'][k]: | |
2640 ret='%s%s%s'%(ret, c, k); c=',' | |
2641 else: | |
2642 ret='%s%s%s=>%s'%(ret, c, k, use[m]['map'][k]); c=',' | |
2643 if ret and ret[-1]==',': ret=ret[:-1] | |
2644 return ret | |
2645 | |
2646 def true_intent_list(var): | |
2647 lst = var['intent'] | |
2648 ret = [] | |
2649 for intent in lst: | |
2650 try: | |
2651 c = eval('isintent_%s(var)' % intent) | |
2652 except NameError: | |
2653 c = 0 | |
2654 if c: | |
2655 ret.append(intent) | |
2656 return ret | |
2657 | |
2658 def vars2fortran(block,vars,args,tab='', as_interface=False): | |
2659 """ | |
2660 TODO: | |
2661 public sub | |
2662 ... | |
2663 """ | |
2664 setmesstext(block) | |
2665 ret='' | |
2666 nout=[] | |
2667 for a in args: | |
2668 if a in block['vars']: | |
2669 nout.append(a) | |
2670 if 'commonvars' in block: | |
2671 for a in block['commonvars']: | |
2672 if a in vars: | |
2673 if a not in nout: | |
2674 nout.append(a) | |
2675 else: | |
2676 errmess('vars2fortran: Confused?!: "%s" is not defined in vars.\n'%a) | |
2677 if 'varnames' in block: | |
2678 nout.extend(block['varnames']) | |
2679 if not as_interface: | |
2680 for a in list(vars.keys()): | |
2681 if a not in nout: | |
2682 nout.append(a) | |
2683 for a in nout: | |
2684 if 'depend' in vars[a]: | |
2685 for d in vars[a]['depend']: | |
2686 if d in vars and 'depend' in vars[d] and a in vars[d]['depend']: | |
2687 errmess('vars2fortran: Warning: cross-dependence between variables "%s" and "%s"\n'%(a, d)) | |
2688 if 'externals' in block and a in block['externals']: | |
2689 if isintent_callback(vars[a]): | |
2690 ret='%s%sintent(callback) %s'%(ret, tab, a) | |
2691 ret='%s%sexternal %s'%(ret, tab, a) | |
2692 if isoptional(vars[a]): | |
2693 ret='%s%soptional %s'%(ret, tab, a) | |
2694 if a in vars and 'typespec' not in vars[a]: | |
2695 continue | |
2696 cont=1 | |
2697 for b in block['body']: | |
2698 if a==b['name'] and b['block']=='function': | |
2699 cont=0;break | |
2700 if cont: | |
2701 continue | |
2702 if a not in vars: | |
2703 show(vars) | |
2704 outmess('vars2fortran: No definition for argument "%s".\n'%a) | |
2705 continue | |
2706 if a==block['name'] and not block['block']=='function': | |
2707 continue | |
2708 if 'typespec' not in vars[a]: | |
2709 if 'attrspec' in vars[a] and 'external' in vars[a]['attrspec']: | |
2710 if a in args: | |
2711 ret='%s%sexternal %s'%(ret, tab, a) | |
2712 continue | |
2713 show(vars[a]) | |
2714 outmess('vars2fortran: No typespec for argument "%s".\n'%a) | |
2715 continue | |
2716 vardef=vars[a]['typespec'] | |
2717 if vardef=='type' and 'typename' in vars[a]: | |
2718 vardef='%s(%s)'%(vardef, vars[a]['typename']) | |
2719 selector={} | |
2720 if 'kindselector' in vars[a]: | |
2721 selector=vars[a]['kindselector'] | |
2722 elif 'charselector' in vars[a]: | |
2723 selector=vars[a]['charselector'] | |
2724 if '*' in selector: | |
2725 if selector['*'] in ['*', ':']: | |
2726 vardef='%s*(%s)'%(vardef, selector['*']) | |
2727 else: | |
2728 vardef='%s*%s'%(vardef, selector['*']) | |
2729 else: | |
2730 if 'len' in selector: | |
2731 vardef='%s(len=%s'%(vardef, selector['len']) | |
2732 if 'kind' in selector: | |
2733 vardef='%s,kind=%s)'%(vardef, selector['kind']) | |
2734 else: | |
2735 vardef='%s)'%(vardef) | |
2736 elif 'kind' in selector: | |
2737 vardef='%s(kind=%s)'%(vardef, selector['kind']) | |
2738 c=' ' | |
2739 if 'attrspec' in vars[a]: | |
2740 attr=[] | |
2741 for l in vars[a]['attrspec']: | |
2742 if l not in ['external']: | |
2743 attr.append(l) | |
2744 if attr: | |
2745 vardef='%s, %s'%(vardef, ','.join(attr)) | |
2746 c=',' | |
2747 if 'dimension' in vars[a]: | |
2748 # if not isintent_c(vars[a]): | |
2749 # vars[a]['dimension'].reverse() | |
2750 vardef='%s%sdimension(%s)'%(vardef, c, ','.join(vars[a]['dimension'])) | |
2751 c=',' | |
2752 if 'intent' in vars[a]: | |
2753 lst = true_intent_list(vars[a]) | |
2754 if lst: | |
2755 vardef='%s%sintent(%s)'%(vardef, c, ','.join(lst)) | |
2756 c=',' | |
2757 if 'check' in vars[a]: | |
2758 vardef='%s%scheck(%s)'%(vardef, c, ','.join(vars[a]['check'])) | |
2759 c=',' | |
2760 if 'depend' in vars[a]: | |
2761 vardef='%s%sdepend(%s)'%(vardef, c, ','.join(vars[a]['depend'])) | |
2762 c=',' | |
2763 if '=' in vars[a]: | |
2764 v = vars[a]['='] | |
2765 if vars[a]['typespec'] in ['complex', 'double complex']: | |
2766 try: | |
2767 v = eval(v) | |
2768 v = '(%s,%s)' % (v.real, v.imag) | |
2769 except: | |
2770 pass | |
2771 vardef='%s :: %s=%s'%(vardef, a, v) | |
2772 else: | |
2773 vardef='%s :: %s'%(vardef, a) | |
2774 ret='%s%s%s'%(ret, tab, vardef) | |
2775 return ret | |
2776 ###### | |
2777 | |
2778 def crackfortran(files): | |
2779 global usermodules | |
2780 outmess('Reading fortran codes...\n', 0) | |
2781 readfortrancode(files, crackline) | |
2782 outmess('Post-processing...\n', 0) | |
2783 usermodules=[] | |
2784 postlist=postcrack(grouplist[0]) | |
2785 outmess('Post-processing (stage 2)...\n', 0) | |
2786 postlist=postcrack2(postlist) | |
2787 return usermodules+postlist | |
2788 | |
2789 def crack2fortran(block): | |
2790 global f2py_version | |
2791 pyf=crack2fortrangen(block)+'\n' | |
2792 header="""! -*- f90 -*- | |
2793 ! Note: the context of this file is case sensitive. | |
2794 """ | |
2795 footer=""" | |
2796 ! This file was auto-generated with f2py (version:%s). | |
2797 ! See http://cens.ioc.ee/projects/f2py2e/ | |
2798 """%(f2py_version) | |
2799 return header+pyf+footer | |
2800 | |
2801 if __name__ == "__main__": | |
2802 files=[] | |
2803 funcs=[] | |
2804 f=1;f2=0;f3=0 | |
2805 showblocklist=0 | |
2806 for l in sys.argv[1:]: | |
2807 if l=='': pass | |
2808 elif l[0]==':': | |
2809 f=0 | |
2810 elif l=='-quiet': | |
2811 quiet=1 | |
2812 verbose=0 | |
2813 elif l=='-verbose': | |
2814 verbose=2 | |
2815 quiet=0 | |
2816 elif l=='-fix': | |
2817 if strictf77: | |
2818 outmess('Use option -f90 before -fix if Fortran 90 code is in fix form.\n', 0) | |
2819 skipemptyends=1 | |
2820 sourcecodeform='fix' | |
2821 elif l=='-skipemptyends': | |
2822 skipemptyends=1 | |
2823 elif l=='--ignore-contains': | |
2824 ignorecontains=1 | |
2825 elif l=='-f77': | |
2826 strictf77=1 | |
2827 sourcecodeform='fix' | |
2828 elif l=='-f90': | |
2829 strictf77=0 | |
2830 sourcecodeform='free' | |
2831 skipemptyends=1 | |
2832 elif l=='-h': | |
2833 f2=1 | |
2834 elif l=='-show': | |
2835 showblocklist=1 | |
2836 elif l=='-m': | |
2837 f3=1 | |
2838 elif l[0]=='-': | |
2839 errmess('Unknown option %s\n'%repr(l)) | |
2840 elif f2: | |
2841 f2=0 | |
2842 pyffilename=l | |
2843 elif f3: | |
2844 f3=0 | |
2845 f77modulename=l | |
2846 elif f: | |
2847 try: | |
2848 open(l).close() | |
2849 files.append(l) | |
2850 except IOError as detail: | |
2851 errmess('IOError: %s\n'%str(detail)) | |
2852 else: | |
2853 funcs.append(l) | |
2854 if not strictf77 and f77modulename and not skipemptyends: | |
2855 outmess("""\ | |
2856 Warning: You have specifyied module name for non Fortran 77 code | |
2857 that should not need one (expect if you are scanning F90 code | |
2858 for non module blocks but then you should use flag -skipemptyends | |
2859 and also be sure that the files do not contain programs without program statement). | |
2860 """, 0) | |
2861 | |
2862 postlist=crackfortran(files, funcs) | |
2863 if pyffilename: | |
2864 outmess('Writing fortran code to file %s\n'%repr(pyffilename), 0) | |
2865 pyf=crack2fortran(postlist) | |
2866 f=open(pyffilename, 'w') | |
2867 f.write(pyf) | |
2868 f.close() | |
2869 if showblocklist: | |
2870 show(postlist) |