Strip.java revision 324c4644fee44b9898524c09511bd33c3f12e2df
1/* 2 * [The "BSD license"] 3 * Copyright (c) 2010 Terence Parr 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29package org.antlr.tool; 30 31import org.antlr.grammar.v3.ANTLRv3Lexer; 32import org.antlr.grammar.v3.ANTLRv3Parser; 33import org.antlr.runtime.*; 34import org.antlr.runtime.tree.CommonTree; 35import org.antlr.runtime.tree.TreeAdaptor; 36import org.antlr.runtime.tree.TreeWizard; 37 38import java.util.List; 39 40/** A basic action stripper. */ 41public class Strip { 42 protected String filename; 43 protected TokenRewriteStream tokens; 44 protected boolean tree_option = false; 45 protected String args[]; 46 47 public static void main(String args[]) throws Exception { 48 Strip s = new Strip(args); 49 s.parseAndRewrite(); 50 System.out.println(s.tokens); 51 } 52 53 public Strip(String[] args) { this.args = args; } 54 55 public TokenRewriteStream getTokenStream() { return tokens; } 56 57 public void parseAndRewrite() throws Exception { 58 processArgs(args); 59 CharStream input = null; 60 if ( filename!=null ) input = new ANTLRFileStream(filename); 61 else input = new ANTLRInputStream(System.in); 62 // BUILD AST 63 ANTLRv3Lexer lex = new ANTLRv3Lexer(input); 64 tokens = new TokenRewriteStream(lex); 65 ANTLRv3Parser g = new ANTLRv3Parser(tokens); 66 ANTLRv3Parser.grammarDef_return r = g.grammarDef(); 67 CommonTree t = (CommonTree)r.getTree(); 68 if (tree_option) System.out.println(t.toStringTree()); 69 rewrite(g.getTreeAdaptor(),t,g.getTokenNames()); 70 } 71 72 public void rewrite(TreeAdaptor adaptor, CommonTree t, String[] tokenNames) throws Exception { 73 TreeWizard wiz = new TreeWizard(adaptor, tokenNames); 74 75 // ACTIONS STUFF 76 wiz.visit(t, ANTLRv3Parser.ACTION, 77 new TreeWizard.Visitor() { 78 public void visit(Object t) { ACTION(tokens, (CommonTree)t); } 79 }); 80 81 wiz.visit(t, ANTLRv3Parser.AT, // ^('@' id ACTION) rule actions 82 new TreeWizard.Visitor() { 83 public void visit(Object t) { 84 CommonTree a = (CommonTree)t; 85 CommonTree action = null; 86 if ( a.getChildCount()==2 ) action = (CommonTree)a.getChild(1); 87 else if ( a.getChildCount()==3 ) action = (CommonTree)a.getChild(2); 88 if ( action.getType()==ANTLRv3Parser.ACTION ) { 89 tokens.delete(a.getTokenStartIndex(), 90 a.getTokenStopIndex()); 91 killTrailingNewline(tokens, action.getTokenStopIndex()); 92 } 93 } 94 }); 95 wiz.visit(t, ANTLRv3Parser.ARG, // wipe rule arguments 96 new TreeWizard.Visitor() { 97 public void visit(Object t) { 98 CommonTree a = (CommonTree)t; 99 a = (CommonTree)a.getChild(0); 100 tokens.delete(a.token.getTokenIndex()); 101 killTrailingNewline(tokens, a.token.getTokenIndex()); 102 } 103 }); 104 wiz.visit(t, ANTLRv3Parser.RET, // wipe rule return declarations 105 new TreeWizard.Visitor() { 106 public void visit(Object t) { 107 CommonTree a = (CommonTree)t; 108 CommonTree ret = (CommonTree)a.getChild(0); 109 tokens.delete(a.token.getTokenIndex(), 110 ret.token.getTokenIndex()); 111 } 112 }); 113 wiz.visit(t, ANTLRv3Parser.SEMPRED, // comment out semantic predicates 114 new TreeWizard.Visitor() { 115 public void visit(Object t) { 116 CommonTree a = (CommonTree)t; 117 tokens.replace(a.token.getTokenIndex(), "/*"+a.getText()+"*/"); 118 } 119 }); 120 wiz.visit(t, ANTLRv3Parser.GATED_SEMPRED, // comment out semantic predicates 121 new TreeWizard.Visitor() { 122 public void visit(Object t) { 123 CommonTree a = (CommonTree)t; 124 String text = tokens.toString(a.getTokenStartIndex(), 125 a.getTokenStopIndex()); 126 tokens.replace(a.getTokenStartIndex(), 127 a.getTokenStopIndex(), 128 "/*"+text+"*/"); 129 } 130 }); 131 wiz.visit(t, ANTLRv3Parser.SCOPE, // comment scope specs 132 new TreeWizard.Visitor() { 133 public void visit(Object t) { 134 CommonTree a = (CommonTree)t; 135 tokens.delete(a.getTokenStartIndex(), 136 a.getTokenStopIndex()); 137 killTrailingNewline(tokens, a.getTokenStopIndex()); 138 } 139 }); 140 wiz.visit(t, ANTLRv3Parser.ARG_ACTION, // args r[x,y] -> ^(r [x,y]) 141 new TreeWizard.Visitor() { 142 public void visit(Object t) { 143 CommonTree a = (CommonTree)t; 144 if ( a.getParent().getType()==ANTLRv3Parser.RULE_REF ) { 145 tokens.delete(a.getTokenStartIndex(), 146 a.getTokenStopIndex()); 147 } 148 } 149 }); 150 wiz.visit(t, ANTLRv3Parser.LABEL_ASSIGN, // ^('=' id ^(RULE_REF [arg])), ... 151 new TreeWizard.Visitor() { 152 public void visit(Object t) { 153 CommonTree a = (CommonTree)t; 154 if ( !a.hasAncestor(ANTLRv3Parser.OPTIONS) ) { // avoid options 155 CommonTree child = (CommonTree)a.getChild(0); 156 tokens.delete(a.token.getTokenIndex()); // kill "id=" 157 tokens.delete(child.token.getTokenIndex()); 158 } 159 } 160 }); 161 wiz.visit(t, ANTLRv3Parser.LIST_LABEL_ASSIGN, // ^('+=' id ^(RULE_REF [arg])), ... 162 new TreeWizard.Visitor() { 163 public void visit(Object t) { 164 CommonTree a = (CommonTree)t; 165 CommonTree child = (CommonTree)a.getChild(0); 166 tokens.delete(a.token.getTokenIndex()); // kill "id+=" 167 tokens.delete(child.token.getTokenIndex()); 168 } 169 }); 170 171 172 // AST STUFF 173 wiz.visit(t, ANTLRv3Parser.REWRITE, 174 new TreeWizard.Visitor() { 175 public void visit(Object t) { 176 CommonTree a = (CommonTree)t; 177 CommonTree child = (CommonTree)a.getChild(0); 178 int stop = child.getTokenStopIndex(); 179 if ( child.getType()==ANTLRv3Parser.SEMPRED ) { 180 CommonTree rew = (CommonTree)a.getChild(1); 181 stop = rew.getTokenStopIndex(); 182 } 183 tokens.delete(a.token.getTokenIndex(), stop); 184 killTrailingNewline(tokens, stop); 185 } 186 }); 187 wiz.visit(t, ANTLRv3Parser.ROOT, 188 new TreeWizard.Visitor() { 189 public void visit(Object t) { 190 tokens.delete(((CommonTree)t).token.getTokenIndex()); 191 } 192 }); 193 wiz.visit(t, ANTLRv3Parser.BANG, 194 new TreeWizard.Visitor() { 195 public void visit(Object t) { 196 tokens.delete(((CommonTree)t).token.getTokenIndex()); 197 } 198 }); 199 } 200 201 public static void ACTION(TokenRewriteStream tokens, CommonTree t) { 202 CommonTree parent = (CommonTree)t.getParent(); 203 int ptype = parent.getType(); 204 if ( ptype==ANTLRv3Parser.SCOPE || // we have special rules for these 205 ptype==ANTLRv3Parser.AT ) 206 { 207 return; 208 } 209 //System.out.println("ACTION: "+t.getText()); 210 CommonTree root = (CommonTree)t.getAncestor(ANTLRv3Parser.RULE); 211 if ( root!=null ) { 212 CommonTree rule = (CommonTree)root.getChild(0); 213 //System.out.println("rule: "+rule); 214 if ( !Character.isUpperCase(rule.getText().charAt(0)) ) { 215 tokens.delete(t.getTokenStartIndex(),t.getTokenStopIndex()); 216 killTrailingNewline(tokens, t.token.getTokenIndex()); 217 } 218 } 219 } 220 221 private static void killTrailingNewline(TokenRewriteStream tokens, int index) { 222 List all = tokens.getTokens(); 223 Token tok = (Token)all.get(index); 224 Token after = (Token)all.get(index+1); 225 String ws = after.getText(); 226 if ( ws.startsWith("\n") ) { 227 //System.out.println("killing WS after action"); 228 if ( ws.length()>1 ) { 229 int space = ws.indexOf(' '); 230 int tab = ws.indexOf('\t'); 231 if ( ws.startsWith("\n") && 232 space>=0 || tab>=0 ) 233 { 234 return; // do nothing if \n + indent 235 } 236 // otherwise kill all \n 237 ws = ws.replaceAll("\n", ""); 238 tokens.replace(after.getTokenIndex(), ws); 239 } 240 else { 241 tokens.delete(after.getTokenIndex()); 242 } 243 } 244 } 245 246 public void processArgs(String[] args) { 247 if ( args==null || args.length==0 ) { 248 help(); 249 return; 250 } 251 for (int i = 0; i < args.length; i++) { 252 if (args[i].equals("-tree")) tree_option = true; 253 else { 254 if (args[i].charAt(0) != '-') { 255 // Must be the grammar file 256 filename = args[i]; 257 } 258 } 259 } 260 } 261 262 private static void help() { 263 System.err.println("usage: java org.antlr.tool.Strip [args] file.g"); 264 System.err.println(" -tree print out ANTLR grammar AST"); 265 } 266 267} 268