92.

The following code implements a constructor for nonempty lists that takes a String representation of a list and parses it into a list, as described in Chapter 14. The parser used is a general-purpose parser for S-expressions. S-expressions (short for symbolic expressions) are built from a set of atomic elements (called atoms or symbols). Given the set of atoms, any S-expression is either an atom or a list of S-expressions.

In order to avoid namespace clash with java.util, all S-expression classes (including List classes) are prepended with S. The constructor itself appears in class SCons. It also appears as a Factory method in class SExp.

This code is also available online at http://www.cs.rice.edu/~eallen.

Listing A-1: String-Parsing List Constructor

start example
 import java.util.*; interface StackI {   /**    * @ pre ! isEmpty()    */   public Object top();   public Object pop();   public void push(Object o);   public boolean isEmpty(); } class SExpParseException extends Exception {   public SExpParseException(String msg) {     super(msg);   } } abstract class SExp {   public static final String LEFT_PAREN = "(";   public static final String RIGHT_PAREN = ")";   public static SExp parse(String tokens) throws SExpParseException {     return parseSExp(new StringStack(tokens));   }   public static SExp parseSExp(StackI tokens) throws SExpParseException {     SExp nextSExp = parseNextSExp(tokens);     if (tokens.isEmpty()) {       // The stack of tokens consisted of a single S-expression       // (with possible subexpressions), as expected.       return nextSExp;     }     else {       throw new SExpParseException("Extraneous material "+                                       "at end of stream.");     }   }   public static SExp parseNextSExp(StackI tokens) throws SExpParseException {     if (tokens.isEmpty()) {       throw new SExpParseException("Unexpected end of token stream.");     }     else { // tokens.pop() succeeds       Object next = tokens.pop();       if (next.equals(LEFT_PAREN)) {         // The S-expression is a list. Accumulate the subexpressions         // this list contains, and return the result.         SList result = SEmpty.ONLY;         while (! tokens.isEmpty()) { // tokens.pop() succeeds           next = tokens.top();           if (next.equals(RIGHT_PAREN)) {             // We've reached the end of the list. We need only             // pop off the ending right parenthesis before returning.             // Since subexpressions were accumulated in the front             // of the list, we must return the reverse of the list             // to reflect the proper structure of the S-expression.             tokens.pop();             return result.reverse();           }           else {             // Recursively parse the next subexpression and             // add it to result.             result = new SCons(parseNextSExp(tokens), result);           }         }         // If we haven't yet returned, then we've reached the end         // of the token stream without finding the matching right         // paren.         throw new SExpParseException("Unmatched left parenthesis.");       }       else if (next.equals(RIGHT_PAREN)) {         // A right parenthesis was encountered at the beginning of         // the S-expression!         throw new SExpParseException("Unmatched right parenthesis.");       }       else {          // The next S-expression is an atom.          return new Atom(next);       }     }   } } class StringStack implements StackI {   StringBuffer _values;   public StringStack(String values) {     _values = new StringBuffer(values);   }   public Object top() {     if (_values.length() == 0) {       throw new RuntimeException("Attempt to call top on an empty stack.");     }     else { // _values.length() >= 1       return new StringBuffer().append(_values.charAt(0)).toString();     }   }   public Object pop() {     if (_values.length() == 0) {       throw new RuntimeException("Attempt to pop an empty stack.");     }     else { // _values.length() >= 1       String result = new StringBuffer().append(_values.charAt(0)).toString();       _values.deleteCharAt(0);       return result;     }   }   public void push(Object o) {     _values.append(o);   }   public boolean isEmpty() {     return _values.length() == 0;   } } abstract class SList extends SExp {   abstract SList reverse();   /**    * Although accessing first() and rest() is valid only on non-empty    * lists, we can simplify many list-based operations by including    * these accessors in the SList interface and then implementing them    * in SEmpty with methods that throw exceptions. Since the alternative    * would be to insert casts in many cases (such as the inner class    * Iterator, below), this design does not decrease the effectiveness    * of static checking. Additionally, the information provided during    * an error at run-time is at least as informative.    */   public abstract SExp first();   public abstract SList rest();   class Iterator {     SList values;     public Iterator() {       values = SList.this;     }     public SExp next() {       SExp result = values.first();       values = values.rest();       return result;     }     public boolean hasNext() {       return !(values == SEmpty.ONLY);     }   } } class SEmpty extends SList {   public static final SEmpty ONLY = new SEmpty();   private SEmpty() {}   public String toString() {     return "()";   }   SList reverse() {     return this;   }   public SExp first() {     throw new RuntimeException("Attempt to access the first element "+                                  "of an empty list.");   }   public SList rest() {     throw new RuntimeException("Attempt to access rest of an empty list.");   } } class SCons extends SList {   private SExp first;   private SList rest;   public SCons(SExp _first, SList _rest) {     this.first = _first;     this.rest = _rest;   }   /**    * @pre SExp.parse(s) instanceof SCons    */   public SCons(String s) throws SExpParseException {     // Notice that the precondition guarantees that the cast     // below will always succeed.     SCons that = (SCons)SExp.parse(s);     first = that.first();     rest = that.rest();   }   public SExp first() {return this.first;}   public SList rest() {return this.rest;}   SList reverse() {     SList result = SEmpty.ONLY;     SList.Iterator iter = this.new Iterator();     while (iter.hasNext()) {       result = new SCons(iter.next(), result);     }     return result;   }   public String toString() {     StringBuffer result = new StringBuffer("(");     SList.Iterator iter = this.new Iterator();     while (iter.hasNext()) {       result.append(iter.next().toString());     }     result.append(")");     return result.toString();   } } class Atom extends SExp {   public Object value;   public Atom(Object _value) {     this.value = _value;   }   public String toString() {     return value.toString();   } } 
end example



Bug Patterns in Java
Bug Patterns In Java
ISBN: 1590590619
EAN: 2147483647
Year: N/A
Pages: 95
Authors: Eric Allen

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net