aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShevek <[email protected]>2014-01-18 22:01:28 -0800
committerShevek <[email protected]>2014-01-18 22:01:28 -0800
commit1df1de70b8fc2a85848d2f21ce16851ab7f8f097 (patch)
tree49dd4f8ebbd6bce8f7c7eda9a5453cea16e04544
parentffbe890c500a0fa57d26f40d1de3a464fe7938a2 (diff)
Better numeric base handling. Fix typos in error messages.
-rw-r--r--src/main/java/org/anarres/cpp/LexerSource.java77
-rw-r--r--src/main/java/org/anarres/cpp/NumericValue.java27
-rw-r--r--src/test/java/org/anarres/cpp/NumericValueTest.java17
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
+
}
}