# HG changeset patch # User Mario de Sousa # Date 1339181072 -3600 # Node ID 0d1ab9e785745ab627b2bdf499d84a5a3630f33d # Parent 5f79478142d7111dda1c77d695c2a91f8b6f422b Add data structure for storing overflow of constant values. diff -r 5f79478142d7 -r 0d1ab9e78574 absyntax/absyntax.cc --- a/absyntax/absyntax.cc Wed Jun 06 16:39:54 2012 +0100 +++ b/absyntax/absyntax.cc Fri Jun 08 19:44:32 2012 +0100 @@ -62,9 +62,9 @@ this->last_column = last_column; this->last_order = last_order; this->datatype = NULL; - this->const_value_real = NULL; - this->const_value_integer = NULL; - this->const_value_uinteger = NULL; + this->const_value_real64 = NULL; + this->const_value_int64 = NULL; + this->const_value_uint64 = NULL; this->const_value_bool = NULL; } diff -r 5f79478142d7 -r 0d1ab9e78574 absyntax/absyntax.hh --- a/absyntax/absyntax.hh Wed Jun 06 16:39:54 2012 +0100 +++ b/absyntax/absyntax.hh Fri Jun 08 19:44:32 2012 +0100 @@ -52,7 +52,7 @@ #include // required for uint64_t, etc... - +/* Determine, for the current platform, which data type (float, double or long double) uses 64 bits. */ /* NOTE: we cant use sizeof() in pre-processor directives, so we do it another way... */ #include #if (LDBL_MANT_DIG == 53) /* NOTE: 64 bit IEC559 real has 53 bits for mantissa! */ @@ -79,12 +79,22 @@ class symbol_c; // forward declaration + + + + + + + + + /* The base class of all symbols */ class symbol_c { public: /* - * Line number for the purposes of error checking + * Line number for the purposes of error checking. + * Annotated (inserted) by stage1_2 */ int first_line; int first_column; @@ -94,6 +104,12 @@ int last_column; const char *last_file; /* filename referenced by last line/column */ long int last_order; /* relative order in which it is read by lexcial analyser */ + + + /* + * Annotations produced during stage 3 + */ + /*** Data type analysis ***/ std::vector candidate_datatypes; /* All possible data types the expression/literal/etc. may take. Filled in stage3 by fill_candidate_datatypes_c class */ /* Data type of the expression/literal/etc. Filled in stage3 by narrow_candidate_datatypes_c * If set to NULL, it means it has not yet been evaluated. @@ -102,10 +118,44 @@ */ symbol_c *datatype; - real64_t *const_value_real; - int64_t *const_value_integer; - uint64_t *const_value_uinteger; - bool *const_value_bool; + /*** constant folding ***/ + /* During stage 3 (semantic analysis/checking) we will be doing constant folding. + * That algorithm will anotate the abstract syntax tree with the result of operations + * on literals (i.e. 44 + 55 will store the result 99). + * Since the same source code (e.g. 1 + 0) may actually be a BOOL or an ANY_INT, + * or an ANY_BIT, we need to handle all possibilities, and determine the result of the + * operation assuming each type. + * For this reason, we have one entry for each possible type, with some expressions + * having more than one entry filled in! + */ + typedef enum { cs_undefined, /* not defined --> const_value is not valid! */ + cs_const_value, /* const value is valid */ + cs_overflow /* result produced overflow or underflow --> const_value is not valid! */ + } const_status_t; + + typedef struct { + const_status_t status; + real64_t value; + } const_value_real64_t; + const_value_real64_t *const_value_real64; /* when NULL --> UNDEFINED */ + + typedef struct { + const_status_t status; + int64_t value; + } const_value_int64_t; + const_value_int64_t *const_value_int64; /* when NULL --> UNDEFINED */ + + typedef struct { + const_status_t status; + uint64_t value; + } const_value_uint64_t; + const_value_uint64_t *const_value_uint64; /* when NULL --> UNDEFINED */ + + typedef struct { + const_status_t status; + bool value; + } const_value_bool_t; + const_value_bool_t *const_value_bool; /* when NULL --> UNDEFINED */ public: diff -r 5f79478142d7 -r 0d1ab9e78574 stage3/constant_folding.cc --- a/stage3/constant_folding.cc Wed Jun 06 16:39:54 2012 +0100 +++ b/stage3/constant_folding.cc Fri Jun 08 19:44:32 2012 +0100 @@ -31,13 +31,85 @@ */ -/* Determine the value of an ST expression. - * Filling in all symbols the correct value. +/* Do constant folding... + * + * I.e., Determine the value of all expressions in which only constant values (i.e. literals) are used. + * The (constant) result of each operation is stored (annotated) in the respective operation symbol + * (e.g.: add_expression_c) in the abstract syntax tree, * * For example: - * 2 + 3 -> returns constant_value_integer = 5 - * 22.2 - 5.0 -> returns constant_value_real = 17.2 + * 2 + 3 -> the constant value '5' is stored in the add_expression_c symbol. + * 22.2 - 5.0 -> the constant value '17.2' is stored in the add_expression_c symbol. * etc... + * + * + * NOTE 1 that some operations and constants can have multiple data types. For example, + * 1 AND 0 + * may be either a BOOL, BYTE, WORD or LWORD. + * + * The same happens with + * 1 + 2 + * which may be signed (e.g. INT) or unsigned (UINT) + * + * For the above reason, instead of storing a single constant value, we actually store 4: + * - bool + * - uint64 + * - int64 + * - real64 + * + * Additionally, since the result of an operation may result in an overflow, we actually + * store the result inside a struct (defined in absyntax.hh) + * + * ** During stage 3 (semantic analysis/checking) we will be doing constant folding. + * * That algorithm will anotate the abstract syntax tree with the result of operations + * * on literals (i.e. 44 + 55 will store the result 99). + * * Since the same source code (e.g. 1 + 0) may actually be a BOOL or an ANY_INT, + * * or an ANY_BIT, we need to handle all possibilities, and determine the result of the + * * operation assuming each type. + * * For this reason, we have one entry for each possible type, with some expressions + * * having more than one entry filled in! + * ** + * typedef enum { cs_undefined, // not defined --> const_value is not valid! + * cs_const_value, // const value is valid + * cs_overflow // result produced overflow or underflow --> const_value is not valid! + * } const_status_t; + * + * typedef struct { + * const_status_t status; + * real64_t value; + * } const_value_real64_t; + * const_value_real64_t *const_value_real64; // when NULL --> UNDEFINED + * + * typedef struct { + * const_status_t status; + * int64_t value; + * } const_value_int64_t; + * const_value_int64_t *const_value_int64; // when NULL --> UNDEFINED + * + * typedef struct { + * const_status_t status; + * uint64_t value; + * } const_value_uint64_t; + * const_value_uint64_t *const_value_uint64; // when NULL --> UNDEFINED + * + * typedef struct { + * const_status_t status; + * bool value; + * } const_value_bool_t; + * const_value_bool_t *const_value_bool; // when NULL --> UNDEFINED + * + * + * + * NOTE 2 + * This file does not print out any error messages! + * We cannot really print out error messages when we find an overflow. Since each operation + * (symbol in the absract syntax tree for that operation) will have up to 4 constant results, + * it may happen that some of them overflow, while other do not. + * We must wait for data type checking to determine the exact data type of each expression + * before we can decide whether or not we should print out an overflow error message. + * + * For this reason, this visitor merely annotates the abstract syntax tree, and leaves the + ` actuall printing of errors for the print_datatype_errors_c class! */ #include "constant_folding.hh" @@ -76,26 +148,31 @@ -#define MALLOC(variable, data_type) \ - variable = (data_type *)malloc(sizeof(data_type)); \ - if (variable == NULL) ERROR; - - -#define DO_OPER(dtype)\ - (NULL != symbol->r_exp->const_value_##dtype ) && \ - (NULL != symbol->l_exp->const_value_##dtype ) - - -#define CHECK_OVERFLOW_SUM(a, b, type)\ - ((((std::numeric_limits< type >::max() - a) < (b)) ? 1 : 0) || \ - (((std::numeric_limits< type >::min() + a) > (b)) ? 1 : 0)) - -#define CHECK_OVERFLOW_SUB(a, b, type)\ - ((((std::numeric_limits< type >::max() - a) < (-b)) ? 1 : 0) || \ - (((std::numeric_limits< type >::min() + a) > (-b)) ? 1 : 0)) - -#define SYMBOL_BOOL_VALUE (symbol->exp->const_value_bool) -#define SYMBOL_REAL_VALUE (symbol->exp->const_value_real) + + + + + + + + +#define NEW_CVALUE(dtype, symbol) \ + (symbol->const_value_##dtype) = new(symbol_c::const_value_##dtype##_t); \ + if ((symbol->const_value_##dtype) == NULL) ERROR; \ + (symbol->const_value_##dtype)->status = symbol_c::cs_undefined; + +#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 + /* The following test is correct in the presence of a NULL pointer, as the logical evaluation will be suspended as soon as the first condition is false! */ +#define VALID_CVALUE(dtype, symbol) ((NULL != (symbol)->const_value_##dtype) && (symbol_c::cs_const_value == (symbol)->const_value_##dtype->status)) +#define ISZERO_CVALUE(dtype, symbol) ((VALID_CVALUE(dtype, symbol)) && (GET_CVALUE(dtype, symbol) == 0)) +#define DO_BIN_OPER(dtype, oper)\ + if (VALID_CVALUE(dtype, symbol->r_exp) && VALID_CVALUE(dtype, symbol->l_exp)) { \ + NEW_CVALUE(dtype, symbol); \ + SET_CVALUE(dtype, symbol, GET_CVALUE(dtype, symbol->l_exp) oper GET_CVALUE(dtype, symbol->r_exp)); \ + } + @@ -110,7 +187,7 @@ if (! (std::numeric_limits::is_iec559) ) STAGE3_WARNING(&null_symbol, &null_symbol, "The platform running the compiler does not implement IEC 559 floating point numbers. " "Any error and/or warning messages related to overflow/underflow of the result of operations on REAL/LREAL literals " - " (i.e. constant folding) may themselves be erroneous, although are most probably correct"); + " (i.e. constant folding) may themselves be erroneous, although are most probably correct."); } @@ -130,116 +207,119 @@ /* B 1.2.1 - Numeric Literals */ /******************************/ void *constant_folding_c::visit(real_c *symbol) { - MALLOC(symbol->const_value_real, real64_t); - *symbol->const_value_real = extract_real_value(symbol); - + NEW_CVALUE(real64, symbol); + SET_CVALUE(real64, symbol, extract_real_value(symbol)); return NULL; } void *constant_folding_c::visit(integer_c *symbol) { - int64_t *integer_value; - - integer_value = (int64_t *)malloc(sizeof(int64_t)); - *integer_value = extract_integer_value(symbol); - symbol->const_value_integer = integer_value; - + NEW_CVALUE( int64, symbol); + SET_CVALUE( int64, symbol, extract_integer_value(symbol)); + NEW_CVALUE(uint64, symbol); + SET_CVALUE(uint64, symbol, extract_integer_value(symbol)); return NULL; } void *constant_folding_c::visit(neg_real_c *symbol) { symbol->exp->accept(*this); - if (NULL == symbol->exp->const_value_real) - ERROR; - symbol->const_value_real = (real64_t*) malloc(sizeof(real64_t)); - *symbol->const_value_real = - *(symbol->exp->const_value_real); - return NULL; -} - - + if (!VALID_CVALUE(real64, symbol->exp)) + return NULL; + NEW_CVALUE(real64, symbol); + SET_CVALUE(real64, symbol, - GET_CVALUE( real64, symbol->exp)); + return NULL; +} + +/* | '-' integer {$$ = new neg_integer_c($2, locloc(@$));} */ void *constant_folding_c::visit(neg_integer_c *symbol) { - int64_t *integer_value; - - integer_value = (int64_t *)malloc(sizeof(int64_t)); - *integer_value = extract_integer_value(symbol); - symbol->const_value_integer = integer_value; - + symbol->exp->accept(*this); + if (VALID_CVALUE(int64, symbol->exp)) { + NEW_CVALUE( int64, symbol); + SET_CVALUE( int64, symbol, - GET_CVALUE( int64, symbol->exp)); + } return NULL; } void *constant_folding_c::visit(binary_integer_c *symbol) { - return NULL; } void *constant_folding_c::visit(octal_integer_c *symbol) { - return NULL; } void *constant_folding_c::visit(hex_integer_c *symbol) { - symbol->const_value_integer = (int64_t*) malloc(sizeof(int64_t)); - *(symbol->const_value_integer) = extract_hex_value(symbol); - - return NULL; -} - - + NEW_CVALUE( int64, symbol); + SET_CVALUE( int64, symbol, extract_hex_value(symbol)); + NEW_CVALUE(uint64, symbol); + SET_CVALUE(uint64, symbol, extract_hex_value(symbol)); + return NULL; +} + + +/* +integer_literal: + integer_type_name '#' signed_integer {$$ = new integer_literal_c($1, $3, locloc(@$));} +| integer_type_name '#' binary_integer {$$ = new integer_literal_c($1, $3, locloc(@$));} +| integer_type_name '#' octal_integer {$$ = new integer_literal_c($1, $3, locloc(@$));} +| integer_type_name '#' hex_integer {$$ = new integer_literal_c($1, $3, locloc(@$));} +*/ +// SYM_REF2(integer_literal_c, type, value) void *constant_folding_c::visit(integer_literal_c *symbol) { symbol->value->accept(*this); - if (NULL == symbol->value->const_value_integer) ERROR; - symbol->const_value_integer = (int64_t*) malloc(sizeof(int64_t)); - *(symbol->const_value_integer) = *(symbol->value->const_value_integer); - + if (VALID_CVALUE( int64, symbol->value)) { + NEW_CVALUE( int64, symbol); + SET_CVALUE( int64, symbol, GET_CVALUE( int64, symbol->value)); + } + if (VALID_CVALUE(uint64, symbol->value)) { + NEW_CVALUE(uint64, symbol); + SET_CVALUE(uint64, symbol, GET_CVALUE(uint64, symbol->value)); + } return NULL; } void *constant_folding_c::visit(real_literal_c *symbol) { symbol->value->accept(*this); - if (NULL == symbol->value->const_value_real) ERROR; - symbol->const_value_real = (real64_t*) malloc(sizeof(real64_t)); - *symbol->const_value_real = *(symbol->value->const_value_real); - + if (VALID_CVALUE(real64, symbol->value)) { + NEW_CVALUE(real64, symbol); + SET_CVALUE(real64, symbol, GET_CVALUE(real64, symbol->value)); + } return NULL; } void *constant_folding_c::visit(bit_string_literal_c *symbol) { - return NULL; } void *constant_folding_c::visit(boolean_literal_c *symbol) { symbol->value->accept(*this); - if (NULL == symbol->value->const_value_bool) ERROR; - symbol->const_value_bool = (bool *)malloc(sizeof(bool)); - *(symbol->const_value_bool) = *(symbol->value->const_value_bool); - + if (VALID_CVALUE(bool, symbol->value)) { + NEW_CVALUE(bool, symbol); + SET_CVALUE(bool, symbol, GET_CVALUE( bool, symbol->value)); + } return NULL; } void *constant_folding_c::visit(boolean_true_c *symbol) { - symbol->const_value_bool = (bool *)malloc(sizeof(bool)); - *(symbol->const_value_bool) = true; - + NEW_CVALUE(bool, symbol); + SET_CVALUE(bool, symbol, true); return NULL; } void *constant_folding_c::visit(boolean_false_c *symbol) { - symbol->const_value_bool = (bool *)malloc(sizeof(bool)); - *(symbol->const_value_bool) = false; - - return NULL; -} - + NEW_CVALUE(bool, symbol); + SET_CVALUE(bool, symbol, false); + return NULL; +} /***************************************/ @@ -251,15 +331,8 @@ void *constant_folding_c::visit(or_expression_c *symbol) { symbol->l_exp->accept(*this); symbol->r_exp->accept(*this); - if (DO_OPER(bool)) { - symbol->const_value_bool = (bool*) malloc(sizeof(bool)); - *(symbol->const_value_bool) = *(symbol->l_exp->const_value_bool) || *(symbol->r_exp->const_value_bool); - } - if (DO_OPER(integer)) { - symbol->const_value_integer = (int64_t*) malloc(sizeof(int64_t)); - *(symbol->const_value_integer) = *(symbol->l_exp->const_value_integer) | *(symbol->r_exp->const_value_integer); - } - + DO_BIN_OPER(bool, ||); + DO_BIN_OPER(uint64, | ); return NULL; } @@ -267,11 +340,8 @@ void *constant_folding_c::visit(xor_expression_c *symbol) { symbol->l_exp->accept(*this); symbol->r_exp->accept(*this); - if (DO_OPER(integer)) { - symbol->const_value_bool = (bool*) malloc(sizeof(bool)); - *(symbol->const_value_bool) = *(symbol->l_exp->const_value_integer) ^ *(symbol->r_exp->const_value_integer); - } - + DO_BIN_OPER(bool, ^); + DO_BIN_OPER(uint64, ^); return NULL; } @@ -279,15 +349,8 @@ void *constant_folding_c::visit(and_expression_c *symbol) { symbol->l_exp->accept(*this); symbol->r_exp->accept(*this); - if (DO_OPER(bool)) { - symbol->const_value_bool = (bool*) malloc(sizeof(bool)); - *(symbol->const_value_bool) = *(symbol->l_exp->const_value_bool) && *(symbol->r_exp->const_value_bool); - } - if (DO_OPER(integer)) { - symbol->const_value_integer = (int64_t*) malloc(sizeof(int64_t)); - *(symbol->const_value_bool) = *(symbol->l_exp->const_value_integer) & *(symbol->r_exp->const_value_integer); - } - + DO_BIN_OPER(bool, &&); + DO_BIN_OPER(uint64, & ); return NULL; } @@ -295,19 +358,10 @@ void *constant_folding_c::visit(equ_expression_c *symbol) { symbol->l_exp->accept(*this); symbol->r_exp->accept(*this); - if (DO_OPER(bool)) { - symbol->const_value_bool = (bool*) malloc(sizeof(bool)); - *(symbol->const_value_bool) = *(symbol->l_exp->const_value_bool) == *(symbol->r_exp->const_value_bool); - } - if (DO_OPER(integer)) { - symbol->const_value_bool = (bool*) malloc(sizeof(bool)); - *(symbol->const_value_bool) = *(symbol->l_exp->const_value_integer) == *(symbol->r_exp->const_value_integer); - } - if (DO_OPER(real)) { - symbol->const_value_bool = (bool*) malloc(sizeof(bool)); - *(symbol->const_value_bool) = *(symbol->l_exp->const_value_real) == *(symbol->r_exp->const_value_real); - } - + DO_BIN_OPER(bool, ==); + DO_BIN_OPER(uint64, ==); + DO_BIN_OPER( int64, ==); + DO_BIN_OPER(real64, ==); return NULL; } @@ -315,19 +369,10 @@ void *constant_folding_c::visit(notequ_expression_c *symbol) { symbol->l_exp->accept(*this); symbol->r_exp->accept(*this); - if (DO_OPER(bool)) { - symbol->const_value_bool = (bool*) malloc(sizeof(bool)); - *(symbol->const_value_bool) = *(symbol->l_exp->const_value_bool) != *(symbol->r_exp->const_value_bool); - } - if (DO_OPER(integer)) { - symbol->const_value_bool = (bool*) malloc(sizeof(bool)); - *(symbol->const_value_bool) = *(symbol->l_exp->const_value_integer) != *(symbol->r_exp->const_value_integer); - } - if (DO_OPER(real)) { - symbol->const_value_bool = (bool*) malloc(sizeof(bool)); - *(symbol->const_value_bool) = *(symbol->l_exp->const_value_real) != *(symbol->r_exp->const_value_real); - } - + DO_BIN_OPER(bool, !=); + DO_BIN_OPER(uint64, !=); + DO_BIN_OPER( int64, !=); + DO_BIN_OPER(real64, !=); return NULL; } @@ -335,15 +380,10 @@ void *constant_folding_c::visit(lt_expression_c *symbol) { symbol->l_exp->accept(*this); symbol->r_exp->accept(*this); - if (DO_OPER(integer)) { - symbol->const_value_bool = (bool*) malloc(sizeof(bool)); - *(symbol->const_value_bool) = *(symbol->l_exp->const_value_integer) < *(symbol->r_exp->const_value_integer); - } - if (DO_OPER(real)) { - symbol->const_value_bool = (bool*) malloc(sizeof(bool)); - *(symbol->const_value_bool) = *(symbol->l_exp->const_value_real) < *(symbol->r_exp->const_value_real); - } - + DO_BIN_OPER(bool, <); + DO_BIN_OPER(uint64, <); + DO_BIN_OPER( int64, <); + DO_BIN_OPER(real64, <); return NULL; } @@ -351,15 +391,10 @@ void *constant_folding_c::visit(gt_expression_c *symbol) { symbol->l_exp->accept(*this); symbol->r_exp->accept(*this); - if (DO_OPER(integer)) { - symbol->const_value_bool = (bool*) malloc(sizeof(bool)); - *(symbol->const_value_bool) = *(symbol->l_exp->const_value_integer) > *(symbol->r_exp->const_value_integer); - } - if (DO_OPER(real)) { - symbol->const_value_bool = (bool*) malloc(sizeof(bool)); - *(symbol->const_value_bool) = *(symbol->l_exp->const_value_real) > *(symbol->r_exp->const_value_real); - } - + DO_BIN_OPER(bool, >); + DO_BIN_OPER(uint64, >); + DO_BIN_OPER( int64, >); + DO_BIN_OPER(real64, >); return NULL; } @@ -367,15 +402,10 @@ void *constant_folding_c::visit(le_expression_c *symbol) { symbol->l_exp->accept(*this); symbol->r_exp->accept(*this); - if (DO_OPER(integer)) { - symbol->const_value_bool = (bool*) malloc(sizeof(bool)); - *(symbol->const_value_bool) = *(symbol->l_exp->const_value_integer) <= *(symbol->r_exp->const_value_integer); - } - if (DO_OPER(real)) { - symbol->const_value_bool = (bool*) malloc(sizeof(bool)); - *(symbol->const_value_bool) = *(symbol->l_exp->const_value_real) <= *(symbol->r_exp->const_value_real); - } - + DO_BIN_OPER(bool, <=); + DO_BIN_OPER(uint64, <=); + DO_BIN_OPER( int64, <=); + DO_BIN_OPER(real64, <=); return NULL; } @@ -383,138 +413,99 @@ void *constant_folding_c::visit(ge_expression_c *symbol) { symbol->l_exp->accept(*this); symbol->r_exp->accept(*this); - if (DO_OPER(integer)) { - symbol->const_value_bool = (bool*) malloc(sizeof(bool)); - *(symbol->const_value_bool) = *(symbol->l_exp->const_value_integer) >= *(symbol->r_exp->const_value_integer); - } - if (DO_OPER(real)) { - symbol->const_value_bool = (bool*) malloc(sizeof(bool)); - *(symbol->const_value_bool) = *(symbol->l_exp->const_value_real) >= *(symbol->r_exp->const_value_real); - } - - return NULL; -} - - + DO_BIN_OPER(bool, >=); + DO_BIN_OPER(uint64, >=); + DO_BIN_OPER( int64, >=); + DO_BIN_OPER(real64, >=); + return NULL; +} + + +#define CHECK_OVERFLOW_SUM(dtype)\ + if (VALID_CVALUE(dtype, symbol)) \ + if ((((std::numeric_limits< dtype##_t >::max() - GET_CVALUE(dtype, symbol->l_exp)) < (GET_CVALUE(dtype, symbol->r_exp))) ? 1 : 0) || \ + (((std::numeric_limits< dtype##_t >::min() + GET_CVALUE(dtype, symbol->l_exp)) > (GET_CVALUE(dtype, symbol->r_exp))) ? 1 : 0)) \ + SET_OVFLOW(dtype, symbol); +#define CHECK_OVERFLOW_real64 \ + if (VALID_CVALUE(real64, symbol)) \ + /* NaN => underflow, overflow, number is a higher precision format, is a complex number (IEEE standard) */ \ + if (isnan(GET_CVALUE(real64, symbol))) \ + SET_OVFLOW(real64, symbol); void *constant_folding_c::visit(add_expression_c *symbol) { symbol->l_exp->accept(*this); symbol->r_exp->accept(*this); - if (DO_OPER(integer)) { - if (CHECK_OVERFLOW_SUM(*(symbol->l_exp->const_value_integer), *(symbol->r_exp->const_value_integer), int64_t)) - STAGE3_ERROR(0, symbol, symbol, "Overflow in constant expression."); - symbol->const_value_integer = (int64_t*) malloc(sizeof(int64_t)); - *(symbol->const_value_integer) = *(symbol->l_exp->const_value_integer) + *(symbol->r_exp->const_value_integer); - } - if (DO_OPER(real)) { - symbol->const_value_real = (real64_t*) malloc(sizeof(real64_t)); - *(symbol->const_value_real) = *(symbol->l_exp->const_value_real) + *(symbol->r_exp->const_value_real); - /* - * According to the IEEE standard, NaN value is used as: - * - representation of a number that has underflowed - * - representation of number that has overflowed - * - number is a higher precision format - * - A complex number - */ - if (isnan(*(symbol->const_value_real))) - STAGE3_ERROR(0, symbol, symbol, "Overflow in constant expression."); - } - - return NULL; -} - - + DO_BIN_OPER(uint64, +); + DO_BIN_OPER( int64, +); + DO_BIN_OPER(real64, +); + CHECK_OVERFLOW_SUM(uint64); + CHECK_OVERFLOW_SUM( int64); + CHECK_OVERFLOW_real64; + return NULL; +} + + +#define CHECK_OVERFLOW_SUB(dtype)\ + if (VALID_CVALUE(dtype, symbol)) \ + if ((((std::numeric_limits< dtype##_t >::max() - GET_CVALUE(dtype, symbol->l_exp)) < (-GET_CVALUE(dtype, symbol->r_exp))) ? 1 : 0) || \ + (((std::numeric_limits< dtype##_t >::min() + GET_CVALUE(dtype, symbol->l_exp)) > (-GET_CVALUE(dtype, symbol->r_exp))) ? 1 : 0)) \ + SET_OVFLOW(dtype, symbol); void *constant_folding_c::visit(sub_expression_c *symbol) { symbol->l_exp->accept(*this); symbol->r_exp->accept(*this); - if (DO_OPER(integer)) { - if (CHECK_OVERFLOW_SUB(*(symbol->l_exp->const_value_integer), *(symbol->r_exp->const_value_integer), int64_t)) - STAGE3_ERROR(0, symbol, symbol, "Overflow in constant expression."); - symbol->const_value_integer = (int64_t*) malloc(sizeof(int64_t)); - *(symbol->const_value_integer) = *(symbol->l_exp->const_value_integer) - *(symbol->r_exp->const_value_integer); - } - if (DO_OPER(real)) { - symbol->const_value_real = (real64_t*) malloc(sizeof(real64_t)); - *(symbol->const_value_real) = *(symbol->l_exp->const_value_real) - *(symbol->r_exp->const_value_real); - /* - * According to the IEEE standard, NaN value is used as: - * - representation of a number that has underflowed - * - representation of number that has overflowed - * - number is a higher precision format - * - A complex number - */ - if (isnan(*(symbol->const_value_real))) - STAGE3_ERROR(0, symbol, symbol, "Overflow in constant expression."); - } - - return NULL; -} - - + DO_BIN_OPER(uint64, -); + DO_BIN_OPER( int64, -); + DO_BIN_OPER(real64, -); + CHECK_OVERFLOW_SUB(uint64); + CHECK_OVERFLOW_SUB( int64); + CHECK_OVERFLOW_real64; + return NULL; +} + + +/* TODO!!! */ +#define CHECK_OVERFLOW_MUL(dtype)\ + if (VALID_CVALUE(dtype, symbol)) \ + if (false) \ + SET_OVFLOW(dtype, symbol); void *constant_folding_c::visit(mul_expression_c *symbol) { symbol->l_exp->accept(*this); symbol->r_exp->accept(*this); - if (DO_OPER(integer)) { - symbol->const_value_integer = (int64_t*) malloc(sizeof(int64_t)); - *(symbol->const_value_integer) = *(symbol->l_exp->const_value_integer) * *(symbol->r_exp->const_value_integer); - } - if (DO_OPER(real)) { - symbol->const_value_real = (real64_t*) malloc(sizeof(real64_t)); - *(symbol->const_value_real) = *(symbol->l_exp->const_value_real) * *(symbol->r_exp->const_value_real); - /* - * According to the IEEE standard, NaN value is used as: - * - representation of a number that has underflowed - * - representation of number that has overflowed - * - number is a higher precision format - * - A complex number - */ - if (isnan(*(symbol->const_value_real))) - STAGE3_ERROR(0, symbol, symbol, "Overflow in constant expression."); - } - - return NULL; -} - - + DO_BIN_OPER(uint64, *); + DO_BIN_OPER( int64, *); + DO_BIN_OPER(real64, *); + CHECK_OVERFLOW_MUL(uint64); + CHECK_OVERFLOW_MUL( int64); + CHECK_OVERFLOW_real64; + return NULL; +} + + + +/* TODO!!! */ +#define CHECK_OVERFLOW_DIV(dtype)\ + if (VALID_CVALUE(dtype, symbol)) \ + if (false) \ + SET_OVFLOW(dtype, symbol); void *constant_folding_c::visit(div_expression_c *symbol) { symbol->l_exp->accept(*this); symbol->r_exp->accept(*this); - if (DO_OPER(integer)) { - if (*(symbol->r_exp->const_value_integer) == 0) - STAGE3_ERROR(0, symbol, symbol, "Division by zero in constant expression."); - symbol->const_value_integer = (int64_t*) malloc(sizeof(int64_t)); - *(symbol->const_value_integer) = *(symbol->l_exp->const_value_integer) / *(symbol->r_exp->const_value_integer); - } - if (DO_OPER(real)) { - if (*(symbol->r_exp->const_value_real) == 0) - STAGE3_ERROR(0, symbol, symbol, "Division by zero in constant expression."); - symbol->const_value_real = (real64_t*) malloc(sizeof(real64_t)); - *(symbol->const_value_real) = *(symbol->l_exp->const_value_real) / *(symbol->r_exp->const_value_real); - /* - * According to the IEEE standard, NaN value is used as: - * - representation of a number that has underflowed - * - representation of number that has overflowed - * - number is a higher precision format - * - A complex number - */ - if (isnan(*(symbol->const_value_real))) - STAGE3_ERROR(0, symbol, symbol, "Overflow in constant expression."); - } - - return NULL; -} - - + if (ISZERO_CVALUE(uint64, symbol->r_exp)) {NEW_CVALUE(uint64, symbol); SET_OVFLOW(uint64, symbol);} else {DO_BIN_OPER(uint64, /); CHECK_OVERFLOW_DIV(uint64)}; + if (ISZERO_CVALUE( int64, symbol->r_exp)) {NEW_CVALUE( int64, symbol); SET_OVFLOW( int64, symbol);} else {DO_BIN_OPER( int64, /); CHECK_OVERFLOW_DIV( int64)}; + if (ISZERO_CVALUE(real64, symbol->r_exp)) {NEW_CVALUE(real64, symbol); SET_OVFLOW(real64, symbol);} else {DO_BIN_OPER(real64, /); CHECK_OVERFLOW_real64;}; + return NULL; +} + + +/* TODO!!! */ +#define CHECK_OVERFLOW_MOD(dtype)\ + if (VALID_CVALUE(dtype, symbol)) \ + if (false) \ + SET_OVFLOW(dtype, symbol); void *constant_folding_c::visit(mod_expression_c *symbol) { symbol->l_exp->accept(*this); symbol->r_exp->accept(*this); - if (DO_OPER(integer)) { - if (*(symbol->r_exp->const_value_integer) == 0) - STAGE3_ERROR(0, symbol, symbol, "Division by zero in constant expression."); - symbol->const_value_integer = (int64_t*) malloc(sizeof(int64_t)); - *(symbol->const_value_integer) = *(symbol->l_exp->const_value_integer) % *(symbol->r_exp->const_value_integer); - - } - + if (ISZERO_CVALUE(uint64, symbol->r_exp)) {NEW_CVALUE(uint64, symbol); SET_OVFLOW(uint64, symbol);} else {DO_BIN_OPER(uint64, %); CHECK_OVERFLOW_MOD(uint64)}; + if (ISZERO_CVALUE( int64, symbol->r_exp)) {NEW_CVALUE( int64, symbol); SET_OVFLOW( int64, symbol);} else {DO_BIN_OPER( int64, %); CHECK_OVERFLOW_MOD( int64)}; return NULL; } @@ -522,34 +513,40 @@ void *constant_folding_c::visit(power_expression_c *symbol) { symbol->l_exp->accept(*this); symbol->r_exp->accept(*this); - if ((NULL != symbol->l_exp->const_value_real) && (NULL != symbol->r_exp->const_value_integer)) { - symbol->const_value_real = (real64_t*) malloc(sizeof(real64_t)); - *(symbol->const_value_real) = pow(*(symbol->l_exp->const_value_real), *(symbol->r_exp->const_value_integer)); - /* - * According to the IEEE standard, NaN value is used as: - * - representation of a number that has underflowed - * - representation of number that has overflowed - * - number is a higher precision format - * - A complex number - */ - if (isnan(*(symbol->const_value_real))) - STAGE3_ERROR(0, symbol, symbol, "Overflow in constant expression."); - } - - return NULL; -} - - + /* NOTE: If the const_value in symbol->r_exp is within the limits of both int64 and uint64, then we do both operations. + * That is OK, as the result should be identicial (we do create an unnecessary CVALUE variable, but who cares?). + * If only one is valid, then that is the oper we will do! + */ + if (VALID_CVALUE(real64, symbol->l_exp) && VALID_CVALUE( int64, symbol->r_exp)) { + NEW_CVALUE(real64, symbol); + SET_CVALUE(real64, symbol, pow(GET_CVALUE(real64, symbol->l_exp), GET_CVALUE( int64, symbol->r_exp))); + } + if (VALID_CVALUE(real64, symbol->l_exp) && VALID_CVALUE(uint64, symbol->r_exp)) { + NEW_CVALUE(real64, symbol); + SET_CVALUE(real64, symbol, pow(GET_CVALUE(real64, symbol->l_exp), GET_CVALUE(uint64, symbol->r_exp))); + } + CHECK_OVERFLOW_real64; + return NULL; +} + + +/* TODO!!! */ +#define CHECK_OVERFLOW_NEG(dtype)\ + if (VALID_CVALUE(dtype, symbol)) \ + if (false) \ + SET_OVFLOW(dtype, symbol); void *constant_folding_c::visit(neg_expression_c *symbol) { symbol->exp->accept(*this); - if (NULL != symbol->exp->const_value_integer) { - symbol->const_value_integer = (int64_t*) malloc(sizeof(int64_t)); - *(symbol->const_value_integer) = - *(symbol->exp->const_value_integer); - } - if (NULL != symbol->exp->const_value_real) { - symbol->const_value_real = (real64_t*) malloc(sizeof(real64_t)); - *(symbol->const_value_real) = - *(symbol->exp->const_value_real); - } + if (VALID_CVALUE( int64, symbol->exp)) { + NEW_CVALUE( int64, symbol); + SET_CVALUE( int64, symbol, - GET_CVALUE( int64, symbol->exp)); + } + if (VALID_CVALUE(real64, symbol->exp)) { + NEW_CVALUE(real64, symbol); + SET_CVALUE(real64, symbol, - GET_CVALUE(real64, symbol->exp)); + } + CHECK_OVERFLOW_NEG( int64); + CHECK_OVERFLOW_real64; return NULL; } @@ -557,13 +554,15 @@ void *constant_folding_c::visit(not_expression_c *symbol) { symbol->exp->accept(*this); - if (NULL != symbol->exp->const_value_bool) { - symbol->const_value_bool = (bool*) malloc(sizeof(bool)); - *(symbol->const_value_bool) = !*(symbol->exp->const_value_bool); - } - - return NULL; -} - - - + if (VALID_CVALUE( bool, symbol->exp)) { + NEW_CVALUE( bool, symbol); + SET_CVALUE( bool, symbol, ! GET_CVALUE( bool, symbol->exp)); + } + if (VALID_CVALUE(uint64, symbol->exp)) { + NEW_CVALUE(uint64, symbol); + SET_CVALUE(uint64, symbol, ~ GET_CVALUE(uint64, symbol->exp)); + } + return NULL; +} + +