/* file: Additive.java author: Robert Keller purpose: Tutorial additive expression parser The program reads an additive expression from standard input and shows its tree as an S expr. A -> V { '+' V } // additive expr V -> a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z // variable In the grammar { }, means 0 or more of what's inside and | means "or" */ import polya.*; import java.io.*; class Additive extends ParseFromString { static String promptString = "additive > "; /** * constructor for additive parser */ Additive(String input) { super(input); // capture input } /** * Top-level parse method: parse and check for residual input */ Object parse() { Object result = A(); skipWhitespace(); if( position < lastPosition ) { System.out.print("*** Residual characters after input: "); while( !eof ) { System.out.print(nextChar()); } System.out.println(); } return result; } /** * PARSE METHOD for A -> V { '+' V } */ Object A() { Object result; Object V1 = V(); if( isFailure(V1) ) return failure; result = V1; while( skipWhitespace() && nextCharIs('+') ) { Object V2 = V(); if( isFailure(V2) ) return failure; result = Polylist.list("+", result, V2); } return result; } /** * PARSE METHOD for V -> a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p * |q|r|s|t|u|v|w|x|y|z */ Object V() { skipWhitespace(); if( isVar(peek()) ) { return (new StringBuffer(1).append(nextChar())).toString(); } return failure; } /** * predicate defining whether its argument is a variable */ boolean isVar(char c) { switch( c ) { case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': return true; default: return false; } } /** * test program for additive parser */ static public void main(String arg[]) { // BufferedReader is used to read a line at a time BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); String input; try { while( prompt() && (input = in.readLine()) != null ) { Additive parser = new Additive(input); Object result = parser.parse(); System.out.println("result: " + result); System.out.println(); } } catch( IOException e ) { System.err.println("*** IOException caught; terminating"); } System.out.println(); } /** * The prompter. Prints a prompt string. * The return value is just so this can be used inside a while condition. */ static boolean prompt() { System.out.print(promptString); System.out.flush(); return true; } } /** * ParseFromString is the base class for parsing from a String, such as a * single input line */ class ParseFromString { public final static ParseFailure failure = new ParseFailure(); // failure protected String input; // input to parser protected int position; // position of current character protected int lastPosition; // last position in input string protected boolean eof; // end-of-file condition exists /** * Create ParseFromString object for string to be parsed. */ ParseFromString(String input) { this.input = input; position = -1; lastPosition = input.length()-1; eof = lastPosition == -1; } /** * Get the next input character. */ char nextChar() { if( position >= lastPosition ) { eof = true; return ' '; } return input.charAt(++position); } /** * If next char is the specified one, remove it and return true. * Otherwise return false. */ boolean nextCharIs(char c) { if( position >= lastPosition ) { eof = true; return false; } if( c == peek() ) { nextChar(); return true; } return false; } /** * Return the next character in the input, but don't remove it. */ char peek() { if( position >= lastPosition ) { return ' '; } return input.charAt(position+1); } /** * Put previously read character back. */ void putBack() { if( position >= 0 ) { position--; } } /** * Skip any whitespace. */ boolean skipWhitespace() { while( !eof && peek() == ' ' ) { nextChar(); } return true; } /** * Test whether the argument is a ParseFailure object. */ boolean isFailure(Object ob) { return ob instanceof ParseFailure; } } // class ParseFromString /** * ParseFailure object is used to indicate a parse failure. */ class ParseFailure { }