--- 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 <set>
+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<symbol_c *> 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<symbol_c *> 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;
}