510 } |
512 } |
511 |
513 |
512 |
514 |
513 |
515 |
514 |
516 |
|
517 /***********************************************************************/ |
|
518 /***********************************************************************/ |
|
519 /***********************************************************************/ |
|
520 /*** Functions to execute operations on the const values ***/ |
|
521 /***********************************************************************/ |
|
522 /***********************************************************************/ |
|
523 /***********************************************************************/ |
|
524 |
|
525 /* static void *handle_cmp(symbol_c *symbol, symbol_c *oper1, symbol_c *oper2, OPERATION) */ |
|
526 #define handle_cmp(symbol, oper1, oper2, operation) { \ |
|
527 if ((NULL == oper1) || (NULL == oper2)) return NULL; \ |
|
528 DO_BINARY_OPER_( bool, operation, bool, oper1, oper2); \ |
|
529 DO_BINARY_OPER_(uint64, operation, bool, oper1, oper2); \ |
|
530 DO_BINARY_OPER_( int64, operation, bool, oper1, oper2); \ |
|
531 DO_BINARY_OPER_(real64, operation, bool, oper1, oper2); \ |
|
532 return NULL; \ |
|
533 } |
|
534 |
|
535 |
|
536 /* NOTE: the MOVE standard function is equivalent to the ':=' in ST syntax */ |
|
537 static void *handle_move(symbol_c *to, symbol_c *from) { |
|
538 if (NULL == from) return NULL; |
|
539 to->const_value = from->const_value; |
|
540 return NULL; |
|
541 } |
|
542 |
|
543 |
|
544 /* unary negation (multiply by -1) */ |
|
545 static void *handle_neg(symbol_c *symbol, symbol_c *oper) { |
|
546 DO_UNARY_OPER( int64, -, oper); CHECK_OVERFLOW_int64_NEG(symbol, oper); |
|
547 DO_UNARY_OPER(real64, -, oper); CHECK_OVERFLOW_real64(symbol); |
|
548 return NULL; |
|
549 } |
|
550 |
|
551 |
|
552 /* unary boolean negation (NOT) */ |
|
553 static void *handle_not(symbol_c *symbol, symbol_c *oper) { |
|
554 if (NULL == oper) return NULL; |
|
555 DO_UNARY_OPER( bool, !, oper); |
|
556 DO_UNARY_OPER(uint64, ~, oper); |
|
557 return NULL; |
|
558 } |
|
559 |
|
560 |
|
561 static void *handle_or (symbol_c *symbol, symbol_c *oper1, symbol_c *oper2) { |
|
562 if ((NULL == oper1) || (NULL == oper2)) return NULL; |
|
563 DO_BINARY_OPER_( bool, ||, bool , oper1, oper2); |
|
564 DO_BINARY_OPER_(uint64, | , uint64, oper1, oper2); |
|
565 return NULL; |
|
566 } |
|
567 |
|
568 |
|
569 static void *handle_xor(symbol_c *symbol, symbol_c *oper1, symbol_c *oper2) { |
|
570 if ((NULL == oper1) || (NULL == oper2)) return NULL; |
|
571 DO_BINARY_OPER_( bool, ^, bool , oper1, oper2); |
|
572 DO_BINARY_OPER_(uint64, ^, uint64, oper1, oper2); |
|
573 return NULL; |
|
574 } |
|
575 |
|
576 |
|
577 static void *handle_and(symbol_c *symbol, symbol_c *oper1, symbol_c *oper2) { |
|
578 if ((NULL == oper1) || (NULL == oper2)) return NULL; |
|
579 DO_BINARY_OPER_( bool, &&, bool, oper1, oper2); |
|
580 DO_BINARY_OPER_(uint64, & , uint64, oper1, oper2); |
|
581 return NULL; |
|
582 } |
|
583 |
|
584 |
|
585 static void *handle_add(symbol_c *symbol, symbol_c *oper1, symbol_c *oper2) { |
|
586 if ((NULL == oper1) || (NULL == oper2)) return NULL; |
|
587 DO_BINARY_OPER_(uint64, +, uint64, oper1, oper2); CHECK_OVERFLOW_uint64_SUM(symbol, oper1, oper2); |
|
588 DO_BINARY_OPER_( int64, +, int64, oper1, oper2); CHECK_OVERFLOW_int64_SUM (symbol, oper1, oper2); |
|
589 DO_BINARY_OPER_(real64, +, real64, oper1, oper2); CHECK_OVERFLOW_real64 (symbol); |
|
590 return NULL; |
|
591 } |
|
592 |
|
593 |
|
594 static void *handle_sub(symbol_c *symbol, symbol_c *oper1, symbol_c *oper2) { |
|
595 if ((NULL == oper1) || (NULL == oper2)) return NULL; |
|
596 DO_BINARY_OPER_(uint64, -, uint64, oper1, oper2); CHECK_OVERFLOW_uint64_SUB(symbol, oper1, oper2); |
|
597 DO_BINARY_OPER_( int64, -, int64, oper1, oper2); CHECK_OVERFLOW_int64_SUB (symbol, oper1, oper2); |
|
598 DO_BINARY_OPER_(real64, -, real64, oper1, oper2); CHECK_OVERFLOW_real64 (symbol); |
|
599 return NULL; |
|
600 } |
|
601 |
|
602 |
|
603 static void *handle_mul(symbol_c *symbol, symbol_c *oper1, symbol_c *oper2) { |
|
604 if ((NULL == oper1) || (NULL == oper2)) return NULL; |
|
605 DO_BINARY_OPER_(uint64, *, uint64, oper1, oper2); CHECK_OVERFLOW_uint64_MUL(symbol, oper1, oper2); |
|
606 DO_BINARY_OPER_( int64, *, int64, oper1, oper2); CHECK_OVERFLOW_int64_MUL (symbol, oper1, oper2); |
|
607 DO_BINARY_OPER_(real64, *, real64, oper1, oper2); CHECK_OVERFLOW_real64 (symbol); |
|
608 return NULL; |
|
609 } |
|
610 |
|
611 |
|
612 static void *handle_div(symbol_c *symbol, symbol_c *oper1, symbol_c *oper2) { |
|
613 if ((NULL == oper1) || (NULL == oper2)) return NULL; |
|
614 if (ISZERO_CVALUE(uint64, oper2)) {SET_OVFLOW(uint64, symbol);} else {DO_BINARY_OPER_(uint64, /, uint64, oper1, oper2); CHECK_OVERFLOW_uint64_DIV(symbol, oper1, oper2);}; |
|
615 if (ISZERO_CVALUE( int64, oper2)) {SET_OVFLOW( int64, symbol);} else {DO_BINARY_OPER_( int64, /, int64, oper1, oper2); CHECK_OVERFLOW_int64_DIV (symbol, oper1, oper2);}; |
|
616 if (ISZERO_CVALUE(real64, oper2)) {SET_OVFLOW(real64, symbol);} else {DO_BINARY_OPER_(real64, /, real64, oper1, oper2); CHECK_OVERFLOW_real64(symbol);}; |
|
617 return NULL; |
|
618 } |
|
619 |
|
620 |
|
621 static void *handle_mod(symbol_c *symbol, symbol_c *oper1, symbol_c *oper2) { |
|
622 if ((NULL == oper1) || (NULL == oper2)) return NULL; |
|
623 /* IEC 61131-3 standard says IN1 MOD IN2 must be equivalent to |
|
624 * IF (IN2 = 0) THEN OUT:=0 ; ELSE OUT:=IN1 - (IN1/IN2)*IN2 ; END_IF |
|
625 * |
|
626 * Note that, when IN1 = INT64_MIN, and IN2 = -1, an overflow occurs in the division, |
|
627 * so although the MOD operation should be OK, acording to the above definition, we actually have an overflow!! |
|
628 */ |
|
629 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);}; |
|
630 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);}; |
|
631 return NULL; |
|
632 } |
|
633 |
|
634 |
|
635 static void *handle_pow(symbol_c *symbol, symbol_c *oper1, symbol_c *oper2) { |
|
636 /* NOTE: If the const_value in symbol->r_exp is within the limits of both int64 and uint64, then we do both operations. |
|
637 * That is OK, as the result should be identicial (we do create an unnecessary CVALUE variable, but who cares?). |
|
638 * If only one is valid, then that is the oper we will do! |
|
639 */ |
|
640 if (VALID_CVALUE(real64, oper1) && VALID_CVALUE( int64, oper2)) |
|
641 SET_CVALUE(real64, symbol, pow(GET_CVALUE(real64, oper1), GET_CVALUE( int64, oper2))); |
|
642 if (VALID_CVALUE(real64, oper1) && VALID_CVALUE(uint64, oper2)) |
|
643 SET_CVALUE(real64, symbol, pow(GET_CVALUE(real64, oper1), GET_CVALUE(uint64, oper2))); |
|
644 CHECK_OVERFLOW_real64(symbol); |
|
645 return NULL; |
|
646 } |
|
647 |
|
648 /***********************************************************************/ |
|
649 /***********************************************************************/ |
|
650 /***********************************************************************/ |
|
651 /*** Helper functions for handling IL instruction lists. ***/ |
|
652 /***********************************************************************/ |
|
653 /***********************************************************************/ |
|
654 /***********************************************************************/ |
|
655 |
|
656 |
|
657 /* If the cvalues of all the prev_il_intructions have the same VALID value, then set the local cvalue to that value, otherwise, set it to NONCONST! */ |
|
658 #define intersect_prev_CVALUE_(dtype, symbol) { \ |
|
659 symbol->const_value._##dtype = symbol->prev_il_instruction[0]->const_value._##dtype; \ |
|
660 for (unsigned int i = 1; i < symbol->prev_il_instruction.size(); i++) { \ |
|
661 if (!ISEQUAL_CVALUE(dtype, symbol, symbol->prev_il_instruction[i])) \ |
|
662 {SET_NONCONST(dtype, symbol); break;} \ |
|
663 } \ |
|
664 } |
|
665 |
|
666 static void intersect_prev_cvalues(il_instruction_c *symbol) { |
|
667 if (symbol->prev_il_instruction.empty()) |
|
668 return; |
|
669 intersect_prev_CVALUE_(real64, symbol); |
|
670 intersect_prev_CVALUE_(uint64, symbol); |
|
671 intersect_prev_CVALUE_( int64, symbol); |
|
672 intersect_prev_CVALUE_( bool, symbol); |
|
673 } |
515 |
674 |
516 |
675 |
517 |
676 |
518 /***********************************************************************/ |
677 /***********************************************************************/ |
519 /***********************************************************************/ |
678 /***********************************************************************/ |
665 return NULL; |
823 return NULL; |
666 } |
824 } |
667 |
825 |
668 |
826 |
669 void *constant_folding_c::visit(boolean_true_c *symbol) { |
827 void *constant_folding_c::visit(boolean_true_c *symbol) { |
670 NEW_CVALUE(bool, symbol); SET_CVALUE(bool, symbol, true); |
828 SET_CVALUE(bool, symbol, true); |
671 return NULL; |
829 return NULL; |
672 } |
830 } |
673 |
831 |
674 |
832 |
675 void *constant_folding_c::visit(boolean_false_c *symbol) { |
833 void *constant_folding_c::visit(boolean_false_c *symbol) { |
676 NEW_CVALUE(bool, symbol); SET_CVALUE(bool, symbol, false); |
834 SET_CVALUE(bool, symbol, false); |
677 return NULL; |
835 return NULL; |
678 } |
836 } |
|
837 |
|
838 |
|
839 |
|
840 |
|
841 |
|
842 /****************************************/ |
|
843 /* B.2 - Language IL (Instruction List) */ |
|
844 /****************************************/ |
|
845 /***********************************/ |
|
846 /* B 2.1 Instructions and Operands */ |
|
847 /***********************************/ |
|
848 /* Not needed, since we inherit from iterator_visitor_c */ |
|
849 /*| instruction_list il_instruction */ |
|
850 // SYM_LIST(instruction_list_c) |
|
851 // void *constant_folding_c::visit(instruction_list_c *symbol) {} |
|
852 |
|
853 /* | label ':' [il_incomplete_instruction] eol_list */ |
|
854 // SYM_REF2(il_instruction_c, label, il_instruction) |
|
855 // void *visit(instruction_list_c *symbol); |
|
856 void *constant_folding_c::visit(il_instruction_c *symbol) { |
|
857 if (NULL == symbol->il_instruction) { |
|
858 /* This empty/null il_instruction does not change the value of the current/default IL variable. |
|
859 * So it inherits the candidate_datatypes from it's previous IL instructions! |
|
860 */ |
|
861 intersect_prev_cvalues(symbol); |
|
862 } else { |
|
863 il_instruction_c fake_prev_il_instruction = *symbol; |
|
864 intersect_prev_cvalues(&fake_prev_il_instruction); |
|
865 |
|
866 if (symbol->prev_il_instruction.size() == 0) prev_il_instruction = NULL; |
|
867 else prev_il_instruction = &fake_prev_il_instruction; |
|
868 symbol->il_instruction->accept(*this); |
|
869 prev_il_instruction = NULL; |
|
870 |
|
871 /* This object has (inherits) the same cvalues as the il_instruction */ |
|
872 symbol->const_value = symbol->il_instruction->const_value; |
|
873 } |
|
874 |
|
875 return NULL; |
|
876 } |
|
877 |
|
878 |
|
879 void *constant_folding_c::visit(il_simple_operation_c *symbol) { |
|
880 /* determine the cvalue of the operand */ |
|
881 if (NULL != symbol->il_operand) { |
|
882 symbol->il_operand->accept(*this); |
|
883 } |
|
884 /* determine the cvalue resulting from executing the il_operator... */ |
|
885 il_operand = symbol->il_operand; |
|
886 symbol->il_simple_operator->accept(*this); |
|
887 il_operand = NULL; |
|
888 /* This object has (inherits) the same cvalues as the il_instruction */ |
|
889 symbol->const_value = symbol->il_simple_operator->const_value; |
|
890 return NULL; |
|
891 } |
|
892 |
|
893 |
|
894 /* TODO: handle function invocations... */ |
|
895 /* | function_name [il_operand_list] */ |
|
896 /* NOTE: The parameters 'called_function_declaration' and 'extensible_param_count' are used to pass data between the stage 3 and stage 4. */ |
|
897 // SYM_REF2(il_function_call_c, function_name, il_operand_list, symbol_c *called_function_declaration; int extensible_param_count;) |
|
898 // void *constant_folding_c::visit(il_function_call_c *symbol) {} |
|
899 |
|
900 |
|
901 /* | il_expr_operator '(' [il_operand] eol_list [simple_instr_list] ')' */ |
|
902 // SYM_REF3(il_expression_c, il_expr_operator, il_operand, simple_instr_list); |
|
903 void *constant_folding_c::visit(il_expression_c *symbol) { |
|
904 symbol_c *prev_il_instruction_backup = prev_il_instruction; |
|
905 |
|
906 if (NULL != symbol->il_operand) |
|
907 symbol->il_operand->accept(*this); |
|
908 |
|
909 if(symbol->simple_instr_list != NULL) |
|
910 symbol->simple_instr_list->accept(*this); |
|
911 |
|
912 /* Now do the operation, */ |
|
913 il_operand = symbol->simple_instr_list; |
|
914 prev_il_instruction = prev_il_instruction_backup; |
|
915 symbol->il_expr_operator->accept(*this); |
|
916 il_operand = NULL; |
|
917 |
|
918 /* This object has (inherits) the same cvalues as the il_instruction */ |
|
919 symbol->const_value = symbol->il_expr_operator->const_value; |
|
920 return NULL; |
|
921 } |
|
922 |
|
923 |
|
924 |
|
925 void *constant_folding_c::visit(il_jump_operation_c *symbol) { |
|
926 /* recursive call to fill const values... */ |
|
927 il_operand = NULL; |
|
928 symbol->il_jump_operator->accept(*this); |
|
929 il_operand = NULL; |
|
930 /* This object has (inherits) the same cvalues as the il_jump_operator */ |
|
931 symbol->const_value = symbol->il_jump_operator->const_value; |
|
932 return NULL; |
|
933 } |
|
934 |
|
935 |
|
936 |
|
937 /* FB calls leave the value in the accumulator unchanged */ |
|
938 /* il_call_operator prev_declared_fb_name |
|
939 * | il_call_operator prev_declared_fb_name '(' ')' |
|
940 * | il_call_operator prev_declared_fb_name '(' eol_list ')' |
|
941 * | il_call_operator prev_declared_fb_name '(' il_operand_list ')' |
|
942 * | il_call_operator prev_declared_fb_name '(' eol_list il_param_list ')' |
|
943 */ |
|
944 /* 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 */ |
|
945 // SYM_REF4(il_fb_call_c, il_call_operator, fb_name, il_operand_list, il_param_list, symbol_c *called_fb_declaration) |
|
946 void *constant_folding_c::visit(il_fb_call_c *symbol) {return handle_move(symbol, prev_il_instruction);} |
|
947 |
|
948 |
|
949 /* TODO: handle function invocations... */ |
|
950 /* | function_name '(' eol_list [il_param_list] ')' */ |
|
951 /* NOTE: The parameter 'called_function_declaration' is used to pass data between the stage 3 and stage 4. */ |
|
952 // SYM_REF2(il_formal_funct_call_c, function_name, il_param_list, symbol_c *called_function_declaration; int extensible_param_count;) |
|
953 // void *constant_folding_c::visit(il_formal_funct_call_c *symbol) {return NULL;} |
|
954 |
|
955 |
|
956 |
|
957 /* Not needed, since we inherit from iterator_visitor_c */ |
|
958 // void *constant_folding_c::visit(il_operand_list_c *symbol); |
|
959 |
|
960 |
|
961 |
|
962 /* | simple_instr_list il_simple_instruction */ |
|
963 /* This object is referenced by il_expression_c objects */ |
|
964 void *constant_folding_c::visit(simple_instr_list_c *symbol) { |
|
965 if (symbol->n <= 0) |
|
966 return NULL; /* List is empty! Nothing to do. */ |
|
967 |
|
968 for(int i = 0; i < symbol->n; i++) |
|
969 symbol->elements[i]->accept(*this); |
|
970 |
|
971 /* This object has (inherits) the same cvalues as the il_jump_operator */ |
|
972 symbol->const_value = symbol->elements[symbol->n-1]->const_value; |
|
973 return NULL; |
|
974 } |
|
975 |
|
976 |
|
977 |
|
978 // SYM_REF1(il_simple_instruction_c, il_simple_instruction, symbol_c *prev_il_instruction;) |
|
979 void *constant_folding_c::visit(il_simple_instruction_c *symbol) { |
|
980 if (symbol->prev_il_instruction.size() > 1) ERROR; /* There should be no labeled insructions inside an IL expression! */ |
|
981 if (symbol->prev_il_instruction.size() == 0) prev_il_instruction = NULL; |
|
982 else prev_il_instruction = symbol->prev_il_instruction[0]; |
|
983 symbol->il_simple_instruction->accept(*this); |
|
984 prev_il_instruction = NULL; |
|
985 |
|
986 /* This object has (inherits) the same cvalues as the il_jump_operator */ |
|
987 symbol->const_value = symbol->il_simple_instruction->const_value; |
|
988 return NULL; |
|
989 } |
|
990 |
|
991 |
|
992 /* |
|
993 void *visit(il_param_list_c *symbol); |
|
994 void *visit(il_param_assignment_c *symbol); |
|
995 void *visit(il_param_out_assignment_c *symbol); |
|
996 */ |
|
997 |
|
998 |
|
999 /*******************/ |
|
1000 /* B 2.2 Operators */ |
|
1001 /*******************/ |
|
1002 void *constant_folding_c::visit( LD_operator_c *symbol) {return handle_move(symbol, il_operand);} |
|
1003 void *constant_folding_c::visit( LDN_operator_c *symbol) {return handle_not (symbol, il_operand);} |
|
1004 |
|
1005 /* NOTE: we are implementing a constant folding algorithm, not a constant propagation algorithm. |
|
1006 * For the constant propagation algorithm, the correct implementation of ST(N)_operator_c would be... |
|
1007 */ |
|
1008 //void *constant_folding_c::visit( ST_operator_c *symbol) {return handle_move(il_operand, symbol);} |
|
1009 //void *constant_folding_c::visit( STN_operator_c *symbol) {return handle_not (il_operand, symbol);} |
|
1010 void *constant_folding_c::visit( ST_operator_c *symbol) {return handle_move(symbol, prev_il_instruction);} |
|
1011 void *constant_folding_c::visit( STN_operator_c *symbol) {return handle_move(symbol, prev_il_instruction);} |
|
1012 |
|
1013 /* NOTE: the standard allows syntax in which the NOT operator is followed by an optional <il_operand> |
|
1014 * NOT [<il_operand>] |
|
1015 * However, it does not define the semantic of the NOT operation when the <il_operand> is specified. |
|
1016 * We therefore consider it an error if an il_operand is specified! This error will be caught elsewhere! |
|
1017 */ |
|
1018 void *constant_folding_c::visit( NOT_operator_c *symbol) {return handle_not(symbol, prev_il_instruction);} |
|
1019 |
|
1020 /* NOTE: Since we are only implementing a constant folding algorithm, and not a constant propagation algorithm, |
|
1021 * the following IL instructions do not change/set the value of the il_operand! |
|
1022 */ |
|
1023 void *constant_folding_c::visit( S_operator_c *symbol) {return handle_move(symbol, prev_il_instruction);} |
|
1024 void *constant_folding_c::visit( R_operator_c *symbol) {return handle_move(symbol, prev_il_instruction);} |
|
1025 |
|
1026 /* FB calls leave the value in the accumulator unchanged */ |
|
1027 void *constant_folding_c::visit( S1_operator_c *symbol) {return handle_move(symbol, prev_il_instruction);} |
|
1028 void *constant_folding_c::visit( R1_operator_c *symbol) {return handle_move(symbol, prev_il_instruction);} |
|
1029 void *constant_folding_c::visit( CLK_operator_c *symbol) {return handle_move(symbol, prev_il_instruction);} |
|
1030 void *constant_folding_c::visit( CU_operator_c *symbol) {return handle_move(symbol, prev_il_instruction);} |
|
1031 void *constant_folding_c::visit( CD_operator_c *symbol) {return handle_move(symbol, prev_il_instruction);} |
|
1032 void *constant_folding_c::visit( PV_operator_c *symbol) {return handle_move(symbol, prev_il_instruction);} |
|
1033 void *constant_folding_c::visit( IN_operator_c *symbol) {return handle_move(symbol, prev_il_instruction);} |
|
1034 void *constant_folding_c::visit( PT_operator_c *symbol) {return handle_move(symbol, prev_il_instruction);} |
|
1035 |
|
1036 void *constant_folding_c::visit( AND_operator_c *symbol) {return handle_and (symbol, prev_il_instruction, il_operand);} |
|
1037 void *constant_folding_c::visit( OR_operator_c *symbol) {return handle_or (symbol, prev_il_instruction, il_operand);} |
|
1038 void *constant_folding_c::visit( XOR_operator_c *symbol) {return handle_xor (symbol, prev_il_instruction, il_operand);} |
|
1039 void *constant_folding_c::visit( ANDN_operator_c *symbol) { handle_and (symbol, prev_il_instruction, il_operand); return handle_not(symbol, symbol);} |
|
1040 void *constant_folding_c::visit( ORN_operator_c *symbol) { handle_or (symbol, prev_il_instruction, il_operand); return handle_not(symbol, symbol);} |
|
1041 void *constant_folding_c::visit( XORN_operator_c *symbol) { handle_xor (symbol, prev_il_instruction, il_operand); return handle_not(symbol, symbol);} |
|
1042 |
|
1043 void *constant_folding_c::visit( ADD_operator_c *symbol) {return handle_add (symbol, prev_il_instruction, il_operand);} |
|
1044 void *constant_folding_c::visit( SUB_operator_c *symbol) {return handle_sub (symbol, prev_il_instruction, il_operand);} |
|
1045 void *constant_folding_c::visit( MUL_operator_c *symbol) {return handle_mul (symbol, prev_il_instruction, il_operand);} |
|
1046 void *constant_folding_c::visit( DIV_operator_c *symbol) {return handle_div (symbol, prev_il_instruction, il_operand);} |
|
1047 void *constant_folding_c::visit( MOD_operator_c *symbol) {return handle_mod (symbol, prev_il_instruction, il_operand);} |
|
1048 |
|
1049 void *constant_folding_c::visit( GT_operator_c *symbol) { handle_cmp (symbol, prev_il_instruction, il_operand, > );} |
|
1050 void *constant_folding_c::visit( GE_operator_c *symbol) { handle_cmp (symbol, prev_il_instruction, il_operand, >=);} |
|
1051 void *constant_folding_c::visit( EQ_operator_c *symbol) { handle_cmp (symbol, prev_il_instruction, il_operand, ==);} |
|
1052 void *constant_folding_c::visit( LT_operator_c *symbol) { handle_cmp (symbol, prev_il_instruction, il_operand, < );} |
|
1053 void *constant_folding_c::visit( LE_operator_c *symbol) { handle_cmp (symbol, prev_il_instruction, il_operand, <=);} |
|
1054 void *constant_folding_c::visit( NE_operator_c *symbol) { handle_cmp (symbol, prev_il_instruction, il_operand, !=);} |
|
1055 |
|
1056 void *constant_folding_c::visit( CAL_operator_c *symbol) {return handle_move(symbol, prev_il_instruction);} |
|
1057 void *constant_folding_c::visit( RET_operator_c *symbol) {return handle_move(symbol, prev_il_instruction);} |
|
1058 void *constant_folding_c::visit( JMP_operator_c *symbol) {return handle_move(symbol, prev_il_instruction);} |
|
1059 void *constant_folding_c::visit( CALC_operator_c *symbol) {return handle_move(symbol, prev_il_instruction);} |
|
1060 void *constant_folding_c::visit(CALCN_operator_c *symbol) {return handle_move(symbol, prev_il_instruction);} |
|
1061 void *constant_folding_c::visit( RETC_operator_c *symbol) {return handle_move(symbol, prev_il_instruction);} |
|
1062 void *constant_folding_c::visit(RETCN_operator_c *symbol) {return handle_move(symbol, prev_il_instruction);} |
|
1063 void *constant_folding_c::visit( JMPC_operator_c *symbol) {return handle_move(symbol, prev_il_instruction);} |
|
1064 void *constant_folding_c::visit(JMPCN_operator_c *symbol) {return handle_move(symbol, prev_il_instruction);} |
|
1065 |
|
1066 |
679 |
1067 |
680 |
1068 |
681 /***************************************/ |
1069 /***************************************/ |
682 /* B.3 - Language ST (Structured Text) */ |
1070 /* B.3 - Language ST (Structured Text) */ |
683 /***************************************/ |
1071 /***************************************/ |
684 /***********************/ |
1072 /***********************/ |
685 /* B 3.1 - Expressions */ |
1073 /* B 3.1 - Expressions */ |
686 /***********************/ |
1074 /***********************/ |
687 void *constant_folding_c::visit(or_expression_c *symbol) { |
1075 void *constant_folding_c::visit( or_expression_c *symbol) {symbol->l_exp->accept(*this); symbol->r_exp->accept(*this); return handle_or (symbol, symbol->l_exp, symbol->r_exp);} |
688 symbol->l_exp->accept(*this); |
1076 void *constant_folding_c::visit( xor_expression_c *symbol) {symbol->l_exp->accept(*this); symbol->r_exp->accept(*this); return handle_xor(symbol, symbol->l_exp, symbol->r_exp);} |
689 symbol->r_exp->accept(*this); |
1077 void *constant_folding_c::visit( and_expression_c *symbol) {symbol->l_exp->accept(*this); symbol->r_exp->accept(*this); return handle_and(symbol, symbol->l_exp, symbol->r_exp);} |
690 DO_BINARY_OPER( bool, ||, bool); |
1078 |
691 DO_BINARY_OPER(uint64, | , uint64); |
1079 void *constant_folding_c::visit( equ_expression_c *symbol) {symbol->l_exp->accept(*this); symbol->r_exp->accept(*this); handle_cmp (symbol, symbol->l_exp, symbol->r_exp, ==);} |
692 return NULL; |
1080 void *constant_folding_c::visit(notequ_expression_c *symbol) {symbol->l_exp->accept(*this); symbol->r_exp->accept(*this); handle_cmp (symbol, symbol->l_exp, symbol->r_exp, !=);} |
693 } |
1081 void *constant_folding_c::visit( lt_expression_c *symbol) {symbol->l_exp->accept(*this); symbol->r_exp->accept(*this); handle_cmp (symbol, symbol->l_exp, symbol->r_exp, < );} |
694 |
1082 void *constant_folding_c::visit( gt_expression_c *symbol) {symbol->l_exp->accept(*this); symbol->r_exp->accept(*this); handle_cmp (symbol, symbol->l_exp, symbol->r_exp, > );} |
695 |
1083 void *constant_folding_c::visit( le_expression_c *symbol) {symbol->l_exp->accept(*this); symbol->r_exp->accept(*this); handle_cmp (symbol, symbol->l_exp, symbol->r_exp, <=);} |
696 void *constant_folding_c::visit(xor_expression_c *symbol) { |
1084 void *constant_folding_c::visit( ge_expression_c *symbol) {symbol->l_exp->accept(*this); symbol->r_exp->accept(*this); handle_cmp (symbol, symbol->l_exp, symbol->r_exp, >=);} |
697 symbol->l_exp->accept(*this); |
1085 |
698 symbol->r_exp->accept(*this); |
1086 void *constant_folding_c::visit( add_expression_c *symbol) {symbol->l_exp->accept(*this); symbol->r_exp->accept(*this); return handle_add(symbol, symbol->l_exp, symbol->r_exp);} |
699 DO_BINARY_OPER( bool, ^, bool); |
1087 void *constant_folding_c::visit( sub_expression_c *symbol) {symbol->l_exp->accept(*this); symbol->r_exp->accept(*this); return handle_sub(symbol, symbol->l_exp, symbol->r_exp);} |
700 DO_BINARY_OPER(uint64, ^, uint64); |
1088 void *constant_folding_c::visit( mul_expression_c *symbol) {symbol->l_exp->accept(*this); symbol->r_exp->accept(*this); return handle_mul(symbol, symbol->l_exp, symbol->r_exp);} |
701 return NULL; |
1089 void *constant_folding_c::visit( div_expression_c *symbol) {symbol->l_exp->accept(*this); symbol->r_exp->accept(*this); return handle_div(symbol, symbol->l_exp, symbol->r_exp);} |
702 } |
1090 void *constant_folding_c::visit( mod_expression_c *symbol) {symbol->l_exp->accept(*this); symbol->r_exp->accept(*this); return handle_mod(symbol, symbol->l_exp, symbol->r_exp);} |
703 |
1091 void *constant_folding_c::visit( power_expression_c *symbol) {symbol->l_exp->accept(*this); symbol->r_exp->accept(*this); return handle_pow(symbol, symbol->l_exp, symbol->r_exp);} |
704 |
1092 |
705 void *constant_folding_c::visit(and_expression_c *symbol) { |
1093 void *constant_folding_c::visit( neg_expression_c *symbol) {symbol-> exp->accept(*this); return handle_neg(symbol, symbol->exp);} |
706 symbol->l_exp->accept(*this); |
1094 void *constant_folding_c::visit( not_expression_c *symbol) {symbol-> exp->accept(*this); return handle_not(symbol, symbol->exp);} |
707 symbol->r_exp->accept(*this); |
1095 |
708 DO_BINARY_OPER( bool, &&, bool); |
1096 /* TODO: handle function invocations... */ |
709 DO_BINARY_OPER(uint64, & , uint64); |
1097 // void *fill_candidate_datatypes_c::visit(function_invocation_c *symbol) {} |
710 return NULL; |
|
711 } |
|
712 |
|
713 |
|
714 void *constant_folding_c::visit(equ_expression_c *symbol) { |
|
715 symbol->l_exp->accept(*this); |
|
716 symbol->r_exp->accept(*this); |
|
717 DO_BINARY_OPER( bool, ==, bool); |
|
718 DO_BINARY_OPER(uint64, ==, bool); |
|
719 DO_BINARY_OPER( int64, ==, bool); |
|
720 DO_BINARY_OPER(real64, ==, bool); |
|
721 return NULL; |
|
722 } |
|
723 |
|
724 |
|
725 void *constant_folding_c::visit(notequ_expression_c *symbol) { |
|
726 symbol->l_exp->accept(*this); |
|
727 symbol->r_exp->accept(*this); |
|
728 DO_BINARY_OPER( bool, !=, bool); |
|
729 DO_BINARY_OPER(uint64, !=, bool); |
|
730 DO_BINARY_OPER( int64, !=, bool); |
|
731 DO_BINARY_OPER(real64, !=, bool); |
|
732 return NULL; |
|
733 } |
|
734 |
|
735 |
|
736 void *constant_folding_c::visit(lt_expression_c *symbol) { |
|
737 symbol->l_exp->accept(*this); |
|
738 symbol->r_exp->accept(*this); |
|
739 DO_BINARY_OPER( bool, <, bool); |
|
740 DO_BINARY_OPER(uint64, <, bool); |
|
741 DO_BINARY_OPER( int64, <, bool); |
|
742 DO_BINARY_OPER(real64, <, bool); |
|
743 return NULL; |
|
744 } |
|
745 |
|
746 |
|
747 void *constant_folding_c::visit(gt_expression_c *symbol) { |
|
748 symbol->l_exp->accept(*this); |
|
749 symbol->r_exp->accept(*this); |
|
750 DO_BINARY_OPER( bool, >, bool); |
|
751 DO_BINARY_OPER(uint64, >, bool); |
|
752 DO_BINARY_OPER( int64, >, bool); |
|
753 DO_BINARY_OPER(real64, >, bool); |
|
754 return NULL; |
|
755 } |
|
756 |
|
757 |
|
758 void *constant_folding_c::visit(le_expression_c *symbol) { |
|
759 symbol->l_exp->accept(*this); |
|
760 symbol->r_exp->accept(*this); |
|
761 DO_BINARY_OPER( bool, <=, bool); |
|
762 DO_BINARY_OPER(uint64, <=, bool); |
|
763 DO_BINARY_OPER( int64, <=, bool); |
|
764 DO_BINARY_OPER(real64, <=, bool); |
|
765 return NULL; |
|
766 } |
|
767 |
|
768 |
|
769 void *constant_folding_c::visit(ge_expression_c *symbol) { |
|
770 symbol->l_exp->accept(*this); |
|
771 symbol->r_exp->accept(*this); |
|
772 DO_BINARY_OPER( bool, >=, bool); |
|
773 DO_BINARY_OPER(uint64, >=, bool); |
|
774 DO_BINARY_OPER( int64, >=, bool); |
|
775 DO_BINARY_OPER(real64, >=, bool); |
|
776 return NULL; |
|
777 } |
|
778 |
|
779 |
|
780 void *constant_folding_c::visit(add_expression_c *symbol) { |
|
781 symbol->l_exp->accept(*this); |
|
782 symbol->r_exp->accept(*this); |
|
783 DO_BINARY_OPER(uint64, +, uint64); CHECK_OVERFLOW_uint64_SUM(symbol, symbol->l_exp, symbol->r_exp); |
|
784 DO_BINARY_OPER( int64, +, int64); CHECK_OVERFLOW_int64_SUM (symbol, symbol->l_exp, symbol->r_exp); |
|
785 DO_BINARY_OPER(real64, +, real64); CHECK_OVERFLOW_real64 (symbol); |
|
786 return NULL; |
|
787 } |
|
788 |
|
789 |
|
790 void *constant_folding_c::visit(sub_expression_c *symbol) { |
|
791 symbol->l_exp->accept(*this); |
|
792 symbol->r_exp->accept(*this); |
|
793 DO_BINARY_OPER(uint64, -, uint64); CHECK_OVERFLOW_uint64_SUB(symbol, symbol->l_exp, symbol->r_exp); |
|
794 DO_BINARY_OPER( int64, -, int64); CHECK_OVERFLOW_int64_SUB (symbol, symbol->l_exp, symbol->r_exp); |
|
795 DO_BINARY_OPER(real64, -, real64); CHECK_OVERFLOW_real64 (symbol); |
|
796 return NULL; |
|
797 } |
|
798 |
|
799 |
|
800 void *constant_folding_c::visit(mul_expression_c *symbol) { |
|
801 symbol->l_exp->accept(*this); |
|
802 symbol->r_exp->accept(*this); |
|
803 DO_BINARY_OPER(uint64, *, uint64); CHECK_OVERFLOW_uint64_MUL(symbol, symbol->l_exp, symbol->r_exp); |
|
804 DO_BINARY_OPER( int64, *, int64); CHECK_OVERFLOW_int64_MUL (symbol, symbol->l_exp, symbol->r_exp); |
|
805 DO_BINARY_OPER(real64, *, real64); CHECK_OVERFLOW_real64 (symbol); |
|
806 return NULL; |
|
807 } |
|
808 |
|
809 |
|
810 |
|
811 void *constant_folding_c::visit(div_expression_c *symbol) { |
|
812 symbol->l_exp->accept(*this); |
|
813 symbol->r_exp->accept(*this); |
|
814 if (ISZERO_CVALUE(uint64, symbol->r_exp)) {NEW_CVALUE(uint64, symbol); SET_OVFLOW(uint64, symbol);} else {DO_BINARY_OPER(uint64, /, uint64); CHECK_OVERFLOW_uint64_DIV(symbol, symbol->l_exp, symbol->r_exp);}; |
|
815 if (ISZERO_CVALUE( int64, symbol->r_exp)) {NEW_CVALUE( int64, symbol); SET_OVFLOW( int64, symbol);} else {DO_BINARY_OPER( int64, /, int64); CHECK_OVERFLOW_int64_DIV(symbol, symbol->l_exp, symbol->r_exp);}; |
|
816 if (ISZERO_CVALUE(real64, symbol->r_exp)) {NEW_CVALUE(real64, symbol); SET_OVFLOW(real64, symbol);} else {DO_BINARY_OPER(real64, /, real64); CHECK_OVERFLOW_real64(symbol);}; |
|
817 return NULL; |
|
818 } |
|
819 |
|
820 |
|
821 void *constant_folding_c::visit(mod_expression_c *symbol) { |
|
822 symbol->l_exp->accept(*this); |
|
823 symbol->r_exp->accept(*this); |
|
824 /* IEC 61131-3 standard says IN1 MOD IN2 must be equivalent to |
|
825 * IF (IN2 = 0) THEN OUT:=0 ; ELSE OUT:=IN1 - (IN1/IN2)*IN2 ; END_IF |
|
826 * |
|
827 * Note that, when IN1 = INT64_MIN, and IN2 = -1, an overflow occurs in the division, |
|
828 * so although the MOD operation should be OK, acording to the above definition, we actually have an overflow!! |
|
829 */ |
|
830 if (ISZERO_CVALUE(uint64, symbol->r_exp)) {NEW_CVALUE(uint64, symbol); SET_CVALUE(uint64, symbol, 0);} else {DO_BINARY_OPER(uint64, %, uint64); CHECK_OVERFLOW_uint64_MOD(symbol, symbol->l_exp, symbol->r_exp);}; |
|
831 if (ISZERO_CVALUE( int64, symbol->r_exp)) {NEW_CVALUE( int64, symbol); SET_CVALUE( int64, symbol, 0);} else {DO_BINARY_OPER( int64, %, int64); CHECK_OVERFLOW_int64_MOD(symbol, symbol->l_exp, symbol->r_exp);}; |
|
832 return NULL; |
|
833 } |
|
834 |
|
835 |
|
836 void *constant_folding_c::visit(power_expression_c *symbol) { |
|
837 symbol->l_exp->accept(*this); |
|
838 symbol->r_exp->accept(*this); |
|
839 /* NOTE: If the const_value in symbol->r_exp is within the limits of both int64 and uint64, then we do both operations. |
|
840 * That is OK, as the result should be identicial (we do create an unnecessary CVALUE variable, but who cares?). |
|
841 * If only one is valid, then that is the oper we will do! |
|
842 */ |
|
843 if (VALID_CVALUE(real64, symbol->l_exp) && VALID_CVALUE( int64, symbol->r_exp)) { |
|
844 NEW_CVALUE(real64, symbol); |
|
845 SET_CVALUE(real64, symbol, pow(GET_CVALUE(real64, symbol->l_exp), GET_CVALUE( int64, symbol->r_exp))); |
|
846 } |
|
847 if (VALID_CVALUE(real64, symbol->l_exp) && VALID_CVALUE(uint64, symbol->r_exp)) { |
|
848 NEW_CVALUE(real64, symbol); |
|
849 SET_CVALUE(real64, symbol, pow(GET_CVALUE(real64, symbol->l_exp), GET_CVALUE(uint64, symbol->r_exp))); |
|
850 } |
|
851 CHECK_OVERFLOW_real64(symbol); |
|
852 return NULL; |
|
853 } |
|
854 |
|
855 |
|
856 void *constant_folding_c::visit(neg_expression_c *symbol) { |
|
857 symbol->exp->accept(*this); |
|
858 DO_UNARY_OPER( int64, -, symbol->exp); CHECK_OVERFLOW_int64_NEG(symbol, symbol->exp); |
|
859 DO_UNARY_OPER(real64, -, symbol->exp); CHECK_OVERFLOW_real64(symbol); |
|
860 return NULL; |
|
861 } |
|
862 |
|
863 |
|
864 |
|
865 void *constant_folding_c::visit(not_expression_c *symbol) { |
|
866 symbol->exp->accept(*this); |
|
867 DO_UNARY_OPER( bool, !, symbol->exp); |
|
868 DO_UNARY_OPER(uint64, ~, symbol->exp); |
|
869 return NULL; |
|
870 } |
|
871 |
|
872 |
|