/* * Name: Mike Cifelli * Course: CIS 443 - Programming Languages * Assignment: Lisp Interpreter Phase 1 - Lexical Analysis */ package scanner; import java.io.InputStream; import java.io.FilterInputStream; import java.io.IOException; /** * A LispFilterStream is an input stream that returns the bytes * from an underlying input stream with all Lisp comments removed and replaced * with newlines. */ public class LispFilterStream extends FilterInputStream { private boolean inQuote; /** * Creates a LispFilterStream with the specified underlying * InputStream. * * @param in * the underlying input stream (must not be null) */ public LispFilterStream(InputStream in) { super(in); inQuote = false; } /** * Reads the next byte of data from this input stream. The value byte is * returned as an int in the range 0 to * 255. If no byte is available because the end of the stream * has been reached, the value -1 is returned. * * @return * the next byte of data, or -1 if the end of the stream has * been reached. * @throws IOException * Indicates that an I/O error has occurred. */ @Override public int read() throws IOException { int next = super.read(); if ((next == ';') && (! inQuote)) { // we have entered a comment, consume all the bytes from the // underlying input stream until we reach a newline character or // the end of the stream while ((next != '\n') && (next != -1)) { next = super.read(); } } else if (next == '\n') { inQuote = false; } else if (next == '\"') { // we have entered or left a quoted string inQuote = (! inQuote); } return next; } /** * Reads up to the specified number of data bytes from this input stream * into an array of bytes starting at the specified offset. If no bytes are * available because the end of this stream has been reached then * -1 is returned. Also, If the specified number of bytes is * more than the number of remaining data bytes in this input stream, then * only the number of remaining data bytes are copied into the byte array. * * @param b * the buffer into which the data bytes are read (must not be * null) * @param off * the start offset in b at which the data is written (must * be >= 0 and < b.length) * @param len * the maximum number of bytes to read into b (len + * off must be < b.length) * @return * the total number of bytes read into the buffer, or -1 if * there is no more data because the end of the stream has been reached * @throws IOException * Indicates that the first byte could not be read into b * for some reason other than reaching the end of the stream. * @throws IndexOutOfBoundsException * Indicates that this method attempted to access an index in * b that was either negative or greater than or equal to * b.length as a result of the given parameters. * @throws NullPointerException * Indicates that b is null. */ @Override public int read(byte[] b, int off, int len) throws IOException { int bytesRead = 0; // make sure we are supposed to read at least one byte into 'b' if (len > 0) { int next = read(); if (next == -1) { // there are no more bytes to read from this input stream return -1; } int i = off; while (next != -1) { ++bytesRead; b[i++] = (byte) next; if (i >= (off + len)) { // we have read 'len' bytes into 'b' break; } try { next = read(); } catch (IOException e) { // treat this exception like an end of stream break; } } } return bytesRead; } /** * Skip over and discard the specified number of bytes from this input * stream. This method may, for a variety of reasons, end up skipping some * smaller number of bytes, possibly 0. The actual number of * bytes skipped is returned. * * @param n * the number of bytes to be skipped * @return * the actual number of bytes skipped * @throws IOException * Indicates that an I/O error has occurred. */ @Override public long skip (long n) throws IOException { long bytesSkipped = 0; while ((n > 0) && (read() != -1)) { ++bytesSkipped; --n; } return bytesSkipped; } }