analyser.py 12 KB

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