Fix search_varfb_instance_decl to be able to find variables and FB when only given an identifier.
authorMario de Sousa <msousa@fe.up.pt>
Thu, 02 Feb 2012 14:18:02 +0000
changeset 420 866eb35e4e14
parent 419 6384168a8e95
child 421 840cb1e1e177
Fix search_varfb_instance_decl to be able to find variables and FB when only given an identifier.
Fix handling of FB calls in stage3.
Start handling of function invocations in stage3.
absyntax/absyntax.def
absyntax_utils/search_varfb_instance_type.cc
absyntax_utils/search_varfb_instance_type.hh
stage3/fill_candidate_datatypes.cc
stage3/fill_candidate_datatypes.hh
--- a/absyntax/absyntax.def	Thu Feb 02 10:00:53 2012 +0000
+++ b/absyntax/absyntax.def	Thu Feb 02 14:18:02 2012 +0000
@@ -1045,7 +1045,9 @@
 
 /*    formal_param_list -> may be NULL ! */
 /* nonformal_param_list -> may be NULL ! */
-/* NOTE: The parameter 'called_function_declaration' is used to pass data between the stage 3 and stage 4.
+/* NOTES:
+ *    The parameter 'called_function_declaration'... 
+ *       ...is used to pass data between the stage 3 and stage 4.
  *       The IEC 61131-3 standard allows for overloaded standard functions. This means that some
  *       function calls are not completely defined by the name of the function being called,
  *       and need to be disambiguated with using the data types of the parameters being passed.
@@ -1054,8 +1056,23 @@
  *       It does not make sense to determine the exact function being called twice (once in stage 3,
  *       and again in stage 4), so stage 3 will store this info in the parameter called_function_declaration
  *       for stage 4 to use it later on.
- */
-SYM_REF3(function_invocation_c, function_name, formal_param_list, nonformal_param_list, symbol_c *called_function_declaration; int extensible_param_count;)
+ *    The parameter 'candidate_functions'... 
+ *       ...is used to pass data between two passes within stage 3
+ *       (actually between fill_candidate_datatypes_c and narrow_candidate_datatypes_c).
+ *       It is used to store all the functions that may be legally called with the current parameters
+ *       being used in this function invocation. Note that the standard includes some standard functions
+ *       that have the exact same input parameter types, but return different data types.
+ *       In order to determine which of these functions should be called, we first create a list
+ *       of all possible functions, and then narrow down the list (hopefully down to 1 function)
+ *       once we know the data type that the function invocation must return (this will take into 
+ *       account the expression in which the function invocation is inserted/occurs).
+ *    The parameter 'extensible_param_count'... 
+ *       ...is used to pass data between the stage 3 and stage 4.
+ *       The IEC 61131-3 standard allows for extensible standard functions. This means that some
+ *       standard functions may be called with a variable number of paramters. Stage 3 will store
+ *       in extensible_param_count the number of parameters being passed to the extensible parameter.
+ */
+SYM_REF3(function_invocation_c, function_name, formal_param_list, nonformal_param_list, symbol_c *called_function_declaration; int extensible_param_count; std::vector <symbol_c *> candidate_functions;)
 
 
 /********************/
--- a/absyntax_utils/search_varfb_instance_type.cc	Thu Feb 02 10:00:53 2012 +0000
+++ b/absyntax_utils/search_varfb_instance_type.cc	Thu Feb 02 14:18:02 2012 +0000
@@ -141,7 +141,28 @@
 
 
 
-
+/*************************/
+/* B.1 - Common elements */
+/*************************/
+/*******************************************/
+/* B 1.1 - Letters, digits and identifiers */
+/*******************************************/
+// SYM_TOKEN(identifier_c)
+void *search_varfb_instance_type_c::visit(identifier_c *variable_name) {
+  /* symbol should be a variable name!! */
+  /* Note: although the method is called get_decl(), it is getting the declaration of the variable, which for us is the type_id of that variable! */
+  current_type_id       = search_var_instance_decl.get_decl (variable_name);
+  current_basetype_decl = search_base_type.get_basetype_decl(current_type_id);
+  current_basetype_id   = search_base_type.get_basetype_id  (current_type_id);
+    
+  /* What if the variable has not been declared?  Then this should not be a compiler error! 
+   * However, currently stage 2 of the compiler already detects when variables have not been delcared,
+   * so if the variable's declaration is not found, then that means that we have an internal compiler error!
+   */
+  if (NULL == current_type_id) ERROR; 
+
+  return NULL;
+}
 
 
 
@@ -269,13 +290,7 @@
 /*********************/
 // SYM_REF1(symbolic_variable_c, var_name)
 void *search_varfb_instance_type_c::visit(symbolic_variable_c *symbol) {
-  /* Note: although the method is called get_decl(), it is getting the declaration of the variable, which for us is the type_id of that variable! */
-  current_type_id       = search_var_instance_decl.get_decl (symbol->var_name);
-  current_basetype_decl = search_base_type.get_basetype_decl(current_type_id);
-  current_basetype_id   = search_base_type.get_basetype_id  (current_type_id);
-    
-  if (NULL == current_type_id) ERROR; /* why should this be an error? what if the variable has not been declared? */
-
+  symbol->var_name->accept(*this);
   return NULL;
 }
 
--- a/absyntax_utils/search_varfb_instance_type.hh	Thu Feb 02 10:00:53 2012 +0000
+++ b/absyntax_utils/search_varfb_instance_type.hh	Thu Feb 02 14:18:02 2012 +0000
@@ -134,13 +134,14 @@
 
 
   private:
-    /* We override the base class' visitor to identifier_c.
-     * This is so because the base class does not consider a function block
-     * to be a type, unlike this class that allows a variable instance
-     * of a function block type...
-     */
-//     void *visit(identifier_c *type_name);
-
+    /*************************/
+    /* B.1 - Common elements */
+    /*************************/
+    /*******************************************/
+    /* B 1.1 - Letters, digits and identifiers */
+    /*******************************************/
+    void *visit(identifier_c *variable_name);
+      
     /********************************/
     /* B 1.3.3 - Derived data types */
     /********************************/
--- a/stage3/fill_candidate_datatypes.cc	Thu Feb 02 10:00:53 2012 +0000
+++ b/stage3/fill_candidate_datatypes.cc	Thu Feb 02 14:18:02 2012 +0000
@@ -63,7 +63,8 @@
 	return NULL;
 }
 
-void fill_candidate_datatypes_c::match_nonformal_call(symbol_c *f_call, symbol_c *f_decl, int *error_count) {
+/* returns true if compatible function/FB invocation, otherwise returns false */
+bool fill_candidate_datatypes_c::match_nonformal_call(symbol_c *f_call, symbol_c *f_decl) {
 	symbol_c *call_param_value,  *param_type;
 	identifier_c *param_name;
 	function_param_iterator_c       fp_iterator(f_decl);
@@ -71,37 +72,34 @@
 	int extensible_parameter_highest_index = -1;
 	unsigned int i;
 
-	/* reset error counter */
-	if (error_count != NULL) *error_count = 0;
 	/* Iterating through the non-formal parameters of the function call */
 	while((call_param_value = fcp_iterator.next_nf()) != NULL) {
-		/* Obtaining the type of the value being passed in the function call */
-		std::vector <symbol_c *>&call_param_types = call_param_value->candidate_datatypes;
 		/* Iterate to the next parameter of the function being called.
 		 * Get the name of that parameter, and ignore if EN or ENO.
 		 */
 		do {
 			param_name = fp_iterator.next();
 			/* If there is no other parameter declared, then we are passing too many parameters... */
-			if(param_name == NULL) {
-				(*error_count)++;
-				return;
-			}
+			if(param_name == NULL) return false;
 		} while ((strcmp(param_name->value, "EN") == 0) || (strcmp(param_name->value, "ENO") == 0));
 
 		/* Get the parameter type */
 		param_type = base_type(fp_iterator.param_type());
-		for(i = 0; i < call_param_types.size(); i++) {
-			/* If the declared parameter and the parameter from the function call do not have the same type */
-			if(is_type_equal(param_type, call_param_types[i])) {
-				break;
-			}
-		}
-		if (i >= call_param_types.size()) (*error_count)++;
-	}
-}
-
-void fill_candidate_datatypes_c::match_formal_call(symbol_c *f_call, symbol_c *f_decl, int *error_count) {
+		
+		/* check whether one of the candidate_data_types of the value being passed is the same as the param_type */
+		for(i = 0; i < call_param_value->candidate_datatypes.size(); i++) {
+			/* If found (correct data type being passed), then stop the search */
+			if(is_type_equal(param_type, call_param_value->candidate_datatypes[i])) break;
+		}
+		/* if we reached the end of the loop, and no compatible type found, then return false */
+		if (i >= call_param_value->candidate_datatypes.size()) return false;
+	}
+	/* call is compatible! */
+	return true;
+}
+
+/* returns true if compatible function/FB invocation, otherwise returns false */
+bool fill_candidate_datatypes_c::match_formal_call(symbol_c *f_call, symbol_c *f_decl) {
 	symbol_c *call_param_value, *call_param_name, *param_type;
 	symbol_c *verify_duplicate_param;
 	identifier_c *param_name;
@@ -111,9 +109,6 @@
 	identifier_c *extensible_parameter_name;
 	unsigned int i;
 
-	/* reset error counter */
-	if (error_count != NULL) *error_count = 0;
-
 	/* Iterating through the formal parameters of the function call */
 	while((call_param_name = fcp_iterator.next_f()) != NULL) {
 
@@ -125,7 +120,7 @@
 		/* Checking if there are duplicated parameter values */
 		verify_duplicate_param = fcp_iterator.search_f(call_param_name);
 		if(verify_duplicate_param != call_param_value)
-			(*error_count)++;
+			return false;
 
 		/* Obtaining the type of the value being passed in the function call */
 		std::vector <symbol_c *>&call_param_types = call_param_value->candidate_datatypes;
@@ -134,7 +129,7 @@
 		/* Find the corresponding parameter in function declaration */
 		param_name = fp_iterator.search(call_param_name);
 		if(param_name == NULL) {
-			(*error_count)++;
+			return false;
 		} else {
 			/* Get the parameter type */
 			param_type = base_type(fp_iterator.param_type());
@@ -143,10 +138,11 @@
 				if(is_type_equal(param_type, call_param_types[i]))
 					break;
 			}
-			if (i >= call_param_types.size()) (*error_count)++;
-		}
-	}
-
+			if (i >= call_param_types.size())
+				return false;;
+		}
+	}
+	return true;
 }
 
 /* a helper function... */
@@ -1667,7 +1663,7 @@
 	function_declaration_c *f_decl;
 	list_c *parameter_list;
 	list_c *parameter_candidate_datatypes;
-	symbol_c *parameter_type;
+	symbol_c *returned_parameter_type;
 	function_symtable_t::iterator lower = function_symtable.lower_bound(symbol->function_name);
 	function_symtable_t::iterator upper = function_symtable.upper_bound(symbol->function_name);
 	/* If the name of the function being called is not found in the function symbol table, then this is an invalid call */
@@ -1683,21 +1679,25 @@
 	if (debug) std::cout << "function()\n";
 	parameter_list->accept(*this);
 	for(; lower != upper; lower++) {
-		int error_count = 0;
+		bool compatible = false;
 		f_decl = function_symtable.get_value(lower);
 		/* Check if function declaration in symbol_table is compatible with parameters */
-		if (NULL != symbol->nonformal_param_list)  match_nonformal_call(symbol, f_decl, &error_count);
-		if (NULL != symbol->   formal_param_list)     match_formal_call(symbol, f_decl, &error_count);
-		if (0 == error_count) {
-			/* Add basetype matching function only if not present */
+		if (NULL != symbol->nonformal_param_list)  compatible=match_nonformal_call(symbol, f_decl);
+		if (NULL != symbol->   formal_param_list)  compatible=   match_formal_call(symbol, f_decl);
+		if (compatible) {
+			/* Add the data type returned by the called functions. 
+			 * However, only do this if this data type is not already present in the candidate_datatypes list_c
+			 */
 			unsigned int k;
-			parameter_type = base_type(f_decl->type_name);
+			returned_parameter_type = base_type(f_decl->type_name);
 			for(k = 0; k < symbol->candidate_datatypes.size(); k++) {
-				if (is_type_equal(parameter_type, symbol->candidate_datatypes[k]))
+				if (is_type_equal(returned_parameter_type, symbol->candidate_datatypes[k]))
 					break;
 			}
-			if (k >= symbol->candidate_datatypes.size())
-				symbol->candidate_datatypes.push_back(parameter_type);
+			if (k >= symbol->candidate_datatypes.size()) {
+				symbol->candidate_datatypes.push_back(returned_parameter_type);
+				symbol->candidate_functions.push_back(f_decl);
+			}
 		}
 	}
 	if (debug) std::cout << "end_function() [" << symbol->candidate_datatypes.size() << "] result.\n";
@@ -1738,11 +1738,18 @@
 /* B 3.2.2 Subprogram Control Statements */
 /*****************************************/
 void *fill_candidate_datatypes_c::visit(fb_invocation_c *symbol) {
+	bool compatible = false;
 	symbol_c *fb_decl = search_varfb_instance_type->get_basetype_decl(symbol->fb_name);
-
+	
 	if (NULL == fb_decl) ERROR;
-	if (symbol->   formal_param_list != NULL) match_formal_call(symbol, fb_decl);
-	if (symbol->nonformal_param_list != NULL) match_nonformal_call(symbol, fb_decl);
+	if (symbol->   formal_param_list != NULL) {
+		symbol->formal_param_list->accept(*this);
+		compatible = match_formal_call(symbol, fb_decl);
+	}
+	if (symbol->nonformal_param_list != NULL) {
+		symbol->nonformal_param_list->accept(*this);
+		compatible = match_nonformal_call(symbol, fb_decl);
+	}
 	if (debug) std::cout << "FB [] ==> "  << symbol->candidate_datatypes.size() << " result.\n";
 	return NULL;
 }
--- a/stage3/fill_candidate_datatypes.hh	Thu Feb 02 10:00:53 2012 +0000
+++ b/stage3/fill_candidate_datatypes.hh	Thu Feb 02 14:18:02 2012 +0000
@@ -85,8 +85,8 @@
     virtual ~fill_candidate_datatypes_c(void);
 
     /* Match a function declaration with a function call through their parameters.*/
-    void match_nonformal_call(symbol_c *f_call, symbol_c *f_decl, int *error_count = NULL);
-    void match_formal_call(symbol_c *f_call, symbol_c *f_decl, int *error_count = NULL);
+    bool match_nonformal_call(symbol_c *f_call, symbol_c *f_decl);
+    bool match_formal_call   (symbol_c *f_call, symbol_c *f_decl);
 
     void *compute_standard_function_default(function_invocation_c *st_symbol, il_formal_funct_call_c *il_symbol);
     void *compute_standard_function_il(il_function_call_c *symbol, symbol_c *param_data_type);