KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > ppg > spec > PPGSpec


1 package ppg.spec;
2
3 import java.io.*;
4 import java.util.*;
5 import ppg.*;
6 import ppg.atoms.*;
7 import ppg.cmds.*;
8 import ppg.code.*;
9 import ppg.lex.*;
10 import ppg.parse.*;
11 import ppg.util.*;
12
13 public class PPGSpec extends Spec
14 {
15     private String JavaDoc include;
16     private Vector commands, code;
17     private Spec parent;
18     private Vector startSyms;
19     
20     /**
21      * PPG spec
22      *
23     public PPGSpec (String incFile, String pkg, Vector imp,
24                       Vector codeParts, Vector syms,
25                       Vector precedence, String startSym, Vector cmds)
26     {
27         super();
28         include = incFile;
29         packageName = pkg;
30         imports = imp;
31         code = codeParts;
32         symbols = syms;
33         prec = precedence;
34         start = startSym; startSyms = null;
35         commands = cmds;
36         parent = null;
37     }
38     */

39     
40     public PPGSpec (String JavaDoc incFile, String JavaDoc pkg, Vector imp,
41                       Vector codeParts, Vector syms,
42                       Vector precedence, Vector startList, Vector cmds)
43     {
44         super();
45         include = incFile;
46         packageName = pkg;
47         imports = imp;
48         code = codeParts;
49         symbols = syms;
50         prec = precedence;
51         startSyms = startList;
52         commands = cmds;
53         parent = null;
54     }
55     
56     public boolean isMultiStartSymbol() {
57         return (startSyms.size() > 1);
58     }
59     
60     /*
61         Token curr_sym;
62         
63         // for each [start_sym, method, token] create code:
64         method () {
65             curr_sym = token;
66             parse();
67         }
68
69         // ^^^^ parse code ^^^^
70     
71         // in front of scanner, add code:
72         // return the "fake" symbol only once after it's set
73         if (curr_sym != null)
74             Token result = curr_sym;
75             curr_sym = null;
76             return result;
77         }
78         
79         // ^^^^ scan code ^^^^
80     
81         // code added to grammar:
82         start with new_unique_start_symbol;
83         
84         new_unique_start_symbol ::=
85             token_1 start_sym_1:s {: RESULT = s; :}
86         | token_2 start_sym_2:s {: RESULT = s; :}
87         | ...
88         ;
89     
90         // ^^^^ grammar ^^^^
91     */

92
93     public void patchMultiStartSymbols (CUPSpec cupSpec) {
94         if (!isMultiStartSymbol()) {
95             cupSpec.setStart((String JavaDoc) startSyms.elementAt(0));
96             return;
97         }
98
99         // Parse Code
100
String JavaDoc parseCode = "";
101         // should it be dynamically generated?
102
String JavaDoc currSymbolName = "ppg_curr_sym";
103         parseCode += "Symbol " + currSymbolName + ";\n\n";
104         
105         // Generate token names
106
Vector tokens = new Vector();
107         for (int i=0; i < startSyms.size(); i+=2) {
108             tokens.addElement(new String JavaDoc("JLGEN_TOKEN_"+String.valueOf(i/2)));
109         }
110         
111         String JavaDoc startSym, method, token;
112         for (int i=0; i < startSyms.size(); i += 2) {
113             startSym = (String JavaDoc) startSyms.elementAt(i);
114             method = (String JavaDoc) startSyms.elementAt(i+1);
115             token = (String JavaDoc) tokens.elementAt(i/2); //startSyms.elementAt(i+2);
116
parseCode += "public Symbol "+ method + " () throws Exception {\n"+
117                          "\t"+currSymbolName+" = "+"new Symbol("+
118                          PPG.SYMBOL_CLASS_NAME+"."+token+")"+";\n"+"\t"+
119                          "return parse();\n}\n\n";
120         }
121         // append parseCode to the actual parse code
122
cupSpec.parserCode.append(parseCode);
123
124         /************************************/
125
126         // Scan code
127
String JavaDoc scanCodeAdd = "\n// scan code generated by PPG\n"+
128                              "if (" + currSymbolName + "!= null) {\n"+
129                              "\tSymbol result = "+currSymbolName+";\n"+
130                              "\t"+currSymbolName+" = null"+";\n"+
131                              "\treturn result;\n"+
132                              "}\n"+
133                              "// end scan code generated by PPG\n\n";
134         // prepend scanCode before the actual scan code
135
if (cupSpec.scanCode != null)
136             cupSpec.scanCode.prepend(scanCodeAdd);
137         else
138             cupSpec.scanCode = new ScanCode(scanCodeAdd);
139         
140         /************************************/
141
142         // create a new start symbol
143
String JavaDoc newStartSym = "multi_start_symbool";
144                 
145         // set start symbol
146
cupSpec.setStart(newStartSym);
147         Nonterminal startNT = new Nonterminal(newStartSym, null);
148         Vector newSymbols = new Vector();
149         newSymbols.addElement(newStartSym);
150         
151         // add start symbol to the grammar
152
SymbolList sl = new SymbolList(SymbolList.NONTERMINAL, null, newSymbols);
153         Vector addedSymbols = new Vector(); addedSymbols.addElement(sl);
154         cupSpec.addSymbols(addedSymbols);
155         
156         // add token declaration to the grammar
157
SymbolList tokenList = new SymbolList(SymbolList.TERMINAL, "Symbol", tokens);
158         Vector addedTokens = new Vector(); addedTokens.addElement(tokenList);
159         cupSpec.addSymbols(addedTokens);
160         
161         Vector rhs = new Vector();
162         
163         //String grammarPatch = newStartSym + " ::=\n";
164
Vector rhsPart;
165         for (int i=0; i < startSyms.size(); i += 2) {
166             rhsPart = new Vector();
167             startSym = (String JavaDoc) startSyms.elementAt(i);
168             token = (String JavaDoc) tokens.elementAt(i/2); //startSyms.elementAt(i+2);
169
//if (i > 0) grammarPatch += "|";
170
//grammarPatch += "\t"+token+" "+startSym+":s {: RESULT = s; :}\n";
171
// add new symbols into vector
172
rhsPart.addElement(new Nonterminal(token, null));
173             rhsPart.addElement(new Nonterminal(startSym, "s"));
174             rhsPart.addElement(new SemanticAction("RESULT = s;"));
175             rhs.addElement(rhsPart);
176         }
177         //grammarPatch += ";\n";
178

179         // patch the grammar
180
Production p = new Production(startNT, rhs);
181         cupSpec.addProductions(p);
182     }
183     
184
185         /**
186          * Parse the chain of inheritance via include files
187          */

188         public void parseChain (String JavaDoc basePath) {
189             InputStream is;
190             File file = null;
191             String JavaDoc simpleName = include;
192             try {
193                 // first look on the classpath.
194
is = ClassLoader.getSystemResourceAsStream(include);
195                 if (is != null) {
196                     PPG.DEBUG("found " + include + " as a resource");
197                 }
198                 else {
199                     // nothing was found on the class path. Try the basePath...
200
String JavaDoc fullPath = ((basePath == "") ?
201                                        "" : basePath + System.getProperty("file.separator")) +
202                                       include;
203                     PPG.DEBUG("looking for " + fullPath + " as a file");
204                     file = new File(fullPath);
205                     is = new FileInputStream(file);
206                     simpleName = file.getName();
207                 }
208
209                 Lexer lex = new Lexer(is, simpleName);
210                 Parser parser = new Parser(simpleName, lex);
211
212                 PPG.DEBUG("parsing "+simpleName);
213                 parser.parse();
214                 parent = (Spec)parser.getProgramNode();
215                 is.close();
216
217             } catch (FileNotFoundException e) {
218                 System.out.println(PPG.HEADER + simpleName + " not found.");
219                 System.exit(1);
220             } catch (Exception JavaDoc e) {
221                 System.out.println(PPG.HEADER+"Exception: "+e.getMessage());
222                 System.exit(1);
223             }
224             parent.setChild(this);
225
226             String JavaDoc parentDir = null;
227             if (file != null) {
228                 parentDir = file.getParent();
229             }
230             parent.parseChain(parentDir == null ? "" : parentDir);
231         }
232
233     public CUPSpec coalesce() throws PPGError {
234         // parent cannot be null by definition
235
CUPSpec combined = parent.coalesce();
236         
237         // work with a copy so we have the unmodified original to refer to
238
CUPSpec newSpec = (CUPSpec) combined.clone();
239         
240         // override package name
241
newSpec.setPkgName(packageName);
242         
243         // add imported classes
244
newSpec.addImports(imports);
245         
246         /* override precedence, using these rules:
247          *
248          * precedence list null: delete precedence list of parent
249          * precedence list of length 0: leave precedence of parent
250          * precedence list of length >0: override with current list
251          */

252         //TODO: test precedence inheritance/overriding/ignoring
253
if (prec == null) {
254             newSpec.prec.removeAllElements();
255         } else if (prec.size() == 0) {
256             // do nothing to parent's precedence list
257
} else {
258             // override with current
259
newSpec.prec.removeAllElements();
260             newSpec.prec.addAll(prec);
261         }
262         
263         // override action/parser/init/scan code
264
newSpec.replaceCode(code);
265         
266         // add in (non)terminals
267
newSpec.addSymbols(symbols);
268         
269         // override start symbol(s), patch grammar (if multi-start-symbol)
270
if (child == null)
271             patchMultiStartSymbols(newSpec);
272         
273         // combine this spec with the rest
274
// of the chain and return the result
275
processTransferL(combined, newSpec);
276         processDrop(combined, newSpec);
277         processOverride(combined, newSpec);
278         processTransferR(combined, newSpec);
279         processExtend(combined, newSpec);
280         processNew(combined, newSpec);
281         
282         // clean the spec, remove nonterminals with no productions
283
newSpec.removeEmptyProductions();
284         
285         return newSpec;
286     }
287     
288     private void processDrop (CUPSpec combined, CUPSpec newSpec) throws PPGError {
289         // DROP
290
Command cmd;
291         DropCmd drop;
292         for (int i=0; i < commands.size(); i++) {
293             cmd = (Command) commands.elementAt(i);
294             if (cmd instanceof DropCmd) {
295                 drop = (DropCmd) cmd;
296                 if (drop.isProdDrop()) {
297                     // remove all productions that have NT as lhs
298
newSpec.dropProductions(drop.getProduction());
299                 } else { /* symbol Drop */
300                     Vector symbols = drop.getSymbols();
301                     String JavaDoc sym;
302                     for (int j=0; j < symbols.size(); j++) {
303                         sym = (String JavaDoc) symbols.elementAt(j);
304                         // remove nonterminals from list of symbols
305
newSpec.dropSymbol(sym);
306                         // remove all productions that have NT as lhs, if possible
307
newSpec.dropAllProductions(sym);
308                     }
309                 }
310             }
311         }
312     }
313
314     private void processOverride (CUPSpec combined, CUPSpec newSpec) {
315         // OVERRIDE
316
Command cmd;
317         OverrideCmd override;
318         for (int i=0; i < commands.size(); i++) {
319             cmd = (Command) commands.elementAt(i);
320             if (cmd instanceof OverrideCmd) {
321                 override = (OverrideCmd) cmd;
322                 newSpec.dropProductions(override.getLHS());
323                 newSpec.addProductions(override.getProduction());
324             }
325         }
326     }
327     
328     private void processExtend (CUPSpec combined, CUPSpec newSpec) {
329         // EXTEND
330
Command cmd;
331         ExtendCmd extend;
332         for (int i=0; i < commands.size(); i++) {
333             cmd = (Command) commands.elementAt(i);
334             if (cmd instanceof ExtendCmd) {
335                 extend = (ExtendCmd) cmd;
336                 newSpec.addProductions(extend.getProduction());
337             }
338         }
339     }
340     
341     private void processTransferL (CUPSpec combined, CUPSpec newSpec) {
342         // TRANSFER_L
343
Command cmd;
344         TransferCmd transfer;
345         Production prod;
346         Nonterminal source;
347         Vector prodList;
348         for (int i=0; i < commands.size(); i++) {
349             cmd = (Command) commands.elementAt(i);
350             if (cmd instanceof TransferCmd) {
351                 transfer = (TransferCmd) cmd;
352                 source = transfer.getSource();
353                 prodList = transfer.getTransferList();
354                 
355                 // there must be at least one production by the grammar definition
356
prod = (Production) prodList.elementAt(0);
357                 prod = (Production) prod.clone();
358                 for (int j=1; j < prodList.size(); j++) {
359                     Production prodNew = (Production) prodList.elementAt(j);
360                     prod.union( (Production) prodNew.clone() );
361                     //prod.union( (Production) prodList.elementAt(j) );
362
}
363                 
364                 prod.setLHS(transfer.getSource());
365                 newSpec.dropProductions(prod);
366             }
367         }
368     }
369     
370     private void processTransferR (CUPSpec combined, CUPSpec newSpec) {
371         // TRANSFER_R
372
Command cmd;
373         TransferCmd transfer;
374         Production prod, prodTransfer;
375         Vector prodList;
376         Nonterminal target;
377         for (int i=0; i < commands.size(); i++) {
378             cmd = (Command) commands.elementAt(i);
379             if (cmd instanceof TransferCmd) {
380                 transfer = (TransferCmd) cmd;
381                 prodList = transfer.getTransferList();
382                 for (int j=0; j < prodList.size(); j++) {
383                     prod = (Production) prodList.elementAt(j);
384                     target = prod.getLHS();
385                     // make sure we get the productions from the source!
386
prod.setLHS(transfer.getSource());
387                     prodTransfer = combined.findProduction(prod);
388                     // but set the LHS back to the actual target
389
// so it is added to the right nonterminal
390
prodTransfer.setLHS(target);
391                     newSpec.addProductions(prodTransfer);
392                     //newSpec.addProductions(prod);
393
}
394             }
395         }
396     }
397     
398     private void processNew (CUPSpec combined, CUPSpec newSpec) {
399         // NEW PRODUCTIONS
400
NewProdCmd newProd;
401         Command cmd;
402         for (int i=0; i < commands.size(); i++) {
403             cmd = (Command) commands.elementAt(i);
404             if (cmd instanceof NewProdCmd) {
405                 newProd = (NewProdCmd) cmd;
406                 newSpec.addProductions(newProd.getProduction());
407             }
408         }
409     }
410     
411     /**
412      * Write out contents to a CodeWriter
413      */

414     public void unparse (CodeWriter cw) {
415         cw.begin(0);
416         if (include != null) {
417             cw.write(include+"\n");
418         }
419         if (commands != null) {
420             for (int i=0; i < commands.size(); i++) {
421                 ((Command)commands.elementAt(i)).unparse(cw);
422             }
423         }
424         cw.end();
425     }
426 }
427
Popular Tags