001: /*
002: *
003: *
004: * Portions Copyright 2000-2007 Sun Microsystems, Inc. All Rights
005: * Reserved. Use is subject to license terms.
006: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
007: *
008: * This program is free software; you can redistribute it and/or
009: * modify it under the terms of the GNU General Public License version
010: * 2 only, as published by the Free Software Foundation.
011: *
012: * This program is distributed in the hope that it will be useful, but
013: * WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * General Public License version 2 for more details (a copy is
016: * included at /legal/license.txt).
017: *
018: * You should have received a copy of the GNU General Public License
019: * version 2 along with this work; if not, write to the Free Software
020: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
021: * 02110-1301 USA
022: *
023: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
024: * Clara, CA 95054 or visit www.sun.com if you need additional
025: * information or have any questions.
026: */
027:
028: /*****************************************************************************
029: * Copyright (C) The Apache Software Foundation. All rights reserved. *
030: * ------------------------------------------------------------------------- *
031: * This software is published under the terms of the Apache Software License *
032: * version 1.1, a copy of which has been included with this distribution in *
033: * the LICENSE file. *
034: *****************************************************************************/package com.sun.perseus.parser;
035:
036: /**
037: * This class represents a parser with support for numbers. Note that
038: * the parameter-less form of the <code>parseNumber</code> methods is meant
039: * for use by subclasses (e.g., <code>TransformListParser</code>).
040: *
041: * @version $Id: NumberParser.java,v 1.2 2006/04/21 06:40:35 st125089 Exp $
042: */
043: public class NumberParser extends AbstractParser {
044: /**
045: * Parses the content of the input String and converts it to a float.
046: *
047: * @param numberString the value to parse
048: * @return the corresponding single precision floating point value.
049: */
050: public float parseNumber(final String numberString) {
051: setString(numberString);
052: return parseNumber(true);
053: }
054:
055: /**
056: * Parses a float value from the current position in the string
057: *
058: * @return floating point value corresponding to the parsed string.
059: */
060: public float parseNumber() {
061: return parseNumber(false);
062: }
063:
064: /**
065: * Parses the next float value in the string.
066: *
067: * @param eos If eos is set to true, then there should be no more
068: * characters at the end of the string.
069: * @return floating point value corresponding to the parsed string.
070: * An <code>IllegalArgumentException</code> is thrown if
071: * the next number in the string
072: * does not have a valid number syntax or if eos is true
073: * and there are more characters in the string after the
074: * number.
075: */
076: public float parseNumber(final boolean eos) {
077: int mant = 0;
078: int mantDig = 0;
079: boolean mantPos = true;
080: boolean mantRead = false;
081:
082: int exp = 0;
083: int expDig = 0;
084: int expAdj = 0;
085: boolean expPos = true;
086:
087: // Only read the next character if the
088: // current one is -1
089: if (current == -1) {
090: current = read();
091: }
092:
093: // Parse the initial +/- sign if any
094: switch (current) {
095: case '-':
096: mantPos = false;
097: case '+':
098: current = read();
099: default:
100: // nothing
101: }
102:
103: // Now, parse the mantisse
104: m1: switch (current) {
105: default:
106: throw new IllegalArgumentException("" + (char) current);
107:
108: case '.':
109: break;
110:
111: case '0':
112: mantRead = true;
113: l: for (;;) {
114: current = read();
115: switch (current) {
116: case '1':
117: case '2':
118: case '3':
119: case '4':
120: case '5':
121: case '6':
122: case '7':
123: case '8':
124: case '9':
125: break l;
126: case '.':
127: case 'e':
128: case 'E':
129: break m1;
130: case -1:
131: break m1;
132: default:
133: if (eos) {
134: throw new IllegalArgumentException(">"
135: + (char) current + "<");
136: } else {
137: return 0;
138: }
139: case '0': // <!>
140: }
141: }
142:
143: case '1':
144: case '2':
145: case '3':
146: case '4':
147: case '5':
148: case '6':
149: case '7':
150: case '8':
151: case '9':
152: mantRead = true;
153: l: for (;;) {
154: if (mantDig < 9) {
155: mantDig++;
156: mant = mant * 10 + (current - '0');
157: } else {
158: expAdj++;
159: }
160: current = read();
161: switch (current) {
162: default:
163: break l;
164: case '0':
165: case '1':
166: case '2':
167: case '3':
168: case '4':
169: case '5':
170: case '6':
171: case '7':
172: case '8':
173: case '9':
174: }
175: }
176: }
177:
178: // If we hit a point, parse the fractional part
179: if (current == '.') {
180: current = read();
181: m2: switch (current) {
182: default:
183: case 'e':
184: case 'E':
185: if (!mantRead) {
186: throw new IllegalArgumentException();
187: }
188: break;
189:
190: case '0':
191: if (mantDig == 0) {
192: l: for (;;) {
193: current = read();
194: expAdj--;
195: switch (current) {
196: case '1':
197: case '2':
198: case '3':
199: case '4':
200: case '5':
201: case '6':
202: case '7':
203: case '8':
204: case '9':
205: break l;
206: default:
207: break m2;
208: case '0':
209: }
210: }
211: }
212: case '1':
213: case '2':
214: case '3':
215: case '4':
216: case '5':
217: case '6':
218: case '7':
219: case '8':
220: case '9':
221: l: for (;;) {
222: if (mantDig < 9) {
223: mantDig++;
224: mant = mant * 10 + (current - '0');
225: expAdj--;
226: }
227: current = read();
228: switch (current) {
229: default:
230: break l;
231: case '0':
232: case '1':
233: case '2':
234: case '3':
235: case '4':
236: case '5':
237: case '6':
238: case '7':
239: case '8':
240: case '9':
241: }
242: }
243: }
244: }
245:
246: // Parse the exponent
247: switch (current) {
248: case 'e':
249: case 'E':
250: current = read();
251: switch (current) {
252: default:
253: throw new IllegalArgumentException();
254: case '-':
255: expPos = false;
256: case '+':
257: current = read();
258: switch (current) {
259: default:
260: throw new IllegalArgumentException();
261: case '0':
262: case '1':
263: case '2':
264: case '3':
265: case '4':
266: case '5':
267: case '6':
268: case '7':
269: case '8':
270: case '9':
271: }
272: case '0':
273: case '1':
274: case '2':
275: case '3':
276: case '4':
277: case '5':
278: case '6':
279: case '7':
280: case '8':
281: case '9':
282: }
283:
284: en: switch (current) {
285: case '0':
286: l: for (;;) {
287: current = read();
288: switch (current) {
289: case '1':
290: case '2':
291: case '3':
292: case '4':
293: case '5':
294: case '6':
295: case '7':
296: case '8':
297: case '9':
298: break l;
299: default:
300: break en;
301: case '0':
302: }
303: }
304:
305: case '1':
306: case '2':
307: case '3':
308: case '4':
309: case '5':
310: case '6':
311: case '7':
312: case '8':
313: case '9':
314: l: for (;;) {
315: if (expDig < 3) {
316: expDig++;
317: exp = exp * 10 + (current - '0');
318: }
319: current = read();
320: switch (current) {
321: default:
322: break l;
323: case '0':
324: case '1':
325: case '2':
326: case '3':
327: case '4':
328: case '5':
329: case '6':
330: case '7':
331: case '8':
332: case '9':
333: }
334: }
335: }
336: default:
337: }
338:
339: if (eos && current != -1) {
340: throw new IllegalArgumentException();
341: }
342:
343: if (!expPos) {
344: exp = -exp;
345: }
346: exp += expAdj;
347: if (!mantPos) {
348: mant = -mant;
349: }
350:
351: return buildFloat(mant, exp);
352: }
353:
354: /**
355: * Computes a float from mantissa and exponent.
356: *
357: * @param mant the mantissa for the floating point value to create
358: * @param exp the exponent for the floating point value to create
359: * @return a single precision floating point value
360: * corresponding to the input mantissa/exponent
361: * pair.
362: */
363: public static float buildFloat(int mant, final int exp) {
364: if (exp < -125 || mant == 0) {
365: return 0f;
366: }
367:
368: if (exp > 128) {
369: if (mant > 0) {
370: return Float.POSITIVE_INFINITY;
371: } else {
372: return Float.NEGATIVE_INFINITY;
373: }
374: }
375:
376: if (exp == 0) {
377: return mant;
378: }
379:
380: if (mant >= 1 << 26) {
381: mant++; // round up trailing bits if they will be dropped.
382: }
383:
384: if (exp > 0) {
385: return mant * POW_10[exp];
386: } else {
387: return mant / POW_10[-exp];
388: }
389: }
390:
391: /**
392: * Array of powers of ten.
393: */
394: private static final float[] POW_10 = new float[128];
395: static {
396: float cur = 0.1f;
397: for (int i = 0; i < POW_10.length; i++) {
398: POW_10[i] = cur * 10;
399: cur = POW_10[i];
400: }
401: };
402: }
|