FileDocCategorySizeDatePackage
NumberParser.javaAPI DocphoneME MR2 API (J2ME)10430Wed May 02 18:00:36 BST 2007com.sun.perseus.parser

NumberParser.java

/*
 *
 *
 * Portions Copyright  2000-2007 Sun Microsystems, Inc. All Rights
 * Reserved.  Use is subject to license terms.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License version
 * 2 only, as published by the Free Software Foundation.
 * 
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License version 2 for more details (a copy is
 * included at /legal/license.txt).
 * 
 * You should have received a copy of the GNU General Public License
 * version 2 along with this work; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 * 
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
 * Clara, CA 95054 or visit www.sun.com if you need additional
 * information or have any questions.
 */

/*****************************************************************************
 * Copyright (C) The Apache Software Foundation. All rights reserved.        *
 * ------------------------------------------------------------------------- *
 * This software is published under the terms of the Apache Software License *
 * version 1.1, a copy of which has been included with this distribution in  *
 * the LICENSE file.                                                         *
 *****************************************************************************/

package com.sun.perseus.parser;

/**
 * This class represents a parser with support for numbers. Note that
 * the parameter-less form of the <code>parseNumber</code> methods is meant
 * for use by subclasses (e.g., <code>TransformListParser</code>).
 *
 * @version $Id: NumberParser.java,v 1.2 2006/04/21 06:40:35 st125089 Exp $
 */
public class NumberParser extends AbstractParser {
    /**
     * Parses the content of the input String and converts it to a float.
     *
     * @param numberString the value to parse
     * @return the corresponding single precision floating point value.
     */
    public float parseNumber(final String numberString) {
        setString(numberString);
        return parseNumber(true);
    }

    /**
     * Parses a float value from the current position in the string
     *
     * @return floating point value corresponding to the parsed string.
     */
    public float parseNumber() {
        return parseNumber(false);
    }

    /**
     * Parses the next float value in the string.
     *
     * @param eos If eos is set to true, then there should be no more
     * characters at the end of the string.
     * @return floating point value corresponding to the parsed string.
     *         An <code>IllegalArgumentException</code> is thrown if
     *         the next number in the string
     *         does not have a valid number syntax or if eos is true
     *         and there are more characters in the string after the
     *         number.
     */
    public float parseNumber(final boolean eos) {
        int     mant     = 0;
        int     mantDig  = 0;
        boolean mantPos  = true;
        boolean mantRead = false;

        int     exp      = 0;
        int     expDig   = 0;
        int     expAdj   = 0;
        boolean expPos   = true;

        // Only read the next character if the
        // current one is -1
        if (current == -1) {
            current  = read();
        }

        // Parse the initial +/- sign if any
        switch (current) {
        case '-':
            mantPos = false;
        case '+':
            current = read();
        default:
            // nothing
        }

        // Now, parse the mantisse
        m1: switch (current) {
        default:
            throw new IllegalArgumentException("" + (char) current);

        case '.':
            break;

        case '0':
            mantRead = true;
            l: for (;;) {
                current = read();
                switch (current) {
                case '1': case '2': case '3': case '4':
                case '5': case '6': case '7': case '8': case '9':
                    break l;
                case '.': case 'e': case 'E':
                    break m1;
                case -1:
                    break m1;
                default:
                    if (eos) {
                        throw new IllegalArgumentException
                            (">" + (char) current + "<");
                    } else {
                        return 0;
                    }
                case '0': // <!>
                }
            }

        case '1': case '2': case '3': case '4':
        case '5': case '6': case '7': case '8': case '9':
            mantRead = true;
            l: for (;;) {
                if (mantDig < 9) {
                    mantDig++;
                    mant = mant * 10 + (current - '0');
                } else {
                    expAdj++;
                }
                current = read();
                switch (current) {
                default:
                    break l;
                case '0': case '1': case '2': case '3': case '4':
                case '5': case '6': case '7': case '8': case '9':
                }              
            }
        }
      
        // If we hit a point, parse the fractional part
        if (current == '.') {
            current = read();
            m2: switch (current) {
            default:
            case 'e': case 'E':
                if (!mantRead) {
                    throw new IllegalArgumentException();
                }
                break;

            case '0':
                if (mantDig == 0) {
                    l: for (;;) {
                        current = read();
                        expAdj--;
                        switch (current) {
                        case '1': case '2': case '3': case '4':
                        case '5': case '6': case '7': case '8': case '9':
                            break l;
                        default:
                            break m2;
                        case '0':
                        }
                    }
                }
            case '1': case '2': case '3': case '4':
            case '5': case '6': case '7': case '8': case '9':
                l: for (;;) {
                    if (mantDig < 9) {
                        mantDig++;
                        mant = mant * 10 + (current - '0');
                        expAdj--;
                    }
                    current = read();
                    switch (current) {
                    default:
                        break l;
                    case '0': case '1': case '2': case '3': case '4':
                    case '5': case '6': case '7': case '8': case '9':
                    }
                }
            }
        }

        // Parse the exponent
        switch (current) {
        case 'e': case 'E':
            current = read();
            switch (current) {
            default:
                throw new IllegalArgumentException();
            case '-':
                expPos = false;
            case '+':
                current = read();
                switch (current) {
                default:
                    throw new IllegalArgumentException();
                case '0': case '1': case '2': case '3': case '4':
                case '5': case '6': case '7': case '8': case '9':
                }
            case '0': case '1': case '2': case '3': case '4':
            case '5': case '6': case '7': case '8': case '9':
            }
          
            en: switch (current) {
            case '0':
                l: for (;;) {
                    current = read();
                    switch (current) {
                    case '1': case '2': case '3': case '4':
                    case '5': case '6': case '7': case '8': case '9':
                        break l;
                    default:
                        break en;
                    case '0':
                    }
                }

            case '1': case '2': case '3': case '4':
            case '5': case '6': case '7': case '8': case '9':
                l: for (;;) {
                    if (expDig < 3) {
                        expDig++;
                        exp = exp * 10 + (current - '0');
                    }
                    current = read();
                    switch (current) {
                    default:
                        break l;
                    case '0': case '1': case '2': case '3': case '4':
                    case '5': case '6': case '7': case '8': case '9':
                    }
                }
            }
        default:
        }

        if (eos && current != -1) {
            throw new IllegalArgumentException();
        }

        if (!expPos) {
            exp = -exp;
        }
        exp += expAdj;
        if (!mantPos) {
            mant = -mant;
        }

        return buildFloat(mant, exp);
    }

    /**
     * Computes a float from mantissa and exponent.
     *
     * @param mant the mantissa for the floating point value to create
     * @param exp the exponent for the floating point value to create
     * @return a single precision floating point value
     *         corresponding to the input mantissa/exponent
     *         pair.
     */
    public static float buildFloat(int mant, final int exp) {
        if (exp < -125 || mant == 0) {
            return 0f;
        }

        if (exp >  128) {
            if (mant > 0) {
                return Float.POSITIVE_INFINITY;
            } else {
                return Float.NEGATIVE_INFINITY;
            }
        }

        if (exp == 0) {
            return mant;
        }
          
        if (mant >= 1 << 26) {
            mant++;  // round up trailing bits if they will be dropped.
        }

        if (exp > 0) {
            return mant * POW_10[exp];
        } else {
            return mant / POW_10[-exp];
        }
    }

    /**
     * Array of powers of ten.
     */
    private static final float[] POW_10 = new float [128];
    static {
        float cur = 0.1f;
        for (int i = 0; i < POW_10.length; i++) {
            POW_10[i] = cur * 10;
            cur = POW_10[i];
        }
    };
}