private Token tokenpaste(Token arg1, Token arg2, PreprocessorMacro macro) { if (arg1 == null) { return arg2; } if (arg2 == null) { return arg1; } final char[] image1 = arg1.getCharImage(); final char[] image2 = arg2.getCharImage(); final int l1 = image1.length; final int l2 = image2.length; final char[] image = new char[l1 + l2]; System.arraycopy(image1, 0, image, 0, l1); System.arraycopy(image2, 0, image, l1, l2); Lexer lex = new Lexer(image, fLexOptions, ILexerLog.NULL, null); try { Token t1 = lex.nextToken(); Token t2 = lex.nextToken(); if (t1.getType() != IToken.tEND_OF_INPUT && t2.getType() == IToken.tEND_OF_INPUT) { t1.setOffset(arg1.getOffset(), arg2.getEndOffset()); return t1; } } catch (OffsetLimitReachedException e) { } handleProblem(IProblem.PREPROCESSOR_MACRO_PASTING_ERROR, macro.getNameCharArray()); return null; }
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; }
private void objStyleTokenPaste(PreprocessorMacro macro, TokenList result) { TokenList replacement = clone(macro.getTokens(fDefinitionParser, fLexOptions, this)); Token l = null; Token n; Token pasteArg1 = null; for (Token t = replacement.first(); t != null; l = t, t = n) { n = (Token) t.getNext(); switch (t.getType()) { case IToken.tPOUNDPOUND: if (pasteArg1 != null) { Token pasteArg2 = null; if (n != null) { pasteArg2 = n; n = (Token) n.getNext(); } t = tokenpaste(pasteArg1, pasteArg2, macro); if (t != null) { if (isKind(n, IToken.tPOUNDPOUND)) { pasteArg1 = t; } else { result.append(t); addSpacemarker(pasteArg2, n, result); // end // token // paste } } } break; default: if (isKind(n, IToken.tPOUNDPOUND)) { addSpacemarker(l, t, result); // start token paste pasteArg1 = t; } else { result.append(t); } break; } } }
private void replaceArgs( PreprocessorMacro macro, TokenList[] args, TokenList[] expandedArgs, TokenList result) { TokenList replacement = clone(macro.getTokens(fDefinitionParser, fLexOptions, this)); Token l = null; Token n; Token pasteArg1 = null; for (Token t = replacement.first(); t != null; l = t, t = n) { n = (Token) t.getNext(); switch (t.getType()) { case ObjCPreprocessor.tMACRO_PARAMETER: int idx = ((TokenParameterReference) t).getIndex(); if (idx < args.length) { // be defensive addSpacemarker(l, t, result); // start argument // replacement if (isKind(n, IToken.tPOUNDPOUND)) { TokenList arg = clone(args[idx]); pasteArg1 = arg.last(); if (pasteArg1 != null) { result.appendAllButLast(arg); addSpacemarker(result.last(), pasteArg1, result); // start // token // paste } } else { TokenList arg = clone(expandedArgs[idx]); result.appendAll(arg); addSpacemarker(t, n, result); // end argument // replacement } } break; case IToken.tPOUND: addSpacemarker(l, t, result); // start stringify StringBuilder buf = new StringBuilder(); buf.append('"'); if (isKind(n, ObjCPreprocessor.tMACRO_PARAMETER)) { idx = ((TokenParameterReference) n).getIndex(); if (idx < args.length) { // be defensive stringify(args[idx], buf); } t = n; n = (Token) n.getNext(); } buf.append('"'); final int length = buf.length(); final char[] image = new char[length]; buf.getChars(0, length, image, 0); Token generated = new TokenWithImage(IToken.tSTRING, null, 0, 0, image); if (isKind(n, IToken.tPOUNDPOUND)) { // start token paste, // same as start // stringify pasteArg1 = generated; } else { result.append(generated); addSpacemarker(t, n, result); // end stringify } break; case IToken.tPOUNDPOUND: Token pasteArg2 = null; TokenList rest = null; if (n != null) { if (n.getType() == ObjCPreprocessor.tMACRO_PARAMETER) { TokenList arg; idx = ((TokenParameterReference) n).getIndex(); if (idx < args.length) { // be defensive arg = clone(args[idx]); pasteArg2 = arg.first(); if (pasteArg2 != null && arg.first() != arg.last()) { rest = arg; rest.removeFirst(); } } } else { idx = -1; pasteArg2 = n; } t = n; n = (Token) n.getNext(); final boolean pasteNext = isKind(n, IToken.tPOUNDPOUND); generated = tokenpaste(pasteArg1, pasteArg2, macro); pasteArg1 = null; if (generated != null) { if (pasteNext && rest == null) { pasteArg1 = generated; // no need to mark // spaces, done ahead } else { result.append(generated); addSpacemarker(pasteArg2, rest == null ? n : rest.first(), result); // end // token // paste } } if (rest != null) { if (pasteNext) { pasteArg1 = rest.last(); if (pasteArg1 != null) { result.appendAllButLast(rest); addSpacemarker(result.last(), pasteArg1, result); // start // token // paste } } else { result.appendAll(rest); if (idx >= 0) { addSpacemarker(t, n, result); // end // argument // replacement } } } } break; case IToken.tCOMMA: if (isKind(n, IToken.tPOUNDPOUND)) { final Token nn = (Token) n.getNext(); if (isKind(nn, ObjCPreprocessor.tMACRO_PARAMETER)) { idx = ((TokenParameterReference) nn).getIndex(); // check for gcc-extension preventing the paste // operation if (idx == args.length - 1 && macro.hasVarArgs() != FunctionStyleMacro.NO_VAARGS && !isKind(nn.getNext(), IToken.tPOUNDPOUND)) { final Token nnn = (Token) nn.getNext(); TokenList arg = clone(expandedArgs[idx]); if (arg.isEmpty()) { addSpacemarker(l, t, result); addSpacemarker(nn, nnn, result); } else { result.append(t); addSpacemarker(t, n, result); result.appendAll(arg); addSpacemarker(nn, nnn, result); } t = nn; n = nnn; break; } } addSpacemarker(l, t, result); pasteArg1 = t; } else { result.append(t); } break; default: if (isKind(n, IToken.tPOUNDPOUND)) { addSpacemarker(l, t, result); // start token paste pasteArg1 = t; } else { result.append(t); } break; } } }
@Override public String toString() { return "{" + (fIsStart ? '+' : '-') + fMacro.getName() + '}'; // $NON-NLS-1$ }
/** * 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; }