123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400 |
- 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', 'string']
- 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)
- PRINT_COUNT = 0
- SCAN_COUNT = 0
- 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, cmdCount, condType, numLogicOps, numRelOps, opList):
- self.cmdCount = cmdCount
- 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, cmdCount, condType, numLogicOps, numRelOps, opList):
- CommandInfo.__init__(self, cmdCount, 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()
- self.cmdCountStack = [0]
- #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 == 'string':
- if type in self.declarations:
- self.declarations[type] += 1
- else:
- self.declarations[type] = 1
- elif 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):
- name = node.__class__.__name__
- self.incCmdCount(name)
- commandList = node.body.block_items
- for cmd in commandList:
- self.proccessCommand(cmd)
- def proccessFuncCall (self, node):
- global PRINT_COUNT, SCAN_COUNT
- name = node.__class__.__name__
- if node.name.name == "printf":
- PRINT_COUNT = PRINT_COUNT + 1
- elif node.name.name == "scanf":
- SCAN_COUNT = SCAN_COUNT + 1
- 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__
- self.cmdCountStack.append(0)
- if cmdName == 'Compound':
- for cmd in cmdList:
- self.proccessCommand(cmd)
- else:
- self.proccessCommand(cmdList)
- self.conditionCommandData.append(CommandInfo(self.cmdCountStack.pop(), 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)
- self.cmdCountStack.append(0)
- 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, self.cmdCountStack.pop(), 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)
- self.cmdCountStack.append(0)
- 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':
- # TODO contar else's
- self.cmdCountStack.append(0)
- self.incCmdCount('Else')
- cmdList = iffalse.block_items
- for cmd in cmdList:
- self.proccessCommand(cmd)
- elif iffalse != None and name != 'NoneType':
- self.cmdCountStack.append(0)
- self.incCmdCount('Else')
- self.proccessCommand(iffalse)
- self.conditionCommandData.append(CommandInfo(self.cmdCountStack.pop(), 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 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.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 'logic_expression'
- elif op in VALID_REL_OPS:
- return 'relational_expression'
- else:
- return 'other_expression'
- elif name == 'UnaryOp':
- op = expr.op
- if op in VALID_LOGIC_OPS:
- return 'logic_expression'
- else:
- return 'other_expression'
- elif name == 'Cast':
- return self.checkCondType(expr.expr)
- else:
- return 'boolean_value'
- def proccessCommand (self, node):
- name = node.__class__.__name__
- self.cmdCountStack[-1] += 1
- if name == 'Decl':
- self.proccessDecl(node)
- self.cmdCountStack[-1] -= 1
- elif name == 'FuncDef':
- self.proccessFuncDef(node)
- self.cmdCountStack[-1] -= 1
- 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)
- self.cmdCountStack[-1] -= 1
- elif name == 'If':
- self.proccessIf(node)
- elif name == 'DoWhile' or name == 'While':
- self.proccessDoWhile(name, node)
- elif name == 'For':
- self.proccessFor(node)
- else:
- self.cmdCountStack[-1] -= 1
- #print("Unknown Command: %s" % name )
|