Переглянути джерело

Implement code analyser and csv generator

Lucas de Souza 5 роки тому
батько
коміт
2d8e20088a
3 змінених файлів з 462 додано та 32 видалено
  1. 2 0
      .gitignore
  2. 372 0
      analyser.py
  3. 88 32
      cjson.py

+ 2 - 0
.gitignore

@@ -1,2 +1,4 @@
 *.pyc
 */**/*.pyc
+31.c
+log.txt

+ 372 - 0
analyser.py

@@ -0,0 +1,372 @@
+from __future__ import print_function
+
+import os
+import copy;
+from pycparser import c_ast
+
+INT_TYPES = ['int', 'short', 'float']
+FLOAT_TYPES = ['float', 'double']
+STRING_TYPES = ['char']
+
+VALID_TPYES = list()
+VALID_TPYES.extend(INT_TYPES)
+VALID_TPYES.extend(FLOAT_TYPES)
+VALID_TPYES.extend(STRING_TYPES)
+
+VALID_LOGIC_OPS = ['||', '&&', '!']
+VALID_REL_OPS = ['==', '!=', '>=', '>', '<=', '<']
+VALID_OPS = list(['*', '-', '/', '+', '%', '++', '--', 'p--', 'p++'])
+VALID_OPS.extend(VALID_LOGIC_OPS)
+VALID_OPS.extend(VALID_REL_OPS)
+
+def normalizeType(type):
+  if type in INT_TYPES:
+    return 'int'
+  elif type in FLOAT_TYPES:
+    return 'float'
+  else:
+    return 'string'
+
+class DeclarationInfo:
+  def __init__ (self, type, dimensions, isPointer = False):
+    self.type = type
+    self.dimensions = dimensions
+    self.isPointer = isPointer
+
+  def isVector (self) :
+    return self.dimensions == 1
+  
+  def isMatrix (self):
+    return self.dimensions == 2
+  
+  def isMultiDimension (self):
+    return self.dimensions > 2
+  
+  def isArray (self):
+    return self.dimensions > 0
+
+class CommandInfo:
+  def __init__ (self, condType, numLogicOps, numRelOps, opList):
+    self.condType = condType
+    self.numLogicOps = numLogicOps
+    self.numRelOps = numRelOps
+    self.opList = opList
+  
+  def __str__(self):
+    return "Type:%s LogicOpCount:%d RelOpCount:%d OpList:%s"%( self.condType, self.numLogicOps, self.numRelOps, self.opList)
+
+class ForCommandInfo (CommandInfo):
+  def __init__ (self, useAssignment, useNext, condType, numLogicOps, numRelOps, opList):
+    CommandInfo.__init__(self, condType, numLogicOps, numRelOps, opList)
+    self.useAssignment = useAssignment
+    self.useNext = useNext
+  
+  def __str__(self):
+    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)
+
+class ASTAnalyser:
+
+  def __init__(self, assignment, student, nodeList):
+    self.assignment = assignment
+    self.student = student
+    self.nodes = nodeList
+    self.commandCount = dict()
+    self.declarationData = list()
+    self.forCommandData = list()
+    self.conditionCommandData = list()
+    self.operatorsCount = dict()
+    self.constantInitCount = dict()
+    #<helpers
+    self.logicOpCount = 0
+    self.relOpCount = 0
+    self.opList = list()
+    #helpers />
+    self.declarations = dict()
+    self.declarationsPointers = dict()
+    self.declarationsVectors = dict()
+    self.declarationsMatrixes = dict()
+  
+  def conditionCommandStr (self) :
+    return [ s.__str__() for s in self.conditionCommandData]
+  
+  def forCommandStr (self) :
+    return [ s.__str__() for s in self.forCommandData]
+
+  def beginAnalysis(self):
+    for n in self.nodes:
+      self.proccessCommand(n)
+    self.countDeclarations()
+
+  def countDeclarations(self):
+    pointers = [i for i in self.declarationData if i.isPointer]
+    vectors = [i for i in self.declarationData if i.isVector()]
+    matrixs = [i for i in self.declarationData if i.isMatrix()]
+    others = [i for i in self.declarationData if not (i.isArray() or i.isPointer)]
+    for p in pointers:
+      type = normalizeType(p.type)
+      if type == 'string':
+        if type in self.declarations:
+          self.declarations[type] += 1
+        else:
+          self.declarations[type] = 1
+      elif type in self.declarationsPointers:
+        self.declarationsPointers[type] += 1
+      else:
+        self.declarationsPointers[type] = 1
+
+    for v in vectors:
+      type = normalizeType(v.type)
+      if type in self.declarationsVectors:
+        self.declarationsVectors[type] += 1
+      else:
+        self.declarationsVectors[type] = 1
+    for m in matrixs:
+      type = normalizeType(m.type)
+      if type in self.declarationsMatrixes:
+        self.declarationsMatrixes[type] += 1
+      else:
+        self.declarationsMatrixes[type] = 1
+    for o in others:
+      type = normalizeType(o.type)
+      if type in self.declarations:
+        self.declarations[type] += 1
+      else:
+        self.declarations[type] = 1
+  
+  def proccessDecl (self, node):
+    type = node.type
+    dimensions = 0
+    isPointer = False
+    while type.__class__.__name__ != 'IdentifierType':
+      if type.__class__.__name__ == 'ArrayDecl':
+        dimensions += 1
+      elif type.__class__.__name__ == 'PtrDecl':
+        isPointer = True
+      type = type.type
+    actualType = type.names[-1]
+    if actualType in VALID_TPYES:
+      self.declarationData.append(DeclarationInfo(actualType, dimensions, isPointer))
+      init = node.init
+      initName = init.__class__.__name__
+      if initName == 'Constant' and dimensions == 0 and not isPointer:
+        if init.value in self.constantInitCount:
+          self.constantInitCount[init.value] += 1
+        else:
+          self.constantInitCount[init.value] = 1
+  
+  def proccessFuncDef (self, node):
+    commandList = node.body.block_items
+    for cmd in commandList:
+      self.proccessCommand(cmd)
+
+  def proccessFuncCall (self, node):
+    name = node.__class__.__name__
+    self.incCmdCount(name)
+    epxrs = node.args.exprs
+    for e in epxrs:
+      self.countOperators(e)
+    
+  def proccessAssignment (self, node):
+    name = node.__class__.__name__
+    self.incCmdCount(name)
+    epxr = node.rvalue
+    self.countOperators(epxr)
+  
+  def proccessReturn (self, node):
+    name = node.__class__.__name__
+    self.incCmdCount(name)
+    epxr = node.expr
+    self.countOperators(epxr)
+  
+  def proccessSwitch (self, node):
+    name = node.__class__.__name__
+    self.incCmdCount(name)
+    epxr = node.cond
+    self.countOperators(epxr)
+    cmdList = node.stmt.block_items
+    for cmd in cmdList:
+      self.proccessCommand(cmd)
+  
+  def proccessDoWhile (self, name, node):
+    self.incCmdCount(name)
+    epxr = node.cond
+    self.logicOpCount = 0
+    self.relOpCount = 0
+    self.opList[:] = []
+    condType = self.checkCondType(epxr)
+    self.countOperators(epxr)
+    logicCount = self.logicOpCount
+    relCount = self.relOpCount
+    opList = copy.deepcopy(self.opList)
+    cmdList = node.stmt
+    cmdName = cmdList.__class__.__name__
+    if cmdName == 'Compound':
+      for cmd in cmdList:
+        self.proccessCommand(cmd)
+    else:
+      self.proccessCommand(cmdList)
+    self.conditionCommandData.append(CommandInfo(condType,logicCount, relCount, opList))
+  
+  def proccessFor (self, node):
+    name = node.__class__.__name__
+    self.incCmdCount(name)
+    epxr = node.cond
+    self.logicOpCount = 0
+    self.relOpCount = 0
+    self.opList[:] = []
+    condType = self.checkCondType(epxr)
+    self.countOperators(epxr)
+    logicCount = self.logicOpCount
+    relCount = self.relOpCount
+    opList = copy.deepcopy(self.opList)
+
+    hasInit = node.init.__class__.__name__ != 'NoneType'
+    if hasInit:
+      self.proccessCommand(node.init)
+    
+    hasNext = node.next.__class__.__name__ != 'NoneType'
+    if hasNext:
+      self.proccessCommand(node.next)
+      if node.next.__class__.__name__ != 'FuncCall':
+        self.countOperators(node.next)
+
+    cmdList = node.stmt
+    cmdName = cmdList.__class__.__name__
+    if cmdName == 'Compound':
+      for cmd in cmdList:
+        self.proccessCommand(cmd)
+    elif name != 'NoneType':
+      self.proccessCommand(cmdList)
+    self.forCommandData.append(ForCommandInfo(hasInit, hasNext, condType, logicCount, relCount, opList))
+  
+  def proccessIf (self, node):
+    name = node.__class__.__name__
+    self.incCmdCount(name)
+    epxr = node.cond
+    self.logicOpCount = 0
+    self.relOpCount = 0
+    self.opList[:] = []
+    condType = self.checkCondType(epxr)
+    self.countOperators(epxr)
+    logicCount = self.logicOpCount
+    relCount = self.relOpCount
+    opList = copy.deepcopy(self.opList)
+
+    iftrue = node.iftrue
+    ifCompound = iftrue.__class__.__name__
+    if ifCompound == 'Compound':
+      cmdList = iftrue.block_items
+      for cmd in cmdList:
+        self.proccessCommand(cmd)
+    else:
+      self.proccessCommand(iftrue)
+
+    iffalse = node.iffalse
+    ifCompound = iffalse.__class__.__name__
+    if ifCompound == 'Compound':
+      cmdList = iffalse.block_items
+      for cmd in cmdList:
+        self.proccessCommand(cmd)
+    elif name != 'NoneType':
+      self.proccessCommand(iffalse)
+    self.conditionCommandData.append(CommandInfo(condType, logicCount, relCount, opList))
+  
+  def proccessCase (self, node):
+    try:
+      epxr = node.expr
+      self.countOperators(epxr)
+    except:
+      pass
+    cmdList = node.stmts
+    for cmd in cmdList:
+      self.proccessCommand(cmd)
+
+  def countOperators (self, expr):
+    name = expr.__class__.__name__
+    if name == 'UnaryOp' :
+      op = expr.op
+      if not op in VALID_OPS:
+        return
+      self.incOpCount(op)
+      if op in VALID_LOGIC_OPS:
+        self.logicOpCount += 1
+      elif op in VALID_REL_OPS:
+        self.relOpCount += 1
+      self.opList.append(op)
+      self.countOperators(expr.expr)
+    elif name == 'BinaryOp':
+      op = expr.op
+      if op in VALID_OPS:
+        self.incOpCount(op)
+      if op in VALID_LOGIC_OPS:
+        self.logicOpCount += 1
+      elif op in VALID_REL_OPS:
+        self.relOpCount += 1
+      self.opList.append(op)
+      self.countOperators(expr.left)
+      self.countOperators(expr.right)
+    elif name == 'FuncCall':
+      self.proccessFuncCall(expr)
+    elif name == 'Cast':
+      self.countOperators(expr.expr)
+    else:
+      pass
+
+  def incOpCount (self, op):
+    if op in self.operatorsCount:
+      self.operatorsCount[op] += 1
+    else:
+      self.operatorsCount[op] = 1
+
+  def incCmdCount (self, cmd):
+    if cmd in self.commandCount:
+      self.commandCount[cmd] += 1
+    else:
+      self.commandCount[cmd] = 1
+  
+  def checkCondType (self, expr):
+    name = expr.__class__.__name__
+    if name == 'BinaryOp':
+      op = expr.op
+      if op in VALID_LOGIC_OPS:
+        return 'LogicOp'
+      elif op in VALID_REL_OPS:
+        return 'RelationalOp'
+      else:
+        return 'OtherOp'
+    elif name == 'UnaryOp':
+      op = expr.op
+      if op in VALID_LOGIC_OPS:
+        return 'LogicOp'
+      else:
+        return 'OtherOp'
+    elif name == 'Cast':
+      return self.checkCondType(expr.expr)
+    else:
+      return 'BooleanValue'
+
+  def proccessCommand (self, node):
+    name = node.__class__.__name__
+    if name == 'Decl':
+      self.proccessDecl(node)
+    elif name == 'FuncDef':
+      self.proccessFuncDef(node)
+    elif name == 'FuncCall':
+      self.proccessFuncCall(node)
+    elif name == 'Assignment':
+      self.proccessAssignment(node)
+    elif name == 'Return':
+      self.proccessReturn(node)
+    elif name == 'Switch':
+      self.proccessSwitch(node)
+    elif name == 'Case' or name == 'Default':
+      self.proccessCase(node)
+    elif name == 'If':
+      self.proccessIf(node)
+    elif name == 'DoWhile' or name == 'While':
+      self.proccessDoWhile(name, node)
+    elif name == 'For':
+      self.proccessFor(node)
+    else:
+      pass
+      #print("Unknown Command: %s" % name )

Різницю між файлами не показано, бо вона завелика
+ 88 - 32
cjson.py