//============================================================================== // tribble/io/CharInputStreamDfl.java //------------------------------------------------------------------------------ package tribble.io; // System imports import java.io.IOException; import java.io.Reader; import java.lang.String; // Local imports import tribble.io.CharInputStreamI; import tribble.io.DiagnosticOutputI; import tribble.io.DiagnosticWriterI; /******************************************************************************* * Default generic character input stream. * *
* This is a default implementation of an input stream that is capable of * reading a single character at a time. Such a stream can be used as the * underlying character input stream for classes implementing the {@link LexerI} * interface. * *
* This character stream handles various combinations of newline termination * characters (LF, CR, and CR/LF pairs), returning a single newline character * ('\n') for any given combination. * *
* This also handles formfeed (FF) and null (NUL) characters, treating them as * spaces (SP). * *
* Tab (HT) characters are replaced with one or more spaces, to align on tabbed
* columns. By default, tabs are replaced with the appropriate number of spaces
* so as to align on 8-character columns, but this can be changed to a different
* width or disabled altogether.
*
* @version $Revision: 1.2 $ $Date: 2003/01/25 18:40:45 $
* @since 2001-05-18
* @author
* David R. Tribble,
* david@tribble.com.
*
* Copyright
* ©2001-2003 by David R. Tribble, all rights reserved.
*
* Permission is granted to freely use and distribute this source code
* provided that the original copyright and authorship notices remain
* intact.
*
* @see LexerI
*/
public class CharInputStreamDfl
implements CharInputStreamI, DiagnosticWriterI
{
// Identification
/** Revision information. */
static final String REV =
"@(#)tribble/io/CharInputStreamDfl.java $Revision: 1.2 $ $Date: 2003/01/25 18:40:45 $\n";
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Public constants
/** End of file character code. */
public static final int EOF = -1;
/** Default tab width. */
public static final int DFL_TABSIZE = 8;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Protected variables
/** Input stream. */
protected Reader m_in;
/** Diagnostic output stream. */
protected DiagnosticOutputI m_out;
/** Pushed-back (unread) character. */
protected int m_ungetc = EOF;
/** Column position (of the last character read). */
protected int m_colNo = 0;
/** Tab (HT) column width. */
protected int m_tabSz = DFL_TABSIZE;
/** Pending tab (HT) character replacement. */
protected int m_tabSp;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Public constructor methods
/***************************************************************************
* Default constructor.
*
* @since 1.1, 2001-05-18
*/
public CharInputStreamDfl()
{
// Do nothing
}
/***************************************************************************
* Constructor.
*
* @param in
* The input stream from which to read characters.
*
* @since 1.1, 2001-05-18
*/
public CharInputStreamDfl(Reader in)
{
// Establish the input stream
setInput(in);
}
/***************************************************************************
* Constructor.
*
* @param in
* The input stream from which to read characters.
*
* @param out
* The diagnostic output stream to write to.
*
* @since 1.1, 2001-05-18
*/
public CharInputStreamDfl(Reader in, DiagnosticOutputI out)
{
// Establish the input and output streams
setInput(in);
setOutput(out);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Public methods
/***************************************************************************
* Establish the output stream to which diagnostic messages (warning and
* error messages) are written during parsing.
*
* @param out
* The diagnostic output stream.
*
* @since 1.1, 2001-05-18
*/
public void setOutput(DiagnosticOutputI out)
//implements tribble.io.DiagnosticWriterI
{
// Establish the output stream
m_out = out;
}
/***************************************************************************
* Establish the input stream from which to read characters.
*
* @param in
* The input stream from which to read characters.
*
* @since 1.1, 2001-05-18
*/
public void setInput(Reader in)
//implements tribble.io.CharInputStreamI
{
// Establish the input stream
m_in = in;
}
/***************************************************************************
* Close the input stream.
*
* @since 1.1, 2001-05-18
*/
public void close()
//implements tribble.io.CharInputStreamI
{
try
{
// Close the input stream
if (m_in != null)
m_in.close();
}
catch (IOException ex)
{
// Ignored
}
// Disassociate the input stream from this character stream
m_in = null;
}
/***************************************************************************
* Read the next character from the input stream.
*
*
* This character stream handles various combinations of newline termination * characters (LF, CR, and CR/LF pairs), returning a single newline * character ('\n') for any given combination. * *
* This stream also handles formfeed (FF) and null (NUL) characters, * replacing them with spaces (SP). * *
* Tab (HT) characters are replaced by one or more space (SP) characters, so * that the character following the tab is aligned on a tab-sized column. * Tab character replacement can be disabled by specifying a tab size of * zero (see {@link #setTabSize}). * * @return * The next character code read from the input stream, or -1 if there are no * more characters to read (i.e., the end of the input stream was reached). * * @throws IOException * Thrown if an I/O (read) error occurs. * * @since 1.1, 2001-05-18 */ public int readChar() throws IOException //implements tribble.io.CharInputStreamI { int ch; // Check for an open input stream if (m_in == null) return (EOF); // End of file // Check for a previously pushed-back character if (m_ungetc != EOF) { // Use the pushed-back character ch = m_ungetc; m_ungetc = EOF; } else if (m_tabSp > 0) { // Continue replacing a tab (HT) with spaces (SP) m_tabSp--; ch = ' '; m_colNo++; } else { // Read the next character from the input stream ch = m_in.read(); // May throw m_colNo++; } // Handle control characters if (ch < ' ') { if (ch == '\n') { // End of line: LF m_colNo = 0; } else if (ch == '\r') { // End of line: CR, check for CR/LF pair ch = m_in.read(); // May throw if (ch != '\n') m_ungetc = ch; ch = '\n'; m_colNo = 0; } else if (ch == '\t' && m_tabSz > 0) { // Tab (HT), replace with spaces (SP) m_tabSp = 8 - m_colNo%8; ch = ' '; } else if (ch == '\f') { // Formfeed (FF), treat as a space (SP) ch = ' '; } else if (ch == '\0') { // Null (NUL) character, treat as a space (SP) ch = ' '; } // else leave character as is } // Done return (ch); } /*************************************************************************** * Establish the tab (HT) column width. * *
* Setting a tab width of zero disables the replacing of tab (HT) characters * with spaces, i.e., tab characters are read as is. The default tab width * is 8. * * @param n * The tab column width. * * @since 1.1, 2001-06-02 */ public void setTabSize(int n) { m_tabSz = n; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Protected methods /*************************************************************************** * Finalization. * Closes the underlying output stream, if any. * * @since 1.1, 2001-05-18 */ protected synchronized void finalize() { // Close and disassociate the input stream close(); // Disassociate (but do not close) the output stream m_out = null; } } // End CharInputStreamDfl.java