/** * 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; }