1 package antlr;
2
3 * <b>SOFTWARE RIGHTS</b>
5 * <p>
6 * ANTLR 2.5.0 MageLang Institute, 1998
7 * <p>
8 * We reserve no legal rights to the ANTLR--it is fully in the
9 * public domain. An individual or company may do whatever
10 * they wish with source code distributed with ANTLR or the
11 * code generated by ANTLR, including the incorporation of
12 * ANTLR, or its output, into commerical software.
13 * <p>
14 * We encourage users to develop software with ANTLR. However,
15 * we do ask that credit is given to us for developing
16 * ANTLR. By "credit", we mean that if you use ANTLR or
17 * incorporate any source code into one of your programs
18 * (commercial product, research project, or otherwise) that
19 * you acknowledge this fact somewhere in the documentation,
20 * research report, etc... If you like ANTLR and have
21 * developed a nice tool with the output, please mention that
22 * you developed it using ANTLR. In addition, we ask that the
23 * headers remain intact in our source code. As long as these
24 * guidelines are kept, we expect to continue enhancing this
25 * system and expect to make other tools available as they are
26 * completed.
27 * <p>
28 * The ANTLR gang:
29 * @version ANTLR 2.5.0 MageLang Institute, 1998
30 * @author Terence Parr, <a href=http://www.MageLang.com>MageLang Institute</a>
31 * @author <br>John Lilley, <a href=http://www.Empathy.com>Empathy Software</a>
32 */
33 import java.util.Enumeration;
34 import antlr.collections.impl.BitSet;
35 import antlr.collections.impl.Vector;
36 import java.io.PrintWriter; import java.io.IOException;
38 import java.io.FileWriter;
39
40
41 public class HTMLCodeGenerator extends CodeGenerator {
42
43 protected int syntacticPredLevel = 0;
44
45
46 protected boolean doingLexRules = false;
47
48 protected boolean firstElementInAlt;
49
50 protected AlternativeElement prevAltElem = null;
52 * The caller must still call setTool, setBehavior, and setAnalyzer
54 * before generating code.
55 */
56 public HTMLCodeGenerator() {
57 super();
58 charFormatter = new JavaCharFormatter();
59 }
60 public void gen() {
61
62 try {
64 Enumeration grammarIter = behavior.grammars.elements();
66 while (grammarIter.hasMoreElements()) {
67 Grammar g = (Grammar)grammarIter.nextElement();
68
69 g.setGrammarAnalyzer(analyzer);
72 analyzer.setGrammar(g);
73 */
74 g.setCodeGenerator(this);
75
76 g.generate();
78
79 if (tool.hasError) {
80 System.out.println("Exiting due to errors.");
81 System.exit(1);
82 }
83
84 }
85
86 // Loop over all token managers (some of which are lexers)
88 Enumeration tmIter = behavior.tokenManagers.elements();
89 while (tmIter.hasMoreElements()) {
90 TokenManager tm = (TokenManager)tmIter.nextElement();
91 if (!tm.isReadOnly()) {
92 // Write the token manager tokens as Java
93 genTokenTypes(tm);
94 }
95 }
96 */
97 }
98 catch (IOException e) {
99 System.out.println(e.getMessage());
100 }
101 }
102 * @param blk The {...} action to generate
104 */
105 public void gen(ActionElement action) {
106 _print("{");
108 _printAction(action.actionText);
109 _print("} ");
110 */
111 }
112 * @param blk The "x|y|z|..." block to generate
114 */
115 public void gen(AlternativeBlock blk) {
116 genGenericBlock(blk, "");
117 }
118 * @param blk The block-end element to generate. Block-end
120 * elements are synthesized by the grammar parser to represent
121 * the end of a block.
122 */
123 public void gen(BlockEndElement end) {
124 }
126 * @param blk The character literal reference to generate
128 */
129 public void gen(CharLiteralElement atom) {
130 if (atom.label != null) {
132 _print(atom.label+"=");
133 }
134 */
135 if (atom.not) {
136 _print("~");
137 }
138 _print(atom.atomText+" ");
139 }
140 * @param blk The character-range reference to generate
142 */
143 public void gen(CharRangeElement r) {
144 if ( r.label!=null ) {
146 _print(r.label+"=");
147 }
148 */
149 print(r.beginText + ".." + r.endText+" ");
150 }
151
152 public void gen(LexerGrammar g) throws IOException {
153 setGrammar(g);
154 System.out.println("Generating " + grammar.getClassName() + ".txt");
155 currentOutput = antlr.Tool.openOutputFile(grammar.getClassName() + ".txt");
156
158 tabs=0;
159 doingLexRules = true;
160
161 genHeader();
163
164 // Output the user-defined lexer premamble
166 println(grammar.preambleAction);
167 */
168
169 println("");
171
172 if ( grammar.comment!=null ) {
174 _println(grammar.comment);
175 }
176
177 println("class " + grammar.getClassName() + " extends " + grammar.getSuperClass() + " {");
178
179
182 // Generate string literals
184 println("");
185 println("*** String literals used in the parser");
186 println("The following string literals were used in the parser.");
187 println("An actual code generator would arrange to place these literals");
188 println("into a table in the generated lexer, so that actions in the");
189 println("generated lexer could match token text against the literals.");
190 println("String literals used in the lexer are not listed here, as they");
191 println("are incorporated into the mainstream lexer processing.");
192 tabs++;
193 // Enumerate all of the symbols and look for string literal symbols
194 Enumeration ids = grammar.getSymbols();
195 while ( ids.hasMoreElements() ) {
196 GrammarSymbol sym = (GrammarSymbol)ids.nextElement();
197 // Only processing string literals -- reject other symbol entries
198 if ( sym instanceof StringLiteralSymbol ) {
199 StringLiteralSymbol s = (StringLiteralSymbol)sym;
200 println(s.getId() + " = " + s.getTokenType());
201 }
202 }
203 tabs--;
204 println("*** End of string literals used by the parser");
205 */
206
207 genNextToken();
211
212
214 Enumeration ids = grammar.rules.elements();
215 while ( ids.hasMoreElements() ) {
216 RuleSymbol rs = (RuleSymbol)ids.nextElement();
217 if (!rs.id.equals("mnextToken")) {
218 genRule(rs);
219 }
220 }
221
222 currentOutput.close();
224 currentOutput = null;
225 doingLexRules = false;
226 }
227 * @param blk The (...)+ block to generate
229 */
230 public void gen(OneOrMoreBlock blk) {
231 genGenericBlock(blk, "+");
232 }
233
234 public void gen(ParserGrammar g) throws IOException {
235 setGrammar(g);
236 System.out.println("Generating " + grammar.getClassName() + ".html");
238 currentOutput = antlr.Tool.openOutputFile(grammar.getClassName()+".html");
239
240 tabs = 0;
241
242 genHeader();
244
245 _print("{");
247 printAction(grammar.preambleAction);
248 _print("}");
249 */
250
251 println("");
253
254 if ( grammar.comment!=null ) {
256 _println(grammar.comment);
257 }
258
259 println("class " + grammar.getClassName() + " extends " + grammar.getSuperClass());
260
261 // Generate user-defined parser class members
263 println("");
264 _print("{");
265 printAction(grammar.classMemberAction);
266 _print("}");
267 */
268
269 Enumeration rules = grammar.rules.elements();
271 while ( rules.hasMoreElements() ) {
272 println("");
273 GrammarSymbol sym = (GrammarSymbol) rules.nextElement();
275 if ( sym instanceof RuleSymbol) {
277 genRule((RuleSymbol)sym);
278 }
279 }
280 tabs--;
281 println("");
282
283 genTail();
284
285 currentOutput.close();
287 currentOutput = null;
288 }
289 * @param blk The rule-reference to generate
291 */
292 public void gen(RuleRefElement rr) {
293 RuleSymbol rs = (RuleSymbol)grammar.getSymbol(rr.targetRule);
294
295 if ( rr.idAssign!=null ) {
298 _print(rr.idAssign+"=");
299 }
300 */
301 _print("<a href="+grammar.getClassName() + ".html#"+rr.targetRule+">");
302 _print(rr.targetRule);
303 _print("</a>");
304 if (rr.args != null) {
305 _print("["+rr.args+"]");
306 }
307 _print(" ");
308 }
309 * @param blk The string-literal reference to generate
311 */
312 public void gen(StringLiteralElement atom) {
313 if (atom.label != null) {
315 _print(atom.label+"=");
316 }
317 */
318 if (atom.not) {
319 _print("~");
320 }
321 _print(atom.atomText);
322 _print(" ");
323 }
324 * @param blk The token-range reference to generate
326 */
327 public void gen(TokenRangeElement r) {
328 if ( r.label!=null ) {
330 _print(r.label+"=");
331 }
332 */
333 print(r.beginText + ".." + r.endText+" ");
334 }
335 * @param blk The token-reference to generate
337 */
338 public void gen(TokenRefElement atom) {
339 if (atom.label != null) {
341 _print(atom.label+"=");
342 }
343 */
344 if (atom.not) {
345 _print("~");
346 }
347 _print(atom.atomText);
348 _print(" ");
349 }
350 public void gen(TreeElement t) {
351 print(t+" ");
352 }
353
354 public void gen(TreeWalkerGrammar g) throws IOException {
355 setGrammar(g);
356 System.out.println("Generating " + grammar.getClassName() + ".txt");
358 currentOutput = antlr.Tool.openOutputFile(grammar.getClassName()+".txt");
359
361 tabs = 0;
362
363 genHeader();
365
366 println("");
368 println("*** Tree-walker Preamble Action.");
369 println("This action will appear before the declaration of your tree-walker class:");
370 tabs++;
371 println(grammar.preambleAction);
372 tabs--;
373 println("*** End of tree-walker Preamble Action");
374
375 println("");
377
378 if ( grammar.comment!=null ) {
380 _println(grammar.comment);
381 }
382
383 println("class " + grammar.getClassName() + " extends " + grammar.getSuperClass() + "{");
384
385 println("");
387 println("*** User-defined tree-walker class members:");
388 println("These are the member declarations that you defined for your class:");
389 tabs++;
390 printAction(grammar.classMemberAction);
391 tabs--;
392 println("*** End of user-defined tree-walker class members");
393
394 println("");
396 println("*** tree-walker rules:");
397 tabs++;
398
399 Enumeration rules = grammar.rules.elements();
401 while ( rules.hasMoreElements() ) {
402 println("");
403 GrammarSymbol sym = (GrammarSymbol) rules.nextElement();
405 if ( sym instanceof RuleSymbol) {
407 genRule((RuleSymbol)sym);
408 }
409 }
410 tabs--;
411 println("");
412 println("*** End of tree-walker rules");
413
414 println("");
415 println("*** End of tree-walker");
416
417 currentOutput.close();
419 currentOutput = null;
420 }
421
422 public void gen(WildcardElement wc) {
423 if ( wc.getLabel()!=null ) {
425 _print(wc.getLabel()+"=");
426 }
427 */
428 _print(". ");
429 }
430 * @param blk The (...)* block to generate
432 */
433 public void gen(ZeroOrMoreBlock blk) {
434 genGenericBlock(blk, "*");
435 }
436 protected void genAlt(Alternative alt) {
437 if (alt.getTreeSpecifier() != null) {
438 _print(alt.getTreeSpecifier().getText());
439 }
440 prevAltElem = null;
441 for (AlternativeElement elem = alt.head; !(elem instanceof BlockEndElement); elem = elem.next) {
442 elem.generate();
443 firstElementInAlt = false;
444 prevAltElem = elem;
445 }
446 }
447 * plain AlternativeBLock. This generates any variable declarations,
449 * init-actions, and syntactic-predicate-testing variables.
450 * @blk The block for which the preamble is to be generated.
451 */
452 protected void genBlockPreamble(AlternativeBlock blk) {
453 if ( blk.initAction!=null ) {
455 printAction("{" + blk.initAction + "}");
456 }
457 }
458 * that needs to be generated at the end of the block. Other routines
460 * may append else-clauses and such for error checking before the postfix
461 * is generated.
462 */
463 public void genCommonBlock(AlternativeBlock blk) {
464 for (int i = 0; i < blk.alternatives.size(); i++) {
465 Alternative alt = blk.getAlternativeAt(i);
466 AlternativeElement elem = alt.head;
467
468 if ( i>0 && blk.alternatives.size()>1 ) {
470 // only do newline if the last element wasn't a multi-line block
472 if ( prevAltElem==null ||
473 !(prevAltElem instanceof AlternativeBlock) ||
474 ((AlternativeBlock)prevAltElem).alternatives.size()==1 )
475 {
476 _println("");
477 }
478 */
479 _println("");
480 print("|\t");
481 }
482
483
485 boolean save = firstElementInAlt;
486 firstElementInAlt = true;
487 tabs++; if (alt.semPred != null) {
490 println("{" + alt.semPred + "}?");
491 }
492 if (alt.synPred != null) {
494 genSynPred(alt.synPred);
495 }
496 genAlt(alt);
497 tabs--;
498 firstElementInAlt = save;
499 }
500 }
501 * for a block.
503 * @param blk The rule block of interest
504 */
505 public void genFollowSetForRuleBlock(RuleBlock blk)
506 {
507 Lookahead follow = grammar.theLLkAnalyzer.FOLLOW(1, blk.endNode);
508 printSet(grammar.maxk, 1, follow);
509 }
510 protected void genGenericBlock(AlternativeBlock blk, String blkOp) {
511 if (blk.alternatives.size() > 1) {
512 if (!firstElementInAlt) {
514 if ( prevAltElem==null ||
516 !(prevAltElem instanceof AlternativeBlock) ||
517 ((AlternativeBlock)prevAltElem).alternatives.size()==1 )
518 {
519 _println("");
520 print("(\t");
521 }
522 else {
523 _print("(\t");
524 }
525 }
528 else {
529 _print("(\t");
530 }
531 } else {
532 _print("( ");
533 }
534 genBlockPreamble(blk);
535 genCommonBlock(blk);
536 if (blk.alternatives.size() > 1) {
537 _println("");
538 print(")" + blkOp + " ");
539 if ( !(blk.next instanceof BlockEndElement) ) {
541 _println("");
542 print("");
543 }
544 } else {
545 _print(")" + blkOp + " ");
546 }
547 }
548
549 protected void genHeader()
550 {
551 println("<HTML>");
552 println("<HEAD>");
553 println("<TITLE>Grammar "+tool.grammarFile+"</TITLE>");
554 println("</HEAD>");
555 println("<BODY>");
556 println("<table border=1 cellpadding=5>");
557 println("<tr>");
558 println("<td>");
559 println("<font size=+2>Grammar "+grammar.getClassName()+"</font><br>");
560 println("<a href=http://www.ANTLR.org>ANTLR</a>-generated HTML file from "+tool.grammarFile);
561 println("<p>");
562 println("Terence Parr, <a href=http://www.magelang.com>MageLang Institute</a>");
563 println("<br>ANTLR Version "+ANTLRParser.version+"; 1989-1998");
564 println("</td>");
565 println("</tr>");
566 println("</table>");
567 println("<PRE>");
568 tabs++;
569 printAction(behavior.headerAction);
570 tabs--;
571 }
572
573 protected void genLookaheadSetForAlt(Alternative alt) {
574 if ( doingLexRules && alt.cache[1].containsEpsilon() ) {
575 println("MATCHES ALL");
576 return;
577 }
578 int depth = alt.lookaheadDepth;
579 if ( depth == GrammarAnalyzer.NONDETERMINISTIC ) {
580 depth = grammar.maxk;
583 }
584 for (int i = 1; i <= depth; i++)
585 {
586 Lookahead lookahead = alt.cache[i];
587 printSet(depth, i, lookahead);
588 }
589 }
590 * for a block.
592 * @param blk The block of interest
593 */
594 public void genLookaheadSetForBlock(AlternativeBlock blk)
595 {
596 int depth = 0;
598 for (int i=0; i<blk.alternatives.size(); i++) {
599 Alternative alt = blk.getAlternativeAt(i);
600 if (alt.lookaheadDepth == GrammarAnalyzer.NONDETERMINISTIC) {
601 depth = grammar.maxk;
602 break;
603 }
604 else if (depth < alt.lookaheadDepth) {
605 depth = alt.lookaheadDepth;
606 }
607 }
608
609 for (int i = 1; i <= depth; i++)
610 {
611 Lookahead lookahead = grammar.theLLkAnalyzer.look(i, blk);
612 printSet(depth, i, lookahead);
613 }
614 }
615 * nextToken is a synthetic lexer rule that is the implicit OR of all
617 * user-defined lexer rules.
618 */
619 public void genNextToken() {
620 println("");
621 println("/** Lexer nextToken rule:");
622 println(" * The lexer nextToken rule is synthesized from all of the user-defined");
623 println(" * lexer rules. It logically consists of one big alternative block with");
624 println(" * each user-defined rule being an alternative.");
625 println(" */");
626
627 RuleBlock blk = MakeGrammar.createNextTokenRule(grammar, grammar.rules, "nextToken");
630
631 RuleSymbol nextTokenRs = new RuleSymbol("mnextToken");
633 nextTokenRs.setDefined();
634 nextTokenRs.setBlock(blk);
635 nextTokenRs.access = "private";
636 grammar.define(nextTokenRs);
637
638 // Analyze the synthesized block
640 if (!grammar.theLLkAnalyzer.deterministic(blk))
641 {
642 println("The grammar analyzer has determined that the synthesized");
643 println("nextToken rule is non-deterministic (i.e., it has ambiguities)");
644 println("This means that there is some overlap of the character");
645 println("lookahead for two or more of your lexer rules.");
646 }
647 */
648
649 genCommonBlock(blk);
650 }
651 * @param s The RuleSymbol describing the rule to generate
653 */
654 public void genRule(RuleSymbol s) {
655 if ( s==null || !s.isDefined() ) return; println("");
657 if ( s.comment!=null ) {
658 _println(s.comment);
659 }
660 if (s.access.length() != 0) {
661 if ( !s.access.equals("public") ) {
662 _print(s.access+" ");
663 }
664 }
665 _print("<a name="+s.getId()+">");
666 _print(s.getId());
667 _print("</a>");
668
669 RuleBlock rblk = s.getBlock();
671
672 if (rblk.returnAction != null) {
674 _print("["+rblk.returnAction+"]");
675 }
676 if (rblk.argAction != null)
678 {
679 _print(" returns [" + rblk.argAction+"]");
680 }
681 _println("");
682 tabs++;
683 print(":\t");
684
685
688 genCommonBlock(rblk);
690
691 _println("");
692 println(";");
693 tabs--;
694 }
695 * the alternative block, buts tracks if we are inside a synPred
697 * @param blk The syntactic predicate block
698 */
699 protected void genSynPred(SynPredBlock blk) {
700 syntacticPredLevel++;
701 genGenericBlock(blk, " =>");
702 syntacticPredLevel--;
703 }
704 public void genTail() {
705 println("</PRE>");
706 println("</BODY>");
707 println("</HTML>");
708 }
709
710 protected void genTokenTypes(TokenManager tm) throws IOException {
711 System.out.println("Generating " + tm.getName() + "TokenTypes.txt");
713 currentOutput = antlr.Tool.openOutputFile(tm.getName() + "TokenTypes.txt");
714 tabs = 0;
716
717 genHeader();
719
720 println("");
723 println("*** Tokens used by the parser");
724 println("This is a list of the token numeric values and the corresponding");
725 println("token identifiers. Some tokens are literals, and because of that");
726 println("they have no identifiers. Literals are double-quoted.");
727 tabs++;
728
729 Vector v = tm.getVocabulary();
731 for (int i = Token.MIN_USER_TYPE; i < v.size(); i++) {
732 String s = (String)v.elementAt(i);
733 if (s != null) {
734 println(s + " = " + i);
735 }
736 }
737
738 tabs--;
740 println("*** End of tokens used by the parser");
741
742 currentOutput.close();
744 currentOutput = null;
745 }
746 * @param v A Vector of String, where each element is an expression in the target language yielding an AST node.
748 */
749 public String getASTCreateString(Vector v) {
750 return null;
751 }
752 * @param str The arguments to the AST constructor
754 */
755 public String getASTCreateString(String str) {
756 return null;
757 }
758 * This is context-sensitive, depending on the rule and alternative
760 * being generated
761 * @param id The identifier name to map
762 * @param forInput true if the input tree node variable is to be returned, otherwise the output variable is returned.
763 */
764 public String mapTreeId(String id, ActionTransInfo tInfo) {
765 return id;
766 }
767 * @param depth The depth of the entire lookahead/follow
769 * @param k The lookahead level to print
770 * @param lookahead The lookahead/follow set to print
771 */
772 public void printSet(int depth, int k, Lookahead lookahead) {
773 int numCols = 5;
774
775 int[] elems = lookahead.fset.toArray();
776
777 if (depth != 1) {
778 print("k==" + k + ": {");
779 } else {
780 print("{ ");
781 }
782 if (elems.length > numCols) {
783 _println("");
784 tabs++;
785 print("");
786 }
787
788 int column = 0;
789 for (int i = 0; i < elems.length; i++)
790 {
791 column++;
792 if (column > numCols) {
793 _println("");
794 print("");
795 column = 0;
796 }
797 if (doingLexRules) {
798 _print(charFormatter.literalChar(elems[i]));
799 } else {
800 _print((String)grammar.tokenManager.getVocabulary().elementAt(elems[i]));
801 }
802 if (i != elems.length-1) {
803 _print(", ");
804 }
805 }
806
807 if (elems.length > numCols) {
808 _println("");
809 tabs--;
810 print("");
811 }
812 _println(" }");
813 }
814 }
815