/** * A parser for simple arithmetic expressions with * the operators +, -, *, / and ( ) * * It was written as a demonstration of a recursive * descent parser, therefore the emphasis is on * simplicity. * * @author P. Tellenbach * @version 16. Dec. 2007 */ public class Parser { /** String to be parsed */ protected String str ; /** Current position in the string */ protected int position ; /** * Parses a "term", which is a production with * the operators "*" or "/" * @throws ParseException thrown by parseFactor */ protected Node parseTerm() throws ParseException { // Parse factor to the left of the operator Node result = parseFactor() ; // While there are term operators in the string while( (position < str.length()) && ((str.charAt(position) == '*') || (str.charAt(position) == '/')) ) { // Create a new node with the operator Node node = new Node( str.substring(position,position+1) ) ; ++position ; // Set the previus node as the left subtree node.setLeft( result ) ; // Set the factor to the right of the operator as the right subtree node.setRight( parseFactor() ) ; result = node ; } return result ; } /** * Parses a "factor", which is either an expression enclosed * by "(" and ")" or a simple number. * Note the recursion via parseExpression. * @throws ParseException if the expression is not terminated by ")" */ protected Node parseFactor() throws ParseException { if( (position < str.length()) && (str.charAt(position) == '(') ) { ++position ; Node result = parseExpression() ; if( (position == str.length()) || (str.charAt(position) != ')') ) throw new ParseException( "Missing ')'" ) ; ++position ; return result ; } return parseNumber() ; } /** * Parses an "expression", which is a production with * the operators + and - * @throws ParseException thrown by parseTerm */ protected Node parseExpression() throws ParseException { Node result = parseTerm() ; while( (position < str.length()) && ((str.charAt(position) == '+') || (str.charAt(position) == '-')) ) { Node node = new Node( str.substring(position,position+1) ) ; ++position ; node.setLeft( result ) ; node.setRight( parseTerm() ) ; result = node ; } return result ; } /** * Returns an integer number from the string * @throws ParseException if the number is not valid */ protected Node parseNumber() throws ParseException { int start = position ; while( (position < str.length()) && (str.charAt(position) >= '0') && (str.charAt(position) <= '9') ) ++position ; if( position == start ) throw new ParseException( "Number expected" ) ; return new Node( str.substring(start,position) ) ; } /** * Sets up the members, starts the parser and checks if * the whole string was parsed correctly. * Note that the string to be parsed may not contain whitespace. * @throws ParseException if there are any unparsed characters */ public Node parse( String expr ) throws ParseException { str = expr ; position = 0 ; Node result = parseExpression() ; if( position != str.length() ) throw new ParseException( "Invalid expression" ) ; return result ; } }