1 //===- PreprocessorLexer.h - C Language Family Lexer ------------*- C++ -*-===// 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 /// \file 10 /// Defines the PreprocessorLexer interface. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #ifndef LLVM_CLANG_LEX_PREPROCESSORLEXER_H 15 #define LLVM_CLANG_LEX_PREPROCESSORLEXER_H 16 17 #include "clang/Basic/SourceLocation.h" 18 #include "clang/Lex/HeaderSearch.h" 19 #include "clang/Lex/MultipleIncludeOpt.h" 20 #include "clang/Lex/Token.h" 21 #include "llvm/ADT/ArrayRef.h" 22 #include "llvm/ADT/SmallVector.h" 23 #include "llvm/ADT/StringMap.h" 24 #include <cassert> 25 26 namespace clang { 27 28 class FileEntry; 29 class Preprocessor; 30 31 class PreprocessorLexer { 32 virtual void anchor(); 33 34 protected: 35 friend class Preprocessor; 36 37 // Preprocessor object controlling lexing. 38 Preprocessor *PP = nullptr; 39 40 /// The SourceManager FileID corresponding to the file being lexed. 41 const FileID FID; 42 43 /// Number of SLocEntries before lexing the file. 44 unsigned InitialNumSLocEntries = 0; 45 46 //===--------------------------------------------------------------------===// 47 // Context-specific lexing flags set by the preprocessor. 48 //===--------------------------------------------------------------------===// 49 50 /// True when parsing \#XXX; turns '\\n' into a tok::eod token. 51 bool ParsingPreprocessorDirective = false; 52 53 /// True after \#include; turns \<xx> or "xxx" into a tok::header_name token. 54 bool ParsingFilename = false; 55 56 /// True if in raw mode. 57 /// 58 /// Raw mode disables interpretation of tokens and is a far faster mode to 59 /// lex in than non-raw-mode. This flag: 60 /// 1. If EOF of the current lexer is found, the include stack isn't popped. 61 /// 2. Identifier information is not looked up for identifier tokens. As an 62 /// effect of this, implicit macro expansion is naturally disabled. 63 /// 3. "#" tokens at the start of a line are treated as normal tokens, not 64 /// implicitly transformed by the lexer. 65 /// 4. All diagnostic messages are disabled. 66 /// 5. No callbacks are made into the preprocessor. 67 /// 68 /// Note that in raw mode that the PP pointer may be null. 69 bool LexingRawMode = false; 70 71 /// A state machine that detects the \#ifndef-wrapping a file 72 /// idiom for the multiple-include optimization. 73 MultipleIncludeOpt MIOpt; 74 75 /// Information about the set of \#if/\#ifdef/\#ifndef blocks 76 /// we are currently in. 77 SmallVector<PPConditionalInfo, 4> ConditionalStack; 78 79 struct IncludeInfo { 80 const FileEntry *File; 81 SourceLocation Location; 82 }; 83 // A complete history of all the files included by the current file. 84 llvm::StringMap<IncludeInfo> IncludeHistory; 85 86 PreprocessorLexer() : FID() {} 87 PreprocessorLexer(Preprocessor *pp, FileID fid); 88 virtual ~PreprocessorLexer() = default; 89 90 virtual void IndirectLex(Token& Result) = 0; 91 92 /// Return the source location for the next observable location. 93 virtual SourceLocation getSourceLocation() = 0; 94 95 //===--------------------------------------------------------------------===// 96 // #if directive handling. 97 98 /// pushConditionalLevel - When we enter a \#if directive, this keeps track of 99 /// what we are currently in for diagnostic emission (e.g. \#if with missing 100 /// \#endif). 101 void pushConditionalLevel(SourceLocation DirectiveStart, bool WasSkipping, 102 bool FoundNonSkip, bool FoundElse) { 103 PPConditionalInfo CI; 104 CI.IfLoc = DirectiveStart; 105 CI.WasSkipping = WasSkipping; 106 CI.FoundNonSkip = FoundNonSkip; 107 CI.FoundElse = FoundElse; 108 ConditionalStack.push_back(CI); 109 } 110 void pushConditionalLevel(const PPConditionalInfo &CI) { 111 ConditionalStack.push_back(CI); 112 } 113 114 /// popConditionalLevel - Remove an entry off the top of the conditional 115 /// stack, returning information about it. If the conditional stack is empty, 116 /// this returns true and does not fill in the arguments. 117 bool popConditionalLevel(PPConditionalInfo &CI) { 118 if (ConditionalStack.empty()) 119 return true; 120 CI = ConditionalStack.pop_back_val(); 121 return false; 122 } 123 124 /// Return the top of the conditional stack. 125 /// \pre This requires that there be a conditional active. 126 PPConditionalInfo &peekConditionalLevel() { 127 assert(!ConditionalStack.empty() && "No conditionals active!"); 128 return ConditionalStack.back(); 129 } 130 131 unsigned getConditionalStackDepth() const { return ConditionalStack.size(); } 132 133 public: 134 PreprocessorLexer(const PreprocessorLexer &) = delete; 135 PreprocessorLexer &operator=(const PreprocessorLexer &) = delete; 136 137 //===--------------------------------------------------------------------===// 138 // Misc. lexing methods. 139 140 /// Lex a token, producing a header-name token if possible. 141 void LexIncludeFilename(Token &FilenameTok); 142 143 /// Inform the lexer whether or not we are currently lexing a 144 /// preprocessor directive. 145 void setParsingPreprocessorDirective(bool f) { 146 ParsingPreprocessorDirective = f; 147 } 148 149 /// Return true if this lexer is in raw mode or not. 150 bool isLexingRawMode() const { return LexingRawMode; } 151 152 /// Return the preprocessor object for this lexer. 153 Preprocessor *getPP() const { return PP; } 154 155 FileID getFileID() const { 156 assert(PP && 157 "PreprocessorLexer::getFileID() should only be used with a Preprocessor"); 158 return FID; 159 } 160 161 /// Number of SLocEntries before lexing the file. 162 unsigned getInitialNumSLocEntries() const { 163 return InitialNumSLocEntries; 164 } 165 166 /// getFileEntry - Return the FileEntry corresponding to this FileID. Like 167 /// getFileID(), this only works for lexers with attached preprocessors. 168 const FileEntry *getFileEntry() const; 169 170 /// Iterator that traverses the current stack of preprocessor 171 /// conditional directives (\#if/\#ifdef/\#ifndef). 172 using conditional_iterator = 173 SmallVectorImpl<PPConditionalInfo>::const_iterator; 174 175 conditional_iterator conditional_begin() const { 176 return ConditionalStack.begin(); 177 } 178 179 conditional_iterator conditional_end() const { 180 return ConditionalStack.end(); 181 } 182 183 void setConditionalLevels(ArrayRef<PPConditionalInfo> CL) { 184 ConditionalStack.clear(); 185 ConditionalStack.append(CL.begin(), CL.end()); 186 } 187 188 void addInclude(StringRef Filename, const FileEntry &File, 189 SourceLocation Location) { 190 IncludeHistory.insert({Filename, {&File, Location}}); 191 } 192 193 const llvm::StringMap<IncludeInfo> &getIncludeHistory() const { 194 return IncludeHistory; 195 } 196 }; 197 198 } // namespace clang 199 200 #endif // LLVM_CLANG_LEX_PREPROCESSORLEXER_H 201