001// 002// Generated by JTB 1.3.2 003// 004package jtb.visitor; 005 006import jtb.syntaxtree.*; 007import java.util.*; 008import java.io.*; 009 010// Dumps the syntax tree to a Writer using the location information in 011// each NodeToken. 012// If 'debug' is set, additionally output all tree nodes, non-terminals 013// terminal tokens alike, to the standard output. 014public class TreeDumper extends DepthFirstVisitor { 015 protected PrintWriter out; 016 private int curLine = 1; 017 private int curColumn = 1; 018 private boolean startAtNextToken = false; 019 private boolean printSpecials = true; 020 private boolean debug = false; 021 022 // The default constructor uses System.out as its output location. 023 // You may specify your own Writer or OutputStream using one of the 024 // other constructors. 025 public TreeDumper() { out = new PrintWriter(System.out, true); } 026 public TreeDumper(Writer o) { out = new PrintWriter(o, true); } 027 public TreeDumper(OutputStream o) { out = new PrintWriter(o, true); } 028 029 // debug constructors 030 public TreeDumper(boolean debug) { 031 out = new PrintWriter(System.out, true); 032 this.debug = debug; 033 super.debug = debug; 034 } 035 public TreeDumper(Writer o, boolean debug) { 036 out = new PrintWriter(o, true); 037 this.debug = debug; 038 super.debug = debug; 039 } 040 public TreeDumper(OutputStream o, boolean debug) { 041 out = new PrintWriter(o, true); 042 this.debug = debug; 043 super.debug = debug; 044 } 045 046 // Flushes the OutputStream or Writer that this TreeDumper is using. 047 public void flushWriter() { out.flush(); } 048 049 // Allows you to specify whether or not to print special tokens. 050 public void printSpecials(boolean b) { printSpecials = b; } 051 052 // Starts the tree dumper on the line containing the next token 053 // visited. For example, if the next token begins on line 50 and the 054 // dumper is currently on line 1 of the file, it will set its current 055 // line to 50 and continue printing from there, as opposed to 056 // printing 49 blank lines and then printing the token. 057 public void startAtNextToken() { startAtNextToken = true; } 058 059 // Resets the position of the output "cursor" to the first line and 060 // column. When using a dumper on a syntax tree more than once, you 061 // either need to call this method or startAtNextToken() between each 062 // dump. 063 public void resetPosition() { curLine = curColumn = 1; } 064 065 // Dumps the current NodeToken to the output stream being used. 066 // 067 // @throws IllegalStateException if the token position is invalid 068 // relative to the current position, i.e. its location places it 069 // before the previous token. 070 public void visit(NodeToken n) { 071 if (debug) System.out.println(super.indents.substring(0, super.indent) + "Token{" + n.kind +"}: " + n.tokenImage); 072 073 if ( n.beginLine == -1 || n.beginColumn == -1 ) { 074 printToken(n.tokenImage); 075 return; 076 } 077 078 // 079 // Handle special tokens 080 // 081 if ( printSpecials && n.numSpecials() > 0 ) 082 for ( Enumeration<NodeToken> e = n.specialTokens.elements(); e.hasMoreElements(); ) 083 visit(e.nextElement()); 084 085 // 086 // Handle startAtNextToken option 087 // 088 if ( startAtNextToken ) { 089 curLine = n.beginLine; 090 curColumn = 1; 091 startAtNextToken = false; 092 093 if ( n.beginColumn < curColumn ) 094 out.println(); 095 } 096 097 // 098 // Check for invalid token position relative to current position. 099 // 100 if ( n.beginLine < curLine ) 101 throw new IllegalStateException("at token \"" + n.tokenImage + 102 "\", n.beginLine = " + Integer.toString(n.beginLine) + 103 ", curLine = " + Integer.toString(curLine)); 104 else if ( n.beginLine == curLine && n.beginColumn < curColumn ) 105 throw new IllegalStateException("at token \"" + n.tokenImage + 106 "\", n.beginColumn = " + 107 Integer.toString(n.beginColumn) + ", curColumn = " + 108 Integer.toString(curColumn)); 109 110 // 111 // Move output "cursor" to proper location, then print the token 112 // 113 if ( curLine < n.beginLine ) { 114 curColumn = 1; 115 for ( ; curLine < n.beginLine; ++curLine ) 116 out.println(); 117 } 118 119 for ( ; curColumn < n.beginColumn; ++curColumn ) 120 out.print(" "); 121 122 printToken(n.tokenImage); 123 } 124 125 private void printToken(String s) { 126 for ( int i = 0; i < s.length(); ++i ) { 127 if ( s.charAt(i) == '\n' ) { 128 ++curLine; 129 curColumn = 1; 130 } 131 else 132 curColumn++; 133 134 out.print(s.charAt(i)); 135 } 136 137 out.flush(); 138 } 139}