1
0
mirror of https://github.com/cc65/cc65.git synced 2025-01-15 07:31:32 +00:00

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> <itemize>
<item> The datatypes "float" and "double" are not available. <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> <p>
<item> C Functions may pass and return structs (or unions) by value, but only <item> C Functions may pass and return structs (or unions) by value, but only
of 1, 2 or 4 byte sizes. 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. ** floating point types are not (yet) supported.
** The integral promotions are performed on both operands. ** 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); lhst = IntPromotion (lhst);
rhst = IntPromotion (rhst); rhst = IntPromotion (rhst);

View File

@ -1901,14 +1901,22 @@ static void UnaryOp (ExprDesc* Expr)
/* Get the expression */ /* Get the expression */
hie10 (Expr); hie10 (Expr);
/* We can only handle integer types */ /* Check for a constant numeric expression */
if (ED_IsConstAbs (Expr)) {
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)) { if (!IsClassInt (Expr->Type)) {
Error ("Argument must have integer type"); Error ("Constant argument must have integer or float type");
ED_MakeConstAbsInt (Expr, 1); ED_MakeConstAbsInt (Expr, 1);
} }
/* Check for a constant numeric expression */
if (ED_IsConstAbs (Expr)) {
/* Value is numeric */ /* Value is numeric */
switch (Tok) { switch (Tok) {
case TOK_MINUS: Expr->IVal = -Expr->IVal; break; case TOK_MINUS: Expr->IVal = -Expr->IVal; break;
@ -1922,10 +1930,17 @@ static void UnaryOp (ExprDesc* Expr)
/* Limit the calculated value to the range of its type */ /* Limit the calculated value to the range of its type */
LimitExprValue (Expr, 1); LimitExprValue (Expr, 1);
}
} else { } else {
unsigned Flags; 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 */ /* Value is not constant */
LoadExpr (CF_NONE, Expr); LoadExpr (CF_NONE, Expr);

View File

@ -704,20 +704,21 @@ static void NumericConst (void)
/* Check for a fractional part and read it */ /* Check for a fractional part and read it */
if (SB_Peek (&Src) == '.') { if (SB_Peek (&Src) == '.') {
Double Scale; Double Scale, ScaleDigit;
/* Skip the dot */ /* Skip the dot */
SB_Skip (&Src); SB_Skip (&Src);
/* Read fractional digits */ /* 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) { while (IsXDigit (SB_Peek (&Src)) && (DigitVal = HexVal (SB_Peek (&Src))) < Base) {
/* Get the value of this digit */ /* 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 */ /* Add it to the float value */
FVal = FP_D_Add (FVal, FracVal); FVal = FP_D_Add (FVal, FracVal);
/* Scale base */ /* Adjust Scale for next digit */
Scale = FP_D_Mul (Scale, FP_D_FromInt (DigitVal)); Scale = FP_D_Mul (Scale, ScaleDigit);
/* Skip the digit */ /* Skip the digit */
SB_Skip (&Src); SB_Skip (&Src);
} }
@ -729,12 +730,15 @@ static void NumericConst (void)
unsigned Digits; unsigned Digits;
unsigned Exp; unsigned Exp;
int Sign;
/* Skip the exponent notifier */ /* Skip the exponent notifier */
SB_Skip (&Src); SB_Skip (&Src);
/* Read an optional sign */ /* Read an optional sign */
Sign = 0;
if (SB_Peek (&Src) == '-') { if (SB_Peek (&Src) == '-') {
Sign = 1;
SB_Skip (&Src); SB_Skip (&Src);
} else if (SB_Peek (&Src) == '+') { } else if (SB_Peek (&Src) == '+') {
SB_Skip (&Src); SB_Skip (&Src);
@ -764,9 +768,11 @@ static void NumericConst (void)
Warning ("Floating constant exponent is too large"); 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) { 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. ** 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 /* Check if the new datatype will have a smaller range. If it
** has a larger range, things are OK, since the value is ** has a larger range, things are OK, since the value is
** internally already represented by a long. ** 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;
}