stage3/declaration_check.cc
changeset 892 54d5d185d6e2
parent 865 7365c3e5c9ae
child 963 e3d4dca7520b
equal deleted inserted replaced
891:58109ca87903 892:54d5d185d6e2
    68     fprintf(stderr, "\n");                                                                                                  \
    68     fprintf(stderr, "\n");                                                                                                  \
    69     warning_found = true;                                                                                                   \
    69     warning_found = true;                                                                                                   \
    70 }
    70 }
    71 
    71 
    72 
    72 
       
    73 
       
    74 
       
    75 
       
    76 
       
    77 
       
    78 
       
    79 
       
    80 #include <set>
       
    81 class check_extern_c: public iterator_visitor_c {
       
    82   public:
       
    83   
       
    84   private:
       
    85     int current_display_error_level;
       
    86     symbol_c *current_pou_decl;
       
    87     symbol_c *current_resource_decl;
       
    88     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!
       
    89   
       
    90   
       
    91   public:
       
    92     static int error_count;
       
    93     
       
    94     check_extern_c(symbol_c *current_pou, symbol_c *current_resource) {
       
    95       current_display_error_level = 0;
       
    96       current_pou_decl      = current_pou;
       
    97       current_resource_decl = current_resource;
       
    98     }
       
    99         
       
   100     ~check_extern_c(void) {}
       
   101     
       
   102     
       
   103     
       
   104     void check_global_decl(symbol_c *p_decl) {
       
   105       if (NULL == current_pou_decl) ERROR;
       
   106       
       
   107       if (checked_decl.find(p_decl) != checked_decl.end()) return; // has already been checked!
       
   108       checked_decl.insert(p_decl);
       
   109 
       
   110       search_var_instance_decl_c search_var_instance_pou_glo_decl(current_pou_decl);
       
   111       search_var_instance_decl_c search_var_instance_res_glo_decl(current_resource_decl);
       
   112       search_var_instance_decl_c search_var_instance_ext_decl(p_decl);
       
   113       function_param_iterator_c  fpi(p_decl);
       
   114       
       
   115       symbol_c *var_name;
       
   116       while((var_name = fpi.next()) != NULL) {            
       
   117         if (fpi.param_direction() == function_param_iterator_c::direction_extref) {
       
   118           /* found an external reference parameter. */
       
   119           symbol_c *ext_decl = search_var_instance_ext_decl.get_decl(var_name);
       
   120           
       
   121           // NOTE: Must check the POU first, and RESOURCE second!
       
   122           symbol_c                                       *glo_decl =  search_var_instance_res_glo_decl.get_decl(var_name);           
       
   123               search_var_instance_decl_c *search_var_instance_glo_decl = &search_var_instance_res_glo_decl;
       
   124           if (NULL == glo_decl) {
       
   125             glo_decl                     =  search_var_instance_pou_glo_decl.get_decl(var_name);
       
   126             search_var_instance_glo_decl = &search_var_instance_pou_glo_decl;
       
   127           }
       
   128           
       
   129           if (NULL == glo_decl) {
       
   130             STAGE3_ERROR(0, ext_decl, ext_decl, "Declaration error. The external variable does not match with any global variable.");
       
   131             continue;
       
   132           }
       
   133     
       
   134           /* Check whether variable's constness (CONSTANT) is compatible.
       
   135            *        VAR_GLOBAL is contant     => VAR_EXTERNAL must also be CONSTANT
       
   136            *        VAR_GLOBAL is not contant => VAR_EXTERNAL may be CONSTANT, or not!
       
   137            */
       
   138           search_var_instance_decl_c::opt_t ext_opt = search_var_instance_ext_decl. get_option(var_name);
       
   139           search_var_instance_decl_c::opt_t glo_opt = search_var_instance_glo_decl->get_option(var_name);
       
   140           if ((glo_opt == search_var_instance_decl_c::constant_opt) && (ext_opt != search_var_instance_decl_c::constant_opt))
       
   141             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.");
       
   142     
       
   143           /* TODO: Check redefinition data type.
       
   144            *       We need a new class (like search_base_type class) to get type id by variable declaration.
       
   145            *  symbol_c *glo_type = ????;
       
   146            *  symbol_c *ext_type = fpi.param_type();
       
   147            */
       
   148           /* For the moment, we will just use search_base_type_c instead... */
       
   149           symbol_c *glo_type = search_base_type_c::get_basetype_decl(glo_decl);
       
   150           symbol_c *ext_type = search_base_type_c::get_basetype_decl(ext_decl);
       
   151           if (! get_datatype_info_c::is_type_equal(glo_type, ext_type))
       
   152             STAGE3_ERROR(0, ext_decl, ext_decl, "Declaration error.  Data type mismatch between external and global variable declarations.");
       
   153         }
       
   154       }
       
   155     }
       
   156     
       
   157     
       
   158     
       
   159     /********************************/
       
   160     /* B 1.3.3 - Derived data types */
       
   161     /********************************/
       
   162     /*  function_block_type_name ASSIGN structure_initialization */
       
   163     /* structure_initialization -> may be NULL ! */
       
   164     //SYM_REF2(fb_spec_init_c, function_block_type_name, structure_initialization)
       
   165     /* NOTE: This class is only used when declaring FB variables, as in:
       
   166      * name_list ':' function_block_type_name ASSIGN structure_initialization
       
   167      *               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
       
   168      *                      fb_spec_init_c                                   
       
   169      * Here, fb_spec_init_c is used whether it is an external, local, or global variable!
       
   170      * Note too that we must also check the datatypes of external and global variables!! 
       
   171      */
       
   172     void *visit(fb_spec_init_c *symbol) {
       
   173       symbol_c *fb_decl = function_block_type_symtable.find_value(symbol->function_block_type_name);
       
   174       /* stage1_2 guarantees that we are sure to find a declaration in FB or Program symtable. */
       
   175       if (fb_decl == function_block_type_symtable.end_value())
       
   176         ERROR;
       
   177       fb_decl->accept(*this);
       
   178       return NULL;
       
   179     }
       
   180     
       
   181     /*****************************/
       
   182     /* B 1.5.2 - Function Blocks */
       
   183     /*****************************/
       
   184     /*  FUNCTION_BLOCK derived_function_block_name io_OR_other_var_declarations function_block_body END_FUNCTION_BLOCK */
       
   185     // SYM_REF3(function_block_declaration_c, fblock_name, var_declarations, fblock_body)
       
   186     void *visit(function_block_declaration_c *symbol) {
       
   187       check_global_decl(symbol);
       
   188       /* The following two lines of code are only valid for v3 of IEC 61131-3, that allows VAR_GLOBAL declarations inside FBs!
       
   189        * current_pou_decl = symbol;  
       
   190        * current_resource_decl = NULL;  
       
   191        */
       
   192       /* check if any FB declared as a VAR has any incompatible VAR_EXTERNAL declarations */
       
   193       if (NULL != symbol->var_declarations)
       
   194         symbol->var_declarations->accept(*this);  // This will eventually call the visit(fb_spec_init_c *) method, if any FB are declared here!
       
   195       return NULL;
       
   196     }
       
   197     
       
   198     /******************************************/
       
   199     /* B 1.5.3 - Declaration & Initialisation */
       
   200     /******************************************/
       
   201     /*  PROGRAM program_type_name program_var_declarations_list function_block_body END_PROGRAM */
       
   202     // SYM_REF3(program_declaration_c, program_type_name, var_declarations, function_block_body)
       
   203     void *visit(program_declaration_c *symbol) {
       
   204       check_global_decl(symbol);
       
   205       /* The following two lines of code are only valid for v3 of IEC 61131-3, that allows VAR_GLOBAL declarations inside PROGRAMs!
       
   206        * current_pou_decl = symbol;  
       
   207        * current_resource_decl = NULL;  
       
   208        */
       
   209       /* check if any FB declared as a VAR has any incompatible VAR_EXTERNAL declarations */
       
   210       if (NULL != symbol->var_declarations)
       
   211         symbol->var_declarations->accept(*this);  // This will eventually call the visit(fb_spec_init_c *) method, if any FB are declared here!
       
   212       return NULL;
       
   213     }
       
   214     
       
   215 };
       
   216 
       
   217 int check_extern_c::error_count = 0;
       
   218 std::set<symbol_c *> check_extern_c::checked_decl;
       
   219 
       
   220 
       
   221 
       
   222 
       
   223 
       
   224 
       
   225 
       
   226 
       
   227 
       
   228 
    73 declaration_check_c::declaration_check_c(symbol_c *ignore) {
   229 declaration_check_c::declaration_check_c(symbol_c *ignore) {
    74   current_display_error_level = 0;
   230   current_display_error_level = 0;
    75   current_pou_decl = NULL;
   231   current_pou_decl = NULL;
    76   current_resource_decl = NULL;
   232   current_resource_decl = NULL;
    77   error_count = 0;
   233   error_count = 0;
    80 declaration_check_c::~declaration_check_c(void) {
   236 declaration_check_c::~declaration_check_c(void) {
    81 
   237 
    82 }
   238 }
    83 
   239 
    84 int declaration_check_c::get_error_count() {
   240 int declaration_check_c::get_error_count() {
    85   return error_count;
   241   return check_extern_c::error_count;
    86 }
   242 }
    87 
       
    88 void declaration_check_c::check_global_decl(symbol_c *p_decl) {
       
    89   if (NULL == current_pou_decl) ERROR;
       
    90   
       
    91   search_var_instance_decl_c search_var_instance_pou_glo_decl(current_pou_decl);
       
    92   search_var_instance_decl_c search_var_instance_res_glo_decl(current_resource_decl);
       
    93   search_var_instance_decl_c search_var_instance_ext_decl(p_decl);
       
    94   function_param_iterator_c  fpi(p_decl);
       
    95   
       
    96   symbol_c *var_name;
       
    97   while((var_name = fpi.next()) != NULL) {
       
    98     if (fpi.param_direction() == function_param_iterator_c::direction_extref) {
       
    99       /* found an external reference parameter. */
       
   100       symbol_c *ext_decl = search_var_instance_ext_decl.get_decl(var_name);
       
   101       
       
   102       // NOTE: Must check the POU first, and RESOURCE second!
       
   103       symbol_c                                       *glo_decl =  search_var_instance_res_glo_decl.get_decl(var_name);           
       
   104       search_var_instance_decl_c *search_var_instance_glo_decl = &search_var_instance_res_glo_decl;
       
   105       if (NULL == glo_decl) {
       
   106         glo_decl                     =  search_var_instance_pou_glo_decl.get_decl(var_name);
       
   107         search_var_instance_glo_decl = &search_var_instance_pou_glo_decl;
       
   108       }
       
   109       
       
   110       if (NULL == glo_decl) {
       
   111         STAGE3_ERROR(0, ext_decl, ext_decl, "Declaration error. The external variable does not match with any global variable.");
       
   112         continue;
       
   113       }
       
   114       
       
   115       /* Check whether variable's constness (CONSTANT) is compatible.
       
   116        *        VAR_GLOBAL is contant     => VAR_EXTERNAL must also be CONSTANT
       
   117        *        VAR_GLOBAL is not contant => VAR_EXTERNAL may be CONSTANT, or not!
       
   118        */
       
   119       search_var_instance_decl_c::opt_t ext_opt = search_var_instance_ext_decl. get_option(var_name);
       
   120       search_var_instance_decl_c::opt_t glo_opt = search_var_instance_glo_decl->get_option(var_name);
       
   121       if ((glo_opt == search_var_instance_decl_c::constant_opt) && (ext_opt != search_var_instance_decl_c::constant_opt))
       
   122         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.");
       
   123 
       
   124       /* TODO: Check redefinition data type.
       
   125        *       We need a new class (like search_base_type class) to get type id by variable declaration.
       
   126        *  symbol_c *glo_type = ????;
       
   127        *  symbol_c *ext_type = fpi.param_type();
       
   128        */
       
   129       /* For the moment, we will just use search_base_type_c instead... */
       
   130       symbol_c *glo_type = search_base_type_c::get_basetype_decl(glo_decl);
       
   131       symbol_c *ext_type = search_base_type_c::get_basetype_decl(ext_decl);
       
   132       if (! get_datatype_info_c::is_type_equal(glo_type, ext_type))
       
   133         STAGE3_ERROR(0, ext_decl, ext_decl, "Declaration error.  Data type mismatch between external and global variable declarations.");
       
   134     }
       
   135   }
       
   136 }
       
   137 
       
   138 
       
   139 
   243 
   140 /*****************************/
   244 /*****************************/
   141 /* B 1.5.2 - Function Blocks */
   245 /* B 1.5.2 - Function Blocks */
   142 /*****************************/
   246 /*****************************/
   143 /*  FUNCTION_BLOCK derived_function_block_name io_OR_other_var_declarations function_block_body END_FUNCTION_BLOCK */
   247 /*  FUNCTION_BLOCK derived_function_block_name io_OR_other_var_declarations function_block_body END_FUNCTION_BLOCK */
   144 // SYM_REF3(function_block_declaration_c, fblock_name, var_declarations, fblock_body)
   248 // SYM_REF3(function_block_declaration_c, fblock_name, var_declarations, fblock_body)
   145 void *declaration_check_c::visit(function_block_declaration_c *symbol) {
   249 void *declaration_check_c::visit(function_block_declaration_c *symbol)
   146   /* The following two lines of code are only valid for v3 of IEC 61131-3, that allows VAR_GLOBAL declarations inside FBs!
   250   {return NULL;} // We only check the declarations that are used to instantiate variables. This is done in the configuration!
   147    * current_pou_decl = symbol;  
       
   148    * current_resource_decl = NULL;  
       
   149    */
       
   150   /* check if any FB declared as a VAR has any incompatible VAR_EXTERNAL declarations */
       
   151   if (NULL != symbol->var_declarations)
       
   152     symbol->var_declarations->accept(*this);
       
   153   return NULL;
       
   154 }
       
   155 
   251 
   156 /******************************************/
   252 /******************************************/
   157 /* B 1.5.3 - Declaration & Initialisation */
   253 /* B 1.5.3 - Declaration & Initialisation */
   158 /******************************************/
   254 /******************************************/
   159 /*  PROGRAM program_type_name program_var_declarations_list function_block_body END_PROGRAM */
   255 /*  PROGRAM program_type_name program_var_declarations_list function_block_body END_PROGRAM */
   160 // SYM_REF3(program_declaration_c, program_type_name, var_declarations, function_block_body)
   256 // SYM_REF3(program_declaration_c, program_type_name, var_declarations, function_block_body)
   161 void *declaration_check_c::visit(program_declaration_c *symbol) {
   257 void *declaration_check_c::visit(program_declaration_c *symbol) 
   162   /* The following two lines of code are only valid for v3 of IEC 61131-3, that allows VAR_GLOBAL declarations inside PROGRAMs!
   258   {return NULL;} // We only check the declarations that are used to instantiate variables. This is done in the configuration!
   163    * current_pou_decl = symbol;  
   259 
   164    * current_resource_decl = NULL;  
   260 
   165    */
       
   166   /* check if any FB declared as a VAR has any incompatible VAR_EXTERNAL declarations */
       
   167   if (NULL != symbol->var_declarations)
       
   168     symbol->var_declarations->accept(*this);
       
   169   return NULL;
       
   170 }
       
   171 
   261 
   172 /********************************/
   262 /********************************/
   173 /* B 1.7 Configuration elements */
   263 /* B 1.7 Configuration elements */
   174 /********************************/
   264 /********************************/
   175 /*
   265 /*
   197 END_RESOURCE
   287 END_RESOURCE
   198 */
   288 */
   199 /* 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 */
   289 /* 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 */
   200 // SYM_REF4(resource_declaration_c, resource_name, resource_type_name, global_var_declarations, resource_declaration, enumvalue_symtable_t enumvalue_symtable;)
   290 // SYM_REF4(resource_declaration_c, resource_name, resource_type_name, global_var_declarations, resource_declaration, enumvalue_symtable_t enumvalue_symtable;)
   201 void *declaration_check_c::visit(resource_declaration_c *symbol) {
   291 void *declaration_check_c::visit(resource_declaration_c *symbol) {
       
   292   // check if any FB instantiated inside this resource (in a VAR_GLOBAL) has any VAR_EXTERNAL declarations incompatible with the configuration's VAR_GLOBALs
       
   293   check_extern_c check_extern(current_pou_decl, current_resource_decl);
       
   294   symbol->global_var_declarations->accept(check_extern);   
       
   295   // Now check the Programs instantiated in this resource
   202   current_resource_decl = symbol;
   296   current_resource_decl = symbol;
   203   /* check if any FB declared as a VAR has any incompatible VAR_EXTERNAL declarations */
       
   204   symbol->resource_declaration->accept(*this);
   297   symbol->resource_declaration->accept(*this);
   205   current_resource_decl = NULL;  
   298   current_resource_decl = NULL;  
   206   return NULL;
   299   return NULL;
   207 }
   300 }
   208 
   301 
   209 /*  PROGRAM [RETAIN | NON_RETAIN] program_name [WITH task_name] ':' program_type_name ['(' prog_conf_elements ')'] */
   302 /*  PROGRAM [RETAIN | NON_RETAIN] program_name [WITH task_name] ':' program_type_name ['(' prog_conf_elements ')'] */
   210 void *declaration_check_c::visit(program_configuration_c *symbol) {
   303 void *declaration_check_c::visit(program_configuration_c *symbol) {
   211   symbol_c *p_decl = program_type_symtable.find_value(symbol->program_type_name);
   304   symbol_c *p_decl = program_type_symtable.find_value(symbol->program_type_name);
   212   if (p_decl == program_type_symtable.end_value())
   305   if (p_decl == program_type_symtable.end_value())
   213     p_decl = function_block_type_symtable.find_value(symbol->program_type_name);
   306     p_decl = function_block_type_symtable.find_value(symbol->program_type_name);
   214   /* stage1_2 guarantees that we are sure to find a declaration in FB or Program symtable. */
       
   215   if (p_decl == function_block_type_symtable.end_value())
   307   if (p_decl == function_block_type_symtable.end_value())
   216     ERROR;
   308     ERROR;  // Should never occur! stage1_2 guarantees that we are sure to find a declaration in FB or Program symtable.
   217   check_global_decl(p_decl);
   309   
       
   310   check_extern_c check_extern(current_pou_decl, current_resource_decl);
       
   311   p_decl->accept(check_extern);
   218   return NULL;
   312   return NULL;
   219 }
   313 }
   220 
   314