llvm-project
163 строки · 5.7 Кб
1//===--- PPCaching.cpp - Handle caching lexed tokens ----------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file implements pieces of the Preprocessor interface that manage the
10// caching of lexed tokens.
11//
12//===----------------------------------------------------------------------===//
13
14#include "clang/Lex/Preprocessor.h"15using namespace clang;16
17// EnableBacktrackAtThisPos - From the point that this method is called, and
18// until CommitBacktrackedTokens() or Backtrack() is called, the Preprocessor
19// keeps track of the lexed tokens so that a subsequent Backtrack() call will
20// make the Preprocessor re-lex the same tokens.
21//
22// Nested backtracks are allowed, meaning that EnableBacktrackAtThisPos can
23// be called multiple times and CommitBacktrackedTokens/Backtrack calls will
24// be combined with the EnableBacktrackAtThisPos calls in reverse order.
25void Preprocessor::EnableBacktrackAtThisPos() {26assert(LexLevel == 0 && "cannot use lookahead while lexing");27BacktrackPositions.push_back(CachedLexPos);28EnterCachingLexMode();29}
30
31// Disable the last EnableBacktrackAtThisPos call.
32void Preprocessor::CommitBacktrackedTokens() {33assert(!BacktrackPositions.empty()34&& "EnableBacktrackAtThisPos was not called!");35BacktrackPositions.pop_back();36}
37
38// Make Preprocessor re-lex the tokens that were lexed since
39// EnableBacktrackAtThisPos() was previously called.
40void Preprocessor::Backtrack() {41assert(!BacktrackPositions.empty()42&& "EnableBacktrackAtThisPos was not called!");43CachedLexPos = BacktrackPositions.back();44BacktrackPositions.pop_back();45recomputeCurLexerKind();46}
47
48void Preprocessor::CachingLex(Token &Result) {49if (!InCachingLexMode())50return;51
52// The assert in EnterCachingLexMode should prevent this from happening.53assert(LexLevel == 1 &&54"should not use token caching within the preprocessor");55
56if (CachedLexPos < CachedTokens.size()) {57Result = CachedTokens[CachedLexPos++];58Result.setFlag(Token::IsReinjected);59return;60}61
62ExitCachingLexMode();63Lex(Result);64
65if (isBacktrackEnabled()) {66// Cache the lexed token.67EnterCachingLexModeUnchecked();68CachedTokens.push_back(Result);69++CachedLexPos;70return;71}72
73if (CachedLexPos < CachedTokens.size()) {74EnterCachingLexModeUnchecked();75} else {76// All cached tokens were consumed.77CachedTokens.clear();78CachedLexPos = 0;79}80}
81
82void Preprocessor::EnterCachingLexMode() {83// The caching layer sits on top of all the other lexers, so it's incorrect84// to cache tokens while inside a nested lex action. The cached tokens would85// be retained after returning to the enclosing lex action and, at best,86// would appear at the wrong position in the token stream.87assert(LexLevel == 0 &&88"entered caching lex mode while lexing something else");89
90if (InCachingLexMode()) {91assert(CurLexerCallback == CLK_CachingLexer && "Unexpected lexer kind");92return;93}94
95EnterCachingLexModeUnchecked();96}
97
98void Preprocessor::EnterCachingLexModeUnchecked() {99assert(CurLexerCallback != CLK_CachingLexer && "already in caching lex mode");100PushIncludeMacroStack();101CurLexerCallback = CLK_CachingLexer;102}
103
104
105const Token &Preprocessor::PeekAhead(unsigned N) {106assert(CachedLexPos + N > CachedTokens.size() && "Confused caching.");107ExitCachingLexMode();108for (size_t C = CachedLexPos + N - CachedTokens.size(); C > 0; --C) {109CachedTokens.push_back(Token());110Lex(CachedTokens.back());111}112EnterCachingLexMode();113return CachedTokens.back();114}
115
116void Preprocessor::AnnotatePreviousCachedTokens(const Token &Tok) {117assert(Tok.isAnnotation() && "Expected annotation token");118assert(CachedLexPos != 0 && "Expected to have some cached tokens");119assert(CachedTokens[CachedLexPos-1].getLastLoc() == Tok.getAnnotationEndLoc()120&& "The annotation should be until the most recent cached token");121
122// Start from the end of the cached tokens list and look for the token123// that is the beginning of the annotation token.124for (CachedTokensTy::size_type i = CachedLexPos; i != 0; --i) {125CachedTokensTy::iterator AnnotBegin = CachedTokens.begin() + i-1;126if (AnnotBegin->getLocation() == Tok.getLocation()) {127assert((BacktrackPositions.empty() || BacktrackPositions.back() <= i) &&128"The backtrack pos points inside the annotated tokens!");129// Replace the cached tokens with the single annotation token.130if (i < CachedLexPos)131CachedTokens.erase(AnnotBegin + 1, CachedTokens.begin() + CachedLexPos);132*AnnotBegin = Tok;133CachedLexPos = i;134return;135}136}137}
138
139bool Preprocessor::IsPreviousCachedToken(const Token &Tok) const {140// There's currently no cached token...141if (!CachedLexPos)142return false;143
144const Token LastCachedTok = CachedTokens[CachedLexPos - 1];145if (LastCachedTok.getKind() != Tok.getKind())146return false;147
148SourceLocation::IntTy RelOffset = 0;149if ((!getSourceManager().isInSameSLocAddrSpace(150Tok.getLocation(), getLastCachedTokenLocation(), &RelOffset)) ||151RelOffset)152return false;153
154return true;155}
156
157void Preprocessor::ReplacePreviousCachedToken(ArrayRef<Token> NewToks) {158assert(CachedLexPos != 0 && "Expected to have some cached tokens");159CachedTokens.insert(CachedTokens.begin() + CachedLexPos - 1, NewToks.begin(),160NewToks.end());161CachedTokens.erase(CachedTokens.begin() + CachedLexPos - 1 + NewToks.size());162CachedLexPos += NewToks.size() - 1;163}
164