| Argyrios Kyrtzidis | b3dd1e0 | 2008-08-10 13:15:22 +0000 | [diff] [blame] | 1 | //===--- PPCaching.cpp - Handle caching lexed tokens ----------------------===// | 
|  | 2 | // | 
|  | 3 | //                     The LLVM Compiler Infrastructure | 
|  | 4 | // | 
|  | 5 | // This file is distributed under the University of Illinois Open Source | 
|  | 6 | // License. See LICENSE.TXT for details. | 
|  | 7 | // | 
|  | 8 | //===----------------------------------------------------------------------===// | 
|  | 9 | // | 
|  | 10 | // This file implements pieces of the Preprocessor interface that manage the | 
|  | 11 | // caching of lexed tokens. | 
|  | 12 | // | 
|  | 13 | //===----------------------------------------------------------------------===// | 
|  | 14 |  | 
|  | 15 | #include "clang/Lex/Preprocessor.h" | 
|  | 16 | using namespace clang; | 
|  | 17 |  | 
| James Dennett | 4a4f72d | 2013-11-27 01:27:40 +0000 | [diff] [blame] | 18 | // EnableBacktrackAtThisPos - From the point that this method is called, and | 
|  | 19 | // until CommitBacktrackedTokens() or Backtrack() is called, the Preprocessor | 
|  | 20 | // keeps track of the lexed tokens so that a subsequent Backtrack() call will | 
|  | 21 | // make the Preprocessor re-lex the same tokens. | 
|  | 22 | // | 
|  | 23 | // Nested backtracks are allowed, meaning that EnableBacktrackAtThisPos can | 
|  | 24 | // be called multiple times and CommitBacktrackedTokens/Backtrack calls will | 
|  | 25 | // be combined with the EnableBacktrackAtThisPos calls in reverse order. | 
| Argyrios Kyrtzidis | bd024c7 | 2008-08-23 12:05:53 +0000 | [diff] [blame] | 26 | void Preprocessor::EnableBacktrackAtThisPos() { | 
| Argyrios Kyrtzidis | bd024c7 | 2008-08-23 12:05:53 +0000 | [diff] [blame] | 27 | BacktrackPositions.push_back(CachedLexPos); | 
|  | 28 | EnterCachingLexMode(); | 
|  | 29 | } | 
| Argyrios Kyrtzidis | a65490c | 2008-08-22 21:27:50 +0000 | [diff] [blame] | 30 |  | 
| James Dennett | 4a4f72d | 2013-11-27 01:27:40 +0000 | [diff] [blame] | 31 | // Disable the last EnableBacktrackAtThisPos call. | 
| Argyrios Kyrtzidis | 75b3453 | 2008-08-24 12:29:43 +0000 | [diff] [blame] | 32 | void Preprocessor::CommitBacktrackedTokens() { | 
| Argyrios Kyrtzidis | bd024c7 | 2008-08-23 12:05:53 +0000 | [diff] [blame] | 33 | assert(!BacktrackPositions.empty() | 
|  | 34 | && "EnableBacktrackAtThisPos was not called!"); | 
|  | 35 | BacktrackPositions.pop_back(); | 
| Argyrios Kyrtzidis | bd024c7 | 2008-08-23 12:05:53 +0000 | [diff] [blame] | 36 | } | 
|  | 37 |  | 
| James Dennett | 4a4f72d | 2013-11-27 01:27:40 +0000 | [diff] [blame] | 38 | // Make Preprocessor re-lex the tokens that were lexed since | 
|  | 39 | // EnableBacktrackAtThisPos() was previously called. | 
| Argyrios Kyrtzidis | bd024c7 | 2008-08-23 12:05:53 +0000 | [diff] [blame] | 40 | void Preprocessor::Backtrack() { | 
|  | 41 | assert(!BacktrackPositions.empty() | 
|  | 42 | && "EnableBacktrackAtThisPos was not called!"); | 
|  | 43 | CachedLexPos = BacktrackPositions.back(); | 
|  | 44 | BacktrackPositions.pop_back(); | 
| Douglas Gregor | 8d76cca | 2012-01-04 06:20:15 +0000 | [diff] [blame] | 45 | recomputeCurLexerKind(); | 
| Argyrios Kyrtzidis | bd024c7 | 2008-08-23 12:05:53 +0000 | [diff] [blame] | 46 | } | 
| Argyrios Kyrtzidis | a65490c | 2008-08-22 21:27:50 +0000 | [diff] [blame] | 47 |  | 
| Argyrios Kyrtzidis | b3dd1e0 | 2008-08-10 13:15:22 +0000 | [diff] [blame] | 48 | void Preprocessor::CachingLex(Token &Result) { | 
| Argyrios Kyrtzidis | c2924de | 2010-07-12 18:49:30 +0000 | [diff] [blame] | 49 | if (!InCachingLexMode()) | 
|  | 50 | return; | 
|  | 51 |  | 
| Argyrios Kyrtzidis | b3dd1e0 | 2008-08-10 13:15:22 +0000 | [diff] [blame] | 52 | if (CachedLexPos < CachedTokens.size()) { | 
|  | 53 | Result = CachedTokens[CachedLexPos++]; | 
|  | 54 | return; | 
|  | 55 | } | 
|  | 56 |  | 
|  | 57 | ExitCachingLexMode(); | 
| Argyrios Kyrtzidis | d1d239f | 2010-07-12 21:41:41 +0000 | [diff] [blame] | 58 | Lex(Result); | 
| Argyrios Kyrtzidis | b3dd1e0 | 2008-08-10 13:15:22 +0000 | [diff] [blame] | 59 |  | 
| Argyrios Kyrtzidis | 4a1049c | 2012-04-04 02:57:01 +0000 | [diff] [blame] | 60 | if (isBacktrackEnabled()) { | 
|  | 61 | // Cache the lexed token. | 
|  | 62 | EnterCachingLexMode(); | 
|  | 63 | CachedTokens.push_back(Result); | 
|  | 64 | ++CachedLexPos; | 
| Argyrios Kyrtzidis | b3dd1e0 | 2008-08-10 13:15:22 +0000 | [diff] [blame] | 65 | return; | 
|  | 66 | } | 
|  | 67 |  | 
| Argyrios Kyrtzidis | 4a1049c | 2012-04-04 02:57:01 +0000 | [diff] [blame] | 68 | if (CachedLexPos < CachedTokens.size()) { | 
|  | 69 | EnterCachingLexMode(); | 
|  | 70 | } else { | 
|  | 71 | // All cached tokens were consumed. | 
|  | 72 | CachedTokens.clear(); | 
|  | 73 | CachedLexPos = 0; | 
|  | 74 | } | 
| Argyrios Kyrtzidis | b3dd1e0 | 2008-08-10 13:15:22 +0000 | [diff] [blame] | 75 | } | 
|  | 76 |  | 
|  | 77 | void Preprocessor::EnterCachingLexMode() { | 
|  | 78 | if (InCachingLexMode()) | 
|  | 79 | return; | 
|  | 80 |  | 
| Ted Kremenek | 50b4f48 | 2008-11-12 22:21:57 +0000 | [diff] [blame] | 81 | PushIncludeMacroStack(); | 
| Douglas Gregor | 8d76cca | 2012-01-04 06:20:15 +0000 | [diff] [blame] | 82 | CurLexerKind = CLK_CachingLexer; | 
| Argyrios Kyrtzidis | b3dd1e0 | 2008-08-10 13:15:22 +0000 | [diff] [blame] | 83 | } | 
|  | 84 |  | 
|  | 85 |  | 
|  | 86 | const Token &Preprocessor::PeekAhead(unsigned N) { | 
|  | 87 | assert(CachedLexPos + N > CachedTokens.size() && "Confused caching."); | 
|  | 88 | ExitCachingLexMode(); | 
|  | 89 | for (unsigned C = CachedLexPos + N - CachedTokens.size(); C > 0; --C) { | 
|  | 90 | CachedTokens.push_back(Token()); | 
|  | 91 | Lex(CachedTokens.back()); | 
|  | 92 | } | 
|  | 93 | EnterCachingLexMode(); | 
|  | 94 | return CachedTokens.back(); | 
|  | 95 | } | 
| Argyrios Kyrtzidis | c7e67a04c | 2008-11-08 16:17:04 +0000 | [diff] [blame] | 96 |  | 
|  | 97 | void Preprocessor::AnnotatePreviousCachedTokens(const Token &Tok) { | 
| Chris Lattner | 5a7971e | 2009-01-26 19:29:26 +0000 | [diff] [blame] | 98 | assert(Tok.isAnnotation() && "Expected annotation token"); | 
| Argyrios Kyrtzidis | c7e67a04c | 2008-11-08 16:17:04 +0000 | [diff] [blame] | 99 | assert(CachedLexPos != 0 && "Expected to have some cached tokens"); | 
| Sebastian Redl | b0e3e1b | 2010-02-08 19:35:18 +0000 | [diff] [blame] | 100 | assert(CachedTokens[CachedLexPos-1].getLastLoc() == Tok.getAnnotationEndLoc() | 
| Argyrios Kyrtzidis | c7e67a04c | 2008-11-08 16:17:04 +0000 | [diff] [blame] | 101 | && "The annotation should be until the most recent cached token"); | 
|  | 102 |  | 
|  | 103 | // Start from the end of the cached tokens list and look for the token | 
|  | 104 | // that is the beginning of the annotation token. | 
|  | 105 | for (CachedTokensTy::size_type i = CachedLexPos; i != 0; --i) { | 
|  | 106 | CachedTokensTy::iterator AnnotBegin = CachedTokens.begin() + i-1; | 
|  | 107 | if (AnnotBegin->getLocation() == Tok.getLocation()) { | 
|  | 108 | assert((BacktrackPositions.empty() || BacktrackPositions.back() < i) && | 
|  | 109 | "The backtrack pos points inside the annotated tokens!"); | 
|  | 110 | // Replace the cached tokens with the single annotation token. | 
| Nuno Lopes | bd2cd92 | 2009-07-26 16:36:45 +0000 | [diff] [blame] | 111 | if (i < CachedLexPos) | 
|  | 112 | CachedTokens.erase(AnnotBegin + 1, CachedTokens.begin() + CachedLexPos); | 
| Argyrios Kyrtzidis | c7e67a04c | 2008-11-08 16:17:04 +0000 | [diff] [blame] | 113 | *AnnotBegin = Tok; | 
|  | 114 | CachedLexPos = i; | 
|  | 115 | return; | 
|  | 116 | } | 
| Chandler Carruth | c4399b1 | 2013-11-27 01:40:12 +0000 | [diff] [blame] | 117 | } | 
|  | 118 | } | 
| Bruno Cardoso Lopes | 428a5aa | 2016-01-31 00:47:51 +0000 | [diff] [blame] | 119 |  | 
|  | 120 | bool Preprocessor::IsPreviousCachedToken(const Token &Tok) const { | 
|  | 121 | // There's currently no cached token... | 
|  | 122 | if (!CachedLexPos) | 
|  | 123 | return false; | 
|  | 124 |  | 
|  | 125 | const Token LastCachedTok = CachedTokens[CachedLexPos - 1]; | 
|  | 126 | if (LastCachedTok.getKind() != Tok.getKind()) | 
|  | 127 | return false; | 
|  | 128 |  | 
|  | 129 | int RelOffset = 0; | 
|  | 130 | if ((!getSourceManager().isInSameSLocAddrSpace( | 
|  | 131 | Tok.getLocation(), getLastCachedTokenLocation(), &RelOffset)) || | 
|  | 132 | RelOffset) | 
|  | 133 | return false; | 
|  | 134 |  | 
|  | 135 | return true; | 
|  | 136 | } | 
|  | 137 |  | 
|  | 138 | void Preprocessor::ReplacePreviousCachedToken(ArrayRef<Token> NewToks) { | 
|  | 139 | assert(CachedLexPos != 0 && "Expected to have some cached tokens"); | 
|  | 140 | CachedTokens.insert(CachedTokens.begin() + CachedLexPos - 1, NewToks.begin(), | 
|  | 141 | NewToks.end()); | 
|  | 142 | CachedTokens.erase(CachedTokens.begin() + CachedLexPos - 1 + NewToks.size()); | 
|  | 143 | CachedLexPos += NewToks.size() - 1; | 
|  | 144 | } |