001: package persistence.antlr;
002:
003: /* ANTLR Translator Generator
004: * Project led by Terence Parr at http://www.jGuru.com
005: * Software rights: http://www.antlr.org/license.html
006: *
007: */
008:
009: import persistence.antlr.collections.impl.BitSet;
010: import persistence.antlr.collections.AST;
011: import persistence.antlr.collections.impl.ASTArray;
012:
013: /**A generic ANTLR parser (LL(k) for k>=1) containing a bunch of
014: * utility routines useful at any lookahead depth. We distinguish between
015: * the LL(1) and LL(k) parsers because of efficiency. This may not be
016: * necessary in the near future.
017: *
018: * Each parser object contains the state of the parse including a lookahead
019: * cache (the form of which is determined by the subclass), whether or
020: * not the parser is in guess mode, where tokens come from, etc...
021: *
022: * <p>
023: * During <b>guess</b> mode, the current lookahead token(s) and token type(s)
024: * cache must be saved because the token stream may not have been informed
025: * to save the token (via <tt>mark</tt>) before the <tt>try</tt> block.
026: * Guessing is started by:
027: * <ol>
028: * <li>saving the lookahead cache.
029: * <li>marking the current position in the TokenBuffer.
030: * <li>increasing the guessing level.
031: * </ol>
032: *
033: * After guessing, the parser state is restored by:
034: * <ol>
035: * <li>restoring the lookahead cache.
036: * <li>rewinding the TokenBuffer.
037: * <li>decreasing the guessing level.
038: * </ol>
039: *
040: * @see persistence.antlr.Token
041: * @see persistence.antlr.TokenBuffer
042: * @see persistence.antlr.Tokenizer
043: * @see persistence.antlr.LL1Parser
044: * @see persistence.antlr.LLkParser
045: */
046:
047: import java.io.IOException;
048: import java.util.Hashtable;
049:
050: import persistence.antlr.debug.MessageListener;
051: import persistence.antlr.debug.ParserListener;
052: import persistence.antlr.debug.ParserMatchListener;
053: import persistence.antlr.debug.ParserTokenListener;
054: import persistence.antlr.debug.SemanticPredicateListener;
055: import persistence.antlr.debug.SyntacticPredicateListener;
056: import persistence.antlr.debug.TraceListener;
057:
058: public abstract class Parser {
059: protected ParserSharedInputState inputState;
060:
061: /** Nesting level of registered handlers */
062: // protected int exceptionLevel = 0;
063: /** Table of token type to token names */
064: protected String[] tokenNames;
065:
066: /** AST return value for a rule is squirreled away here */
067: protected AST returnAST;
068:
069: /** AST support code; parser delegates to this object.
070: * This is set during parser construction by default
071: * to either "new ASTFactory()" or a ctor that
072: * has a token type to class map for hetero nodes.
073: */
074: protected ASTFactory astFactory = null;
075:
076: /** Constructed if any AST types specified in tokens{..}.
077: * Maps an Integer->Class object.
078: */
079: protected Hashtable tokenTypeToASTClassMap = null;
080:
081: private boolean ignoreInvalidDebugCalls = false;
082:
083: /** Used to keep track of indentdepth for traceIn/Out */
084: protected int traceDepth = 0;
085:
086: public Parser() {
087: this (new ParserSharedInputState());
088: }
089:
090: public Parser(ParserSharedInputState state) {
091: inputState = state;
092: }
093:
094: /** If the user specifies a tokens{} section with heterogeneous
095: * AST node types, then ANTLR generates code to fill
096: * this mapping.
097: */
098: public Hashtable getTokenTypeToASTClassMap() {
099: return tokenTypeToASTClassMap;
100: }
101:
102: public void addMessageListener(MessageListener l) {
103: if (!ignoreInvalidDebugCalls)
104: throw new IllegalArgumentException(
105: "addMessageListener() is only valid if parser built for debugging");
106: }
107:
108: public void addParserListener(ParserListener l) {
109: if (!ignoreInvalidDebugCalls)
110: throw new IllegalArgumentException(
111: "addParserListener() is only valid if parser built for debugging");
112: }
113:
114: public void addParserMatchListener(ParserMatchListener l) {
115: if (!ignoreInvalidDebugCalls)
116: throw new IllegalArgumentException(
117: "addParserMatchListener() is only valid if parser built for debugging");
118: }
119:
120: public void addParserTokenListener(ParserTokenListener l) {
121: if (!ignoreInvalidDebugCalls)
122: throw new IllegalArgumentException(
123: "addParserTokenListener() is only valid if parser built for debugging");
124: }
125:
126: public void addSemanticPredicateListener(SemanticPredicateListener l) {
127: if (!ignoreInvalidDebugCalls)
128: throw new IllegalArgumentException(
129: "addSemanticPredicateListener() is only valid if parser built for debugging");
130: }
131:
132: public void addSyntacticPredicateListener(
133: SyntacticPredicateListener l) {
134: if (!ignoreInvalidDebugCalls)
135: throw new IllegalArgumentException(
136: "addSyntacticPredicateListener() is only valid if parser built for debugging");
137: }
138:
139: public void addTraceListener(TraceListener l) {
140: if (!ignoreInvalidDebugCalls)
141: throw new IllegalArgumentException(
142: "addTraceListener() is only valid if parser built for debugging");
143: }
144:
145: /**Get another token object from the token stream */
146: public abstract void consume() throws TokenStreamException;
147:
148: /** Consume tokens until one matches the given token */
149: public void consumeUntil(int tokenType) throws TokenStreamException {
150: while (LA(1) != Token.EOF_TYPE && LA(1) != tokenType) {
151: consume();
152: }
153: }
154:
155: /** Consume tokens until one matches the given token set */
156: public void consumeUntil(BitSet set) throws TokenStreamException {
157: while (LA(1) != Token.EOF_TYPE && !set.member(LA(1))) {
158: consume();
159: }
160: }
161:
162: protected void defaultDebuggingSetup(TokenStream lexer,
163: TokenBuffer tokBuf) {
164: // by default, do nothing -- we're not debugging
165: }
166:
167: /** Get the AST return value squirreled away in the parser */
168: public AST getAST() {
169: return returnAST;
170: }
171:
172: public ASTFactory getASTFactory() {
173: return astFactory;
174: }
175:
176: public String getFilename() {
177: return inputState.filename;
178: }
179:
180: public ParserSharedInputState getInputState() {
181: return inputState;
182: }
183:
184: public void setInputState(ParserSharedInputState state) {
185: inputState = state;
186: }
187:
188: public String getTokenName(int num) {
189: return tokenNames[num];
190: }
191:
192: public String[] getTokenNames() {
193: return tokenNames;
194: }
195:
196: public boolean isDebugMode() {
197: return false;
198: }
199:
200: /** Return the token type of the ith token of lookahead where i=1
201: * is the current token being examined by the parser (i.e., it
202: * has not been matched yet).
203: */
204: public abstract int LA(int i) throws TokenStreamException;
205:
206: /**Return the ith token of lookahead */
207: public abstract Token LT(int i) throws TokenStreamException;
208:
209: // Forwarded to TokenBuffer
210: public int mark() {
211: return inputState.input.mark();
212: }
213:
214: /**Make sure current lookahead symbol matches token type <tt>t</tt>.
215: * Throw an exception upon mismatch, which is catch by either the
216: * error handler or by the syntactic predicate.
217: */
218: public void match(int t) throws MismatchedTokenException,
219: TokenStreamException {
220: if (LA(1) != t)
221: throw new MismatchedTokenException(tokenNames, LT(1), t,
222: false, getFilename());
223: else
224: // mark token as consumed -- fetch next token deferred until LA/LT
225: consume();
226: }
227:
228: /**Make sure current lookahead symbol matches the given set
229: * Throw an exception upon mismatch, which is catch by either the
230: * error handler or by the syntactic predicate.
231: */
232: public void match(BitSet b) throws MismatchedTokenException,
233: TokenStreamException {
234: if (!b.member(LA(1)))
235: throw new MismatchedTokenException(tokenNames, LT(1), b,
236: false, getFilename());
237: else
238: // mark token as consumed -- fetch next token deferred until LA/LT
239: consume();
240: }
241:
242: public void matchNot(int t) throws MismatchedTokenException,
243: TokenStreamException {
244: if (LA(1) == t)
245: // Throws inverted-sense exception
246: throw new MismatchedTokenException(tokenNames, LT(1), t,
247: true, getFilename());
248: else
249: // mark token as consumed -- fetch next token deferred until LA/LT
250: consume();
251: }
252:
253: /** @deprecated as of 2.7.2. This method calls System.exit() and writes
254: * directly to stderr, which is usually not appropriate when
255: * a parser is embedded into a larger application. Since the method is
256: * <code>static</code>, it cannot be overridden to avoid these problems.
257: * ANTLR no longer uses this method internally or in generated code.
258: */
259: public static void panic() {
260: System.err.println("Parser: panic");
261: System.exit(1);
262: }
263:
264: public void removeMessageListener(MessageListener l) {
265: if (!ignoreInvalidDebugCalls)
266: throw new RuntimeException(
267: "removeMessageListener() is only valid if parser built for debugging");
268: }
269:
270: public void removeParserListener(ParserListener l) {
271: if (!ignoreInvalidDebugCalls)
272: throw new RuntimeException(
273: "removeParserListener() is only valid if parser built for debugging");
274: }
275:
276: public void removeParserMatchListener(ParserMatchListener l) {
277: if (!ignoreInvalidDebugCalls)
278: throw new RuntimeException(
279: "removeParserMatchListener() is only valid if parser built for debugging");
280: }
281:
282: public void removeParserTokenListener(ParserTokenListener l) {
283: if (!ignoreInvalidDebugCalls)
284: throw new RuntimeException(
285: "removeParserTokenListener() is only valid if parser built for debugging");
286: }
287:
288: public void removeSemanticPredicateListener(
289: SemanticPredicateListener l) {
290: if (!ignoreInvalidDebugCalls)
291: throw new IllegalArgumentException(
292: "removeSemanticPredicateListener() is only valid if parser built for debugging");
293: }
294:
295: public void removeSyntacticPredicateListener(
296: SyntacticPredicateListener l) {
297: if (!ignoreInvalidDebugCalls)
298: throw new IllegalArgumentException(
299: "removeSyntacticPredicateListener() is only valid if parser built for debugging");
300: }
301:
302: public void removeTraceListener(TraceListener l) {
303: if (!ignoreInvalidDebugCalls)
304: throw new RuntimeException(
305: "removeTraceListener() is only valid if parser built for debugging");
306: }
307:
308: /** Parser error-reporting function can be overridden in subclass */
309: public void reportError(RecognitionException ex) {
310: System.err.println(ex);
311: }
312:
313: /** Parser error-reporting function can be overridden in subclass */
314: public void reportError(String s) {
315: if (getFilename() == null) {
316: System.err.println("error: " + s);
317: } else {
318: System.err.println(getFilename() + ": error: " + s);
319: }
320: }
321:
322: /** Parser warning-reporting function can be overridden in subclass */
323: public void reportWarning(String s) {
324: if (getFilename() == null) {
325: System.err.println("warning: " + s);
326: } else {
327: System.err.println(getFilename() + ": warning: " + s);
328: }
329: }
330:
331: public void rewind(int pos) {
332: inputState.input.rewind(pos);
333: }
334:
335: /** Specify an object with support code (shared by
336: * Parser and TreeParser. Normally, the programmer
337: * does not play with this, using setASTNodeType instead.
338: */
339: public void setASTFactory(ASTFactory f) {
340: astFactory = f;
341: }
342:
343: public void setASTNodeClass(String cl) {
344: astFactory.setASTNodeType(cl);
345: }
346:
347: /** Specify the type of node to create during tree building; use setASTNodeClass now
348: * to be consistent with Token Object Type accessor.
349: * @deprecated since 2.7.1
350: */
351: public void setASTNodeType(String nodeType) {
352: setASTNodeClass(nodeType);
353: }
354:
355: public void setDebugMode(boolean debugMode) {
356: if (!ignoreInvalidDebugCalls)
357: throw new RuntimeException(
358: "setDebugMode() only valid if parser built for debugging");
359: }
360:
361: public void setFilename(String f) {
362: inputState.filename = f;
363: }
364:
365: public void setIgnoreInvalidDebugCalls(boolean value) {
366: ignoreInvalidDebugCalls = value;
367: }
368:
369: /** Set or change the input token buffer */
370: public void setTokenBuffer(TokenBuffer t) {
371: inputState.input = t;
372: }
373:
374: public void traceIndent() {
375: for (int i = 0; i < traceDepth; i++)
376: System.out.print(" ");
377: }
378:
379: public void traceIn(String rname) throws TokenStreamException {
380: traceDepth += 1;
381: traceIndent();
382: System.out.println("> " + rname + "; LA(1)==" + LT(1).getText()
383: + ((inputState.guessing > 0) ? " [guessing]" : ""));
384: }
385:
386: public void traceOut(String rname) throws TokenStreamException {
387: traceIndent();
388: System.out.println("< " + rname + "; LA(1)==" + LT(1).getText()
389: + ((inputState.guessing > 0) ? " [guessing]" : ""));
390: traceDepth -= 1;
391: }
392: }
|