aboutsummaryrefslogtreecommitdiffstats
path: root/src/main/java/org/anarres/cpp/NumericValue.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/org/anarres/cpp/NumericValue.java')
-rw-r--r--src/main/java/org/anarres/cpp/NumericValue.java179
1 files changed, 179 insertions, 0 deletions
diff --git a/src/main/java/org/anarres/cpp/NumericValue.java b/src/main/java/org/anarres/cpp/NumericValue.java
new file mode 100644
index 0000000..8d961c4
--- /dev/null
+++ b/src/main/java/org/anarres/cpp/NumericValue.java
@@ -0,0 +1,179 @@
+/*
+ * Anarres C Preprocessor
+ * Copyright (c) 2007-2008, Shevek
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+package org.anarres.cpp;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+public class NumericValue extends Number {
+
+ public static final int F_UNSIGNED = 1;
+ public static final int F_INT = 2;
+ public static final int F_LONG = 4;
+ public static final int F_LONGLONG = 8;
+ public static final int F_FLOAT = 16;
+ public static final int F_DOUBLE = 32;
+
+ public static final int FF_SIZE = F_INT | F_LONG | F_LONGLONG | F_FLOAT | F_DOUBLE;
+
+ private final int base;
+ private final String integer;
+ private String fraction;
+ private String exponent;
+ private int flags;
+
+ public NumericValue(int base, String integer) {
+ this.base = base;
+ this.integer = integer;
+ }
+
+ public int getBase() {
+ return base;
+ }
+
+ public String getIntegerPart() {
+ return integer;
+ }
+
+ public String getFractionalPart() {
+ return fraction;
+ }
+
+ /* pp */ void setFractionalPart(String fraction) {
+ this.fraction = fraction;
+ }
+
+ public String getExponent() {
+ return exponent;
+ }
+
+ /* pp */ void setExponent(String exponent) {
+ this.exponent = exponent;
+ }
+
+ public int getFlags() {
+ return flags;
+ }
+
+ /* pp */ void setFlags(int flags) {
+ this.flags = flags;
+ }
+
+ /**
+ * So, it turns out that parsing arbitrary bases into arbitrary
+ * precision numbers is nontrivial, and this routine gets it wrong
+ * in many important cases.
+ */
+ public BigDecimal toBigDecimal() {
+ int scale = 0;
+ String text = getIntegerPart();
+ String t_fraction = getFractionalPart();
+ if (t_fraction != null) {
+ text += getFractionalPart();
+ // XXX Wrong for anything but base 10.
+ scale += getFractionalPart().length();
+ }
+ if (getExponent() != null)
+ scale -= Integer.parseInt(getExponent());
+ BigInteger unscaled = new BigInteger(text, getBase());
+ return new BigDecimal(unscaled, scale);
+ }
+
+ public Number toJavaLangNumber() {
+ int flags = getFlags();
+ if ((flags & F_DOUBLE) != 0)
+ return doubleValue();
+ else if ((flags & F_FLOAT) != 0)
+ return floatValue();
+ else if ((flags & (F_LONG | F_LONGLONG)) != 0)
+ return longValue();
+ else if ((flags & F_INT) != 0)
+ return intValue();
+ else if (getFractionalPart() != null)
+ return doubleValue(); // .1 is a double in Java.
+ else if (getExponent() != null)
+ return doubleValue();
+ else
+ return intValue();
+ }
+
+ @Override
+ public int intValue() {
+ return Integer.parseInt(toString());
+ }
+
+ @Override
+ public long longValue() {
+ return Long.parseLong(toString());
+ }
+
+ @Override
+ public float floatValue() {
+ return Float.parseFloat(toString());
+ }
+
+ @Override
+ public double doubleValue() {
+ return Double.parseDouble(toString());
+ }
+
+ private boolean appendFlags(StringBuilder buf, String suffix, int flag) {
+ if ((getFlags() & flag) != flag)
+ return false;
+ buf.append(suffix);
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder buf = new StringBuilder();
+ switch (base) {
+ case 8:
+ buf.append('0');
+ break;
+ case 10:
+ break;
+ case 16:
+ buf.append("0x");
+ break;
+ case 2:
+ buf.append('b');
+ break;
+ default:
+ buf.append("[base-").append(base).append("]");
+ break;
+ }
+ buf.append(getIntegerPart());
+ if (getFractionalPart() != null)
+ buf.append('.').append(getFractionalPart());
+ if (getExponent() != null) {
+ buf.append(base > 10 ? 'p' : 'e');
+ buf.append(getExponent());
+ }
+ /*
+ if (appendFlags(buf, "ui", F_UNSIGNED | F_INT));
+ else if (appendFlags(buf, "ul", F_UNSIGNED | F_LONG));
+ else if (appendFlags(buf, "ull", F_UNSIGNED | F_LONGLONG));
+ else if (appendFlags(buf, "i", F_INT));
+ else if (appendFlags(buf, "l", F_LONG));
+ else if (appendFlags(buf, "ll", F_LONGLONG));
+ else if (appendFlags(buf, "f", F_FLOAT));
+ else if (appendFlags(buf, "d", F_DOUBLE));
+ */
+ return buf.toString();
+ }
+}