analyser.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379
  1. from __future__ import print_function
  2. import os
  3. import copy;
  4. from pycparser import c_ast
  5. INT_TYPES = ['int', 'short', 'float']
  6. FLOAT_TYPES = ['float', 'double']
  7. STRING_TYPES = ['char', 'string']
  8. VALID_TPYES = list()
  9. VALID_TPYES.extend(INT_TYPES)
  10. VALID_TPYES.extend(FLOAT_TYPES)
  11. VALID_TPYES.extend(STRING_TYPES)
  12. VALID_LOGIC_OPS = ['||', '&&', '!']
  13. VALID_REL_OPS = ['==', '!=', '>=', '>', '<=', '<']
  14. VALID_OPS = list(['*', '-', '/', '+', '%', '++', '--', 'p--', 'p++'])
  15. VALID_OPS.extend(VALID_LOGIC_OPS)
  16. VALID_OPS.extend(VALID_REL_OPS)
  17. def normalizeType(type):
  18. if type in INT_TYPES:
  19. return 'int'
  20. elif type in FLOAT_TYPES:
  21. return 'float'
  22. else:
  23. return 'string'
  24. class DeclarationInfo:
  25. def __init__ (self, type, dimensions, isPointer = False):
  26. self.type = type
  27. self.dimensions = dimensions
  28. self.isPointer = isPointer
  29. def isVector (self) :
  30. return self.dimensions == 1
  31. def isMatrix (self):
  32. return self.dimensions == 2
  33. def isMultiDimension (self):
  34. return self.dimensions > 2
  35. def isArray (self):
  36. return self.dimensions > 0
  37. class CommandInfo:
  38. def __init__ (self, condType, numLogicOps, numRelOps, opList):
  39. self.condType = condType
  40. self.numLogicOps = numLogicOps
  41. self.numRelOps = numRelOps
  42. self.opList = opList
  43. def __str__(self):
  44. return "Type:%s LogicOpCount:%d RelOpCount:%d OpList:%s"%( self.condType, self.numLogicOps, self.numRelOps, self.opList)
  45. class ForCommandInfo (CommandInfo):
  46. def __init__ (self, useAssignment, useNext, condType, numLogicOps, numRelOps, opList):
  47. CommandInfo.__init__(self, condType, numLogicOps, numRelOps, opList)
  48. self.useAssignment = useAssignment
  49. self.useNext = useNext
  50. def __str__(self):
  51. return "hasInit:%s hasNext:%s Type:%s LogicOpCount:%d RelOpCount:%d OpList:%s"%(self.useAssignment, self.useNext, self.condType, self.numLogicOps, self.numRelOps, self.opList)
  52. class ASTAnalyser:
  53. def __init__(self, assignment, student, nodeList):
  54. self.assignment = assignment
  55. self.student = student
  56. self.nodes = nodeList
  57. self.commandCount = dict()
  58. self.declarationData = list()
  59. self.forCommandData = list()
  60. self.conditionCommandData = list()
  61. self.operatorsCount = dict()
  62. self.constantInitCount = dict()
  63. #<helpers
  64. self.logicOpCount = 0
  65. self.relOpCount = 0
  66. self.opList = list()
  67. #helpers />
  68. self.declarations = dict()
  69. self.declarationsPointers = dict()
  70. self.declarationsVectors = dict()
  71. self.declarationsMatrixes = dict()
  72. def conditionCommandStr (self) :
  73. return [ s.__str__() for s in self.conditionCommandData]
  74. def forCommandStr (self) :
  75. return [ s.__str__() for s in self.forCommandData]
  76. def beginAnalysis(self):
  77. for n in self.nodes:
  78. self.proccessCommand(n)
  79. self.countDeclarations()
  80. def countDeclarations(self):
  81. pointers = [i for i in self.declarationData if i.isPointer]
  82. vectors = [i for i in self.declarationData if i.isVector()]
  83. matrixs = [i for i in self.declarationData if i.isMatrix()]
  84. others = [i for i in self.declarationData if not (i.isArray() or i.isPointer)]
  85. for p in pointers:
  86. type = normalizeType(p.type)
  87. if type == 'string':
  88. if type in self.declarations:
  89. self.declarations[type] += 1
  90. else:
  91. self.declarations[type] = 1
  92. elif type in self.declarationsPointers:
  93. self.declarationsPointers[type] += 1
  94. else:
  95. self.declarationsPointers[type] = 1
  96. for v in vectors:
  97. type = normalizeType(v.type)
  98. if type == 'string':
  99. if type in self.declarations:
  100. self.declarations[type] += 1
  101. else:
  102. self.declarations[type] = 1
  103. elif type in self.declarationsVectors:
  104. self.declarationsVectors[type] += 1
  105. else:
  106. self.declarationsVectors[type] = 1
  107. for m in matrixs:
  108. type = normalizeType(m.type)
  109. if type in self.declarationsMatrixes:
  110. self.declarationsMatrixes[type] += 1
  111. else:
  112. self.declarationsMatrixes[type] = 1
  113. for o in others:
  114. type = normalizeType(o.type)
  115. if type in self.declarations:
  116. self.declarations[type] += 1
  117. else:
  118. self.declarations[type] = 1
  119. def proccessDecl (self, node):
  120. type = node.type
  121. dimensions = 0
  122. isPointer = False
  123. while type.__class__.__name__ != 'IdentifierType':
  124. if type.__class__.__name__ == 'ArrayDecl':
  125. dimensions += 1
  126. elif type.__class__.__name__ == 'PtrDecl':
  127. isPointer = True
  128. type = type.type
  129. actualType = type.names[-1]
  130. if actualType in VALID_TPYES:
  131. self.declarationData.append(DeclarationInfo(actualType, dimensions, isPointer))
  132. init = node.init
  133. initName = init.__class__.__name__
  134. if initName == 'Constant' and dimensions == 0 and not isPointer:
  135. if init.value in self.constantInitCount:
  136. self.constantInitCount[init.value] += 1
  137. else:
  138. self.constantInitCount[init.value] = 1
  139. def proccessFuncDef (self, node):
  140. name = node.__class__.__name__
  141. self.incCmdCount(name)
  142. commandList = node.body.block_items
  143. for cmd in commandList:
  144. self.proccessCommand(cmd)
  145. def proccessFuncCall (self, node):
  146. name = node.__class__.__name__
  147. self.incCmdCount(name)
  148. epxrs = node.args.exprs
  149. for e in epxrs:
  150. self.countOperators(e)
  151. def proccessAssignment (self, node):
  152. name = node.__class__.__name__
  153. self.incCmdCount(name)
  154. epxr = node.rvalue
  155. self.countOperators(epxr)
  156. def proccessReturn (self, node):
  157. name = node.__class__.__name__
  158. self.incCmdCount(name)
  159. epxr = node.expr
  160. self.countOperators(epxr)
  161. def proccessSwitch (self, node):
  162. name = node.__class__.__name__
  163. self.incCmdCount(name)
  164. epxr = node.cond
  165. self.countOperators(epxr)
  166. cmdList = node.stmt.block_items
  167. for cmd in cmdList:
  168. self.proccessCommand(cmd)
  169. def proccessDoWhile (self, name, node):
  170. self.incCmdCount(name)
  171. epxr = node.cond
  172. self.logicOpCount = 0
  173. self.relOpCount = 0
  174. self.opList[:] = []
  175. condType = self.checkCondType(epxr)
  176. self.countOperators(epxr)
  177. logicCount = self.logicOpCount
  178. relCount = self.relOpCount
  179. opList = copy.deepcopy(self.opList)
  180. cmdList = node.stmt
  181. cmdName = cmdList.__class__.__name__
  182. if cmdName == 'Compound':
  183. for cmd in cmdList:
  184. self.proccessCommand(cmd)
  185. else:
  186. self.proccessCommand(cmdList)
  187. self.conditionCommandData.append(CommandInfo(condType,logicCount, relCount, opList))
  188. def proccessFor (self, node):
  189. name = node.__class__.__name__
  190. self.incCmdCount(name)
  191. epxr = node.cond
  192. self.logicOpCount = 0
  193. self.relOpCount = 0
  194. self.opList[:] = []
  195. condType = self.checkCondType(epxr)
  196. self.countOperators(epxr)
  197. logicCount = self.logicOpCount
  198. relCount = self.relOpCount
  199. opList = copy.deepcopy(self.opList)
  200. hasInit = node.init.__class__.__name__ != 'NoneType'
  201. if hasInit:
  202. self.proccessCommand(node.init)
  203. hasNext = node.next.__class__.__name__ != 'NoneType'
  204. if hasNext:
  205. self.proccessCommand(node.next)
  206. if node.next.__class__.__name__ != 'FuncCall':
  207. self.countOperators(node.next)
  208. cmdList = node.stmt
  209. cmdName = cmdList.__class__.__name__
  210. if cmdName == 'Compound':
  211. for cmd in cmdList:
  212. self.proccessCommand(cmd)
  213. elif name != 'NoneType':
  214. self.proccessCommand(cmdList)
  215. self.forCommandData.append(ForCommandInfo(hasInit, hasNext, condType, logicCount, relCount, opList))
  216. def proccessIf (self, node):
  217. name = node.__class__.__name__
  218. self.incCmdCount(name)
  219. epxr = node.cond
  220. self.logicOpCount = 0
  221. self.relOpCount = 0
  222. self.opList[:] = []
  223. condType = self.checkCondType(epxr)
  224. self.countOperators(epxr)
  225. logicCount = self.logicOpCount
  226. relCount = self.relOpCount
  227. opList = copy.deepcopy(self.opList)
  228. iftrue = node.iftrue
  229. ifCompound = iftrue.__class__.__name__
  230. if ifCompound == 'Compound':
  231. cmdList = iftrue.block_items
  232. for cmd in cmdList:
  233. self.proccessCommand(cmd)
  234. else:
  235. self.proccessCommand(iftrue)
  236. iffalse = node.iffalse
  237. ifCompound = iffalse.__class__.__name__
  238. if ifCompound == 'Compound':
  239. cmdList = iffalse.block_items
  240. for cmd in cmdList:
  241. self.proccessCommand(cmd)
  242. elif name != 'NoneType':
  243. self.proccessCommand(iffalse)
  244. self.conditionCommandData.append(CommandInfo(condType, logicCount, relCount, opList))
  245. def proccessCase (self, node):
  246. try:
  247. epxr = node.expr
  248. self.countOperators(epxr)
  249. except:
  250. pass
  251. cmdList = node.stmts
  252. for cmd in cmdList:
  253. self.proccessCommand(cmd)
  254. def countOperators (self, expr):
  255. name = expr.__class__.__name__
  256. if name == 'UnaryOp' :
  257. op = expr.op
  258. if not op in VALID_OPS:
  259. return
  260. self.incOpCount(op)
  261. if op in VALID_LOGIC_OPS:
  262. self.logicOpCount += 1
  263. elif op in VALID_REL_OPS:
  264. self.relOpCount += 1
  265. self.opList.append(op)
  266. self.countOperators(expr.expr)
  267. elif name == 'BinaryOp':
  268. op = expr.op
  269. if op in VALID_OPS:
  270. self.incOpCount(op)
  271. if op in VALID_LOGIC_OPS:
  272. self.logicOpCount += 1
  273. elif op in VALID_REL_OPS:
  274. self.relOpCount += 1
  275. self.opList.append(op)
  276. self.countOperators(expr.left)
  277. self.countOperators(expr.right)
  278. elif name == 'FuncCall':
  279. self.proccessFuncCall(expr)
  280. elif name == 'Cast':
  281. self.countOperators(expr.expr)
  282. else:
  283. pass
  284. def incOpCount (self, op):
  285. if op in self.operatorsCount:
  286. self.operatorsCount[op] += 1
  287. else:
  288. self.operatorsCount[op] = 1
  289. def incCmdCount (self, cmd):
  290. if cmd in self.commandCount:
  291. self.commandCount[cmd] += 1
  292. else:
  293. self.commandCount[cmd] = 1
  294. def checkCondType (self, expr):
  295. name = expr.__class__.__name__
  296. if name == 'BinaryOp':
  297. op = expr.op
  298. if op in VALID_LOGIC_OPS:
  299. return 'LogicOp'
  300. elif op in VALID_REL_OPS:
  301. return 'RelationalOp'
  302. else:
  303. return 'OtherOp'
  304. elif name == 'UnaryOp':
  305. op = expr.op
  306. if op in VALID_LOGIC_OPS:
  307. return 'LogicOp'
  308. else:
  309. return 'OtherOp'
  310. elif name == 'Cast':
  311. return self.checkCondType(expr.expr)
  312. else:
  313. return 'BooleanValue'
  314. def proccessCommand (self, node):
  315. name = node.__class__.__name__
  316. if name == 'Decl':
  317. self.proccessDecl(node)
  318. elif name == 'FuncDef':
  319. self.proccessFuncDef(node)
  320. elif name == 'FuncCall':
  321. self.proccessFuncCall(node)
  322. elif name == 'Assignment':
  323. self.proccessAssignment(node)
  324. elif name == 'Return':
  325. self.proccessReturn(node)
  326. elif name == 'Switch':
  327. self.proccessSwitch(node)
  328. elif name == 'Case' or name == 'Default':
  329. self.proccessCase(node)
  330. elif name == 'If':
  331. self.proccessIf(node)
  332. elif name == 'DoWhile' or name == 'While':
  333. self.proccessDoWhile(name, node)
  334. elif name == 'For':
  335. self.proccessFor(node)
  336. else:
  337. pass
  338. #print("Unknown Command: %s" % name )