001: package org.ofbiz.rules.parse.tokens;
002:
003: import java.io.*;
004:
005: /**
006: * <p><b>Title:</b> Number State
007: * <p><b>Description:</b> None
008: * <p>Copyright (c) 1999 Steven J. Metsker.
009: * <p>Copyright (c) 2001 The Open For Business Project - www.ofbiz.org
010: *
011: * <p>Permission is hereby granted, free of charge, to any person obtaining a
012: * copy of this software and associated documentation files (the "Software"),
013: * to deal in the Software without restriction, including without limitation
014: * the rights to use, copy, modify, merge, publish, distribute, sublicense,
015: * and/or sell copies of the Software, and to permit persons to whom the
016: * Software is furnished to do so, subject to the following conditions:
017: *
018: * <p>The above copyright notice and this permission notice shall be included
019: * in all copies or substantial portions of the Software.
020: *
021: * <p>THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
022: * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
023: * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
024: * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
025: * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
026: * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
027: * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
028: *
029: * <br>
030: * A NumberState object returns a number from a reader. This
031: * state's idea of a number allows an optional, initial
032: * minus sign, followed by one or more digits. A decimal
033: * point and another string of digits may follow these
034: * digits.
035: *
036: * @author Steven J. Metsker
037: * @version 1.0
038: */
039: public class NumberState extends TokenizerState {
040: protected int c;
041: protected double value;
042: protected boolean absorbedLeadingMinus;
043: protected boolean absorbedDot;
044: protected boolean gotAdigit;
045:
046: /**
047: * Convert a stream of digits into a number, making this
048: * number a fraction if the boolean parameter is true.
049: */
050: protected double absorbDigits(PushbackReader r, boolean fraction)
051: throws IOException {
052:
053: int divideBy = 1;
054: double v = 0;
055:
056: while ('0' <= c && c <= '9') {
057: gotAdigit = true;
058: v = v * 10 + (c - '0');
059: c = r.read();
060: if (fraction) {
061: divideBy *= 10;
062: }
063: }
064: if (fraction) {
065: v = v / divideBy;
066: }
067: return v;
068: }
069:
070: /**
071: * Return a number token from a reader.
072: *
073: * @return a number token from a reader
074: */
075: public Token nextToken(PushbackReader r, int cin, Tokenizer t)
076: throws IOException {
077:
078: reset(cin);
079: parseLeft(r);
080: parseRight(r);
081: r.unread(c);
082: return value(r, t);
083: }
084:
085: /**
086: * Parse up to a decimal point.
087: */
088: protected void parseLeft(PushbackReader r) throws IOException {
089:
090: if (c == '-') {
091: c = r.read();
092: absorbedLeadingMinus = true;
093: }
094: value = absorbDigits(r, false);
095: }
096:
097: /**
098: * Parse from a decimal point to the end of the number.
099: */
100: protected void parseRight(PushbackReader r) throws IOException {
101:
102: if (c == '.') {
103: c = r.read();
104: absorbedDot = true;
105: value += absorbDigits(r, true);
106: }
107: }
108:
109: /**
110: * Prepare to assemble a new number.
111: */
112: protected void reset(int cin) {
113: c = cin;
114: value = 0;
115: absorbedLeadingMinus = false;
116: absorbedDot = false;
117: gotAdigit = false;
118: }
119:
120: /**
121: * Put together the pieces of a number.
122: */
123: protected Token value(PushbackReader r, Tokenizer t)
124: throws IOException {
125:
126: if (!gotAdigit) {
127: if (absorbedLeadingMinus && absorbedDot) {
128: r.unread('.');
129: return t.symbolState().nextToken(r, '-', t);
130: }
131: if (absorbedLeadingMinus) {
132: return t.symbolState().nextToken(r, '-', t);
133: }
134: if (absorbedDot) {
135: return t.symbolState().nextToken(r, '.', t);
136: }
137: }
138: if (absorbedLeadingMinus) {
139: value = -value;
140: }
141: return new Token(Token.TT_NUMBER, "", value);
142: }
143: }
|