001/* 002 * Anarres C Preprocessor 003 * Copyright (c) 2007-2015, Shevek 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 014 * or implied. See the License for the specific language governing 015 * permissions and limitations under the License. 016 */ 017package org.anarres.cpp; 018 019import java.math.BigDecimal; 020import java.math.BigInteger; 021import javax.annotation.CheckForNull; 022import javax.annotation.CheckForSigned; 023import javax.annotation.Nonnegative; 024import javax.annotation.Nonnull; 025 026public class NumericValue extends Number { 027 028 public static final int F_UNSIGNED = 1; 029 public static final int F_INT = 2; 030 public static final int F_LONG = 4; 031 public static final int F_LONGLONG = 8; 032 public static final int F_FLOAT = 16; 033 public static final int F_DOUBLE = 32; 034 035 public static final int FF_SIZE = F_INT | F_LONG | F_LONGLONG | F_FLOAT | F_DOUBLE; 036 037 private final int base; 038 private final String integer; 039 private String fraction; 040 private int expbase = 0; 041 private String exponent; 042 private int flags; 043 044 public NumericValue(@Nonnegative int base, @Nonnull String integer) { 045 this.base = base; 046 this.integer = integer; 047 } 048 049 @Nonnegative 050 public int getBase() { 051 return base; 052 } 053 054 @Nonnull 055 public String getIntegerPart() { 056 return integer; 057 } 058 059 @CheckForNull 060 public String getFractionalPart() { 061 return fraction; 062 } 063 064 /* pp */ void setFractionalPart(@Nonnull String fraction) { 065 this.fraction = fraction; 066 } 067 068 @CheckForSigned 069 public int getExponentBase() { 070 return expbase; 071 } 072 073 @CheckForNull 074 public String getExponent() { 075 return exponent; 076 } 077 078 /* pp */ void setExponent(@Nonnegative int expbase, @Nonnull String exponent) { 079 this.expbase = expbase; 080 this.exponent = exponent; 081 } 082 083 public int getFlags() { 084 return flags; 085 } 086 087 /* pp */ void setFlags(int flags) { 088 this.flags = flags; 089 } 090 091 /** 092 * So, it turns out that parsing arbitrary bases into arbitrary 093 * precision numbers is nontrivial, and this routine gets it wrong 094 * in many important cases. 095 */ 096 @Nonnull 097 public BigDecimal toBigDecimal() { 098 int scale = 0; 099 String text = getIntegerPart(); 100 String t_fraction = getFractionalPart(); 101 if (t_fraction != null) { 102 text += getFractionalPart(); 103 // XXX Wrong for anything but base 10. 104 scale += t_fraction.length(); 105 } 106 String t_exponent = getExponent(); 107 if (t_exponent != null) 108 scale -= Integer.parseInt(t_exponent); 109 BigInteger unscaled = new BigInteger(text, getBase()); 110 return new BigDecimal(unscaled, scale); 111 } 112 113 // We could construct a heuristic for when an 'int' is large enough. 114 // private static final int S_MAXLEN_LONG = String.valueOf(Long.MAX_VALUE).length(); 115 // private static final int S_MAXLEN_INT = String.valueOf(Integer.MAX_VALUE).length(); 116 117 @Nonnull 118 public Number toJavaLangNumber() { 119 int flags = getFlags(); 120 if ((flags & F_DOUBLE) != 0) 121 return doubleValue(); 122 else if ((flags & F_FLOAT) != 0) 123 return floatValue(); 124 else if ((flags & (F_LONG | F_LONGLONG)) != 0) 125 return longValue(); 126 else if ((flags & F_INT) != 0) 127 return intValue(); 128 else if (getFractionalPart() != null) 129 return doubleValue(); // .1 is a double in Java. 130 else if (getExponent() != null) 131 return doubleValue(); 132 else { 133 // This is an attempt to avoid overflowing on over-long integers. 134 // However, now we just overflow on over-long longs. 135 // We should really use BigInteger. 136 long value = longValue(); 137 if (value <= Integer.MAX_VALUE && value >= Integer.MIN_VALUE) 138 return (int) value; 139 return value; 140 } 141 } 142 143 private int exponentValue() { 144 return Integer.parseInt(exponent, 10); 145 } 146 147 @Override 148 public int intValue() { 149 // String.isEmpty() is since 1.6 150 int v = integer.length() == 0 ? 0 : Integer.parseInt(integer, base); 151 if (expbase == 2) 152 v = v << exponentValue(); 153 else if (expbase != 0) 154 v = (int) (v * Math.pow(expbase, exponentValue())); 155 return v; 156 } 157 158 @Override 159 public long longValue() { 160 // String.isEmpty() is since 1.6 161 long v = integer.length() == 0 ? 0 : Long.parseLong(integer, base); 162 if (expbase == 2) 163 v = v << exponentValue(); 164 else if (expbase != 0) 165 v = (long) (v * Math.pow(expbase, exponentValue())); 166 return v; 167 } 168 169 @Override 170 public float floatValue() { 171 if (getBase() != 10) 172 return longValue(); 173 return Float.parseFloat(toString()); 174 } 175 176 @Override 177 public double doubleValue() { 178 if (getBase() != 10) 179 return longValue(); 180 return Double.parseDouble(toString()); 181 } 182 183 private boolean appendFlags(StringBuilder buf, String suffix, int flag) { 184 if ((getFlags() & flag) != flag) 185 return false; 186 buf.append(suffix); 187 return true; 188 } 189 190 @Override 191 public String toString() { 192 StringBuilder buf = new StringBuilder(); 193 switch (base) { 194 case 8: 195 buf.append('0'); 196 break; 197 case 10: 198 break; 199 case 16: 200 buf.append("0x"); 201 break; 202 case 2: 203 buf.append('b'); 204 break; 205 default: 206 buf.append("[base-").append(base).append("]"); 207 break; 208 } 209 buf.append(getIntegerPart()); 210 if (getFractionalPart() != null) 211 buf.append('.').append(getFractionalPart()); 212 if (getExponent() != null) { 213 buf.append(base > 10 ? 'p' : 'e'); 214 buf.append(getExponent()); 215 } 216 /* 217 if (appendFlags(buf, "ui", F_UNSIGNED | F_INT)); 218 else if (appendFlags(buf, "ul", F_UNSIGNED | F_LONG)); 219 else if (appendFlags(buf, "ull", F_UNSIGNED | F_LONGLONG)); 220 else if (appendFlags(buf, "i", F_INT)); 221 else if (appendFlags(buf, "l", F_LONG)); 222 else if (appendFlags(buf, "ll", F_LONGLONG)); 223 else if (appendFlags(buf, "f", F_FLOAT)); 224 else if (appendFlags(buf, "d", F_DOUBLE)); 225 */ 226 return buf.toString(); 227 } 228}