Skip to content

Instantly share code, notes, and snippets.

@Komzpa
Created November 16, 2014 22:20
Show Gist options
  • Save Komzpa/7c7e1a0f330378ee1773 to your computer and use it in GitHub Desktop.
Save Komzpa/7c7e1a0f330378ee1773 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import logging
import re
from itertools import islice
def window(seq, n=2):
"Returns a sliding window (of width n) over data from the iterable"
" s -> (s0,s1,...s[n-1]), (s1,s2,...,sn), ... "
it = iter(seq)
result = tuple(islice(it, n))
if len(result) == n:
yield result
for elem in it:
result = result[1:] + (elem,)
yield result
def clean_varname(var):
return var.strip().strip('[]&*')
def is_const(c):
if c.isdigit():
return True
if c == 'NULL':
return True
if c[0] == '"':
return True
if c[-1] == 'f':
try:
f = float(c[:-1])
return True
except:
pass
cpp_source = open("cpp.cpp").read()
types = ('const', 'void', 'int', 'char', 'float', 'size_t', 'void**', 'pD3DDevice', 'POINT', 'XZGAMEMENUVERTEX', 'D3DXVECTOR3', 'LPDIRECT3DDEVICE9', 'LPDIRECT3DTEXTURE9', 'RECT')
# удаляем whitespace
cpp_source = cpp_source.replace('\t', ' ')
cpp_source = cpp_source.replace(' ', ' ')
# удаляем комментарии
cpp_source = re.sub('//.*?$|/\*.*\*/', '', cpp_source, flags= re.S | re.M)
# скобочки отделяем
cpp_source = cpp_source.replace('{', '\n{\n')
cpp_source = cpp_source.replace('(', '\n(\n')
cpp_source = cpp_source.replace(')', '\n)\n')
cpp_source = cpp_source.replace('}', '\n}\n')
#cpp_source = cpp_source.replace(']', '\n]\n')
#cpp_source = cpp_source.replace('[', '\n[\n')
# разделители на отдельные строки
cpp_source = cpp_source.replace(',', '\n,\n')
cpp_source = cpp_source.replace(';', '\n;\n')
# операторы объединений
cpp_source = cpp_source.replace(' &&', '\n&&\n')
cpp_source = cpp_source.replace(' ||', '\n||\n')
cpp_source = cpp_source.replace(' -', '\n-\n')
cpp_source = cpp_source.replace(' +', '\n+\n')
# типы
for t in types:
cpp_source = cpp_source.replace(t+" ", '\n'+t+'\n')
# операторы присваивания
cpp_source = cpp_source.replace(' = ', '\n=\n')
cpp_source = cpp_source.replace('++', '\n++\n')
# ключевые слова
cpp_source = cpp_source.replace('delete []', '\ndelete[]\n')
cpp_source = cpp_source.replace('throw', '\nthrow\n')
cpp_source = cpp_source.replace('new', '\nnew\n')
cpp_source = cpp_source.replace('return', '\nreturn\n')
# операторы сравнения
cpp_source = cpp_source.replace(' > ', '\n>\n')
cpp_source = cpp_source.replace(' < ', '\n<\n')
cpp_source = cpp_source.replace(' >= ', '\n>=\n')
cpp_source = cpp_source.replace(' <= ', '\n<=\n')
cpp_source = cpp_source.replace(' != ', '\n!=\n')
cpp_source = cpp_source.replace(' == ', '\n==\n')
cpp_source = [i.strip() for i in cpp_source.split('\n') if i.strip()]
# - внутри сравнения
# - входные параметры
# - глобальные переменные
# - неиспользуемые переменные
depth = 0
control_depth = 1000
cmp_count = 0
vars_assigned = set()
vars_control = set()
vars_global = set()
vars_all = set()
for i, j, k in window(cpp_source, 3):
tags = set()
if j == "(" or j == '{':
depth += 1
continue
elif j == ")" or j == '}':
depth -= 1
if control_depth == depth +1:
# конец ифа
control_depth = 1000
#print "IF FINISHED!"
continue
elif is_const(j): # цифры - константы, неинтересно
continue
elif j in (',', ';'): # разделители - неинтересно
continue
elif j == 'if':
control_depth = depth + 1
#print "IF STARTED!"
continue
elif k == '(': #TODO функция или вызов
continue
elif j in types:
continue
elif j in ('&&', '||', '+', '-', '/', '*', ':'):
continue
elif j in ('else', 'throw', 'new'):
continue
elif j in ('<', '>', '==', '!=', '>=', '<='):
cmp_count += 1
continue
elif j in ('=', '++'):
vars_assigned.add(clean_varname(i))
if depth == 0:
vars_global.add(clean_varname(i))
continue
elif j in ('delete[]'):
vars_assigned.add(clean_varname(k))
continue
is_control_now = control_depth <= depth
if is_control_now:
vars_control.add(clean_varname(j))
vars_all.add(clean_varname(j))
#print is_control_now, depth, clean_varname(j)
print 'McClure metric = ', cmp_count + len(vars_control)
print '(comparisons) C = ', cmp_count
print '(control vars) V = ', len(vars_control), vars_control
print
print 'Chapin metric = ', len(vars_global) + 2 *len(vars_global) + 3 *len(vars_control)
print '(global vars) P = ', len(vars_global), vars_global
print '(modified vars) M = ', len(vars_assigned), vars_assigned
print '(control vars) C = ', len(vars_control), vars_control
print '(unused vars) G = ', 0
# готовим вывод
cpp_source = "\n".join(cpp_source)
open('c_tree', 'w').write(cpp_source)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment