001: /*
002: * xtc - The eXTensible Compiler
003: * Copyright (C) 2007 IBM Corp.
004: *
005: * This program is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU General Public License
007: * version 2 as published by the Free Software Foundation.
008: *
009: * This program is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
012: * GNU General Public License for more details.
013: *
014: * You should have received a copy of the GNU General Public License
015: * along with this program; if not, write to the Free Software
016: * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
017: * USA.
018: */
019: package xtc.lang.jeannie;
020:
021: import java.util.Stack;
022:
023: import xtc.lang.CPrinter;
024: import xtc.lang.JavaPrinter;
025: import xtc.tree.GNode;
026: import xtc.tree.Node;
027: import xtc.tree.Printer;
028: import xtc.tree.Visitor;
029:
030: /**
031: A pretty printer for Jeannie (pretty JNI).
032:
033: This is an example of combining two visitors (CPrinter and JavaPrinter). But it
034: is slightly unusual in that those visitors don't call dispatch() on themselves for
035: children directly; instead, they call it indirectly through Printer, which is not
036: a visitor itself.
037:
038: TD 41 double-check that this takes care of precedence, dangling else, and such
039:
040: <h2>Simplified abstract Jeannie grammar:</h2>
041:
042: This grammar describes the kinds of AST nodes that can occur in a Jeannie AST; in
043: addition, all AST nodes from the plain C and Java grammars that are not modified here
044: can also occur. See JavaAstSimplifier for notation explanation.<p>
045:
046: <p><u>Notation explanation</u>
047: <table border=0>
048: <tr><td><i>Whole = Part1 Part2 ... PartN</i> <td>the <i>Whole</i> consists of all the parts <i>Part<sub>i</sub></i>
049: <tr><td><i>Whole = Part1 / Part2 / ... / PartN</i> <td>the <i>Whole</i> consists of one of the parts <i>Part<sub>i</sub></i>
050: <tr><td><i>Super > Sub1, Sub2, ..., SubN</i> <td>any of the <i>Sub<sub>i</sub></i> can appear where a <i>Super</i> is expected
051: <tr><td><i>Super > {Pre1,Pre2,...,PreN}Sub</i> <td>shorthand for <i>Super > Pre1Sub, Pre2Sub, ..., PreNSub</i>
052: <tr><td><i>Super</i> : <i>Lit1, Lit2, ..., LitN</i> <td>shorthand for <i>Super > "Lit1", "Lit2", ..., "LitN"</i>
053: <tr><td>[<i>Option</i>] <td>zero or one occurrences
054: <tr><td><i>Repetee</i>* <td>zero or more occurrences
055: <tr><td><i>Repetee</i>+ <td>one or more occurrences
056: <tr><td>"<i>token</i>" <td>literal string token
057: </table>
058:
059: <hr size=1>
060:
061: <u>Modifications to Java grammar</u>
062:
063: <table border=0>
064: <tr><td>CompilationUnit <td>= <td>CDeclarations [PackageDeclaration] ImportDeclaration* JeannieJava.Declaration*
065: <tr><td>Block <td>> <td>JavaInJavaBlock, CInJavaBlock
066: <tr><td>JeannieJava.Expression <td>> <td>..., CInJavaExpression
067: </table>
068:
069: <u>Modifications to C grammar</u>
070:
071: <table border=0>
072: <tr><td>TranslationUnit <td>= <td>[JavaImports] ExternalDeclaration* Annotations
073: <tr><td>CompoundStatement <td>> <td>CInCBlock, JavaInCBlock
074: <tr><td>FunctionDeclarator <td>= <td>(ParameterTypeList / IdentifierList) JavaThrows
075: <tr><td>JeannieC.Statement <td>> <td>..., JavaInCStatement, CancelStatement, CommitStatement, WithStatement
076: <tr><td>JeannieC.UnaryExpression <td>> <td>..., JavaInCExpression
077: <tr><td>TypeSpecifier <td>> <td>..., JavaType
078: </table>
079:
080: <u>New productions</u>
081:
082: <table border=0>
083: <tr><td>JeannieFile <td>> <td>TranslationUnit, CompilationUnit
084: <tr><td>CDeclarations <td>= <td>ExternalDeclaration*
085: <tr><td>CInCBlock <td>= <td>LocalLabelDeclaration* JeannieC.DeclarationOrStatement* Annotations
086: <tr><td>CInJavaBlock <td>= <td>CInCBlock
087: <tr><td>CInJavaExpression <td>= <td>JeannieC.UnaryExpression
088: <tr><td>JavaImports <td>= <td>ImportDeclaration*
089: <tr><td>JavaInCBlock <td>= <td>JavaInJavaBlock
090: <tr><td>JavaInCExpression <td>= <td>JeannieJava.UnaryExpression
091: <tr><td>JavaInCStatement <td>= <td>TryStatement / SynchronizedStatement / ThrowStatement
092: <tr><td>JavaInJavaBlock <td>= <td>JeannieJava.DeclarationOrStatement*
093: <tr><td>JavaThrows <td>= <td>[ThrowsClause]
094: <tr><td>JavaType <td>= <td>QualifiedIdentifier
095: <tr><td>CancelStatement <td>= <td>JeannieC.PrimaryIdentifier
096: <tr><td>CommitStatement <td>= <td>JeannieC.PrimaryIdentifier
097: <tr><td>WithStatement <td>= <td>WithInitializer CInCBlock
098: <tr><td>WithInitializer <td>> <td>JeannieC.Declaration, JeannieC.AssignmentExpression
099: </table>
100:
101: @author Martin Hirzel
102: @version $Revision: 1.6 $
103: */
104: public class JeanniePrinter extends Visitor {
105: private static final class Context {
106: final Visitor _activePrinter;
107:
108: final TransitionKind _transitionKind;
109:
110: Context(final Visitor activePrinter,
111: final TransitionKind transitionKind) {
112: _activePrinter = activePrinter;
113: _transitionKind = transitionKind;
114: }
115: }
116:
117: private static final class JeannieCPrinter extends CPrinter {
118: JeannieCPrinter(final Printer p) {
119: super (p);
120: }
121:
122: public void endExpression(final int prec) {
123: super .endExpression(prec);
124: }
125:
126: public int startExpression(final int prec) {
127: return super .startExpression(prec);
128: }
129: }
130:
131: private static final class JeannieJPrinter extends JavaPrinter {
132: JeannieJPrinter(final Printer p) {
133: super (p);
134: }
135:
136: public void endExpression(final int prec) {
137: super .endExpression(prec);
138: }
139:
140: public int startExpression(final int prec) {
141: return super .startExpression(prec);
142: }
143: }
144:
145: enum TransitionKind {
146: SILENT, SHORT, LONG
147: }
148:
149: protected final Printer _printer;
150:
151: private final Stack<Context> _stack;
152:
153: private final JeannieCPrinter _cPrinter;
154:
155: private final JeannieJPrinter _jPrinter;
156:
157: public JeanniePrinter(final Printer printer, final String language) {
158: _printer = printer;
159: _cPrinter = new JeannieCPrinter(printer);
160: _jPrinter = new JeannieJPrinter(printer);
161: printer.register(this );
162: _stack = new Stack<Context>();
163: if ("C".equals(language))
164: enterC(TransitionKind.SILENT);
165: if ("Java".equals(language))
166: enterJava(TransitionKind.SILENT);
167: }
168:
169: private Visitor activePrinter() {
170: return _stack.isEmpty() ? null : _stack.peek()._activePrinter;
171: }
172:
173: final void enterC(final TransitionKind transitionKind) {
174: assert _cPrinter != activePrinter();
175: _stack.push(new Context(_cPrinter, transitionKind));
176: switch (transitionKind) {
177: case SILENT:
178: break;
179: case SHORT:
180: _printer.p('`');
181: break;
182: case LONG:
183: _printer.indent().p("`.C {");
184: break;
185: }
186: }
187:
188: final void enterJava(final TransitionKind transitionKind) {
189: assert _jPrinter != activePrinter();
190: _stack.push(new Context(_jPrinter, transitionKind));
191: switch (transitionKind) {
192: case SILENT:
193: break;
194: case SHORT:
195: _printer.p('`');
196: break;
197: case LONG:
198: _printer.indent().p("`.Java {");
199: break;
200: }
201: }
202:
203: final void exitC() {
204: assert _cPrinter == activePrinter();
205: final Context old = _stack.pop();
206: if (TransitionKind.LONG == old._transitionKind)
207: _printer.p("}");
208: }
209:
210: final void exitJava() {
211: assert _jPrinter == activePrinter();
212: final Context old = _stack.pop();
213: if (TransitionKind.LONG == old._transitionKind)
214: _printer.p("}");
215: }
216:
217: public final void visit(final Node n) {
218: activePrinter().dispatch(n);
219: }
220:
221: /** Visit a Block > JavaInJavaBlock, CInJavaBlock. */
222: public final void visitBlock(final GNode n) {
223: assert _jPrinter == activePrinter();
224: assert null == n;
225: }
226:
227: /** Visit a CancelStatement = JeannieC.PrimaryIdentifier. */
228: public final void visitCancelStatement(final GNode n) {
229: assert _cPrinter == activePrinter();
230: _printer.p("_cancel ").p(n.getNode(0)).p(";");
231: }
232:
233: /** Visit a CDeclarations = ExternalDeclaration*. */
234: public final void visitCDeclarations(final GNode n) {
235: enterC(TransitionKind.LONG);
236: for (int i = 0; i < n.size(); i++)
237: dispatch(n.getNode(i));
238: exitC();
239: }
240:
241: /** Visit a CInCBlock = LocalLabelDeclaration* JeannieC.DeclarationOrStatement* Annotations. */
242: public final void visitCInCBlock(final GNode n) {
243: assert _cPrinter == activePrinter();
244: _cPrinter.visitCompoundStatement(n);
245: }
246:
247: /** Visit a CInJavaBlock = CInCBlock. */
248: public final void visitCInJavaBlock(final GNode n) {
249: enterC(TransitionKind.SHORT);
250: dispatch(n.getNode(0));
251: exitC();
252: }
253:
254: /** Visit a CInJavaExpression = JeannieC.UnaryExpression. */
255: public final void visitCInJavaExpression(final GNode n) {
256: enterC(TransitionKind.SHORT);
257: final int prec = _cPrinter.startExpression(150);
258: dispatch(n.getNode(0));
259: _cPrinter.endExpression(prec);
260: exitC();
261: }
262:
263: /** Visit a CommitStatement = JeannieC.PrimaryIdentifier. */
264: public final void visitCommitStatement(final GNode n) {
265: assert _cPrinter == activePrinter();
266: _printer.p("_commit ").p(n.getNode(0)).p(";");
267: }
268:
269: /** Visit a CompilationUnit = CDeclarations [PackageDeclaration] ImportDeclaration* JeannieJava.Declaration*. */
270: public final void visitCompilationUnit(final GNode n) {
271: assert null == activePrinter();
272: enterJava(TransitionKind.SILENT);
273: activePrinter().dispatch(n);
274: exitJava();
275: }
276:
277: /** Visit a CompoundStatement > CInCBlock, JavaInCBlock. */
278: public final void visitCompoundStatement(final GNode n) {
279: assert null == n;
280: }
281:
282: /** Visit a File > TranslationUnit, CompilationUnit. */
283: public final void visitFile(final GNode n) {
284: assert null == n;
285: }
286:
287: /** Visit a FunctionDeclarator = (ParameterTypeList / IdentifierList) JavaThrows. */
288: public final void visitFunctionDeclarator(final GNode n) {
289: assert _cPrinter == activePrinter();
290: _cPrinter.dispatch(n);
291: dispatch(n.getNode(2));
292: }
293:
294: /** Visit a JavaImports = ImportDeclaration*. */
295: public final void visitJavaImports(final GNode n) {
296: enterJava(TransitionKind.LONG);
297: for (int i = 0; i < n.size(); i++)
298: dispatch(n.getNode(i));
299: exitJava();
300: }
301:
302: /** Visit a JavaInCBlock = JavaInJavaBlock. */
303: public final void visitJavaInCBlock(final GNode n) {
304: enterJava(TransitionKind.SHORT);
305: dispatch(n.getNode(0));
306: exitJava();
307: }
308:
309: /** Visit a JavaInCExpression = JeannieJava.UnaryExpression. */
310: public final void visitJavaInCExpression(final GNode n) {
311: enterJava(TransitionKind.SHORT);
312: final int prec = _jPrinter.startExpression(150);
313: dispatch(n.getNode(0));
314: _jPrinter.endExpression(prec);
315: exitJava();
316: }
317:
318: /** Visit a JavaInCStatement = TryStatement / SynchronizedStatement / ThrowStatement. */
319: public final void visitJavaInCStatement(final GNode n) {
320: enterJava(TransitionKind.SHORT);
321: dispatch(n.getNode(0));
322: exitJava();
323: }
324:
325: /** Visit a JavaInJavaBlock = JeannieJava.DeclarationOrStatement*. */
326: public final void visitJavaInJavaBlock(final GNode n) {
327: assert _jPrinter == activePrinter();
328: _jPrinter.visitBlock(n);
329: }
330:
331: /** Visit a JavaThrows = [ThrowsClause]. */
332: public final void visitJavaThrows(final GNode n) {
333: if (null == n.get(0))
334: return;
335: enterJava(TransitionKind.SHORT);
336: dispatch(n.getNode(0));
337: exitJava();
338: }
339:
340: /** Visit a JavaType = QualifiedIdentifier. */
341: public final void visitJavaType(final GNode n) {
342: enterJava(TransitionKind.SHORT);
343: dispatch(n.getNode(0));
344: exitJava();
345: }
346:
347: /** Visit a TranslationUnit = [JavaImports] ExternalDeclaration* Annotations. */
348: public final void visitTranslationUnit(final GNode n) {
349: assert null == activePrinter();
350: enterC(TransitionKind.SILENT);
351: activePrinter().dispatch(n);
352: exitC();
353: }
354:
355: /** Visit a WithStatement = (JeannieC.Declaration / JeannieC.AssignmentExpression) CInCBlock. */
356: public final void visitWithStatement(final GNode n) {
357: assert _cPrinter == activePrinter();
358: _printer.p("_with (");
359: dispatch(n.getNode(0));
360: _printer.p(")");
361: dispatch(n.getNode(1));
362: }
363: }
|