# HG changeset patch # User Mario de Sousa # Date 1334583667 -3600 # Node ID 9317e04c1dde7b9a62b6c490881dd61dcc92849d # Parent 35d391c38a30bffa89b39adbb07ffd3c3ddbc9d6 Fixing check for assignment to output variables. diff -r 35d391c38a30 -r 9317e04c1dde stage3/lvalue_check.cc --- a/stage3/lvalue_check.cc Sun Apr 15 19:56:33 2012 +0100 +++ b/stage3/lvalue_check.cc Mon Apr 16 14:41:07 2012 +0100 @@ -44,7 +44,7 @@ LAST_(symbol1,symbol2) ->last_line, LAST_(symbol1,symbol2) ->last_column);\ fprintf(stderr, __VA_ARGS__); \ fprintf(stderr, "\n"); \ - error_found = true; \ + error_count++; \ } \ } @@ -60,14 +60,14 @@ lvalue_check_c::lvalue_check_c(symbol_c *ignore) { - error_found = false; + error_count = 0; } lvalue_check_c::~lvalue_check_c(void) { } -int lvalue_check_c::get_error_found() { - return error_found; +int lvalue_check_c::get_error_count() { + return error_count; } @@ -84,18 +84,47 @@ } -/* fb_instance.var := ... is not valid if var is output (not input ??) variable */ -void lvalue_check_c::check_assignment_to_output(symbol_c * lvalue) { - symbol_c *type_id = search_varfb_instance_type->get_basetype_id(lvalue); - if (NULL != type_id) { - function_block_declaration_c *fb_decl = function_block_type_symtable.find_value(type_id); - if (function_block_type_symtable.end_value() != fb_decl) { - search_var_instance_decl_c search_var_instance_decl(fb_decl); - structured_variable_c * str_var = (structured_variable_c *)lvalue; - unsigned int vartype = search_var_instance_decl.get_vartype(str_var->field_selector); - if (vartype == search_var_instance_decl_c::output_vt) - STAGE3_ERROR(0, lvalue, lvalue, "Assignment to FB output field variable is not be allowed."); +/* fb_instance.var := ... is not valid if var is output variable */ +/* NOTE, if a fb_instance1.fb_instance2.fb_instance3.var is used, we must iteratively check that none of the + * FB records are declared as OUTPUT variables!! + * This is the reason why we have the while() loop in this function! + */ +void lvalue_check_c::check_assignment_to_output(symbol_c *lvalue) { + decompose_var_instance_name_c decompose_lvalue(lvalue); + search_base_type_c search_base_type; + + symbol_c *struct_elem = decompose_lvalue.next_part(); + symbol_c *type_decl = search_var_instance_decl->get_decl(struct_elem); + // symbol_c *type_id = spec_init_sperator_c::get_spec(type_decl); /* this is not required! search_base_type_c can handle spec_init symbols! */ + symbol_c *basetype_id = search_base_type.get_basetype_id(/*type_id*/ type_decl); + /* If we can not determine the data type of the element, then the code must have a data type semantic error. + * This will have been caught by the data type semantic verifier, so we do not bother with this anymore! + */ + if (NULL == basetype_id) return; + + /* Determine if the record/structure element is of a FB type. */ + /* NOTE: If the structure element is not a FB type, then we can quit this check. + * Remember that the standard does not allow a STRUCT data type to have elements that are FB instances! + * Similarly, arrays of FB instances is also not allowed. + * So, as soon as we find one record/structure element that is not a FB, no other record/structure element + * will be of FB type, which means we can quit this check! + */ + function_block_declaration_c *fb_decl = function_block_type_symtable.find_value(basetype_id); + if (function_block_type_symtable.end_value() == fb_decl) return; + + while (NULL != (struct_elem = decompose_lvalue.next_part())) { + search_var_instance_decl_c fb_search_var_instance_decl(fb_decl); + if (search_var_instance_decl_c::output_vt == fb_search_var_instance_decl.get_vartype(struct_elem)) { + STAGE3_ERROR(0, struct_elem, struct_elem, "Assignment to FB output variable is not allowed."); + return; /* no need to carry on checking once the first error is found! */ } + + /* prepare for any possible further record/structure elements */ + type_decl = fb_search_var_instance_decl.get_decl(struct_elem); + basetype_id = search_base_type.get_basetype_id(type_decl); + if (NULL == basetype_id) return; /* same comment as above... */ + fb_decl = function_block_type_symtable.find_value(basetype_id); + if (function_block_type_symtable.end_value() == fb_decl) return; /* same comment as above... */ } } @@ -113,17 +142,17 @@ void lvalue_check_c::check_assignment_to_expression(symbol_c *lvalue) { /* TODO: check whether the lvalue is an expresion! */ /* This may occur in function invocations, when passing values (possibly an expression) to one - * of the function's OUTPUT parameters. + * of the function's OUTPUT or IN_OUT parameters. */ } void lvalue_check_c::verify_is_lvalue(symbol_c *lvalue) { + check_assignment_to_expression(lvalue); check_assignment_to_controlvar(lvalue); check_assignment_to_output(lvalue); check_assignment_to_constant(lvalue); - check_assignment_to_expression(lvalue); } @@ -161,8 +190,7 @@ /* We only check if 'call_param_value' is a valid lvalue if the value is being passed * to a valid paramater of the function being called, and that parameter is either OUT or IN_OUT. */ - if ((param_name != NULL) && - ((function_param_iterator_c::direction_out == param_direction) || (function_param_iterator_c::direction_inout == param_direction))) { + if ((param_name != NULL) && ((function_param_iterator_c::direction_out == param_direction) || (function_param_iterator_c::direction_inout == param_direction))) { verify_is_lvalue(call_param_value); } } @@ -227,10 +255,8 @@ /***********************/ // SYM_REF3(function_invocation_c, function_name, formal_param_list, nonformal_param_list, symbol_c *called_function_declaration; int extensible_param_count; std::vector candidate_functions;) void *lvalue_check_c::visit(function_invocation_c *symbol) { - if (NULL != symbol->formal_param_list) - check_formal_call(symbol, symbol->called_function_declaration); - if (NULL != symbol->nonformal_param_list) - check_nonformal_call(symbol, symbol->called_function_declaration); + if (NULL != symbol->formal_param_list ) check_formal_call (symbol, symbol->called_function_declaration); + if (NULL != symbol->nonformal_param_list) check_nonformal_call(symbol, symbol->called_function_declaration); return NULL; } diff -r 35d391c38a30 -r 9317e04c1dde stage3/lvalue_check.hh --- a/stage3/lvalue_check.hh Sun Apr 15 19:56:33 2012 +0100 +++ b/stage3/lvalue_check.hh Mon Apr 16 14:41:07 2012 +0100 @@ -47,7 +47,7 @@ search_varfb_instance_type_c *search_varfb_instance_type; search_var_instance_decl_c *search_var_instance_decl; search_base_type_c search_base_type; - int error_found; + int error_count; int current_display_error_level; std::vector control_variables; @@ -63,7 +63,7 @@ public: lvalue_check_c(symbol_c *ignore); virtual ~lvalue_check_c(void); - int get_error_found(); + int get_error_count(); /**************************************/ /* B 1.5 - Program organisation units */ diff -r 35d391c38a30 -r 9317e04c1dde stage3/print_datatypes_error.cc --- a/stage3/print_datatypes_error.cc Sun Apr 15 19:56:33 2012 +0100 +++ b/stage3/print_datatypes_error.cc Mon Apr 16 14:41:07 2012 +0100 @@ -61,7 +61,7 @@ fprintf(stderr, __VA_ARGS__); \ fprintf(stderr, "\n"); \ il_error = true; \ - error_found = true; \ + error_count++; \ } \ } @@ -80,7 +80,7 @@ static int debug = 0; print_datatypes_error_c::print_datatypes_error_c(symbol_c *ignore) { - error_found = false; + error_count = 0; warning_found = false; current_display_error_level = error_level_default; } @@ -88,8 +88,8 @@ print_datatypes_error_c::~print_datatypes_error_c(void) { } -int print_datatypes_error_c::get_error_found() { - return error_found; +int print_datatypes_error_c::get_error_count() { + return error_count; } diff -r 35d391c38a30 -r 9317e04c1dde stage3/print_datatypes_error.hh --- a/stage3/print_datatypes_error.hh Sun Apr 15 19:56:33 2012 +0100 +++ b/stage3/print_datatypes_error.hh Mon Apr 16 14:41:07 2012 +0100 @@ -73,7 +73,7 @@ */ int il_parenthesis_level; bool il_error; - bool error_found; + int error_count; bool warning_found; /* the current data type of the data stored in the IL stack, i.e. the default variable */ @@ -99,7 +99,7 @@ public: print_datatypes_error_c(symbol_c *ignore); virtual ~print_datatypes_error_c(void); - int get_error_found(); + int get_error_count(); /*********************/ diff -r 35d391c38a30 -r 9317e04c1dde stage3/stage3.cc --- a/stage3/stage3.cc Sun Apr 15 19:56:33 2012 +0100 +++ b/stage3/stage3.cc Mon Apr 16 14:41:07 2012 +0100 @@ -56,18 +56,29 @@ tree_root->accept(narrow_candidate_datatypes); print_datatypes_error_c print_datatypes_error(tree_root); tree_root->accept(print_datatypes_error); - if (print_datatypes_error.get_error_found()) - return -1; - lvalue_check_c lvalue_check(tree_root); - tree_root->accept(lvalue_check); - if (lvalue_check.get_error_found()) - return -1; - return 0; + return print_datatypes_error.get_error_count(); } +/* Type safety analysis assumes that flow control analysis has already been completed, + * so be sure to call flow_control_analysis() before calling this function + */ +static int lvalue_check(symbol_c *tree_root){ + lvalue_check_c lvalue_check(tree_root); + tree_root->accept(lvalue_check); + return lvalue_check.get_error_count(); +} + int stage3(symbol_c *tree_root){ - flow_control_analysis(tree_root); - return type_safety(tree_root); + int error_count = 0; + error_count += flow_control_analysis(tree_root); + error_count += type_safety(tree_root); + error_count += lvalue_check(tree_root); + + if (error_count > 0) { + fprintf(stderr, "%d errors found. Bailing out!\n", error_count); + return -1; + } + return 0; }