• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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