https://github.com/statycc/pymwp
Tip revision: 47b05d5139a07338f1051e9922f4220af3739a77 authored by Neea Rusch on 11 June 2021, 01:06:57 UTC
Merge pull request #35 from seiller/pypi-alpha2
Merge pull request #35 from seiller/pypi-alpha2
Tip revision: 47b05d5
Analysis.py
from __future__ import print_function
import sys
import json
import os
from pycparser import parse_file, c_parser, c_ast
from pymwp.matrix import decode
from pymwp import Relation, RelationList, Monomial, Polynomial
# -*- coding: UTF-8 -*-
#
sys.path.extend([".", ".."])
DEBUG_LEVEL = 0
NVIND = -1
# Create the parser and ask to parse the text. parse() will throw
# a ParseError if there's an error in the code
#
parser = c_parser.CParser()
# Parse a given file ↓
filename = sys.argv[1]
ast = parse_file(filename, use_cpp=True, cpp_path="gcc",
cpp_args=["-E"]) # replace cpp with gcc to remove comments
# Or parse the one given in text above ↑
# ast = parser.parse(text, filename='<None>')
# Can show the ast ↓
# ast.ext[0].show()
# print(ast.ext[0])
# Loop object
class MyWhile:
def __init__(self, node_while, parent, isOpt, subWhiles):
# Corresponding node in the ast
self.node_while = node_while
# its parent node
self.parent = parent
# a boolean to know if it's optimzed yet
self.isOpt = isOpt
# Sub loops it may contains
self.subWhiles = subWhiles
# Pretty printing
def show(self, indent=""):
indice = self.parent[1]
opt = self.isOpt
print(indent + "while - " + str(indice) + " est opt:" + str(opt))
self.node_while.show()
for sub_while in self.subWhiles:
sub_while.show("\t")
# pycparser provides visitors of nodes
# This simplify action we want to perform on specific node in a traversal way
# Here for visiting variables nodes
class varVisitor(c_ast.NodeVisitor):
def __init__(self):
self.values = []
def visit_ID(self, node):
self.values.append(node.name)
# Her for visiting and performing actions for every encountered while node
class WhileVisitor(c_ast.NodeVisitor):
def __init__(self):
# Will contain list of `myWhile` object
self.values = []
def visit(self, node, parent=None, i=-1):
method = "visit_" + node.__class__.__name__
visitor = getattr(self, method, self.generic_visit)
return visitor(node, parent, i)
# When visit create `myWhile` object to the list of while
def visit_While(self, node, parent=None, i=-1):
wv = WhileVisitor()
wv.visit(node.stmt)
myWhile = MyWhile(node, (parent, i), False, wv.values)
# mywhile = c_ast.While(node.cond,node.stmt)
self.values.append(myWhile)
def generic_visit(self, node, parent, i):
"""Called if no explicit visitor function exists for a
node. Implements preorder visiting of the node.
"""
i = 0
for c_name, c in node.children():
self.visit(c, node, i)
i += 1
# Rreturn the list of variables in a node
def list_var(node):
vv = varVisitor()
vv.visit(node)
return vv.values
# Assign value flow regarding to operator type
def create_vector(index, dblist, type): # type in ("u","+","*","undef")
list_vect = []
poly = Polynomial([])
if type == "u":
poly = Polynomial([
Monomial("m", [(0, index)]),
Monomial("m", [(1, index)]),
Monomial("m", [(2, index)]),
])
list_vect.append([poly])
if type == "*" and dblist[1][0] == dblist[1][1]:
poly = Polynomial([
Monomial("w", [(0, index)]),
Monomial("w", [(1, index)]),
Monomial("w", [(2, index)]),
])
list_vect.append([poly])
if type == "+" and dblist[1][0] == dblist[1][1]:
poly = Polynomial([
Monomial("w", [(0, index)]),
Monomial("p", [(1, index)]),
Monomial("w", [(2, index)]),
])
list_vect.append([poly])
if type == "*" and dblist[1][0] != dblist[1][1]:
poly = Polynomial([
Monomial("w", [(0, index)]),
Monomial("w", [(1, index)]),
Monomial("w", [(2, index)]),
])
poly2 = Polynomial([
Monomial("w", [(0, index)]),
Monomial("w", [(1, index)]),
Monomial("w", [(2, index)]),
])
list_vect.append([poly, poly2])
if type == "+" and dblist[1][0] != dblist[1][1]:
poly = Polynomial([
Monomial("w", [(0, index)]),
Monomial("m", [(1, index)]),
Monomial("p", [(2, index)]),
])
poly2 = Polynomial([
Monomial("w", [(0, index)]),
Monomial("p", [(1, index)]),
Monomial("m", [(2, index)]),
])
list_vect.append([poly, poly2])
if dblist[0][0] not in dblist[1]:
for v in list_vect:
v.insert(0, Polynomial([Monomial("o", [])]))
index = index + 1
return index, list_vect
# Return a RelationList corresponding for all possible matrices for `node`
def compute_rel(index, node): # miss unary and constantes operation
print("In compute_rel")
if isinstance(node, c_ast.Assignment):
x = node.lvalue.name
dblist = [[x], []]
if isinstance(node.rvalue, c_ast.BinaryOp): # x=y+z
nb_cst = 2
if not isinstance(node.rvalue.left, c_ast.Constant):
y = node.rvalue.left.name
dblist[1].append(y)
nb_cst -= 1
if not isinstance(node.rvalue.right, c_ast.Constant):
z = node.rvalue.right.name
dblist[1].append(z)
nb_cst -= 1
listvar = dblist[0]
for var in dblist[1]:
if var not in listvar:
listvar.append(var)
# listvar=list(set(dblist[0])|set(dblist[1]))
rest = RelationList.identity(listvar)
# Define dependence type
node.show()
if node.rvalue.op in ["+", "-"]:
print("operator +…")
if nb_cst == 0:
index, list_vect = create_vector(index, dblist, "+")
else:
index, list_vect = create_vector(index, dblist, "u")
elif node.rvalue.op in ["*"]:
print("operator *…")
if nb_cst == 0:
index, list_vect = create_vector(index, dblist, "*")
else:
index, list_vect = create_vector(index, dblist, "u")
else:
index, list_vect = create_vector(index, dblist, "undef")
####
print("list_vect=", list_vect)
rest.replace_column(list_vect[0], dblist[0][0])
if DEBUG_LEVEL >= 2:
print("DEBUG: Computing Relation (first case)")
node.show()
rest.show()
return index, rest
if isinstance(node.rvalue, c_ast.Constant): # x=Cte
rest = RelationList([x])
if DEBUG_LEVEL >= 2:
print("DEBUG: Computing Relation (second case)")
node.show()
rest.show()
return index, rest
if isinstance(node.rvalue, c_ast.UnaryOp): # x=exp(…)
listVar = None # list_var(exp)
rels = RelationList.identity([x] + listVar)
# A FAIRE
if DEBUG_LEVEL >= 2:
print("DEBUG: Computing Relation (third case)")
node.show()
rels.show()
return index, rels
if isinstance(node, c_ast.If): # if cond then … else …
print("analysing If:")
relT = RelationList([])
relF = RelationList([])
# handle case where statement block has no braces
# -> there are no block_items
if 'block_items' not in node.iftrue:
index, rel_list = compute_rel(index, node.iftrue)
relT.composition(rel_list)
if node.iffalse is not None:
index, rel_list = compute_rel(index, node.iffalse)
relF.composition(rel_list)
else:
for child in node.iftrue.block_items:
index, rel_list = compute_rel(index, child)
relT.composition(rel_list)
if node.iffalse is not None:
for child in node.iffalse.block_items:
index, rel_list = compute_rel(index, child)
relF.composition(rel_list)
rels = relF + relT
# rels=rels.conditionRel(list_var(node.cond))
if DEBUG_LEVEL >= 2:
print("DEBUG: Computing Relation (conditional case)")
node.show()
rels.show()
return index, rels
if isinstance(node, c_ast.While):
print("analysing While:")
rels = RelationList([])
for child in node.stmt.block_items:
index, rel_list = compute_rel(index, child)
rels.composition(rel_list)
if DEBUG_LEVEL >= 2:
print(
"DEBUG: Computing Relation (loop case) before fixpoint")
rels.show()
rels.fixpoint()
if DEBUG_LEVEL >= 2:
print("DEBUG: Computing Relation (loop case) after fixpoint")
rels.show()
rels.while_correction()
# rels = rels.conditionRel(list_var(node.cond))
if DEBUG_LEVEL >= 2:
print("DEBUG: Computing Relation (loop case)")
node.show()
rels.show()
return index, rels
if isinstance(node, c_ast.For):
print("analysing For:")
rels = RelationList([])
for child in node.stmt.block_items:
index, rel_list = compute_rel(index, child)
rels = rels.composition(rel_list)
rels = rels.fixpoint()
rels = rels.conditionRel(list_var(node.cond))
if DEBUG_LEVEL >= 2:
print("DEBUG: Computing Relation (loop case)")
node.show()
rels.show()
return index, rels
print("uncovered case ! Create empty RelationList (function call) ?")
node.show()
return index, RelationList([]) # FIX
# ################# Perform on loops ##########
# wv = WhileVisitor()
# wv.visit(ast)
# if len(wv.values) == 0 :
# print("No loops")
# else :
# myWhile = wv.values[0]
# myWhile.show()
# CompList(myWhile)
# Perform on entire main function
def analysis():
name = (os.path.join("./output/" +
os.path.basename(os.path.splitext(filename)[0])) +
".txt")
return compute_relation(name)
# uncomment when issues are fixed
# if not os.path.isfile(
# name) or os.path.getmtime(filename) > os.path.getmtime(name):
# return compute_relation(name)
# else:
# return retrieve_relation(name)
def compute_relation(name):
function_body = ast.ext[0].body
rels = RelationList([])
index = 0
for stmt in function_body.block_items:
index, rel_list = compute_rel(index, stmt)
rels.composition(rel_list)
combinations = output_json(name, rels, index)
return rels, combinations
def retrieve_relation(name):
with open(name, "r") as file_object:
data = json.load(file_object)
matrix = data["relation"]["matrix"]
variables = data["relation"]["variables"]
combinations = data["combinations"]
rel = Relation(variables, decode(matrix))
rels = RelationList([])
rels.list[0] = rel
return rels, combinations
def output_json(name, rels, index):
rel = rels.relations[0]
combinations = rel.non_infinity([0, 1, 2], index)
info = {"relation": rel.to_dict(), "combinations": combinations}
dir_path, file_name = os.path.split(name)
if not os.path.exists(dir_path):
os.makedirs(dir_path)
with open(name, "w") as outfile:
json.dump(info, outfile, indent=4)
return combinations
print('=' * 50)
print('Running deprecated version of Analysis.')
print('press enter to proceed...')
print('=' * 50)
input()
rels, combinations = analysis()
rels.show()
if combinations:
print(combinations)
else:
print("infinite")
# print("*********** FINAL CODE ****************")
# if DEBUG>=3:
# ast.show()
# generator = c_generator.CGenerator()
# print(generator.visit(ast))