analyser.py 11 KB

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