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