# HG changeset patch # User mjsousa # Date 1400570759 -3600 # Node ID 54d5d185d6e2a993fb2c5a2386d80b2f05da2c76 # Parent 58109ca8790339c723c71daed472839b62bff0cc Check VAR_EXTERN variables declared in FBs instantiated in a Program (and recursively too - FBs in FBs). diff -r 58109ca87903 -r 54d5d185d6e2 stage3/declaration_check.cc --- a/stage3/declaration_check.cc Tue May 20 08:24:25 2014 +0100 +++ b/stage3/declaration_check.cc Tue May 20 08:25:59 2014 +0100 @@ -70,6 +70,162 @@ } + + + + + + + +#include +class check_extern_c: public iterator_visitor_c { + public: + + private: + int current_display_error_level; + symbol_c *current_pou_decl; + symbol_c *current_resource_decl; + static std::set checked_decl; // A set with all the declarations that have already been checked, so we don't recheck it again! + + + public: + static int error_count; + + check_extern_c(symbol_c *current_pou, symbol_c *current_resource) { + current_display_error_level = 0; + current_pou_decl = current_pou; + current_resource_decl = current_resource; + } + + ~check_extern_c(void) {} + + + + void check_global_decl(symbol_c *p_decl) { + if (NULL == current_pou_decl) ERROR; + + if (checked_decl.find(p_decl) != checked_decl.end()) return; // has already been checked! + checked_decl.insert(p_decl); + + search_var_instance_decl_c search_var_instance_pou_glo_decl(current_pou_decl); + search_var_instance_decl_c search_var_instance_res_glo_decl(current_resource_decl); + search_var_instance_decl_c search_var_instance_ext_decl(p_decl); + function_param_iterator_c fpi(p_decl); + + symbol_c *var_name; + while((var_name = fpi.next()) != NULL) { + if (fpi.param_direction() == function_param_iterator_c::direction_extref) { + /* found an external reference parameter. */ + symbol_c *ext_decl = search_var_instance_ext_decl.get_decl(var_name); + + // NOTE: Must check the POU first, and RESOURCE second! + symbol_c *glo_decl = search_var_instance_res_glo_decl.get_decl(var_name); + search_var_instance_decl_c *search_var_instance_glo_decl = &search_var_instance_res_glo_decl; + if (NULL == glo_decl) { + glo_decl = search_var_instance_pou_glo_decl.get_decl(var_name); + search_var_instance_glo_decl = &search_var_instance_pou_glo_decl; + } + + if (NULL == glo_decl) { + STAGE3_ERROR(0, ext_decl, ext_decl, "Declaration error. The external variable does not match with any global variable."); + continue; + } + + /* Check whether variable's constness (CONSTANT) is compatible. + * VAR_GLOBAL is contant => VAR_EXTERNAL must also be CONSTANT + * VAR_GLOBAL is not contant => VAR_EXTERNAL may be CONSTANT, or not! + */ + search_var_instance_decl_c::opt_t ext_opt = search_var_instance_ext_decl. get_option(var_name); + search_var_instance_decl_c::opt_t glo_opt = search_var_instance_glo_decl->get_option(var_name); + if ((glo_opt == search_var_instance_decl_c::constant_opt) && (ext_opt != search_var_instance_decl_c::constant_opt)) + STAGE3_ERROR(0, glo_decl, glo_decl, "Declaration error. The external variable must be declared as constant, as it maps to a constant global variable."); + + /* TODO: Check redefinition data type. + * We need a new class (like search_base_type class) to get type id by variable declaration. + * symbol_c *glo_type = ????; + * symbol_c *ext_type = fpi.param_type(); + */ + /* For the moment, we will just use search_base_type_c instead... */ + symbol_c *glo_type = search_base_type_c::get_basetype_decl(glo_decl); + symbol_c *ext_type = search_base_type_c::get_basetype_decl(ext_decl); + if (! get_datatype_info_c::is_type_equal(glo_type, ext_type)) + STAGE3_ERROR(0, ext_decl, ext_decl, "Declaration error. Data type mismatch between external and global variable declarations."); + } + } + } + + + + /********************************/ + /* B 1.3.3 - Derived data types */ + /********************************/ + /* function_block_type_name ASSIGN structure_initialization */ + /* structure_initialization -> may be NULL ! */ + //SYM_REF2(fb_spec_init_c, function_block_type_name, structure_initialization) + /* NOTE: This class is only used when declaring FB variables, as in: + * name_list ':' function_block_type_name ASSIGN structure_initialization + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + * fb_spec_init_c + * Here, fb_spec_init_c is used whether it is an external, local, or global variable! + * Note too that we must also check the datatypes of external and global variables!! + */ + void *visit(fb_spec_init_c *symbol) { + symbol_c *fb_decl = function_block_type_symtable.find_value(symbol->function_block_type_name); + /* stage1_2 guarantees that we are sure to find a declaration in FB or Program symtable. */ + if (fb_decl == function_block_type_symtable.end_value()) + ERROR; + fb_decl->accept(*this); + return NULL; + } + + /*****************************/ + /* B 1.5.2 - Function Blocks */ + /*****************************/ + /* FUNCTION_BLOCK derived_function_block_name io_OR_other_var_declarations function_block_body END_FUNCTION_BLOCK */ + // SYM_REF3(function_block_declaration_c, fblock_name, var_declarations, fblock_body) + void *visit(function_block_declaration_c *symbol) { + check_global_decl(symbol); + /* The following two lines of code are only valid for v3 of IEC 61131-3, that allows VAR_GLOBAL declarations inside FBs! + * current_pou_decl = symbol; + * current_resource_decl = NULL; + */ + /* check if any FB declared as a VAR has any incompatible VAR_EXTERNAL declarations */ + if (NULL != symbol->var_declarations) + symbol->var_declarations->accept(*this); // This will eventually call the visit(fb_spec_init_c *) method, if any FB are declared here! + return NULL; + } + + /******************************************/ + /* B 1.5.3 - Declaration & Initialisation */ + /******************************************/ + /* PROGRAM program_type_name program_var_declarations_list function_block_body END_PROGRAM */ + // SYM_REF3(program_declaration_c, program_type_name, var_declarations, function_block_body) + void *visit(program_declaration_c *symbol) { + check_global_decl(symbol); + /* The following two lines of code are only valid for v3 of IEC 61131-3, that allows VAR_GLOBAL declarations inside PROGRAMs! + * current_pou_decl = symbol; + * current_resource_decl = NULL; + */ + /* check if any FB declared as a VAR has any incompatible VAR_EXTERNAL declarations */ + if (NULL != symbol->var_declarations) + symbol->var_declarations->accept(*this); // This will eventually call the visit(fb_spec_init_c *) method, if any FB are declared here! + return NULL; + } + +}; + +int check_extern_c::error_count = 0; +std::set check_extern_c::checked_decl; + + + + + + + + + + declaration_check_c::declaration_check_c(symbol_c *ignore) { current_display_error_level = 0; current_pou_decl = NULL; @@ -82,92 +238,26 @@ } int declaration_check_c::get_error_count() { - return error_count; -} - -void declaration_check_c::check_global_decl(symbol_c *p_decl) { - if (NULL == current_pou_decl) ERROR; - - search_var_instance_decl_c search_var_instance_pou_glo_decl(current_pou_decl); - search_var_instance_decl_c search_var_instance_res_glo_decl(current_resource_decl); - search_var_instance_decl_c search_var_instance_ext_decl(p_decl); - function_param_iterator_c fpi(p_decl); - - symbol_c *var_name; - while((var_name = fpi.next()) != NULL) { - if (fpi.param_direction() == function_param_iterator_c::direction_extref) { - /* found an external reference parameter. */ - symbol_c *ext_decl = search_var_instance_ext_decl.get_decl(var_name); - - // NOTE: Must check the POU first, and RESOURCE second! - symbol_c *glo_decl = search_var_instance_res_glo_decl.get_decl(var_name); - search_var_instance_decl_c *search_var_instance_glo_decl = &search_var_instance_res_glo_decl; - if (NULL == glo_decl) { - glo_decl = search_var_instance_pou_glo_decl.get_decl(var_name); - search_var_instance_glo_decl = &search_var_instance_pou_glo_decl; - } - - if (NULL == glo_decl) { - STAGE3_ERROR(0, ext_decl, ext_decl, "Declaration error. The external variable does not match with any global variable."); - continue; - } - - /* Check whether variable's constness (CONSTANT) is compatible. - * VAR_GLOBAL is contant => VAR_EXTERNAL must also be CONSTANT - * VAR_GLOBAL is not contant => VAR_EXTERNAL may be CONSTANT, or not! - */ - search_var_instance_decl_c::opt_t ext_opt = search_var_instance_ext_decl. get_option(var_name); - search_var_instance_decl_c::opt_t glo_opt = search_var_instance_glo_decl->get_option(var_name); - if ((glo_opt == search_var_instance_decl_c::constant_opt) && (ext_opt != search_var_instance_decl_c::constant_opt)) - STAGE3_ERROR(0, glo_decl, glo_decl, "Declaration error. The external variable must be declared as constant, as it maps to a constant global variable."); - - /* TODO: Check redefinition data type. - * We need a new class (like search_base_type class) to get type id by variable declaration. - * symbol_c *glo_type = ????; - * symbol_c *ext_type = fpi.param_type(); - */ - /* For the moment, we will just use search_base_type_c instead... */ - symbol_c *glo_type = search_base_type_c::get_basetype_decl(glo_decl); - symbol_c *ext_type = search_base_type_c::get_basetype_decl(ext_decl); - if (! get_datatype_info_c::is_type_equal(glo_type, ext_type)) - STAGE3_ERROR(0, ext_decl, ext_decl, "Declaration error. Data type mismatch between external and global variable declarations."); - } - } -} - - + return check_extern_c::error_count; +} /*****************************/ /* B 1.5.2 - Function Blocks */ /*****************************/ /* FUNCTION_BLOCK derived_function_block_name io_OR_other_var_declarations function_block_body END_FUNCTION_BLOCK */ // SYM_REF3(function_block_declaration_c, fblock_name, var_declarations, fblock_body) -void *declaration_check_c::visit(function_block_declaration_c *symbol) { - /* The following two lines of code are only valid for v3 of IEC 61131-3, that allows VAR_GLOBAL declarations inside FBs! - * current_pou_decl = symbol; - * current_resource_decl = NULL; - */ - /* check if any FB declared as a VAR has any incompatible VAR_EXTERNAL declarations */ - if (NULL != symbol->var_declarations) - symbol->var_declarations->accept(*this); - return NULL; -} +void *declaration_check_c::visit(function_block_declaration_c *symbol) + {return NULL;} // We only check the declarations that are used to instantiate variables. This is done in the configuration! /******************************************/ /* B 1.5.3 - Declaration & Initialisation */ /******************************************/ /* PROGRAM program_type_name program_var_declarations_list function_block_body END_PROGRAM */ // SYM_REF3(program_declaration_c, program_type_name, var_declarations, function_block_body) -void *declaration_check_c::visit(program_declaration_c *symbol) { - /* The following two lines of code are only valid for v3 of IEC 61131-3, that allows VAR_GLOBAL declarations inside PROGRAMs! - * current_pou_decl = symbol; - * current_resource_decl = NULL; - */ - /* check if any FB declared as a VAR has any incompatible VAR_EXTERNAL declarations */ - if (NULL != symbol->var_declarations) - symbol->var_declarations->accept(*this); - return NULL; -} +void *declaration_check_c::visit(program_declaration_c *symbol) + {return NULL;} // We only check the declarations that are used to instantiate variables. This is done in the configuration! + + /********************************/ /* B 1.7 Configuration elements */ @@ -199,8 +289,11 @@ /* enumvalue_symtable is filled in by enum_declaration_check_c, during stage3 semantic verification, with a list of all enumerated constants declared inside this POU */ // SYM_REF4(resource_declaration_c, resource_name, resource_type_name, global_var_declarations, resource_declaration, enumvalue_symtable_t enumvalue_symtable;) void *declaration_check_c::visit(resource_declaration_c *symbol) { + // check if any FB instantiated inside this resource (in a VAR_GLOBAL) has any VAR_EXTERNAL declarations incompatible with the configuration's VAR_GLOBALs + check_extern_c check_extern(current_pou_decl, current_resource_decl); + symbol->global_var_declarations->accept(check_extern); + // Now check the Programs instantiated in this resource current_resource_decl = symbol; - /* check if any FB declared as a VAR has any incompatible VAR_EXTERNAL declarations */ symbol->resource_declaration->accept(*this); current_resource_decl = NULL; return NULL; @@ -211,10 +304,11 @@ symbol_c *p_decl = program_type_symtable.find_value(symbol->program_type_name); if (p_decl == program_type_symtable.end_value()) p_decl = function_block_type_symtable.find_value(symbol->program_type_name); - /* stage1_2 guarantees that we are sure to find a declaration in FB or Program symtable. */ if (p_decl == function_block_type_symtable.end_value()) - ERROR; - check_global_decl(p_decl); + ERROR; // Should never occur! stage1_2 guarantees that we are sure to find a declaration in FB or Program symtable. + + check_extern_c check_extern(current_pou_decl, current_resource_decl); + p_decl->accept(check_extern); return NULL; }