KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > edu > rice > cs > util > sexp > SExpParser


1 /*BEGIN_COPYRIGHT_BLOCK
2  *
3  * This file is part of DrJava. Download the current version of this project from http://www.drjava.org/
4  * or http://sourceforge.net/projects/drjava/
5  *
6  * DrJava Open Source License
7  *
8  * Copyright (C) 2001-2006 JavaPLT group at Rice University (javaplt@rice.edu). All rights reserved.
9  *
10  * Developed by: Java Programming Languages Team, Rice University, http://www.cs.rice.edu/~javaplt/
11  *
12  * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
13  * documentation files (the "Software"), to deal with the Software without restriction, including without limitation
14  * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
15  * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
16  *
17  * - Redistributions of source code must retain the above copyright notice, this list of conditions and the
18  * following disclaimers.
19  * - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
20  * following disclaimers in the documentation and/or other materials provided with the distribution.
21  * - Neither the names of DrJava, the JavaPLT, Rice University, nor the names of its contributors may be used to
22  * endorse or promote products derived from this Software without specific prior written permission.
23  * - Products derived from this software may not be called "DrJava" nor use the term "DrJava" as part of their
24  * names without prior written permission from the JavaPLT group. For permission, write to javaplt@rice.edu.
25  *
26  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
27  * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28  * CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
29  * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
30  * WITH THE SOFTWARE.
31  *
32  *END_COPYRIGHT_BLOCK*/

33
34 package edu.rice.cs.util.sexp;
35
36 import java.io.File JavaDoc;
37 import java.io.Reader JavaDoc;
38 import java.io.FileReader JavaDoc;
39 import java.io.StringReader JavaDoc;
40 import java.io.IOException JavaDoc;
41 import java.util.List JavaDoc;
42 import java.util.ArrayList JavaDoc;
43 import java.util.LinkedList JavaDoc;
44
45 /**
46  * This parser is not meant to be instantiated. It has
47  * static methods that do all the work for you. These
48  * parse methods take in the data that is to be parsed
49  * and simply returns an s-expression abstract syntax.
50  * @author Jonathan Lugo, PLT Group
51  */

52 public class SExpParser {
53   
54   public static List JavaDoc<SEList> parse(File JavaDoc f) throws SExpParseException, IOException JavaDoc{
55     return parse(new FileReader JavaDoc(f));
56   }
57   
58   public static List JavaDoc<SEList> parse(String JavaDoc s) throws SExpParseException {
59     return parse(new StringReader JavaDoc(s));
60   }
61   
62   public static List JavaDoc<SEList> parse(Reader JavaDoc r) throws SExpParseException {
63     try {
64       return new ParseHelper(r).parseMultiple();
65     }
66     catch(LexingException e) {
67       throw new SExpParseException(e.getMessage());
68     }
69     catch(PrivateParseException e) {
70       throw new SExpParseException(e.getMessage());
71     }
72   }
73   
74   /**
75    * A new helper is instantiated for each time
76    * the user wants to parse data. This is not
77    * reused. The instances of the ParseHelpers are
78    * handled solely in the outer class SExpParser.
79    */

80   private static class ParseHelper {
81     
82     private Lexer _lex;
83     
84     public ParseHelper(Reader JavaDoc r) {
85       _lex = new Lexer(r);
86     }
87     
88     /**
89      * Parse a forest of top-level s-expressions from {@link #parseTopLevelExp()}.
90      * @see #parseTopLevelExp()
91      */

92     public List JavaDoc<SEList> parseMultiple() {
93       ArrayList JavaDoc<SEList> l = new ArrayList JavaDoc<SEList>();
94       SEList exp;
95       while ( (exp = parseTopLevelExp()) != null) {
96         l.add(exp);
97       }
98       return l;
99     }
100     
101     /**
102      * A top-level s-expression is simply a non-empty list. Our s-expression files
103      * can be a forest of several trees, but the Atomic values are not allowed
104      * at the top level, only lists.
105      * @return the top-level list s-expression
106      */

107     public SEList parseTopLevelExp() {
108       Tokens.SExpToken t = _lex.readToken();
109       if (t == Tokens.LeftParenToken.ONLY) {
110         return parseList();
111       }
112       else if (t == null) {
113         return null;
114       }
115       else {
116         throw new PrivateParseException("A top-level s-expression must be a list. "+
117                                         "Invalid start of list: " + t);
118       }
119     }
120     
121     /**
122      * Parses the next s-expression in the lexer's buffer.
123      * This may be either a cons or an atom
124      * @return the next s-expression in the read buffer.
125      */

126     public SExp parseExp() {
127       Tokens.SExpToken t = _lex.readToken();
128       assertNotEOF(t);
129       if (t == Tokens.LeftParenToken.ONLY) {
130         return parseList();
131       }
132       else {
133         return parseAtom(t);
134       }
135     }
136     
137     /**
138      * The left paren has already been read. This starts
139      * building up the recursive list structure
140      * @return the parsed recursive s-expression list
141      */

142     private SEList parseList() {
143       LinkedList JavaDoc<SExp> list = new LinkedList JavaDoc<SExp>();
144       Tokens.SExpToken t = _lex.peek();
145       assertNotEOF(t);
146       
147       while (t != Tokens.RightParenToken.ONLY) {
148         list.addFirst(parseExp());
149         t = _lex.peek();
150       }
151       
152       // t has to be a Tokens.RightParenToken at this point.
153
// simply eat the token
154
_lex.readToken();
155       
156       // Compile the cons structure from the list of exps
157
SEList cons = Empty.ONLY;
158       for (SExp exp : list) {
159         cons = new Cons(exp, cons);
160       }
161       return cons;
162     }
163     
164     /**
165      * Parses an atom. The token was already read and
166      * found not to start a list, this method interprets
167      * what is given. This method chooses which type of
168      * atom the token represents and creates the atom.
169      * @param t the token to interpret
170      * @return the correct corresponding atom
171      */

172     private Atom parseAtom(Tokens.SExpToken t) {
173       if (t instanceof Tokens.BooleanToken) {
174         if (((Tokens.BooleanToken)t).getValue())
175           return BoolAtom.TRUE;
176         else
177           return BoolAtom.FALSE;
178       }
179       else if (t instanceof Tokens.NumberToken) {
180         return new NumberAtom(((Tokens.NumberToken)t).getValue());
181       }
182       else if (t instanceof Tokens.QuotedTextToken) {
183         return new QuotedTextAtom(t.getText());
184       }
185       else {
186         return new TextAtom(t.getText());
187       }
188     }
189     
190     /**
191      * Throws the EOF exception if the given token is the end of file
192      * @param t the token to check
193      */

194     private void assertNotEOF(Tokens.SExpToken t) {
195       if (t == null) {
196         throw new PrivateParseException("Unexpected <EOF> at line " + _lex.lineno());
197       }
198     }
199   }
200   
201   /**
202    * This runtime exception makes it easier to write the parser since
203    * the methods of the helper class won't need to constantly declare
204    * the SExpParseException to be thrown.
205    */

206   private static class PrivateParseException extends RuntimeException JavaDoc {
207     /**
208      * Creates a runtime exception with the message that is desired for
209      * the eventual checked exception
210      * @param msg the message to display
211      */

212     public PrivateParseException(String JavaDoc msg) { super(msg); }
213   }
214 }
Popular Tags