001: /*
002: * Copyright 2002 (C) TJDO.
003: * All rights reserved.
004: *
005: * This software is distributed under the terms of the TJDO License version 1.0.
006: * See the terms of the TJDO License in the documentation provided with this software.
007: *
008: * $Id: Parser.java,v 1.3 2003/02/04 23:23:38 jackknifebarber Exp $
009: */
010:
011: package com.triactive.jdo.store;
012:
013: import com.triactive.jdo.util.Imports;
014: import java.math.BigDecimal;
015: import java.math.BigInteger;
016: import java.text.CharacterIterator;
017: import java.text.StringCharacterIterator;
018: import javax.jdo.JDOUserException;
019:
020: class Parser {
021: private final String input;
022: private final Imports imports;
023: private final CharacterIterator ci;
024:
025: public Parser(String input, Imports imports) {
026: this .input = input;
027: this .imports = imports;
028:
029: ci = new StringCharacterIterator(input);
030: }
031:
032: public String getInput() {
033: return input;
034: }
035:
036: public int getIndex() {
037: return ci.getIndex();
038: }
039:
040: public int skipWS() {
041: int startIdx = ci.getIndex();
042: char c = ci.current();
043:
044: while (Character.isWhitespace(c))
045: c = ci.next();
046:
047: return startIdx;
048: }
049:
050: public boolean parseEOS() {
051: skipWS();
052:
053: return ci.current() == CharacterIterator.DONE;
054: }
055:
056: public boolean parseChar(char c) {
057: skipWS();
058:
059: if (ci.current() == c) {
060: ci.next();
061: return true;
062: } else
063: return false;
064: }
065:
066: public boolean parseChar(char c, char unlessFollowedBy) {
067: int savedIdx = skipWS();
068:
069: if (ci.current() == c && ci.next() != unlessFollowedBy)
070: return true;
071: else {
072: ci.setIndex(savedIdx);
073: return false;
074: }
075: }
076:
077: public boolean parseString(String s) {
078: int savedIdx = skipWS();
079:
080: int len = s.length();
081: char c = ci.current();
082:
083: for (int i = 0; i < len; ++i) {
084: if (c != s.charAt(i)) {
085: ci.setIndex(savedIdx);
086: return false;
087: }
088:
089: c = ci.next();
090: }
091:
092: return true;
093: }
094:
095: public boolean parseString(String s, char unlessFollowedBy) {
096: int savedIdx = skipWS();
097:
098: if (parseString(s) && ci.next() != unlessFollowedBy)
099: return true;
100: else {
101: ci.setIndex(savedIdx);
102: return false;
103: }
104: }
105:
106: public String parseIdentifier() {
107: skipWS();
108: char c = ci.current();
109:
110: if (!Character.isJavaIdentifierStart(c))
111: return null;
112:
113: StringBuffer id = new StringBuffer().append(c);
114:
115: while (Character.isJavaIdentifierPart(c = ci.next()))
116: id.append(c);
117:
118: return id.toString();
119: }
120:
121: public String parseName() {
122: int savedIdx = skipWS();
123: String id;
124:
125: if ((id = parseIdentifier()) == null)
126: return null;
127:
128: StringBuffer qn = new StringBuffer(id);
129:
130: while (parseChar('.')) {
131: if ((id = parseIdentifier()) == null) {
132: ci.setIndex(savedIdx);
133: return null;
134: }
135:
136: qn.append('.').append(id);
137: }
138:
139: return qn.toString();
140: }
141:
142: public Class parseCast() {
143: int savedIdx = skipWS();
144: String typeName;
145:
146: if (!parseChar('(') || (typeName = parseName()) == null
147: || !parseChar(')')) {
148: ci.setIndex(savedIdx);
149: return null;
150: }
151:
152: try {
153: return imports.resolveClassDeclaration(typeName);
154: } catch (ClassNotFoundException e) {
155: ci.setIndex(savedIdx);
156: return null;
157: }
158: }
159:
160: private final static boolean isDecDigit(char c) {
161: return c >= '0' && c <= '9';
162: }
163:
164: private final static boolean isOctDigit(char c) {
165: return c >= '0' && c <= '7';
166: }
167:
168: private final static boolean isHexDigit(char c) {
169: return c >= '0' && c <= '9' || c >= 'a' && c <= 'f' || c >= 'A'
170: && c <= 'F';
171: }
172:
173: public BigInteger parseIntegerLiteral() {
174: int savedIdx = skipWS();
175:
176: StringBuffer digits = new StringBuffer();
177: int radix;
178: char c = ci.current();
179:
180: if (c == '0') {
181: c = ci.next();
182:
183: if (c == 'x' || c == 'X') {
184: radix = 16;
185: c = ci.next();
186:
187: while (isHexDigit(c)) {
188: digits.append(c);
189: c = ci.next();
190: }
191: } else if (isOctDigit(c)) {
192: radix = 8;
193:
194: do {
195: digits.append(c);
196: c = ci.next();
197: } while (isOctDigit(c));
198: } else {
199: radix = 10;
200: digits.append('0');
201: }
202: } else {
203: radix = 10;
204:
205: while (isDecDigit(c)) {
206: digits.append(c);
207: c = ci.next();
208: }
209: }
210:
211: if (digits.length() == 0) {
212: ci.setIndex(savedIdx);
213: return null;
214: }
215:
216: if (c == 'l' || c == 'L')
217: ci.next();
218:
219: return new BigInteger(digits.toString(), radix);
220: }
221:
222: public BigDecimal parseFloatingPointLiteral() {
223: int savedIdx = skipWS();
224: StringBuffer val = new StringBuffer();
225: boolean dotSeen = false;
226: boolean expSeen = false;
227: boolean sfxSeen = false;
228:
229: char c = ci.current();
230:
231: while (isDecDigit(c)) {
232: val.append(c);
233: c = ci.next();
234: }
235:
236: if (c == '.') {
237: dotSeen = true;
238: val.append(c);
239: c = ci.next();
240:
241: while (isDecDigit(c)) {
242: val.append(c);
243: c = ci.next();
244: }
245: }
246:
247: if (val.length() < (dotSeen ? 2 : 1)) {
248: ci.setIndex(savedIdx);
249: return null;
250: }
251:
252: if (c == 'e' || c == 'E') {
253: expSeen = true;
254: val.append(c);
255: c = ci.next();
256:
257: if (c != '+' && c != '-' && !isDecDigit(c)) {
258: ci.setIndex(savedIdx);
259: return null;
260: }
261:
262: do {
263: val.append(c);
264: c = ci.next();
265: } while (isDecDigit(c));
266: }
267:
268: if (c == 'f' || c == 'F' || c == 'd' || c == 'D') {
269: sfxSeen = true;
270: ci.next();
271: }
272:
273: if (!dotSeen && !expSeen && !sfxSeen) {
274: ci.setIndex(savedIdx);
275: return null;
276: }
277:
278: return new BigDecimal(val.toString());
279: }
280:
281: public Boolean parseBooleanLiteral() {
282: int savedIdx = skipWS();
283: String id;
284:
285: if ((id = parseIdentifier()) == null)
286: return null;
287:
288: if (id.equals("true"))
289: return Boolean.TRUE;
290: else if (id.equals("false"))
291: return Boolean.FALSE;
292: else {
293: ci.setIndex(savedIdx);
294: return null;
295: }
296: }
297:
298: public Character parseCharacterLiteral() {
299: skipWS();
300:
301: if (ci.current() != '\'')
302: return null;
303:
304: char c = ci.next();
305:
306: if (c == CharacterIterator.DONE)
307: throw new JDOUserException("Invalid character literal: "
308: + input);
309:
310: if (c == '\\')
311: c = parseEscapedCharacter();
312:
313: if (ci.next() != '\'')
314: throw new JDOUserException("Invalid character literal: "
315: + input);
316:
317: ci.next();
318:
319: return new Character(c);
320: }
321:
322: public String parseStringLiteral() {
323: skipWS();
324:
325: if (ci.current() != '"')
326: return null;
327:
328: StringBuffer lit = new StringBuffer();
329: char c;
330:
331: while ((c = ci.next()) != '"') {
332: if (c == CharacterIterator.DONE)
333: throw new JDOUserException("Invalid string literal: "
334: + input);
335:
336: if (c == '\\')
337: c = parseEscapedCharacter();
338:
339: lit.append(c);
340: }
341:
342: ci.next();
343:
344: return lit.toString();
345: }
346:
347: private char parseEscapedCharacter() {
348: char c;
349:
350: if (isOctDigit(c = ci.next())) {
351: int i = (int) (c - '0');
352:
353: if (isOctDigit(c = ci.next())) {
354: i = i * 8 + (int) (c - '0');
355:
356: if (isOctDigit(c = ci.next()))
357: i = i * 8 + (int) (c - '0');
358: else
359: ci.previous();
360: } else
361: ci.previous();
362:
363: if (i > 0xff)
364: throw new JDOUserException(
365: "Invalid character escape: '\\"
366: + Integer.toOctalString(i) + "'");
367:
368: return (char) i;
369: } else {
370: switch (c) {
371: case 'b':
372: return '\b';
373: case 't':
374: return '\t';
375: case 'n':
376: return '\n';
377: case 'f':
378: return '\f';
379: case 'r':
380: return '\r';
381: case '"':
382: return '"';
383: case '\'':
384: return '\'';
385: case '\\':
386: return '\\';
387: default:
388: throw new JDOUserException(
389: "Invalid character escape: '\\" + c + "'");
390: }
391: }
392: }
393:
394: public boolean parseNullLiteral() {
395: int savedIdx = skipWS();
396: String id;
397:
398: if ((id = parseIdentifier()) == null)
399: return false;
400: else if (id.equals("null"))
401: return true;
402: else {
403: ci.setIndex(savedIdx);
404: return false;
405: }
406: }
407: }
|