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