Source code: org/sablecc/sablecc/ResolveIds.java
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2 * This file is part of SableCC. *
3 * See the file "LICENSE" for copyright information and the *
4 * terms and conditions for copying, distribution and *
5 * modification of SableCC. *
6 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
7
8 package org.sablecc.sablecc;
9
10 import org.sablecc.sablecc.analysis.*;
11 import org.sablecc.sablecc.node.*;
12 import java.util.*;
13 import com.sun.java.util.collections.*;
14 import java.io.*;
15
16 public class ResolveIds extends DepthFirstAdapter
17 {
18 public final Map helpers = new TypedTreeMap(
19 StringComparator.instance,
20 StringCast.instance,
21 NodeCast.instance);
22 public final Map states = new TypedTreeMap(
23 StringComparator.instance,
24 StringCast.instance,
25 NodeCast.instance);
26 public final Map tokens = new TypedTreeMap(
27 StringComparator.instance,
28 StringCast.instance,
29 NodeCast.instance);
30 public final Map ignTokens = new TypedTreeMap(
31 StringComparator.instance,
32 StringCast.instance,
33 NodeCast.instance);
34 public final Map prods = new TypedTreeMap(
35 StringComparator.instance,
36 StringCast.instance,
37 NodeCast.instance);
38 public final Map alts = new TypedTreeMap(
39 StringComparator.instance,
40 StringCast.instance,
41 NodeCast.instance);
42 public final Map elems = new TypedTreeMap(
43 StringComparator.instance,
44 StringCast.instance,
45 NodeCast.instance);
46 public final Map names = new TypedTreeMap(
47 NodeComparator.instance,
48 NodeCast.instance,
49 StringCast.instance);
50 public final Map errorNames = new TypedTreeMap(
51 NodeComparator.instance,
52 NodeCast.instance,
53 StringCast.instance);
54 public final Map elemTypes = new TypedTreeMap(
55 NodeComparator.instance,
56 NodeCast.instance,
57 StringCast.instance);
58 public final Map fixedTokens = new TypedTreeMap(
59 NodeComparator.instance,
60 NodeCast.instance,
61 BooleanCast.instance);
62 public final List tokenList = new TypedLinkedList(StringCast.instance);
63 public final LinkedList stateList = new TypedLinkedList(StringCast.instance);
64 public File pkgDir;
65 public String pkgName = "";
66
67 private boolean processingStates;
68 private boolean processingIgnTokens;
69
70 String currentProd;
71 String currentAlt;
72 private int lastLine;
73 private int lastPos;
74
75 public ResolveIds(File currentDir)
76 {
77 pkgDir = currentDir;
78 }
79
80 public void inPkgName1(PkgName1 node)
81 {
82 pkgName = node.getNode1().getText();
83 pkgDir = new File(pkgDir, node.getNode1().getText());
84
85 if(!pkgDir.exists())
86 {
87 if(!pkgDir.mkdir())
88 {
89 throw new RuntimeException("Unable to create " + pkgDir.getAbsolutePath());
90 }
91 }
92 }
93
94 public void inPkgNameTail1(PkgNameTail1 node)
95 {
96 pkgName += "." + node.getNode2().getText();
97 pkgDir = new File(pkgDir, node.getNode2().getText());
98
99 if(!pkgDir.exists())
100 {
101 if(!pkgDir.mkdir())
102 {
103 throw new RuntimeException("Unable to create " + pkgDir.getAbsolutePath());
104 }
105 }
106 }
107
108 public void caseBasic4(Basic4 node)
109 {
110 String name = node.getNode1().getText();
111
112 if(helpers.get(name) == null)
113 {
114 error2(node.getNode1(), name);
115 }
116 }
117
118 public void outHelperDef1(HelperDef1 node)
119 {
120 String name = node.getNode1().getText();
121
122 if(helpers.put(name, node) != null)
123 {
124 error(node.getNode1(), name);
125 }
126
127 names.put(node, name);
128 }
129
130 public void outTokenDef1(TokenDef1 node)
131 {
132 String name = "T" + name(node.getNode2().getText());
133 String errorName = errorName(node.getNode2().getText());
134
135 if(tokens.put(name, node) != null)
136 {
137 error(node.getNode2(), name);
138 }
139
140 names.put(node, name);
141 errorNames.put(node, errorName);
142 tokenList.add(name);
143 }
144
145 public void inStates1(States1 node)
146 {
147 processingStates = true;
148 }
149
150 public void outStates1(States1 node)
151 {
152 processingStates = false;
153 }
154
155 public void inIgnTokens1(IgnTokens1 node)
156 {
157 processingIgnTokens = true;
158 }
159
160 public void outIgnTokens1(IgnTokens1 node)
161 {
162 processingIgnTokens = false;
163 }
164
165 public void inIdList1(IdList1 node)
166 {
167 if(processingStates)
168 {
169 String name = node.getNode1().getText().toUpperCase();
170
171 if(states.put(name, node.getNode1()) != null)
172 {
173 error(node.getNode1(), name);
174 }
175
176 names.put(node.getNode1(), name);
177 stateList.add(name);
178 }
179
180 if(processingIgnTokens)
181 {
182 String name = "T" + name(node.getNode1().getText());
183
184 if(tokens.get(name) == null)
185 {
186 error2(node.getNode1(), name);
187 }
188
189 if(ignTokens.put(name, node.getNode1()) != null)
190 {
191 error(node.getNode1(), name);
192 }
193
194 names.put(node.getNode1(), name);
195 }
196 }
197
198 public void inIdListTail1(IdListTail1 node)
199 {
200 if(processingStates)
201 {
202 String name = node.getNode2().getText().toUpperCase();
203
204 if(states.put(name, node.getNode2()) != null)
205 {
206 error(node.getNode2(), name);
207 }
208
209 names.put(node.getNode2(), name);
210 stateList.add(name);
211 }
212
213 if(processingIgnTokens)
214 {
215 String name = "T" + name(node.getNode2().getText());
216
217 if(tokens.get(name) == null)
218 {
219 error2(node.getNode2(), name);
220 }
221
222 if(ignTokens.put(name, node.getNode2()) != null)
223 {
224 error(node.getNode2(), name);
225 }
226
227 names.put(node.getNode2(), name);
228 }
229 }
230
231 private Map stateMap;
232
233 public void inStateList1(StateList1 node)
234 {
235 stateMap = new TypedTreeMap(
236 StringComparator.instance,
237 StringCast.instance,
238 NodeCast.instance);
239
240 String name = node.getNode2().getText().toUpperCase();
241
242 if(states.get(name) == null)
243 {
244 error2(node.getNode2(), name);
245 }
246
247 if(stateMap.put(name, node) != null)
248 {
249 error(node.getNode2(), name);
250 }
251 }
252
253 public void outStateList1(StateList1 node)
254 {
255 stateMap = null;
256 }
257
258 public void inStateListTail1(StateListTail1 node)
259 {
260 String name = node.getNode2().getText().toUpperCase();
261
262 if(states.get(name) == null)
263 {
264 error2(node.getNode2(), name);
265 }
266
267 if(stateMap.put(name, node) != null)
268 {
269 error(node.getNode2(), name);
270 }
271 }
272
273 public void inTransition1(Transition1 node)
274 {
275 String name = node.getNode2().getText().toUpperCase();
276
277 if(states.get(name) == null)
278 {
279 error2(node.getNode2(), name);
280 }
281 }
282
283 public void inProd1(Prod1 node)
284 {
285 currentProd = name(node.getNode1().getText());
286
287 String name = "P" + currentProd;
288
289 if(prods.put(name, node) != null)
290 {
291 error(node.getNode1(), name);
292 }
293
294 names.put(node, name);
295 }
296
297 private class Alt1Switch extends AnalysisAdapter
298 {
299 Alt1 alt;
300
301 Alt1Switch(Alt1 alt)
302 {
303 this.alt = alt;
304 }
305
306 public void caseAltNameOpt1(AltNameOpt1 node)
307 {
308 currentAlt =
309 "A" +
310 name(((AltName1) node.getNode1()).getNode2().getText()) +
311 currentProd;
312
313 if(alts.put(currentAlt, alt) != null)
314 {
315 error(((AltName1) node.getNode1()).getNode2(), currentAlt);
316 }
317
318 names.put(alt, currentAlt);
319 }
320
321 public void caseAltNameOpt2(AltNameOpt2 node)
322 {
323 currentAlt = "A" + currentProd;
324
325 if(alts.put(currentAlt, alt) != null)
326 {
327 error(currentAlt);
328 }
329
330 names.put(alt, currentAlt);
331 }
332 }
333
334 public void inAlt1(final Alt1 alt)
335 {
336 alt.getNode1().apply(new Alt1Switch(alt));
337 }
338
339 public void defaultcase(Node node)
340 {
341 if(node instanceof Token)
342 {
343 Token t = (Token) node;
344 lastLine = t.getLine();
345 lastPos = t.getPos() + t.getText().length();
346 }
347 }
348
349 private class Alt2Switch extends AnalysisAdapter
350 {
351 Alt2 alt;
352
353 Alt2Switch(Alt2 alt)
354 {
355 this.alt = alt;
356 }
357
358 public void caseAltNameOpt1(AltNameOpt1 node)
359 {
360 currentAlt =
361 "A" +
362 name(((AltName1) node.getNode1()).getNode2().getText()) +
363 currentProd;
364
365 if(alts.put(currentAlt, alt) != null)
366 {
367 error(((AltName1) node.getNode1()).getNode2(), currentAlt);
368 }
369
370 names.put(alt, currentAlt);
371 }
372
373 public void caseAltNameOpt2(AltNameOpt2 node)
374 {
375 currentAlt = "A" + currentProd;
376
377 if(alts.put(currentAlt, alt) != null)
378 {
379 error(currentAlt);
380 }
381
382 names.put(alt, currentAlt);
383 }
384 }
385
386 public void inLookAhead1(LookAhead1 node)
387 {
388 Token token = (Token) node.getNode1();
389
390 throw new RuntimeException(
391 "[" + token.getLine() + "," + token.getPos() + "] " +
392 "Look ahead not yet supported.");
393 }
394 public void inAlt2(final Alt2 alt)
395 {
396 alt.getNode2().apply(new Alt2Switch(alt));
397 }
398
399 public void caseElem1(final Elem1 elem)
400 {
401 elem.getNode1().apply(new AnalysisAdapter()
402 {
403 public void caseElemNameOpt1(ElemNameOpt1 node)
404 {
405 String name = currentAlt + "." +
406 name(((ElemName1)node.getNode1()).getNode2().getText());
407
408 if(elems.put(name, elem) != null)
409 {
410 error(((ElemName1)node.getNode1()).getNode2(), name);
411 }
412
413 if(((ElemName1)node.getNode1()).getNode2().getText().equals("class"))
414 {
415 error5(((ElemName1)node.getNode1()).getNode2());
416 }
417
418 names.put(elem, name(((ElemName1)node.getNode1()).getNode2().getText()));
419 }
420
421 public void caseElemNameOpt2(ElemNameOpt2 node)
422 {
423 String name = currentAlt + "." +
424 name(elem.getNode3().getText());
425
426 if(elems.put(name, elem) != null)
427 {
428 error(elem.getNode3(), name);
429 }
430
431 if(elem.getNode3().getText().equals("class"))
432 {
433 error5(elem.getNode3());
434 }
435
436 names.put(elem, name(elem.getNode3().getText()));
437 }
438 });
439 }
440
441 public void outProductions1(Productions1 prod)
442 {
443 prod.apply(new DepthFirstAdapter()
444 {
445 public void caseElem1(Elem1 node)
446 {
447 String name = name(node.getNode3().getText());
448
449 if(node.getNode2() instanceof SpecifierOpt1)
450 {
451 if(((SpecifierOpt1) node.getNode2()).getNode1() instanceof Specifier1)
452 {
453 if(tokens.get("T" + name) == null)
454 {
455 error2(node.getNode3(), "T" + name);
456 }
457
458 if(ignTokens.get("T" + name) != null)
459 {
460 error3(node.getNode3(), "T" + name);
461 }
462
463 elemTypes.put(node, "T" + name);
464 }
465 else
466 {
467 if(prods.get("P" + name) == null)
468 {
469 error2(node.getNode3(), "P" + name);
470 }
471
472 elemTypes.put(node, "P" + name);
473 }
474 }
475 else
476 {
477 Object token = tokens.get("T" + name);
478 Object ignToken = ignTokens.get("T" + name);
479 Object production = prods.get("P" + name);
480
481 if((token == null) && (production == null))
482 {
483 error2(node.getNode3(), "P" + name + " and T" + name);
484 }
485
486 if(token != null)
487 {
488 if(production != null)
489 {
490 error4(node.getNode3(), "P" + name + " and T" + name);
491 }
492
493 if(ignToken != null)
494 {
495 error3(node.getNode3(), "T" + name);
496 }
497
498 elemTypes.put(node, "T" + name);
499 }
500 else
501 {
502 elemTypes.put(node, "P" + name);
503 }
504 }
505 }
506 });
507 }
508
509 public static String name(String s)
510 {
511 StringBuffer result = new StringBuffer();
512 boolean upcase = true;
513 int length = s.length();
514 char c;
515
516 for(int i = 0; i < length; i++)
517 {
518 c = s.charAt(i);
519 switch(c)
520 {
521 case '_':
522 upcase = true;
523 break;
524 default:
525 if(upcase)
526 {
527 result.append(Character.toUpperCase(c));
528 upcase = false;
529 }
530 else
531 {
532 result.append(c);
533 }
534 break;
535 }
536 }
537
538 return result.toString();
539 }
540
541 public static String errorName(String s)
542 {
543 StringBuffer result = new StringBuffer();
544 int length = s.length();
545 char c;
546
547 for(int i = 0; i < length; i++)
548 {
549 c = s.charAt(i);
550 switch(c)
551 {
552 case '_':
553 {
554 result.append(' ');
555 }
556 break;
557 default:
558 {
559 result.append(c);
560 }
561 break;
562 }
563 }
564
565 return result.toString();
566 }
567
568 private static void error(Token token, String name)
569 {
570 throw new RuntimeException(
571 "[" + token.getLine() + "," + token.getPos() + "] " +
572 "Redefinition of " + name + ".");
573 }
574
575 private void error(String name)
576 {
577 throw new RuntimeException(
578 "[" + lastLine + "," + lastPos + "] " +
579 "Redefinition of " + name + ".");
580 }
581
582 private static void error2(Token token, String name)
583 {
584 throw new RuntimeException(
585 "[" + token.getLine() + "," + token.getPos() + "] " +
586 name + " undefined.");
587 }
588
589 private static void error3(Token token, String name)
590 {
591 throw new RuntimeException(
592 "[" + token.getLine() + "," + token.getPos() + "] " +
593 name + " is ignored.");
594 }
595
596 private static void error4(Token token, String name)
597 {
598 throw new RuntimeException(
599 "[" + token.getLine() + "," + token.getPos() + "] " +
600 "ambiguous " + name + ".");
601 }
602
603 private static void error5(Token token)
604 {
605 throw new RuntimeException(
606 "[" + token.getLine() + "," + token.getPos() + "] " +
607 "class is an invalid element name.");
608 }
609
610 public String toString()
611 {
612 StringBuffer s = new StringBuffer();
613 String nl = System.getProperty("line.separator");
614
615 s.append("Helpers:");
616 s.append(nl);
617 s.append(helpers);
618 s.append(nl);
619
620 s.append("States:");
621 s.append(nl);
622 s.append(states);
623 s.append(nl);
624
625 s.append("Tokens:");
626 s.append(nl);
627 s.append(tokens);
628 s.append(nl);
629
630 s.append("Ignored Tokens:");
631 s.append(nl);
632 s.append(ignTokens);
633 s.append(nl);
634
635 s.append("Productions:");
636 s.append(nl);
637 s.append(prods);
638 s.append(nl);
639
640 s.append("Alternatives:");
641 s.append(nl);
642 s.append(alts);
643 s.append(nl);
644
645 s.append("Elements:");
646 s.append(nl);
647 s.append(elems);
648 s.append(nl);
649
650 return s.toString();
651 }
652 }
653