Commit cc756c32 authored by Botond Baranyi's avatar Botond Baranyi
Browse files

Handled special float values in str2float and float2str (bug 527847)



Change-Id: Id20fcdd4d76e710a32037bc0d7ae71a42b5963fc
Signed-off-by: Botond Baranyi's avatarBotond Baranyi <botond.baranyi@ericsson.com>
parent 325363e0
......@@ -597,6 +597,15 @@ namespace Common {
string *float2str(const Real& value)
{
if (value == REAL_INFINITY) {
return new string("infinity");
}
if (value == -REAL_INFINITY) {
return new string("-infinity");
}
if (value != value) {
return new string("not_a_number");
}
char str_buf[64];
if ( (value > -MAX_DECIMAL_FLOAT && value <= -MIN_DECIMAL_FLOAT)
|| (value >= MIN_DECIMAL_FLOAT && value < MAX_DECIMAL_FLOAT)
......
......@@ -5421,8 +5421,31 @@ void Value::chk_expr_operand_execute_refd(Value *v1,
return;
} else if (v_last->valuetype != V_CSTR) return;
const string& s = v_last->get_val_str();
enum { S_INITIAL, S_INITIAL_WS, S_FIRST_M, S_ZERO_M, S_MORE_M, S_FIRST_F,
S_MORE_F, S_INITIAL_E, S_FIRST_E, S_ZERO_E, S_MORE_E, S_END, S_ERR }
size_t start = 0;
size_t end = s.size();
while (string::is_whitespace(s[start])) {
if (start == 0) {
val->warning("Leading whitespace was detected and ignored in the "
"operand of operation `%s'", opname);
}
++start;
}
while (end > start && string::is_whitespace(s[end - 1])) {
if (end == s.size()) {
val->warning("Trailing whitespace was detected and ignored in the "
"operand of operation `%s'", opname);
}
--end;
}
if ((end - start == 8 && s.find("infinity", start) == start) ||
(end - start == 9 && s.find("-infinity", start) == start) ||
(end - start == 12 && s.find("not_a_number", start) == start)) {
// special values => OK
return;
}
// otherwise look for a real number
enum { S_INITIAL, S_FIRST_M, S_ZERO_M, S_MORE_M, S_FIRST_F,
S_MORE_F, S_INITIAL_E, S_FIRST_E, S_ZERO_E, S_MORE_E, S_ERR }
state = S_INITIAL;
// state: expected characters
// S_INITIAL, S_INITIAL_WS: +, -, first digit of integer part in mantissa,
......@@ -5436,21 +5459,14 @@ void Value::chk_expr_operand_execute_refd(Value *v1,
// S_ZERO_E, S_MORE_E: more digits of exponent, trailing whitespace
// S_END: trailing whitespace
// S_ERR: error was found, stop
for (size_t i = 0; i < s.size(); i++) {
for (size_t i = start; i < end; i++) {
char c = s[i];
switch (state) {
case S_INITIAL:
case S_INITIAL_WS:
if (c == '+' || c == '-') state = S_FIRST_M;
else if (c == '0') state = S_ZERO_M;
else if (c >= '1' && c <= '9') state = S_MORE_M;
else if (string::is_whitespace(c)) {
if (state == S_INITIAL) {
val->warning("Leading whitespace was detected and ignored in the "
"operand of operation `%s'", opname);
state = S_INITIAL_WS;
}
} else state = S_ERR;
else state = S_ERR;
break;
case S_FIRST_M:
if (c == '0') state = S_ZERO_M;
......@@ -5479,7 +5495,6 @@ void Value::chk_expr_operand_execute_refd(Value *v1,
case S_MORE_F:
if (c == 'E' || c == 'e') state = S_INITIAL_E;
else if (c >= '0' && c <= '9') {}
else if (string::is_whitespace(c)) state = S_END;
else state = S_ERR;
break;
case S_INITIAL_E:
......@@ -5498,17 +5513,13 @@ void Value::chk_expr_operand_execute_refd(Value *v1,
val->warning("Leading zero digit was detected and ignored in the "
"exponent of the operand of operation `%s'", opname);
state = S_MORE_E;
} else if (string::is_whitespace(c)) state = S_END;
}
else state = S_ERR;
break;
case S_MORE_E:
if (c >= '0' && c <= '9') {}
else if (string::is_whitespace(c)) state = S_END;
else state = S_ERR;
break;
case S_END:
if (!string::is_whitespace(c)) state = S_ERR;
break;
default:
break;
}
......@@ -5529,7 +5540,6 @@ void Value::chk_expr_operand_execute_refd(Value *v1,
}
switch (state) {
case S_INITIAL:
case S_INITIAL_WS:
val->error("%s operand of operation `%s' should be a string containing a "
"valid float value instead of an empty string", opnum, opname);
set_valuetype(V_ERROR);
......@@ -5554,10 +5564,6 @@ void Value::chk_expr_operand_execute_refd(Value *v1,
opnum, opname);
set_valuetype(V_ERROR);
break;
case S_END:
val->warning("Trailing whitespace was detected and ignored in the "
"operand of operation `%s'", opname);
break;
default:
break;
}
......@@ -8096,7 +8102,20 @@ void Value::chk_expr_operand_execute_refd(Value *v1,
case OPTYPE_STR2FLOAT: {
if(is_unfoldable()) break;
v1=u.expr.v1->get_value_refd_last();
Real r=string2Real(v1->get_val_str(), *u.expr.v1);
const string& s = v1->get_val_str();
Real r;
if (s.find("-infinity") != s.size()) {
r = -REAL_INFINITY;
}
else if (s.find("infinity") != s.size()) {
r = REAL_INFINITY;
}
else if (s.find("not_a_number") != s.size()) {
r = REAL_NAN;
}
else {
r = string2Real(s, *u.expr.v1);
}
clean_up();
valuetype=V_REAL;
u.val_Real=r;
......
......@@ -1221,120 +1221,146 @@ double str2float(const CHARSTRING& value)
if (value_len == 0) TTCN_error("The argument of function str2float() is "
"an empty string, which does not represent a valid float value.");
const char *value_str = value;
enum { S_INITIAL, S_FIRST_M, S_ZERO_M, S_MORE_M, S_FIRST_F, S_MORE_F,
S_INITIAL_E, S_FIRST_E, S_ZERO_E, S_MORE_E, S_END, S_ERR }
state = S_INITIAL;
// state: expected characters
// S_INITIAL: +, -, first digit of integer part in mantissa,
// leading whitespace
// S_FIRST_M: first digit of integer part in mantissa
// S_ZERO_M, S_MORE_M: more digits of mantissa, decimal dot, E
// S_FIRST_F: first digit of fraction
// S_MORE_F: more digits of fraction, E, trailing whitespace
// S_INITIAL_E: +, -, first digit of exponent
// S_FIRST_E: first digit of exponent
// S_ZERO_E, S_MORE_E: more digits of exponent, trailing whitespace
// S_END: trailing whitespace
// S_ERR: error was found, stop
boolean leading_ws = FALSE, leading_zero = FALSE;
for (int i = 0; i < value_len; i++) {
char c = value_str[i];
size_t start = 0;
size_t end = value_len;
boolean leading_ws = FALSE;
boolean trailing_ws = FALSE;
boolean leading_zero = FALSE;
double ret_val;
while (is_whitespace(value_str[start])) {
leading_ws = TRUE;
++start;
}
while (end > start && is_whitespace(value_str[end - 1])) {
trailing_ws = TRUE;
--end;
}
if ((end - start == 8 &&
strncmp(value_str + start, "infinity", end - start) == 0)) {
ret_val = INFINITY;
}
else if ((end - start == 9 &&
strncmp(value_str + start, "-infinity", end - start) == 0)) {
ret_val = -INFINITY;
}
else if ((end - start == 12 &&
strncmp(value_str + start, "not_a_number", end - start) == 0)) {
#ifdef NAN
ret_val = NAN;
#else
ret_val = INFINITY + (-INFINITY);
#endif
}
else {
enum { S_INITIAL, S_FIRST_M, S_ZERO_M, S_MORE_M, S_FIRST_F, S_MORE_F,
S_INITIAL_E, S_FIRST_E, S_ZERO_E, S_MORE_E, S_ERR }
state = S_INITIAL;
// state: expected characters
// S_INITIAL: +, -, first digit of integer part in mantissa,
// leading whitespace
// S_FIRST_M: first digit of integer part in mantissa
// S_ZERO_M, S_MORE_M: more digits of mantissa, decimal dot, E
// S_FIRST_F: first digit of fraction
// S_MORE_F: more digits of fraction, E, trailing whitespace
// S_INITIAL_E: +, -, first digit of exponent
// S_FIRST_E: first digit of exponent
// S_ZERO_E, S_MORE_E: more digits of exponent, trailing whitespace
// S_END: trailing whitespace
// S_ERR: error was found, stop
for (int i = 0; i < value_len; i++) {
char c = value_str[i];
switch (state) {
case S_INITIAL:
if (c == '+' || c == '-') state = S_FIRST_M;
else if (c == '0') state = S_ZERO_M;
else if (c >= '1' && c <= '9') state = S_MORE_M;
else state = S_ERR;
break;
case S_FIRST_M: // first mantissa digit
if (c == '0') state = S_ZERO_M;
else if (c >= '1' && c <= '9') state = S_MORE_M;
else state = S_ERR;
break;
case S_ZERO_M: // leading mantissa zero
if (c == '.') state = S_FIRST_F;
else if (c == 'E' || c == 'e') state = S_INITIAL_E;
else if (c >= '0' && c <= '9') {
leading_zero = TRUE;
state = S_MORE_M;
} else state = S_ERR;
break;
case S_MORE_M:
if (c == '.') state = S_FIRST_F;
else if (c == 'E' || c == 'e') state = S_INITIAL_E;
else if (c >= '0' && c <= '9') {}
else state = S_ERR;
break;
case S_FIRST_F:
if (c >= '0' && c <= '9') state = S_MORE_F;
else state = S_ERR;
break;
case S_MORE_F:
if (c == 'E' || c == 'e') state = S_INITIAL_E;
else if (c >= '0' && c <= '9') {}
else state = S_ERR;
break;
case S_INITIAL_E:
if (c == '+' || c == '-') state = S_FIRST_E;
else if (c == '0') state = S_ZERO_E;
else if (c >= '1' && c <= '9') state = S_MORE_E;
else state = S_ERR;
break;
case S_FIRST_E:
if (c == '0') state = S_ZERO_E;
else if (c >= '1' && c <= '9') state = S_MORE_E;
else state = S_ERR;
break;
case S_ZERO_E:
if (c >= '0' && c <= '9') {
leading_zero = TRUE;
state = S_MORE_E;
}
else state = S_ERR;
break;
case S_MORE_E:
if (c >= '0' && c <= '9') {}
else state = S_ERR;
break;
default:
break;
}
if (state == S_ERR) {
TTCN_error_begin("The argument of function str2float(), which is ");
value.log();
TTCN_Logger::log_event_str(", does not represent a valid float "
"value. Invalid character `");
TTCN_Logger::log_char_escaped(c);
TTCN_Logger::log_event("' was found at index %d.", i);
TTCN_error_end();
}
}
switch (state) {
case S_INITIAL:
if (c == '+' || c == '-') state = S_FIRST_M;
else if (c == '0') state = S_ZERO_M;
else if (c >= '1' && c <= '9') state = S_MORE_M;
else if (is_whitespace(c)) leading_ws = TRUE;
else state = S_ERR;
break;
case S_FIRST_M: // first mantissa digit
if (c == '0') state = S_ZERO_M;
else if (c >= '1' && c <= '9') state = S_MORE_M;
else state = S_ERR;
break;
case S_ZERO_M: // leading mantissa zero
if (c == '.') state = S_FIRST_F;
else if (c == 'E' || c == 'e') state = S_INITIAL_E;
else if (c >= '0' && c <= '9') {
leading_zero = TRUE;
state = S_MORE_M;
} else state = S_ERR;
break;
case S_MORE_M:
if (c == '.') state = S_FIRST_F;
else if (c == 'E' || c == 'e') state = S_INITIAL_E;
else if (c >= '0' && c <= '9') {}
else state = S_ERR;
break;
case S_FIRST_F:
if (c >= '0' && c <= '9') state = S_MORE_F;
else state = S_ERR;
break;
case S_MORE_F:
if (c == 'E' || c == 'e') state = S_INITIAL_E;
else if (c >= '0' && c <= '9') {}
else if (is_whitespace(c)) state = S_END;
else state = S_ERR;
break;
case S_INITIAL_E:
if (c == '+' || c == '-') state = S_FIRST_E;
else if (c == '0') state = S_ZERO_E;
else if (c >= '1' && c <= '9') state = S_MORE_E;
else state = S_ERR;
break;
case S_FIRST_E:
if (c == '0') state = S_ZERO_E;
else if (c >= '1' && c <= '9') state = S_MORE_E;
else state = S_ERR;
break;
case S_ZERO_E:
if (c >= '0' && c <= '9') {
leading_zero = TRUE;
state = S_MORE_E;
} else if (is_whitespace(c)) state = S_END;
else state = S_ERR;
break;
case S_MORE_E:
if (c >= '0' && c <= '9') {}
else if (is_whitespace(c)) state = S_END;
else state = S_ERR;
// OK, originally
break;
case S_END:
if (!is_whitespace(c)) state = S_ERR;
case S_ZERO_M:
case S_MORE_M:
// OK now (decimal dot missing after mantissa)
break;
default:
case S_FIRST_F:
// OK now (fraction part missing)
break;
}
if (state == S_ERR) {
default:
TTCN_error_begin("The argument of function str2float(), which is ");
value.log();
TTCN_Logger::log_event_str(", does not represent a valid float "
"value. Invalid character `");
TTCN_Logger::log_char_escaped(c);
TTCN_Logger::log_event("' was found at index %d.", i);
TTCN_Logger::log_event_str(", does not represent a valid float value. "
"Premature end of the string.");
TTCN_error_end();
break;
}
}
switch (state) {
case S_MORE_F:
case S_ZERO_E:
case S_MORE_E:
// OK, originally
break;
case S_ZERO_M:
case S_MORE_M:
// OK now (decimal dot missing after mantissa)
break;
case S_FIRST_F:
// OK now (fraction part missing)
break;
default:
TTCN_error_begin("The argument of function str2float(), which is ");
value.log();
TTCN_Logger::log_event_str(", does not represent a valid float value. "
"Premature end of the string.");
TTCN_error_end();
break;
ret_val = atof(value_str);
}
if (leading_ws) {
TTCN_warning_begin("Leading whitespace was detected in the argument "
......@@ -1350,14 +1376,14 @@ double str2float(const CHARSTRING& value)
TTCN_Logger::log_char('.');
TTCN_warning_end();
}
if (state == S_END) {
if (trailing_ws) {
TTCN_warning_begin("Trailing whitespace was detected in the argument "
"of function str2float(): ");
value.log();
TTCN_Logger::log_char('.');
TTCN_warning_end();
}
return atof(value_str);
return ret_val;
}
// C.33 - regexp
......@@ -2801,6 +2827,15 @@ HEXSTRING str2hex(const CHARSTRING_ELEMENT& value)
CHARSTRING float2str(double value)
{
if (value == INFINITY) {
return CHARSTRING("infinity");
}
if (value == -INFINITY) {
return CHARSTRING("-infinity");
}
if (value != value) {
return CHARSTRING("not_a_number");
}
boolean f = value == 0.0
|| (value > -MAX_DECIMAL_FLOAT && value <= -MIN_DECIMAL_FLOAT)
|| (value >= MIN_DECIMAL_FLOAT && value < MAX_DECIMAL_FLOAT);
......
......@@ -85,6 +85,9 @@ modulepar charstring f2spar4 := float2str(-0.345)
modulepar charstring f2spar5 := float2str(0.1234567)
modulepar charstring f2spar6 := float2str(123456748901.0)
modulepar charstring f2spar7 := float2str(123456758901.0)
modulepar charstring f2spar8 := float2str(infinity)
modulepar charstring f2spar9 := float2str(-infinity)
modulepar charstring f2spar10 := float2str(not_a_number)
testcase float_to_str() runs on PDTestComponent{
......@@ -117,7 +120,18 @@ testcase float_to_str() runs on PDTestComponent{
and (f2spar7 == float2str(123456758901.0)))
{setverdict(pass);}
else {setverdict(fail);}
if ((f2spar8 == "infinity")
and (f2spar8 == float2str(infinity)))
{setverdict(pass);}
else {setverdict(fail);}
if ((f2spar9 == "-infinity")
and (f2spar9 == float2str(-infinity)))
{setverdict(pass);}
else {setverdict(fail);}
if ((f2spar10 == "not_a_number")
and (f2spar10 == float2str(not_a_number)))
{setverdict(pass);}
else {setverdict(fail);}
}
control {
......
......@@ -76,6 +76,9 @@ const charstring f2scon4 := float2str(-0.345)
const charstring f2scon5 := float2str(0.1234567)
const charstring f2scon6 := float2str(123456748901.0)
const charstring f2scon7 := float2str(123456758901.0)
const charstring f2scon8 := float2str(infinity);
const charstring f2scon9 := float2str(-infinity);
const charstring f2scon10 := float2str(not_a_number);
testcase float_to_str() runs on PDTestComponent{ //In testcase definition//
......@@ -115,6 +118,21 @@ testcase float_to_str() runs on PDTestComponent{ //In testcase definition//
{setverdict(pass);}
else {setverdict(fail);} //^In else statement// \
//^warning\: Control never reaches this code because of previous effective condition\(s\)//
if ((f2scon8 == "infinity")
and (f2scon8 == float2str(infinity)))
{setverdict(pass);}
else {setverdict(fail);} //^In else statement// \
//^warning\: Control never reaches this code because of previous effective condition\(s\)//
if ((f2scon9 == "-infinity")
and (f2scon9 == float2str(-infinity)))
{setverdict(pass);}
else {setverdict(fail);} //^In else statement// \
//^warning\: Control never reaches this code because of previous effective condition\(s\)//
if ((f2scon10 == "not_a_number")
and (f2scon10 == float2str(not_a_number)))
{setverdict(pass);}
else {setverdict(fail);} //^In else statement// \
//^warning\: Control never reaches this code because of previous effective condition\(s\)//
}
control {
......
......@@ -94,6 +94,10 @@ modulepar float s2fpar11:= str2float("-0");
modulepar float s2fpar12:= str2float("-0.");
modulepar float s2fpar13:= str2float("-0.0");
modulepar float s2fpar14:= str2float("infinity");
modulepar float s2fpar15:= str2float("-infinity");
modulepar float s2fpar16:= str2float("not_a_number");
// modulepar prevents constant folding
......@@ -119,6 +123,10 @@ modulepar charstring s2fmp11_str:= "-0";
modulepar charstring s2fmp12_str:= "-0.";
modulepar charstring s2fmp13_str:= "-0.0";
modulepar charstring s2fmp14_str := "infinity";
modulepar charstring s2fmp15_str := "-infinity";
modulepar charstring s2fmp16_str := "not_a_number";
//modulepar float s2fmp := str2float("")
modulepar float s2fmp := str2float("0.0")
......@@ -149,6 +157,10 @@ modulepar float s2fmp11:= str2float("-0");
modulepar float s2fmp12:= str2float("-0.");
modulepar float s2fmp13:= str2float("-0.0");
modulepar float s2fmp14:= str2float("infinity");
modulepar float s2fmp15:= str2float("-infinity");
modulepar float s2fmp16:= str2float("not_a_number");
testcase str_to_float() runs on PDTestComponent{ //In testcase definition//
......@@ -245,6 +257,19 @@ testcase str_to_float() runs on PDTestComponent{ //In testcase definition//
and (s2fpar13== -0.0))
{setverdict(pass);}
else {setverdict(fail, __LINE__);}
if ((s2fpar14 == str2float("infinity"))
and (s2fpar14 == infinity))
{setverdict(pass);}
else {setverdict(fail, __LINE__);}
if ((s2fpar15 == str2float("-infinity"))
and (s2fpar15 == -infinity))
{setverdict(pass);}
else {setverdict(fail, __LINE__);}
if ((s2fpar16 == str2float("not_a_number"))
and (s2fpar16 == not_a_number))
{setverdict(pass);}
else {setverdict(fail, __LINE__);}
// run-time
if ((s2fmp == str2float(s2fmp_str))
and (s2fmp == 0.0))
......@@ -329,6 +354,18 @@ testcase str_to_float() runs on PDTestComponent{ //In testcase definition//
and (s2fmp13 == -0.0))
{setverdict(pass);}
else {setverdict(fail, __LINE__);}
if ((s2fmp14 == str2float(s2fmp14_str))
and (s2fmp14 == infinity))
{setverdict(pass);}
else {setverdict(fail, __LINE__);}
if ((s2fmp15 == str2float(s2fmp15_str))
and (s2fmp15 == -infinity))
{setverdict(pass);}
else {setverdict(fail, __LINE__);}
if ((s2fmp16 == str2float(s2fmp16_str))
and (s2fmp16 == not_a_number))
{setverdict(pass);}
else {setverdict(fail, __LINE__);}
}
......
......@@ -81,24 +81,14 @@ const float s2fcon11:= str2float("-0");
const float s2fcon12:= str2float("-0.");
const float s2fcon13:= str2float("-0.0");
// HL67862
const charstring s2fmp7_str := "1";
const charstring s2fmp7m_str:= "-1";
const charstring s2fmp8m_str:= "-1.";
const charstring s2fmp8_str := "1.";
const charstring s2fmp9_str := "+001";
const charstring s2fmp10_str:= "+001.";
const charstring s2fmp11_str:= "-0";
const charstring s2fmp12_str:= "-0.";
const charstring s2fmp13_str:= "-0.0";
const float s2fcon14:= str2float("infinity");
const float s2fcon15:= str2float("-infinity");
const float s2fcon16:= str2float("not_a_number");
testcase str_to_float() runs on PDTestComponent{ //In testcase definition//
// compile-time
if ((s2fcon == str2float("0.0"))
and (s2fcon == 0.0))
{setverdict(pass);}
......@@ -183,64 +173,18 @@ testcase str_to_float() runs on PDTestComponent{ //In testcase definition//
{setverdict(pass);}
else {setverdict(fail);} //^In else statement// \
//^warning\: Control never reaches this code because of previous effective condition\(s\)//
/* run-time
if ((s2fmp == str2float(s2fmp_str))
and (s2fmp == 0.0))
{setverdict(pass);}
else {setverdict(fail);}
if ((s2fmp1 == str2float(s2fmp1_str))
and (s2fmp1 == 12345678901.0))
{setverdict(pass);}
else {setverdict(fail);}
if ((s2fmp2 == str2float("000000000000" & "12345678901.0"))
and (s2fmp2 == 12345678901.0))
{setverdict(pass);}
else {setverdict(fail);}
if ((s2fmp3 == str2float("-12" & "345678901.0"))
and (s2fmp3 == -12345678901.0))
{setverdict(pass);}
else {setverdict(fail);}
if ((s2fmp4 == str2float(s2fmp4_str))
and (s2fmp4 == 1234.0))
{setverdict(pass);}
else {setverdict(fail);}
if ((s2fmp5 == str2float(s2fmp5_str))
and (s2fmp5 == 1.234))
{setverdict(pass);}
else {setverdict(fail);}
if ((s2fmp6 == str2float(s2fmp6_str))
and (s2fmp6 == 1.0))
{setverdict(pass);}