KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > percederberg > grammatica > output > JavaParserFile


1 /*
2  * JavaParserFile.java
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public License
6  * as published by the Free Software Foundation; either version 2.1
7  * of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free
16  * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
17  * MA 02111-1307, USA.
18  *
19  * Copyright (c) 2003-2005 Per Cederberg. All rights reserved.
20  */

21
22 package net.percederberg.grammatica.output;
23
24 import java.io.IOException JavaDoc;
25 import java.util.HashMap JavaDoc;
26
27 import net.percederberg.grammatica.code.java.JavaClass;
28 import net.percederberg.grammatica.code.java.JavaComment;
29 import net.percederberg.grammatica.code.java.JavaConstructor;
30 import net.percederberg.grammatica.code.java.JavaFile;
31 import net.percederberg.grammatica.code.java.JavaImport;
32 import net.percederberg.grammatica.code.java.JavaMethod;
33 import net.percederberg.grammatica.code.java.JavaVariable;
34 import net.percederberg.grammatica.parser.ProductionPattern;
35 import net.percederberg.grammatica.parser.ProductionPatternAlternative;
36 import net.percederberg.grammatica.parser.ProductionPatternElement;
37
38 /**
39  * The Java parser file generator. This class encapsulates all the
40  * Java code necessary for creating a parser.
41  *
42  * @author Per Cederberg, <per at percederberg dot net>
43  * @version 1.0
44  */

45 class JavaParserFile {
46
47     /**
48      * The class comment.
49      */

50     private static final String JavaDoc TYPE_COMMENT =
51         "A token stream parser.";
52
53     /**
54      * The production constant comment.
55      */

56     private static final String JavaDoc PRODUCTION_COMMENT =
57         "A generated production node identity constant.";
58
59     /**
60      * The first constructor comment.
61      */

62     private static final String JavaDoc CONSTRUCTOR1_COMMENT =
63         "Creates a new parser.\n\n" +
64         "@param in the input stream to read from\n\n" +
65         "@throws ParserCreationException if the parser couldn't be\n" +
66         " initialized correctly";
67
68     /**
69      * The second constructor comment.
70      */

71     private static final String JavaDoc CONSTRUCTOR2_COMMENT =
72         "Creates a new parser.\n\n" +
73         "@param in the input stream to read from\n" +
74         "@param analyzer the analyzer to use while parsing\n\n" +
75         "@throws ParserCreationException if the parser couldn't be\n" +
76         " initialized correctly";
77
78     /**
79      * The init method comment.
80      */

81     private static final String JavaDoc INIT_METHOD_COMMENT =
82         "Initializes the parser by creating all the production patterns.\n\n" +
83         "@throws ParserCreationException if the parser couldn't be\n" +
84         " initialized correctly";
85
86     /**
87      * The Java parser generator.
88      */

89     private JavaParserGenerator gen;
90
91     /**
92      * The tokenizer file generator.
93      */

94     private JavaTokenizerFile tokenizer;
95
96     /**
97      * The Java file to write.
98      */

99     private JavaFile file;
100
101     /**
102      * The Java class to write.
103      */

104     private JavaClass cls;
105
106     /**
107      * The Java class initializer method.
108      */

109     private JavaMethod initMethod;
110
111     /**
112      * A map with the production constants in this class. This map
113      * is indexed with the pattern id and contains the production
114      * constant name.
115      */

116     private HashMap JavaDoc constantNames = new HashMap JavaDoc();
117
118     /**
119      * The first available constant id number.
120      */

121     private int constantId = 1;
122
123     /**
124      * Creates a new parser file.
125      *
126      * @param gen the parser generator to use
127      * @param tokenizer the tokenizer file generator
128      */

129     public JavaParserFile(JavaParserGenerator gen,
130                           JavaTokenizerFile tokenizer) {
131
132         int modifiers;
133
134         this.gen = gen;
135         this.tokenizer = tokenizer;
136         this.file = gen.createJavaFile();
137         if (gen.getPublicAccess()) {
138             modifiers = JavaClass.PUBLIC;
139         } else {
140             modifiers = JavaClass.PACKAGE_LOCAL;
141         }
142         this.cls = new JavaClass(modifiers,
143                                  gen.getBaseName() + "Parser",
144                                  "RecursiveDescentParser");
145         this.initMethod = new JavaMethod(JavaMethod.PRIVATE,
146                                          "createPatterns",
147                                          "",
148                                          "void");
149         initializeCode();
150     }
151
152     /**
153      * Initializes the source code objects.
154      */

155     private void initializeCode() {
156         JavaConstructor constr;
157         String JavaDoc str;
158
159         // Add imports
160
file.addImport(new JavaImport("java.io", "Reader"));
161         file.addImport(new JavaImport("net.percederberg.grammatica.parser",
162                                       "Analyzer"));
163         file.addImport(new JavaImport("net.percederberg.grammatica.parser",
164                                       "ParserCreationException"));
165         file.addImport(new JavaImport("net.percederberg.grammatica.parser",
166                                       "ProductionPattern"));
167         file.addImport(new JavaImport("net.percederberg.grammatica.parser",
168                                       "ProductionPatternAlternative"));
169         file.addImport(new JavaImport("net.percederberg.grammatica.parser",
170                                       "RecursiveDescentParser"));
171
172         // Add class
173
file.addClass(cls);
174         str = TYPE_COMMENT;
175         if (gen.getClassComment() != null) {
176             str += "\n\n" + gen.getClassComment();
177         }
178         cls.addComment(new JavaComment(str));
179
180         // Add file comment
181
str = file.toString() + "\n\n" + gen.getFileComment();
182         file.addComment(new JavaComment(JavaComment.BLOCK, str));
183
184         // Add constructor
185
constr = new JavaConstructor("Reader in");
186         cls.addConstructor(constr);
187         constr.addComment(new JavaComment(CONSTRUCTOR1_COMMENT));
188         constr.addThrows("ParserCreationException");
189         constr.addCode("super(" + tokenizer.getConstructorCall("in") + ");");
190         constr.addCode("createPatterns();");
191
192         // Add constructor
193
constr = new JavaConstructor("Reader in, Analyzer analyzer");
194         cls.addConstructor(constr);
195         constr.addComment(new JavaComment(CONSTRUCTOR2_COMMENT));
196         constr.addThrows("ParserCreationException");
197         constr.addCode("super(" + tokenizer.getConstructorCall("in") +
198                        ", analyzer);");
199         constr.addCode("createPatterns();");
200
201         // Add init method
202
cls.addMethod(initMethod);
203         initMethod.addComment(new JavaComment(INIT_METHOD_COMMENT));
204         initMethod.addThrows("ParserCreationException");
205         initMethod.addCode("ProductionPattern pattern;");
206         initMethod.addCode("ProductionPatternAlternative alt;");
207     }
208
209     /**
210      * Adds a production constant definition to this file.
211      *
212      * @param pattern the production pattern
213      */

214     public void addProductionConstant(ProductionPattern pattern) {
215         String JavaDoc constant;
216         JavaVariable var;
217         int modifiers;
218
219         if (pattern.isSynthetic()) {
220             constant = "SUBPRODUCTION_" + constantId;
221             modifiers = JavaVariable.PRIVATE + JavaVariable.STATIC +
222                         JavaVariable.FINAL;
223             var = new JavaVariable(modifiers,
224                                    "int",
225                                    constant,
226                                    String.valueOf(constantId + 3000));
227             var.addComment(new JavaComment(PRODUCTION_COMMENT));
228             cls.addVariable(var);
229             constantNames.put(new Integer JavaDoc(pattern.getId()), constant);
230             constantId++;
231         }
232     }
233
234     /**
235      * Adds a production pattern definition to this file.
236      *
237      * @param pattern the production pattern
238      * @param constants the constants file generator
239      */

240     public void addProduction(ProductionPattern pattern,
241                               JavaConstantsFile constants) {
242         StringBuffer JavaDoc code;
243         String JavaDoc str;
244
245         // Create new pattern
246
code = new StringBuffer JavaDoc();
247         code.append("pattern = new ProductionPattern(");
248         code.append(getConstant(constants, pattern.getId()));
249         code.append(",\n");
250         code.append(" \"");
251         if (pattern.isSynthetic()) {
252             str = getConstant(constants, pattern.getId());
253             code.append(gen.getCodeStyle().getMixedCase(str, true));
254         } else {
255             code.append(pattern.getName());
256         }
257         code.append("\");");
258         initMethod.addCode("");
259         initMethod.addCode(code.toString());
260
261         // Set syntetic flag
262
if (pattern.isSynthetic()) {
263             initMethod.addCode("pattern.setSynthetic(true);");
264         }
265
266         // Create pattern rules
267
for (int i = 0; i < pattern.getAlternativeCount(); i++) {
268             addProductionAlternative(pattern.getAlternative(i),
269                                      constants);
270         }
271
272         // Add pattern to parser
273
initMethod.addCode("addPattern(pattern);");
274     }
275
276     /**
277      * Adds a production pattern alternative definition to the init
278      * method.
279      *
280      * @param alt the production pattern alternative
281      * @param constants the constants file generator
282      */

283     private void addProductionAlternative(ProductionPatternAlternative alt,
284                                           JavaConstantsFile constants) {
285
286         ProductionPatternElement elem;
287         StringBuffer JavaDoc code;
288
289         initMethod.addCode("alt = new ProductionPatternAlternative();");
290         for (int i = 0; i < alt.getElementCount(); i++) {
291             elem = alt.getElement(i);
292             code = new StringBuffer JavaDoc();
293             code.append("alt.");
294             if (elem.isToken()) {
295                 code.append("addToken(");
296             } else {
297                 code.append("addProduction(");
298             }
299             code.append(getConstant(constants, elem.getId()));
300             code.append(", ");
301             code.append(elem.getMinCount());
302             code.append(", ");
303             if (elem.getMaxCount() == Integer.MAX_VALUE) {
304                 code.append("-1");
305             } else {
306                 code.append(elem.getMaxCount());
307             }
308             code.append(");");
309             initMethod.addCode(code.toString());
310         }
311         initMethod.addCode("pattern.addAlternative(alt);");
312     }
313
314     /**
315      * Returns the constant name for a specified pattern or token id.
316      *
317      * @param constants the constants file
318      * @param id the pattern id
319      *
320      * @return the constant name to use
321      */

322     private String JavaDoc getConstant(JavaConstantsFile constants, int id) {
323         Integer JavaDoc value = new Integer JavaDoc(id);
324
325         if (constantNames.containsKey(value)) {
326             return (String JavaDoc) constantNames.get(value);
327         } else {
328             return constants.getConstant(id);
329         }
330     }
331
332     /**
333      * Writes the file source code.
334      *
335      * @throws IOException if the output file couldn't be created
336      * correctly
337      */

338     public void writeCode() throws IOException JavaDoc {
339         file.writeCode(gen.getCodeStyle());
340     }
341 }
342
Popular Tags