Home | History | Annotate | Line # | Download | only in Lex
      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 
     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).
     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   }
    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.
    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.
    117   PPConditionalInfo &peekConditionalLevel() {
    118     assert(!ConditionalStack.empty() && "No conditionals active!");
    119     return ConditionalStack.back();
    120   }
    121 
    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.
    136   void setParsingPreprocessorDirective(bool f) {
    137     ParsingPreprocessorDirective = f;
    138   }
    139 
    140   /// Return true if this lexer is in raw mode or not.
    141   bool isLexingRawMode() const { return LexingRawMode; }
    142 
    143   /// Return the preprocessor object for this lexer.
    144   Preprocessor *getPP() const { return PP; }
    145 
    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.
    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 
    166   conditional_iterator conditional_begin() const {
    167     return ConditionalStack.begin();
    168   }
    169 
    170   conditional_iterator conditional_end() const {
    171     return ConditionalStack.end();
    172   }
    173 
    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