1 /** 2 * Redistribution and use in source and binary forms, with or without 3 * modification, are permitted provided that the following conditions are 4 * met : 5 * 6 * . Redistributions of source code must retain the above copyright 7 * notice, this list of conditions and the following disclaimer. 8 * 9 * . Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * . The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 25 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 package cpptools.preprocessor; 30 31 import java.io.StringReader; 32 import java.util.ArrayList; 33 import java.util.List; 34 import java.util.Stack; 35 import cppast.JavaCharStream; 36 import cppast.ParserTokenManager; 37 import cppast.Token; 38 39 /** 40 * Captures filter common behaviours. 41 * 42 * @author Mathieu Champlon 43 */ 44 public abstract class AbstractTokenFilter implements TokenFilter 45 { 46 private final Stack<Token> buffer; 47 private final List<Token> tokens; 48 private final String name; 49 50 /** 51 * Create an abstract token filter. 52 * 53 * @param buffer the token stack where to output filtered tokens 54 * @param name the name of the filter 55 * @param value the raw value of the filtering result 56 */ 57 public AbstractTokenFilter( final Stack<Token> buffer, final String name, final String value ) 58 { 59 if( buffer == null ) 60 throw new IllegalArgumentException( "parameter 'buffer' is null" ); 61 if( name == null ) 62 throw new IllegalArgumentException( "parameter 'name' is null" ); 63 this.buffer = buffer; 64 this.name = check( name ); 65 this.tokens = parse( value ); 66 } 67 68 private String check( final String name ) 69 { 70 if( name.length() == 0 ) 71 throw new IllegalArgumentException( "Empty macro/define name specified" ); 72 final ParserTokenManager manager = new ParserTokenManager( new JavaCharStream( new StringReader( name ) ) ); 73 final Token token = manager.getNextToken(); 74 if( token.kind != ParserTokenManager.ID ) 75 throw new IllegalArgumentException( "Illegal macro/define name : " + "'" + name + "'" ); 76 final Token next = manager.getNextToken(); 77 if( next.kind != ParserTokenManager.EOF ) 78 throw new IllegalArgumentException( "Illegal macro/define name : " + "'" + name + "'" ); 79 return name; 80 } 81 82 private List<Token> parse( final String value ) 83 { 84 final List<Token> result = new ArrayList<Token>(); 85 final ParserTokenManager manager = new ParserTokenManager( new JavaCharStream( new StringReader( value ) ) ); 86 Token token = manager.getNextToken(); 87 while( token.kind != ParserTokenManager.EOF ) 88 { 89 result.add( 0, token ); 90 token = manager.getNextToken(); 91 } 92 return result; 93 } 94 95 /** 96 * Put both tokens back into the flow. 97 * 98 * @param token the head of the flow 99 * @param next the token following the head 100 */ 101 protected final void undo( final Token token, final Token next ) 102 { 103 buffer.push( next ); 104 buffer.push( token ); 105 } 106 107 /** 108 * Insert filtered tokens into the token flow. 109 * 110 * @param location the location of the insertion 111 */ 112 protected final void insert( final Token location ) 113 { 114 for( Token token : tokens ) 115 buffer.push( copy( token, location ) ); 116 } 117 118 private Token copy( final Token token, final Token location ) 119 { 120 final Token result = Token.newToken( token.kind ); 121 result.kind = token.kind; 122 result.beginColumn = location.beginColumn; 123 result.beginLine = location.beginLine; 124 result.endColumn = location.endColumn; 125 result.endLine = location.endLine; 126 result.image = token.image; 127 result.next = token.next; 128 result.specialToken = token.specialToken; 129 return result; 130 } 131 132 /** 133 * {@inheritDoc} 134 */ 135 public final boolean matches( final String name ) 136 { 137 return this.name.equals( name ); 138 } 139 }