10b57cec5SDimitry Andric //===- PreprocessorLexer.h - C Language Family Lexer ------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric /// \file
100b57cec5SDimitry Andric /// Defines the PreprocessorLexer interface.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #ifndef LLVM_CLANG_LEX_PREPROCESSORLEXER_H
150b57cec5SDimitry Andric #define LLVM_CLANG_LEX_PREPROCESSORLEXER_H
160b57cec5SDimitry Andric 
1781ad6265SDimitry Andric #include "clang/Basic/FileEntry.h"
186e75b2fbSDimitry Andric #include "clang/Basic/SourceLocation.h"
190b57cec5SDimitry Andric #include "clang/Lex/MultipleIncludeOpt.h"
200b57cec5SDimitry Andric #include "clang/Lex/Token.h"
210b57cec5SDimitry Andric #include "llvm/ADT/ArrayRef.h"
220b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h"
230b57cec5SDimitry Andric #include <cassert>
240b57cec5SDimitry Andric 
250b57cec5SDimitry Andric namespace clang {
260b57cec5SDimitry Andric 
270b57cec5SDimitry Andric class FileEntry;
280b57cec5SDimitry Andric class Preprocessor;
290b57cec5SDimitry Andric 
300b57cec5SDimitry Andric class PreprocessorLexer {
310b57cec5SDimitry Andric   virtual void anchor();
320b57cec5SDimitry Andric 
330b57cec5SDimitry Andric protected:
340b57cec5SDimitry Andric   friend class Preprocessor;
350b57cec5SDimitry Andric 
360b57cec5SDimitry Andric   // Preprocessor object controlling lexing.
370b57cec5SDimitry Andric   Preprocessor *PP = nullptr;
380b57cec5SDimitry Andric 
390b57cec5SDimitry Andric   /// The SourceManager FileID corresponding to the file being lexed.
400b57cec5SDimitry Andric   const FileID FID;
410b57cec5SDimitry Andric 
420b57cec5SDimitry Andric   /// Number of SLocEntries before lexing the file.
430b57cec5SDimitry Andric   unsigned InitialNumSLocEntries = 0;
440b57cec5SDimitry Andric 
450b57cec5SDimitry Andric   //===--------------------------------------------------------------------===//
460b57cec5SDimitry Andric   // Context-specific lexing flags set by the preprocessor.
470b57cec5SDimitry Andric   //===--------------------------------------------------------------------===//
480b57cec5SDimitry Andric 
490b57cec5SDimitry Andric   /// True when parsing \#XXX; turns '\\n' into a tok::eod token.
500b57cec5SDimitry Andric   bool ParsingPreprocessorDirective = false;
510b57cec5SDimitry Andric 
520b57cec5SDimitry Andric   /// True after \#include; turns \<xx> or "xxx" into a tok::header_name token.
530b57cec5SDimitry Andric   bool ParsingFilename = false;
540b57cec5SDimitry Andric 
550b57cec5SDimitry Andric   /// True if in raw mode.
560b57cec5SDimitry Andric   ///
570b57cec5SDimitry Andric   /// Raw mode disables interpretation of tokens and is a far faster mode to
580b57cec5SDimitry Andric   /// lex in than non-raw-mode.  This flag:
590b57cec5SDimitry Andric   ///  1. If EOF of the current lexer is found, the include stack isn't popped.
600b57cec5SDimitry Andric   ///  2. Identifier information is not looked up for identifier tokens.  As an
610b57cec5SDimitry Andric   ///     effect of this, implicit macro expansion is naturally disabled.
620b57cec5SDimitry Andric   ///  3. "#" tokens at the start of a line are treated as normal tokens, not
630b57cec5SDimitry Andric   ///     implicitly transformed by the lexer.
640b57cec5SDimitry Andric   ///  4. All diagnostic messages are disabled.
650b57cec5SDimitry Andric   ///  5. No callbacks are made into the preprocessor.
660b57cec5SDimitry Andric   ///
670b57cec5SDimitry Andric   /// Note that in raw mode that the PP pointer may be null.
680b57cec5SDimitry Andric   bool LexingRawMode = false;
690b57cec5SDimitry Andric 
700b57cec5SDimitry Andric   /// A state machine that detects the \#ifndef-wrapping a file
710b57cec5SDimitry Andric   /// idiom for the multiple-include optimization.
720b57cec5SDimitry Andric   MultipleIncludeOpt MIOpt;
730b57cec5SDimitry Andric 
740b57cec5SDimitry Andric   /// Information about the set of \#if/\#ifdef/\#ifndef blocks
750b57cec5SDimitry Andric   /// we are currently in.
760b57cec5SDimitry Andric   SmallVector<PPConditionalInfo, 4> ConditionalStack;
770b57cec5SDimitry Andric 
PreprocessorLexer()780b57cec5SDimitry Andric   PreprocessorLexer() : FID() {}
790b57cec5SDimitry Andric   PreprocessorLexer(Preprocessor *pp, FileID fid);
800b57cec5SDimitry Andric   virtual ~PreprocessorLexer() = default;
810b57cec5SDimitry Andric 
820b57cec5SDimitry Andric   virtual void IndirectLex(Token& Result) = 0;
830b57cec5SDimitry Andric 
840b57cec5SDimitry Andric   /// Return the source location for the next observable location.
850b57cec5SDimitry Andric   virtual SourceLocation getSourceLocation() = 0;
860b57cec5SDimitry Andric 
870b57cec5SDimitry Andric   //===--------------------------------------------------------------------===//
880b57cec5SDimitry Andric   // #if directive handling.
890b57cec5SDimitry Andric 
900b57cec5SDimitry Andric   /// pushConditionalLevel - When we enter a \#if directive, this keeps track of
910b57cec5SDimitry Andric   /// what we are currently in for diagnostic emission (e.g. \#if with missing
920b57cec5SDimitry Andric   /// \#endif).
pushConditionalLevel(SourceLocation DirectiveStart,bool WasSkipping,bool FoundNonSkip,bool FoundElse)930b57cec5SDimitry Andric   void pushConditionalLevel(SourceLocation DirectiveStart, bool WasSkipping,
940b57cec5SDimitry Andric                             bool FoundNonSkip, bool FoundElse) {
950b57cec5SDimitry Andric     PPConditionalInfo CI;
960b57cec5SDimitry Andric     CI.IfLoc = DirectiveStart;
970b57cec5SDimitry Andric     CI.WasSkipping = WasSkipping;
980b57cec5SDimitry Andric     CI.FoundNonSkip = FoundNonSkip;
990b57cec5SDimitry Andric     CI.FoundElse = FoundElse;
1000b57cec5SDimitry Andric     ConditionalStack.push_back(CI);
1010b57cec5SDimitry Andric   }
pushConditionalLevel(const PPConditionalInfo & CI)1020b57cec5SDimitry Andric   void pushConditionalLevel(const PPConditionalInfo &CI) {
1030b57cec5SDimitry Andric     ConditionalStack.push_back(CI);
1040b57cec5SDimitry Andric   }
1050b57cec5SDimitry Andric 
1060b57cec5SDimitry Andric   /// popConditionalLevel - Remove an entry off the top of the conditional
1070b57cec5SDimitry Andric   /// stack, returning information about it.  If the conditional stack is empty,
1080b57cec5SDimitry Andric   /// this returns true and does not fill in the arguments.
popConditionalLevel(PPConditionalInfo & CI)1090b57cec5SDimitry Andric   bool popConditionalLevel(PPConditionalInfo &CI) {
1100b57cec5SDimitry Andric     if (ConditionalStack.empty())
1110b57cec5SDimitry Andric       return true;
1120b57cec5SDimitry Andric     CI = ConditionalStack.pop_back_val();
1130b57cec5SDimitry Andric     return false;
1140b57cec5SDimitry Andric   }
1150b57cec5SDimitry Andric 
1160b57cec5SDimitry Andric   /// Return the top of the conditional stack.
1170b57cec5SDimitry Andric   /// \pre This requires that there be a conditional active.
peekConditionalLevel()1180b57cec5SDimitry Andric   PPConditionalInfo &peekConditionalLevel() {
1190b57cec5SDimitry Andric     assert(!ConditionalStack.empty() && "No conditionals active!");
1200b57cec5SDimitry Andric     return ConditionalStack.back();
1210b57cec5SDimitry Andric   }
1220b57cec5SDimitry Andric 
getConditionalStackDepth()1230b57cec5SDimitry Andric   unsigned getConditionalStackDepth() const { return ConditionalStack.size(); }
1240b57cec5SDimitry Andric 
1250b57cec5SDimitry Andric public:
1260b57cec5SDimitry Andric   PreprocessorLexer(const PreprocessorLexer &) = delete;
1270b57cec5SDimitry Andric   PreprocessorLexer &operator=(const PreprocessorLexer &) = delete;
1280b57cec5SDimitry Andric 
1290b57cec5SDimitry Andric   //===--------------------------------------------------------------------===//
1300b57cec5SDimitry Andric   // Misc. lexing methods.
1310b57cec5SDimitry Andric 
1320b57cec5SDimitry Andric   /// Lex a token, producing a header-name token if possible.
1330b57cec5SDimitry Andric   void LexIncludeFilename(Token &FilenameTok);
1340b57cec5SDimitry Andric 
1350b57cec5SDimitry Andric   /// Inform the lexer whether or not we are currently lexing a
1360b57cec5SDimitry Andric   /// preprocessor directive.
setParsingPreprocessorDirective(bool f)1370b57cec5SDimitry Andric   void setParsingPreprocessorDirective(bool f) {
1380b57cec5SDimitry Andric     ParsingPreprocessorDirective = f;
1390b57cec5SDimitry Andric   }
1400b57cec5SDimitry Andric 
1410b57cec5SDimitry Andric   /// Return true if this lexer is in raw mode or not.
isLexingRawMode()1420b57cec5SDimitry Andric   bool isLexingRawMode() const { return LexingRawMode; }
1430b57cec5SDimitry Andric 
1440b57cec5SDimitry Andric   /// Return the preprocessor object for this lexer.
getPP()1450b57cec5SDimitry Andric   Preprocessor *getPP() const { return PP; }
1460b57cec5SDimitry Andric 
getFileID()1470b57cec5SDimitry Andric   FileID getFileID() const {
1480b57cec5SDimitry Andric     assert(PP &&
1490b57cec5SDimitry Andric       "PreprocessorLexer::getFileID() should only be used with a Preprocessor");
1500b57cec5SDimitry Andric     return FID;
1510b57cec5SDimitry Andric   }
1520b57cec5SDimitry Andric 
1530b57cec5SDimitry Andric   /// Number of SLocEntries before lexing the file.
getInitialNumSLocEntries()1540b57cec5SDimitry Andric   unsigned getInitialNumSLocEntries() const {
1550b57cec5SDimitry Andric     return InitialNumSLocEntries;
1560b57cec5SDimitry Andric   }
1570b57cec5SDimitry Andric 
1580b57cec5SDimitry Andric   /// getFileEntry - Return the FileEntry corresponding to this FileID.  Like
1590b57cec5SDimitry Andric   /// getFileID(), this only works for lexers with attached preprocessors.
1605f757f3fSDimitry Andric   OptionalFileEntryRef getFileEntry() const;
1610b57cec5SDimitry Andric 
1620b57cec5SDimitry Andric   /// Iterator that traverses the current stack of preprocessor
1630b57cec5SDimitry Andric   /// conditional directives (\#if/\#ifdef/\#ifndef).
1640b57cec5SDimitry Andric   using conditional_iterator =
1650b57cec5SDimitry Andric       SmallVectorImpl<PPConditionalInfo>::const_iterator;
1660b57cec5SDimitry Andric 
conditional_begin()1670b57cec5SDimitry Andric   conditional_iterator conditional_begin() const {
1680b57cec5SDimitry Andric     return ConditionalStack.begin();
1690b57cec5SDimitry Andric   }
1700b57cec5SDimitry Andric 
conditional_end()1710b57cec5SDimitry Andric   conditional_iterator conditional_end() const {
1720b57cec5SDimitry Andric     return ConditionalStack.end();
1730b57cec5SDimitry Andric   }
1740b57cec5SDimitry Andric 
setConditionalLevels(ArrayRef<PPConditionalInfo> CL)1750b57cec5SDimitry Andric   void setConditionalLevels(ArrayRef<PPConditionalInfo> CL) {
1760b57cec5SDimitry Andric     ConditionalStack.clear();
1770b57cec5SDimitry Andric     ConditionalStack.append(CL.begin(), CL.end());
1780b57cec5SDimitry Andric   }
1790b57cec5SDimitry Andric };
1800b57cec5SDimitry Andric 
1810b57cec5SDimitry Andric } // namespace clang
1820b57cec5SDimitry Andric 
1830b57cec5SDimitry Andric #endif // LLVM_CLANG_LEX_PREPROCESSORLEXER_H
184