--- 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;
}