crackfortran.py 129 KB

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