~ubuntu-branches/debian/sid/eclipse-cdt/sid

« back to all changes in this revision

Viewing changes to core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/MacroDefinitionParser.java

  • Committer: Package Import Robot
  • Author(s): Jakub Adam
  • Date: 2011-10-06 21:15:04 UTC
  • mfrom: (1.1.4)
  • Revision ID: package-import@ubuntu.com-20111006211504-8dutmljjih0zikfv
Tags: 8.0.1-1
* New upstream release.
* Split the JNI packages into a separate architecture dependent
  package and made eclipse-cdt architecture independent.
* Install JNI libraries into multiarch aware location
* Bumped Standards-Version to 3.9.2.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*******************************************************************************
 
2
 * Copyright (c) 2007, 2009 Wind River Systems, Inc. and others.
 
3
 * All rights reserved. This program and the accompanying materials
 
4
 * are made available under the terms of the Eclipse Public License v1.0
 
5
 * which accompanies this distribution, and is available at
 
6
 * http://www.eclipse.org/legal/epl-v10.html
 
7
 *
 
8
 * Contributors:
 
9
 *    Markus Schorn - initial API and implementation
 
10
 *******************************************************************************/ 
 
11
package org.eclipse.cdt.internal.core.parser.scanner;
 
12
 
 
13
import java.util.ArrayList;
 
14
 
 
15
import org.eclipse.cdt.core.parser.IProblem;
 
16
import org.eclipse.cdt.core.parser.IToken;
 
17
import org.eclipse.cdt.core.parser.Keywords;
 
18
import org.eclipse.cdt.core.parser.OffsetLimitReachedException;
 
19
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
 
20
import org.eclipse.cdt.internal.core.parser.scanner.Lexer.LexerOptions;
 
21
 
 
22
/**
 
23
 * Utility to parse macro definitions and create the macro objects for the preprocessor.
 
24
 * @since 5.0
 
25
 */
 
26
public class MacroDefinitionParser {
 
27
        private static final int ORIGIN_PREPROCESSOR_DIRECTIVE = OffsetLimitReachedException.ORIGIN_PREPROCESSOR_DIRECTIVE;
 
28
 
 
29
        /**
 
30
         * Exception for reporting problems while parsing a macro definition.
 
31
         */
 
32
        static class InvalidMacroDefinitionException extends Exception {
 
33
                public char[] fName;
 
34
                public int fStartOffset;
 
35
                public int fEndOffset;
 
36
                public InvalidMacroDefinitionException(char[] name, int startOffset, int endOffset) {
 
37
                        fName= name;
 
38
                        fStartOffset= startOffset;
 
39
                        fEndOffset= endOffset;
 
40
                }
 
41
        }
 
42
 
 
43
        /**
 
44
         * Token used for macro parameters found in the replacement list.
 
45
         */
 
46
        static class TokenParameterReference extends TokenWithImage {
 
47
                private final int fIndex;
 
48
        
 
49
                public TokenParameterReference(int type, int idx, Object source, int offset, int endOffset, char[] name) {
 
50
                        super(type, source, offset, endOffset, name);
 
51
                        fIndex= idx;
 
52
                }
 
53
        
 
54
                public int getIndex() {
 
55
                        return fIndex;
 
56
                }
 
57
                
 
58
                @Override
 
59
                public String toString() {
 
60
                        return "[" + fIndex + "]";  //$NON-NLS-1$ //$NON-NLS-2$
 
61
                }
 
62
        }
 
63
        
 
64
        public static char[] getExpansion(AbstractCharArray expansionImage, int offset, int endOffset) {
 
65
                TokenList tl= new TokenList();
 
66
                Lexer lex= new Lexer(expansionImage, offset, endOffset, new LexerOptions(), ILexerLog.NULL, null);
 
67
                try {
 
68
                        lex.nextToken(); // consume the start token
 
69
                        new MacroDefinitionParser().parseExpansion(lex, ILexerLog.NULL, null, new char[][]{}, tl);
 
70
                } catch (OffsetLimitReachedException e) {
 
71
                }
 
72
 
 
73
                StringBuffer buf= new StringBuffer();
 
74
                Token t= tl.first();
 
75
                if (t == null) {
 
76
                        return CharArrayUtils.EMPTY;
 
77
                }
 
78
                endOffset= t.getOffset();
 
79
                for (; t != null; t= (Token) t.getNext()) {
 
80
                        if (endOffset < t.getOffset()) {
 
81
                                buf.append(' ');
 
82
                        }
 
83
                        buf.append(t.getCharImage());
 
84
                        endOffset= t.getEndOffset();
 
85
                }
 
86
                final int length= buf.length(); 
 
87
                final char[] expansion= new char[length];
 
88
                buf.getChars(0, length, expansion, 0);
 
89
                return expansion;
 
90
        }
 
91
 
 
92
        private int fHasVarArgs;
 
93
        private int fExpansionOffset;
 
94
        private int fExpansionEndOffset;
 
95
        private Token fNameToken;
 
96
                
 
97
        MacroDefinitionParser() {
 
98
        }
 
99
        
 
100
        /**
 
101
         * In case the name was successfully parsed, the name token is returned.
 
102
         * Otherwise the return value is undefined.
 
103
         */
 
104
        public Token getNameToken() {
 
105
                return fNameToken;
 
106
        }
 
107
 
 
108
        /** 
 
109
         * Parses an entire macro definition. Name must be the next token of the lexer.
 
110
         */
 
111
        public ObjectStyleMacro parseMacroDefinition(final Lexer lexer, final ILexerLog log) 
 
112
                        throws OffsetLimitReachedException, InvalidMacroDefinitionException {
 
113
        final Token name = parseName(lexer);
 
114
        final AbstractCharArray source= lexer.getInput();
 
115
        final char[] nameChars= name.getCharImage();
 
116
        final char[][] paramList= parseParamList(lexer, name);
 
117
        final TokenList replacement= new TokenList();
 
118
        parseExpansion(lexer, log, nameChars, paramList, replacement);
 
119
        if (paramList == null) {
 
120
                return new ObjectStyleMacro(nameChars, fExpansionOffset, fExpansionEndOffset, replacement, source);
 
121
        }
 
122
        return new FunctionStyleMacro(nameChars, paramList, fHasVarArgs, fExpansionOffset, fExpansionEndOffset, replacement, source);
 
123
        }
 
124
 
 
125
        /** 
 
126
         * Parses a macro definition without the replacement. Name must be the next token of the lexer.
 
127
         */
 
128
        public PreprocessorMacro parseMacroDefinition(final Lexer lexer, final ILexerLog log, final char[] replacement) 
 
129
                        throws InvalidMacroDefinitionException, OffsetLimitReachedException {
 
130
                final Token name = parseName(lexer);
 
131
 
 
132
                final char[] nameChars = name.getCharImage();
 
133
                final char[][] paramList= parseParamList(lexer, name);
 
134
                final Token replacementToken = lexer.currentToken();
 
135
                if (replacementToken.getType() != IToken.tEND_OF_INPUT) {
 
136
                        throw new InvalidMacroDefinitionException(nameChars, replacementToken.getOffset(), replacementToken.getEndOffset());
 
137
                }
 
138
                
 
139
                if (paramList == null) { 
 
140
                        return new ObjectStyleMacro(nameChars, replacement);
 
141
                }
 
142
                return new FunctionStyleMacro(nameChars, paramList, fHasVarArgs, replacement);
 
143
        }
 
144
 
 
145
        /** 
 
146
         * Parses a macro definition basically checking for var-args.
 
147
         */
 
148
        public static PreprocessorMacro parseMacroDefinition(final char[] name, char[][] paramList, final char[] replacement) {
 
149
                int hasVarargs= 0;
 
150
                if (paramList != null) {
 
151
                        final int length = paramList.length;
 
152
                        if (length > 0) {
 
153
                                char[] lastParam= paramList[length-1];
 
154
                                final int lpl = lastParam.length;
 
155
                                switch(lpl) {
 
156
                                case 0: case 1: case 2:
 
157
                                        break;
 
158
                                case 3:
 
159
                                        if (CharArrayUtils.equals(lastParam, Keywords.cpELLIPSIS)) {
 
160
                                                hasVarargs= FunctionStyleMacro.VAARGS;
 
161
                                                char[][] copy= new char[length][];
 
162
                                                System.arraycopy(paramList, 0, copy, 0, length-1);
 
163
                                                copy[length-1]= Keywords.cVA_ARGS;
 
164
                                                paramList= copy;
 
165
                                        }
 
166
                                        break;
 
167
                                default:
 
168
                                        if (CharArrayUtils.equals(lastParam, lpl-3, 3, Keywords.cpELLIPSIS)) {
 
169
                                                hasVarargs= FunctionStyleMacro.NAMED_VAARGS;
 
170
                                                char[][] copy= new char[length][];
 
171
                                                System.arraycopy(paramList, 0, copy, 0, length-1);
 
172
                                                copy[length-1]= CharArrayUtils.subarray(lastParam, 0, lpl-3);
 
173
                                                paramList= copy;
 
174
                                        }
 
175
                                break;
 
176
                                }
 
177
                        }
 
178
                }
 
179
                
 
180
                if (paramList == null) { 
 
181
                        return new ObjectStyleMacro(name, replacement);
 
182
                }
 
183
                return new FunctionStyleMacro(name, paramList, hasVarargs, replacement);
 
184
        }
 
185
 
 
186
        private Token parseName(final Lexer lexer) throws OffsetLimitReachedException,  InvalidMacroDefinitionException {
 
187
                final Token name= lexer.nextToken();
 
188
        final int tt= name.getType();
 
189
        if (tt != IToken.tIDENTIFIER) {
 
190
                if (tt == IToken.tCOMPLETION) {
 
191
                        throw new OffsetLimitReachedException(ORIGIN_PREPROCESSOR_DIRECTIVE, name);
 
192
                }
 
193
                throw new InvalidMacroDefinitionException(name.getCharImage(), name.getOffset(), name.getEndOffset());
 
194
        }
 
195
        fNameToken= name;
 
196
                return name;
 
197
        }
 
198
        
 
199
        private char[][] parseParamList(Lexer lex, final Token name) throws OffsetLimitReachedException, InvalidMacroDefinitionException {
 
200
            final Token lparen= lex.nextToken();
 
201
                fHasVarArgs= FunctionStyleMacro.NO_VAARGS;
 
202
                if (lparen.getType() != IToken.tLPAREN || name.getEndOffset() != lparen.getOffset()) { 
 
203
                        return null;
 
204
                }
 
205
                ArrayList<char[]> paramList= new ArrayList<char[]>();
 
206
                IToken next= null;
 
207
                do {
 
208
                        final Token param= lex.nextToken();
 
209
                        switch (param.getType()) {
 
210
                        case IToken.tCOMPLETION:
 
211
                                throw new OffsetLimitReachedException(ORIGIN_PREPROCESSOR_DIRECTIVE, param);
 
212
 
 
213
                        case IToken.tIDENTIFIER:
 
214
                                paramList.add(param.getCharImage());
 
215
                                next= lex.nextToken();
 
216
                                if (next.getType() == IToken.tELLIPSIS) {
 
217
                                        fHasVarArgs= FunctionStyleMacro.NAMED_VAARGS;
 
218
                                        next= lex.nextToken();
 
219
                                }
 
220
                                break;
 
221
 
 
222
                        case IToken.tELLIPSIS:
 
223
                                fHasVarArgs= FunctionStyleMacro.VAARGS;
 
224
                                paramList.add(Keywords.cVA_ARGS);
 
225
                                next= lex.nextToken();
 
226
                                break;
 
227
                                
 
228
                        case IToken.tRPAREN:
 
229
                                if (next == null) {
 
230
                                        next= param;
 
231
                                        break;
 
232
                                }
 
233
                                throw new InvalidMacroDefinitionException(name.getCharImage(), name.getOffset(), param.getEndOffset());
 
234
                        default:
 
235
                                throw new InvalidMacroDefinitionException(name.getCharImage(), name.getOffset(), param.getEndOffset());
 
236
                        }
 
237
                }
 
238
                while (fHasVarArgs==0 && next.getType() == IToken.tCOMMA);
 
239
                if (next.getType() != IToken.tRPAREN) {
 
240
                        throw new InvalidMacroDefinitionException(name.getCharImage(), name.getOffset(), next.getEndOffset());
 
241
                }
 
242
                next= lex.nextToken(); // consume the closing parenthesis
 
243
 
 
244
                return paramList.toArray(new char[paramList.size()][]);
 
245
        }
 
246
 
 
247
        /**
 
248
         * Parses the expansion for a macro, the current token must be the first token of the expansion
 
249
         * @since 5.0
 
250
         */
 
251
        public void parseExpansion(final Lexer lexer, final ILexerLog log, final char[] name, final char[][] paramList,
 
252
                        TokenList result) throws OffsetLimitReachedException {
 
253
                boolean needParam= false;
 
254
                boolean isFirst= true;
 
255
                Token needAnotherToken= null;
 
256
 
 
257
                Token candidate= lexer.currentToken();
 
258
                fExpansionOffset= fExpansionEndOffset= candidate.getOffset();           
 
259
 
 
260
                loop: while(true) {
 
261
                        switch(candidate.getType()) {
 
262
                        case IToken.tCOMPLETION:
 
263
                                throw new OffsetLimitReachedException(ORIGIN_PREPROCESSOR_DIRECTIVE, candidate);
 
264
                        case IToken.tEND_OF_INPUT:
 
265
                        case Lexer.tNEWLINE:
 
266
                                break loop;
 
267
                        case IToken.tIDENTIFIER:
 
268
                                if (paramList != null) {
 
269
                                        // convert the parameters to special tokens
 
270
                                        final char[] image = candidate.getCharImage();
 
271
                                        int idx= CharArrayUtils.indexOf(image, paramList);
 
272
                                        if (idx >= 0) {
 
273
                                                candidate= new TokenParameterReference(CPreprocessor.tMACRO_PARAMETER, idx, lexer.getSource(), candidate.getOffset(), candidate.getEndOffset(), paramList[idx]);
 
274
                                                needParam= false;
 
275
                                        }
 
276
                                        else {
 
277
                                                if (needParam) {
 
278
                                                        log.handleProblem(IProblem.PREPROCESSOR_MACRO_PASTING_ERROR, name, fExpansionOffset, candidate.getEndOffset());
 
279
                                                }
 
280
                                                else if (CharArrayUtils.equals(Keywords.cVA_ARGS, image)) {
 
281
                                                        log.handleProblem(IProblem.PREPROCESSOR_INVALID_VA_ARGS, null, fExpansionOffset, candidate.getEndOffset());
 
282
                                                }
 
283
                                                needParam= false;
 
284
                                        }
 
285
                                }
 
286
                                needAnotherToken= null;
 
287
                                break;
 
288
                        case IToken.tPOUND:
 
289
                                needParam= paramList != null;
 
290
                                needAnotherToken= null;
 
291
                                break;
 
292
                        case IToken.tPOUNDPOUND:
 
293
                                if (needParam || isFirst) {
 
294
                                        log.handleProblem(IProblem.PREPROCESSOR_MACRO_PASTING_ERROR, name, fExpansionOffset, candidate.getEndOffset());
 
295
                                }
 
296
                                needAnotherToken= candidate;
 
297
                                needParam= false;
 
298
                                break;
 
299
                        default:
 
300
                                if (needParam) {
 
301
                                        log.handleProblem(IProblem.PREPROCESSOR_MACRO_PASTING_ERROR, name, fExpansionOffset, candidate.getEndOffset());
 
302
                                        needParam= false;
 
303
                                }
 
304
                                needAnotherToken= null;
 
305
                                break;
 
306
                        }
 
307
                        isFirst= false;
 
308
                        fExpansionEndOffset= candidate.getEndOffset();
 
309
                        result.append(candidate);
 
310
                        candidate= lexer.nextToken();
 
311
                }
 
312
                if (needAnotherToken != null) {
 
313
                        log.handleProblem(IProblem.PREPROCESSOR_MACRO_PASTING_ERROR, name, needAnotherToken.getOffset(), needAnotherToken.getEndOffset());
 
314
                }
 
315
        }
 
316
}