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
commit 05cd805cbc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 78 additions and 25 deletions

View File

@ -807,6 +807,9 @@ and the one defined by the ISO standard:
<itemize>
<item> The datatypes "float" and "double" are not available.
Floating point constants may be used, though they will have to be
converted and stored into integer values.
Floating point arithmetic expressions are not supported.
<p>
<item> C Functions may pass and return structs (or unions) by value, but only
of 1, 2 or 4 byte sizes.

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.

View File

@ -0,0 +1,14 @@
/* Demonstrates that floating point constants are allowed in a limited way.
Value will be converted to an int, with a warning if precision is lost. */
int a = 3.0;
int b = 23.1;
int c = -5.0;
int main(void)
{
if (a != 3) return 1;
if (b != 23) return 2;
if (c != -5) return 3;
return 0;
}