Fix constant folding: now handles INT_MIN and neg_integer_c correctly.
authorMario de Sousa <msousa@fe.up.pt>
Wed, 29 Aug 2012 19:38:15 +0100
changeset 643 1cc0e1ca2aad
parent 641 5681f600ac18
child 644 e7ac0fe9a287
Fix constant folding: now handles INT_MIN and neg_integer_c correctly.
stage1_2/iec_bison.yy
stage3/constant_folding.cc
stage3/fill_candidate_datatypes.cc
--- a/stage1_2/iec_bison.yy	Thu Aug 16 22:44:38 2012 +0200
+++ b/stage1_2/iec_bison.yy	Wed Aug 29 19:38:15 2012 +0100
@@ -433,7 +433,7 @@
 /* B 1.2 - Constants */
 /*********************/
 %type <leaf>	constant
-%type <leaf>	non_negative_constant
+%type <leaf>	non_int_or_real_constant
 
 /******************************/
 /* B 1.2.1 - Numeric Literals */
@@ -1297,7 +1297,7 @@
 %type  <leaf>	unary_expression
 // %type  <leaf>	unary_operator
 %type  <leaf>	primary_expression
-%type  <leaf>	non_negative_primary_expression
+%type  <leaf>	non_int_or_real_primary_expression
 /* intermediate helper symbol for primary_expression */
 %type  <leaf>	function_invocation
 
@@ -1728,91 +1728,64 @@
 /* B 1.2 - Constants */
 /*********************/
 constant:
-  numeric_literal
-| character_string
+  character_string
 | time_literal
 | bit_string_literal
 | boolean_literal
+| numeric_literal  
+/* NOTE: Our definition of numeric_literal is diferent than the one in the standard.
+ *       We will now add what is missing in our definition of numeric literal, so our
+ *       definition of constant matches what the definition of constant in the standard.
+ */
 /* NOTE: in order to remove reduce/reduce conflicts,
  * [between -9.5 being parsed as 
  *     (i)   a signed real, 
  *     (ii)  or as a real preceded by the '-' operator
  *  ]
  *  we need to define a variant of the constant construct
- *  where any constant is never preceded by the '-' character.
- * In order to do this, we have borugh the signed_real 
- * directly into the definition of the constant construct
- * (so we can define another non_negative_constant
- * construct that does not include it!)
- */
-| signed_real
-/* NOTE: in order to remove reduce/reduce conflicts,
- * unsigned_integer, signed_integer, binary_integer, octal_integer
- * and hex_integer have been integrated directly into
- * the constants construct, instead of belonging to
- * both the bit_string_literal or integer_literal
- * construct.
- */
+ *  where any real or integer constant is always preceded by 
+ *  a sign (i.e. the '-' or '+' characters).
+ *  (For more info, see comment in the construct non_int_or_real_primary_expression)
+ *
+ * For the above reason, our definition of the numeric_literal construct
+ * is missing the integer and real constrcuts (when not preceded by a sign)
+ * so we add then here explicitly!
+ */
+| real
+| integer
 /* NOTE: unsigned_integer, although used in some
  * rules, is not defined in the spec!
  * We therefore replaced unsigned_integer as integer
  */
-/*| integer {} */  /* i.e. an unsigned_integer */ /* NOTE: already included as a signed integer! */
-| signed_integer
-| binary_integer
-| octal_integer
-| hex_integer
-;
-
-
+;
+
+
+
+
+non_int_or_real_constant:
+  character_string
+| time_literal
+| bit_string_literal
+| boolean_literal
+| numeric_literal  
+/* NOTE: Our definition of numeric_literal is diferent than the one in the standard.
+ *       It is missing the integer and real when not prefixed by a sign 
+ *       (i.e. -54, +42 is included in numerical_literal,
+ *        but   54,  42 is not parsed as a numeric_literal!!)
+ */
 /* NOTE: in order to remove reduce/reduce conflicts,
  * [between -9.5 being parsed as 
  *     (i)   a signed real, 
  *     (ii)  or as a real preceded by the '-' operator
  *  ]
+ * [and a similar situation for integers!]
  *  we need to define a variant of the constant construct
- *  where any constant is never preceded by the '-' character.
- * In order to do this, we have borugh the signed_real 
- * directly into the definition of the constant construct
- * (so we can define another non_negative_constant
- * construct that does not include it!)
- */
-non_negative_constant:
-  numeric_literal
-| character_string
-| time_literal
-| bit_string_literal
-| boolean_literal
-/* NOTE: in order to remove reduce/reduce conflicts,
- * [between -9.5 being parsed as 
- *     (i)   a signed real, 
- *     (ii)  or as a real preceded by the '-' operator
- *  ]
- *  we need to define a variant of the constant construct
- *  where any constant is never preceded by the '-' character.
- * In order to do this, we have borugh the signed_real 
- * directly into the definition of the constant construct
- * (so we can define another non_negative_constant
- * construct that does not include it!)
- */
-/* | signed_real */
-| real /* an unsigned real */
-/* NOTE: in order to remove reduce/reduce conflicts,
- * unsigned_integer, signed_integer, binary_integer, octal_integer
- * and hex_integer have been integrated directly into
- * the constants construct, instead of belonging to
- * both the bit_string_literal or integer_literal
- * construct.
- */
-/* NOTE: unsigned_integer, although used in some
- * rules, is not defined in the spec!
- * We therefore replaced unsigned_integer as integer
- */
-| integer  /* i.e. an unsigned_integer */
-/* | signed_integer */
-| binary_integer
-| octal_integer
-| hex_integer
+ *  where any real or integer constant is always preceded by 
+ *  a sign (i.e. the '-' or '+' characters).
+ *
+ * For the above reason, our definition of the numeric_literal construct
+ * is missing the integer and real constrcuts (when not preceded by a sign)
+ */
 ;
 
 
@@ -1914,10 +1887,13 @@
 	{$$ = new integer_literal_c($1, $3, locloc(@$));}
 | integer_type_name '#' hex_integer
 	{$$ = new integer_literal_c($1, $3, locloc(@$));}
-/* NOTE: see note in the definition of constant for reason
- * why signed_integer, binary_integer, octal_integer
- * and hex_integer are missing here!
- */
+| binary_integer
+| octal_integer
+| hex_integer
+//|signed_integer  /* We expand the construct signed_integer here, so we can remove one of its constituents */
+//|  integer       /* REMOVED! see note in the definition of constant for reason why integer is missing here! */
+| '+' integer   {$$ = $2;}
+| '-' integer	{$$ = new neg_integer_c($2, locloc(@$));}
 /* ERROR_CHECK_BEGIN */
 | integer_type_name signed_integer
 	{$$ = NULL; print_err_msg(locl(@1), locf(@2), "'#' missing between integer type name and value in integer literal."); yynerrs++;}
@@ -1936,6 +1912,13 @@
 /* ERROR_CHECK_END */
 ;
 
+/* NOTE: this construct is used in the definition of integer_literal. However, in order to remove
+ *       a reduce/reduce conflict (see NOTE in definition of constant for reason why)
+ *       it is not used directly, but rather its expansion is copied there.
+ *
+ *       If for some reason you need to change the definition of signed_integer, don't forget
+ *       to change its expansion in integer_literal too!
+*/
 signed_integer:
   integer
 | '+' integer   {$$ = $2;}
@@ -1944,11 +1927,11 @@
 
 
 real_literal:
-/* NOTE: see note in the definition of constant for reason
- * why signed_real is missing here!
- */
-/*  signed_real */
-  real_type_name '#' signed_real
+// signed_real /* We expand the construct signed_integer here, so we can remove one of its constituents */
+// real        /* REMOVED! see note in the definition of constant for reason why real is missing here! */
+  '+' real	{$$ = $2;}
+| '-' real	{$$ = new neg_real_c($2, locloc(@2));}
+| real_type_name '#' signed_real
 	{$$ = new real_literal_c($1, $3, locloc(@$));}
 /* ERROR_CHECK_BEGIN */
 | real_type_name signed_real
@@ -1962,7 +1945,13 @@
 /* ERROR_CHECK_END */
 ;
 
-
+/* NOTE: this construct is used in the definition of real_literal. However, in order to remove
+ *       a reduce/reduce conflict (see NOTE in definition of constant for reason why)
+ *       it is not used directly, but rather its expansion is copied there.
+ *
+ *       If for some reason you need to change the definition of signed_real, don't forget
+ *       to change its expansion in real_literal too!
+*/
 signed_real:
   real
 | '+' real	{$$ = $2;}
@@ -1970,7 +1959,6 @@
 ;
 
 
-
 bit_string_literal:
   bit_string_type_name '#' integer  /* i.e. unsigned_integer */
 	{$$ = new bit_string_literal_c($1, $3, locloc(@$));}
@@ -7197,8 +7185,8 @@
 
 
 unary_expression:
-  non_negative_primary_expression
-| '-' non_negative_primary_expression
+  primary_expression
+| '-' non_int_or_real_primary_expression
 	{$$ = new neg_expression_c($2, locloc(@$));}
 | NOT primary_expression
 	{$$ = new not_expression_c($2, locloc(@$));}
@@ -7234,8 +7222,34 @@
  *       (i.e. the constant 9, preceded by a unary negation)
  *
  *       To remove the conflict, we only allow constants without
- *       a preceding '-' to be used in primary_expression
+ *       integer or reals that are not preceded by a sign 
+ *       (i.e. a '-' or '+' character) to be used in primary_expression
  *       (i.e. as a parameter to the unary negation operator)
+ *
+ *       e.g.  '-42', '+54', '42', '54' are all allowed in primary expression
+ *       according to the standard. However, we will allow only '-42' and '+54'
+ *       to be used as an argument to the negation operator ('-').
+ */
+/* NOTE: Notice that the standard considers the following syntax correct:
+ *         VAR intv: INT; END_VAR
+ *         intv :=      42;         <----- OK
+ *         intv :=     -42;         <----- OK
+ *         intv :=     +42;         <----- OK
+ *         intv :=    --42;         <----- OK!!
+ *         intv :=    -+42;         <----- OK!!
+ *         intv :=  -(--42);        <----- OK!!
+ *         intv :=  -(-+42);        <----- OK!!
+ *         intv :=-(-(--42));       <----- OK!!
+ *         intv :=-(-(-+42));       <----- OK!!
+ *     but does NOT allow the following syntax:
+ *         VAR intv: INT; END_VAR
+ *         intv :=   ---42;       <----- ERROR!!
+ *         intv :=   --+42;       <----- ERROR!!
+ *         intv :=  ----42;       <----- ERROR!!
+ *         intv :=  ---+42;       <----- ERROR!!
+ *
+ *    Although strange, we follow the standard to the letter, and do exactly
+ *    as stated above!!
  */
 /* NOTE: We use enumerated_value_without_identifier instead of enumerated_value
  *       in order to remove a reduce/reduce conflict between reducing an
@@ -7247,8 +7261,8 @@
  *       for a variable and an enumerated value, then the variable shall be
  *       considered.
  */
-non_negative_primary_expression:
-  non_negative_constant
+non_int_or_real_primary_expression:
+  non_int_or_real_constant
 //| enumerated_value_without_identifier
 | enumerated_value
 | variable
--- a/stage3/constant_folding.cc	Thu Aug 16 22:44:38 2012 +0200
+++ b/stage3/constant_folding.cc	Wed Aug 29 19:38:15 2012 +0100
@@ -175,31 +175,27 @@
 
 
 
-#define SET_CVALUE(dtype, symbol, new_value)  ((symbol)->const_value._##dtype.value) = new_value; ((symbol)->const_value._##dtype.status) = symbol_c::cs_const_value;
+#define SET_CVALUE(dtype, symbol, new_value) {((symbol)->const_value._##dtype.value) = new_value; ((symbol)->const_value._##dtype.status) = symbol_c::cs_const_value;}
 #define GET_CVALUE(dtype, symbol)             ((symbol)->const_value._##dtype.value)
 #define SET_OVFLOW(dtype, symbol)             ((symbol)->const_value._##dtype.status) = symbol_c::cs_overflow
 #define SET_NONCONST(dtype, symbol)           ((symbol)->const_value._##dtype.status) = symbol_c::cs_non_const
 
 #define VALID_CVALUE(dtype, symbol)           (symbol_c::cs_const_value == (symbol)->const_value._##dtype.status)
+#define IS_OVFLOW(dtype, symbol)              (symbol_c::cs_overflow    == (symbol)->const_value._##dtype.status)
 #define ISZERO_CVALUE(dtype, symbol)          ((VALID_CVALUE(dtype, symbol)) && (GET_CVALUE(dtype, symbol) == 0))
 
 #define ISEQUAL_CVALUE(dtype, symbol1, symbol2) \
 	(VALID_CVALUE(dtype, symbol1) && VALID_CVALUE(dtype, symbol2) && (GET_CVALUE(dtype, symbol1) == GET_CVALUE(dtype, symbol2))) 
 
-#define DO_BINARY_OPER(dtype, oper, otype)\
-	if (VALID_CVALUE(dtype, symbol->r_exp) && VALID_CVALUE(dtype, symbol->l_exp)) {                                \
-		SET_CVALUE(otype, symbol, GET_CVALUE(dtype, symbol->l_exp) oper GET_CVALUE(dtype, symbol->r_exp));     \
-	}
-
-#define DO_BINARY_OPER_(oper_type, operation, res_type, operand1, operand2)\
-	if (VALID_CVALUE(oper_type, operand1) && VALID_CVALUE(oper_type, operand2)) {                                     \
+#define DO_BINARY_OPER(oper_type, operation, res_type, operand1, operand2) {                                             \
+	if (VALID_CVALUE(oper_type, operand1) && VALID_CVALUE(oper_type, operand2))                                       \
 		SET_CVALUE(res_type, symbol, GET_CVALUE(oper_type, operand1) operation GET_CVALUE(oper_type, operand2));  \
-	}
-
-#define DO_UNARY_OPER(dtype, operation, operand)\
-	if (VALID_CVALUE(dtype, operand)) {                                                                               \
+}
+
+#define DO_UNARY_OPER(dtype, operation, operand) {                                                                        \
+	if (VALID_CVALUE(dtype, operand))                                                                                 \
 		SET_CVALUE(dtype, symbol, operation GET_CVALUE(dtype, operand));                                          \
-	}
+}
 
 
 
@@ -430,6 +426,18 @@
 }
 
 
+/* res = - a */
+static void CHECK_OVERFLOW_uint64_NEG(symbol_c *res, symbol_c *a) {
+	/* The only legal operation is res = -0, everything else is an overflow! */
+	if (VALID_CVALUE(uint64, a) && (GET_CVALUE(uint64, a) != 0))
+		SET_OVFLOW(uint64, res);
+}
+
+
+
+
+
+
 /* res = a + b */
 static void CHECK_OVERFLOW_int64_SUM(symbol_c *res, symbol_c *a_ptr, symbol_c *b_ptr) {
 	if (!VALID_CVALUE(int64, res))
@@ -501,16 +509,16 @@
 
 
 /* res = - a */
-static void CHECK_OVERFLOW_int64_NEG(symbol_c *res, symbol_c *a_ptr) {
+static void CHECK_OVERFLOW_int64_NEG(symbol_c *res, symbol_c *a) {
 	if (!VALID_CVALUE(int64, res))
 		return;
-	int64_t a = GET_CVALUE(int64, a_ptr);
-	if (a == INT64_MIN)
+	if (GET_CVALUE(int64, a) == INT64_MIN)
 		SET_OVFLOW(int64, res);
 }
 
 
 
+
 static void CHECK_OVERFLOW_real64(symbol_c *res_ptr) {
 	if (!VALID_CVALUE(real64, res_ptr))
 		return;
@@ -539,10 +547,10 @@
 /* static void *handle_cmp(symbol_c *symbol, symbol_c *oper1, symbol_c *oper2, OPERATION) */
 #define handle_cmp(symbol, oper1, oper2, operation) {               \
 	if ((NULL == oper1) || (NULL == oper2)) return NULL;        \
-	DO_BINARY_OPER_(  bool, operation, bool, oper1, oper2);     \
-	DO_BINARY_OPER_(uint64, operation, bool, oper1, oper2);     \
-	DO_BINARY_OPER_( int64, operation, bool, oper1, oper2);     \
-	DO_BINARY_OPER_(real64, operation, bool, oper1, oper2);     \
+	DO_BINARY_OPER(  bool, operation, bool, oper1, oper2);     \
+	DO_BINARY_OPER(uint64, operation, bool, oper1, oper2);     \
+	DO_BINARY_OPER( int64, operation, bool, oper1, oper2);     \
+	DO_BINARY_OPER(real64, operation, bool, oper1, oper2);     \
 	return NULL;                                                \
 }
 
@@ -557,12 +565,17 @@
 
 /* unary negation (multiply by -1) */
 static void *handle_neg(symbol_c *symbol, symbol_c *oper) {
-	DO_UNARY_OPER( int64, -, oper);	CHECK_OVERFLOW_int64_NEG(symbol, oper);
-	/*
-	 * NOTE : The syntax:   uint_v := -<INT_MIN>  may occur inside a neg_expression_c, but would always
-	 *        result in a data type error (in-> INT, out -> UINT). So, although we could handle it here, 
-	 *        it is not really necessary as it will later be caught by the data type checking classes.
+	if (NULL == oper) return NULL;
+	/* NOTE: The oper may never be an integer/real literal, '-1' and '-2.2' are stored as an neg_integer_c/neg_real_c instead.
+	 *       Because of this, we MUST NOT handle the INT_MIN special situation that is handled in neg_integer_c visitor!
+	 *
+	 *       VAR v1, v2, v3 : UINT; END_VAR;
+	 *       v1 =  9223372036854775808 ; (* |INT64_MIN| == -INT64_MIN *)   <------ LEGAL
+	 *       v2 =  -(-v1);                                                 <------ ILLEGAL (since it -v1 is overflow!)
+	 *       v2 =  -(-9223372036854775808 );                               <------ MUST also be ILLEGAL 
 	 */
+	DO_UNARY_OPER(uint64, -, oper);	CHECK_OVERFLOW_uint64_NEG(symbol, oper);  /* handle the uint_v := -0 situation! */
+	DO_UNARY_OPER( int64, -, oper);	CHECK_OVERFLOW_int64_NEG (symbol, oper);
 	DO_UNARY_OPER(real64, -, oper);	CHECK_OVERFLOW_real64(symbol);
 	return NULL;
 }
@@ -579,60 +592,60 @@
 
 static void *handle_or (symbol_c *symbol, symbol_c *oper1, symbol_c *oper2) {
 	if ((NULL == oper1) || (NULL == oper2)) return NULL;
-	DO_BINARY_OPER_(  bool, ||, bool  , oper1, oper2);
-	DO_BINARY_OPER_(uint64, | , uint64, oper1, oper2);
+	DO_BINARY_OPER(  bool, ||, bool  , oper1, oper2);
+	DO_BINARY_OPER(uint64, | , uint64, oper1, oper2);
 	return NULL;
 }
 
 
 static void *handle_xor(symbol_c *symbol, symbol_c *oper1, symbol_c *oper2) {
 	if ((NULL == oper1) || (NULL == oper2)) return NULL;
-	DO_BINARY_OPER_(  bool, ^, bool  , oper1, oper2);
-	DO_BINARY_OPER_(uint64, ^, uint64, oper1, oper2);
+	DO_BINARY_OPER(  bool, ^, bool  , oper1, oper2);
+	DO_BINARY_OPER(uint64, ^, uint64, oper1, oper2);
 	return NULL;
 }
 
 
 static void *handle_and(symbol_c *symbol, symbol_c *oper1, symbol_c *oper2) {
 	if ((NULL == oper1) || (NULL == oper2)) return NULL;
-	DO_BINARY_OPER_(  bool, &&, bool, oper1, oper2);
-	DO_BINARY_OPER_(uint64, & , uint64, oper1, oper2);
+	DO_BINARY_OPER(  bool, &&, bool, oper1, oper2);
+	DO_BINARY_OPER(uint64, & , uint64, oper1, oper2);
 	return NULL;
 }
 
 
 static void *handle_add(symbol_c *symbol, symbol_c *oper1, symbol_c *oper2) {
 	if ((NULL == oper1) || (NULL == oper2)) return NULL;
-	DO_BINARY_OPER_(uint64, +, uint64, oper1, oper2);   CHECK_OVERFLOW_uint64_SUM(symbol, oper1, oper2);
-	DO_BINARY_OPER_( int64, +,  int64, oper1, oper2);   CHECK_OVERFLOW_int64_SUM (symbol, oper1, oper2);
-	DO_BINARY_OPER_(real64, +, real64, oper1, oper2);   CHECK_OVERFLOW_real64    (symbol);
+	DO_BINARY_OPER(uint64, +, uint64, oper1, oper2);   CHECK_OVERFLOW_uint64_SUM(symbol, oper1, oper2);
+	DO_BINARY_OPER( int64, +,  int64, oper1, oper2);   CHECK_OVERFLOW_int64_SUM (symbol, oper1, oper2);
+	DO_BINARY_OPER(real64, +, real64, oper1, oper2);   CHECK_OVERFLOW_real64    (symbol);
 	return NULL;
 }
 
 
 static void *handle_sub(symbol_c *symbol, symbol_c *oper1, symbol_c *oper2) {
 	if ((NULL == oper1) || (NULL == oper2)) return NULL;
-	DO_BINARY_OPER_(uint64, -, uint64, oper1, oper2);   CHECK_OVERFLOW_uint64_SUB(symbol, oper1, oper2);
-	DO_BINARY_OPER_( int64, -,  int64, oper1, oper2);   CHECK_OVERFLOW_int64_SUB (symbol, oper1, oper2);
-	DO_BINARY_OPER_(real64, -, real64, oper1, oper2);   CHECK_OVERFLOW_real64    (symbol);
+	DO_BINARY_OPER(uint64, -, uint64, oper1, oper2);   CHECK_OVERFLOW_uint64_SUB(symbol, oper1, oper2);
+	DO_BINARY_OPER( int64, -,  int64, oper1, oper2);   CHECK_OVERFLOW_int64_SUB (symbol, oper1, oper2);
+	DO_BINARY_OPER(real64, -, real64, oper1, oper2);   CHECK_OVERFLOW_real64    (symbol);
 	return NULL;
 }
 
 
 static void *handle_mul(symbol_c *symbol, symbol_c *oper1, symbol_c *oper2) {
 	if ((NULL == oper1) || (NULL == oper2)) return NULL;
-	DO_BINARY_OPER_(uint64, *, uint64, oper1, oper2);   CHECK_OVERFLOW_uint64_MUL(symbol, oper1, oper2);
-	DO_BINARY_OPER_( int64, *,  int64, oper1, oper2);   CHECK_OVERFLOW_int64_MUL (symbol, oper1, oper2);
-	DO_BINARY_OPER_(real64, *, real64, oper1, oper2);   CHECK_OVERFLOW_real64    (symbol);
+	DO_BINARY_OPER(uint64, *, uint64, oper1, oper2);   CHECK_OVERFLOW_uint64_MUL(symbol, oper1, oper2);
+	DO_BINARY_OPER( int64, *,  int64, oper1, oper2);   CHECK_OVERFLOW_int64_MUL (symbol, oper1, oper2);
+	DO_BINARY_OPER(real64, *, real64, oper1, oper2);   CHECK_OVERFLOW_real64    (symbol);
 	return NULL;
 }
 
 
 static void *handle_div(symbol_c *symbol, symbol_c *oper1, symbol_c *oper2) {
 	if ((NULL == oper1) || (NULL == oper2)) return NULL;
-	if (ISZERO_CVALUE(uint64, oper2))  {SET_OVFLOW(uint64, symbol);} else {DO_BINARY_OPER_(uint64, /, uint64, oper1, oper2); CHECK_OVERFLOW_uint64_DIV(symbol, oper1, oper2);};
-	if (ISZERO_CVALUE( int64, oper2))  {SET_OVFLOW( int64, symbol);} else {DO_BINARY_OPER_( int64, /,  int64, oper1, oper2); CHECK_OVERFLOW_int64_DIV (symbol, oper1, oper2);};
-	if (ISZERO_CVALUE(real64, oper2))  {SET_OVFLOW(real64, symbol);} else {DO_BINARY_OPER_(real64, /, real64, oper1, oper2); CHECK_OVERFLOW_real64(symbol);};
+	if (ISZERO_CVALUE(uint64, oper2))  {SET_OVFLOW(uint64, symbol);} else {DO_BINARY_OPER(uint64, /, uint64, oper1, oper2); CHECK_OVERFLOW_uint64_DIV(symbol, oper1, oper2);};
+	if (ISZERO_CVALUE( int64, oper2))  {SET_OVFLOW( int64, symbol);} else {DO_BINARY_OPER( int64, /,  int64, oper1, oper2); CHECK_OVERFLOW_int64_DIV (symbol, oper1, oper2);};
+	if (ISZERO_CVALUE(real64, oper2))  {SET_OVFLOW(real64, symbol);} else {DO_BINARY_OPER(real64, /, real64, oper1, oper2); CHECK_OVERFLOW_real64(symbol);};
 	return NULL;
 }
 
@@ -645,8 +658,8 @@
 	 * Note that, when IN1 = INT64_MIN, and IN2 = -1, an overflow occurs in the division,
 	 * so although the MOD operation should be OK, acording to the above definition, we actually have an overflow!!
 	 */
-	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);};
-	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);};
+	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);};
+	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);};
 	return NULL;
 }
 
@@ -756,36 +769,44 @@
 
 void *constant_folding_c::visit(neg_real_c *symbol) {
 	symbol->exp->accept(*this);
-	DO_UNARY_OPER(real64, -, symbol->exp);
-	CHECK_OVERFLOW_real64(symbol);
-	return NULL;
-}
+	DO_UNARY_OPER(real64, -, symbol->exp); CHECK_OVERFLOW_real64(symbol);
+	if (IS_OVFLOW(real64, symbol->exp)) SET_OVFLOW(real64, symbol);
+	return NULL;
+}
+
+
 
 /* | '-' integer	{$$ = new neg_integer_c($2, locloc(@$));} */
 void *constant_folding_c::visit(neg_integer_c *symbol) {
 	symbol->exp->accept(*this);
-	DO_UNARY_OPER(int64, -, symbol->exp);
-	CHECK_OVERFLOW_int64_NEG(symbol, symbol->exp);
+	/* Note that due to syntax restrictions, the value of symbol->exp will always be positive. 
+	 * However, the following code does not depend on that restriction.
+	 */
+	/* The remainder of the code (for example, data type checking) considers the neg_integer_c as a leaf of the
+	 * abstract syntax tree, and therefore simply ignores the values of neg_integer_c->exp.
+	 * For this reason only, and in only this situation, we must guarantee that any 'overflow' situation in 
+	 * the cvalue of neg_integer_c->exp is also reflected back to this neg_integer_c symbol.
+	 * For the rest of the code we do NOT do this, as it would gurantee that a single overflow deep inside
+	 * an expression would imply that the expression itself would also be set to 'overflow' condition.
+	 * This in turn would then have the compiler produce a whole load of error messages where they are not wanted!
+	 */
+	DO_UNARY_OPER(uint64, -, symbol->exp); CHECK_OVERFLOW_uint64_NEG(symbol, symbol->exp);  /* handle the uintv := -0 situation */
+	if (IS_OVFLOW(uint64, symbol->exp)) SET_OVFLOW(uint64, symbol);
+	DO_UNARY_OPER( int64, -, symbol->exp); CHECK_OVERFLOW_int64_NEG (symbol, symbol->exp);
+	if (IS_OVFLOW( int64, symbol->exp)) SET_OVFLOW( int64, symbol);
 	/* NOTE 1: INT64_MIN = -(INT64_MAX + 1)   ---> assuming two's complement representation!!!
 	 * NOTE 2: if the user happens to want INT_MIN, that value will first be parsed as a positive integer, before being negated here.
 	 * However, the positive value cannot be stored inside an int64! So, in this case, we will get the value from the uint64 cvalue.
+	 *
+	 * This same situation is usually considered an overflow (check handle_neg() function). However, here we have a special
+	 * situation. If we do not allow this, then the user would never the able to use the following code:
+	 *  VAR v : LINT; END_VAR
+	 *    v := -9223372036854775809 ; (* - |INT64_MIN| == INT64_MIN *)
 	 */
 	// if (INT64_MIN == -INT64_MAX - 1) // We do not really need to check that the platform uses two's complement
 	if (VALID_CVALUE(uint64, symbol->exp) && (GET_CVALUE(uint64, symbol->exp) == (uint64_t)INT64_MAX+1)) {
 		SET_CVALUE(int64, symbol, INT64_MIN);
 	}
-	/* NOTE 3: The standard allows considers the following strange syntax correct:
-	 *            int_v = ----------42;
-	 *         However, it will be parsed as multiple neg_expression_c, with a single final neg_integer_c.
-	 *         So, when parsing a neg_integer_c, we are guaranteed to always have a positive value in symbol->exp
-	 *         --> Conclusion: 
-	 *         We do not need to handle the situation where we are negating the INT_MIN value, whose
-	 *         result can only be stored inside an UINT (remember that INT_MIN is < 0 !!).
-	 *
-	 * NOTE 4: The syntax:   uint_v := -<INT_MIN>  may occur inside a neg_expression_c, but would always
-	 *         result in a data type error. So, although we could handle it here, it is not really
-	 *         necessary as it will later be caught by the data type checking classes.
-	 */
 	return NULL;
 }
 
--- a/stage3/fill_candidate_datatypes.cc	Thu Aug 16 22:44:38 2012 +0200
+++ b/stage3/fill_candidate_datatypes.cc	Wed Aug 29 19:38:15 2012 +0100
@@ -466,7 +466,7 @@
 	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";
+	if (debug) std::cout << "ANY_LITERAL [" << symbol->candidate_datatypes.size() << "]\n";
 	return NULL;
 }