ANTLRTreePrinter.g revision 324c4644fee44b9898524c09511bd33c3f12e2df
1/*
2 [The "BSD license"]
3 Copyright (c) 2005-2011 Terence Parr
4 All rights reserved.
5
6 Grammar conversion to ANTLR v3:
7 Copyright (c) 2011 Sam Harwell
8 All rights reserved.
9
10 Redistribution and use in source and binary forms, with or without
11 modification, are permitted provided that the following conditions
12 are met:
13 1. Redistributions of source code must retain the above copyright
14	notice, this list of conditions and the following disclaimer.
15 2. Redistributions in binary form must reproduce the above copyright
16	notice, this list of conditions and the following disclaimer in the
17	documentation and/or other materials provided with the distribution.
18 3. The name of the author may not be used to endorse or promote products
19	derived from this software without specific prior written permission.
20
21 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31*/
32
33/** Print out a grammar (no pretty printing).
34 *
35 *  Terence Parr
36 *  University of San Francisco
37 *  August 19, 2003
38 */
39tree grammar ANTLRTreePrinter;
40
41options
42{
43	tokenVocab = ANTLR;
44	ASTLabelType = GrammarAST;
45}
46
47@header {
48package org.antlr.grammar.v3;
49import org.antlr.tool.*;
50import java.util.StringTokenizer;
51}
52
53@members {
54protected Grammar grammar;
55protected boolean showActions;
56protected StringBuilder buf = new StringBuilder(300);
57
58private ANTLRTreePrinter.block_return block(GrammarAST t, boolean forceParens) throws RecognitionException {
59    ANTLRTreePrinter other = new ANTLRTreePrinter(new CommonTreeNodeStream(t));
60    other.buf = buf;
61    return other.block(forceParens);
62}
63
64public final int countAltsForBlock(GrammarAST t) {
65    int n = 0;
66    for ( int i = 0; i < t.getChildCount(); i++ )
67    {
68        if ( t.getChild(i).getType() == ALT )
69            n++;
70    }
71
72    return n;
73}
74
75public void out(String s) {
76    buf.append(s);
77}
78
79@Override
80public void reportError(RecognitionException ex) {
81    Token token = null;
82    if (ex instanceof MismatchedTokenException) {
83        token = ((MismatchedTokenException)ex).token;
84    } else if (ex instanceof NoViableAltException) {
85        token = ((NoViableAltException)ex).token;
86    }
87
88    ErrorManager.syntaxError(
89        ErrorManager.MSG_SYNTAX_ERROR,
90        grammar,
91        token,
92        "antlr.print: " + ex.toString(),
93        ex );
94}
95
96/** Normalize a grammar print out by removing all double spaces
97 *  and trailing/beginning stuff.  FOr example, convert
98 *
99 *  ( A  |  B  |  C )*
100 *
101 *  to
102 *
103 *  ( A | B | C )*
104 */
105public static String normalize(String g) {
106    StringTokenizer st = new StringTokenizer(g, " ", false);
107    StringBuffer buf = new StringBuffer();
108    while ( st.hasMoreTokens() ) {
109        String w = st.nextToken();
110        buf.append(w);
111        buf.append(" ");
112    }
113    return buf.toString().trim();
114}
115}
116
117/** Call this to figure out how to print */
118public
119toString[Grammar g, boolean showActions] returns [String s=null]
120@init {
121	grammar = g;
122	this.showActions = showActions;
123}
124	:	(	grammar_
125		|	rule
126		|	alternative
127		|	element
128		|	single_rewrite
129		|	rewrite
130		|	EOR //{s="EOR";}
131		)
132		{return normalize(buf.toString());}
133	;
134
135// --------------
136
137grammar_
138	:	^( LEXER_GRAMMAR grammarSpec["lexer " ] )
139	|	^( PARSER_GRAMMAR grammarSpec["parser "] )
140	|	^( TREE_GRAMMAR grammarSpec["tree "] )
141	|	^( COMBINED_GRAMMAR grammarSpec[""] )
142	;
143
144attrScope
145	:	^( 'scope' ID ruleAction* ACTION )
146	;
147
148grammarSpec[String gtype]
149	:	id=ID {out(gtype+"grammar "+$id.text);}
150		(cmt=DOC_COMMENT {out($cmt.text+"\n");} )?
151		(optionsSpec)? {out(";\n");}
152		(delegateGrammars)?
153		(tokensSpec)?
154		(attrScope)*
155		(actions)?
156		rules
157	;
158
159actions
160	:	( action )+
161	;
162
163action
164@init {
165	String scope=null, name=null;
166	String action=null;
167}
168	:	^(	AMPERSAND id1=ID
169			(	id2=ID a1=ACTION
170				{scope=$id1.text; name=$a1.text; action=$a1.text;}
171			|	a2=ACTION
172				{scope=null; name=$id1.text; action=$a2.text;}
173			)
174		)
175		{
176			if ( showActions )
177			{
178				out("@"+(scope!=null?scope+"::":"")+name+action);
179			}
180		}
181	;
182
183optionsSpec
184	:	^(	OPTIONS {out(" options {");}
185			(option {out("; ");})+
186			{out("} ");}
187		)
188	;
189
190option
191	:	^( ASSIGN id=ID {out($id.text+"=");} optionValue )
192	;
193
194optionValue
195	:	id=ID            {out($id.text);}
196	|	s=STRING_LITERAL {out($s.text);}
197	|	c=CHAR_LITERAL   {out($c.text);}
198	|	i=INT            {out($i.text);}
199//	|   charSet
200	;
201
202/*
203charSet
204	:   #( CHARSET charSetElement )
205	;
206
207charSetElement
208	:   c:CHAR_LITERAL {out(#c.getText());}
209	|   #( OR c1:CHAR_LITERAL c2:CHAR_LITERAL )
210	|   #( RANGE c3:CHAR_LITERAL c4:CHAR_LITERAL )
211	;
212*/
213
214delegateGrammars
215	:	^( 'import' ( ^(ASSIGN ID ID) | ID )+ )
216	;
217
218tokensSpec
219	:	^(TOKENS tokenSpec*)
220	;
221
222tokenSpec
223	:	TOKEN_REF
224	|	^( ASSIGN TOKEN_REF (STRING_LITERAL|CHAR_LITERAL) )
225	;
226
227rules
228	:	( rule | precRule )+
229	;
230
231rule
232	:	^(	RULE id=ID
233			(modifier)?
234			{out($id.text);}
235			^(ARG (arg=ARG_ACTION {out("["+$arg.text+"]");} )? )
236			^(RET (ret=ARG_ACTION {out(" returns ["+$ret.text+"]");} )? )
237			(throwsSpec)?
238			(optionsSpec)?
239			(ruleScopeSpec)?
240			(ruleAction)*
241			{out(" :");}
242			{
243				if ( input.LA(5) == NOT || input.LA(5) == ASSIGN )
244					out(" ");
245			}
246			b=block[false]
247			(exceptionGroup)?
248			EOR {out(";\n");}
249		)
250	;
251
252precRule
253	:	^(	PREC_RULE id=ID
254			(modifier)?
255			{out($id.text);}
256			^(ARG (arg=ARG_ACTION {out("["+$arg.text+"]");} )? )
257			^(RET (ret=ARG_ACTION {out(" returns ["+$ret.text+"]");} )? )
258			(throwsSpec)?
259			(optionsSpec)?
260			(ruleScopeSpec)?
261			(ruleAction)*
262			{out(" :");}
263			{
264				if ( input.LA(5) == NOT || input.LA(5) == ASSIGN )
265					out(" ");
266			}
267			b=block[false]
268			(exceptionGroup)?
269			EOR {out(";\n");}
270		)
271	;
272
273ruleAction
274	:	^(AMPERSAND id=ID a=ACTION )
275		{if ( showActions ) out("@"+$id.text+"{"+$a.text+"}");}
276	;
277
278modifier
279@init
280{out($modifier.start.getText()); out(" ");}
281	:	'protected'
282	|	'public'
283	|	'private'
284	|	'fragment'
285	;
286
287throwsSpec
288	:	^('throws' ID+)
289	;
290
291ruleScopeSpec
292	:	^( 'scope' ruleAction* (ACTION)? ( ID )* )
293	;
294
295block[boolean forceParens]
296@init
297{
298int numAlts = countAltsForBlock($start);
299}
300	:	^(	BLOCK
301			{
302				if ( forceParens||numAlts>1 )
303				{
304					//for ( Antlr.Runtime.Tree.Tree parent = $start.getParent(); parent != null && parent.getType() != RULE; parent = parent.getParent() )
305					//{
306					//	if ( parent.getType() == BLOCK && countAltsForBlock((GrammarAST)parent) > 1 )
307					//	{
308					//		out(" ");
309					//		break;
310					//	}
311					//}
312					out(" (");
313				}
314			}
315			(optionsSpec {out(" :");} )?
316			alternative rewrite ( {out("|");} alternative rewrite )*
317			EOB   {if ( forceParens||numAlts>1 ) out(")");}
318		 )
319	;
320
321alternative
322	:	^( ALT element* EOA )
323	;
324
325exceptionGroup
326	:	( exceptionHandler )+ (finallyClause)?
327	|	finallyClause
328	;
329
330exceptionHandler
331	:	^('catch' ARG_ACTION ACTION)
332	;
333
334finallyClause
335	:	^('finally' ACTION)
336	;
337
338rewrite
339	:	^(REWRITES single_rewrite+)
340	|	REWRITES
341	|
342	;
343
344single_rewrite
345	:	^(	REWRITE {out(" ->");}
346			(	SEMPRED {out(" {"+$SEMPRED.text+"}?");}
347			)?
348			(	alternative
349			|	rewrite_template
350			|	ETC {out("...");}
351			|	ACTION {out(" {"+$ACTION.text+"}");}
352			)
353		)
354	;
355
356rewrite_template
357	:	^(	TEMPLATE
358			(	id=ID {out(" "+$id.text);}
359			|	ind=ACTION {out(" ({"+$ind.text+"})");}
360			)
361			^(	ARGLIST
362				{out("(");}
363				(	^(	ARG arg=ID {out($arg.text+"=");}
364						a=ACTION   {out($a.text);}
365					)
366				)*
367				{out(")");}
368			)
369			(	DOUBLE_QUOTE_STRING_LITERAL {out(" "+$DOUBLE_QUOTE_STRING_LITERAL.text);}
370			|	DOUBLE_ANGLE_STRING_LITERAL {out(" "+$DOUBLE_ANGLE_STRING_LITERAL.text);}
371			)?
372		)
373	;
374
375element
376	:	^(ROOT element) {out("^");}
377	|	^(BANG element) {out("!");}
378	|	atom
379	|	^(NOT {out("~");} element)
380	|	^(RANGE atom {out("..");} atom)
381	|	^(CHAR_RANGE atom {out("..");} atom)
382	|	^(ASSIGN id=ID {out($id.text+"=");} element)
383	|	^(PLUS_ASSIGN id2=ID {out($id2.text+"+=");} element)
384	|	ebnf
385	|	tree_
386	|	^( SYNPRED block[true] ) {out("=>");}
387	|	a=ACTION  {if ( showActions ) {out("{"); out($a.text); out("}");}}
388	|	a2=FORCED_ACTION  {if ( showActions ) {out("{{"); out($a2.text); out("}}");}}
389	|	pred=SEMPRED
390		{
391			if ( showActions )
392			{
393				out("{");
394				out($pred.text);
395				out("}?");
396			}
397			else
398			{
399				out("{...}?");
400			}
401		}
402	|	spred=SYN_SEMPRED
403		{
404			String name = $spred.text;
405			GrammarAST predAST=grammar.getSyntacticPredicate(name);
406			block(predAST, true);
407			out("=>");
408		}
409	|	^(BACKTRACK_SEMPRED .*) // don't print anything (auto backtrack stuff)
410	|	gpred=GATED_SEMPRED
411		{
412		if ( showActions ) {out("{"); out($gpred.text); out("}? =>");}
413		else {out("{...}? =>");}
414		}
415	|	EPSILON
416	;
417
418ebnf
419	:	block[true] {out(" ");}
420	|	^( OPTIONAL block[true] ) {out("? ");}
421	|	^( CLOSURE block[true] )  {out("* ");}
422	|	^( POSITIVE_CLOSURE block[true] ) {out("+ ");}
423	;
424
425tree_
426	:	^(TREE_BEGIN {out(" ^(");} element (element)* {out(") ");} )
427	;
428
429atom
430@init
431{out(" ");}
432	:	(	^(	RULE_REF		{out($start.toString());}
433				(rarg=ARG_ACTION	{out("["+$rarg.toString()+"]");})?
434				(ast_suffix)?
435			)
436		|	^(	TOKEN_REF		{out($start.toString());}
437				(targ=ARG_ACTION	{out("["+$targ.toString()+"]");} )?
438				(ast_suffix)?
439			)
440		|	^(	CHAR_LITERAL	{out($start.toString());}
441				(ast_suffix)?
442			)
443		|	^(	STRING_LITERAL	{out($start.toString());}
444				(ast_suffix)?
445			)
446		|	^(	WILDCARD		{out($start.toString());}
447				(ast_suffix)?
448			)
449		)
450		{out(" ");}
451	|	LABEL {out(" $"+$LABEL.text);} // used in -> rewrites
452	|	^(DOT ID {out($ID.text+".");} atom) // scope override on rule
453	;
454
455ast_suffix
456	:	ROOT {out("^");}
457	|	BANG  {out("!");}
458	;
459