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 }