blob: f41109019d41dc801a734b11a1fb6b559e9ea298 [file] [log] [blame]
/*
* [The "BSD license"]
* Copyright (c) 2010 Terence Parr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.antlr.tool;
import org.antlr.grammar.v3.ANTLRv3Lexer;
import org.antlr.grammar.v3.ANTLRv3Parser;
import org.antlr.runtime.*;
import org.antlr.runtime.tree.CommonTree;
import org.antlr.runtime.tree.TreeAdaptor;
import org.antlr.runtime.tree.TreeWizard;
import java.util.List;
/** A basic action stripper. */
public class Strip {
protected String filename;
protected TokenRewriteStream tokens;
protected boolean tree_option = false;
protected String args[];
public static void main(String args[]) throws Exception {
Strip s = new Strip(args);
s.parseAndRewrite();
System.out.println(s.tokens);
}
public Strip(String[] args) { this.args = args; }
public TokenRewriteStream getTokenStream() { return tokens; }
public void parseAndRewrite() throws Exception {
processArgs(args);
CharStream input;
if ( filename!=null ) input = new ANTLRFileStream(filename);
else input = new ANTLRInputStream(System.in);
// BUILD AST
ANTLRv3Lexer lex = new ANTLRv3Lexer(input);
tokens = new TokenRewriteStream(lex);
ANTLRv3Parser g = new ANTLRv3Parser(tokens);
ANTLRv3Parser.grammarDef_return r = g.grammarDef();
CommonTree t = r.getTree();
if (tree_option) System.out.println(t.toStringTree());
rewrite(g.getTreeAdaptor(),t,g.getTokenNames());
}
public void rewrite(TreeAdaptor adaptor, CommonTree t, String[] tokenNames) throws Exception {
TreeWizard wiz = new TreeWizard(adaptor, tokenNames);
// ACTIONS STUFF
wiz.visit(t, ANTLRv3Parser.ACTION,
new TreeWizard.Visitor() {
@Override
public void visit(Object t) { ACTION(tokens, (CommonTree)t); }
});
wiz.visit(t, ANTLRv3Parser.AT, // ^('@' id ACTION) rule actions
new TreeWizard.Visitor() {
@Override
public void visit(Object t) {
CommonTree a = (CommonTree)t;
CommonTree action = null;
if ( a.getChildCount()==2 ) action = (CommonTree)a.getChild(1);
else if ( a.getChildCount()==3 ) action = (CommonTree)a.getChild(2);
if ( action.getType()==ANTLRv3Parser.ACTION ) {
tokens.delete(a.getTokenStartIndex(),
a.getTokenStopIndex());
killTrailingNewline(tokens, action.getTokenStopIndex());
}
}
});
wiz.visit(t, ANTLRv3Parser.ARG, // wipe rule arguments
new TreeWizard.Visitor() {
@Override
public void visit(Object t) {
CommonTree a = (CommonTree)t;
a = (CommonTree)a.getChild(0);
tokens.delete(a.token.getTokenIndex());
killTrailingNewline(tokens, a.token.getTokenIndex());
}
});
wiz.visit(t, ANTLRv3Parser.RET, // wipe rule return declarations
new TreeWizard.Visitor() {
@Override
public void visit(Object t) {
CommonTree a = (CommonTree)t;
CommonTree ret = (CommonTree)a.getChild(0);
tokens.delete(a.token.getTokenIndex(),
ret.token.getTokenIndex());
}
});
wiz.visit(t, ANTLRv3Parser.SEMPRED, // comment out semantic predicates
new TreeWizard.Visitor() {
@Override
public void visit(Object t) {
CommonTree a = (CommonTree)t;
tokens.replace(a.token.getTokenIndex(), "/*"+a.getText()+"*/");
}
});
wiz.visit(t, ANTLRv3Parser.GATED_SEMPRED, // comment out semantic predicates
new TreeWizard.Visitor() {
@Override
public void visit(Object t) {
CommonTree a = (CommonTree)t;
String text = tokens.toString(a.getTokenStartIndex(),
a.getTokenStopIndex());
tokens.replace(a.getTokenStartIndex(),
a.getTokenStopIndex(),
"/*"+text+"*/");
}
});
wiz.visit(t, ANTLRv3Parser.SCOPE, // comment scope specs
new TreeWizard.Visitor() {
@Override
public void visit(Object t) {
CommonTree a = (CommonTree)t;
tokens.delete(a.getTokenStartIndex(),
a.getTokenStopIndex());
killTrailingNewline(tokens, a.getTokenStopIndex());
}
});
wiz.visit(t, ANTLRv3Parser.ARG_ACTION, // args r[x,y] -> ^(r [x,y])
new TreeWizard.Visitor() {
@Override
public void visit(Object t) {
CommonTree a = (CommonTree)t;
if ( a.getParent().getType()==ANTLRv3Parser.RULE_REF ) {
tokens.delete(a.getTokenStartIndex(),
a.getTokenStopIndex());
}
}
});
wiz.visit(t, ANTLRv3Parser.LABEL_ASSIGN, // ^('=' id ^(RULE_REF [arg])), ...
new TreeWizard.Visitor() {
@Override
public void visit(Object t) {
CommonTree a = (CommonTree)t;
if ( !a.hasAncestor(ANTLRv3Parser.OPTIONS) ) { // avoid options
CommonTree child = (CommonTree)a.getChild(0);
tokens.delete(a.token.getTokenIndex()); // kill "id="
tokens.delete(child.token.getTokenIndex());
}
}
});
wiz.visit(t, ANTLRv3Parser.LIST_LABEL_ASSIGN, // ^('+=' id ^(RULE_REF [arg])), ...
new TreeWizard.Visitor() {
@Override
public void visit(Object t) {
CommonTree a = (CommonTree)t;
CommonTree child = (CommonTree)a.getChild(0);
tokens.delete(a.token.getTokenIndex()); // kill "id+="
tokens.delete(child.token.getTokenIndex());
}
});
// AST STUFF
wiz.visit(t, ANTLRv3Parser.REWRITE,
new TreeWizard.Visitor() {
@Override
public void visit(Object t) {
CommonTree a = (CommonTree)t;
CommonTree child = (CommonTree)a.getChild(0);
int stop = child.getTokenStopIndex();
if ( child.getType()==ANTLRv3Parser.SEMPRED ) {
CommonTree rew = (CommonTree)a.getChild(1);
stop = rew.getTokenStopIndex();
}
tokens.delete(a.token.getTokenIndex(), stop);
killTrailingNewline(tokens, stop);
}
});
wiz.visit(t, ANTLRv3Parser.ROOT,
new TreeWizard.Visitor() {
@Override
public void visit(Object t) {
tokens.delete(((CommonTree)t).token.getTokenIndex());
}
});
wiz.visit(t, ANTLRv3Parser.BANG,
new TreeWizard.Visitor() {
@Override
public void visit(Object t) {
tokens.delete(((CommonTree)t).token.getTokenIndex());
}
});
}
public static void ACTION(TokenRewriteStream tokens, CommonTree t) {
CommonTree parent = (CommonTree)t.getParent();
int ptype = parent.getType();
if ( ptype==ANTLRv3Parser.SCOPE || // we have special rules for these
ptype==ANTLRv3Parser.AT )
{
return;
}
//System.out.println("ACTION: "+t.getText());
CommonTree root = (CommonTree)t.getAncestor(ANTLRv3Parser.RULE);
if ( root!=null ) {
CommonTree rule = (CommonTree)root.getChild(0);
//System.out.println("rule: "+rule);
if ( !Character.isUpperCase(rule.getText().charAt(0)) ) {
tokens.delete(t.getTokenStartIndex(),t.getTokenStopIndex());
killTrailingNewline(tokens, t.token.getTokenIndex());
}
}
}
private static void killTrailingNewline(TokenRewriteStream tokens, int index) {
List<? extends Token> all = tokens.getTokens();
Token tok = all.get(index);
Token after = all.get(index+1);
String ws = after.getText();
if ( ws.startsWith("\n") ) {
//System.out.println("killing WS after action");
if ( ws.length()>1 ) {
int space = ws.indexOf(' ');
int tab = ws.indexOf('\t');
if ( ws.startsWith("\n") &&
space>=0 || tab>=0 )
{
return; // do nothing if \n + indent
}
// otherwise kill all \n
ws = ws.replaceAll("\n", "");
tokens.replace(after.getTokenIndex(), ws);
}
else {
tokens.delete(after.getTokenIndex());
}
}
}
public void processArgs(String[] args) {
if ( args==null || args.length==0 ) {
help();
return;
}
for (int i = 0; i < args.length; i++) {
if (args[i].equals("-tree")) tree_option = true;
else {
if (args[i].charAt(0) != '-') {
// Must be the grammar file
filename = args[i];
}
}
}
}
private static void help() {
System.err.println("usage: java org.antlr.tool.Strip [args] file.g");
System.err.println(" -tree print out ANTLR grammar AST");
}
}