OLD
DOCUMENTATION
Documentation for JTB Pre-Release Versions
This section details the new features of JTB found in versions cumulatively
through 1.1pre3.
JTB 1.1pre1 adds a new option in addition to the ones described
above. The main change with this version of JTB is the addition of
a syntax tree builder for the Scheme programming language. The command-line
option -scheme does two things:
-
Generates records.scm to the current directory. This file
is analgous to the syntaxtree directory in that it defines the
syntax tree. The difference is that this file contains Scheme record
definitions as opposed to Java classes.
-
Generates the visitor SchemeTreeBuilder.java into the visitor
directory and package. This visitor will traverse a syntax tree and
output the Scheme equivalent of the tree. The default output location
is standard output, but this can be modified by passing the constructor
a Java Writer object.
Several constraints must be placed on a JavaCC grammar if the Scheme option
is to be used:
-
Choices such as ( x | y ) may only occur at the top level of a
production. The choice may only be between two nonterminal symbols.
For example, ( x y | z ) would be illegal.
-
Whatever goes within a list, optional list, or optional, such as (
x )+, ( y )*, or [ z ] may only be a single nonterminal
symbol. For example, [ x y ] would be illegal.
JTB 1.1pre2 adds the much requested feature of being able to store
JavaCC special tokens (which commonly represent comments in many grammars)
in the JTB parse tree. To do this, simply use the command-line option
-tk. This will cause JTB to generate the code necessary to store
and retrieve special tokens in the tree.
-
The special token will be stored in the in the next NodeToken
that occurs in the input. Should several special tokens appear in
the input prior to a regular token, the NodeToken representing
that token will contain each of those special tokens.
-
The NodeToken class has been modified to accomodate this new feature.
Its new interface is as follows:
//***Note these methods have changed for version 1.1pre3***
public class NodeToken implements Node {
public NodeToken(String s);
public int numSpecials();
public String getSpecialAt(int i);
public void addSpecial(String s);
public void trimSpecials();
public String toString();
public String withSpecials();
public void accept(visitor.Visitor v);
public String tokenImage;
}
numSpecials() and getSpecialAt() are used to access the
specials in the NodeToken.
addSpecial() and trimSpecials() are used when the tree
is being built. The programmer probably won't need to use these methods.
toString() returns the string of the regular token.
withSpecials() works like toString(), but it preceeds
the regular token with all the special tokens. If the special tokens
need special formatting, it would be best to override the visit(NodeToken)
method in the visitor rather than altering this method.
JTB 1.1pre3 introduces an important change and a couple of new features
that were requested by users.
-
The Visitor class has been changed to an interface. A new
visitor named DepthFirstVisitor has been added to the list of
files JTB generates. It essentially duplicates functionality of the
Visitor class in previous versions of JTB (i.e. it visits all
the nodes of the tree in depth-first order).
-
This change breaks code written for versions of JTB prior to 1.1pre3.
In order to fix it, simply replace all occurances of Visitor with
DepthFirstVisitor.
-
NodeTokens now store the JavaCC Token fields beginLine,
endLine, beginColumn, and endColumn.
-
The specialToken field now stores a Vector of NodeTokens
rather than a Vector of Strings as it did in 1.1pre2.
The methods of NodeToken have been altered accordingly.
-
The command-line option -jd causes JTB to generate JavaDoc-friendly
comments. For example, a comment in the Visitor class which, in previous
versions, looked like this:
//
// f0 -> "class"
// f1 -> <IDENTIFIER>
// f2 -> [ "extends" Name() ]
// f3 -> [ "implements" NameList() ]
// f4 -> ClassBody()
//
Looks like this in 1.1pre3 when the -jd flag is used:
/**
* <PRE>
* f0 -> "class"
* f1 -> <IDENTIFIER>
* f2 -> [ "extends" Name() ]
* f3 -> [ "implements" NameList() ]
* f4 -> ClassBody()
* </PRE>
*/
JTB 1.1pre4 adds two new toolkit visitors for your convenience as
well as a command-line option -w to cause it not to overwrite
existing files. In addition, a new interface has been added
to the list of automatically generated classes. NodeList,
NodeListOptional, and NodeSequence now all implement
the NodeListInterface interface which defines the methods shared
between the three classes. This addition should have no effect on
existing code.
-
The visitor TreeDumper, when used on a syntax tree, will output
(to standard output or another OutputStream or Writer
of your choice) the tree based on the token location variables in each
NodeToken. If you use this visitor on an unmodified syntax
tree, it will print the tree out exactly as it was read in. It contains
several methods:
public void flushWriter() |
Flushes the OutputStream or Writer that TreeDumper is using
to output the syntax tree. |
public void printSpecials(boolean b) |
Allows you to specify whether or not to print special tokens. |
public void startAtNextToken() |
Starts the tree dumper on the line containing the next token visited.
For example, if the next token begins on line 50 and the dumper is currently
on line 1 of the file, it will set its current line to 50 and continue
printing from there, as opposed to printing 49 blank lines and then printing
the token. |
public void resetPosition() |
Resets the position of the internal "cursor" to the first line and
column. For example, if the interal cursor was at line twenty and
the next token begins on line twenty one, a single carriage return is output,
then the token. If resetPosition() is called, the interal
cursor will be reset to line 1. Twenty carriage returns would be
output, then the token.
When using a dumper on a syntax tree more than once, you either need
to call this method or startAtNextToken() between each dump. |
-
Using these methods, it is possible to only print certain parts of the
tree. For example, to only print method signatures in the Java grammar,
the following annonymous class could be used:
root.accept(new DepthFirstVisitor() {
public void visit(MethodDeclaration n) {
dumper.startAtNextToken();
n.f0.accept(dumper);
n.f1.accept(dumper);
n.f2.accept(dumper);
n.f3.accept(dumper);
// skip n.f4, the method body
System.out.println();
}
});
The TreeFormatter visitor is a skeleton pretty printer template.
It contains convenience methods to modify the token location information
in each NodeToken:
public TreeFormatter(int indentAmt,
int wrapWidth) |
Allows you to specify the number of spaces per indentation level and
the number of columns per line, after which tokens are wrapped to the next
line (the default constructor assumes an indentAmt of 3 and a
wrapWidth of 0, i.e. no line wrapping). |
protected void add(FormatCommand cmd) |
Use this method to add FormatCommands to the command queue
to be executed when the next token in the tree is visited. |
protected FormatCommand force(int i) |
A Force command inserts one or more line breaks and indents the next
line to the current indentation level. Without an argument, adds
just one line break. Use add(force()); |
protected FormatCommand indent() |
An Indent command increases the indentation level by one or more.
Without an argument, just adds one indent level. Use add(indent()); |
protected FormatCommand outdent() |
An Outdent command is the reverse of the Indent command: it reduces
the indentation level. Use add(outdent()); |
protected FormatCommand space() |
A Space command simply adds one or more spaces between tokens.
Without an argument, adds just just one space. Use add(space()); |
protected void processList(
NodeListInterface n, FormatCommand cmd) |
Visits each element of a NodeList, NodeListOptional,
or NodeSequence and inserts an optional FormatCommand
between each element (but not after the last one). |
-
For example, this is how the CompilationUnit visit() method looks
in the rewritten Java pretty printer example:
/**
* f0 -> [ PackageDeclaration() ]
* f1 -> ( ImportDeclaration() )*
* f2 -> ( TypeDeclaration() )*
* f3 -> <EOF>
*/
public void visit(CompilationUnit n) {
if ( n.f0.present() ) {
n.f0.accept(this);
add(force(2));
}
if ( n.f1.present() ) {
processList(n.f1, force());
add(force(2));
}
if ( n.f2.present() ) {
processList(n.f2, force(2));
add(force());
}
n.f3.accept(this);
}
Still have questions? Suggestions on improving this document?
Feel free to mail Wanjun Wang or
Jens Palsberg.
Back
Maintained by Wanjun Wang, wanjun@purdue.edu.
|
Created January 6, 1999.
Last modified June 26, 1999. |