stage3/fill_candidate_datatypes.cc
author Manuele Conti <conti.ma@alice.it>
Mon, 30 Jul 2012 22:59:00 +0200
changeset 622 eaa49b276e17
parent 612 c062ff18d04f
child 643 1cc0e1ca2aad
permissions -rwxr-xr-x
Add check bison version in configure.ac file.
To build correctly matiec we need bison greater or equals than 2.4 version.
Now the "configure" script is able to check if system has correctly requirements.
/*
 *  matiec - a compiler for the programming languages defined in IEC 61131-3
 *
 *  Copyright (C) 2009-2012  Mario de Sousa (msousa@fe.up.pt)
 *  Copyright (C) 2012       Manuele Conti (manuele.conti@sirius-es.it)
 *  Copyright (C) 2012       Matteo Facchinetti (matteo.facchinetti@sirius-es.it)
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *
 * This code is made available on the understanding that it will not be
 * used in safety-critical situations without a full and competent review.
 */

/*
 * An IEC 61131-3 compiler.
 *
 * Based on the
 * FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10)
 *
 */


/* TODO - things yet not checked by this data type checker...
 *
 * - check variable declarations
 * - check data type declarations
 * - check inside configurations (variable declarations)
 * - check SFC code
 * - must fix S and R IL functions (includes potientialy fixing stage4 code!) 
 */


/* NOTE: The algorithm implemented here assumes that flow control analysis has already been completed!
 *       BEFORE running this visitor, be sure to CALL the flow_control_analysis_c visitor!
 */


/*
 *  Fill the candidate datatype list for all symbols that may legally 'have' a data type (e.g. variables, literals, function calls, expressions, etc.)
 * 
 *  The candidate datatype list will be filled with a list of all the data types that expression may legally take.
 *  For example, the very simple literal '0' (as in foo := 0), may represent a:
 *    BOOL, BYTE, WORD, DWORD, LWORD, USINT, SINT, UINT, INT, UDINT, DINT, ULINT, LINT (as well as the SAFE versions of these data tyes too!)
 */

#include <../main.hh>         /* required for UINT64_MAX, INT64_MAX, INT64_MIN, ... */
#include "fill_candidate_datatypes.hh"
#include "datatype_functions.hh"
#include <typeinfo>
#include <list>
#include <string>
#include <string.h>
#include <strings.h>

#define GET_CVALUE(dtype, symbol)             ((symbol)->const_value._##dtype.value)
#define VALID_CVALUE(dtype, symbol)           (symbol_c::cs_const_value == (symbol)->const_value._##dtype.status)
#define IS_OVERFLOW(dtype, symbol)            (symbol_c::cs_overflow == (symbol)->const_value._##dtype.status)

/* set to 1 to see debug info during execution */
static int debug = 0;

fill_candidate_datatypes_c::fill_candidate_datatypes_c(symbol_c *ignore) {
}

fill_candidate_datatypes_c::~fill_candidate_datatypes_c(void) {
}

symbol_c *fill_candidate_datatypes_c::widening_conversion(symbol_c *left_type, symbol_c *right_type, const struct widen_entry widen_table[]) {
	int k;
	/* find a widening table entry compatible */
	for (k = 0; NULL != widen_table[k].left;  k++)
		if ((typeid(*left_type) == typeid(*widen_table[k].left)) && (typeid(*right_type) == typeid(*widen_table[k].right)))
                      return widen_table[k].result;
	return NULL;
}


/* add a data type to a candidate data type list, while guaranteeing no duplicate entries! */
/* Returns true if it really did add the datatype to the list, or false if it was already present in the list! */
bool fill_candidate_datatypes_c::add_datatype_to_candidate_list(symbol_c *symbol, symbol_c *datatype) {
  /* If it is an invalid data type, do not insert!
   * NOTE: it reduces overall code size to do this test here, instead of doing every time before calling the add_datatype_to_candidate_list() function. 
   */
  if (!is_type_valid(datatype)) /* checks for NULL and invalid_type_name_c */
    return false;

  if (search_in_candidate_datatype_list(datatype, symbol->candidate_datatypes) >= 0) 
    /* already in the list, Just return! */
    return false;
  
  /* not yet in the candidate data type list, so we insert it now! */
  symbol->candidate_datatypes.push_back(datatype);
  return true;
}
    
    
bool fill_candidate_datatypes_c::add_2datatypes_to_candidate_list(symbol_c *symbol, symbol_c *datatype1, symbol_c *datatype2) {
  add_datatype_to_candidate_list(symbol, datatype1);
  add_datatype_to_candidate_list(symbol, datatype2);
  return true;
}



void fill_candidate_datatypes_c::remove_incompatible_datatypes(symbol_c *symbol) {
  #ifdef __REMOVE__
    #error __REMOVE__ macro already exists. Choose another name!
  #endif
  #define __REMOVE__(datatype)\
      remove_from_candidate_datatype_list(&search_constant_type_c::datatype,       symbol->candidate_datatypes);\
      remove_from_candidate_datatype_list(&search_constant_type_c::safe##datatype, symbol->candidate_datatypes);
  
  {/* Remove unsigned data types */
    uint64_t value = 0;
    if (VALID_CVALUE( uint64, symbol)) value = GET_CVALUE(uint64, symbol);
    if (IS_OVERFLOW ( uint64, symbol)) value = (uint64_t)UINT32_MAX + (uint64_t)1;
    
    if (value > 1          )          {__REMOVE__(bool_type_name);}
    if (value > UINT8_MAX  )          {__REMOVE__(usint_type_name);  __REMOVE__( byte_type_name);}
    if (value > UINT16_MAX )          {__REMOVE__( uint_type_name);  __REMOVE__( word_type_name);}
    if (value > UINT32_MAX )          {__REMOVE__(udint_type_name);  __REMOVE__(dword_type_name);}
    if (IS_OVERFLOW( uint64, symbol)) {__REMOVE__(ulint_type_name);  __REMOVE__(lword_type_name);}
  }

  {/* Remove signed data types */
    int64_t value = 0;
    if (VALID_CVALUE(  int64, symbol)) value = GET_CVALUE(int64, symbol);
    if (IS_OVERFLOW (  int64, symbol)) value = (int64_t)INT32_MAX + (int64_t)1;
    
    if ((value <  INT8_MIN) || (value >  INT8_MAX)) {__REMOVE__(sint_type_name);}
    if ((value < INT16_MIN) || (value > INT16_MAX)) {__REMOVE__( int_type_name);}
    if ((value < INT32_MIN) || (value > INT32_MAX)) {__REMOVE__(dint_type_name);}
    if (IS_OVERFLOW( int64, symbol))                {__REMOVE__(lint_type_name);}
  }
    
  {/* Remove floating point data types */
    real64_t value = 0;
    if (VALID_CVALUE( real64, symbol)) value = GET_CVALUE(real64, symbol);
    if (IS_OVERFLOW ( real64, symbol)) value = (real64_t)REAL32_MAX + (real64_t)1;
    if (value >  REAL32_MAX )         {__REMOVE__( real_type_name);}
    if (value < -REAL32_MAX )         {__REMOVE__( real_type_name);}
    if (IS_OVERFLOW( real64, symbol)) {__REMOVE__(lreal_type_name);}
  }
  #undef __REMOVE__
}
    

/* returns true if compatible function/FB invocation, otherwise returns false */
/* Assumes that the candidate_datatype lists of all the parameters being passed haved already been filled in */
/*
 * All parameters being passed to the called function MUST be in the parameter list to which f_call points to!
 * This means that, for non formal function calls in IL, de current (default value) must be artificially added to the
 * beginning of the parameter list BEFORE calling handle_function_call().
 */
bool fill_candidate_datatypes_c::match_nonformal_call(symbol_c *f_call, symbol_c *f_decl) {
	symbol_c *call_param_value,  *param_datatype;
	identifier_c *param_name;
	function_param_iterator_c       fp_iterator(f_decl);
	function_call_param_iterator_c fcp_iterator(f_call);
	int extensible_parameter_highest_index = -1;
	unsigned int i;

	/* Iterating through the non-formal parameters of the function call */
	while((call_param_value = fcp_iterator.next_nf()) != NULL) {
		/* 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) return false;
		} while ((strcmp(param_name->value, "EN") == 0) || (strcmp(param_name->value, "ENO") == 0));

		/* TODO: verify if it is lvalue when INOUT or OUTPUT parameters! */
		/* Get the parameter type */
		param_datatype = base_type(fp_iterator.param_type());
		
		/* check whether one of the candidate_data_types of the value being passed is the same as the param_type */
		if (search_in_candidate_datatype_list(param_datatype, call_param_value->candidate_datatypes) < 0)
			return false; /* return false if param_type not in the list! */
	}
	/* call is compatible! */
	return true;
}



/* returns true if compatible function/FB invocation, otherwise returns false */
/* Assumes that the candidate_datatype lists of all the parameters being passed haved already been filled in */
bool fill_candidate_datatypes_c::match_formal_call(symbol_c *f_call, symbol_c *f_decl, symbol_c **first_param_datatype) {
	symbol_c *call_param_value, *call_param_name, *param_datatype;
	symbol_c *verify_duplicate_param;
	identifier_c *param_name;
	function_param_iterator_c       fp_iterator(f_decl);
	function_call_param_iterator_c fcp_iterator(f_call);
	int extensible_parameter_highest_index = -1;
	identifier_c *extensible_parameter_name;
	unsigned int i;
	bool is_first_param = true;

	/* Iterating through the formal parameters of the function call */
	while((call_param_name = fcp_iterator.next_f()) != NULL) {
		/* Obtaining the value being passed in the function call */
		call_param_value = fcp_iterator.get_current_value();
		/* the following should never occur. If it does, then we have a bug in our code... */
		if (NULL == call_param_value) ERROR;

		/* Obtaining the assignment direction:  := (assign_in) or => (assign_out) */
		function_call_param_iterator_c::assign_direction_t call_param_dir = fcp_iterator.get_assign_direction();

		/* Checking if there are duplicated parameter values */
		verify_duplicate_param = fcp_iterator.search_f(call_param_name);
		if(verify_duplicate_param != call_param_value)
			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;

		/* Find the corresponding parameter in function declaration */
		param_name = fp_iterator.search(call_param_name);
		if(param_name == NULL) return false;
		/* Get the parameter data type */
		param_datatype = base_type(fp_iterator.param_type());
		/* Get the parameter direction: IN, OUT, IN_OUT */
		function_param_iterator_c::param_direction_t param_dir = fp_iterator.param_direction();

		/* check whether direction (IN, OUT, IN_OUT) and assignment types (:= , =>) are compatible !!! */
		if          (function_call_param_iterator_c::assign_in  == call_param_dir) {
			if ((function_param_iterator_c::direction_in    != param_dir) &&
			    (function_param_iterator_c::direction_inout != param_dir))
				return false;
		} else if   (function_call_param_iterator_c::assign_out == call_param_dir) {
			if ((function_param_iterator_c::direction_out   != param_dir))
				return false;
		} else ERROR;
		
		/* check whether one of the candidate_data_types of the value being passed is the same as the param_type */
		if (search_in_candidate_datatype_list(param_datatype, call_param_types) < 0)
			return false; /* return false if param_type not in the list! */
		
		/* If this is the first parameter, then copy the datatype to *first_param_datatype */
		if (is_first_param)
			if (NULL != first_param_datatype)
				*first_param_datatype = param_datatype;
		is_first_param = false;
	}
	/* call is compatible! */
	return true;
}




/* Handle a generic function call!
 * Assumes that the parameter_list containing the values being passed in this function invocation
 * has already had all the candidate_datatype lists filled in!
 *
 * All parameters being passed to the called function MUST be in the parameter list to which f_call points to!
 * This means that, for non formal function calls in IL, de current (default value) must be artificially added to the
 * beginning of the parameter list BEFORE calling handle_function_call().
 */
/*
typedef struct {
  symbol_c *function_name,
  symbol_c *nonformal_operand_list,
  symbol_c *   formal_operand_list,

  std::vector <symbol_c *> &candidate_functions,  
  symbol_c &*called_function_declaration,
  int      &extensible_param_count
} generic_function_call_t;
*/
/*
void narrow_candidate_datatypes_c::narrow_function_invocation(symbol_c *fcall, generic_function_call_t fcall_data) {
void *fill_candidate_datatypes_c::handle_function_call(symbol_c *f_call, symbol_c *function_name, invocation_type_t invocation_type,
                                                       std::vector <symbol_c *> *candidate_datatypes,
                                                       std::vector <symbol_c *> *candidate_functions) {
  */
void fill_candidate_datatypes_c::handle_function_call(symbol_c *fcall, generic_function_call_t fcall_data) {
	function_declaration_c *f_decl;
	list_c *parameter_list;
	list_c *parameter_candidate_datatypes;
	symbol_c *returned_parameter_type;

	if (debug) std::cout << "function()\n";

	function_symtable_t::iterator lower = function_symtable.lower_bound(fcall_data.function_name);
	function_symtable_t::iterator upper = function_symtable.upper_bound(fcall_data.function_name);
	/* If the name of the function being called is not found in the function symbol table, then this is an invalid call */
	/* Since the lexical parser already checks for this, then if this occurs then we have an internal compiler error. */
	if (lower == function_symtable.end()) ERROR;
	
	/* Look for all compatible function declarations, and add their return datatypes 
	 * to the candidate_datatype list of this function invocation. 
	 *
	 * If only one function exists, we add its return datatype to the candidate_datatype list,
	 * even if the parameters passed to it are invalid.
	 * This guarantees that the remainder of the expression in which the function call is inserted
	 * is treated as if the function call returns correctly, and therefore does not generate
	 * spurious error messages.
	 * Even if the parameters to the function call are invalid, doing this is still safe, as the 
	 * expressions inside the function call will themselves have erros and will  guarantee that 
	 * compilation is aborted in stage3 (in print_datatypes_error_c).
	 */
	if (function_symtable.multiplicity(fcall_data.function_name) == 1) {
		f_decl = function_symtable.get_value(lower);
		returned_parameter_type = base_type(f_decl->type_name);
		if (add_datatype_to_candidate_list(fcall, returned_parameter_type))
			/* we only add it to the function declaration list if this entry was not already present in the candidate datatype list! */
			fcall_data.candidate_functions.push_back(f_decl);
		
	}
	for(; lower != upper; lower++) {
		bool compatible = false;
		
		f_decl = function_symtable.get_value(lower);
		/* Check if function declaration in symbol_table is compatible with parameters */
		if (NULL != fcall_data.nonformal_operand_list) compatible=match_nonformal_call(fcall, f_decl);
		if (NULL != fcall_data.   formal_operand_list) compatible=   match_formal_call(fcall, 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
			 */
			returned_parameter_type = base_type(f_decl->type_name);		
			if (add_datatype_to_candidate_list(fcall, returned_parameter_type))
				/* we only add it to the function declaration list if this entry was not already present in the candidate datatype list! */
				fcall_data.candidate_functions.push_back(f_decl);
		}
	}
	if (debug) std::cout << "end_function() [" << fcall->candidate_datatypes.size() << "] result.\n";
	return;
}


/* handle implicit FB call in IL.
 * e.g.  CLK ton_var
 *        CU counter_var
 */
void *fill_candidate_datatypes_c::handle_implicit_il_fb_call(symbol_c *il_instruction, const char *param_name, symbol_c *&called_fb_declaration) {
	symbol_c *fb_type_id = search_varfb_instance_type->get_basetype_id(il_operand);
  	/* Although a call to a non-declared FB is a semantic error, this is currently caught by stage 2! */
	if (NULL == fb_type_id) ERROR;

	function_block_declaration_c *fb_decl = function_block_type_symtable.find_value(fb_type_id);
	if (function_block_type_symtable.end_value() == fb_decl)
		/* The il_operand is not the name of a FB instance. Most probably it is the name of a variable of some other type.
		 * this is a semantic error.
		 */
		fb_decl = NULL;
	
	/* The narrow_candidate_datatypes_c does not rely on this called_fb_declaration pointer being == NULL to conclude that
	 * we have a datatype incompatibility error, so we set it to fb_decl to allow the print_datatype_error_c to print out
	 * more informative error messages!
	 */
	called_fb_declaration = fb_decl;

	/* This implicit FB call does not change the value stored in the current/default IL variable */
	/* It does, however, require that the datatype be compatible with the input parameter of the FB being called. 
	 * If we were to follow the filling & narrowing algorithm correctly (implemented in fill_candidate_datatypes_c
	 * & narrow_candidate_datatypes_c respectively), we should be restricting the candidate_datatpes to the datatypes
	 * that are compatible to the FB call. 
	 * However, doing the above will often result in some very confusing error messages for the user, especially in the case
	 * in which the FB call is wrong, so the resulting cadidate datatypes is an empty list. In this case, the user would see
	 * many error messages related to the IL instructions that follow the FB call, even though those IL instructions may be perfectly
	 * correct.
	 * For now, we will simply let the narrow_candidate_datatypes_c verify if the datatypes are compatible (something that should be done
	 * here).
	 */
	if (NULL != prev_il_instruction)
		il_instruction->candidate_datatypes = prev_il_instruction->candidate_datatypes; 

	if (debug) std::cout << "handle_implicit_il_fb_call() [" << prev_il_instruction->candidate_datatypes.size() << "] ==> " << il_instruction->candidate_datatypes.size() << " result.\n";
	return NULL;
}




/* handle a binary IL operator, like ADD, SUB, etc... */
void *fill_candidate_datatypes_c::handle_binary_operator(const struct widen_entry widen_table[], symbol_c *symbol, symbol_c *l_expr, symbol_c *r_expr) {
	if (NULL == l_expr) /* if no prev_il_instruction */
		return NULL; 

	for(unsigned int i = 0; i < l_expr->candidate_datatypes.size(); i++)
		for(unsigned int j = 0; j < r_expr->candidate_datatypes.size(); j++)
			/* NOTE: add_datatype_to_candidate_list() will only really add the datatype if it is != NULL !!! */
			add_datatype_to_candidate_list(symbol, widening_conversion(l_expr->candidate_datatypes[i], r_expr->candidate_datatypes[j], widen_table));
	remove_incompatible_datatypes(symbol);
	if (debug) std::cout <<  "[" << l_expr->candidate_datatypes.size() << "," << r_expr->candidate_datatypes.size() << "] ==> "  << symbol->candidate_datatypes.size() << " result.\n";
	return NULL;
}


/* handle a binary ST expression, like '+', '-', etc... */
void *fill_candidate_datatypes_c::handle_binary_expression(const struct widen_entry widen_table[], symbol_c *symbol, symbol_c *l_expr, symbol_c *r_expr) {
	l_expr->accept(*this);
	r_expr->accept(*this);
	return handle_binary_operator(widen_table, symbol, l_expr, r_expr);
}




/* a helper function... */
symbol_c *fill_candidate_datatypes_c::base_type(symbol_c *symbol) {
	/* NOTE: symbol == NULL is valid. It will occur when, for e.g., an undefined/undeclared symbolic_variable is used
	 *       in the code.
	 */
	if (symbol == NULL) return NULL;
	return (symbol_c *)symbol->accept(search_base_type);
}

/*********************/
/* B 1.2 - Constants */
/*********************/
/******************************/
/* B 1.2.1 - Numeric Literals */
/******************************/
#define sizeoftype(symbol) get_sizeof_datatype_c::getsize(symbol)

void *fill_candidate_datatypes_c::handle_any_integer(symbol_c *symbol) {
	add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::bool_type_name,  &search_constant_type_c::safebool_type_name);
	add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::byte_type_name,  &search_constant_type_c::safebyte_type_name);
	add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::word_type_name,  &search_constant_type_c::safeword_type_name);
	add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::dword_type_name, &search_constant_type_c::safedword_type_name);
	add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::lword_type_name, &search_constant_type_c::safelword_type_name);
	add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::sint_type_name,  &search_constant_type_c::safesint_type_name);
	add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::int_type_name,   &search_constant_type_c::safeint_type_name);
	add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::dint_type_name,  &search_constant_type_c::safedint_type_name);
	add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::lint_type_name,  &search_constant_type_c::safelint_type_name);
	add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::usint_type_name, &search_constant_type_c::safeusint_type_name);
	add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::uint_type_name,  &search_constant_type_c::safeuint_type_name);
	add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::udint_type_name, &search_constant_type_c::safeudint_type_name);
	add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::ulint_type_name, &search_constant_type_c::safeulint_type_name);
	remove_incompatible_datatypes(symbol);
	if (debug) std::cout << "ANY_INT [" << symbol->candidate_datatypes.size()<< "]" << std::endl;
	return NULL;
}



void *fill_candidate_datatypes_c::handle_any_real(symbol_c *symbol) {
	add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::real_type_name,  &search_constant_type_c::safereal_type_name);
	add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::lreal_type_name, &search_constant_type_c::safelreal_type_name);
	remove_incompatible_datatypes(symbol);
	if (debug) std::cout << "ANY_REAL [" << symbol->candidate_datatypes.size() << "]" << std::endl;
	return NULL;
}



void *fill_candidate_datatypes_c::handle_any_literal(symbol_c *symbol, symbol_c *symbol_value, symbol_c *symbol_type) {
	symbol_value->accept(*this);
	if (search_in_candidate_datatype_list(symbol_type, symbol_value->candidate_datatypes) >= 0)
		add_datatype_to_candidate_list(symbol, symbol_type);
	remove_incompatible_datatypes(symbol);
	if (debug) std::cout << "XXX_LITERAL [" << symbol->candidate_datatypes.size() << "]\n";
	return NULL;
}



void *fill_candidate_datatypes_c::visit(    real_c *symbol) {return handle_any_real(symbol);}
void *fill_candidate_datatypes_c::visit(neg_real_c *symbol) {return handle_any_real(symbol);}



void *fill_candidate_datatypes_c::visit(neg_integer_c *symbol) {
	add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::int_type_name, &search_constant_type_c::safeint_type_name);
	add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::sint_type_name, &search_constant_type_c::safesint_type_name);
	add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::dint_type_name, &search_constant_type_c::safedint_type_name);
	add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::lint_type_name, &search_constant_type_c::safelint_type_name);
	remove_incompatible_datatypes(symbol);
	if (debug) std::cout << "neg ANY_INT [" << symbol->candidate_datatypes.size() << "]" << std::endl;
	return NULL;
}



void *fill_candidate_datatypes_c::visit(integer_c        *symbol) {return handle_any_integer(symbol);}
void *fill_candidate_datatypes_c::visit(binary_integer_c *symbol) {return handle_any_integer(symbol);}
void *fill_candidate_datatypes_c::visit(octal_integer_c  *symbol) {return handle_any_integer(symbol);}
void *fill_candidate_datatypes_c::visit(hex_integer_c    *symbol) {return handle_any_integer(symbol);}



// SYM_REF2(integer_literal_c, type, value)
/*
 * integer_literal:
 *   integer_type_name '#' signed_integer
 * | integer_type_name '#' binary_integer
 * | integer_type_name '#' octal_integer
 * | integer_type_name '#' hex_integer
 */
void *fill_candidate_datatypes_c::visit(   integer_literal_c *symbol) {return handle_any_literal(symbol, symbol->value, symbol->type);}
void *fill_candidate_datatypes_c::visit(      real_literal_c *symbol) {return handle_any_literal(symbol, symbol->value, symbol->type);}
void *fill_candidate_datatypes_c::visit(bit_string_literal_c *symbol) {return handle_any_literal(symbol, symbol->value, symbol->type);}

void *fill_candidate_datatypes_c::visit(   boolean_literal_c *symbol) {
	if (NULL != symbol->type) return handle_any_literal(symbol, symbol->value, symbol->type);

	symbol->value->accept(*this);
	symbol->candidate_datatypes = symbol->value->candidate_datatypes;
	return NULL;
}


void *fill_candidate_datatypes_c::visit(boolean_true_c *symbol) {
	add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::bool_type_name, &search_constant_type_c::safebool_type_name);
	return NULL;
}

void *fill_candidate_datatypes_c::visit(boolean_false_c *symbol) {
	add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::bool_type_name, &search_constant_type_c::safebool_type_name);
	return NULL;
}

/*******************************/
/* B.1.2.2   Character Strings */
/*******************************/
void *fill_candidate_datatypes_c::visit(double_byte_character_string_c *symbol) {
	add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::wstring_type_name, &search_constant_type_c::safewstring_type_name);
	return NULL;
}

void *fill_candidate_datatypes_c::visit(single_byte_character_string_c *symbol) {
	add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::string_type_name, &search_constant_type_c::safestring_type_name);
	return NULL;
}

/***************************/
/* B 1.2.3 - Time Literals */
/***************************/
/************************/
/* B 1.2.3.1 - Duration */
/************************/
void *fill_candidate_datatypes_c::visit(duration_c *symbol) {
	/* TODO: check whether the literal follows the rules specified in section '2.2.3.1 Duration' of the standard! */
	
	add_datatype_to_candidate_list(symbol, symbol->type_name);
	if (debug) std::cout << "TIME_LITERAL [" << symbol->candidate_datatypes.size() << "]\n";
	return NULL;
}

/************************************/
/* B 1.2.3.2 - Time of day and Date */
/************************************/
void *fill_candidate_datatypes_c::visit(time_of_day_c   *symbol) {add_datatype_to_candidate_list(symbol, symbol->type_name); return NULL;}
void *fill_candidate_datatypes_c::visit(date_c          *symbol) {add_datatype_to_candidate_list(symbol, symbol->type_name); return NULL;}
void *fill_candidate_datatypes_c::visit(date_and_time_c *symbol) {add_datatype_to_candidate_list(symbol, symbol->type_name); return NULL;}

/**********************/
/* B 1.3 - Data types */
/**********************/
/********************************/
/* B 1.3.3 - Derived data types */
/********************************/

/* simple_specification ASSIGN constant */
// SYM_REF2(simple_spec_init_c, simple_specification, constant)
void *fill_candidate_datatypes_c::visit(simple_spec_init_c *symbol) {
	if (NULL != symbol->constant) symbol->constant->accept(*this);
	add_datatype_to_candidate_list(symbol->simple_specification, base_type(symbol->simple_specification));
	symbol->candidate_datatypes = symbol->simple_specification->candidate_datatypes;
	/* NOTE: Even if the constant and the type are of incompatible data types, we let the
	 *       simple_spec_init_c object inherit the data type of the type declaration (simple_specification)
	 *       This will let us produce more informative error messages when checking data type compatibility
	 *       with located variables (AT %QW3.4 : WORD).
	 */
	// if (NULL != symbol->constant) intersect_candidate_datatype_list(symbol /*origin, dest.*/, symbol->constant /*with*/);
	return NULL;
}

/*  signed_integer DOTDOT signed_integer */
// SYM_REF2(subrange_c, lower_limit, upper_limit)
void *fill_candidate_datatypes_c::visit(subrange_c *symbol) {
	symbol->lower_limit->accept(*this);
	symbol->upper_limit->accept(*this);
	
	for (unsigned int u = 0; u < symbol->upper_limit->candidate_datatypes.size(); u++) {
		for(unsigned int l = 0; l < symbol->lower_limit->candidate_datatypes.size(); l++) {
			if (is_type_equal(symbol->upper_limit->candidate_datatypes[u], symbol->lower_limit->candidate_datatypes[l]))
				add_datatype_to_candidate_list(symbol, symbol->lower_limit->candidate_datatypes[l]);
		}
	}
	return NULL;
}

/*  TYPE type_declaration_list END_TYPE */
// SYM_REF1(data_type_declaration_c, type_declaration_list)
/* NOTE: Not required. already handled by iterator_visitor_c base class */
/*
void *fill_candidate_datatypes_c::visit(data_type_declaration_c *symbol) {
	symbol->type_declaration_list->accept(*this);
	return NULL;
}
*/

void *fill_candidate_datatypes_c::visit(enumerated_value_c *symbol) {
	symbol_c *enumerated_type;

	if (NULL != symbol->type)
		enumerated_type = symbol->type;
	else {
		enumerated_type = enumerated_value_symtable.find_value(symbol->value);
		if (enumerated_type == enumerated_value_symtable.end_value())
			enumerated_type = NULL;
	}
	enumerated_type = base_type(enumerated_type);
	if (NULL != enumerated_type)
		add_datatype_to_candidate_list(symbol, enumerated_type);

	if (debug) std::cout << "ENUMERATE [" << symbol->candidate_datatypes.size() << "]\n";
	return NULL;
}


/*********************/
/* B 1.4 - Variables */
/*********************/
void *fill_candidate_datatypes_c::visit(symbolic_variable_c *symbol) {
	add_datatype_to_candidate_list(symbol, search_varfb_instance_type->get_basetype_decl(symbol)); /* will only add if non NULL */
	if (debug) std::cout << "VAR [" << symbol->candidate_datatypes.size() << "]\n";
	return NULL;
}


/********************************************/
/* B 1.4.1 - Directly Represented Variables */
/********************************************/
void *fill_candidate_datatypes_c::visit(direct_variable_c *symbol) {
	/* Comment added by mario:
	 * The following code is safe, actually, as the lexical parser guarantees the correct IEC61131-3 syntax was used.
	 */
	/* However, we should probably add an assertion in case we later change the lexical parser! */
	/* if (symbol->value == NULL) ERROR;
	 * if (symbol->value[0] == '\0') ERROR;
	 * if (symbol->value[1] == '\0') ERROR;
	 */
	switch (symbol->value[2]) {
		case 'x': case 'X': /* bit   -  1 bit  */ add_datatype_to_candidate_list(symbol, &search_constant_type_c::bool_type_name);  break;
		case 'b': case 'B': /* byte  -  8 bits */ add_datatype_to_candidate_list(symbol, &search_constant_type_c::byte_type_name);  break;
		case 'w': case 'W': /* word  - 16 bits */ add_datatype_to_candidate_list(symbol, &search_constant_type_c::word_type_name);  break;
		case 'd': case 'D': /* dword - 32 bits */ add_datatype_to_candidate_list(symbol, &search_constant_type_c::dword_type_name); break;
		case 'l': case 'L': /* lword - 64 bits */ add_datatype_to_candidate_list(symbol, &search_constant_type_c::lword_type_name); break;
        	          /* if none of the above, then the empty string was used <=> boolean */
		default:                        add_datatype_to_candidate_list(symbol, &search_constant_type_c::bool_type_name);  break;
	}
	return NULL;
}

/*************************************/
/* B 1.4.2 - Multi-element variables */
/*************************************/
/*  subscripted_variable '[' subscript_list ']' */
// SYM_REF2(array_variable_c, subscripted_variable, subscript_list)
void *fill_candidate_datatypes_c::visit(array_variable_c *symbol) {
	/* get the declaration of the data type __stored__ in the array... */
	/* 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);
	
	/* recursively call the subscript list, so we can check the data types of the expressions used for the subscripts */
	symbol->subscript_list->accept(*this);

	if (debug) std::cout << "ARRAY_VAR [" << symbol->candidate_datatypes.size() << "]\n";	
	return NULL;
}


/* subscript_list ',' subscript */
// SYM_LIST(subscript_list_c)
/* NOTE: we inherit from iterator visitor, so we do not need to implement this method... */
// void *fill_candidate_datatypes_c::visit(subscript_list_c *symbol)


/*  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)
/* 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) {
	add_datatype_to_candidate_list(symbol, search_varfb_instance_type->get_basetype_decl(symbol));  /* will only add if non NULL */
	return NULL;
}



/******************************************/
/* B 1.4.3 - Declaration & Initialisation */
/******************************************/

void *fill_candidate_datatypes_c::visit(var1_list_c *symbol) {
#if 0   /* We don't really need to set the datatype of each variable. We just check the declaration itself! */
  for(int i = 0; i < symbol->n; i++) {
    add_datatype_to_candidate_list(symbol->elements[i], search_varfb_instance_type->get_basetype_decl(symbol->elements[i])); /* will only add if non NULL */
  }
#endif
  return NULL;
}  


/*  AT direct_variable */
// SYM_REF1(location_c, direct_variable)
void *fill_candidate_datatypes_c::visit(location_c *symbol) {
 /* This is a special situation. 
  *
  * The reason is that a located variable may be declared to be of any data type, as long as the size
  * matches the location (lines 1 3 and 4 of table 17). For example:
  *   var1 AT %MB42.0 : BYTE;
  *   var1 AT %MB42.1 : SINT;
  *   var1 AT %MB42.2 : USINT;
  *   var1 AT %MW64   : INT;
  *   var1 AT %MD56   : DINT;
  *   var1 AT %MD57   : REAL;
  *  are all valid!!
  *
  *  However, when used inside an expression, the direct variable (uses the same syntax as the location
  *  of a located variable) is limited to the following (ANY_BIT) data types:
  *    %MX --> BOOL
  *    %MB --> BYTE
  *    %MW --> WORD
  *    %MD --> DWORD
  *    %ML --> LWORD
  *
  *  So, in order to be able to analyse expressions with direct variables
  *   e.g:  var1 := 66 OR %MW34
  *  where the direct variable may only take the ANY_BIT data types, the fill_candidate_datatypes_c
  *  considers that only the ANY_BIT data types are allowed for a direct variable.
  *  However, it appears from the examples in the standard (lines 1 3 and 4 of table 17)
  *  a location may have any data type (presumably as long as the size in bits match).
  *  For this reason, a location_c may have more allowable data types than a direct_variable_c
  */

	symbol->direct_variable->accept(*this);
	for (unsigned int i = 0; i < symbol->direct_variable->candidate_datatypes.size(); i++) {
        	switch (get_sizeof_datatype_c::getsize(symbol->direct_variable->candidate_datatypes[i])) {
			case  1: /* bit   -  1 bit  */
					add_datatype_to_candidate_list(symbol, &search_constant_type_c::bool_type_name);
					add_datatype_to_candidate_list(symbol, &search_constant_type_c::safebool_type_name);
					break;
			case  8: /* byte  -  8 bits */
					add_datatype_to_candidate_list(symbol, &search_constant_type_c::byte_type_name);
					add_datatype_to_candidate_list(symbol, &search_constant_type_c::safebyte_type_name);
					add_datatype_to_candidate_list(symbol, &search_constant_type_c::sint_type_name);
					add_datatype_to_candidate_list(symbol, &search_constant_type_c::safesint_type_name);
					add_datatype_to_candidate_list(symbol, &search_constant_type_c::usint_type_name);
					add_datatype_to_candidate_list(symbol, &search_constant_type_c::safeusint_type_name);
					break;
			case 16: /* word  - 16 bits */
	 				add_datatype_to_candidate_list(symbol, &search_constant_type_c::word_type_name);
					add_datatype_to_candidate_list(symbol, &search_constant_type_c::safeword_type_name);
					add_datatype_to_candidate_list(symbol, &search_constant_type_c::int_type_name);
					add_datatype_to_candidate_list(symbol, &search_constant_type_c::safeint_type_name);
					add_datatype_to_candidate_list(symbol, &search_constant_type_c::uint_type_name);
					add_datatype_to_candidate_list(symbol, &search_constant_type_c::safeuint_type_name);
					break;
			case 32: /* dword - 32 bits */
					add_datatype_to_candidate_list(symbol, &search_constant_type_c::dword_type_name);
					add_datatype_to_candidate_list(symbol, &search_constant_type_c::safedword_type_name);
					add_datatype_to_candidate_list(symbol, &search_constant_type_c::dint_type_name);
					add_datatype_to_candidate_list(symbol, &search_constant_type_c::safedint_type_name);
					add_datatype_to_candidate_list(symbol, &search_constant_type_c::udint_type_name);
					add_datatype_to_candidate_list(symbol, &search_constant_type_c::safeudint_type_name);
					add_datatype_to_candidate_list(symbol, &search_constant_type_c::real_type_name);
					add_datatype_to_candidate_list(symbol, &search_constant_type_c::safereal_type_name);
					break;
			case 64: /* lword - 64 bits */
					add_datatype_to_candidate_list(symbol, &search_constant_type_c::lword_type_name);
					add_datatype_to_candidate_list(symbol, &search_constant_type_c::safelword_type_name);
					add_datatype_to_candidate_list(symbol, &search_constant_type_c::lint_type_name);
					add_datatype_to_candidate_list(symbol, &search_constant_type_c::safelint_type_name);
					add_datatype_to_candidate_list(symbol, &search_constant_type_c::ulint_type_name);
					add_datatype_to_candidate_list(symbol, &search_constant_type_c::safeulint_type_name);
					add_datatype_to_candidate_list(symbol, &search_constant_type_c::lreal_type_name);
					add_datatype_to_candidate_list(symbol, &search_constant_type_c::safelreal_type_name);
					break;
			default: /* if none of the above, then no valid datatype allowed... */
					break;
		} /* switch() */
	} /* for */

	return NULL;
}


/*  [variable_name] location ':' located_var_spec_init */
/* variable_name -> may be NULL ! */
// SYM_REF3(located_var_decl_c, variable_name, location, located_var_spec_init)
void *fill_candidate_datatypes_c::visit(located_var_decl_c *symbol) {
  symbol->located_var_spec_init->accept(*this);
  symbol->location->accept(*this);
  if (NULL != symbol->variable_name) {
    symbol->variable_name->candidate_datatypes = symbol->location->candidate_datatypes;
    intersect_candidate_datatype_list(symbol->variable_name /*origin, dest.*/, symbol->located_var_spec_init /*with*/);
  }
  return NULL;
}  





/************************************/
/* B 1.5 Program organization units */
/************************************/
/*********************/
/* B 1.5.1 Functions */
/*********************/
void *fill_candidate_datatypes_c::visit(function_declaration_c *symbol) {
	if (debug) printf("Filling candidate data types list of function %s\n", ((token_c *)(symbol->derived_function_name))->value);
	search_varfb_instance_type = new search_varfb_instance_type_c(symbol);
	symbol->var_declarations_list->accept(*this);
	symbol->function_body->accept(*this);
	delete search_varfb_instance_type;
	search_varfb_instance_type = NULL;
	return NULL;
}

/***************************/
/* B 1.5.2 Function blocks */
/***************************/
void *fill_candidate_datatypes_c::visit(function_block_declaration_c *symbol) {
	if (debug) printf("Filling candidate data types list of FB %s\n", ((token_c *)(symbol->fblock_name))->value);
	search_varfb_instance_type = new search_varfb_instance_type_c(symbol);
	symbol->var_declarations->accept(*this);
	symbol->fblock_body->accept(*this);
	delete search_varfb_instance_type;
	search_varfb_instance_type = NULL;
	return NULL;
}

/**********************/
/* B 1.5.3 - Programs */
/**********************/
void *fill_candidate_datatypes_c::visit(program_declaration_c *symbol) {
	if (debug) printf("Filling candidate data types list in program %s\n", ((token_c *)(symbol->program_type_name))->value);
	search_varfb_instance_type = new search_varfb_instance_type_c(symbol);
	symbol->var_declarations->accept(*this);
	symbol->function_block_body->accept(*this);
	delete search_varfb_instance_type;
	search_varfb_instance_type = NULL;
	return NULL;
}



/********************************/
/* B 1.7 Configuration elements */
/********************************/
void *fill_candidate_datatypes_c::visit(configuration_declaration_c *symbol) {
	// TODO !!!
	/* for the moment we must return NULL so semantic analysis of remaining code is not interrupted! */
	return NULL;
}

/****************************************/
/* B.2 - Language IL (Instruction List) */
/****************************************/
/***********************************/
/* B 2.1 Instructions and Operands */
/***********************************/

/*| instruction_list il_instruction */
// SYM_LIST(instruction_list_c)
void *fill_candidate_datatypes_c::visit(instruction_list_c *symbol) {
	/* In order to fill the data type candidates correctly
	 * in IL instruction lists containing JMPs to labels that come before the JMP instruction
	 * itself, we need to run the fill candidate datatypes algorithm twice on the Instruction List.
	 * e.g.:  ...
	 *          ld 23
	 *   label1:st byte_var
	 *          ld 34
	 *          JMP label1     
	 *
	 * Note that the second time we run the algorithm, most of the candidate datatypes are already filled
	 * in, so it will be able to produce tha correct candidate datatypes for the IL instruction referenced
	 * by the label, as in the 2nd pass we already know the candidate datatypes of the JMP instruction!
	 */
	for(int j = 0; j < 2; j++) {
		for(int i = 0; i < symbol->n; i++) {
			symbol->elements[i]->accept(*this);
		}
	}
	return NULL;
}



/* | label ':' [il_incomplete_instruction] eol_list */
// SYM_REF2(il_instruction_c, label, il_instruction)
// void *visit(instruction_list_c *symbol);
void *fill_candidate_datatypes_c::visit(il_instruction_c *symbol) {
	if (NULL == symbol->il_instruction) {
		/* This empty/null il_instruction does not change the value of the current/default IL variable.
		 * So it inherits the candidate_datatypes from it's previous IL instructions!
		 */
		intersect_prev_candidate_datatype_lists(symbol);
	} else {
		il_instruction_c fake_prev_il_instruction = *symbol;
		intersect_prev_candidate_datatype_lists(&fake_prev_il_instruction);

		if (symbol->prev_il_instruction.size() == 0)  prev_il_instruction = NULL;
		else                                          prev_il_instruction = &fake_prev_il_instruction;
		symbol->il_instruction->accept(*this);
		prev_il_instruction = NULL;

		/* This object has (inherits) the same candidate datatypes as the il_instruction */
		symbol->candidate_datatypes = symbol->il_instruction->candidate_datatypes;
	}

	return NULL;
}



void *fill_candidate_datatypes_c::visit(il_simple_operation_c *symbol) {
	/* determine the data type of the operand */
	if (NULL != symbol->il_operand) {
		symbol->il_operand->accept(*this);
	}
	/* recursive call to fill the candidate data types list */
	il_operand = symbol->il_operand;
	symbol->il_simple_operator->accept(*this);
	il_operand = NULL;
	/* This object has (inherits) the same candidate datatypes as the il_simple_operator */
	symbol->candidate_datatypes = symbol->il_simple_operator->candidate_datatypes;
	return NULL;
}


/* | function_name [il_operand_list] */
/* NOTE: The parameters 'called_function_declaration' and 'extensible_param_count' are used to pass data between the stage 3 and stage 4. */
// SYM_REF2(il_function_call_c, function_name, il_operand_list, symbol_c *called_function_declaration; int extensible_param_count;)
void *fill_candidate_datatypes_c::visit(il_function_call_c *symbol) {
	/* The first parameter of a non formal function call in IL will be the 'current value' (i.e. the prev_il_instruction)
	 * In order to be able to handle this without coding special cases, we will simply prepend that symbol
	 * to the il_operand_list, and remove it after calling handle_function_call().
	 *
	 * However, if no further paramters are given, then il_operand_list will be NULL, and we will
	 * need to create a new object to hold the pointer to prev_il_instruction.
	 */
	if (NULL == symbol->il_operand_list)  symbol->il_operand_list = new il_operand_list_c;
	if (NULL == symbol->il_operand_list)  ERROR;

	symbol->il_operand_list->accept(*this);

	if (NULL != prev_il_instruction) {
		((list_c *)symbol->il_operand_list)->insert_element(prev_il_instruction, 0);	

		generic_function_call_t fcall_param = {
			/* fcall_param.function_name               = */ symbol->function_name,
			/* fcall_param.nonformal_operand_list      = */ symbol->il_operand_list,
			/* fcall_param.formal_operand_list         = */ NULL,
			/* enum {POU_FB, POU_function} POU_type    = */ generic_function_call_t::POU_function,
			/* fcall_param.candidate_functions         = */ symbol->candidate_functions,
			/* fcall_param.called_function_declaration = */ symbol->called_function_declaration,
			/* fcall_param.extensible_param_count      = */ symbol->extensible_param_count
		};
		handle_function_call(symbol, fcall_param);

		/* Undo the changes to the abstract syntax tree we made above... */
		((list_c *)symbol->il_operand_list)->remove_element(0);
	}

	/* Undo the changes to the abstract syntax tree we made above... */
	if (((list_c *)symbol->il_operand_list)->n == 0) {
		/* if the list becomes empty, then that means that it did not exist before we made these changes, so we delete it! */
		delete 	symbol->il_operand_list;
		symbol->il_operand_list = NULL;
	}
	
	if (debug) std::cout << "il_function_call_c [" << symbol->candidate_datatypes.size() << "] result.\n";
	return NULL;
}


/* | il_expr_operator '(' [il_operand] eol_list [simple_instr_list] ')' */
// SYM_REF3(il_expression_c, il_expr_operator, il_operand, simple_instr_list);
void *fill_candidate_datatypes_c::visit(il_expression_c *symbol) {
  symbol_c *prev_il_instruction_backup = prev_il_instruction;
  
  if (NULL != symbol->il_operand)
    symbol->il_operand->accept(*this);

  if(symbol->simple_instr_list != NULL)
    symbol->simple_instr_list->accept(*this);

  /* Now check the if the data type semantics of operation are correct,  */
  il_operand = symbol->simple_instr_list;
  prev_il_instruction = prev_il_instruction_backup;
  symbol->il_expr_operator->accept(*this);
  il_operand = NULL;
  
  /* This object has the same candidate datatypes as the il_expr_operator. */
  symbol->candidate_datatypes = symbol->il_expr_operator->candidate_datatypes;
  return NULL;
}


void *fill_candidate_datatypes_c::visit(il_jump_operation_c *symbol) {
  /* recursive call to fill the candidate data types list */
  il_operand = NULL;
  symbol->il_jump_operator->accept(*this);
  il_operand = NULL;
  /* This object has the same candidate datatypes as the il_jump_operator. */
  symbol->candidate_datatypes = symbol->il_jump_operator->candidate_datatypes;
  return NULL;
}


/*   il_call_operator prev_declared_fb_name
 * | il_call_operator prev_declared_fb_name '(' ')'
 * | il_call_operator prev_declared_fb_name '(' eol_list ')'
 * | il_call_operator prev_declared_fb_name '(' il_operand_list ')'
 * | il_call_operator prev_declared_fb_name '(' eol_list il_param_list ')'
 */
/* NOTE: The parameter 'called_fb_declaration'is used to pass data between stage 3 and stage4 (although currently it is not used in stage 4 */
// SYM_REF4(il_fb_call_c, il_call_operator, fb_name, il_operand_list, il_param_list, symbol_c *called_fb_declaration)
void *fill_candidate_datatypes_c::visit(il_fb_call_c *symbol) {
	/* We do not call
	 * fb_decl = search_varfb_instance_type->get_basetype_decl(symbol->fb_name);
	 * because we want to make sure it is a FB instance, and not some other data type...
	 */
	symbol_c *fb_type_id = search_varfb_instance_type->get_basetype_id(symbol->fb_name);
	/* Although a call to a non-declared FB is a semantic error, this is currently caught by stage 2! */
	if (NULL == fb_type_id) ERROR;

 	function_block_declaration_c *fb_decl = function_block_type_symtable.find_value(fb_type_id);
	if (function_block_type_symtable.end_value() == fb_decl) 
		/* The fb_name not the name of a FB instance. Most probably it is the name of a variable of some other type. */
		fb_decl = NULL;

	/* Although a call to a non-declared FB is a semantic error, this is currently caught by stage 2! */
	if (NULL == fb_decl) ERROR;

	if (symbol->  il_param_list != NULL) symbol->il_param_list->accept(*this);
	if (symbol->il_operand_list != NULL) symbol->il_operand_list->accept(*this);

	/* The print_datatypes_error_c does not rely on this called_fb_declaration pointer being != NULL to conclude that
	 * we have a datat type incompatibility error, so setting it to the correct fb_decl is actually safe,
	 * as the compiler will never reach the compilation stage!
	 */
	symbol->called_fb_declaration = fb_decl;

	/* Let the il_call_operator (CAL, CALC, or CALCN) determine the candidate datatypes of the il_fb_call_c... */
	/* NOTE: We ignore whether the call is 'compatible' or not when filling in the candidate datatypes list.
	 *       Even if it is not compatible, we fill in the candidate datatypes list correctly so that the following
	 *       IL instructions may be handled correctly and debuged.
	 *       Doing this is actually safe, as the parameter_list will still contain errors that will be found by
	 *       print_datatypes_error_c, so the code will never reach stage 4!
	 */
	symbol->il_call_operator->accept(*this);
	symbol->candidate_datatypes = symbol->il_call_operator->candidate_datatypes;

	if (debug) std::cout << "FB [] ==> "  << symbol->candidate_datatypes.size() << " result.\n";
	return NULL;
}


/* | function_name '(' eol_list [il_param_list] ')' */
/* NOTE: The parameter 'called_function_declaration' is used to pass data between the stage 3 and stage 4. */
// SYM_REF2(il_formal_funct_call_c, function_name, il_param_list, symbol_c *called_function_declaration; int extensible_param_count;)
void *fill_candidate_datatypes_c::visit(il_formal_funct_call_c *symbol) {
	symbol->il_param_list->accept(*this);

	generic_function_call_t fcall_param = {
		/* fcall_param.function_name               = */ symbol->function_name,
		/* fcall_param.nonformal_operand_list      = */ NULL,
		/* fcall_param.formal_operand_list         = */ symbol->il_param_list,
		/* enum {POU_FB, POU_function} POU_type    = */ generic_function_call_t::POU_function,
		/* fcall_param.candidate_functions         = */ symbol->candidate_functions,
		/* fcall_param.called_function_declaration = */ symbol->called_function_declaration,
		/* fcall_param.extensible_param_count      = */ symbol->extensible_param_count
	};
	handle_function_call(symbol, fcall_param);

	if (debug) std::cout << "il_formal_funct_call_c [" << symbol->candidate_datatypes.size() << "] result.\n";
	return NULL;
}


//     void *visit(il_operand_list_c *symbol);


/* | simple_instr_list il_simple_instruction */
/* This object is referenced by il_expression_c objects */
void *fill_candidate_datatypes_c::visit(simple_instr_list_c *symbol) {
  if (symbol->n <= 0)
    return NULL;  /* List is empty! Nothing to do. */
    
  for(int i = 0; i < symbol->n; i++)
    symbol->elements[i]->accept(*this);

  /* This object has (inherits) the same candidate datatypes as the last il_instruction */
  symbol->candidate_datatypes = symbol->elements[symbol->n-1]->candidate_datatypes;
  
  if (debug) std::cout << "simple_instr_list_c [" << symbol->candidate_datatypes.size() << "] result.\n";
  return NULL;
}




// SYM_REF1(il_simple_instruction_c, il_simple_instruction, symbol_c *prev_il_instruction;)
void *fill_candidate_datatypes_c::visit(il_simple_instruction_c *symbol) {
  if (symbol->prev_il_instruction.size() > 1) ERROR; /* There should be no labeled insructions inside an IL expression! */
  if (symbol->prev_il_instruction.size() == 0)  prev_il_instruction = NULL;
  else                                          prev_il_instruction = symbol->prev_il_instruction[0];
  symbol->il_simple_instruction->accept(*this);
  prev_il_instruction = NULL;

  /* This object has (inherits) the same candidate datatypes as the il_simple_instruction it points to */
  symbol->candidate_datatypes = symbol->il_simple_instruction->candidate_datatypes;
  return NULL;
}


/*
    void *visit(il_param_list_c *symbol);
    void *visit(il_param_assignment_c *symbol);
    void *visit(il_param_out_assignment_c *symbol);
*/

/*******************/
/* B 2.2 Operators */
/*******************/
void *fill_candidate_datatypes_c::visit(LD_operator_c *symbol) {
	for(unsigned int i = 0; i < il_operand->candidate_datatypes.size(); i++) {
		add_datatype_to_candidate_list(symbol, il_operand->candidate_datatypes[i]);
	}
	if (debug) std::cout << "LD [" <<  il_operand->candidate_datatypes.size() << "] ==> "  << symbol->candidate_datatypes.size() << " result.\n";
	return NULL;
}

void *fill_candidate_datatypes_c::visit(LDN_operator_c *symbol) {
	for(unsigned int i = 0; i < il_operand->candidate_datatypes.size(); i++) {
		if      (is_ANY_BIT_compatible(il_operand->candidate_datatypes[i]))
			add_datatype_to_candidate_list(symbol, il_operand->candidate_datatypes[i]);
	}
	if (debug) std::cout << "LDN [" << il_operand->candidate_datatypes.size() << "] ==> "  << symbol->candidate_datatypes.size() << " result.\n";
	return NULL;
}

void *fill_candidate_datatypes_c::visit(ST_operator_c *symbol) {
	symbol_c *prev_instruction_type, *operand_type;

	if (NULL == prev_il_instruction) return NULL;
	for (unsigned int i = 0; i < prev_il_instruction->candidate_datatypes.size(); i++) {
		for(unsigned int j = 0; j < il_operand->candidate_datatypes.size(); j++) {
			prev_instruction_type = prev_il_instruction->candidate_datatypes[i];
			operand_type = il_operand->candidate_datatypes[j];
			if (is_type_equal(prev_instruction_type, operand_type))
				add_datatype_to_candidate_list(symbol, prev_instruction_type);
		}
	}
	if (debug) std::cout << "ST [" << prev_il_instruction->candidate_datatypes.size() << "," << il_operand->candidate_datatypes.size() << "] ==> "  << symbol->candidate_datatypes.size() << " result.\n";
	return NULL;
}

void *fill_candidate_datatypes_c::visit(STN_operator_c *symbol) {
	symbol_c *prev_instruction_type, *operand_type;

	if (NULL == prev_il_instruction) return NULL;
	for (unsigned int i = 0; i < prev_il_instruction->candidate_datatypes.size(); i++) {
		for(unsigned int j = 0; j < il_operand->candidate_datatypes.size(); j++) {
			prev_instruction_type = prev_il_instruction->candidate_datatypes[i];
			operand_type = il_operand->candidate_datatypes[j];
			if (is_type_equal(prev_instruction_type,operand_type) && is_ANY_BIT_compatible(operand_type))
				add_datatype_to_candidate_list(symbol, prev_instruction_type);
		}
	}
	if (debug) std::cout << "STN [" << prev_il_instruction->candidate_datatypes.size() << "," << il_operand->candidate_datatypes.size() << "] ==> "  << symbol->candidate_datatypes.size() << " result.\n";
	return NULL;
}

void *fill_candidate_datatypes_c::visit(NOT_operator_c *symbol) {
	/* NOTE: the standard allows syntax in which the NOT operator is followed by an optional <il_operand>
	 *              NOT [<il_operand>]
	 *       However, it does not define the semantic of the NOT operation when the <il_operand> is specified.
	 *       We therefore consider it an error if an il_operand is specified!
	 *       We do not need to generate an error message. This error will be caught somewhere else!
	 */
	if (NULL == prev_il_instruction) return NULL;
	for (unsigned int i = 0; i < prev_il_instruction->candidate_datatypes.size(); i++) {
		if (is_ANY_BIT_compatible(prev_il_instruction->candidate_datatypes[i]))
			add_datatype_to_candidate_list(symbol, prev_il_instruction->candidate_datatypes[i]);
	}
	if (debug) std::cout <<  "NOT_operator [" << prev_il_instruction->candidate_datatypes.size() << "] ==> "  << symbol->candidate_datatypes.size() << " result.\n";
	return NULL;
}


void *fill_candidate_datatypes_c::visit(S_operator_c *symbol) {
  /* TODO: what if this is a FB call ?? */
	symbol_c *prev_instruction_type, *operand_type;

	if (NULL == prev_il_instruction) return NULL;
	for (unsigned int i = 0; i < prev_il_instruction->candidate_datatypes.size(); i++) {
		for(unsigned int j = 0; j < il_operand->candidate_datatypes.size(); j++) {
			prev_instruction_type = prev_il_instruction->candidate_datatypes[i];
			operand_type = il_operand->candidate_datatypes[j];
			/* TODO: I believe the following is wrong! The data types of prev_instruction_type and operand_type DO NOT have to be equal.
			 * the prev_instruction_type MUST be BOOL compatible.
			 * I am not too sure about operand_type, does it have to be BOOL compatible, or can it be ANY_BIT compatible? Must check!
			 */
			if (is_type_equal(prev_instruction_type,operand_type) && is_ANY_BOOL_compatible(operand_type))
				add_datatype_to_candidate_list(symbol, prev_instruction_type);
		}
	}
	if (debug) std::cout << "S [" << prev_il_instruction->candidate_datatypes.size() << "," << il_operand->candidate_datatypes.size() << "] ==> "  << symbol->candidate_datatypes.size() << " result.\n";
	return NULL;
}


void *fill_candidate_datatypes_c::visit(R_operator_c *symbol) {
  /* TODO: what if this is a FB call ?? */
	symbol_c *prev_instruction_type, *operand_type;

	if (NULL == prev_il_instruction) return NULL;
	for (unsigned int i = 0; i < prev_il_instruction->candidate_datatypes.size(); i++) {
		for(unsigned int j = 0; j < il_operand->candidate_datatypes.size(); j++) {
			prev_instruction_type = prev_il_instruction->candidate_datatypes[i];
			operand_type = il_operand->candidate_datatypes[j];
			/* TODO: I believe the following is wrong! The data types of prev_instruction_type and operand_type DO NOT have to be equal.
			 * the prev_instruction_type MUST be BOOL compatible.
			 * I am not too sure about operand_type, does it have to be BOOL compatible, or can it be ANY_BIT compatible? Must check!
			 */
			if (is_type_equal(prev_instruction_type,operand_type) && is_ANY_BOOL_compatible(operand_type))
				add_datatype_to_candidate_list(symbol, prev_instruction_type);
		}
	}
	if (debug) std::cout << "R [" << prev_il_instruction->candidate_datatypes.size() << "," << il_operand->candidate_datatypes.size() << "] ==> "  << symbol->candidate_datatypes.size() << " result.\n";
	return NULL;
}


void *fill_candidate_datatypes_c::visit( S1_operator_c  *symbol) {return handle_implicit_il_fb_call(symbol,  "S1", symbol->called_fb_declaration);}
void *fill_candidate_datatypes_c::visit( R1_operator_c  *symbol) {return handle_implicit_il_fb_call(symbol,  "R1", symbol->called_fb_declaration);}
void *fill_candidate_datatypes_c::visit( CLK_operator_c *symbol) {return handle_implicit_il_fb_call(symbol, "CLK", symbol->called_fb_declaration);}
void *fill_candidate_datatypes_c::visit( CU_operator_c  *symbol) {return handle_implicit_il_fb_call(symbol,  "CU", symbol->called_fb_declaration);}
void *fill_candidate_datatypes_c::visit( CD_operator_c  *symbol) {return handle_implicit_il_fb_call(symbol,  "CD", symbol->called_fb_declaration);}
void *fill_candidate_datatypes_c::visit( PV_operator_c  *symbol) {return handle_implicit_il_fb_call(symbol,  "PV", symbol->called_fb_declaration);}
void *fill_candidate_datatypes_c::visit( IN_operator_c  *symbol) {return handle_implicit_il_fb_call(symbol,  "IN", symbol->called_fb_declaration);}
void *fill_candidate_datatypes_c::visit( PT_operator_c  *symbol) {return handle_implicit_il_fb_call(symbol,  "PT", symbol->called_fb_declaration);}

void *fill_candidate_datatypes_c::visit( AND_operator_c *symbol) {return handle_binary_operator(widen_AND_table, symbol, prev_il_instruction, il_operand);}
void *fill_candidate_datatypes_c::visit(  OR_operator_c *symbol) {return handle_binary_operator( widen_OR_table, symbol, prev_il_instruction, il_operand);}
void *fill_candidate_datatypes_c::visit( XOR_operator_c *symbol) {return handle_binary_operator(widen_XOR_table, symbol, prev_il_instruction, il_operand);}
void *fill_candidate_datatypes_c::visit(ANDN_operator_c *symbol) {return handle_binary_operator(widen_AND_table, symbol, prev_il_instruction, il_operand);}
void *fill_candidate_datatypes_c::visit( ORN_operator_c *symbol) {return handle_binary_operator( widen_OR_table, symbol, prev_il_instruction, il_operand);}
void *fill_candidate_datatypes_c::visit(XORN_operator_c *symbol) {return handle_binary_operator(widen_XOR_table, symbol, prev_il_instruction, il_operand);}

void *fill_candidate_datatypes_c::visit( ADD_operator_c *symbol) {return handle_binary_operator(widen_ADD_table, symbol, prev_il_instruction, il_operand);}
void *fill_candidate_datatypes_c::visit( SUB_operator_c *symbol) {return handle_binary_operator(widen_SUB_table, symbol, prev_il_instruction, il_operand);}
void *fill_candidate_datatypes_c::visit( MUL_operator_c *symbol) {return handle_binary_operator(widen_MUL_table, symbol, prev_il_instruction, il_operand);}
void *fill_candidate_datatypes_c::visit( DIV_operator_c *symbol) {return handle_binary_operator(widen_DIV_table, symbol, prev_il_instruction, il_operand);}
void *fill_candidate_datatypes_c::visit( MOD_operator_c *symbol) {return handle_binary_operator(widen_MOD_table, symbol, prev_il_instruction, il_operand);}

void *fill_candidate_datatypes_c::visit(  GT_operator_c *symbol) {return handle_binary_operator(widen_CMP_table, symbol, prev_il_instruction, il_operand);}
void *fill_candidate_datatypes_c::visit(  GE_operator_c *symbol) {return handle_binary_operator(widen_CMP_table, symbol, prev_il_instruction, il_operand);}
void *fill_candidate_datatypes_c::visit(  EQ_operator_c *symbol) {return handle_binary_operator(widen_CMP_table, symbol, prev_il_instruction, il_operand);}
void *fill_candidate_datatypes_c::visit(  LT_operator_c *symbol) {return handle_binary_operator(widen_CMP_table, symbol, prev_il_instruction, il_operand);}
void *fill_candidate_datatypes_c::visit(  LE_operator_c *symbol) {return handle_binary_operator(widen_CMP_table, symbol, prev_il_instruction, il_operand);}
void *fill_candidate_datatypes_c::visit(  NE_operator_c *symbol) {return handle_binary_operator(widen_CMP_table, symbol, prev_il_instruction, il_operand);}



void *fill_candidate_datatypes_c::handle_conditional_il_flow_control_operator(symbol_c *symbol) {
	if (NULL == prev_il_instruction) return NULL;
	for (unsigned int i = 0; i < prev_il_instruction->candidate_datatypes.size(); i++) {
		if (is_ANY_BOOL_compatible(prev_il_instruction->candidate_datatypes[i]))
			add_datatype_to_candidate_list(symbol, prev_il_instruction->candidate_datatypes[i]);
	}
	return NULL;
}

void *fill_candidate_datatypes_c::visit(  CAL_operator_c *symbol) {if (NULL != prev_il_instruction) symbol->candidate_datatypes = prev_il_instruction->candidate_datatypes; return NULL;}
void *fill_candidate_datatypes_c::visit(  RET_operator_c *symbol) {if (NULL != prev_il_instruction) symbol->candidate_datatypes = prev_il_instruction->candidate_datatypes; return NULL;}
void *fill_candidate_datatypes_c::visit(  JMP_operator_c *symbol) {if (NULL != prev_il_instruction) symbol->candidate_datatypes = prev_il_instruction->candidate_datatypes; return NULL;}
void *fill_candidate_datatypes_c::visit( CALC_operator_c *symbol) {return handle_conditional_il_flow_control_operator(symbol);}
void *fill_candidate_datatypes_c::visit(CALCN_operator_c *symbol) {return handle_conditional_il_flow_control_operator(symbol);}
void *fill_candidate_datatypes_c::visit( RETC_operator_c *symbol) {return handle_conditional_il_flow_control_operator(symbol);}
void *fill_candidate_datatypes_c::visit(RETCN_operator_c *symbol) {return handle_conditional_il_flow_control_operator(symbol);}
void *fill_candidate_datatypes_c::visit( JMPC_operator_c *symbol) {return handle_conditional_il_flow_control_operator(symbol);}
void *fill_candidate_datatypes_c::visit(JMPCN_operator_c *symbol) {return handle_conditional_il_flow_control_operator(symbol);}




/* Symbol class handled together with function call checks */
// void *visit(il_assign_operator_c *symbol, variable_name);
/* Symbol class handled together with function call checks */
// void *visit(il_assign_operator_c *symbol, option, variable_name);

/***************************************/
/* B.3 - Language ST (Structured Text) */
/***************************************/
/***********************/
/* B 3.1 - Expressions */
/***********************/
void *fill_candidate_datatypes_c::visit(   or_expression_c  *symbol) {return handle_binary_expression(widen_OR_table,  symbol, symbol->l_exp, symbol->r_exp);}
void *fill_candidate_datatypes_c::visit(   xor_expression_c *symbol) {return handle_binary_expression(widen_XOR_table, symbol, symbol->l_exp, symbol->r_exp);}
void *fill_candidate_datatypes_c::visit(   and_expression_c *symbol) {return handle_binary_expression(widen_AND_table, symbol, symbol->l_exp, symbol->r_exp);}

void *fill_candidate_datatypes_c::visit(   equ_expression_c *symbol) {return handle_binary_expression(widen_CMP_table, symbol, symbol->l_exp, symbol->r_exp);}
void *fill_candidate_datatypes_c::visit(notequ_expression_c *symbol) {return handle_binary_expression(widen_CMP_table, symbol, symbol->l_exp, symbol->r_exp);}
void *fill_candidate_datatypes_c::visit(    lt_expression_c *symbol) {return handle_binary_expression(widen_CMP_table, symbol, symbol->l_exp, symbol->r_exp);}
void *fill_candidate_datatypes_c::visit(    gt_expression_c *symbol) {return handle_binary_expression(widen_CMP_table, symbol, symbol->l_exp, symbol->r_exp);}
void *fill_candidate_datatypes_c::visit(    le_expression_c *symbol) {return handle_binary_expression(widen_CMP_table, symbol, symbol->l_exp, symbol->r_exp);}
void *fill_candidate_datatypes_c::visit(    ge_expression_c *symbol) {return handle_binary_expression(widen_CMP_table, symbol, symbol->l_exp, symbol->r_exp);}


/* The following code is correct when handling the addition of 2 symbolic_variables
 * In this case, adding two variables (e.g. USINT_var1 + USINT_var2) will always yield
 * the same data type, even if the result of the adition could not fit inside the same
 * data type (due to overflowing)
 *
 * However, when adding two literals (e.g. USINT#42 + USINT#3)
 * we should be able to detect overflows of the result, and therefore not consider
 * that the result may be of type USINT.
 * Currently we do not yet detect these overflows, and allow handling the sum of two USINTs
 * as always resulting in an USINT, even in the following expression
 * (USINT#65535 + USINT#2).
 *
 * In the future we can add some code to reduce
 * all the expressions that are based on literals into the resulting literal
 * value (maybe some visitor class that will run before or after data type
 * checking). Since this class will have to be very careful to make sure it implements the same mathematical
 * details (e.g. how to round and truncate numbers) as defined in IEC 61131-3, we will leave this to the future.
 * Also, the question will arise if we should also replace calls to standard
 * functions if the input parameters are all literals (e.g. ADD(42, 42)). This
 * means this class will be more difficult than it appears at first.
 */
void *fill_candidate_datatypes_c::visit(  add_expression_c *symbol) {return handle_binary_expression(widen_ADD_table,  symbol, symbol->l_exp, symbol->r_exp);}
void *fill_candidate_datatypes_c::visit(  sub_expression_c *symbol) {return handle_binary_expression(widen_SUB_table,  symbol, symbol->l_exp, symbol->r_exp);}
void *fill_candidate_datatypes_c::visit(  mul_expression_c *symbol) {return handle_binary_expression(widen_MUL_table,  symbol, symbol->l_exp, symbol->r_exp);}
void *fill_candidate_datatypes_c::visit(  div_expression_c *symbol) {return handle_binary_expression(widen_DIV_table,  symbol, symbol->l_exp, symbol->r_exp);}
void *fill_candidate_datatypes_c::visit(  mod_expression_c *symbol) {return handle_binary_expression(widen_MOD_table,  symbol, symbol->l_exp, symbol->r_exp);}
void *fill_candidate_datatypes_c::visit(power_expression_c *symbol) {return handle_binary_expression(widen_EXPT_table, symbol, symbol->l_exp, symbol->r_exp);}


void *fill_candidate_datatypes_c::visit(neg_expression_c *symbol) {
  /* NOTE: The standard defines the syntax for this 'negation' operation, but
   *       does not define the its semantics.
   *
   *       We could be tempted to consider that the semantics of the
   *       'negation' operation are similar/identical to the semantics of the 
   *       SUB expression/operation. This would include assuming that the
   *       possible datatypes for the 'negation' operation is also
   *       the same as those for the SUB expression/operation, namely ANY_MAGNITUDE.
   *
   *       However, this would then mean that the following ST code would be 
   *       syntactically and semantically correct:
   *       uint_var := - (uint_var);
   *
   *       According to the standard, the above code should result in a 
   *       runtime error, when we try to apply a negative value to the
   *       UINT typed variable 'uint_var'.
   *
   *       It is much easier for the compiler to detect this at compile time,
   *       and it is probably safer to the resulting code too.
   *
   *       To detect these tyes of errors at compile time, the easisest solution
   *       is to only allow ANY_NUM datatytpes that are signed.
   *        So, that is what we do here!
   */
	symbol->exp->accept(*this);
	for (unsigned int i = 0; i < symbol->exp->candidate_datatypes.size(); i++) {
		if (is_ANY_signed_MAGNITUDE_compatible(symbol->exp->candidate_datatypes[i]))
			add_datatype_to_candidate_list(symbol, symbol->exp->candidate_datatypes[i]);
	}
	if (debug) std::cout << "neg [" << symbol->exp->candidate_datatypes.size() << "] ==> "  << symbol->candidate_datatypes.size() << " result.\n";
	return NULL;
}


void *fill_candidate_datatypes_c::visit(not_expression_c *symbol) {
	symbol->exp->accept(*this);
	for (unsigned int i = 0; i < symbol->exp->candidate_datatypes.size(); i++) {
		if      (is_ANY_BIT_compatible(symbol->exp->candidate_datatypes[i]))
			add_datatype_to_candidate_list(symbol, symbol->exp->candidate_datatypes[i]);
	}
	if (debug) std::cout << "not [" << symbol->exp->candidate_datatypes.size() << "] ==> "  << symbol->candidate_datatypes.size() << " result.\n";
	return NULL;
}


void *fill_candidate_datatypes_c::visit(function_invocation_c *symbol) {
	if      (NULL != symbol->formal_param_list)        symbol->   formal_param_list->accept(*this);
	else if (NULL != symbol->nonformal_param_list)     symbol->nonformal_param_list->accept(*this);
	else ERROR;

	generic_function_call_t fcall_param = {
		/* fcall_param.function_name               = */ symbol->function_name,
		/* fcall_param.nonformal_operand_list      = */ symbol->nonformal_param_list,
		/* fcall_param.formal_operand_list         = */ symbol->formal_param_list,
		/* enum {POU_FB, POU_function} POU_type    = */ generic_function_call_t::POU_function,
		/* fcall_param.candidate_functions         = */ symbol->candidate_functions,
		/* fcall_param.called_function_declaration = */ symbol->called_function_declaration,
		/* fcall_param.extensible_param_count      = */ symbol->extensible_param_count
	};
	handle_function_call(symbol, fcall_param);

	if (debug) std::cout << "function_invocation_c [" << symbol->candidate_datatypes.size() << "] result.\n";
	return NULL;
}



/********************/
/* B 3.2 Statements */
/********************/
// SYM_LIST(statement_list_c)
/* The visitor of the base class search_visitor_c will handle calling each instruction in the list.
 * We do not need to do anything here...
 */
// void *fill_candidate_datatypes_c::visit(statement_list_c *symbol)


/*********************************/
/* B 3.2.1 Assignment Statements */
/*********************************/
void *fill_candidate_datatypes_c::visit(assignment_statement_c *symbol) {
	symbol_c *left_type, *right_type;

	symbol->l_exp->accept(*this);
	symbol->r_exp->accept(*this);
	for (unsigned int i = 0; i < symbol->l_exp->candidate_datatypes.size(); i++) {
		for(unsigned int j = 0; j < symbol->r_exp->candidate_datatypes.size(); j++) {
			left_type = symbol->l_exp->candidate_datatypes[i];
			right_type = symbol->r_exp->candidate_datatypes[j];
			if (is_type_equal(left_type, right_type))
				add_datatype_to_candidate_list(symbol, left_type);
		}
	}
	if (debug) std::cout << ":= [" << symbol->l_exp->candidate_datatypes.size() << "," << symbol->r_exp->candidate_datatypes.size() << "] ==> "  << symbol->candidate_datatypes.size() << " result.\n";
	return NULL;
}

/*****************************************/
/* B 3.2.2 Subprogram Control Statements */
/*****************************************/
void *fill_candidate_datatypes_c::visit(fb_invocation_c *symbol) {
	symbol_c *fb_type_id = search_varfb_instance_type->get_basetype_id(symbol->fb_name);
	/* Although a call to a non-declared FB is a semantic error, this is currently caught by stage 2! */
	if (NULL == fb_type_id) ERROR;

	function_block_declaration_c *fb_decl = function_block_type_symtable.find_value(fb_type_id);
	if (function_block_type_symtable.end_value() == fb_decl) 
		/* The fb_name not the name of a FB instance. Most probably it is the name of a variable of some other type. */
		fb_decl = NULL;

	/* Although a call to a non-declared FB is a semantic error, this is currently caught by stage 2! */
	if (NULL == fb_decl) ERROR;
	
	if (symbol->   formal_param_list != NULL) symbol->formal_param_list->accept(*this);
	if (symbol->nonformal_param_list != NULL) symbol->nonformal_param_list->accept(*this);

	/* The print_datatypes_error_c does not rely on this called_fb_declaration pointer being != NULL to conclude that
	 * we have a datat type incompatibility error, so setting it to the correct fb_decl is actually safe,
	 * as the compiler will never reach the compilation stage!
	 */
	symbol->called_fb_declaration = fb_decl;

	if (debug) std::cout << "FB [] ==> "  << symbol->candidate_datatypes.size() << " result.\n";
	return NULL;
}



/********************************/
/* B 3.2.3 Selection Statements */
/********************************/
void *fill_candidate_datatypes_c::visit(if_statement_c *symbol) {
	symbol->expression->accept(*this);
	if (NULL != symbol->statement_list)
		symbol->statement_list->accept(*this);
	if (NULL != symbol->elseif_statement_list)
		symbol->elseif_statement_list->accept(*this);
	if (NULL != symbol->else_statement_list)
		symbol->else_statement_list->accept(*this);
	return NULL;
}


void *fill_candidate_datatypes_c::visit(elseif_statement_c *symbol) {
	symbol->expression->accept(*this);
	if (NULL != symbol->statement_list)
		symbol->statement_list->accept(*this);
	return NULL;
}

/* CASE expression OF case_element_list ELSE statement_list END_CASE */
// SYM_REF3(case_statement_c, expression, case_element_list, statement_list)
void *fill_candidate_datatypes_c::visit(case_statement_c *symbol) {
	symbol->expression->accept(*this);
	if (NULL != symbol->case_element_list)
		symbol->case_element_list->accept(*this);
	if (NULL != symbol->statement_list)
		symbol->statement_list->accept(*this);
	return NULL;
}


/* helper symbol for case_statement */
// SYM_LIST(case_element_list_c)
/* NOTE: visitor method for case_element_list_c is not required since we inherit from iterator_visitor_c */

/*  case_list ':' statement_list */
// SYM_REF2(case_element_c, case_list, statement_list)
/* NOTE: visitor method for case_element_c is not required since we inherit from iterator_visitor_c */

// SYM_LIST(case_list_c)
/* NOTE: visitor method for case_list_c is not required since we inherit from iterator_visitor_c */

/********************************/
/* B 3.2.4 Iteration Statements */
/********************************/

void *fill_candidate_datatypes_c::visit(for_statement_c *symbol) {
	symbol->control_variable->accept(*this);
	symbol->beg_expression->accept(*this);
	symbol->end_expression->accept(*this);
	if (NULL != symbol->by_expression)
		symbol->by_expression->accept(*this);
	if (NULL != symbol->statement_list)
		symbol->statement_list->accept(*this);
	return NULL;
}


void *fill_candidate_datatypes_c::visit(while_statement_c *symbol) {
	symbol->expression->accept(*this);
	if (NULL != symbol->statement_list)
		symbol->statement_list->accept(*this);
	return NULL;
}


void *fill_candidate_datatypes_c::visit(repeat_statement_c *symbol) {
	symbol->expression->accept(*this);
	if (NULL != symbol->statement_list)
		symbol->statement_list->accept(*this);
	return NULL;
}