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: * <code>AbstractParser</code> is the base class for parsers found
038: * in this package. <br />
039: * All parsers work on a <code>String</code> and the <code>AbstractParser</code>
040: * keeps a reference to that string along with the current position
041: * (@see #currentPos) and current character (@see current). <br />
042: * The key methods for this class are <code>read</code> which reads the next
043: * character in the parsed string, <code>setString</code> which sets the string
044: * to be parsed, and the utility methods <code>skipCommaSpaces</code>,
045: * <code>skipSpaces</code> and <code>skipSpacesCommaSpaces</code> which can
046: * be used by descendants to skip common separators.
047: * <br />
048: * For an implementation example, see {@link TransformListParser}.
049: *
050: * @version $Id: AbstractParser.java,v 1.2 2006/04/21 06:40:21 st125089 Exp $
051: */
052: public abstract class AbstractParser {
053: /**
054: * The current position in the string
055: */
056: protected int currentPos;
057:
058: /**
059: * The String being parsed
060: */
061: protected String s;
062:
063: /**
064: * The current character being parsed
065: * This is accessible by sub-classes
066: */
067: protected int current;
068:
069: /**
070: * @return the next character. Returns -1 when the
071: * end of the String has been reached.
072: */
073: protected final int read() {
074: if (currentPos < s.length()) {
075: return s.charAt(currentPos++);
076: }
077: return -1;
078: }
079:
080: /**
081: * Sets this parser's String. This also resets the
082: * current position to 0
083: *
084: * @param str the string this parser should parse. Should
085: * not be null.
086: */
087: protected final void setString(final String str) {
088: if (str == null) {
089: throw new IllegalArgumentException();
090: }
091:
092: this .s = str;
093: this .currentPos = 0;
094: this .current = -1;
095: }
096:
097: /**
098: * Skips the whitespaces in the current reader.
099: */
100: protected final void skipSpaces() {
101: for (;;) {
102: switch (current) {
103: default:
104: return;
105: case 0x20:
106: case 0x09:
107: case 0x0D:
108: case 0x0A:
109: }
110: current = read();
111: }
112: }
113:
114: /**
115: * Skips the whitespaces and an optional comma.
116: */
117: protected final void skipCommaSpaces() {
118: skipSepSpaces(',');
119: }
120:
121: /**
122: * Skips the whitespaces and an optional comma.
123: *
124: * @param sep seperator to skip in addition to spaces.
125: */
126: protected final void skipSepSpaces(final char sep) {
127: wsp1: for (;;) {
128: switch (current) {
129: default:
130: break wsp1;
131: case 0x20:
132: case 0x9:
133: case 0xD:
134: case 0xA:
135: }
136: current = read();
137: }
138: if (current == sep) {
139: wsp2: for (;;) {
140: switch (current = read()) {
141: default:
142: break wsp2;
143: case 0x20:
144: case 0x9:
145: case 0xD:
146: case 0xA:
147: }
148: }
149: }
150: }
151:
152: /**
153: * Skips wsp*,wsp* and throws an IllegalArgumentException
154: * if no comma is found.
155: */
156: protected final void skipSpacesCommaSpaces() {
157: skipSpaces();
158:
159: if (current != ',') {
160: throw new IllegalArgumentException();
161: }
162:
163: current = read();
164: skipSpaces();
165: }
166:
167: /**
168: * Tests if the current substring (i.e. the substring beginning at the
169: * current position) starts with the specified prefix. If the current
170: * substring starts with the specified prefix, the current character will
171: * be updated to point to the character immediately following the last
172: * character in the prefix; otherwise, the <code>currentPos</code> will
173: * not be affected. For example, if the string being parsed is
174: * "timingAttr", and the current character is 'A':
175: * <pre>
176: * currentStartsWith("Att") returns true, current == 'r'
177: * currentStartsWith("Attr") returns true, current == -1
178: * currentStartsWith("Attx") returns false, current == 'A'
179: * </pre>
180: *
181: * @param str the prefix to be tested
182: * @return <code>true</code> if the current substring starts with the
183: * specified prefix. The result is <code>false</code> if
184: * <code>currentPos</code> is non-positive, or if the current substring
185: * does not start with the specified prefix.
186: */
187: protected final boolean currentStartsWith(final String str) {
188: if (currentPos <= 0) {
189: return false;
190: }
191: if (s.startsWith(str, currentPos - 1)) {
192: currentPos += str.length() - 1;
193: current = read();
194: return true;
195: }
196: return false;
197: }
198: }
|