PageRenderTime 91ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/pytel/parsers/parserFortran.py

http://github.com/ogoe/OpenTelemac-svn-mirror
Python | 1099 lines | 1038 code | 11 blank | 50 comment | 5 complexity | 2bea19292cc0973fe661361d8b3e89ed MD5 | raw file
Possible License(s): GPL-2.0
  1. """@author Sebastien E. Bourban and Noemie Durand
  2. """
  3. """@note ... this work is based on a collaborative effort between
  4. .________. ,--.
  5. | | . ( (
  6. |,-. / HR Wallingford EDF - LNHE / \_ \_/ .--.
  7. / \ / Howbery Park, 6, quai Watier \ ) /_ )
  8. ,. `' Wallingford, Oxfordshire 78401 Cedex `-'_ __ `--
  9. / \ / OX10 8BA, United Kingdom Chatou, France __/ \ \ `.
  10. / `-'| www.hrwallingford.com innovation.edf.com | ) ) )
  11. !________! `--' `--
  12. """
  13. """@history 28/04/2011 -- Sebastien E. Bourban
  14. Now supports SYSTELCFG as a directory (old Perl version, to which
  15. systel.cfg is added) or as a file.
  16. """
  17. """@history 30/04/2011 -- Sebastien E. Bourban
  18. Upgrade made to config parsing to include the option to reset the
  19. version and the root from the command line option:
  20. -v <version>, reset the version read in the config file with this
  21. -r <root>, reset the root path read in the config file with this
  22. """
  23. """@brief
  24. """
  25. # _____ ___________________________________________________
  26. # ____/ Imports /__________________________________________________/
  27. #
  28. # ~~> dependencies towards standard python
  29. import re
  30. import sys
  31. from os import path,walk
  32. # ~~> dependencies towards the root of pytel
  33. from config import OptionParser,parseConfigFile, parseConfig_CompileTELEMAC
  34. # ~~> dependencies towards other pytel/modules
  35. from utils.files import getTheseFiles,isNewer,addToList
  36. from utils.progressbar import ProgressBar
  37. debug = False
  38. # _____ ______________________________________________
  39. # ____/ Instructions /_____________________________________________/
  40. #
  41. listINSTRUCTION = ['ALLOCATE','ASSIGN', \
  42. 'BACKSPACE','BLOCK DATA', \
  43. 'CALL','CASE','CLOSE','COMMON','CYCLE','CONTINUE', \
  44. 'DATA','DEALLOCATE','DEFAULT','DO', \
  45. 'ELSE','ELSEIF','ENDIF','ENDDO','END','ENDFILE','EQUIVALENCE','EXIT', \
  46. 'FORMAT', \
  47. 'GO','TO','GOTO', \
  48. 'IF','IMPLICIT NONE','INCLUDE','INQUIRE','INTERFACE', \
  49. 'MULTIPLE', \
  50. 'NAMELIST','NULLIFY', \
  51. 'OPEN', \
  52. 'PRINT', \
  53. 'READ','REWIND','RETURN', \
  54. 'SELECT','STOP','SAVE', \
  55. 'THEN', 'USE', \
  56. 'WHILE','WHERE','WRITE' ]
  57. listINTRINSIC = [ \
  58. 'ABS', 'ACCESS','ACHAR','ACOS','ACOSH','ADJUSTL','ADJUSTR','AIMAG','AINT','ALARM','ALL', \
  59. 'ALLOCATED','AND','ANINT','ANY','ASIN','ASINH','ASSOCIATED','ATAN','ATAN2','ATANH', \
  60. 'BESJ0','BESJ1','BESJN','BESY0','BESY1','BESYN','BIT_SIZE','BTEST', \
  61. 'CEILING','CHAR','CHDIR','CHMOD','CMPLX','COMMAND_ARGUMENT_COUNT','CONJG','COS','COSH','COUNT','CPU_TIME','CSHIFT','CTIME', \
  62. 'DATE_AND_TIME','DBLE','DCMPLX','DFLOAT','DIGITS','DIM','DOT_PRODUCT','DPROD','DREAL','DTIME', \
  63. 'DMAX1','DMIN1','DMOD','DSQRT','DSIN','DCOS','DTAN','DABS','DATAN','DATAN2','DEXP','DLOG','DSINH','DCOSH','DTANH', \
  64. 'EOSHIFT','EPSILON','ERF','ERFC','ETIME','EXIT','EXP','EXPONENT', \
  65. 'FDATE','FGET','FGETC','FLOAT','FLOOR','FLUSH','FNUM','FPUT','FPUTC','FRACTION','FREE','FSEEK','FSTAT','FTELL', \
  66. 'GERROR','GETARG','GET_COMMAND','GET_COMMAND_ARGUMENT','GETCWD','GETENV','GET_ENVIRONMENT_VARIABLE','GETGID','GETLOG','GETPID','GETUID','GMTIME', \
  67. 'HOSTNM','HUGE', \
  68. 'IACHAR','IAND','IARGC','IBCLR','IBITS','IBSET','ICHAR','IDATE','IEOR','IERRNO', \
  69. 'INDEX','IDINT','INT','INT2','INT8','IOR','IRAND','ISATTY','ISHFT','ISHFTC','ITIME', \
  70. 'KILL','KIND', \
  71. 'LBOUND','LEN','LEN_TRIM','LGE','LGT','LINK','LLE','LLT','LNBLNK','LOC','LOG','LOG10','LOGICAL','LONG','LSHIFT','LSTAT','LTIME', \
  72. 'MALLOC','MATMUL','MAX','MAX0','MAXEXPONENT','MAXLOC','MAXVAL','MCLOCK','MCLOCK8','MERGE','MIN','MIN0','MINEXPONENT','MINLOC','MINVAL','MOD','MODULO','MOVE_ALLOC','MVBITS', \
  73. 'NEAREST','NEW_LINE','NINT','NOT','NULL', \
  74. 'OR', \
  75. 'PACK','PERROR','PRECISION','PRESENT','PRODUCT', \
  76. 'RADIX','RANDOM_NUMBER','RANDOM_SEED','RAND','RANGE','RAN','REAL','RENAME','REPEAT','RESHAPE','RRSPACING','RSHIFT', \
  77. 'SCALE','SCAN','SECNDS','SECOND','SELECTED_INT_KIND','SELECTED_REAL_KIND','SET_EXPONENT','SHAPE','SIGN','SIGNAL','SIN','SINH','SIZE', \
  78. 'SLEEP','SNGL','SPACING','SPREAD','SQRT','SRAND','STAT','SUM','SYMLNK','SYSTEM','SYSTEM_CLOCK', \
  79. 'TAN','TANH','TIME','TIME8','TINY','TRANSFER','TRANSPOSE','TRIM','TTYNAM', \
  80. 'UBOUND','UMASK','UNLINK','UNPACK','VERIFY','XOR' ]
  81. # _____ ________________________________
  82. # ____/ Global Regular Expressions /_______________________________/
  83. #
  84. """
  85. """
  86. #?beforethisafter=r'\s*(?P<before>%s(?=\s*(\b(%s)\b)))'+ \
  87. #? r'\s*(?P<this>(\b(%s)\b))'+ \
  88. #? r'\s*(?P<after>%s)\s*\Z'
  89. beforethisafter=r'(?P<before>%s(?=\s?(\b(%s)\b)))'+ \
  90. r'\s?(?P<this>(\b(%s)\b))'+ \
  91. r'\s?(?P<after>%s)\Z'
  92. #?emptyline = re.compile(r'\s*\Z') #,re.I)
  93. emptyline = re.compile(r'\Z') #,re.I)
  94. f77comment = re.compile(r'[C!#*]') #,re.I)
  95. f77continu2 = re.compile(r'(\s{5}\S\s*)(?P<line>.*)') #,re.I)
  96. #?f90comment = re.compile(r'(?P<line>([^"]*"[^"]*"[^"!]*|[^\']*\'[^\']*\'[^\'!]*|[^!]*))!{1}(?P<rest>.*)') #,re.I)
  97. f90comment = re.compile(r'(?P<line>([^"]*"[^"]*"[^"!]*|[^\']*\'[^\']*\'[^\'!]*|[^!]*))!{1}(?P<rest>[^\Z]*)') #,re.I)
  98. #?f90continu1 = re.compile(r'(?P<line>.*)&\s*\Z') #,re.I)
  99. f90continu1 = re.compile(r'(?P<line>.*)&\Z') #,re.I)
  100. #?f90continu2 = re.compile(r'(\s*&\s*)(?P<line>.*)&\s*\Z') #,re.I)
  101. f90continu2 = re.compile(r'(&\s?)(?P<line>.*)&\Z') #,re.I)
  102. #?f90continu3 = re.compile(r'(\s*&\s*)(?P<line>.*)') #,re.I)
  103. f90continu3 = re.compile(r'(&\s?)(?P<line>.*)') #,re.I)
  104. var_dquots = re.compile(r'(?P<dquot>".*?")') #,re.I)
  105. var_squots = re.compile(r"(?P<squot>'.*?')") #,re.I)
  106. var_bracks = re.compile(r'(?P<brack>\([\w,*\s+-/:]*?\))') #,re.I)
  107. # no (\+|\-)? to capture the sign if there ... different from the utils version
  108. #?var_doublep = re.compile(r'\s*(?P<before>.*?)(?P<number>\b(|[^a-zA-Z(,])(?:(\d+(|\.)\d*[dDeE](\+|\-)?\d+|\d+\.\d+)(\b|[^a-zA-Z,)])))(?P<after>.*?)\s*\Z') #,re.I)
  109. var_doublep = re.compile(r'(?P<before>.*?)(?P<number>\b(|[^a-zA-Z(,])(?:(\d+(|\.)\d*[dDeE](\+|\-)?\d+|\d+\.\d+)(\b|[^a-zA-Z,)])))(?P<after>[^\Z]*)\Z') #,re.I)
  110. #?var_integer = re.compile(r'\s*(?P<before>.*?)(?P<number>\b(|[^a-zA-Z(,])(?:(\d+)(\b|[^a-zA-Z,)])))(?P<after>.*?)\s*\Z') #,re.I)
  111. var_integer = re.compile(r'(?P<before>.*?)(?P<number>\b(|[^a-zA-Z(,])(?:(\d+)(\b|[^a-zA-Z,)])))(?P<after>[^\Z]*)\Z') #,re.I)
  112. f90logic = '(FALSE|TRUE|EQ|NE|GT|LT|GE|LE|OR|AND|XOR)'
  113. #?var_logical = re.compile(r'.*?(?P<logic>\.\s*?%s\s*?\.).*?'%(f90logic)) #,re.I)
  114. var_logical = re.compile(r'[^\.](?P<logic>\.\s?%s\s?\.)'%(f90logic)) #,re.I)
  115. #?var_pointer = re.compile(r'\s*(?P<before>.*?)(?P<this>%\w+)(?P<after>.*?)\s*\Z') #,re.I)
  116. var_pointer = re.compile(r'(?P<before>.*?)(?P<this>%\w+)(?P<after>[^\Z]*)\Z') #,re.I)
  117. #?var_word = re.compile(r'\s*(?P<before>.*?)(?P<word>\b\w+?\b)(?P<after>.*?)\s*\Z') #,re.I)
  118. var_word = re.compile(r'(?P<before>.*?)(?P<word>\b\w+?\b)(?P<after>[^\Z]*)\Z') #,re.I)
  119. #?var_assocs = re.compile(r'\s*(?P<before>.*?)(?P<name>\s*\b\w+?\b\s*=\s*)(?P<after>.*?)\s*\Z') #,re.I)
  120. var_assocs = re.compile(r'(?P<before>.*?)(?P<name>\s?\b\w+?\b\s?=\s?)(?P<after>[^\Z]*)\Z') #,re.I)
  121. #?var_equals = re.compile(r'\s*(?P<before>.*?)(?P<name>\s*\b\w+?\b)(?P<value>\s*=[^,]*)(?P<after>.*?)\s*\Z') #,re.I)
  122. var_equals = re.compile(r'(?P<before>.*?)(?P<name>\s?\b\w+?\b)(?P<value>\s?=[^,]*)(?P<after>[^\Z]*)\Z') #,re.I)
  123. #?var_operand = re.compile(r'\s*(?P<before>.*?)(?=[^\s])\W+(?P<after>.*?)\s*\Z') #,re.I)
  124. var_operand = re.compile(r'(?P<before>.*?)(?=[^\s])\W+(?P<after>[^\Z]*)\Z') #,re.I)
  125. #?argnames = re.compile(r'\s*(?P<name>\b\w+\b)\s*?(|\((?P<args>.*)\))\s*\Z') #,re.I)
  126. argnames = re.compile(r'(?P<name>\b\w+\b)\s?(|\((?P<args>.*)\))\Z') #,re.I)
  127. #?itf_title = re.compile(r'\s*?\bINTERFACE\b(|\s+?(?P<name>\w+).*?)\s*\Z') #,re.I)
  128. itf_title = re.compile(r'\bINTERFACE\b(|\s(?P<name>\w+)[^\Z]*)\Z') #,re.I)
  129. #?itf_uless = re.compile(r'\s*?\bMODULE\s+?PROCEDURE\s+?(?P<name>\w+).*?\s*\Z') #,re.I)
  130. itf_uless = re.compile(r'\bMODULE\sPROCEDURE\s(?P<name>\w+)[^\Z]*\Z') #,re.I)
  131. #?itf_close = re.compile(r'\s*?\bEND\s+INTERFACE\b(|\s+?(?P<name>\w+).*?)\s*\Z') #,re.I)
  132. itf_close = re.compile(r'\bEND\sINTERFACE\b(|\s(?P<name>\w+)[^\Z]*)\Z') #,re.I)
  133. #?use_title = re.compile(r'\s*?\bUSE\b\s+?(?P<name>\b\w+\b)\s*(|,\s*(?P<after>.*?))\s*\Z') #,re.I)
  134. use_title = re.compile(r'\bUSE\b\s(?P<name>\b\w+\b)\s?(|,\s?(?P<after>[^\Z]*))\Z') #,re.I)
  135. #?xtn_title = re.compile(r'.*?\bEXTERNAL\b(.*?::)?\s*?(?P<vars>.*?)\s*\Z') #,re.I)
  136. xtn_title = re.compile(r'.*?\bEXTERNAL\b(.*?::)?\s?(?P<vars>[^\Z]*)\Z') #,re.I)
  137. #?itz_title = re.compile(r'\s*?\bINTRINSIC\b(.*?::)?\s*?(?P<vars>.*?)\s*\Z') #,re.I)
  138. itz_title = re.compile(r'\bINTRINSIC\b([^:]?::)?\s?(?P<vars>[^\Z]*)\Z') #,re.I)
  139. #?implictNone = re.compile(r'\s*?\bIMPLICIT\s+NONE\b\s*\Z') #,re.I)
  140. implictNone = re.compile(r'\bIMPLICIT\sNONE\b\Z') #,re.I)
  141. #?inc_title = re.compile(r'\s*?\bINCLUDE\b\s*(?P<file>.*?)\s*\Z') #,re.I)
  142. inc_title = re.compile(r'\bINCLUDE\b\s?(?P<file>[^\Z]*)\Z') #,re.I)
  143. #?cmn_title = re.compile(r'\s*?\bCOMMON\b\s*?/\s*(?P<name>\w*)\s*/\s*?(?P<after>.*?)\s*\Z') #,re.I)
  144. cmn_title = re.compile(r'\bCOMMON\b\s?/\s?(?P<name>\w*)\s?/\s?(?P<after>[^\Z]*)\Z') #,re.I)
  145. #?ctn_title = re.compile(r'\s*?\bCONTAINS\b\s*\Z') #,re.I)
  146. ctn_title = re.compile(r'\bCONTAINS\b\Z') #,re.I)
  147. #?def_title = re.compile(r'\s*?\bTYPE\b\s+?(?P<name>\b\w+\b)\s*\Z') #,re.I)
  148. def_title = re.compile(r'\bTYPE\b\s(?P<name>\b\w+\b)\Z') #,re.I)
  149. #?def_close = re.compile(r'\s*?\bEND TYPE\b\s+?(?P<name>\b\w+\b)\s*\Z') #,re.I)
  150. def_close = re.compile(r'\bEND TYPE\b\s(?P<name>\b\w+\b)\Z') #,re.I)
  151. #?als_core = re.compile(r'(?P<before>.*?)(?P<alias>\b\w([\w%]|\([\w(,:)%]*\))*)\s*=>\s*(?P<link>\b\w+?\b)(?P<after>.*?)\s*\Z') #,re.I)
  152. als_core = re.compile(r'(?P<before>.*?)(?P<alias>\b\w([\w%]|\([\w(,:)%]*\))*)\s?=>\s?(?P<link>\b\w+?\b)(?P<after>[^\Z]*)\Z') #,re.I)
  153. #?var_format = re.compile(r'\s*(?P<before>.*?)\d+?\s+?\bFORMAT\b(?P<after>.*?)\s*\Z') #,re.I)
  154. var_format = re.compile(r'(?P<before>.*?)\d+?\s\bFORMAT\b(?P<after>[^\Z]*)\Z') #,re.I)
  155. #?cls_title = re.compile(r".*?\bCALL\b\s+?(?P<name>\b\w+\b)\s*?(|\((?P<args>[\w\s\*\+\-\/=,%('.:)]*)\))\s*\Z") #,re.I)
  156. cls_title = re.compile(r".*?\bCALL\b\s(?P<name>\b\w+\b)\s?(|\((?P<args>[\w\s\*\+\-\/=,%('.:)]*)\))\Z") #,re.I)
  157. #?fct_title = re.compile(r"\s*(?P<before>.*?)(?P<name>\b\w+\b)\s*?\((?P<args>[\w\s\*\+\-\/=,%('.:)]*)\)(?P<after>.*?)\s*\Z") #,re.I)
  158. fct_title = re.compile(r"(?P<before>.*?)(?P<name>\b\w+\b)\s?\((?P<args>[\w\s\*\+\-\/=,%('.:)]*)\)(?P<after>[^\Z]*)\Z") #,re.I)
  159. #?f90types = '(CHARACTER|LOGICAL|INTEGER|REAL|COMPLEX|DOUBLE\s*(PRECISION\s*(COMPLEX|)|COMPLEX))\s*?(\**\s*?\d+|\**\(.*?\))?|TYPE\s*\([\w\s,=(*)]*?\)'
  160. f90types = '(CHARACTER|LOGICAL|INTEGER|REAL|COMPLEX|DOUBLE\s?(PRECISION\s?(COMPLEX|)|COMPLEX))\s?(\**\s?\d+|\**\(.*?\))?|TYPE\s?\([\w\s,=(*)]*?\)'
  161. #?f90xport = '(PUBLIC|PRIVATE|SAVE|PARAMETER|DATA|SEQUENCE)\s*?'
  162. f90xport = '(PUBLIC|PRIVATE|SAVE|PARAMETER|DATA|SEQUENCE)'
  163. #?f95_name = re.compile(r"\s*(?P<name>\b\w+\b)\s*?:\s*(?P<after>.*?)\s*\Z") #,re.I)
  164. f95_name = re.compile(r"(?P<name>\b\w+\b)\s?:\s?(?P<after>[^\Z]*)\Z") #,re.I)
  165. #?typ_args = re.compile(r'\s*?(.*?::)?\s*?(?P<vars>.*?)\s*\Z',re.I)
  166. typ_args = re.compile(r'(.*?::)?\s?(?P<vars>[^\Z]*)\Z') #,re.I)
  167. #?typ_name = re.compile(r'\s*?(?P<type>(%s))\s*?\Z'%(f90types)) #,re.I)
  168. typ_name = re.compile(r'(?P<type>(%s))\Z'%(f90types)) #,re.I)
  169. #?typ_title = re.compile(r'\s*?(?P<type>(%s))\s*?(?P<after>.*?)\s*\Z'%(f90types)) #,re.I)
  170. typ_name = re.compile(r'(?P<type>(%s))\Z'%(f90types)) #,re.I)
  171. #?typ_title = re.compile(r'\s*?(?P<type>(%s))\s*?(?P<after>.*?)\s*\Z'%(f90types)) #,re.I)
  172. typ_title = re.compile(r'(?P<type>(%s))\s?(?P<after>[^\Z]*)\Z'%(f90types)) #,re.I)
  173. #?typ_xport = re.compile(r'\s*?(?P<type>(%s))\s*?(?P<after>.*?)\s*\Z'%(f90xport)) #,re.I)
  174. typ_xport = re.compile(r'(?P<type>(%s))\s?(?P<after>[^\Z]*)\Z'%(f90xport)) #,re.I)
  175. #?pcl_title = re.compile(r'\s*?((?P<type>[\w\s(=*+-/)]*?)|)\b(?P<object>(PROGRAM|FUNCTION|SUBROUTINE|MODULE))\b\s*(?P<after>.*?)\s*?(\bRESULT\b\s*?(?P<result>\w+[\w\s]*)|)\s*\Z') #,re.I)
  176. pcl_title = re.compile(r'((?P<type>[\w\s(=*+-/)]*?)|)\b(?P<object>(PROGRAM|FUNCTION|SUBROUTINE|MODULE))\b\s?(?P<after>.*?)\s?(\bRESULT\b\s?(?P<result>\w+[\w\s]*)|)\Z') #,re.I)
  177. #?pcl_close = re.compile(r'\s*?\bEND\b(|\s+?(?P<object>(PROGRAM|FUNCTION|SUBROUTINE|MODULE))(|\s+?(?P<name>\w+?)))\s*\Z') #,re.I)
  178. pcl_close = re.compile(r'\bEND\b(|\s(?P<object>(PROGRAM|FUNCTION|SUBROUTINE|MODULE))(|\s(?P<name>\w+?)))\Z') #,re.I)
  179. # _____ ____________________________________
  180. # ____/ FORTRAN Parser Toolbox /___________________________________/
  181. #
  182. def cleanSpaces(istr):
  183. return istr.strip().replace(' ',' ').replace(' ',' ')
  184. def cleanAssoc(istr):
  185. while 1:
  186. ostr = istr
  187. proc = re.match(var_assocs,ostr)
  188. if proc:
  189. istr = proc.group('before')+proc.group('after')
  190. if ostr == istr: break
  191. return cleanSpaces(ostr)
  192. def cleanBracks(istr):
  193. while 1:
  194. ostr = istr
  195. for brack in re.findall(var_bracks,ostr):
  196. istr = istr.replace(brack,'')
  197. if ostr == istr: return cleanSpaces(ostr)
  198. def cleanEquals(istr):
  199. while 1:
  200. ostr = istr
  201. proc = re.match(var_equals,ostr)
  202. if proc:
  203. istr = proc.group('before')+proc.group('name')+proc.group('after')
  204. if ostr == istr: break
  205. return cleanSpaces(ostr)
  206. def cleanFormatted(istr):
  207. proc = re.match(var_format,istr)
  208. if proc: istr = ''
  209. return istr.strip()
  210. def cleanInstruction(istr,list):
  211. ostr = ''
  212. while 1:
  213. proc = re.match(var_word,istr)
  214. if proc:
  215. ostr = ostr + ' ' + proc.group('before')
  216. istr = proc.group('after')
  217. instr = proc.group('word')
  218. if instr not in list: ostr = ostr + ' ' + instr
  219. else: break
  220. return cleanSpaces(ostr)
  221. def cleanLogicals(istr):
  222. while 1:
  223. ostr = istr
  224. proc = re.match(var_logical,ostr)
  225. if proc:
  226. istr = istr.replace(proc.group('logic'),' ')
  227. if ostr == istr: break
  228. return cleanSpaces(ostr)
  229. def cleanNumbers(istr):
  230. while 1:
  231. ostr = istr
  232. proc = re.match(var_doublep,ostr)
  233. if proc:
  234. istr = proc.group('before')+proc.group('after')
  235. if ostr == istr: break
  236. while 1:
  237. ostr = istr
  238. proc = re.match(var_integer,ostr)
  239. if proc:
  240. istr = proc.group('before')+proc.group('after')
  241. if ostr == istr: break
  242. return cleanSpaces(ostr)
  243. def cleanOperators(istr):
  244. while 1:
  245. ostr = istr
  246. proc = re.match(var_operand,ostr)
  247. if proc:
  248. istr = proc.group('before')+' '+proc.group('after')
  249. if ostr == istr: break
  250. return cleanSpaces(ostr)
  251. def cleanPointers(istr):
  252. while 1:
  253. ostr = istr
  254. proc = re.match(var_pointer,ostr)
  255. if proc:
  256. istr = proc.group('before')+proc.group('after')
  257. if ostr == istr: break
  258. return cleanSpaces(ostr)
  259. def cleanQuotes(istr):
  260. istr = istr.replace("'''","'").replace('"""',"'")
  261. # ~~> Deal with single quotes
  262. while 1:
  263. ostr = istr
  264. for quote in re.findall(var_squots,ostr):
  265. istr = istr.replace(quote,"''")
  266. if ostr == istr: break
  267. # ~~> Deal with double quotes (replace by sigle quotes)
  268. while 1:
  269. ostr = istr
  270. for quote in re.findall(var_dquots,ostr):
  271. istr = istr.replace(quote,"''")
  272. if ostr == istr: break
  273. # ~~> Remove the internal apostrophies
  274. ostr = ostr.replace("''''","''").replace("''''","''")
  275. return ostr
  276. def parseAlias(lines):
  277. listAlias = []; count = 0
  278. core = []; core.extend(lines)
  279. for line in lines :
  280. line = cleanQuotes(line)
  281. proc = re.match(als_core,line)
  282. if proc:
  283. alias = proc.group('alias').strip()
  284. if not re.match(var_pointer,alias):
  285. if alias not in listAlias: listAlias.append(alias)
  286. core[count] = proc.group('before') + ' ' + proc.group('link') + proc.group('after')
  287. count = count + 1
  288. return core,listAlias
  289. def parseArgs(ilist):
  290. return cleanPointers(cleanNumbers(cleanLogicals(cleanEquals(cleanBracks(cleanQuotes(ilist)))))).replace(' ','').split(',')
  291. def parseImplicitNone(lines):
  292. core = []; core.extend(lines)
  293. if lines == []: return lines,False
  294. line = lines[0]
  295. proc = re.match(implictNone,line)
  296. if proc :
  297. core.pop(0)
  298. return core,True
  299. return core,False
  300. def parseDeclarations(lines):
  301. listCommon = []; listDeclar = []; listIntrinsic = []; listExternal = []
  302. core = []; core.extend(lines)
  303. ignoreblock = False
  304. for line in lines :
  305. headline = False
  306. # ~~ TYPE Definition ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  307. if not ignoreblock:
  308. proc = re.match(def_title,line)
  309. if proc :
  310. ignoreblock = True
  311. core.pop(0); headline = True; continue
  312. else:
  313. proc = re.match(def_close,line)
  314. if proc : ignoreblock = False
  315. core.pop(0); headline = True; continue
  316. # ~~ Common Declaration ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  317. proc = re.match(cmn_title,line)
  318. if proc :
  319. listCommon.append([proc.group('name'),parseArgs(proc.group('after'))])
  320. core.pop(0); headline = True; continue
  321. # ~~ Private/Public Declarations ~~~~~~~~~~~~~~~~~~~~~~~~~~
  322. proc = re.match(typ_xport,line)
  323. if proc :
  324. #listCommon.append([proc.group('name'),parseArgs(proc.group('after'))])
  325. core.pop(0); headline = True; continue
  326. # ~~ INCLUDE Declarations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  327. proc = re.match(inc_title,line) # you should parse the content from MainWrap
  328. if proc : core.pop(0); headline = True; continue
  329. # ~~ Type Declaration ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  330. proc = re.match(typ_title,line)
  331. if proc :
  332. if not re.match(xtn_title,proc.group('after')):
  333. proc = re.match(typ_args,proc.group('after'))
  334. if proc :
  335. if proc.group('vars') != None: listDeclar.extend(parseArgs(proc.group('vars')))
  336. core.pop(0); headline = True; continue
  337. # ~~ Intrinsic Declaration ~~~~~~~~~~~~~~~~~~~~~~~~~~
  338. proc = re.match(itz_title,line)
  339. if proc :
  340. if proc.group('vars') != None: listIntrinsic.extend(parseArgs(proc.group('vars')))
  341. core.pop(0); headline = True; continue
  342. # ~~ External Declaration ~~~~~~~~~~~~~~~~~~~~~~~~
  343. proc = re.match(xtn_title,line)
  344. if proc :
  345. if proc.group('vars') != None: listExternal.extend(parseArgs(proc.group('vars')))
  346. core.pop(0); headline = True; continue
  347. # ~~ Reached main core ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  348. if not headline: break
  349. return core,{ 'cmn':listCommon, 'dec':listDeclar, 'itz':listIntrinsic, 'xtn':listExternal, 'als':[] }
  350. def parseUses(lines):
  351. listUses = {}; listAlias = {}; core = []; core.extend(lines)
  352. for line in lines :
  353. proc = re.match(use_title,line)
  354. if proc :
  355. name = proc.group('name') # You should not find None here
  356. args = ''
  357. if proc.group('after') != None: args = proc.group('after') # Do you need to distinguish the ONLYs ?
  358. core.pop(0)
  359. addToList(listUses,name,args)
  360. else: break
  361. return core,listUses
  362. def parseVars(ilist):
  363. return cleanPointers(cleanNumbers(cleanLogicals(cleanAssoc(cleanBracks(cleanQuotes(ilist)))))).replace(' ','').split(',')
  364. def parseCalls(lines):
  365. listCalls = {} #; count = 0
  366. core = []; core.extend(lines)
  367. for line in lines :
  368. proc = re.match(cls_title,cleanPointers(cleanQuotes(line))) # you might not want to clean Logical at this stage /!\
  369. if proc :
  370. name = proc.group('name'); args = []
  371. if proc.group('args') != None: args = parseVars(proc.group('args'))
  372. addToList(listCalls,name,args)
  373. return core,listCalls
  374. def parseFunctions(lines):
  375. listFcts = set([]); listTags = []
  376. for line in lines :
  377. line = cleanQuotes(line)
  378. line = cleanPointers(line)
  379. proc = re.match(cls_title,cleanLogicals(line))
  380. if proc :
  381. line = ''
  382. if proc.group('args') != None: line = ' '.join(parseVars(proc.group('args')))
  383. line = cleanFormatted(line)
  384. proc = re.match(fct_title,line)
  385. if proc : line = proc.group('before')+proc.group('name')+'('+cleanAssoc(proc.group('args'))+')'+proc.group('after')
  386. line = cleanLogicals(line)
  387. line = cleanNumbers(line)
  388. proc = re.match(f95_name,line)
  389. if proc:
  390. line = proc.group('after')
  391. listTags.append(proc.group('name'))
  392. line = cleanInstruction(line,listTags)
  393. line = cleanOperators(line)
  394. line = cleanInstruction(line,listINSTRUCTION)
  395. line = cleanInstruction(line,listINTRINSIC)
  396. if line != '':
  397. listFcts = listFcts | set(line.split())
  398. return listFcts
  399. def parsePrincipalWrap(lines):
  400. # you could be parsing the INTERFACE / END INTERFACE as well
  401. # and in the case of a module ... declarations / definitions
  402. core = []; core.extend(lines)
  403. face = []
  404. proc = re.match(pcl_title,lines[0])
  405. if proc :
  406. name = proc.group('after')
  407. resu = proc.group('result')
  408. objt = proc.group('object')
  409. type = proc.group('type').strip()
  410. if ( type != '' ):
  411. if not re.match(typ_name,type):
  412. print 'Invalid header type ' + type + ' ' + objt + ' ' + name
  413. sys.exit() #return [],[],[],lines
  414. proc = re.match(argnames,name)
  415. if proc :
  416. name = proc.group('name')
  417. args = []
  418. if proc.group('args') != None: args = parseArgs(proc.group('args'))
  419. #~~> header completed
  420. count = 0; block = 0
  421. ctain = 0; ltain = False; lface = False
  422. for line in lines[1:]: # /!\ does not work with empty lines
  423. count = count + 1
  424. #~~> interface
  425. if lface:
  426. proc = re.match(itf_close,line)
  427. if proc:
  428. lface = False
  429. else:
  430. proc = re.match(itf_uless,line)
  431. if not proc: face.append(line)
  432. core.pop(count)
  433. count = count - 1
  434. continue # THIS IS TO IGNORE THE LOCAL VARIABLES
  435. else:
  436. proc = re.match(itf_title,line)
  437. if proc :
  438. lface = True
  439. core.pop(count)
  440. count = count - 1
  441. #~~> contains
  442. if ltain: ctain = ctain - 1
  443. if not ltain:
  444. if re.match(ctn_title,line) : ltain = True
  445. proc = re.match(pcl_close,line)
  446. if proc :
  447. block = block - 1
  448. else:
  449. proc = re.match(pcl_title,line)
  450. if proc :
  451. t = proc.group('type').strip()
  452. if ( t != '' ):
  453. if not re.match(typ_name,t): continue
  454. block = block + 1
  455. if block < 0 :
  456. if proc.group('name') != name:
  457. if debug: print 'Different name at END ' + objt + ' ' + name
  458. if proc.group('object') != objt:
  459. if debug: print 'Different type at END ' + objt
  460. return core[1:count+ctain],[ objt[0:1], name, args, resu ],face,core[count+ctain+1:count],core[count+1:]
  461. # ~~> Acount for empty MODULE (including only INTERFACE and CONTAINS)
  462. if ltain and block == 0 and count+1 >= len(core)-1:
  463. if proc.group('name') != name:
  464. if debug: print 'Different name at END ' + objt + ' ' + name
  465. if proc.group('object') != objt:
  466. if debug: print 'Different type at END ' + objt
  467. return core[1:count+ctain],[ objt[0:1], name, args, resu ],face,core[count+ctain+1:count],core[count+2:]
  468. else:
  469. print 'Invalid header type for first line' + lines[0]
  470. sys.exit()
  471. print 'Invalid header type for first line' + lines[0]
  472. sys.exit()
  473. return # /!\ this return is just for python parsing
  474. def parsePrincipalMain(lines,who,type,name,args,resu):
  475. core = []; core.extend(lines)
  476. whi = dict.copy(who); whi['uses'] = {}; whi['vars'] = {}; whi['calls'] = {}; whi['called'] = [] #; whi['alias'] = {}
  477. whi['type'] = type; whi['name'] = name; whi['args'] = args; whi['resu'] = resu
  478. # ~~ Lists aliases in File ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  479. core,alias = parseAlias(core)
  480. # ~~ Lists uses in File ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  481. core,uses = parseUses(core)
  482. for k in uses.keys():
  483. whi['uses'].update({k:[]})
  484. for v in uses[k]: addToList(whi['uses'],k,v)
  485. # ~~ Imposes IMPLICIT NONE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  486. core,l = parseImplicitNone(core)
  487. if not l and whi['type'] != 'M' and debug:
  488. print 'No IMPLICIT NONE in ',whi['name'],whi['file']
  489. # ~~ Lists declarations in File ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  490. core,decs = parseDeclarations(core)
  491. for dec in decs['xtn']:
  492. if dec in decs['dec']: decs['dec'].remove(dec)
  493. for dec in decs['cmn']:
  494. for k in dec[1]:
  495. if k in decs['dec']: decs['dec'].remove(k)
  496. for dec in args:
  497. if dec in decs['dec']: decs['dec'].remove(dec)
  498. for k in decs.keys():
  499. whi['vars'][k] = []
  500. for v in decs[k]: addToList(whi['vars'],k,v)
  501. whi['vars']['als'] = alias
  502. # ~~ Lists calls in File ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  503. core,calls = parseCalls(core)
  504. for k in calls.keys():
  505. whi['calls'][k] = []
  506. for v in calls[k]: addToList(whi['calls'],k,v) # still includes xtn calls
  507. # ~~ Lists functions in File ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  508. fcts = []
  509. for fct in parseFunctions(core):
  510. if fct not in args:
  511. if fct not in whi['vars']['dec']:
  512. if fct not in whi['vars']['als']:
  513. found = False
  514. for cmn in whi['vars']['cmn']:
  515. if fct in cmn[1]: found = True
  516. if not found and fct != name: fcts.append(fct)
  517. whi['functions'] = fcts # still includes the ones from the USEs (and xtn)
  518. return name,whi,core
  519. """
  520. In order for multiple line of code to be interpreted, remove the
  521. continuation symbols so every line is self contained --
  522. This takes into account the possibility for f77 and f90
  523. continuation -- assumes that in between comments have been
  524. removed already
  525. Return the set of lines without continuation
  526. """
  527. def delContinuedsF77(lines):
  528. # ~~ Assumes code without comments ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  529. cmds = []
  530. cmd = ''
  531. for line in lines :
  532. proc1 = re.match(f77continu2,line)
  533. if proc1:
  534. #?cmd = cmd.rstrip() + proc1.group('line')
  535. cmd = ( cmd.rstrip() + proc1.group('line') ).strip().replace(' ',' ').replace(' ',' ') # /!\ Looking to save on upper space
  536. else:
  537. if cmd is not '' : cmds.append(cmd)
  538. #?cmd = line
  539. cmd = line.strip().replace(' ',' ').replace(' ',' ') # /!\ Looking to save on upper space
  540. cmds.append(cmd)
  541. return cmds
  542. def delContinuedsF90(lines):
  543. # ~~ Assumes code without comments ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  544. cmds = []
  545. cmd = ''
  546. cnt = False
  547. for line in lines :
  548. proc2 = re.match(f90continu1,line)
  549. proc3 = re.match(f90continu2,line)
  550. proc4 = re.match(f90continu3,line)
  551. if proc3 :
  552. #?cmd = cmd.rstrip() + proc3.group('line')
  553. cmd = cleanSpaces( cmd + proc3.group('line') ) # /!\ Looking to save on upper space
  554. cnt = True
  555. elif proc2 :
  556. if not cnt:
  557. if cmd is not '' : cmds.append(cmd)
  558. cmd = ''
  559. #?cmd = cmd.rstrip() + proc2.group('line')
  560. cmd = cleanSpaces( cmd + proc2.group('line') ) # /!\ Looking to save on upper space
  561. cnt = True
  562. elif proc4 :
  563. #?cmd = cmd.rstrip() + proc4.group('line')
  564. cmd = cleanSpaces( cmd + proc4.group('line') ) # /!\ Looking to save on upper space
  565. cnt = False
  566. else:
  567. if cnt:
  568. #?cmd = cmd.rstrip() + line
  569. cmd = cleanSpaces( cmd + line ) # /!\ Looking to save on upper space
  570. else:
  571. if cmd is not '' : cmds.append(cmd)
  572. #?cmd = line
  573. cmd = cleanSpaces(line) # /!\ Looking to save on upper space
  574. cnt = False
  575. if cmd is not '' : cmds.append(cmd)
  576. return cmds
  577. """
  578. In order for multiple lines of code to be interpreted, remove all
  579. comments form these, whether they include f77 or f09 comments --
  580. Return the command lines (without empty lines)
  581. """
  582. def delComments(lines):
  583. # ~~ Also removes end lines and sets to UPPERCASE ~~~~~~~~~~~~~~~
  584. cmds = []
  585. for line in lines :
  586. line = cleanQuotes(line).rstrip().upper()
  587. proc1 = re.match(f77continu2,line) # no strip here
  588. proc = re.match(f77comment,line) # no strip here
  589. if proc and not proc1 :
  590. cmd = ''
  591. else :
  592. while 1:
  593. cmd = line
  594. proc = re.match(f90comment,cmd)
  595. if proc: line = proc.group('line').rstrip()
  596. if cmd == line: break
  597. if cmd != '' :
  598. proc = re.match(emptyline,cmd)
  599. if not proc:
  600. cmds.append(cmd.replace('\n','').replace('\r',''))
  601. return cmds
  602. def scanSources(cfgdir,cfg,BYPASS):
  603. fic = {}; mdl = {}; sbt = {}; fct = {}; prg = {}; dep = {}; wcw = {}
  604. # ~~ Looking at each file individually ~~~~~~~~~~~~~~~~~~~~~~~~~~
  605. for mod in cfg['MODULES'].keys() :
  606. wcw.update({mod:{'path':cfg['MODULES'][mod]['path']}})
  607. fic.update({mod:{}})
  608. # ~~ Scans the sources that are relevant to the model ~~~~~~~~
  609. SrcDir = path.join(cfg['MODULES'][mod]['path'],'sources') # assumes the sources are under ./sources
  610. FileList = getTheseFiles(SrcDir,['.f','.f90'])
  611. ODir = path.join(cfg['MODULES'][mod]['path'],cfgdir)
  612. print '... now scanning ', path.basename(cfg['MODULES'][mod]['path'])
  613. ibar = 0; pbar = ProgressBar(maxval=len(FileList)).start()
  614. #/!\ if you need to print within this loop, you now need to use
  615. # pbar.write(text,ibar) so the progress bar moves along
  616. for File in FileList :
  617. ibar = ibar + 1; pbar.update(ibar)
  618. if not fic.has_key(mod): update({mod:{}})
  619. fic[mod].update({File:[]})
  620. #pbar.write(File,ibar)
  621. who = { 'path':path.abspath(path.dirname(File)), \
  622. 'file':path.basename(File), \
  623. 'libname':mod, \
  624. 'type':'', \
  625. 'name':'', \
  626. 'args':[], \
  627. 'resu':'', \
  628. 'contains':[], \
  629. 'uses':{}, \
  630. 'vars':{}, \
  631. 'calls':{}, \
  632. 'called':[], \
  633. 'functions':[], \
  634. 'rank':1, \
  635. 'time':0 }
  636. if path.isdir(ODir) :
  637. if cfg['COMPILER']['REBUILD'] == 2:
  638. who['time'] = 0
  639. else:
  640. #who['time'] = isNewer(path.join(ODir,path.splitext(path.basename(File))[0] + cfg['SYSTEM']['sfx_obj'].lower()),File)
  641. who['time'] = isNewer(File,path.join(ODir,path.splitext(path.basename(File))[0] + cfg['SYSTEM']['sfx_obj'].lower()))
  642. SrcF = open(File,'r')
  643. if path.splitext(who['file'])[1].lower() in ['.f90','.f95']:
  644. flines = delContinuedsF90(delComments(SrcF)) # Strips the F90+ commented lines
  645. else:
  646. flines = delContinuedsF77(delComments(SrcF)) # Strips the F77 commented lines
  647. SrcF.close() # and deletes the continuation characters
  648. core = flines
  649. found = False #ndu
  650. while core != [] and not found: # ignores what might be in the file after the main program
  651. # ~~ Parse Main Structure ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  652. code,w,face,ctns,core = parsePrincipalWrap(core)
  653. name,whoi,rest = parsePrincipalMain(code,who,w[0],w[1],w[2],w[3])
  654. if w[0] == 'P': prg = addToList(prg,name,whoi['libname'])# main program
  655. if w[0] == 'P': found = BYPASS
  656. if w[0] == 'S': sbt = addToList(sbt,name,whoi['libname'])# subroutine
  657. if w[0] == 'M': mdl = addToList(mdl,name,whoi['libname'])# module
  658. if w[0] == 'F': fct = addToList(fct,name,whoi['libname'])# function
  659. fic[mod][File].append(name)
  660. while face != []:
  661. fcode,fw,ff,ft,face = parsePrincipalWrap(face)
  662. if fcode != []:
  663. fname,whof,rest = parsePrincipalMain(fcode,who,fw[0],fw[1],fw[2],fw[3])
  664. for k in whof['uses'].keys():
  665. for v in whof['uses'][k]: addToList(whoi['uses'],k,v)
  666. while ctns != []: # contains fcts & subs
  667. ccode,cw,cf,ct,ctns = parsePrincipalWrap(ctns)
  668. if ccode != []:
  669. cname,whoc,rest = parsePrincipalMain(ccode,who,cw[0],cw[1],cw[2],cw[3])
  670. whoi['contains'].append(cname)
  671. if cw[0] == 'S': sbt = addToList(sbt,cname,whoi['libname'])# subroutine
  672. if cw[0] == 'F': fct = addToList(fct,cname,whoi['libname'])# function
  673. for k in whoc['uses'].keys():
  674. for v in whoc['uses'][k]: addToList(whoi['uses'],k,v)
  675. for k in whoc['vars'].keys():
  676. for v in whoc['vars'][k]: addToList(whoi['vars'],k,v)
  677. for k in whoc['calls'].keys():
  678. for v in whoc['calls'][k]: addToList(whoi['calls'],k,v)
  679. for k in whoc['functions']:
  680. if k not in whoi['functions']: whoi['functions'].append(k)
  681. whoi['vars'].update({'use':{}})
  682. wcw[mod].update({name:whoi}) # ~~ All ~~~~~~~~~~
  683. #if core == []: break
  684. pbar.finish()
  685. # ~~ Cross-referencing CALLS together ~~~~~~~~~~~~~~~~~~~~~~~~~~~
  686. # For those CALLs stored in 'calls' but not part of the system:
  687. # move them from 'calls' to 'function' (outsiders remain)
  688. for mod in wcw.keys() :
  689. for name in wcw[mod]:
  690. if name != 'path':
  691. who = wcw[mod][name]
  692. for s in who['calls'].keys():
  693. if s not in sbt.keys():
  694. del wcw[mod][name]['calls'][s]
  695. wcw[mod][name]['functions'].append(s)
  696. # ~~ Cross-referencing FUNCTIONS together ~~~~~~~~~~~~~~~~~~~~~~~
  697. for mod in wcw.keys() :
  698. for name in wcw[mod]:
  699. if name != 'path':
  700. who = wcw[mod][name]
  701. for f in who['vars']['xtn']:
  702. if f not in who['functions']:
  703. if debug: print f,' declared but not used in ',who['name']
  704. who['functions'].append(f)
  705. for f in fct.keys():
  706. while f in who['functions']:
  707. who['functions'].remove(f)
  708. who['calls'].update({f:[['']]})
  709. for mod in wcw.keys() :
  710. for name in wcw[mod]:
  711. if name != 'path':
  712. who = wcw[mod][name]
  713. f,u = sortFunctions(who['functions'],who['vars']['use'],wcw,mdl,who['uses'])
  714. who['functions'] = f
  715. who['vars']['use'].update(u) # because this is a dico-list, updating who updates wcw
  716. # ~~ Sort out referencing ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  717. # Fill-in the 'called' category
  718. for mod in wcw.keys() :
  719. for name in wcw[mod]:
  720. if name != 'path':
  721. for call in wcw[mod][name]['calls'].keys():
  722. if sbt.has_key(call):
  723. for u in sbt[call]:
  724. if wcw[u].has_key(call):
  725. wcw[u][call]['called'].append(name)
  726. if fct.has_key(call):
  727. for u in fct[call]:
  728. if wcw[u].has_key(call):
  729. wcw[u][call]['called'].append(name)
  730. return fic,mdl,sbt,fct,prg,dep,wcw
  731. def sortFunctions(ifcts,iuses,list,mods,xuses):
  732. #found = False
  733. ofcts = []; ofcts.extend(ifcts)
  734. for d in ifcts:
  735. for u in xuses:
  736. if u not in mods.keys():
  737. continue
  738. if d in list[mods[u][0]][u]['vars']['dec']:
  739. ofcts.remove(d)
  740. addToList(iuses,u,d)
  741. break
  742. if d in list[mods[u][0]][u]['vars']['als']:
  743. ofcts.remove(d)
  744. addToList(iuses,u,d)
  745. break
  746. ifcts = ofcts
  747. for u in xuses:
  748. if u in mods.keys() and ifcts != []:
  749. ifcts,iuses = sortFunctions(ifcts,iuses,list,mods,list[mods[u][0]][u]['uses'])
  750. return ifcts,iuses
  751. # _____ ____________________________________________
  752. # ____/ DOXYGEN parse /___________________________________________/
  753. #
  754. doxycomment = re.compile(r'!>(?P<doxy>.*)\s*\Z') #,re.I)
  755. doxy_tag = re.compile(r'!>\s*?@(?P<tag>[\w\[,\]]+)(?P<after>.*)\s*\Z') #,re.I)
  756. doxy_title = re.compile(r'\s+(?P<title>.*)\s*\Z') #,re.I)
  757. """
  758. Parse a list of entry lines, removing the lines that are
  759. understood to be part of a tag -- the lines are removed
  760. from the 'core' iteratively -- Return one complete tag
  761. """
  762. def getNextDoxyTag(core):
  763. ltag = []; tag = ''; name = ''
  764. found = False
  765. while core != []:
  766. proc = re.match(doxy_tag,core[0])
  767. if proc:
  768. if not found:
  769. tag = proc.group('tag')
  770. proc = re.match(doxy_title,proc.group('after'))
  771. if proc: name = proc.group('title')
  772. found = True
  773. else: break
  774. if found: ltag.append(core[0])
  775. core.pop(0)
  776. return tag,name,ltag,core
  777. """
  778. Parse a list of entry lines, removing the doxygen blocks
  779. listing them out by tag names -- the doxygen blocks are removed
  780. from the 'core' iteratively -- Return the list of tags by blocks
  781. """
  782. def parseDoxyTags(core):
  783. tags = []
  784. while 1:
  785. tname,title,field,core = getNextDoxyTag(core)
  786. if tname =='': break
  787. tags.append([tname,title,field])
  788. return tags
  789. # _____ ____________________________________________
  790. # ____/ FORTRAN parse /___________________________________________/
  791. #
  792. #?varcomment = re.compile(r'[C!#*]\s*?[|!]\s*?(?P<vars>[\s\w,()]*)(?P<inout>(|[|!->=<\s]*[|!]))(?P<after>(|[^|!]*))\s*[|!]?\s*\Z') #,re.I)
  793. varcomment = re.compile(r'[C!#*]\s*?[|!]\s*?(?P<vars>[\s\w,()]*)(?P<inout>(|[|!->=<\s]*[|!]))(?P<after>(|[^|!]*))\s*[|!]?\s*\Z') #,re.I)
  794. def parseFortHeader(core):
  795. docs = []; title = []; vars = {}
  796. while 1:
  797. line = delComments([core[0]])
  798. if line == []:
  799. proc = re.match(varcomment,core[0])
  800. if proc:
  801. #print core[0].rstrip()
  802. if proc.group('vars').strip() != '':
  803. var = proc.group('vars').strip()
  804. val = proc.group('after').strip()
  805. ino = proc.group('inout').strip()
  806. if ino == '!!' or ino == '||': ino = '<>'
  807. #print val
  808. vars.update({var:[ino,[val]]})
  809. elif proc.group('after').strip() != '':
  810. #print vars
  811. vars[var][1].append(proc.group('after').strip())
  812. #print '##'+proc.group('vars')+'##','@@'+proc.group('inout')+'@@','>>'+proc.group('after')+'<<'
  813. #print var,vars[var]
  814. core.pop(0)
  815. continue
  816. line = line[0].rstrip()
  817. proc = re.match(pcl_title,line)
  818. if proc:
  819. type = proc.group('type').strip()
  820. if ( type != '' ):
  821. if not re.match(typ_name,type): break
  822. docs.append(core[0].rstrip())
  823. core.pop(0)
  824. continue
  825. proc = re.match(use_title,line)
  826. proc = proc or re.match(implictNone,line)
  827. proc = proc or re.match(itf_title,line)
  828. proc = proc or re.match(def_title,line)
  829. proc = proc or re.match(cmn_title,line)
  830. proc = proc or re.match(typ_xport,line)
  831. proc = proc or re.match(inc_title,line)
  832. proc = proc or re.match(typ_title,line)
  833. proc = proc or re.match(itz_title,line)
  834. proc = proc or re.match(xtn_title,line)
  835. if proc: break
  836. #proc = re.match(f77comment,line)
  837. #if not proc:
  838. docs.append(core[0].rstrip())
  839. core.pop(0)
  840. return docs,vars,core
  841. # Note that the spaces are kept in the 'after' text for possible formatting
  842. doxytags = '(brief|note|warning|history|bug|code)'
  843. doxycomment = re.compile(r'\s*!(?P<name>%s\b)(?P<after>.*?)\s*\Z'%(doxytags)) #,re.I)
  844. doxycommentadd = re.compile(r"\s*!\+(?P<after>.*?)\s*\Z") #,re.I)
  845. def parseDoxyHeader(body):
  846. # It is now assumed that doxytags could be part of the main
  847. # core of the Fortran.
  848. tags = []; tfound = False; tcount = -1
  849. core = []; core.extend(body); bcount = -1
  850. nfound = False
  851. # ~~ Parse Doxygen Tags ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  852. while core != []:
  853. line = core[0].rstrip()
  854. bcount = bcount + 1
  855. # ~~> parsing the tags
  856. proc = re.match(doxycomment,line)
  857. if proc:
  858. tcount = tcount + 1
  859. tags.extend([[]])
  860. tags[tcount].append(proc.group('name'))
  861. tags[tcount].append([proc.group('after')])
  862. tfound = True
  863. core.pop(0)
  864. body.pop(bcount)
  865. bcount = bcount - 1
  866. continue
  867. proc = re.match(doxycommentadd,line)
  868. if proc and tfound:
  869. tags[tcount][1].append(proc.group('after'))
  870. core.pop(0)
  871. body.pop(bcount)
  872. bcount = bcount - 1
  873. continue
  874. tfound = False
  875. # ~~> parsing the name of the program for later reference
  876. if not nfound:
  877. proc = re.match(pcl_title,line)
  878. if proc :
  879. proc = re.match(var_word,proc.group('after'))
  880. if proc : name = proc.group('word')
  881. nfound = True
  882. core.pop(0)
  883. return name,tags
  884. """
  885. Split a set of lines (content of a file) into a Doxygen header
  886. the definition of the FORTRAN entity and the text between the
  887. the definition oan the core of the FORTRAN entity -- The wrap
  888. iteratively goes through all included entities and sub-entities
  889. - lines contains the content of the file
  890. - icount is the number of entities included (functions, subroutines, etc.)
  891. """
  892. def parseDoxyWrap(lines):
  893. core = []; core.extend(lines)
  894. wrap = []; wrap.extend([[]])
  895. blevel = 0; bcount = 0
  896. # ~~ Split the content of the file by blocks ~~~~~~~~~~~~~~~~~~~~
  897. while core != []:
  898. line = core[0].rstrip()
  899. wrap[bcount].append(line)
  900. core.pop(0)
  901. proc = re.match(pcl_close,line)
  902. if proc:
  903. blevel = blevel - 1
  904. if blevel == 0:
  905. bcount = bcount + 1
  906. wrap.extend([[]])
  907. continue
  908. proc = re.match(pcl_title,line)
  909. if proc:
  910. blevel = blevel + 1
  911. continue
  912. # ~~ Clean the wrap ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  913. # remove the the last item of the wrap,
  914. # which is empty since it gets set just after the pcl_close
  915. ##>wrap.pop(len(wrap)-1)
  916. # ~~ Parse the DOXYGEN tags ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  917. doxy = []; name = ''
  918. for w in wrap:
  919. if w != []:
  920. n,d = parseDoxyHeader(w)
  921. if name == '': name = n #/!\ here takes the first name of the file
  922. doxy.extend([(name,n,d,w)])
  923. return doxy
  924. # _____ ________________________________________________
  925. # ____/ MAIN CALL /_______________________________________________/
  926. #
  927. __author__="Sebastien E. Bourban; Noemie Durand"
  928. __date__ ="$19-Jul-2010 08:51:29$"
  929. if __name__ == "__main__":
  930. # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  931. # ~~~~ Reads config file ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  932. print '\n\nLoading Options and Configurations\n\
  933. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n'
  934. USETELCFG = ''
  935. if environ.has_key('USETELCFG'): USETELCFG = environ['USETELCFG']
  936. SYSTELCFG = 'systel.cfg'
  937. if environ.has_key('SYSTELCFG'): SYSTELCFG = environ['SYSTELCFG']
  938. if path.isdir(SYSTELCFG): SYSTELCFG = path.join(SYSTELCFG,'systel.cfg')
  939. parser = OptionParser("usage: %prog [options] \nuse -h for more help.")
  940. parser.add_option("-c", "--configname",
  941. type="string",
  942. dest="configName",
  943. default=USETELCFG,
  944. help="specify configuration name, default is randomly found in the configuration file" )
  945. parser.add_option("-f", "--configfile",
  946. type="string",
  947. dest="configFile",
  948. default=SYSTELCFG,
  949. help="specify configuration file, default is systel.cfg" )
  950. parser.add_option("-r", "--rootdir",
  951. type="string",
  952. dest="rootDir",
  953. default='',
  954. help="specify the root, default is taken from config file" )
  955. parser.add_option("-v", "--version",
  956. type="string",
  957. dest="version",
  958. default='',
  959. help="specify the version number, default is taken from config file" )
  960. options, args = parser.parse_args()
  961. if not path.isfile(options.configFile):
  962. print '\nNot able to get to the configuration file: ' + options.configFile + '\n'
  963. dircfg = path.dirname(options.configFile)
  964. if path.isdir(dircfg) :
  965. print ' ... in directory: ' + dircfg + '\n ... use instead: '
  966. for dirpath,dirnames,filenames in walk(dircfg) : break
  967. for file in filenames :
  968. head,tail = path.splitext(file)
  969. if tail == '.cfg' : print ' +> ',file
  970. sys.exit()
  971. # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  972. # ~~~~ Works for all configurations unless specified ~~~~~~~~~~~~~~~
  973. cfgs = parseConfigFile(options.configFile)
  974. cfgnames = cfgs.keys()
  975. if options.configName != '':
  976. if options.configName not in cfgnames:
  977. print '\nNot able to find your configuration in the configuration file: ' + options.configFile + '\n'
  978. print ' ... use instead:'
  979. for cfgname in cfgnames : print ' +> ',cfgname
  980. sys.exit()
  981. cfgnames = [options.configName]
  982. # /!\ for testing purposes ... no real use
  983. for cfgname in cfgnames:
  984. # still in lower case
  985. if options.rootDir != '': cfgs[cfgname]['root'] = options.rootDir
  986. if options.version != '': cfgs[cfgname]['version'] = options.version
  987. # parsing for proper naming
  988. cfg = parseConfig_CompileTELEMAC(cfgs[cfgname])
  989. debug = True
  990. # ~~ Scans all source files to build a relation database ~~~~~
  991. print '\n\nScanning the source code\n\
  992. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n'
  993. fic,mdl,sbt,fct,prg,dep,all = scanSources(cfgname,cfg,False)
  994. sys.exit()