Commit b561ff18 authored by Sergio Costas's avatar Sergio Costas

At every end of a block will compare the current execution status (the status of all variables)

with the status when another execution thread passed in the same end of block, and if it already
has been checked, that execution thread will be removed. This allows to avoid combinatorial
explossion when having too much IFs, FORs, WHILEs and/or SWITCHes.
parent a0904278
......@@ -87,6 +87,7 @@ class crust(object): = None
self.intval = 0
self.floatval = 0.0
self.uid = None
def copy(self):
retval = crust.AST_node()
......@@ -120,6 +121,7 @@ class crust(object):
self.debug = []
self.print_debug = do_print_debug
self.id_counter = 0
self.expoints = {}
with open(headerpath, "r") as header:
do_process = False
......@@ -243,6 +245,9 @@ class crust(object):
if data is not None:
if (name == "type"):
data = tokens.tokens.get_token(data)
if data == "END_BLOCK":
newnode.uid = self.id_counter
self.id_counter += 1
elif isinstance(data, bytes):
data = data.decode("utf8")
elif isinstance(data, POINTER(self.AST_leaf)):
......@@ -1358,6 +1363,8 @@ class crust(object):
thread_status["debug_level"] = 0
thread_status["loop_level"] = 0
thread_status["find_label"] = None
# delete all the old expoints, because each function is processed independently
self.expoints = {}
if tree[0].type == "START_BLOCK":
tree = tree[1:] # the variable block has been already added
blocks = [ (tree, thread_status) ]
......@@ -1368,7 +1375,8 @@ class crust(object):
blocks = blocks[1:]
if current_block[0] is not None:
retval = self._process_block2(current_block[0], current_block[1])
blocks = retval + blocks
if retval is not None:
blocks = retval + blocks
if (current_block[1]["returned_something"] is None) and (current_block[1]["return_is_crust"] is not None):
self._add_error(current_block[1], self.MSG_ERROR, "Function '{:s}' expects a return value, but the code exited without it", function_name)
......@@ -1439,6 +1447,42 @@ class crust(object):
self._add_error(thread_status, self.MSG_ERROR, "Memory block '{:s}', initialized at line {:d}, is still in use at exit point in line {:d}", variable, init_line, line)
def _compare_status(self, ex_point, status):
""" Gets the current status and compares it with all the previous status in the same execution point.
If the current status has been already found, it returns TRUE. If not, it will be stored and will return FALSE
ex_point: the execution point UID
status: the status to compare
TRUE if the status has been already checked; FALSE if not
current_vars = status["variables"][0]
if not ex_point in self.expoints:
self.expoints[ex_point] = [ current_vars.copy() ]
return False
for old_expoint in self.expoints[ex_point]:
if len(old_expoint) != len(current_vars):
is_equal = True
for element in old_expoint:
if not element in current_vars:
is_equal = False
for item in old_expoint[element]:
if old_expoint[element][item] != current_vars[element][item]:
is_equal = False
if not is_equal:
if is_equal:
return True
return False
def _process_block2(self, tree, thread_status):
node = tree[0]
......@@ -1480,6 +1524,9 @@ class crust(object):
if (len(thread_status["variables"]) == 1):
# if we are at the end of the function, check the global variables
self._check_global_vars(thread_status, node.line)
if self._compare_status(node.uid, thread_status):
return None
return self._check_return_block(tree[1:], thread_status)
if node.type == "EMPTY_DECLARATOR":
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment