Lisp for Java Users: Peek Stream

Before implementing a simple parser it is useful to implement a wrapper around input streams. The PeekStream class wraps an InputStream and provides methods to peek and read the next character.

The class definition starts like this:

public class PeekStream { private static final String BLANKS = " \t\n\r"; private final InputStream stream; private int pushback = -1; public PeekStream (final InputStream stream) { this.stream = stream; } }

The first method peeks at the next character and returns its value, but leaves it available for the next read operation. This works using the instance variable pushback as a single character buffer. (The stream methods mark and reset could be used instead of a pushback buffer, but not all InputStreams support the mark method.)

public int peekChar () throws IOException { if (pushback < 0) { pushback = stream.read (); } return pushback; }

The second method peeks at the next character and determines if it is expected. The boolean value indicates if the next character is expected or not.

public boolean peekChar (final char expected) throws IOException { if (pushback < 0) { pushback = stream.read (); } return expected == (char)pushback; }

The third method simple reads the next character and returns it. If peek has been called, the character will be in the pushback buffer. Otherwise, the character is obtained from the wrapped stream.

public int readChar () throws IOException { if (pushback >= 0) { final int result = pushback; pushback = -1; return result; } return stream.read (); }

The fourth method reads the next character and determines if it is expected. An error is thrown if the character is not as expected.

public void readChar (final char expected) throws IOException { final int chr = readChar (); if (chr != expected) { throw new Error (String.format ("Expected '%c' but read '%c'", expected, chr)); } }

The fifth method reads and discards blank characters. This method could be extended to support comments, if required.

public void skipBlanks () throws IOException { while (BLANKS.indexOf (peekChar ()) >= 0) { readChar (); } }

The PeekStream class includes the methods defined above. As you can see, these are all very simple support methods, but they make it easier to implement a simple parser.