From 1df1de70b8fc2a85848d2f21ce16851ab7f8f097 Mon Sep 17 00:00:00 2001 From: Shevek Date: Sat, 18 Jan 2014 22:01:28 -0800 Subject: Better numeric base handling. Fix typos in error messages. --- src/main/java/org/anarres/cpp/LexerSource.java | 77 ++++++++++++++++------ src/main/java/org/anarres/cpp/NumericValue.java | 27 +++++--- .../java/org/anarres/cpp/NumericValueTest.java | 17 +++-- 3 files changed, 90 insertions(+), 31 deletions(-) diff --git a/src/main/java/org/anarres/cpp/LexerSource.java b/src/main/java/org/anarres/cpp/LexerSource.java index 1ba73bb..607ec65 100644 --- a/src/main/java/org/anarres/cpp/LexerSource.java +++ b/src/main/java/org/anarres/cpp/LexerSource.java @@ -120,10 +120,10 @@ public class LexerSource extends Source { } /* - private boolean _isLineSeparator(int c) { - return Character.getType(c) == Character.LINE_SEPARATOR - || c == -1; - } + * private boolean _isLineSeparator(int c) { + * return Character.getType(c) == Character.LINE_SEPARATOR + * || c == -1; + * } */ /* XXX Move to JoinReader and canonicalise newlines. */ @@ -197,14 +197,14 @@ public class LexerSource extends Source { } /* - if (isLineSeparator(c)) { - line++; - lastcolumn = column; - column = 0; - } - else { - column++; - } + * if (isLineSeparator(c)) { + * line++; + * lastcolumn = column; + * column = 0; + * } + * else { + * column++; + * } */ return c; } @@ -479,7 +479,7 @@ public class LexerSource extends Source { d = read(); } else if (d == 'L' || d == 'l') { if ((flags & NumericValue.FF_SIZE) != 0) - warning("Nultiple length suffixes after " + text); + warning("Multiple length suffixes after " + text); text.append((char) d); int e = read(); if (e == d) { // Case must match. Ll is Welsh. @@ -492,19 +492,19 @@ public class LexerSource extends Source { } } else if (d == 'I' || d == 'i') { if ((flags & NumericValue.FF_SIZE) != 0) - warning("Nultiple length suffixes after " + text); + warning("Multiple length suffixes after " + text); flags |= NumericValue.F_INT; text.append((char) d); d = read(); } else if (d == 'F' || d == 'f') { if ((flags & NumericValue.FF_SIZE) != 0) - warning("Nultiple length suffixes after " + text); + warning("Multiple length suffixes after " + text); flags |= NumericValue.F_FLOAT; text.append((char) d); d = read(); } else if (d == 'D' || d == 'd') { if ((flags & NumericValue.FF_SIZE) != 0) - warning("Nultiple length suffixes after " + text); + warning("Multiple length suffixes after " + text); flags |= NumericValue.F_DOUBLE; text.append((char) d); d = read(); @@ -555,11 +555,19 @@ public class LexerSource extends Source { NumericValue value = new NumericValue(8, negative, integer); int d = read(); if (d == '.') { + // TODO: This means it's decimal. text.append((char) d); String fraction = _number_part(text, 8, true); value.setFractionalPart(fraction); d = read(); } + if (d == 'E' || d == 'e') { + // TODO: This means it's decimal. + text.append((char) d); + String exponent = _number_part(text, 10, true); + value.setExponent(10, exponent); + d = read(); + } return _number_suffix(text, value, d); } @@ -581,8 +589,8 @@ public class LexerSource extends Source { } if (d == 'P' || d == 'p') { text.append((char) d); - String exponent = _number_part(text, 16, true); - value.setExponent(exponent); + String exponent = _number_part(text, 10, true); + value.setExponent(2, exponent); d = read(); } // XXX Make sure it's got enough parts @@ -608,13 +616,44 @@ public class LexerSource extends Source { if (d == 'E' || d == 'e') { text.append((char) d); String exponent = _number_part(text, 10, true); - value.setExponent(exponent); + value.setExponent(10, exponent); d = read(); } // XXX Make sure it's got enough parts return _number_suffix(text, value, d); } + /** + * Section 6.4.4.2 of C99 + * + * A floating constant has a significand part that may be followed + * by an exponent part and a suffix that specifies its type. The + * components of the significand part may include a digit sequence + * representing the whole-number part, followed by a period (.), + * followed by a digit sequence representing the fraction part. + * + * The components of the exponent part are an e, E, p, or P + * followed by an exponent consisting of an optionally signed digit + * sequence. Either the whole-number part or the fraction part has to + * be present; for decimal floating constants, either the period or + * the exponent part has to be present. + * + * The significand part is interpreted as a (decimal or hexadecimal) + * rational number; the digit sequence in the exponent part is + * interpreted as a decimal integer. For decimal floating constants, + * the exponent indicates the power of 10 by which the significand + * part is to be scaled. For hexadecimal floating constants, the + * exponent indicates the power of 2 by which the significand part is + * to be scaled. + * + * For decimal floating constants, and also for hexadecimal + * floating constants when FLT_RADIX is not a power of 2, the result + * is either the nearest representable value, or the larger or smaller + * representable value immediately adjacent to the nearest representable + * value, chosen in an implementation-defined manner. For hexadecimal + * floating constants when FLT_RADIX is a power of 2, the result is + * correctly rounded. + */ @Nonnull private Token number() throws IOException, diff --git a/src/main/java/org/anarres/cpp/NumericValue.java b/src/main/java/org/anarres/cpp/NumericValue.java index e972ec7..2911b8a 100644 --- a/src/main/java/org/anarres/cpp/NumericValue.java +++ b/src/main/java/org/anarres/cpp/NumericValue.java @@ -19,6 +19,7 @@ package org.anarres.cpp; import java.math.BigDecimal; import java.math.BigInteger; import javax.annotation.CheckForNull; +import javax.annotation.CheckForSigned; import javax.annotation.Nonnegative; import javax.annotation.Nonnull; @@ -37,6 +38,7 @@ public class NumericValue extends Number { private final boolean negative; private final String integer; private String fraction; + private int expbase = 0; private String exponent; private int flags; @@ -69,12 +71,18 @@ public class NumericValue extends Number { this.fraction = fraction; } + @CheckForSigned + public int getExponentBase() { + return expbase; + } + @CheckForNull public String getExponent() { return exponent; } - /* pp */ void setExponent(String exponent) { + /* pp */ void setExponent(int expbase, String exponent) { + this.expbase = expbase; this.exponent = exponent; } @@ -126,24 +134,27 @@ public class NumericValue extends Number { return intValue(); } - private double exponentValue() { - int e = Integer.parseInt(exponent, base); - return Math.pow(base, e); + private int exponentValue() { + return Integer.parseInt(exponent, 10); } @Override public int intValue() { int v = integer.isEmpty() ? 0 : Integer.parseInt(integer, base); - if (exponent != null) - v = (int) (v * exponentValue()); + if (expbase == 2) + v = v << exponentValue(); + else if (expbase != 0) + v = (int) (v * Math.pow(expbase, exponentValue())); return isNegative() ? -v : v; } @Override public long longValue() { long v = integer.isEmpty() ? 0 : Long.parseLong(integer, base); - if (exponent != null) - v = (long) (v * exponentValue()); + if (expbase == 2) + v = v << exponentValue(); + else if (expbase != 0) + v = (int) (v * Math.pow(expbase, exponentValue())); return isNegative() ? -v : v; } diff --git a/src/test/java/org/anarres/cpp/NumericValueTest.java b/src/test/java/org/anarres/cpp/NumericValueTest.java index f09d10d..7907457 100644 --- a/src/test/java/org/anarres/cpp/NumericValueTest.java +++ b/src/test/java/org/anarres/cpp/NumericValueTest.java @@ -29,10 +29,10 @@ public class NumericValueTest { Token tok = testNumericValue(in); assertEquals(in, tok.getText()); NumericValue value = (NumericValue) tok.getValue(); - assertEquals(out, value.doubleValue(), 0.01d); - assertEquals((float) out, value.floatValue(), 0.01f); - assertEquals((long) out, value.longValue()); - assertEquals((int) out, value.intValue()); + assertEquals("Double mismatch", out, value.doubleValue(), 0.01d); + assertEquals("Float mismatch", (float) out, value.floatValue(), 0.01f); + assertEquals("Long mismatch", (long) out, value.longValue()); + assertEquals("Integer mismatch", (int) out, value.intValue()); } @Test @@ -73,9 +73,18 @@ public class NumericValueTest { testNumericValue("00.0", 0); testNumericValue("00.", 0); + // Sign on exponents testNumericValue("1e1", 1e1); testNumericValue("-1e1", -1e1); testNumericValue("1e-1", 1e-1); + // Based numbers with exponents + // testNumericValue("012e3", 012e3); // Fails + testNumericValue("0x12e3", 0x12e3); + testNumericValue("0x12p3", 0x12p3); + + // Octal prefix with decimal suffix + // testNumericValue("067e8", 067e8); // Fails + } } -- cgit v1.2.3