Fix datatype analysis of structured variables that contain arrays in their fields (e.g. var.x1[var2 + 42].y1).
authormjsousa
Wed, 07 Aug 2013 10:18:29 +0100
changeset 827 e3800aff352c
parent 826 1e6bf9839ece
child 828 a5f08df62002
Fix datatype analysis of structured variables that contain arrays in their fields (e.g. var.x1[var2 + 42].y1).
stage3/fill_candidate_datatypes.cc
stage3/narrow_candidate_datatypes.cc
stage3/narrow_candidate_datatypes.hh
stage3/print_datatypes_error.cc
--- a/stage3/fill_candidate_datatypes.cc	Mon Aug 05 15:57:00 2013 +0100
+++ b/stage3/fill_candidate_datatypes.cc	Wed Aug 07 10:18:29 2013 +0100
@@ -1112,12 +1112,29 @@
 	/* if we were to want the data type of the array itself, then we should call_param_name
 	 * search_varfb_instance_type->get_basetype_decl(symbol->subscripted_variable)
 	 */
-	symbol_c *result = search_varfb_instance_type->get_basetype_decl(symbol);
-	if (NULL != result) add_datatype_to_candidate_list(symbol, result);
+	add_datatype_to_candidate_list(symbol, search_varfb_instance_type->get_basetype_decl(symbol));   /* will only add if non NULL */
 	
 	/* recursively call the subscript list, so we can check the data types of the expressions used for the subscripts */
 	symbol->subscript_list->accept(*this);
 
+	/* recursively call the subscripted_variable. We need to do this since the array variable may be stored inside a structured
+	 * variable (i.e. if it is an element inside a struct), in which case we want to recursively visit every element of the struct,
+	 * as it may contain more arrays whose subscripts must also be visited!
+	 * e.g.   structvar.a1[v1+2].b1.c1[v2+3].d1
+	 *        TYPE
+	 *           d_s: STRUCT d1: int; d2: int;
+	 *           d_a: ARRAY [1..3] OF d_s;  
+	 *           c_s: STRUCT c1: d_a; c2: d_a;
+	 *           b_s: STRUCT b1: c_s; b2: c_s;
+	 *           b_a: ARRAY [1..3] OF b_s;  
+	 *           a_s: STRUCT a1: b_a; a2: b_a;
+	 *        END_TYPE 
+	 *        VAR
+	 *          structvar: a_s;
+	 *        END_VAR
+	 */
+	symbol->subscripted_variable->accept(*this);
+
 	if (debug) std::cout << "ARRAY_VAR [" << symbol->candidate_datatypes.size() << "]\n";	
 	return NULL;
 }
@@ -1136,11 +1153,18 @@
  *           this into account!
  */
 // SYM_REF2(structured_variable_c, record_variable, field_selector)
-/* NOTE: We do not need to recursively determine the data types of each field_selector, as the search_varfb_instance_type
- * will do that for us. So we determine the candidate datatypes only for the full structured_variable.
- */
 void *fill_candidate_datatypes_c::visit(structured_variable_c *symbol) {
+	/* NOTE: We do not need to recursively determine the data types of each field_selector, as the search_varfb_instance_type
+	 * will do that for us. So we determine the candidate datatypes only for the full structured_variable.
+	 */
 	add_datatype_to_candidate_list(symbol, search_varfb_instance_type->get_basetype_decl(symbol));  /* will only add if non NULL */
+	/* However, we do need to visit each record type recursively!
+	 * Remember that a structured variable may be stored inside an array (e.g. arrayvar[33].elem1)
+	 * The array subscripts may contain a complex expression (e.g. arrayvar[ varx + 33].elem1) whose datatype must be correctly determined!
+	 * The expression, may even contain a function call to an overloaded function!
+	 *      (e.g.  arrayvar[ varx + TRUNC(realvar)].elem1)
+	 */
+	symbol->record_variable->accept(*this);
 	return NULL;
 }
 
--- a/stage3/narrow_candidate_datatypes.cc	Mon Aug 05 15:57:00 2013 +0100
+++ b/stage3/narrow_candidate_datatypes.cc	Wed Aug 07 10:18:29 2013 +0100
@@ -662,6 +662,14 @@
 void *narrow_candidate_datatypes_c::visit(array_variable_c *symbol) {
 	/* we need to check the data types of the expressions used for the subscripts... */
 	symbol->subscript_list->accept(*this);
+
+	/* Set the datatype of the subscripted variable and visit it recursively. For the reason why we do this,                                                 */
+	/* Please read the comments in the array_variable_c and structured_variable_c visitors in the fill_candidate_datatypes.cc file! */
+	symbol->subscripted_variable->accept(*this); // visit recursively
+
+	if (symbol->subscripted_variable->candidate_datatypes.size() == 1)
+	  symbol->subscripted_variable->datatype = symbol->subscripted_variable->candidate_datatypes[0]; // set the datatype
+
 	return NULL;
 }
 
@@ -681,6 +689,24 @@
 
 
 
+/*  record_variable '.' field_selector */
+/*  WARNING: input and/or output variables of function blocks
+ *           may be accessed as fields of a structured variable!
+ *           Code handling a structured_variable_c must take
+ *           this into account!
+ */
+// SYM_REF2(structured_variable_c, record_variable, field_selector)
+void *narrow_candidate_datatypes_c::visit(structured_variable_c *symbol) {
+	/* Set the datatype of the record_variable and visit it recursively. For the reason why we do this,                                                      */
+	/* Please read the comments in the array_variable_c and structured_variable_c visitors in the fill_candidate_datatypes.cc file! */
+	symbol->record_variable->accept(*this); // visit recursively
+
+	if (symbol->record_variable->candidate_datatypes.size() == 1)
+	  symbol->record_variable->datatype = symbol->record_variable->candidate_datatypes[0]; // set the datatype
+
+	return NULL;
+}
+
 
 /******************************************/
 /* B 1.4.3 - Declaration & Initialisation */
--- a/stage3/narrow_candidate_datatypes.hh	Mon Aug 05 15:57:00 2013 +0100
+++ b/stage3/narrow_candidate_datatypes.hh	Wed Aug 07 10:18:29 2013 +0100
@@ -189,6 +189,7 @@
     /*************************************/
     void *visit(array_variable_c *symbol);
     void *visit(subscript_list_c *symbol);
+    void *visit(structured_variable_c *symbol);
 
     /******************************************/
     /* B 1.4.3 - Declaration & Initialisation */
--- a/stage3/print_datatypes_error.cc	Mon Aug 05 15:57:00 2013 +0100
+++ b/stage3/print_datatypes_error.cc	Wed Aug 07 10:18:29 2013 +0100
@@ -134,6 +134,10 @@
 	bool function_invocation_error = false;
 	const char *POU_str = NULL;
 
+debug_c::print("print_datatypes_error_c::handle_function_invocation() CALLED!\n");
+debug_c::print(fcall);
+
+
 	if (generic_function_call_t::POU_FB       == fcall_data.POU_type)  POU_str = "FB";
 	if (generic_function_call_t::POU_function == fcall_data.POU_type)  POU_str = "function";
 	if (NULL == POU_str) ERROR;
@@ -204,7 +208,11 @@
 		}
 	}
 	if (NULL != fcall_data.nonformal_operand_list) {
+debug_c::print("print_datatypes_error_c::handle_function_invocation() CALLING  ---> fcall_data.nonformal_operand_list->accept(*this)!\n");
+debug_c::print_ast(fcall_data.nonformal_operand_list);
+debug_c::print("print_datatypes_error_c::handle_function_invocation() LIST_END\n");
 		fcall_data.nonformal_operand_list->accept(*this);
+debug_c::print("print_datatypes_error_c::handle_function_invocation() RETURNED <--- fcall_data.nonformal_operand_list->accept(*this)!\n");
 		if (f_decl)
 			for (int i = 1; (param_value = fcp_iterator.next_nf()) != NULL; i++) {
 		  		/* TODO: verify if it is lvalue when INOUT or OUTPUT parameters! */
@@ -569,6 +577,10 @@
 /*  subscripted_variable '[' subscript_list ']' */
 // SYM_REF2(array_variable_c, subscripted_variable, subscript_list)
 void *print_datatypes_error_c::visit(array_variable_c *symbol) {
+	/* the subscripted variable may be a structure or another array variable, that must also be visisted! */
+	/* Please read the comments in the array_variable_c and structured_variable_c visitors in the fill_candidate_datatypes.cc file! */
+	symbol->subscripted_variable->accept(*this); 
+	
 	if (symbol->candidate_datatypes.size() == 0)
 		STAGE3_ERROR(0, symbol, symbol, "Array variable not declared in this scope.");
 	
@@ -598,13 +610,13 @@
  *           this into account!
  */
 // SYM_REF2(structured_variable_c, record_variable, field_selector)
-/* NOTE: We do not recursively determine the data types of each field_selector in fill_candidate_datatypes_c,
- * so it does not make sense to recursively visit all the field_selectors to print out error messages. 
- * Maybe in the future, if we find the need to print out more detailed error messages, we might do it that way. For now, we don't!
- */
 void *print_datatypes_error_c::visit(structured_variable_c *symbol) {
+	/* the record variable may be another structure or even an array variable, that must also be visisted! */
+	/* Please read the comments in the array_variable_c and structured_variable_c visitors in the fill_candidate_datatypes.cc file! */
+	symbol->record_variable->accept(*this);
+	
 	if (symbol->candidate_datatypes.size() == 0)
-		STAGE3_ERROR(0, symbol, symbol, "Undeclared structured/FB variable.");
+		STAGE3_ERROR(0, symbol, symbol, "Undeclared structured (or FB) variable, or non-existant field (variable) in structure (FB).");
 	return NULL;
 }