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:
commit
05cd805cbc
@ -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.
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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.
|
||||||
|
14
test/val/float-const-convert.c
Normal file
14
test/val/float-const-convert.c
Normal 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;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user