/* * [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 = null; 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 = (CommonTree)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() { public void visit(Object t) { ACTION(tokens, (CommonTree)t); } }); wiz.visit(t, ANTLRv3Parser.AT, // ^('@' id ACTION) rule actions new TreeWizard.Visitor() { 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() { 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() { 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() { 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() { 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() { 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() { 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() { 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() { 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() { 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() { public void visit(Object t) { tokens.delete(((CommonTree)t).token.getTokenIndex()); } }); wiz.visit(t, ANTLRv3Parser.BANG, new TreeWizard.Visitor() { 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 all = tokens.getTokens(); Token tok = (Token)all.get(index); Token after = (Token)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"); } }