Merge pull request #2085 from bbbradsmith/numerical_constant_errors-float

Numerical constant errors and improvements (float)
This commit is contained in:
Bob Andrews
2023-08-25 22:30:07 +02:00
committed by GitHub
6 changed files with 78 additions and 25 deletions

View File

@@ -670,6 +670,10 @@ const Type* ArithmeticConvert (const Type* lhst, const Type* rhst)
** floating point types are not (yet) supported.
** The integral promotions are performed on both operands.
*/
if (IsClassFloat(lhst) || IsClassFloat(rhst)) {
Error ("Floating point arithmetic not supported.");
return type_long;
}
lhst = IntPromotion (lhst);
rhst = IntPromotion (rhst);

View File

@@ -1901,31 +1901,46 @@ static void UnaryOp (ExprDesc* Expr)
/* Get the expression */
hie10 (Expr);
/* We can only handle integer types */
if (!IsClassInt (Expr->Type)) {
Error ("Argument must have integer type");
ED_MakeConstAbsInt (Expr, 1);
}
/* Check for a constant numeric expression */
if (ED_IsConstAbs (Expr)) {
/* Value is numeric */
switch (Tok) {
case TOK_MINUS: Expr->IVal = -Expr->IVal; break;
case TOK_PLUS: break;
case TOK_COMP: Expr->IVal = ~Expr->IVal; break;
default: Internal ("Unexpected token: %d", Tok);
if (IsClassFloat (Expr->Type)) {
switch (Tok) {
case TOK_MINUS: Expr->V.FVal = FP_D_Sub(FP_D_Make(0.0),Expr->V.FVal); break;
case TOK_PLUS: break;
case TOK_COMP: Error ("Unary ~ operator not valid for floating point constant"); break;
default: Internal ("Unexpected token: %d", Tok);
}
} else {
if (!IsClassInt (Expr->Type)) {
Error ("Constant argument must have integer or float type");
ED_MakeConstAbsInt (Expr, 1);
}
/* Value is numeric */
switch (Tok) {
case TOK_MINUS: Expr->IVal = -Expr->IVal; break;
case TOK_PLUS: break;
case TOK_COMP: Expr->IVal = ~Expr->IVal; break;
default: Internal ("Unexpected token: %d", Tok);
}
/* Adjust the type of the expression */
Expr->Type = IntPromotion (Expr->Type);
/* Limit the calculated value to the range of its type */
LimitExprValue (Expr, 1);
}
/* Adjust the type of the expression */
Expr->Type = IntPromotion (Expr->Type);
/* Limit the calculated value to the range of its type */
LimitExprValue (Expr, 1);
} else {
unsigned Flags;
/* If not constant, we can only handle integer types */
if (!IsClassInt (Expr->Type)) {
Error ("Non-constant argument must have integer type");
ED_MakeConstAbsInt (Expr, 1);
}
/* Value is not constant */
LoadExpr (CF_NONE, Expr);

View File

@@ -704,20 +704,21 @@ static void NumericConst (void)
/* Check for a fractional part and read it */
if (SB_Peek (&Src) == '.') {
Double Scale;
Double Scale, ScaleDigit;
/* Skip the dot */
SB_Skip (&Src);
/* Read fractional digits */
Scale = FP_D_Make (1.0);
ScaleDigit = FP_D_Div (FP_D_Make (1.0), FP_D_FromInt (Base));
Scale = ScaleDigit;
while (IsXDigit (SB_Peek (&Src)) && (DigitVal = HexVal (SB_Peek (&Src))) < Base) {
/* Get the value of this digit */
Double FracVal = FP_D_Div (FP_D_FromInt (DigitVal * Base), Scale);
Double FracVal = FP_D_Mul (FP_D_FromInt (DigitVal), Scale);
/* Add it to the float value */
FVal = FP_D_Add (FVal, FracVal);
/* Scale base */
Scale = FP_D_Mul (Scale, FP_D_FromInt (DigitVal));
/* Adjust Scale for next digit */
Scale = FP_D_Mul (Scale, ScaleDigit);
/* Skip the digit */
SB_Skip (&Src);
}
@@ -729,12 +730,15 @@ static void NumericConst (void)
unsigned Digits;
unsigned Exp;
int Sign;
/* Skip the exponent notifier */
SB_Skip (&Src);
/* Read an optional sign */
Sign = 0;
if (SB_Peek (&Src) == '-') {
Sign = 1;
SB_Skip (&Src);
} else if (SB_Peek (&Src) == '+') {
SB_Skip (&Src);
@@ -764,9 +768,11 @@ static void NumericConst (void)
Warning ("Floating constant exponent is too large");
}
/* Scale the exponent and adjust the value accordingly */
/* Scale the exponent and adjust the value accordingly.
** Decimal exponents are base 10, hexadecimal exponents are base 2 (C99).
*/
if (Exp) {
FVal = FP_D_Mul (FVal, FP_D_Make (pow (10, Exp)));
FVal = FP_D_Mul (FVal, FP_D_Make (pow ((Base == 16) ? 2.0 : 10.0, (Sign ? -1.0 : 1.0) * Exp)));
}
}

View File

@@ -123,6 +123,17 @@ static void DoConversion (ExprDesc* Expr, const Type* NewType, int Explicit)
** to handle sign extension correctly.
*/
/* If this is a floating point constant, convert to integer,
** and warn if precision is discarded.
*/
if (IsClassFloat (OldType) && IsClassInt (NewType)) {
long IVal = (long)Expr->V.FVal.V;
if ((Expr->V.FVal.V != FP_D_FromInt(IVal).V) && !Explicit) {
Warning ("Floating point constant (%f) converted to integer loses precision (%ld)",Expr->V.FVal.V,IVal);
}
Expr->IVal = IVal;
}
/* Check if the new datatype will have a smaller range. If it
** has a larger range, things are OK, since the value is
** internally already represented by a long.