private BitSet getParamUsage(PreprocessorMacro macro) { final BitSet result = new BitSet(); final TokenList replacement = macro.getTokens(fDefinitionParser, fLexOptions, this); Token l = null; Token n; for (Token t = replacement.first(); t != null; l = t, t = n) { n = (Token) t.getNext(); switch (t.getType()) { case ObjCPreprocessor.tMACRO_PARAMETER: int idx = 2 * ((TokenParameterReference) t).getIndex(); if (!isKind(n, IToken.tPOUNDPOUND)) { idx++; } result.set(idx); break; case IToken.tPOUND: if (isKind(n, ObjCPreprocessor.tMACRO_PARAMETER)) { idx = ((TokenParameterReference) n).getIndex(); result.set(2 * idx); t = n; n = (Token) n.getNext(); } break; case IToken.tPOUNDPOUND: if (isKind(n, ObjCPreprocessor.tMACRO_PARAMETER)) { idx = ((TokenParameterReference) n).getIndex(); // gcc-extension if (isKind(l, IToken.tCOMMA) && macro.hasVarArgs() != FunctionStyleMacro.NO_VAARGS && idx == macro.getParameterPlaceholderList().length - 1 && !isKind(n.getNext(), IToken.tPOUNDPOUND)) { result.set(2 * idx + 1); } else { result.set(2 * idx); } t = n; n = (Token) n.getNext(); } break; } } return result; }
/** * Expects that the identifier of the macro expansion has been consumed. Expands the macro * consuming tokens from the input (to read the parameters) and stores the resulting tokens * together with boundary markers in the result token list. Returns the last token of the * expansion. * * @throws AbortMacroExpansionException */ private Token expandOne( Token lastConsumed, PreprocessorMacro macro, IdentityHashMap<PreprocessorMacro, PreprocessorMacro> forbidden, TokenSource input, TokenList result, MacroExpansionTracker tracker) throws OffsetLimitReachedException { if (macro.isFunctionStyle()) { final int paramCount = macro.getParameterPlaceholderList().length; final TokenSource[] argInputs = new TokenSource[paramCount]; final BitSet paramUsage = getParamUsage(macro); if (tracker != null) { tracker.startFunctionStyleMacro((Token) lastConsumed.clone()); } try { lastConsumed = parseArguments(input, (FunctionStyleMacro) macro, forbidden, argInputs, tracker); } catch (AbortMacroExpansionException e) { // ignore this macro expansion for (int i = 0; i < argInputs.length; i++) { TokenSource argInput = argInputs[i]; executeScopeMarkers(argInput, forbidden); if (tracker != null) { tracker.setExpandedMacroArgument(null); } } if (tracker != null) { if (tracker.isRequestedStep()) { tracker.storeFunctionStyleMacroReplacement(macro, new TokenList(), result); } else if (tracker.isDone()) { tracker.appendFunctionStyleMacro(result); } tracker.endFunctionStyleMacro(); } return null; } TokenList[] clonedArgs = new TokenList[paramCount]; TokenList[] expandedArgs = new TokenList[paramCount]; for (int i = 0; i < paramCount; i++) { final TokenSource argInput = argInputs[i]; final boolean needCopy = paramUsage.get(2 * i); final boolean needExpansion = paramUsage.get(2 * i + 1); clonedArgs[i] = needCopy ? argInput.cloneTokens() : EMPTY_TOKEN_LIST; expandedArgs[i] = needExpansion ? expandAll(argInput, forbidden, false, tracker) : EMPTY_TOKEN_LIST; if (!needExpansion) { executeScopeMarkers(argInput, forbidden); } if (tracker != null) { tracker.setExpandedMacroArgument(needExpansion ? expandedArgs[i] : null); // make sure that the trailing arguments do not get // expanded. if (tracker.isDone()) { paramUsage.clear(); } } } if (tracker == null) { replaceArgs(macro, clonedArgs, expandedArgs, result); } else { if (tracker.isRequestedStep()) { TokenList replacement = new TokenList(); replaceArgs(macro, clonedArgs, expandedArgs, replacement); tracker.storeFunctionStyleMacroReplacement(macro, replacement, result); } else if (tracker.isDone()) { tracker.appendFunctionStyleMacro(result); } else { replaceArgs(macro, clonedArgs, expandedArgs, result); } tracker.endFunctionStyleMacro(); } } else { if (tracker == null) { objStyleTokenPaste(macro, result); } else { if (tracker.isRequestedStep()) { TokenList replacement = new TokenList(); objStyleTokenPaste(macro, replacement); tracker.storeObjectStyleMacroReplacement(macro, lastConsumed, replacement, result); } else { objStyleTokenPaste(macro, result); } tracker.endObjectStyleMacro(); } } return lastConsumed; }