def getrpnftndoc(filename): """Extract in a list of dictionaries the parsed RPN style doc string of a Fortran file, one dic per sub or fn of prog getrpnftndoc(filename) """ #Define regex refunc = re.compile(r'^\s+([a-zA-Z][a-zA-Z0-9_*]+\s+function)\s+([a-zA-Z][a-zA-Z0-9_]+).*',re.I) resub = re.compile(r'^\s+(subroutine|program)\s+([a-zA-Z][a-zA-Z0-9_]+).*',re.I) retag = re.compile(r'^[*!]([a-zA-Z]+).*',re.I) rebgn = re.compile(r'^[*!]\*\*([a-zA-Z].*)',re.I) reend = re.compile(r'^[*!]\*.*',re.I) ignorelist = [ re.compile(r'^#include\s+<model_macros_f\.h>',re.I), re.compile(r'^#include\s+[\'"]impnone.cdk[\'"]',re.I), re.compile(r'^\*[cv]dir\s+',re.I), re.compile(r'^(\*|\s*!)?\s*$',re.I) ] #read file fsock = openAnything(filename) a = fsock.read() mylist = a.splitlines() #initialize var for loop indoc = False insec = None counter = 0 linecounter = 0 mydocdic = [{ 'filename':filename, 'subname':'', 'startline':0, 'all':'' }, ] #loop through lines for myline in mylist: linecounter += 1 keepline = True ignore = False for reitem in ignorelist: if re.search(reitem,myline,re.I): ignore = True if indoc and not ignore: mydocdic[counter]['all'] += myline+"\n" if re.search(retag,myline,re.I): insec = (re.sub(retag,r'\1',myline)).lower() keepline = False elif re.search(resub,myline,re.I): insec = 'main' mydocdic[counter]['subname'] = \ re.sub(resub,r'\2',myline) mydocdic[counter]['startline'] = linecounter elif re.search(refunc,myline,re.I): insec = 'main' mydocdic[counter]['subname'] = \ re.sub(refunc,r'\2',myline) mydocdic[counter]['startline'] = linecounter #elif re.search(r'^\s+',myline): #code line # pass elif re.search(r'^[*cC!]\s+\W+',myline): #in section comment line pass elif re.search(r'^[^*cC!]\s*\W+',myline): #code line pass elif re.search(reend,myline): #end of doc section indoc = False keepline = False if insec and keepline: if insec in mydocdic[counter].keys(): mydocdic[counter][insec] += str(myline)+"\n" else: mydocdic[counter][insec] = myline+"\n" elif re.search(rebgn,myline): indoc = True insec = 'title' mydocdic[counter]['all'] += myline+"\n" mydocdic[counter][insec] = myline+"\n" #if len(subsecs)<1 or insec in subsecs: # print insec,myline return mydocdic
def tidy_f90(filename): """echo a tidy up version of a f90 program tidy_f90(filename) """ emptypattern = [ # - merge multiple empty lines (empty comment == empty line) (r'\n[ \t]*![ \t]*\n',"\n\n"), (r'\n([ \t]*\n)+', "\n\n") ] #Define regex patternlist = [ # - remove trailing blanks (r'[ \t]+\n', "\n"), # - remove extra head blanks in comments (more than 3) (r'\n[ \t]*![ \t][ \t][ \t]+',"\n! "), # - remove extra spaces around parentesis [except after if] (r'[ \t]*\([ \t]*', "("), (r'[ \t]*\)', ")"), (r'if\(', "if ("), # - max one space after comma (none before) (r'[ \t]+,', ","), #TODO: should not catch '\n[ \t]+\(' (r',[ \t]+', ", "), # - at least one space before trailing & (r'&[ \t]*\n', " &\n"), #TODO: should not add one if there # - update doc format (r'!author','!@author'), (r'!revision','!@revisions'), (r'!arguments','!@arguments'), (r'!object','!@description'), (r'\n!\*\*[ \t]*s/r[ \t]*','\n!/**\n!@objective'), (r'\n!\*[ \t]*\n','\n!**/\n'), # - misc (r'end[ \t]+do','enddo'), (r'end[ \t]+if','endif'), (r'else[ \t]+if','elseif') ] # - replace .eq. (and other) notation, one space around, lowercase oprlist = [ (r'\.eq\.',r'=='), (r'\.ne\.',r'/='), (r'\.gt\.',r'>'), (r'\.ge\.',r'>='), (r'\.lt\.',r'<'), (r'\.le\.',r'<=') ] postfixlist = [ (r'\b[ \t]*\.or\.[ \t]*\b',' .or. '), (r'\b[ \t]*\.and\.[ \t]*\b',' .and. '), (r'[ \t]*=[ \t]*',' = '), (r'\b\([ \t]*len[ \t]*=[ \t]*\b','(len='), (r'\b\([ \t]*kind[ \t]*=[ \t]*\b','(kind='), (r'= +=','=='), (r'/ +=','/='), (r'> +=','>='), (r'< +=','<='), (r'= +>','=>') ] pattern = [] replace = [] for (opr1,opr2) in patternlist: pattern.append(re.compile(opr1,re.I)) replace.append(opr2) for (opr1,opr2) in oprlist: pattern.append(re.compile(opr1,re.I)) replace.append(opr2) # - one and only on space around = and other operators for (opr1,opr2) in oprlist: #TODO:not in comments/string pattern.append(re.compile(r'[ \t]*'+opr2+r'[ \t]*',re.I)) replace.append(' '+opr2+' ') for (opr1,opr2) in postfixlist: pattern.append(re.compile(opr1,re.I)) replace.append(opr2) pattern.append(re.compile(opr1,re.I)) replace.append(opr2) pattern.append(re.compile(opr1,re.I)) replace.append(opr2) #read file fsock = openAnything(filename) myfilestr = fsock.read() #s = re.sub("(?<= )(.+)(?= )", lambda m: "can use a callable for the %s text too" % m.group(1), s) #print(re.sub(pattern,replace,myfilestr)) (myfilestr,commentlist,stringslist) = pull_comm_str(myfilestr) i = 0 for mypatt in pattern: myfilestr = re.sub(mypatt,replace[i],myfilestr) i=i+1 myfilestr = indent_f90(myfilestr) myfilestr = push_comm_str(myfilestr,commentlist,stringslist) pattern = [] replace = [] for (opr1,opr2) in emptypattern: pattern.append(re.compile(opr1,re.I)) replace.append(opr2) i = 0 for mypatt in pattern: myfilestr = re.sub(mypatt,replace[i],myfilestr) i=i+1 #TODO: # - replace licence # - last end should with function/sub name # - lower case [but not parameters] # - external and parameters... now attributes # - split too long lines # - add () on subroutine name and call sub when missing return myfilestr