KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2  * CSharpParserFile.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.csharp.CSharpClass;
28 import net.percederberg.grammatica.code.csharp.CSharpComment;
29 import net.percederberg.grammatica.code.csharp.CSharpConstructor;
30 import net.percederberg.grammatica.code.csharp.CSharpEnumeration;
31 import net.percederberg.grammatica.code.csharp.CSharpFile;
32 import net.percederberg.grammatica.code.csharp.CSharpMethod;
33 import net.percederberg.grammatica.code.csharp.CSharpNamespace;
34 import net.percederberg.grammatica.code.csharp.CSharpUsing;
35 import net.percederberg.grammatica.parser.ProductionPattern;
36 import net.percederberg.grammatica.parser.ProductionPatternAlternative;
37 import net.percederberg.grammatica.parser.ProductionPatternElement;
38
39 /**
40  * The C# parser file generator. This class encapsulates all the
41  * C# code necessary for creating a parser.
42  *
43  * @author Per Cederberg, <per at percederberg dot net>
44  * @version 1.5
45  */

46 class CSharpParserFile {
47
48     /**
49      * The type comment.
50      */

51     private static final String JavaDoc TYPE_COMMENT =
52         "<remarks>A token stream parser.</remarks>";
53
54     /**
55      * The production enumeration comment.
56      */

57     private static final String JavaDoc ENUM_COMMENT =
58         "<summary>An enumeration with the generated production node\n" +
59         "identity constants.</summary>";
60
61     /**
62      * The first constructor comment.
63      */

64     private static final String JavaDoc CONSTRUCTOR1_COMMENT =
65         "<summary>Creates a new parser.</summary>\n\n" +
66         "<param name='input'>the input stream to read from</param>\n\n" +
67         "<exception cref='ParserCreationException'>if the parser\n" +
68         "couldn't be initialized correctly</exception>";
69
70     /**
71      * The second constructor comment.
72      */

73     private static final String JavaDoc CONSTRUCTOR2_COMMENT =
74         "<summary>Creates a new parser.</summary>\n\n" +
75         "<param name='input'>the input stream to read from</param>\n\n" +
76         "<param name='analyzer'>the analyzer to parse with</param>\n\n" +
77         "<exception cref='ParserCreationException'>if the parser\n" +
78         "couldn't be initialized correctly</exception>";
79
80     /**
81      * The init method comment.
82      */

83     private static final String JavaDoc INIT_METHOD_COMMENT =
84         "<summary>Initializes the parser by creating all the production\n" +
85         "patterns.</summary>\n\n" +
86         "<exception cref='ParserCreationException'>if the parser\n" +
87         "couldn't be initialized correctly</exception>";
88
89     /**
90      * The parser generator.
91      */

92     private CSharpParserGenerator gen;
93
94     /**
95      * The tokenizer file generator.
96      */

97     private CSharpTokenizerFile tokenizer;
98
99     /**
100      * The file to write.
101      */

102     private CSharpFile file;
103
104     /**
105      * The class to write.
106      */

107     private CSharpClass cls;
108
109     /**
110      * The syntetic contants enumeration.
111      */

112     private CSharpEnumeration enm;
113
114     /**
115      * The class initializer method.
116      */

117     private CSharpMethod initMethod;
118
119     /**
120      * A map with the production constants in this class. This map
121      * is indexed with the pattern id and contains the production
122      * constant name.
123      */

124     private HashMap JavaDoc constantNames = new HashMap JavaDoc();
125
126     /**
127      * The first available constant id number.
128      */

129     private int constantId = 1;
130
131     /**
132      * Creates a new parser file.
133      *
134      * @param gen the parser generator to use
135      * @param tokenizer the tokenizer file generator
136      */

137     public CSharpParserFile(CSharpParserGenerator gen,
138                             CSharpTokenizerFile tokenizer) {
139
140         String JavaDoc name = gen.getBaseName() + "Parser";
141         int modifiers;
142
143         this.gen = gen;
144         this.tokenizer = tokenizer;
145         this.file = new CSharpFile(gen.getBaseDir(), name);
146         if (gen.getPublicAccess()) {
147             modifiers = CSharpClass.PUBLIC;
148         } else {
149             modifiers = CSharpClass.INTERNAL;
150         }
151         this.cls = new CSharpClass(modifiers,
152                                    name,
153                                    "RecursiveDescentParser");
154         this.enm = new CSharpEnumeration(CSharpEnumeration.PRIVATE,
155                                           "SynteticPatterns");
156         this.initMethod = new CSharpMethod(CSharpMethod.PRIVATE,
157                                            "CreatePatterns",
158                                            "",
159                                            "void");
160         initializeCode();
161     }
162
163     /**
164      * Initializes the source code objects.
165      */

166     private void initializeCode() {
167         CSharpConstructor constr;
168         String JavaDoc str;
169
170         // Add using
171
file.addUsing(new CSharpUsing("System.IO"));
172         file.addUsing(new CSharpUsing("PerCederberg.Grammatica.Runtime"));
173
174         // Add namespace
175
if (gen.getNamespace() == null) {
176             file.addClass(cls);
177         } else {
178             CSharpNamespace n = new CSharpNamespace(gen.getNamespace());
179             n.addClass(cls);
180             file.addNamespace(n);
181         }
182
183         // Add file comment
184
str = file.toString() + "\n\n" + gen.getFileComment();
185         file.addComment(new CSharpComment(CSharpComment.BLOCK, str));
186
187         // Add type comment
188
cls.addComment(new CSharpComment(TYPE_COMMENT));
189
190         // Add enumeration
191
cls.addEnumeration(enm);
192         enm.addComment(new CSharpComment(ENUM_COMMENT));
193
194         // Add constructor
195
constr = new CSharpConstructor("TextReader input");
196         cls.addConstructor(constr);
197         constr.addComment(new CSharpComment(CONSTRUCTOR1_COMMENT));
198         constr.addInitializer("base(" +
199                               tokenizer.getConstructorCall("input") +
200                               ")");
201         constr.addCode("CreatePatterns();");
202
203         // Add constructor
204
constr = new CSharpConstructor("TextReader input, " +
205                                        "Analyzer analyzer");
206         cls.addConstructor(constr);
207         constr.addComment(new CSharpComment(CONSTRUCTOR2_COMMENT));
208         constr.addInitializer("base(" +
209                               tokenizer.getConstructorCall("input") +
210                               ", analyzer)");
211         constr.addCode("CreatePatterns();");
212
213         // Add init method
214
cls.addMethod(initMethod);
215         initMethod.addComment(new CSharpComment(INIT_METHOD_COMMENT));
216         initMethod.addCode("ProductionPattern pattern;");
217         initMethod.addCode("ProductionPatternAlternative alt;");
218     }
219
220     /**
221      * Adds a production constant definition to this file.
222      *
223      * @param pattern the production pattern
224      */

225     public void addProductionConstant(ProductionPattern pattern) {
226         String JavaDoc constant;
227
228         if (pattern.isSynthetic()) {
229             constant = "SUBPRODUCTION_" + constantId;
230             enm.addConstant(constant, String.valueOf(constantId + 3000));
231             constantNames.put(new Integer JavaDoc(pattern.getId()), constant);
232             constantId++;
233         }
234     }
235
236     /**
237      * Adds a production pattern definition to this file.
238      *
239      * @param pattern the production pattern
240      * @param constants the constants file generator
241      */

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

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

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

341     public void writeCode() throws IOException JavaDoc {
342         file.writeCode(gen.getCodeStyle());
343     }
344 }
345
Popular Tags