Commit 86d04ba9 authored by Sergio Costas's avatar Sergio Costas

Added support for GOTO statements

parent 39e806bb
......@@ -221,7 +221,7 @@ class crust(object):
def _copy_status(self, status):
""" Fully copies a thread_status to allow several parallel emulations """
retval = {"debug_level": status["debug_level"], "loop_level": status["loop_level"], "variables": []}
retval = {"debug_level": status["debug_level"], "loop_level": status["loop_level"], "find_label": status["find_label"], "variables": []}
for element in status["variables"]:
vargroup = {}
for varname in element:
......@@ -416,11 +416,13 @@ class crust(object):
*"node" the variable node being assigned, or None if it is not a variable
"""
thread_status = self._copy_status(thread_status)
if thread_status["find_label"] is not None:
return [ {"thread_status":thread_status, "value":self.VALUE_NOT_NULL_OR_NULL, "type":self.TYPE_NO_CRUST, "condition":self.CONDITION_FALSE_TRUE, "node":None} ]
if statement is None:
return [ {"thread_status":thread_status, "value":crust.VALUE_UNINITIALIZED, "type":self.TYPE_NO_MATTER, "condition":self.CONDITION_FALSE_TRUE, "node":None} ]
thread_status = self._copy_status(thread_status)
if statement.type == "CONSTANT":
if (statement.t_null) or (statement.intval == 0):
......@@ -1024,7 +1026,7 @@ class crust(object):
def process_tree(self, tree):
""" Process the main tree with the global variables and the function definitions and declarations """
thread_status = { "variables": [ {} ], "debug_level": 0, "loop_level": 0}
thread_status = { "variables": [ {} ], "debug_level": 0, "loop_level": 0, "find_label": None }
# First fill all the global variables and the function declarations
for node in tree:
if (node.type == "TYPE_SPECIFIER"):
......@@ -1100,6 +1102,7 @@ class crust(object):
def _process_block(self, tree, thread_status):
thread_status["debug_level"] = 0
thread_status["loop_level"] = 0
thread_status["find_label"] = None
if tree[0].type == "START_BLOCK":
tree = tree[1:] # the variable block has been already added
blocks = [ (tree, thread_status) ]
......@@ -1141,7 +1144,8 @@ class crust(object):
return self._check_return_block(tree[1:], thread_status)
if node.type == "CRUST_DEBUG":
self._do_debug(thread_status)
if thread_status["find_label"] is None:
self._do_debug(thread_status)
return self._check_return_block(tree[1:], thread_status)
if node.type == "CRUST_ENABLE":
......@@ -1191,7 +1195,7 @@ class crust(object):
var_defined["enum"] = False
var_defined = self._node_fill_parameters(thread_status, node, var_defined)
thread_status["variables"][0][node.name] = var_defined
if node.assignment is None:
if (node.assignment is None):
return self._check_return_block(tree[1:], thread_status)
# if the variable definition also has an assignment, then create a fake '=' node
tmpnode = node.copy()
......@@ -1224,22 +1228,23 @@ class crust(object):
retvals += self._check_return_block(block_false, self._copy_status(option["thread_status"]))
return retvals
if node.type == "RETURN":
if node.child1 is not None:
self._eval_statement(node.child1[0], thread_status, True)
# check if there are blocks in use
while(len(thread_status["variables"]) > 1):
self._check_blocks_in_use(thread_status, thread_status["variables"][0], node.line)
thread_status["variables"] = thread_status["variables"][1:]
return [(None, thread_status)]
if node.type == "BREAK":
if thread_status["loop_level"] == 0:
self._add_error(thread_status, self.MSG_CRITICAL, "Break not in a loop at line {:d}", node.line)
if thread_status["find_label"] is None:
if node.type == "RETURN":
if node.child1 is not None:
self._eval_statement(node.child1[0], thread_status, True)
# check if there are blocks in use
while(len(thread_status["variables"]) > 1):
self._check_blocks_in_use(thread_status, thread_status["variables"][0], node.line)
thread_status["variables"] = thread_status["variables"][1:]
return [(None, thread_status)]
while(tree[0].type != "END_LOOP"):
tree = tree[1:]
return self._check_return_block(tree, thread_status)
if node.type == "BREAK":
if thread_status["loop_level"] == 0:
self._add_error(thread_status, self.MSG_CRITICAL, "Break not in a loop at line {:d}", node.line)
return [(None, thread_status)]
while(tree[0].type != "END_LOOP"):
tree = tree[1:]
return self._check_return_block(tree, thread_status)
if node.type == "END_LOOP":
thread_status["loop_level"] -= 1
......@@ -1309,10 +1314,21 @@ class crust(object):
else:
return retvals
options = self._eval_statement(node, thread_status, True)
if node.type == "GOTO":
if thread_status["find_label"] is None:
thread_status["find_label"] = node.name
return self._check_return_block(tree[1:], thread_status)
if node.type == "LABEL":
if thread_status["find_label"] is not None:
if node.name == thread_status["find_label"]:
thread_status["find_label"] = None
return self._check_return_block(tree[1:], thread_status)
threads = self._eval_statement(node, thread_status, True)
retvals = []
for option in options:
retvals += self._check_return_block(tree[1:], option["thread_status"])
for thread in threads:
retvals += self._check_return_block(tree[1:], thread["thread_status"])
return retvals
......
......@@ -402,27 +402,3 @@ void comment(void) {
}
error("unterminated comment");
}
/*int check_type(void) {
if (find_type(yytext) != NULL) {
return TYPE_NAME;
} else {
return IDENTIFIER;
}
*
* pseudo code --- this is what it should check
*
* if (yytext == type_name)
* return TYPE_NAME;
*
* return IDENTIFIER;
*
*
* it actually will only return IDENTIFIER
*
// return IDENTIFIER;
}*/
......@@ -320,7 +320,7 @@ declaration
| declaration_specifiers init_declarator_list ';' { $$ = $2;
for(tmpleaf = $2; tmpleaf != NULL; tmpleaf = tmpleaf->next) {
if ((tmpleaf->type != FUNCTION_DECLARATION) &&
(tmpleaf->type != FUNCTION_POINTER_DECLARATION) ){
(tmpleaf->type != FUNCTION_POINTER_DECLARATION)) {
tmpleaf->type = VARIABLE_DEFINITION;
}
mix_ast_leaves(tmpleaf,$1);
......@@ -570,7 +570,7 @@ direct_declarator
free_tree($2);
free_tree($4); }
| direct_declarator '(' identifier_list ')' { $$ = $1; show_error(__LINE__, $$); }
| direct_declarator '(' ')' { $$ = $1; // List of parameters in the definition of a function without parameters
| direct_declarator '(' ')' { $$ = $1; // Definition of a function without parameters
if (!$$->function) {
$$->type = FUNCTION_DECLARATION;
}
......@@ -845,7 +845,8 @@ iteration_statement
jump_statement
: GOTO IDENTIFIER ';' { $$ = $1;
$$->child1 = $2;
$$->name = strdup($2->data);
free_tree($2);
free_tree($3); }
| CONTINUE ';' { $$ = $1;
free_tree($2);}
......
......@@ -665,6 +665,9 @@ class Test(unittest.TestCase):
self._check_is_alias_of(lib, "alias1", "param1", 3)
self._check_is_alias_of(lib, "alias2", "param2", 3)
def test133GotoJumpsOverAll(self):
self._generic_test("unitest/test133.c", [ (crust.crust.MSG_ERROR, "Memory block '{:s}', initialized at line {:d}, is still in use at exit point at line {:d}", "param", 12, 21) ])
if __name__ == '__main__':
try:
os.remove("error_list.txt")
......
__crust_t__ struct t_crust_t {
int value;
__crust_t__ struct t_crust_t *next;
}
typedef struct t_crust_t *crust_t;
#define NULL ((void *)0)
void tmpfunc();
void main(crust_t param) {
goto END_TEST;
main(param); // this must not be called, because of the GOTO statement
END_TEST:
tmpfunc();
}
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