> Another option I'm looking at is the JavaCC,
> which I would have to manually add in my own
> actions in the grammar to get the information (a
> bit too low level).
As part of some code generation and refactoring tools for a project,
I've been using JavaCC and its JJTree. The changes needed in the
grammar were very minor, after I figured out how to use JJTree. This
generates a visitor and a AST class for each production -- just what it
sounds like you wanted. To get this, I added the following four lines
to the grammer options:
options {
STATIC = false;
MULTI = true;
VISITOR = true;
NODE_USES_PARSER = true;
JAVA_UNICODE_ESCAPE = true;
}
I also changed CompilationUnit() to return an AST:
ASTCompilationUnit CompilationUnit() :
{}
{
[ PackageDeclaration() ]
( ImportDeclaration() )*
( TypeDeclaration() )*
<EOF>
{ return jjtThis; }
}
As a final change to the grammar, I changed white space from SKIP to
SPECIAL_TOKEN, so I could keep the tokens and use them when I write the
code back:
SPECIAL_TOKEN :
{
" "
| "\t"
| "\n"
| "\r"
| "\f"
}
Once I've run JJTree, and JavaCC against the .jj file from JJTree, I
modified the generated SimpleNode.java file to pick up the first and
last token of each production:
/**
* Called when the first token of the node is encountered.
*/
public void jjtOpen() {
firstToken = parser.getToken(1);
}
/**
* Called when the last token of the node is encountered.
*/
public void jjtClose() {
lastToken = parser.getToken(0);
}
/**
* Returns the first token associated with this node.
*/
public Token getFirstToken() {
return firstToken;
}
/**
* Returns the last token associated with this node.
*/
public Token getLastToken() {
return lastToken;
}
Now, we can create a visitor that uses the tokens. My first was the
following visitor. This a bit more than is necessary, since I could
have simply started with the first token of ASTCompilationUnit, and
iterated all the way to the last. But this provides some useful code,
from which I've created variations that reformat the code, replace
tokens, etc. I created a series of command beans to do this, but that
would be another story. Incidentally, the generated
JavaParserTokenManager is context-free, so you can parse just the body
of the method, if you wish. This too is another story.
public class JavaPrintVisitor implements JavaParserVisitor {
protected PrintWriter out;
public JavaPrintVisitor(PrintWriter out) {
this.out = out;
}
/**
* Scan through all tokens associated with this node
* and print them. Delegate to each child node to
* continue printing the tokens associated with the
* child nodes.
* @param node The visited node to be printed.
* @param data Additional data passed through visitation.
*/
public Object print(SimpleNode node, Object data) {
SimpleNode childNode;
Token stopToken;
Token token = node.getFirstToken();
int count = node.jjtGetNumChildren();
for (int i = 0; i < count; i++) {
childNode = (SimpleNode) node.jjtGetChild(i);
// Print each token until we reach the first token
// token that belongs to the selected child.
stopToken = childNode.getFirstToken();
while (token != stopToken) {
print(token);
token = token.next;
}
// Tell the child print itself.
childNode.jjtAccept(this, data);
// We'll be printing all tokens between this child
// and the first token of the next node.
token = childNode.getLastToken();
}
// Print the remaining tokens (if any)
stopToken = node.getLastToken();
while (token != stopToken) {
print(token);
token = token.next;
}
return data;
}
/**
* Print the token and all special tokens that preceed
* the specified token.
*/
protected void print(Token token) {
Token specialToken = token.specialToken;
if (specialToken != null) {
// Drill back to the first special token
while (specialToken.specialToken != null) {
specialToken = specialToken.specialToken;
}
// Print each successive special token
while (specialToken != null) {
print(specialToken.image);
specialToken = specialToken.next;
}
}
// Print the current token
print(token.image);
}
/**
* Escape any characters that are not part of the
* standard ascii character set.
*/
private void print(String str) {
char[] array = str.toCharArray();
char ch;
for (int i = 0; i < array.length; i++) {
ch = array[i];
if ((ch < 0x20 || ch > 0x7e) && ch != '\t' && ch != '\n' &&
ch != '\r' && ch != '\f') {
String val = Integer.toString(ch, 16);
out.print("\\u");
out.print("0000".substring(4 - val.length()));
out.print(val);
} else {
out.print(ch);
}
}
}
public Object visit(SimpleNode node, Object data) {
return print(node, data);
}
public Object visit(ASTCompilationUnit node, Object data) {
return print(node, data);
}
public Object visit(ASTMethodUnit node, Object data) {
return print(node, data);
}
...
}
Phillip E. DuLion
Technologist
CAP Gemini Ernst & Young, LLC.
____________________________________________________
To change your JDJList options, please visit:
http://www.sys-con.com/java/list.cfm
Be respectful! Clean up your posts before replying
____________________________________________________