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