// file: SexpParser.java // author: Robert Keller // purpose: Illustrating S expression parser // // The grammar used here is: // // S -> '(' {S} ')' | A S expressions // // A -> 'a' | 'b' | 'c' atoms // // Here {....} means 0-or-more of .... and | is alternatives // // Each parse method returns true or false indicating whether or not // it parsed its syntactic category from the input stream import java.io.*; class SexpParser { PushbackInputStream in; // stream from which parsing takes characters SexpParser(InputStream in) // constructor { this.in = new PushbackInputStream(in); } // parse method for S expression boolean S() { int c; // character read if( end(c = read()) ) return false; // eof is not S expression if( c == '(' ) // see if "(..." { while( !end(c = read()) ) { if( c == ')' ) return true; // terminated "...)" unread(c); if( !S() ) // parse inner S expressions return false; } return false; // something else } else { unread(c); return A(); // not "(...", must be atom } } // Parse method for atom boolean A() { int c = read(); switch( c ) { case 'a': case 'b': case 'c': return true; default: unread(c); return false; } } // loop tries to parse one S expression per line, until end-of-file void loop() { int c; while( !eof(c = read()) ) // while not end-of-file { unread(c); if( S() ) { System.out.print("ok"); skipWhitespace(); if( (c = read()) != '\n' ) { System.out.println(", except garbage at the end"); } else System.out.println(); unread(c); } else { System.out.println("bad"); } skipToEOL(); // skip to end-of-line } } // main program public static void main(String[] arg) { SexpParser parser = new SexpParser(System.in); parser.loop(); } // read next character int read() { int c; try { c = in.read(); return c; } catch(IOException e) { System.err.println("Input Exception"); return -1; // treat as end-of-file } } // unread character void unread(int c) { try { in.unread(c); } catch(IOException e) { System.err.println("Exception unreading"); } } // skip to end-of-line void skipToEOL() { int c; while( (c = read()) >= 0 ) // stop if end-of-file { switch( c ) { case '\n': return; } } } // skip any whitespace void skipWhitespace() { int c; while( (c = read()) >= 0 ) // stop if end-of-file { switch( c ) { case '\t': case ' ' : break; // whitespace, keep going default: unread(c); // other, return return; } } } // end tells whether c is end-of-line or end-of-file static boolean end(int c) { if( eof(c) ) return true; if( c == '\n' ) return true; return false; } // eof tells whether c is end-of-file static boolean eof(int c) { return c < 0; } } // SexpParser