KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > fri > patterns > interpreter > parsergenerator > parsertables > AbstractParserTables


1 package fri.patterns.interpreter.parsergenerator.parsertables;
2
3 import java.util.*;
4 import java.io.*;
5 import java.lang.reflect.*;
6 import fri.patterns.interpreter.parsergenerator.ParserTables;
7 import fri.patterns.interpreter.parsergenerator.Token;
8 import fri.patterns.interpreter.parsergenerator.syntax.*;
9
10 /**
11     Base class for all parser tables. Default implementations.
12     <p>
13     Source generation method: <i>toSourceFile()</i>. Needed by <i>CompiledTables</i>,
14     used for buffering compiled table classes at runtime.
15     <p>
16     Dump methods to print human readable table contents. Dumping does not work on
17     buffered table objects (needs scratch build by constructor).
18
19     @author (c) 2000, 2001, 2002 Fritz Ritzberger
20 */

21
22 public abstract class AbstractParserTables implements
23     ParserTables,
24     Serializable
25 {
26     /** The raw syntax to apply on parsing. */
27     protected Syntax syntax;
28
29     /** The GOTO-table with all possible follow states. As much lines as states and columns as terminals and nonterminals are present. */
30     protected List gotoTable;
31
32     /** The PARSE-ACTION table with SHIFT and REDUCE entries. As much lines as states and as much columns as terminals are present. */
33     protected List parseTable;
34
35     /** Non-terminals and terminals, without EPSILON, with START-symbol: column header of GOTO-table. */
36     protected transient List symbols = new ArrayList();
37
38     /** Terminals, with EPSILON: column header of PARSE-ACTION table. */
39     protected transient List terminals = new ArrayList();
40
41     /** Terminals, without EPSILON: tokens for the Lexer. */
42     protected List terminalsWithoutEpsilon = new ArrayList();
43
44     /** Non-terminals, with START-symbol. */
45     protected transient List nonterminals = new ArrayList();
46
47     /** Helper for the cell width of printed tables. Can be set manually if automatic result does not fit. */
48     public transient static int CELLWIDTH = 0;
49
50
51     /** Serializable constructor. */
52     protected AbstractParserTables() {
53     }
54     
55     /**
56         Implements ParserTables: returns the next state from GOTO-table.
57         @param currentState curent state
58         @param symbol current terminal or nonterminal
59         @return new state
60     */

61     public Integer JavaDoc getGotoState(Integer JavaDoc currentState, String JavaDoc symbol) {
62         Integer JavaDoc state = null;
63         Map map = (Map) gotoTable.get(currentState.intValue());
64         if (map != null)
65             state = (Integer JavaDoc) map.get(symbol);
66         return state == null ? ParserTables.ERROR : state;
67     }
68
69     /**
70         Implements ParserTables: returns the next action from PARSE-ACTION-table.
71         @param currentState curent state
72         @param symbol current terminal
73         @return new action
74     */

75     public Integer JavaDoc getParseAction(Integer JavaDoc currentState, String JavaDoc terminal) {
76         Integer JavaDoc action = null;
77         Map map = (Map) parseTable.get(currentState.intValue());
78         if (map != null)
79             action = (Integer JavaDoc) map.get(terminal);
80         return action == null ? ParserTables.ERROR : action;
81     }
82
83     /** Implements ParserTables: returns String List of terminals, without EPSILON. */
84     public List getTerminals() {
85         return terminalsWithoutEpsilon;
86     }
87     
88     /** Implements ParserTables: returns Syntax. */
89     public Syntax getSyntax() {
90         return syntax;
91     }
92
93     /** Implements ParserTables: Returns a Map of the expected tokens for current state, contained in keySet iterator. */
94     public Map getExpected(Integer JavaDoc state) {
95         return (Map) parseTable.get(state.intValue());
96     }
97
98     
99
100     /**
101         Factory to build precompiled parser tables, or construct them from scratch.
102         Used by <i>CompiledTables</i> and <i>SerializedTables</i>.
103         @param parserType LALRParserTables, SLRParserTables, LRParserTables class.
104         @param syntax can be null for precompiled tables, else the syntax to build.
105     */

106     public static AbstractParserTables construct(Class JavaDoc parserType, Syntax syntax)
107         throws Exception JavaDoc
108     {
109         Constructor constr;
110         if (syntax == null) { // load compiled table
111
constr = parserType.getConstructor(new Class JavaDoc [0]);
112             return (AbstractParserTables)constr.newInstance(new Object JavaDoc [0]);
113         }
114         else { // build tables from scratch
115
try { // if this fails
116
constr = parserType.getConstructor(new Class JavaDoc [] { syntax.getClass() });
117             }
118             catch (Exception JavaDoc e) { // try Object as parameter for Constructor
119
constr = parserType.getConstructor(new Class JavaDoc [] { Object JavaDoc.class });
120             }
121             return (AbstractParserTables)constr.newInstance(new Object JavaDoc [] { syntax });
122         }
123     }
124
125     
126
127
128     // dump methods, display rules and tables
129

130
131     /** Implements ParserTables: prints rules, FIRST/FOLLOW sets, syntax nodes (states), GOTO-table, PARSE-ACTION-table. */
132     public void dump(PrintStream out) {
133         dumpSyntax(out);
134         dumpTables(out);
135     }
136     
137     public void dumpTables(PrintStream out) {
138         dumpGoto(out);
139         dumpParseAction(out);
140     }
141     
142     public void dumpSyntax(PrintStream out) {
143         for (int i = 0; i < syntax.size(); i++)
144             out.println(dumpRule(syntax.getRule(i), i));
145         out.println();
146     }
147
148     protected String JavaDoc dumpRule(Rule rule, int i) {
149         StringBuffer JavaDoc sb = new StringBuffer JavaDoc("(Rule "+i+") "+rule.getNonterminal()+" : ");
150         for (int j = 0; j < rule.rightSize(); j++)
151             sb.append(rule.getRightSymbol(j)+" ");
152         return sb.toString();
153     }
154     
155     protected void dumpGoto(PrintStream out) {
156         if (symbols.size() > 0)
157             dumpTable("GOTO TABLE", symbols, gotoTable, out);
158     }
159     
160     protected void dumpParseAction(PrintStream out) {
161         if (terminals.size() > 0)
162             dumpTable("PARSE-ACTION TABLE", terminals, parseTable, out);
163     }
164     
165     
166     protected void dumpTable(String JavaDoc title, List head, List table, PrintStream out) {
167         out.println(title);
168         out.println(dummy(title.length(), "="));
169         
170         // if no CELLWIDTH is set, estimate maximum cell width
171
if (CELLWIDTH <= 0) {
172             for (Iterator it = head.iterator(); it.hasNext(); ) {
173                 String JavaDoc s = (String JavaDoc) it.next();
174                 if (s.length() > CELLWIDTH && it.hasNext()) // not last
175
CELLWIDTH = s.length() + 1;
176             }
177         }
178         
179         // print table header
180
dumpCell(" | ", CELLWIDTH, false, out);
181         for (Iterator it = head.iterator(); it.hasNext(); ) {
182             String JavaDoc s = (String JavaDoc) it.next();
183             if (Token.isEpsilon(s))
184                 s = "<EOF>";
185             dumpCell(s, CELLWIDTH, ! it.hasNext(), out);
186         }
187         
188         out.println();
189         out.println(dummy(CELLWIDTH * (head.size() + 1), "_"));
190         
191         int i = 0;
192         for (Iterator it = table.iterator(); it.hasNext(); i++) {
193             Map h = (Map) it.next();
194
195             dumpCell(Integer.toString(i)+" | ", CELLWIDTH, false, out);
196             for (Iterator it2 = head.iterator(); it2.hasNext(); ) {
197                 String JavaDoc symbol = (String JavaDoc) it2.next();
198
199                 Integer JavaDoc intg = h != null ? (Integer JavaDoc) h.get(symbol) : null;
200                 String JavaDoc digit = intg == null ? "-" : intg.equals(ParserTables.SHIFT) ? "SH" : intg.equals(ParserTables.ACCEPT) ? "AC" : intg.toString();
201
202                 dumpCell(digit, CELLWIDTH, ! it2.hasNext(), out);
203             }
204             out.println();
205         }
206         
207         out.println();
208     }
209     
210     private void dumpCell(String JavaDoc digit, int width, boolean isLast, PrintStream out) {
211         StringBuffer JavaDoc tab = new StringBuffer JavaDoc(" ");
212         for (int i = 0; i < width - 1 - digit.length(); i++)
213             tab.append(' ');
214             
215         String JavaDoc s = tab+digit;
216         if (!isLast && s.length() > width && width > 2)
217             s = s.substring(0, width);
218             
219         out.print(s);
220     }
221
222     private String JavaDoc dummy(int width, String JavaDoc ch) {
223         StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
224         for (int i = 0; i < width; i++)
225             sb.append(ch);
226         return sb.toString();
227     }
228
229
230     /** Reports count of rules, ternminals and nonterminals. */
231     public void report(PrintStream out) {
232         out.println("rules: "+syntax.size());
233         out.println("terminals: "+terminals.size());
234         out.println("nonterminals: "+nonterminals.size());
235     }
236
237
238
239     
240     // Java source generation methods
241

242     
243     private transient Writer f = null;
244
245     private void fwrite(String JavaDoc line)
246         throws IOException
247     {
248         f.write(line, 0, line.length());
249     }
250     
251     /**
252         Generates a compilable source file "parserClassName.java".
253         If the class name contains package path, the file will be generated
254         within the corresponding directory, else within working directory.
255         @param parserClassName name of class to generate:
256                 "Java" will generate "Java.java" in current directory,
257                 "my.pkg.PT" will generate "my/pkg/PT.java" in current directory.
258         @return fileName if File could be written, else null.
259     */

260     public String JavaDoc toSourceFile(String JavaDoc parserClassName)
261         throws IOException
262     {
263         if (parserClassName.endsWith("ParserTables") == false)
264             parserClassName = parserClassName+"ParserTables";
265             
266         String JavaDoc fileName = parserClassName.replace('.', File.separatorChar)+".java";
267         System.err.println("Writing Java Source to "+fileName);
268
269         File file = new File(fileName);
270         String JavaDoc path = file.getParent();
271         if (path != null && new File(path).exists() == false)
272             new File(path).mkdirs();
273
274         // begin file writing
275
f = new BufferedWriter(new FileWriter(file));
276         
277         // header of Java source
278
if (path != null) {
279             if (path.endsWith(File.separator))
280                 path = path.substring(0, path.length() - 1);
281
282             fwrite("package "+path.replace(File.separatorChar, '.')+";\n\n");
283             
284             parserClassName = parserClassName.substring(parserClassName.lastIndexOf(".") + 1);
285         }
286
287         fwrite("import java.util.*;\n");
288         fwrite("import fri.patterns.interpreter.parsergenerator.syntax.*;\n");
289         fwrite("import fri.patterns.interpreter.parsergenerator.parsertables.AbstractParserTables;\n\n");
290         fwrite("/**\n");
291         fwrite(" * DO NOT EDIT - ParserTables generated\n");
292         fwrite(" * at "+new Date()+"\n");
293         fwrite(" * by fri.patterns.interpreter.parsergenerator.parsertables.AbstractParserTables.\n");
294         fwrite(" */\n\n");
295         fwrite("public final class "+parserClassName+" extends AbstractParserTables\n");
296         fwrite("{\n");
297
298         // begin constructor
299
fwrite(" public "+parserClassName+"() {\n");
300
301         fwrite(" syntax = new Syntax("+syntax.size()+");\n");
302         fwrite(" Rule s;\n");
303         fwrite("\n");
304         for (int i = 0; i < syntax.size(); i++) {
305             Rule s = syntax.getRule(i);
306             fwrite(" syntax.addRule(s = new Rule(\""+s.getNonterminal()+"\", "+s.rightSize()+")); // rule "+i+"\n");
307             for (int j = 0; j < s.rightSize(); j++)
308                 fwrite(" s.addRightSymbol(\""+sub(s.getRightSymbol(j))+"\");\n");
309             fwrite("\n");
310         }
311         fwrite("\n");
312
313         // call methods to build tables
314
fwrite(" loadGotoTable();\n");
315         fwrite(" loadParseActionTable();\n");
316         fwrite("\n");
317
318         // load terminal list that gets passed to Lexer
319
fwrite(" terminalsWithoutEpsilon = new ArrayList("+terminalsWithoutEpsilon.size()+");\n");
320         for (int i = 0; i < terminalsWithoutEpsilon.size(); i++)
321             fwrite(" terminalsWithoutEpsilon.add(\""+sub(terminalsWithoutEpsilon.get(i))+"\");\n");
322
323         fwrite(" }\n");
324         // end constructor
325

326
327         // method to load Goto table
328
fwrite(" private void loadGotoTable() {\n");
329         fwrite(" gotoTable = new ArrayList("+gotoTable.size()+");\n");
330         fwrite("\n");
331         for (int i = 0; i < gotoTable.size(); i++) {
332             Map g = (Map) gotoTable.get(i);
333             if (g == null)
334                 fwrite(" gotoTable.add(null); // state "+i);
335             else
336                 fwrite(" loadGoto_"+i+"();");
337             fwrite("\n");
338         }
339         fwrite(" }\n");
340
341         // every goto state is a method as Java can not load methods bigger than 65563 Bytes
342
for (int i = 0; i < gotoTable.size(); i++) {
343             Map g = (Map) gotoTable.get(i);
344             if (g != null) {
345                 fwrite(" private void loadGoto_"+i+"() {\n");
346                 fwrite(" Hashtable g = new Hashtable("+g.size()+", 1);\n");
347                 fwrite(" gotoTable.add(g);\n");
348                 for (Iterator it = g.keySet().iterator(); it.hasNext(); ) {
349                     String JavaDoc key = (String JavaDoc) it.next();
350                     Object JavaDoc value = g.get(key);
351                     fwrite(" g.put(\""+sub(key)+"\", new Integer("+value+"));\n");
352                 }
353                 fwrite(" }\n");
354             }
355         }
356
357         // method to load Parse-Action table
358
fwrite(" private void loadParseActionTable() {\n");
359         fwrite(" parseTable = new ArrayList("+parseTable.size()+");\n");
360         fwrite("\n");
361         for (int i = 0; i < parseTable.size(); i++) {
362             Map p = (Map) parseTable.get(i);
363             if (p == null)
364                 fwrite(" parseTable.add(null); // state "+i);
365             else
366                 fwrite(" loadParseAction_"+i+"();");
367             fwrite("\n");
368         }
369         fwrite(" }\n");
370
371         // every action state is a method as Java can not load methods bigger than 65563 Bytes
372
for (int i = 0; i < parseTable.size(); i++) {
373             Map p = (Map) parseTable.get(i);
374             if (p != null) {
375                 fwrite(" private void loadParseAction_"+i+"() {\n");
376                 fwrite(" Hashtable p = new Hashtable("+p.size()+", 1);\n");
377                 fwrite(" parseTable.add(p);\n");
378                 for (Iterator it = p.keySet().iterator(); it.hasNext(); ) {
379                     String JavaDoc key = (String JavaDoc) it.next();
380                     Object JavaDoc value = p.get(key);
381                     fwrite(" p.put(\""+sub(key)+"\", new Integer("+value+"));\n");
382                 }
383                 fwrite(" }\n");
384             }
385         }
386
387         fwrite("}");
388
389         // end file writing
390
f.flush();
391         f.close();
392         f = null;
393         
394         return fileName;
395     }
396
397
398     private String JavaDoc sub(Object JavaDoc o) {
399         return SyntaxUtil.maskQuoteAndBackslash((String JavaDoc) o);
400     }
401     
402 }
Popular Tags