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 |