173 |
173 |
174 |
174 |
175 |
175 |
176 |
176 |
177 |
177 |
178 #define SET_CVALUE(dtype, symbol, new_value) ((symbol)->const_value._##dtype.value) = new_value; ((symbol)->const_value._##dtype.status) = symbol_c::cs_const_value; |
178 #define SET_CVALUE(dtype, symbol, new_value) {((symbol)->const_value._##dtype.value) = new_value; ((symbol)->const_value._##dtype.status) = symbol_c::cs_const_value;} |
179 #define GET_CVALUE(dtype, symbol) ((symbol)->const_value._##dtype.value) |
179 #define GET_CVALUE(dtype, symbol) ((symbol)->const_value._##dtype.value) |
180 #define SET_OVFLOW(dtype, symbol) ((symbol)->const_value._##dtype.status) = symbol_c::cs_overflow |
180 #define SET_OVFLOW(dtype, symbol) ((symbol)->const_value._##dtype.status) = symbol_c::cs_overflow |
181 #define SET_NONCONST(dtype, symbol) ((symbol)->const_value._##dtype.status) = symbol_c::cs_non_const |
181 #define SET_NONCONST(dtype, symbol) ((symbol)->const_value._##dtype.status) = symbol_c::cs_non_const |
182 |
182 |
183 #define VALID_CVALUE(dtype, symbol) (symbol_c::cs_const_value == (symbol)->const_value._##dtype.status) |
183 #define VALID_CVALUE(dtype, symbol) (symbol_c::cs_const_value == (symbol)->const_value._##dtype.status) |
|
184 #define IS_OVFLOW(dtype, symbol) (symbol_c::cs_overflow == (symbol)->const_value._##dtype.status) |
184 #define ISZERO_CVALUE(dtype, symbol) ((VALID_CVALUE(dtype, symbol)) && (GET_CVALUE(dtype, symbol) == 0)) |
185 #define ISZERO_CVALUE(dtype, symbol) ((VALID_CVALUE(dtype, symbol)) && (GET_CVALUE(dtype, symbol) == 0)) |
185 |
186 |
186 #define ISEQUAL_CVALUE(dtype, symbol1, symbol2) \ |
187 #define ISEQUAL_CVALUE(dtype, symbol1, symbol2) \ |
187 (VALID_CVALUE(dtype, symbol1) && VALID_CVALUE(dtype, symbol2) && (GET_CVALUE(dtype, symbol1) == GET_CVALUE(dtype, symbol2))) |
188 (VALID_CVALUE(dtype, symbol1) && VALID_CVALUE(dtype, symbol2) && (GET_CVALUE(dtype, symbol1) == GET_CVALUE(dtype, symbol2))) |
188 |
189 |
189 #define DO_BINARY_OPER(dtype, oper, otype)\ |
190 #define DO_BINARY_OPER(oper_type, operation, res_type, operand1, operand2) { \ |
190 if (VALID_CVALUE(dtype, symbol->r_exp) && VALID_CVALUE(dtype, symbol->l_exp)) { \ |
191 if (VALID_CVALUE(oper_type, operand1) && VALID_CVALUE(oper_type, operand2)) \ |
191 SET_CVALUE(otype, symbol, GET_CVALUE(dtype, symbol->l_exp) oper GET_CVALUE(dtype, symbol->r_exp)); \ |
|
192 } |
|
193 |
|
194 #define DO_BINARY_OPER_(oper_type, operation, res_type, operand1, operand2)\ |
|
195 if (VALID_CVALUE(oper_type, operand1) && VALID_CVALUE(oper_type, operand2)) { \ |
|
196 SET_CVALUE(res_type, symbol, GET_CVALUE(oper_type, operand1) operation GET_CVALUE(oper_type, operand2)); \ |
192 SET_CVALUE(res_type, symbol, GET_CVALUE(oper_type, operand1) operation GET_CVALUE(oper_type, operand2)); \ |
197 } |
193 } |
198 |
194 |
199 #define DO_UNARY_OPER(dtype, operation, operand)\ |
195 #define DO_UNARY_OPER(dtype, operation, operand) { \ |
200 if (VALID_CVALUE(dtype, operand)) { \ |
196 if (VALID_CVALUE(dtype, operand)) \ |
201 SET_CVALUE(dtype, symbol, operation GET_CVALUE(dtype, operand)); \ |
197 SET_CVALUE(dtype, symbol, operation GET_CVALUE(dtype, operand)); \ |
202 } |
198 } |
203 |
199 |
204 |
200 |
205 |
201 |
206 |
202 |
207 |
203 |
537 /***********************************************************************/ |
545 /***********************************************************************/ |
538 |
546 |
539 /* static void *handle_cmp(symbol_c *symbol, symbol_c *oper1, symbol_c *oper2, OPERATION) */ |
547 /* static void *handle_cmp(symbol_c *symbol, symbol_c *oper1, symbol_c *oper2, OPERATION) */ |
540 #define handle_cmp(symbol, oper1, oper2, operation) { \ |
548 #define handle_cmp(symbol, oper1, oper2, operation) { \ |
541 if ((NULL == oper1) || (NULL == oper2)) return NULL; \ |
549 if ((NULL == oper1) || (NULL == oper2)) return NULL; \ |
542 DO_BINARY_OPER_( bool, operation, bool, oper1, oper2); \ |
550 DO_BINARY_OPER( bool, operation, bool, oper1, oper2); \ |
543 DO_BINARY_OPER_(uint64, operation, bool, oper1, oper2); \ |
551 DO_BINARY_OPER(uint64, operation, bool, oper1, oper2); \ |
544 DO_BINARY_OPER_( int64, operation, bool, oper1, oper2); \ |
552 DO_BINARY_OPER( int64, operation, bool, oper1, oper2); \ |
545 DO_BINARY_OPER_(real64, operation, bool, oper1, oper2); \ |
553 DO_BINARY_OPER(real64, operation, bool, oper1, oper2); \ |
546 return NULL; \ |
554 return NULL; \ |
547 } |
555 } |
548 |
556 |
549 |
557 |
550 /* NOTE: the MOVE standard function is equivalent to the ':=' in ST syntax */ |
558 /* NOTE: the MOVE standard function is equivalent to the ':=' in ST syntax */ |
577 } |
590 } |
578 |
591 |
579 |
592 |
580 static void *handle_or (symbol_c *symbol, symbol_c *oper1, symbol_c *oper2) { |
593 static void *handle_or (symbol_c *symbol, symbol_c *oper1, symbol_c *oper2) { |
581 if ((NULL == oper1) || (NULL == oper2)) return NULL; |
594 if ((NULL == oper1) || (NULL == oper2)) return NULL; |
582 DO_BINARY_OPER_( bool, ||, bool , oper1, oper2); |
595 DO_BINARY_OPER( bool, ||, bool , oper1, oper2); |
583 DO_BINARY_OPER_(uint64, | , uint64, oper1, oper2); |
596 DO_BINARY_OPER(uint64, | , uint64, oper1, oper2); |
584 return NULL; |
597 return NULL; |
585 } |
598 } |
586 |
599 |
587 |
600 |
588 static void *handle_xor(symbol_c *symbol, symbol_c *oper1, symbol_c *oper2) { |
601 static void *handle_xor(symbol_c *symbol, symbol_c *oper1, symbol_c *oper2) { |
589 if ((NULL == oper1) || (NULL == oper2)) return NULL; |
602 if ((NULL == oper1) || (NULL == oper2)) return NULL; |
590 DO_BINARY_OPER_( bool, ^, bool , oper1, oper2); |
603 DO_BINARY_OPER( bool, ^, bool , oper1, oper2); |
591 DO_BINARY_OPER_(uint64, ^, uint64, oper1, oper2); |
604 DO_BINARY_OPER(uint64, ^, uint64, oper1, oper2); |
592 return NULL; |
605 return NULL; |
593 } |
606 } |
594 |
607 |
595 |
608 |
596 static void *handle_and(symbol_c *symbol, symbol_c *oper1, symbol_c *oper2) { |
609 static void *handle_and(symbol_c *symbol, symbol_c *oper1, symbol_c *oper2) { |
597 if ((NULL == oper1) || (NULL == oper2)) return NULL; |
610 if ((NULL == oper1) || (NULL == oper2)) return NULL; |
598 DO_BINARY_OPER_( bool, &&, bool, oper1, oper2); |
611 DO_BINARY_OPER( bool, &&, bool, oper1, oper2); |
599 DO_BINARY_OPER_(uint64, & , uint64, oper1, oper2); |
612 DO_BINARY_OPER(uint64, & , uint64, oper1, oper2); |
600 return NULL; |
613 return NULL; |
601 } |
614 } |
602 |
615 |
603 |
616 |
604 static void *handle_add(symbol_c *symbol, symbol_c *oper1, symbol_c *oper2) { |
617 static void *handle_add(symbol_c *symbol, symbol_c *oper1, symbol_c *oper2) { |
605 if ((NULL == oper1) || (NULL == oper2)) return NULL; |
618 if ((NULL == oper1) || (NULL == oper2)) return NULL; |
606 DO_BINARY_OPER_(uint64, +, uint64, oper1, oper2); CHECK_OVERFLOW_uint64_SUM(symbol, oper1, oper2); |
619 DO_BINARY_OPER(uint64, +, uint64, oper1, oper2); CHECK_OVERFLOW_uint64_SUM(symbol, oper1, oper2); |
607 DO_BINARY_OPER_( int64, +, int64, oper1, oper2); CHECK_OVERFLOW_int64_SUM (symbol, oper1, oper2); |
620 DO_BINARY_OPER( int64, +, int64, oper1, oper2); CHECK_OVERFLOW_int64_SUM (symbol, oper1, oper2); |
608 DO_BINARY_OPER_(real64, +, real64, oper1, oper2); CHECK_OVERFLOW_real64 (symbol); |
621 DO_BINARY_OPER(real64, +, real64, oper1, oper2); CHECK_OVERFLOW_real64 (symbol); |
609 return NULL; |
622 return NULL; |
610 } |
623 } |
611 |
624 |
612 |
625 |
613 static void *handle_sub(symbol_c *symbol, symbol_c *oper1, symbol_c *oper2) { |
626 static void *handle_sub(symbol_c *symbol, symbol_c *oper1, symbol_c *oper2) { |
614 if ((NULL == oper1) || (NULL == oper2)) return NULL; |
627 if ((NULL == oper1) || (NULL == oper2)) return NULL; |
615 DO_BINARY_OPER_(uint64, -, uint64, oper1, oper2); CHECK_OVERFLOW_uint64_SUB(symbol, oper1, oper2); |
628 DO_BINARY_OPER(uint64, -, uint64, oper1, oper2); CHECK_OVERFLOW_uint64_SUB(symbol, oper1, oper2); |
616 DO_BINARY_OPER_( int64, -, int64, oper1, oper2); CHECK_OVERFLOW_int64_SUB (symbol, oper1, oper2); |
629 DO_BINARY_OPER( int64, -, int64, oper1, oper2); CHECK_OVERFLOW_int64_SUB (symbol, oper1, oper2); |
617 DO_BINARY_OPER_(real64, -, real64, oper1, oper2); CHECK_OVERFLOW_real64 (symbol); |
630 DO_BINARY_OPER(real64, -, real64, oper1, oper2); CHECK_OVERFLOW_real64 (symbol); |
618 return NULL; |
631 return NULL; |
619 } |
632 } |
620 |
633 |
621 |
634 |
622 static void *handle_mul(symbol_c *symbol, symbol_c *oper1, symbol_c *oper2) { |
635 static void *handle_mul(symbol_c *symbol, symbol_c *oper1, symbol_c *oper2) { |
623 if ((NULL == oper1) || (NULL == oper2)) return NULL; |
636 if ((NULL == oper1) || (NULL == oper2)) return NULL; |
624 DO_BINARY_OPER_(uint64, *, uint64, oper1, oper2); CHECK_OVERFLOW_uint64_MUL(symbol, oper1, oper2); |
637 DO_BINARY_OPER(uint64, *, uint64, oper1, oper2); CHECK_OVERFLOW_uint64_MUL(symbol, oper1, oper2); |
625 DO_BINARY_OPER_( int64, *, int64, oper1, oper2); CHECK_OVERFLOW_int64_MUL (symbol, oper1, oper2); |
638 DO_BINARY_OPER( int64, *, int64, oper1, oper2); CHECK_OVERFLOW_int64_MUL (symbol, oper1, oper2); |
626 DO_BINARY_OPER_(real64, *, real64, oper1, oper2); CHECK_OVERFLOW_real64 (symbol); |
639 DO_BINARY_OPER(real64, *, real64, oper1, oper2); CHECK_OVERFLOW_real64 (symbol); |
627 return NULL; |
640 return NULL; |
628 } |
641 } |
629 |
642 |
630 |
643 |
631 static void *handle_div(symbol_c *symbol, symbol_c *oper1, symbol_c *oper2) { |
644 static void *handle_div(symbol_c *symbol, symbol_c *oper1, symbol_c *oper2) { |
632 if ((NULL == oper1) || (NULL == oper2)) return NULL; |
645 if ((NULL == oper1) || (NULL == oper2)) return NULL; |
633 if (ISZERO_CVALUE(uint64, oper2)) {SET_OVFLOW(uint64, symbol);} else {DO_BINARY_OPER_(uint64, /, uint64, oper1, oper2); CHECK_OVERFLOW_uint64_DIV(symbol, oper1, oper2);}; |
646 if (ISZERO_CVALUE(uint64, oper2)) {SET_OVFLOW(uint64, symbol);} else {DO_BINARY_OPER(uint64, /, uint64, oper1, oper2); CHECK_OVERFLOW_uint64_DIV(symbol, oper1, oper2);}; |
634 if (ISZERO_CVALUE( int64, oper2)) {SET_OVFLOW( int64, symbol);} else {DO_BINARY_OPER_( int64, /, int64, oper1, oper2); CHECK_OVERFLOW_int64_DIV (symbol, oper1, oper2);}; |
647 if (ISZERO_CVALUE( int64, oper2)) {SET_OVFLOW( int64, symbol);} else {DO_BINARY_OPER( int64, /, int64, oper1, oper2); CHECK_OVERFLOW_int64_DIV (symbol, oper1, oper2);}; |
635 if (ISZERO_CVALUE(real64, oper2)) {SET_OVFLOW(real64, symbol);} else {DO_BINARY_OPER_(real64, /, real64, oper1, oper2); CHECK_OVERFLOW_real64(symbol);}; |
648 if (ISZERO_CVALUE(real64, oper2)) {SET_OVFLOW(real64, symbol);} else {DO_BINARY_OPER(real64, /, real64, oper1, oper2); CHECK_OVERFLOW_real64(symbol);}; |
636 return NULL; |
649 return NULL; |
637 } |
650 } |
638 |
651 |
639 |
652 |
640 static void *handle_mod(symbol_c *symbol, symbol_c *oper1, symbol_c *oper2) { |
653 static void *handle_mod(symbol_c *symbol, symbol_c *oper1, symbol_c *oper2) { |
643 * IF (IN2 = 0) THEN OUT:=0 ; ELSE OUT:=IN1 - (IN1/IN2)*IN2 ; END_IF |
656 * IF (IN2 = 0) THEN OUT:=0 ; ELSE OUT:=IN1 - (IN1/IN2)*IN2 ; END_IF |
644 * |
657 * |
645 * Note that, when IN1 = INT64_MIN, and IN2 = -1, an overflow occurs in the division, |
658 * Note that, when IN1 = INT64_MIN, and IN2 = -1, an overflow occurs in the division, |
646 * so although the MOD operation should be OK, acording to the above definition, we actually have an overflow!! |
659 * so although the MOD operation should be OK, acording to the above definition, we actually have an overflow!! |
647 */ |
660 */ |
648 if (ISZERO_CVALUE(uint64, oper2)) {SET_CVALUE(uint64, symbol, 0);} else {DO_BINARY_OPER_(uint64, %, uint64, oper1, oper2); CHECK_OVERFLOW_uint64_MOD(symbol, oper1, oper2);}; |
661 if (ISZERO_CVALUE(uint64, oper2)) {SET_CVALUE(uint64, symbol, 0);} else {DO_BINARY_OPER(uint64, %, uint64, oper1, oper2); CHECK_OVERFLOW_uint64_MOD(symbol, oper1, oper2);}; |
649 if (ISZERO_CVALUE( int64, oper2)) {SET_CVALUE( int64, symbol, 0);} else {DO_BINARY_OPER_( int64, %, int64, oper1, oper2); CHECK_OVERFLOW_int64_MOD (symbol, oper1, oper2);}; |
662 if (ISZERO_CVALUE( int64, oper2)) {SET_CVALUE( int64, symbol, 0);} else {DO_BINARY_OPER( int64, %, int64, oper1, oper2); CHECK_OVERFLOW_int64_MOD (symbol, oper1, oper2);}; |
650 return NULL; |
663 return NULL; |
651 } |
664 } |
652 |
665 |
653 |
666 |
654 static void *handle_pow(symbol_c *symbol, symbol_c *oper1, symbol_c *oper2) { |
667 static void *handle_pow(symbol_c *symbol, symbol_c *oper1, symbol_c *oper2) { |
754 } |
767 } |
755 |
768 |
756 |
769 |
757 void *constant_folding_c::visit(neg_real_c *symbol) { |
770 void *constant_folding_c::visit(neg_real_c *symbol) { |
758 symbol->exp->accept(*this); |
771 symbol->exp->accept(*this); |
759 DO_UNARY_OPER(real64, -, symbol->exp); |
772 DO_UNARY_OPER(real64, -, symbol->exp); CHECK_OVERFLOW_real64(symbol); |
760 CHECK_OVERFLOW_real64(symbol); |
773 if (IS_OVFLOW(real64, symbol->exp)) SET_OVFLOW(real64, symbol); |
761 return NULL; |
774 return NULL; |
762 } |
775 } |
|
776 |
|
777 |
763 |
778 |
764 /* | '-' integer {$$ = new neg_integer_c($2, locloc(@$));} */ |
779 /* | '-' integer {$$ = new neg_integer_c($2, locloc(@$));} */ |
765 void *constant_folding_c::visit(neg_integer_c *symbol) { |
780 void *constant_folding_c::visit(neg_integer_c *symbol) { |
766 symbol->exp->accept(*this); |
781 symbol->exp->accept(*this); |
767 DO_UNARY_OPER(int64, -, symbol->exp); |
782 /* Note that due to syntax restrictions, the value of symbol->exp will always be positive. |
768 CHECK_OVERFLOW_int64_NEG(symbol, symbol->exp); |
783 * However, the following code does not depend on that restriction. |
|
784 */ |
|
785 /* The remainder of the code (for example, data type checking) considers the neg_integer_c as a leaf of the |
|
786 * abstract syntax tree, and therefore simply ignores the values of neg_integer_c->exp. |
|
787 * For this reason only, and in only this situation, we must guarantee that any 'overflow' situation in |
|
788 * the cvalue of neg_integer_c->exp is also reflected back to this neg_integer_c symbol. |
|
789 * For the rest of the code we do NOT do this, as it would gurantee that a single overflow deep inside |
|
790 * an expression would imply that the expression itself would also be set to 'overflow' condition. |
|
791 * This in turn would then have the compiler produce a whole load of error messages where they are not wanted! |
|
792 */ |
|
793 DO_UNARY_OPER(uint64, -, symbol->exp); CHECK_OVERFLOW_uint64_NEG(symbol, symbol->exp); /* handle the uintv := -0 situation */ |
|
794 if (IS_OVFLOW(uint64, symbol->exp)) SET_OVFLOW(uint64, symbol); |
|
795 DO_UNARY_OPER( int64, -, symbol->exp); CHECK_OVERFLOW_int64_NEG (symbol, symbol->exp); |
|
796 if (IS_OVFLOW( int64, symbol->exp)) SET_OVFLOW( int64, symbol); |
769 /* NOTE 1: INT64_MIN = -(INT64_MAX + 1) ---> assuming two's complement representation!!! |
797 /* NOTE 1: INT64_MIN = -(INT64_MAX + 1) ---> assuming two's complement representation!!! |
770 * NOTE 2: if the user happens to want INT_MIN, that value will first be parsed as a positive integer, before being negated here. |
798 * NOTE 2: if the user happens to want INT_MIN, that value will first be parsed as a positive integer, before being negated here. |
771 * However, the positive value cannot be stored inside an int64! So, in this case, we will get the value from the uint64 cvalue. |
799 * However, the positive value cannot be stored inside an int64! So, in this case, we will get the value from the uint64 cvalue. |
|
800 * |
|
801 * This same situation is usually considered an overflow (check handle_neg() function). However, here we have a special |
|
802 * situation. If we do not allow this, then the user would never the able to use the following code: |
|
803 * VAR v : LINT; END_VAR |
|
804 * v := -9223372036854775809 ; (* - |INT64_MIN| == INT64_MIN *) |
772 */ |
805 */ |
773 // if (INT64_MIN == -INT64_MAX - 1) // We do not really need to check that the platform uses two's complement |
806 // if (INT64_MIN == -INT64_MAX - 1) // We do not really need to check that the platform uses two's complement |
774 if (VALID_CVALUE(uint64, symbol->exp) && (GET_CVALUE(uint64, symbol->exp) == (uint64_t)INT64_MAX+1)) { |
807 if (VALID_CVALUE(uint64, symbol->exp) && (GET_CVALUE(uint64, symbol->exp) == (uint64_t)INT64_MAX+1)) { |
775 SET_CVALUE(int64, symbol, INT64_MIN); |
808 SET_CVALUE(int64, symbol, INT64_MIN); |
776 } |
809 } |
777 /* NOTE 3: The standard allows considers the following strange syntax correct: |
|
778 * int_v = ----------42; |
|
779 * However, it will be parsed as multiple neg_expression_c, with a single final neg_integer_c. |
|
780 * So, when parsing a neg_integer_c, we are guaranteed to always have a positive value in symbol->exp |
|
781 * --> Conclusion: |
|
782 * We do not need to handle the situation where we are negating the INT_MIN value, whose |
|
783 * result can only be stored inside an UINT (remember that INT_MIN is < 0 !!). |
|
784 * |
|
785 * NOTE 4: The syntax: uint_v := -<INT_MIN> may occur inside a neg_expression_c, but would always |
|
786 * result in a data type error. So, although we could handle it here, it is not really |
|
787 * necessary as it will later be caught by the data type checking classes. |
|
788 */ |
|
789 return NULL; |
810 return NULL; |
790 } |
811 } |
791 |
812 |
792 |
813 |
793 void *constant_folding_c::visit(binary_integer_c *symbol) { |
814 void *constant_folding_c::visit(binary_integer_c *symbol) { |