621 * 082 -> 82 |
621 * 082 -> 82 |
622 * +082 -> 82 |
622 * +082 -> 82 |
623 * -82 -> -82 |
623 * -82 -> -82 |
624 * -8_2 -> -82 |
624 * -8_2 -> -82 |
625 * -082 -> -82 |
625 * -082 -> -82 |
|
626 * |
|
627 * NOTE: since matiec supports arrays with a variable size (a non compliant IEC 61131-3 extension) |
|
628 * (e.g.: ARRAY [1..max] of INT, where max must be a constant variable) |
|
629 * the symbol passed to this function may also be a symbolic_variable |
|
630 * (or more correctly, a symbolic_constant_c). |
|
631 * In this case we simply return the string itself. |
626 */ |
632 */ |
627 #include <string.h> /* required for strlen() */ |
633 #include <string.h> /* required for strlen() */ |
628 static std::string normalize_integer(symbol_c *symbol) { |
634 static std::string normalize_subrange_limit(symbol_c *symbol) { |
629 integer_c *token = dynamic_cast<integer_c *>(symbol); |
635 // See if it is an integer... |
630 if (NULL == token) ERROR; |
636 integer_c *integer = dynamic_cast<integer_c *>(symbol); |
631 |
637 if (NULL != integer) { |
632 std::string str = ""; |
638 // handle it as an integer! |
633 bool leading_zero = true; |
639 std::string str = ""; |
634 unsigned int offset = 0; |
640 bool leading_zero = true; |
635 |
641 unsigned int offset = 0; |
636 // handle any possible leading '-' or '+' |
642 |
637 if (token->value[0] == '-') { |
643 // handle any possible leading '-' or '+' |
638 // '-' -> retained |
644 if (integer->value[0] == '-') { |
639 str += token->value[0]; |
645 // '-' -> retained |
640 offset++; |
646 str += integer->value[0]; |
641 } else if (token->value[0] == '+') |
647 offset++; |
642 // '+' -> skip, so '+8' and '8' will both result in '8' |
648 } else if (integer->value[0] == '+') |
643 offset++; |
649 // '+' -> skip, so '+8' and '8' will both result in '8' |
644 |
650 offset++; |
645 for (unsigned int i = offset; i < strlen(token->value); i++) { |
651 |
646 if (leading_zero && (token->value[i] != '0')) |
652 for (unsigned int i = offset; i < strlen(integer->value); i++) { |
647 leading_zero = false; |
653 if (leading_zero && (integer->value[i] != '0')) |
648 if (!leading_zero && token->value[i] != '_') |
654 leading_zero = false; |
649 str += token->value[i]; |
655 if (!leading_zero && integer->value[i] != '_') |
|
656 str += integer->value[i]; |
|
657 } |
|
658 return str; |
650 } |
659 } |
651 return str; |
660 |
|
661 // See if it is an sybolic_variable_c or symbolic_constant_c... |
|
662 /* NOTE: Remember that this is only needed if the subrange limit has not yet been |
|
663 * constant_folded --> when the const_value is valid, the normalize_subrange_limit() |
|
664 * never gets called!! |
|
665 * |
|
666 * Situations where it has not been constant folded can occur if: |
|
667 * - the get_datatype_info_c::is_type_equal() is called before the constant folding algorithm does its thing |
|
668 * - the constant folding algorithm is called before get_datatype_info_c::is_type_equal(), but |
|
669 * the symbol does not get constant folded |
|
670 * (e.g: the POU containing a VAR_EXTERN is not instantiated, and that external variable is used to define a |
|
671 * limit of an array (ARRAY of [1..ext_var] OF INT) |
|
672 * However, currently get_datatype_info_c::is_type_equal() is not called to handle the above case, |
|
673 * and constant_folding is being called before all algorithms that call get_datatype_info_c::is_type_equal(), |
|
674 * which means that the following code is really not needed. But it is best to have it here just in case... |
|
675 */ |
|
676 token_c *token = NULL; |
|
677 symbolic_constant_c *symconst = dynamic_cast<symbolic_constant_c *>(symbol); |
|
678 symbolic_variable_c *symvar = dynamic_cast<symbolic_variable_c *>(symbol); |
|
679 if (NULL != symconst) token = dynamic_cast< token_c *>(symconst->var_name); |
|
680 if (NULL != symvar ) token = dynamic_cast< token_c *>(symvar ->var_name); |
|
681 if (NULL != token) |
|
682 // handle it as a symbolic_variable/constant_c |
|
683 return token->value; |
|
684 |
|
685 ERROR; |
|
686 return NULL; // humour the compiler... |
652 } |
687 } |
653 |
688 |
654 |
689 |
655 /* A helper method to get_datatype_info_c::is_type_equal() |
690 /* A helper method to get_datatype_info_c::is_type_equal() |
656 * Assuming the relaxed datatype model, determine whether the two array datatypes are equal/equivalent |
691 * Assuming the relaxed datatype model, determine whether the two array datatypes are equal/equivalent |
689 && (subrange_2->upper_limit->const_value._int64.is_valid() || subrange_2->upper_limit->const_value._uint64.is_valid()) |
724 && (subrange_2->upper_limit->const_value._int64.is_valid() || subrange_2->upper_limit->const_value._uint64.is_valid()) |
690 ) { |
725 ) { |
691 if (! (subrange_1->lower_limit->const_value == subrange_2->lower_limit->const_value)) return false; |
726 if (! (subrange_1->lower_limit->const_value == subrange_2->lower_limit->const_value)) return false; |
692 if (! (subrange_1->upper_limit->const_value == subrange_2->upper_limit->const_value)) return false; |
727 if (! (subrange_1->upper_limit->const_value == subrange_2->upper_limit->const_value)) return false; |
693 } else { |
728 } else { |
694 if (normalize_integer(subrange_1->lower_limit) != normalize_integer(subrange_2->lower_limit)) return false; |
729 // NOTE: nocasecmp_c() class is defined in absyntax.hh. nocasecmp_c() instantiates an object, and nocasecmp_c()() uses the () operator on that object. |
695 if (normalize_integer(subrange_1->upper_limit) != normalize_integer(subrange_2->upper_limit)) return false; |
730 if (! nocasecmp_c()(normalize_subrange_limit(subrange_1->lower_limit), normalize_subrange_limit(subrange_2->lower_limit))) return false; |
|
731 if (! nocasecmp_c()(normalize_subrange_limit(subrange_1->upper_limit), normalize_subrange_limit(subrange_2->upper_limit))) return false; |
696 } |
732 } |
697 } |
733 } |
698 |
734 |
699 return is_type_equal(search_base_type_c::get_basetype_decl(array_1->non_generic_type_name), |
735 return is_type_equal(search_base_type_c::get_basetype_decl(array_1->non_generic_type_name), |
700 search_base_type_c::get_basetype_decl(array_2->non_generic_type_name)); |
736 search_base_type_c::get_basetype_decl(array_2->non_generic_type_name)); |