Created
November 16, 2014 22:20
-
-
Save Komzpa/7c7e1a0f330378ee1773 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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 '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