mdd.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. #!/home/nickm/bin/python2.3
  2. import re, sys
  3. import textwrap
  4. files = sys.argv[1:]
  5. funcDeclaredIn = {}
  6. fileDeclares = {}
  7. functionCalls = {}
  8. funcCalledByFile = {}
  9. funcCalledByFunc = {}
  10. for fname in files:
  11. f = open(fname, 'r')
  12. curFunc = "???"
  13. functionCalls.setdefault(curFunc,{})
  14. lineno = 0
  15. for line in f.xreadlines():
  16. lineno += 1
  17. m = re.match(r'^[^\s/].*\s(\w+)\([^;]*$', line)
  18. if m:
  19. #print line, "->", m.group(1)
  20. curFunc = m.group(1)
  21. functionCalls.setdefault(curFunc,{})
  22. funcDeclaredIn[m.group(1)] = fname
  23. fileDeclares.setdefault(fname, {})[m.group(1)] = 1
  24. continue
  25. m = re.match(r'^(\w+)\([^;]', line)
  26. if m:
  27. #print line, "->", m.group(1)
  28. curFunc = m.group(1)
  29. functionCalls.setdefault(curFunc,{})
  30. funcDeclaredIn[m.group(1)] = fname
  31. fileDeclares.setdefault(fname, {})[m.group(1)] = 1
  32. continue
  33. while line:
  34. m = re.search(r'(\w+)\(', line)
  35. if not m: break
  36. #print line, "->", m.group(1)
  37. functionCalls[curFunc][m.group(1)] = 1
  38. #if curFunc == "???":
  39. # print ">>!!!!! at %s:%s"%(fname,lineno)
  40. funcCalledByFunc.setdefault(m.group(1), {})[curFunc]=1
  41. funcCalledByFile.setdefault(m.group(1), {})[fname]=1
  42. line = line[m.end():]
  43. f.close()
  44. fileUsers = {}
  45. fileUses = {}
  46. for fname in files:
  47. print "%s:"%fname
  48. users = {}
  49. for func in fileDeclares[fname]:
  50. cb = funcCalledByFile.get(func,{}).keys()
  51. for f in cb: users[f] = 1
  52. #print "users[%s] = %s"%(f,users[f])
  53. users = users.keys()
  54. users.sort()
  55. fileUsers[fname] = users
  56. for user in users:
  57. fileUses.setdefault(user,[]).append(fname)
  58. if user == fname: continue
  59. print " from %s:"%user
  60. for func in fileDeclares[fname]:
  61. if funcCalledByFile.get(func,{}).get(user,0):
  62. print " %s()"%func
  63. def wrap(s, pre):
  64. return textwrap.fill(s,
  65. width=77, initial_indent=pre,
  66. subsequent_indent=" "*len(pre))
  67. for fname in files:
  68. print
  69. print "===== %s"%fname
  70. print wrap(" ".join(fileUses[fname]),
  71. " Calls: ")
  72. print wrap(" ".join(fileUsers[fname]),
  73. " Called by: ")
  74. print "=============================="
  75. funcnames = functionCalls.keys()
  76. funcnames.sort()
  77. if 1:
  78. for func in funcnames:
  79. print "===== %s"%func
  80. callers = [c for c in funcCalledByFunc.get(func,{}).keys()
  81. if c != "???"]
  82. callers.sort()
  83. called = [c for c in functionCalls[func].keys() if c != "???"]
  84. called.sort()
  85. print wrap(" ".join(callers),
  86. " Called by:")
  87. print wrap(" ".join(called),
  88. " Calls:")
  89. # simple topological sort.
  90. functionDepth = {}
  91. while 1:
  92. BIG = 1000000
  93. any = 0
  94. for func in funcnames:
  95. if functionDepth.has_key(func):
  96. continue
  97. called = [c for c in functionCalls[func] if c != func and
  98. functionCalls.has_key(c)]
  99. if len(called) == 0:
  100. functionDepth[func] = 0
  101. #print "Depth(%s)=%s"%(func,0)
  102. any = 1
  103. continue
  104. calledDepths = [ functionDepth.get(c,BIG) for c in called ]
  105. if max(calledDepths) < BIG:
  106. d = functionDepth[func] = max(calledDepths)+1
  107. #print "Depth(%s)=%s"%(func,d)
  108. any = 1
  109. continue
  110. if not any:
  111. break
  112. # compute lexical closure.
  113. cycCalls = {}
  114. for func in funcnames:
  115. if not functionDepth.has_key(func):
  116. calls = [ c for c in functionCalls[func] if c != func and
  117. functionCalls.has_key(c) and not functionDepth.has_key(c)]
  118. cycCalls[func] = d = {}
  119. for c in calls:
  120. d[c]=1
  121. cycNames = cycCalls.keys()
  122. while 1:
  123. any = 0
  124. for func in cycNames:
  125. L = len(cycCalls[func])
  126. for called in cycCalls[func].keys():
  127. cycCalls[func].update(cycCalls[called])
  128. if L != len(cycCalls[func]):
  129. any = 1
  130. if not any:
  131. break
  132. depthList = [ (v,k) for k,v in functionDepth.items() ]
  133. depthList.sort()
  134. cycList = [ (len(v),k) for k,v in cycCalls.items() ]
  135. cycList.sort()
  136. for depth,name in depthList:
  137. print "Depth[%s]=%s"%(name,depth)
  138. for bredth,name in cycList:
  139. print "Width[%s]=%s"%(name,bredth)
  140. print "Sorted %s / %s"%(len(functionDepth),len(funcnames))