/** Expects that the identifier has been consumed. */ private Token parseArguments( TokenSource input, FunctionStyleMacro macro, IdentityHashMap<PreprocessorMacro, PreprocessorMacro> forbidden, TokenSource[] result, MacroExpansionTracker tracker) throws OffsetLimitReachedException, AbortMacroExpansionException { final int argCount = macro.getParameterPlaceholderList().length; final boolean hasVarargs = macro.hasVarArgs() != FunctionStyleMacro.NO_VAARGS; final int requiredArgs = hasVarargs ? argCount - 1 : argCount; int idx = 0; int nesting = -1; for (int i = 0; i < result.length; i++) { result[i] = new TokenSource(null); } boolean missingRParenthesis = false; boolean tooManyArgs = false; boolean isFirstOfArg = true; Token lastToken = null; TokenList spaceMarkers = new TokenList(); loop: while (true) { Token t = input.fetchFirst(); if (t == null) { missingRParenthesis = true; break loop; } if (tracker != null) { switch (t.getType()) { case IToken.tEND_OF_INPUT: case IToken.tCOMPLETION: case ObjCPreprocessor.tSCOPE_MARKER: case Lexer.tNEWLINE: break; default: tracker.addFunctionStyleMacroExpansionToken((Token) t.clone()); break; } } lastToken = t; switch (t.getType()) { case IToken.tEND_OF_INPUT: assert nesting >= 0; if (fCompletionMode) { if (idx < result.length) { throw new CompletionInMacroExpansionException(ORIGIN, t, result[idx]); } throw new OffsetLimitReachedException(ORIGIN, null); } missingRParenthesis = true; break loop; case IToken.tCOMPLETION: if (idx < result.length) { result[idx].append(t); throw new CompletionInMacroExpansionException(ORIGIN, t, result[idx]); } throw new OffsetLimitReachedException(ORIGIN, t); case Lexer.tNEWLINE: continue loop; case IToken.tLPAREN: // the first one sets nesting to zero. if (++nesting == 0) { continue; } break; case IToken.tRPAREN: assert nesting >= 0; if (--nesting < 0) { break loop; } break; case IToken.tCOMMA: assert nesting >= 0; if (nesting == 0) { if (idx < argCount - 1) { // next argument isFirstOfArg = true; spaceMarkers.clear(); idx++; continue loop; } else if (!hasVarargs) { tooManyArgs = true; break loop; } } break; case ObjCPreprocessor.tSCOPE_MARKER: if (argCount == 0) { ((ExpansionBoundary) t).execute(forbidden); } else { result[idx].append(t); } continue loop; case ObjCPreprocessor.tSPACE: case ObjCPreprocessor.tNOSPACE: if (!isFirstOfArg) { spaceMarkers.append(t); } continue loop; default: assert nesting >= 0; } if (argCount == 0) { tooManyArgs = true; break loop; } result[idx].appendAll(spaceMarkers); result[idx].append(t); isFirstOfArg = false; } if (missingRParenthesis) { handleProblem(IProblem.PREPROCESSOR_MISSING_RPAREN_PARMLIST, macro.getNameCharArray()); throw new AbortMacroExpansionException(); } if (tooManyArgs) { handleProblem(IProblem.PREPROCESSOR_MACRO_USAGE_ERROR, macro.getNameCharArray()); } else if (idx + 1 < requiredArgs) { handleProblem(IProblem.PREPROCESSOR_MACRO_USAGE_ERROR, macro.getNameCharArray()); } return lastToken; }