private void executeScopeMarkers( TokenSource input, IdentityHashMap<PreprocessorMacro, PreprocessorMacro> forbidden) { Token t = input.removeFirst(); while (t != null) { if (t.getType() == ObjCPreprocessor.tSCOPE_MARKER) { ((ExpansionBoundary) t).execute(forbidden); } t = input.removeFirst(); } }
/** * Method for tracking macro expansions. * * @since 5.0 */ public void expand( String beforeExpansion, MacroExpansionTracker tracker, String filePath, int lineNumber, boolean protectDefinedConstructs) { fImplicitMacroExpansions.clear(); fImageLocationInfos.clear(); fFixedInput = beforeExpansion.toCharArray(); fFixedCurrentFilename = filePath; fFixedLineNumber = lineNumber; Lexer lexer = new Lexer(fFixedInput, fLexOptions, fLog, this); try { tracker.start(lexer); Token identifier = lexer.nextToken(); if (identifier.getType() != IToken.tIDENTIFIER) { tracker.fail(); return; } PreprocessorMacro macro = fDictionary.get(identifier.getCharImage()); if (macro == null) { tracker.fail(); return; } lexer.nextToken(); fStartOffset = identifier.getOffset(); fEndOffset = identifier.getEndOffset(); fCompletionMode = false; IdentityHashMap<PreprocessorMacro, PreprocessorMacro> forbidden = new IdentityHashMap<PreprocessorMacro, PreprocessorMacro>(); // setup input sequence TokenSource input = new TokenSource(lexer); TokenList firstExpansion = new TokenList(); firstExpansion.append(new ExpansionBoundary(macro, true)); expandOne(identifier, macro, forbidden, input, firstExpansion, tracker); firstExpansion.append(new ExpansionBoundary(macro, false)); input.prepend(firstExpansion); TokenList result = expandAll(input, forbidden, protectDefinedConstructs, tracker); tracker.finish(result, fEndOffset); } catch (OffsetLimitReachedException e) { } }
/** Expects that the identifier has been consumed, stores the result in the list provided. */ public TokenList expand( ITokenSequence lexer, final boolean isPPCondition, PreprocessorMacro macro, Token identifier, boolean completionMode) throws OffsetLimitReachedException { fImplicitMacroExpansions.clear(); fImageLocationInfos.clear(); fStartOffset = identifier.getOffset(); fEndOffset = identifier.getEndOffset(); fCompletionMode = completionMode; IdentityHashMap<PreprocessorMacro, PreprocessorMacro> forbidden = new IdentityHashMap<PreprocessorMacro, PreprocessorMacro>(); // setup input sequence TokenSource input = new TokenSource(lexer); TokenList firstExpansion = new TokenList(); TokenList result; try { firstExpansion.append(new ExpansionBoundary(macro, true)); expandOne(identifier, macro, forbidden, input, firstExpansion, null); firstExpansion.append(new ExpansionBoundary(macro, false)); input.prepend(firstExpansion); result = expandAll(input, forbidden, isPPCondition, null); } catch (CompletionInMacroExpansionException e) { // for content assist in macro expansions, we return the list of // tokens of the // parameter at the current cursor position and hope that they make // sense if // they are inserted at the position of the expansion. // For a better solution one would have to perform the expansion // with artificial // parameters and then check where the completion token ends up in // the expansion. result = e.getParameterTokens().cloneTokens(); } postProcessTokens(result); return result; }
/** add n elements to buffer */ protected void fetch(int n) { for (int i = 1; i <= n; i++) { Token t = tokenSource.nextToken(); t.setTokenIndex(tokens.size()); // System.out.println("adding "+t+" at index "+tokens.size()); tokens.add(t); if (t.getType() == Token.EOF) break; } }
/** 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; }
/** * 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; }
private TokenList expandAll( TokenSource input, IdentityHashMap<PreprocessorMacro, PreprocessorMacro> forbidden, boolean protectDefinedConstructs, MacroExpansionTracker tracker) throws OffsetLimitReachedException { final TokenList result = new TokenList(); boolean protect = false; Token l = null; Token t = input.removeFirst(); while (t != null) { switch (t.getType()) { case ObjCPreprocessor.tSCOPE_MARKER: ((ExpansionBoundary) t).execute(forbidden); break; case IToken.tIDENTIFIER: final char[] image = t.getCharImage(); PreprocessorMacro macro = fDictionary.get(image); if (protect || (tracker != null && tracker.isDone())) { result.append(t); } else if (protectDefinedConstructs && Arrays.equals(image, Keywords.cDEFINED)) { t.setType(ObjCPreprocessor.tDEFINED); result.append(t); protect = true; } // tricky: don't mark function-style macros if you don't // find the left parenthesis else if (macro == null || (macro.isFunctionStyle() && !input.findLParenthesis())) { result.append(t); } else if (forbidden.containsKey(macro)) { t.setType(ObjCPreprocessor.tEXPANDED_IDENTIFIER); // prevent // any // further // expansion result.append(t); } else { if (fLocationMap != null) { ImageLocationInfo info = null; if (fLexOptions.fCreateImageLocations) { info = createImageLocationInfo(t); } fImplicitMacroExpansions.add( fLocationMap.encounterImplicitMacroExpansion(macro, info)); } TokenList replacement = new TokenList(); addSpacemarker(l, t, replacement); // start expansion replacement.append(new ExpansionBoundary(macro, true)); Token last = expandOne(t, macro, forbidden, input, replacement, tracker); replacement.append(new ExpansionBoundary(macro, false)); addSpacemarker(last, input.first(), replacement); // end // expansion input.prepend(replacement); } break; case IToken.tLPAREN: case ObjCPreprocessor.tNOSPACE: case ObjCPreprocessor.tSPACE: result.append(t); break; default: protect = false; result.append(t); break; } l = t; t = input.removeFirst(); } return result; }
public String getSourceName() { return tokenSource.getSourceName(); }