stage3/narrow_candidate_datatypes.cc
changeset 451 a1b87eb155e4
parent 450 eb1b28acec2e
child 452 79ac274d1cc4
equal deleted inserted replaced
450:eb1b28acec2e 451:a1b87eb155e4
   114 		symbol_c *desired_datatype = base_type(fp_iterator.param_type());
   114 		symbol_c *desired_datatype = base_type(fp_iterator.param_type());
   115 		if ((NULL != param_name) && (NULL == desired_datatype)) ERROR;
   115 		if ((NULL != param_name) && (NULL == desired_datatype)) ERROR;
   116 		if ((NULL == param_name) && (NULL != desired_datatype)) ERROR;
   116 		if ((NULL == param_name) && (NULL != desired_datatype)) ERROR;
   117 
   117 
   118 		/* NOTE: When we are handling a nonformal function call made from IL, the first parameter is the 'default' or 'current'
   118 		/* NOTE: When we are handling a nonformal function call made from IL, the first parameter is the 'default' or 'current'
   119 		 *       il value. However, a pointer to the prev_il_instruction is pre-pended into the operand list (done in fill_candidate_datatypes_c,
   119 		 *       il value. However, a pointer to a copy of the prev_il_instruction is pre-pended into the operand list, so 
   120 		 *       and later undone in print_datatypes_error_c - this class is run after the first, and before the latter!), so 
       
   121 		 *       the call 
   120 		 *       the call 
   122 		 *       call_param_value->accept(*this);
   121 		 *       call_param_value->accept(*this);
   123 		 *       may actually be calling an object of the il_instruction_c class.
   122 		 *       may actually be calling an object of the base symbol_c .
   124 		 *       If that is the case, that same il_instruction_c object will be called again inside the for() loop
       
   125 		 *       of void *narrow_candidate_datatypes_c::visit(instruction_list_c *symbol);
       
   126 		 *       Since this is not safe (the prev_il_instruction variable will be overwritten with a wrong value!), 
       
   127 		 *       we only do the recursive call if this parameter does not point to a il_instruction_c object.
       
   128 		 *       Actually, it is easier to check whether it is not the same as the prev_il_instruction.
       
   129 		 */
   123 		 */
   130 		set_datatype(desired_datatype, call_param_value);
   124 		set_datatype(desired_datatype, call_param_value);
   131 		if (call_param_value != prev_il_instruction)
   125 		call_param_value->accept(*this);
   132 			call_param_value->accept(*this);
       
   133 
   126 
   134 		if (NULL != param_name) 
   127 		if (NULL != param_name) 
   135 			if (extensible_parameter_highest_index < fp_iterator.extensible_param_index())
   128 			if (extensible_parameter_highest_index < fp_iterator.extensible_param_index())
   136 				extensible_parameter_highest_index = fp_iterator.extensible_param_index();
   129 				extensible_parameter_highest_index = fp_iterator.extensible_param_index();
   137 	}
   130 	}
   180 		if ((NULL == param_name) && (NULL != desired_datatype)) ERROR;
   173 		if ((NULL == param_name) && (NULL != desired_datatype)) ERROR;
   181 
   174 
   182 		/* set the desired data type for this parameter */
   175 		/* set the desired data type for this parameter */
   183 		set_datatype(desired_datatype, call_param_value);
   176 		set_datatype(desired_datatype, call_param_value);
   184 		/* And recursively call that parameter/expression, so it can propagate that info */
   177 		/* And recursively call that parameter/expression, so it can propagate that info */
   185 		/* However, when handling an implicit IL FB call, the first parameter is fake, and points to the prev_il_instruction.
   178 		/* However, when handling an implicit IL FB call, the first parameter is fake (a copy of the prev_il_instruction).
   186 		 * In this case, we do not propagate this info down, as that prev_il_instruction will be called later
   179 		 * so the call call_param_value->accept(*this) may actually be calling an object of the base symbol_c .
   187 		 * (remember, we iterate backwards through the IL instructions) by the for() loop in the instruction_list_c.
       
   188 		 */
   180 		 */
   189 		if (call_param_value != prev_il_instruction)
   181 		call_param_value->accept(*this);
   190 			call_param_value->accept(*this);
       
   191 
   182 
   192 		if (NULL != param_name) 
   183 		if (NULL != param_name) 
   193 			if (extensible_parameter_highest_index < fp_iterator.extensible_param_index())
   184 			if (extensible_parameter_highest_index < fp_iterator.extensible_param_index())
   194 				extensible_parameter_highest_index = fp_iterator.extensible_param_index();
   185 				extensible_parameter_highest_index = fp_iterator.extensible_param_index();
   195 	}
   186 	}
   277 		 */
   268 		 */
   278 		return;
   269 		return;
   279 	if (NULL == prev_il_instruction) {
   270 	if (NULL == prev_il_instruction) {
   280 		/* This IL implicit FB call (e.g. CLK ton_var) is not preceded by another IL instruction
   271 		/* This IL implicit FB call (e.g. CLK ton_var) is not preceded by another IL instruction
   281 		 * (or list of instructions) that will set the IL current/default value.
   272 		 * (or list of instructions) that will set the IL current/default value.
   282 		 * We cannot proceed verifying type compatibility of something that does not ecist.
   273 		 * We cannot proceed verifying type compatibility of something that does not exist.
   283 		 */
   274 		 */
   284 		return;
   275 		return;
   285 	}
   276 	}
   286 
   277 
       
   278 	/* The value being passed to the 'param_name' parameter is actually the prev_il_instruction.
       
   279 	 * However, we do not place that object directly in the fake il_param_list_c that we will be
       
   280 	 * creating, since the visit(il_fb_call_c *) method will recursively call every object in that list.
       
   281 	 * The il_prev_intruction object will be visited once we have handled this implici IL FB call
       
   282 	 * (called from the instruction_list_c for() loop that works backwards). We DO NOT want to visit it twice.
       
   283 	 * (Anyway, if we let the visit(il_fb_call_c *) recursively visit the current prev_il_instruction, this pointer
       
   284 	 * would be changed to the IL instruction coming before the current prev_il_instruction! => things would get all messed up!)
       
   285 	 * The easiest way to work around this is to simply use a new object, and copy the relevant details to that object!
       
   286 	 */
       
   287 	symbol_c param_value = *prev_il_instruction;
       
   288 	
   287 	identifier_c variable_name(param_name);
   289 	identifier_c variable_name(param_name);
   288 	// SYM_REF1(il_assign_operator_c, variable_name)
   290 	// SYM_REF1(il_assign_operator_c, variable_name)
   289 	il_assign_operator_c il_assign_operator(&variable_name);  
   291 	il_assign_operator_c il_assign_operator(&variable_name);  
   290 	// SYM_REF3(il_param_assignment_c, il_assign_operator, il_operand, simple_instr_list)
   292 	// SYM_REF3(il_param_assignment_c, il_assign_operator, il_operand, simple_instr_list)
   291 	il_param_assignment_c il_param_assignment(&il_assign_operator, prev_il_instruction/*il_operand*/, NULL);
   293 	il_param_assignment_c il_param_assignment(&il_assign_operator, &param_value/*il_operand*/, NULL);
   292 	il_param_list_c il_param_list;
   294 	il_param_list_c il_param_list;
   293 	il_param_list.add_element(&il_param_assignment);
   295 	il_param_list.add_element(&il_param_assignment);
   294 	// SYM_REF4(il_fb_call_c, il_call_operator, fb_name, il_operand_list, il_param_list, symbol_c *called_fb_declaration)
   296 	// SYM_REF4(il_fb_call_c, il_call_operator, fb_name, il_operand_list, il_param_list, symbol_c *called_fb_declaration)
   295 	il_fb_call_c il_fb_call(NULL, il_operand, NULL, &il_param_list);
   297 	il_fb_call_c il_fb_call(NULL, il_operand, NULL, &il_param_list);
   296 	
   298 	
   301 	 *
   303 	 *
   302 	 * The above will be done by the visit(il_fb_call_c *) method, so we must make sure to
   304 	 * The above will be done by the visit(il_fb_call_c *) method, so we must make sure to
   303 	 * correctly set up the il_fb_call.datatype variable!
   305 	 * correctly set up the il_fb_call.datatype variable!
   304 	 */
   306 	 */
   305 	copy_candidate_datatype_list(il_instruction/*from*/, &il_fb_call/*to*/);
   307 	copy_candidate_datatype_list(il_instruction/*from*/, &il_fb_call/*to*/);
   306 	il_fb_call.datatype = il_instruction->datatype;
       
   307 	il_fb_call.accept(*this);
   308 	il_fb_call.accept(*this);
   308 	il_instruction->datatype = il_fb_call.datatype;
   309 	
       
   310 	/* set the required datatype of the previous IL instruction! */
       
   311 	/* NOTE:
       
   312 	 * When handling these implicit IL calls, the parameter_value being passed to the FB parameter
       
   313 	 * is actually the prev_il_instruction.
       
   314 	 * 
       
   315 	 * However, since the FB call does not change the value in the current/default IL variable, this value
       
   316 	 * must also be used ny the IL instruction coming after this FB call.
       
   317 	 *
       
   318 	 * This means that we have two consumers/users for the same value. 
       
   319 	 * We must therefore check whether the datatype required by the IL instructions following this FB call 
       
   320 	 * is the same as that required for the first parameter. If not, then we have a semantic error,
       
   321 	 * and we set it to NULL.
       
   322 	 *
       
   323 	 * However, we only do that if:
       
   324 	 *  - The IL instruction that comes after this IL FB call actually asked this FB call for a specific 
       
   325 	 *     datatype in the current/default vairable, once this IL FB call returns.
       
   326 	 *     However, sometimes, (for e.g., this FB call is the last in the IL list) the subsequent FB to not aks this
       
   327 	 *     FB call for any datatype. In that case, then the datatype required to pass to the first parameter of the
       
   328 	 *     FB call must be left unchanged!
       
   329 	 */
       
   330 // 	if (NULL != prev_il_instruction) /* already checked above! */
       
   331 		if (is_type_equal(param_value.datatype, il_instruction->datatype)) {
       
   332 			prev_il_instruction->datatype = param_value.datatype;
       
   333 		} else {
       
   334 			prev_il_instruction->datatype = NULL;
       
   335 		}
       
   336 
   309 }
   337 }
   310 
   338 
   311 
   339 
   312 /* a helper function... */
   340 /* a helper function... */
   313 symbol_c *narrow_candidate_datatypes_c::base_type(symbol_c *symbol) {
   341 symbol_c *narrow_candidate_datatypes_c::base_type(symbol_c *symbol) {
   491 
   519 
   492 /* | function_name [il_operand_list] */
   520 /* | function_name [il_operand_list] */
   493 /* NOTE: The parameters 'called_function_declaration' and 'extensible_param_count' are used to pass data between the stage 3 and stage 4. */
   521 /* NOTE: The parameters 'called_function_declaration' and 'extensible_param_count' are used to pass data between the stage 3 and stage 4. */
   494 // SYM_REF2(il_function_call_c, function_name, il_operand_list, symbol_c *called_function_declaration; int extensible_param_count;)
   522 // SYM_REF2(il_function_call_c, function_name, il_operand_list, symbol_c *called_function_declaration; int extensible_param_count;)
   495 void *narrow_candidate_datatypes_c::visit(il_function_call_c *symbol) {
   523 void *narrow_candidate_datatypes_c::visit(il_function_call_c *symbol) {
       
   524 	/* The first parameter of a non formal function call in IL will be the 'current value' (i.e. the prev_il_instruction)
       
   525 	 * In order to be able to handle this without coding special cases, we will simply prepend that symbol
       
   526 	 * to the il_operand_list, and remove it after calling handle_function_call().
       
   527 	 * However, since handle_function_call() will be recursively calling all parameter, and we don't want
       
   528 	 * to do that for the prev_il_instruction (since it has already been visited by the fill_candidate_datatypes_c)
       
   529 	 * we create a new ____ symbol_c ____ object, and copy the relevant info to/from that object before/after
       
   530 	 * the call to handle_function_call().
       
   531 	 *
       
   532 	 * However, if no further paramters are given, then il_operand_list will be NULL, and we will
       
   533 	 * need to create a new object to hold the pointer to prev_il_instruction.
       
   534 	 * This change will also be undone later in print_datatypes_error_c.
       
   535 	 */
       
   536 	symbol_c param_value;
       
   537 	if (NULL == symbol->il_operand_list)  symbol->il_operand_list = new il_operand_list_c;
       
   538 	if (NULL == symbol->il_operand_list)  ERROR;
       
   539 
       
   540 	if (NULL != prev_il_instruction)
       
   541 		param_value = *prev_il_instruction;
       
   542 	((list_c *)symbol->il_operand_list)->insert_element(&param_value, 0);
       
   543 
   496 	generic_function_call_t fcall_param = {
   544 	generic_function_call_t fcall_param = {
   497 		/* fcall_param.function_name               = */ symbol->function_name,
   545 		/* fcall_param.function_name               = */ symbol->function_name,
   498 		/* fcall_param.nonformal_operand_list      = */ symbol->il_operand_list,
   546 		/* fcall_param.nonformal_operand_list      = */ symbol->il_operand_list,
   499 		/* fcall_param.formal_operand_list         = */ NULL,
   547 		/* fcall_param.formal_operand_list         = */ NULL,
   500 		/* enum {POU_FB, POU_function} POU_type    = */ generic_function_call_t::POU_function,
   548 		/* enum {POU_FB, POU_function} POU_type    = */ generic_function_call_t::POU_function,
   501 		/* fcall_param.candidate_functions         = */ symbol->candidate_functions,
   549 		/* fcall_param.candidate_functions         = */ symbol->candidate_functions,
   502 		/* fcall_param.called_function_declaration = */ symbol->called_function_declaration,
   550 		/* fcall_param.called_function_declaration = */ symbol->called_function_declaration,
   503 		/* fcall_param.extensible_param_count      = */ symbol->extensible_param_count
   551 		/* fcall_param.extensible_param_count      = */ symbol->extensible_param_count
   504 	};
   552 	};
   505 
   553 
   506 	/* The first parameter of a non formal function call in IL will be the 'current value' (i.e. the prev_il_instruction)
       
   507 	 * In order to be able to handle this without coding special cases, we simply prepend that symbol
       
   508 	 * to the il_operand_list (done in fill_candidate_datatypes_c), and remove it later (in the print_datatypes_error_c).
       
   509 	 *
       
   510 	 * Since this class is executed after fill_candidate_datatypes_c, and before print_datatypes_error_c,
       
   511 	 * the following code is actually correct!
       
   512 	 */
       
   513 	narrow_function_invocation(symbol, fcall_param);
   554 	narrow_function_invocation(symbol, fcall_param);
   514 	/* The desired datatype of the previous il instruction was already set by narrow_function_invocation() */
   555 	if (NULL != prev_il_instruction)
       
   556 		prev_il_instruction->datatype = param_value.datatype;
       
   557 
       
   558 	/* Undo the changes to the abstract syntax tree we made above... */
       
   559 	((list_c *)symbol->il_operand_list)->remove_element(0);
       
   560 	if (((list_c *)symbol->il_operand_list)->n == 0) {
       
   561 		/* if the list becomes empty, then that means that it did not exist before we made these changes, so we delete it! */
       
   562 		delete 	symbol->il_operand_list;
       
   563 		symbol->il_operand_list = NULL;
       
   564 	}
       
   565 
   515 	return NULL;
   566 	return NULL;
   516 }
   567 }
   517 
   568 
   518 /* MJS: Manuele, could you please not delete the following 2 lines of comments. They help me understand where this class is used
   569 /* MJS: Manuele, could you please not delete the following 2 lines of comments. They help me understand where this class is used
   519  *     and when it is created by bison - syntax parse, and how it can show up in the abstract syntax tree.
   570  *     and when it is created by bison - syntax parse, and how it can show up in the abstract syntax tree.
   535  * | il_call_operator prev_declared_fb_name '(' eol_list il_param_list ')'
   586  * | il_call_operator prev_declared_fb_name '(' eol_list il_param_list ')'
   536  */
   587  */
   537 /* 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 */
   588 /* 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 */
   538 // SYM_REF4(il_fb_call_c, il_call_operator, fb_name, il_operand_list, il_param_list, symbol_c *called_fb_declaration)
   589 // SYM_REF4(il_fb_call_c, il_call_operator, fb_name, il_operand_list, il_param_list, symbol_c *called_fb_declaration)
   539 void *narrow_candidate_datatypes_c::visit(il_fb_call_c *symbol) {
   590 void *narrow_candidate_datatypes_c::visit(il_fb_call_c *symbol) {
   540 	/* set the desired datatype of the previous il instruction */
       
   541 	/* NOTE 1:
       
   542 	 * A FB call does not return any datatype, but the IL instructions that come after this
       
   543 	 * FB call may require a specific datatype in the il current/default variable, 
       
   544 	 * so we must pass this information up to the IL instruction before the FB call, since it will
       
   545 	 * be that IL instruction that will be required to produce the desired dtataype.
       
   546 	 * NOTE 2:
       
   547 	 * Copying the required datatype must be done before calling narrow_[non]formal_call().
       
   548 	 * Note that this visit(il_fb_call_c *) method will be called from narrow_implicit_il_fb_call().
       
   549 	 * This means that we must also be able to handle implicit IL FB calls (e.g. CU counter_var)
       
   550 	 * correctly in this visitor class.
       
   551 	 * When handling these implicit IL calls, the parameter_value being passed to the FB parameter
       
   552 	 * (in the previous example, the 'CU' parameter) is actually the prev_il_instruction.
       
   553 	 * In this case, the prev_il_instruction->datatype will be set by the arrow_[non]formal_call(),
       
   554 	 * using the prama_value pointer to this same object.
       
   555 	 * If we were to have the following line of code after calling arrow_[non]formal_call(),
       
   556 	 * we would then be overwriting the datatype with the wrong value!
       
   557 	 */
       
   558 	if (NULL != prev_il_instruction)
       
   559 		prev_il_instruction->datatype = symbol->datatype;
       
   560 
       
   561 	/* Note: We do not use the symbol->called_fb_declaration value (set in fill_candidate_datatypes_c)
   591 	/* Note: We do not use the symbol->called_fb_declaration value (set in fill_candidate_datatypes_c)
   562 	 *       because we try to identify any other datatype errors in the expressions used in the 
   592 	 *       because we try to identify any other datatype errors in the expressions used in the 
   563 	 *       parameters to the FB call. e.g.
   593 	 *       parameters to the FB call. e.g.
   564 	 *          fb_var( 
   594 	 *          fb_var( 
   565 	 *             in1 := var1,
   595 	 *             in1 := var1,
   577 	/* Although a call to a non-declared FB is a semantic error, this is currently caught by stage 2! */
   607 	/* Although a call to a non-declared FB is a semantic error, this is currently caught by stage 2! */
   578 	if (NULL == fb_decl) ERROR;
   608 	if (NULL == fb_decl) ERROR;
   579 	if (NULL != symbol->il_operand_list)  narrow_nonformal_call(symbol, fb_decl);
   609 	if (NULL != symbol->il_operand_list)  narrow_nonformal_call(symbol, fb_decl);
   580 	if (NULL != symbol->  il_param_list)     narrow_formal_call(symbol, fb_decl);
   610 	if (NULL != symbol->  il_param_list)     narrow_formal_call(symbol, fb_decl);
   581 
   611 
   582 	/* NOTE:
   612 	/* An IL FB call does not change the default value in the current/default IL variable, so we pass the
   583 	 * When handling these implicit IL calls, the parameter_value being passed to the FB parameter
   613 	 * required datatype up to the previous IL instruction
   584 	 * (in the previous example, the 'CU' parameter) is actually the prev_il_instruction.
       
   585 	 * In this case, the prev_il_instruction->datatype will be set by the narrow_[non]formal_call(),
       
   586 	 * using the param_value pointer to this same object.
       
   587 	 * 
       
   588 	 * We must check that the datatype required by the IL instructions following this FB call 
       
   589 	 * is the same as that required for the first parameter. If not, then we have a semantic error,
       
   590 	 * and we set it to NULL.
       
   591 	 *
       
   592 	 * However, we only do that if:
       
   593 	 *  - There really exists an il_prev_instruction 
       
   594 	 *     (if it does not exist, it will be a semantic error. But that will be caught by the print_datatypes_error_c)
       
   595 	 *  - The IL instruction that comes after this IL FB call actually asked this FB call for a specific 
       
   596 	 *     datatype in the current/default vairable, once this IL FB call returns.
       
   597 	 *     However, sometimes, (for e.g., this FB call is the last in the IL list) the subsequent FB to not aks this
       
   598 	 *     FB call for any datatype. In that case, then the datatype required to pass to the first parameter of the
       
   599 	 *     FB call must be left unchanged!
       
   600 	 */
   614 	 */
   601 	if ((NULL != prev_il_instruction) && (NULL != symbol->datatype))
   615 	if (NULL != prev_il_instruction)
   602 		if (!is_type_equal(prev_il_instruction->datatype, symbol->datatype)) {
   616 		prev_il_instruction->datatype = symbol->datatype;
   603 			prev_il_instruction->datatype = NULL;
       
   604 		}
       
   605 	return NULL;
   617 	return NULL;
   606 }
   618 }
   607 
   619 
   608 
   620 
   609 /* | function_name '(' eol_list [il_param_list] ')' */
   621 /* | function_name '(' eol_list [il_param_list] ')' */