| //===- PreprocessorLexer.h - C Language Family Lexer ------------*- C++ -*-===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| /// \file |
| /// Defines the PreprocessorLexer interface. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLVM_CLANG_LEX_PREPROCESSORLEXER_H |
| #define LLVM_CLANG_LEX_PREPROCESSORLEXER_H |
| |
| #include "clang/Lex/MultipleIncludeOpt.h" |
| #include "clang/Lex/Token.h" |
| #include "clang/Basic/SourceLocation.h" |
| #include "llvm/ADT/ArrayRef.h" |
| #include "llvm/ADT/SmallVector.h" |
| #include <cassert> |
| |
| namespace clang { |
| |
| class FileEntry; |
| class Preprocessor; |
| |
| class PreprocessorLexer { |
| virtual void anchor(); |
| |
| protected: |
| friend class Preprocessor; |
| |
| // Preprocessor object controlling lexing. |
| Preprocessor *PP = nullptr; |
| |
| /// The SourceManager FileID corresponding to the file being lexed. |
| const FileID FID; |
| |
| /// Number of SLocEntries before lexing the file. |
| unsigned InitialNumSLocEntries = 0; |
| |
| //===--------------------------------------------------------------------===// |
| // Context-specific lexing flags set by the preprocessor. |
| //===--------------------------------------------------------------------===// |
| |
| /// True when parsing \#XXX; turns '\\n' into a tok::eod token. |
| bool ParsingPreprocessorDirective = false; |
| |
| /// True after \#include; turns \<xx> into a tok::angle_string_literal |
| /// token. |
| bool ParsingFilename = false; |
| |
| /// True if in raw mode. |
| /// |
| /// Raw mode disables interpretation of tokens and is a far faster mode to |
| /// lex in than non-raw-mode. This flag: |
| /// 1. If EOF of the current lexer is found, the include stack isn't popped. |
| /// 2. Identifier information is not looked up for identifier tokens. As an |
| /// effect of this, implicit macro expansion is naturally disabled. |
| /// 3. "#" tokens at the start of a line are treated as normal tokens, not |
| /// implicitly transformed by the lexer. |
| /// 4. All diagnostic messages are disabled. |
| /// 5. No callbacks are made into the preprocessor. |
| /// |
| /// Note that in raw mode that the PP pointer may be null. |
| bool LexingRawMode = false; |
| |
| /// A state machine that detects the \#ifndef-wrapping a file |
| /// idiom for the multiple-include optimization. |
| MultipleIncludeOpt MIOpt; |
| |
| /// Information about the set of \#if/\#ifdef/\#ifndef blocks |
| /// we are currently in. |
| SmallVector<PPConditionalInfo, 4> ConditionalStack; |
| |
| PreprocessorLexer() : FID() {} |
| PreprocessorLexer(Preprocessor *pp, FileID fid); |
| virtual ~PreprocessorLexer() = default; |
| |
| virtual void IndirectLex(Token& Result) = 0; |
| |
| /// Return the source location for the next observable location. |
| virtual SourceLocation getSourceLocation() = 0; |
| |
| //===--------------------------------------------------------------------===// |
| // #if directive handling. |
| |
| /// pushConditionalLevel - When we enter a \#if directive, this keeps track of |
| /// what we are currently in for diagnostic emission (e.g. \#if with missing |
| /// \#endif). |
| void pushConditionalLevel(SourceLocation DirectiveStart, bool WasSkipping, |
| bool FoundNonSkip, bool FoundElse) { |
| PPConditionalInfo CI; |
| CI.IfLoc = DirectiveStart; |
| CI.WasSkipping = WasSkipping; |
| CI.FoundNonSkip = FoundNonSkip; |
| CI.FoundElse = FoundElse; |
| ConditionalStack.push_back(CI); |
| } |
| void pushConditionalLevel(const PPConditionalInfo &CI) { |
| ConditionalStack.push_back(CI); |
| } |
| |
| /// popConditionalLevel - Remove an entry off the top of the conditional |
| /// stack, returning information about it. If the conditional stack is empty, |
| /// this returns true and does not fill in the arguments. |
| bool popConditionalLevel(PPConditionalInfo &CI) { |
| if (ConditionalStack.empty()) |
| return true; |
| CI = ConditionalStack.pop_back_val(); |
| return false; |
| } |
| |
| /// Return the top of the conditional stack. |
| /// \pre This requires that there be a conditional active. |
| PPConditionalInfo &peekConditionalLevel() { |
| assert(!ConditionalStack.empty() && "No conditionals active!"); |
| return ConditionalStack.back(); |
| } |
| |
| unsigned getConditionalStackDepth() const { return ConditionalStack.size(); } |
| |
| public: |
| PreprocessorLexer(const PreprocessorLexer &) = delete; |
| PreprocessorLexer &operator=(const PreprocessorLexer &) = delete; |
| |
| //===--------------------------------------------------------------------===// |
| // Misc. lexing methods. |
| |
| /// After the preprocessor has parsed a \#include, lex and |
| /// (potentially) macro expand the filename. |
| /// |
| /// If the sequence parsed is not lexically legal, emit a diagnostic and |
| /// return a result EOD token. |
| void LexIncludeFilename(Token &Result); |
| |
| /// Inform the lexer whether or not we are currently lexing a |
| /// preprocessor directive. |
| void setParsingPreprocessorDirective(bool f) { |
| ParsingPreprocessorDirective = f; |
| } |
| |
| /// Return true if this lexer is in raw mode or not. |
| bool isLexingRawMode() const { return LexingRawMode; } |
| |
| /// Return the preprocessor object for this lexer. |
| Preprocessor *getPP() const { return PP; } |
| |
| FileID getFileID() const { |
| assert(PP && |
| "PreprocessorLexer::getFileID() should only be used with a Preprocessor"); |
| return FID; |
| } |
| |
| /// Number of SLocEntries before lexing the file. |
| unsigned getInitialNumSLocEntries() const { |
| return InitialNumSLocEntries; |
| } |
| |
| /// getFileEntry - Return the FileEntry corresponding to this FileID. Like |
| /// getFileID(), this only works for lexers with attached preprocessors. |
| const FileEntry *getFileEntry() const; |
| |
| /// Iterator that traverses the current stack of preprocessor |
| /// conditional directives (\#if/\#ifdef/\#ifndef). |
| using conditional_iterator = |
| SmallVectorImpl<PPConditionalInfo>::const_iterator; |
| |
| conditional_iterator conditional_begin() const { |
| return ConditionalStack.begin(); |
| } |
| |
| conditional_iterator conditional_end() const { |
| return ConditionalStack.end(); |
| } |
| |
| void setConditionalLevels(ArrayRef<PPConditionalInfo> CL) { |
| ConditionalStack.clear(); |
| ConditionalStack.append(CL.begin(), CL.end()); |
| } |
| }; |
| |
| } // namespace clang |
| |
| #endif // LLVM_CLANG_LEX_PREPROCESSORLEXER_H |