1 //===- PreprocessorLexer.h - C Language Family Lexer ------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 /// \file
11 /// Defines the PreprocessorLexer interface.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #ifndef LLVM_CLANG_LEX_PREPROCESSORLEXER_H
16 #define LLVM_CLANG_LEX_PREPROCESSORLEXER_H
17 
18 #include "clang/Lex/MultipleIncludeOpt.h"
19 #include "clang/Lex/Token.h"
20 #include "clang/Basic/SourceLocation.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> into a tok::angle_string_literal
53   /// token.
54   bool ParsingFilename = false;
55 
56   /// True if in raw mode.
57   ///
58   /// Raw mode disables interpretation of tokens and is a far faster mode to
59   /// lex in than non-raw-mode.  This flag:
60   ///  1. If EOF of the current lexer is found, the include stack isn't popped.
61   ///  2. Identifier information is not looked up for identifier tokens.  As an
62   ///     effect of this, implicit macro expansion is naturally disabled.
63   ///  3. "#" tokens at the start of a line are treated as normal tokens, not
64   ///     implicitly transformed by the lexer.
65   ///  4. All diagnostic messages are disabled.
66   ///  5. No callbacks are made into the preprocessor.
67   ///
68   /// Note that in raw mode that the PP pointer may be null.
69   bool LexingRawMode = false;
70 
71   /// A state machine that detects the \#ifndef-wrapping a file
72   /// idiom for the multiple-include optimization.
73   MultipleIncludeOpt MIOpt;
74 
75   /// Information about the set of \#if/\#ifdef/\#ifndef blocks
76   /// we are currently in.
77   SmallVector<PPConditionalInfo, 4> ConditionalStack;
78 
PreprocessorLexer()79   PreprocessorLexer() : FID() {}
80   PreprocessorLexer(Preprocessor *pp, FileID fid);
81   virtual ~PreprocessorLexer() = default;
82 
83   virtual void IndirectLex(Token& Result) = 0;
84 
85   /// Return the source location for the next observable location.
86   virtual SourceLocation getSourceLocation() = 0;
87 
88   //===--------------------------------------------------------------------===//
89   // #if directive handling.
90 
91   /// pushConditionalLevel - When we enter a \#if directive, this keeps track of
92   /// what we are currently in for diagnostic emission (e.g. \#if with missing
93   /// \#endif).
pushConditionalLevel(SourceLocation DirectiveStart,bool WasSkipping,bool FoundNonSkip,bool FoundElse)94   void pushConditionalLevel(SourceLocation DirectiveStart, bool WasSkipping,
95                             bool FoundNonSkip, bool FoundElse) {
96     PPConditionalInfo CI;
97     CI.IfLoc = DirectiveStart;
98     CI.WasSkipping = WasSkipping;
99     CI.FoundNonSkip = FoundNonSkip;
100     CI.FoundElse = FoundElse;
101     ConditionalStack.push_back(CI);
102   }
pushConditionalLevel(const PPConditionalInfo & CI)103   void pushConditionalLevel(const PPConditionalInfo &CI) {
104     ConditionalStack.push_back(CI);
105   }
106 
107   /// popConditionalLevel - Remove an entry off the top of the conditional
108   /// stack, returning information about it.  If the conditional stack is empty,
109   /// this returns true and does not fill in the arguments.
popConditionalLevel(PPConditionalInfo & CI)110   bool popConditionalLevel(PPConditionalInfo &CI) {
111     if (ConditionalStack.empty())
112       return true;
113     CI = ConditionalStack.pop_back_val();
114     return false;
115   }
116 
117   /// Return the top of the conditional stack.
118   /// \pre This requires that there be a conditional active.
peekConditionalLevel()119   PPConditionalInfo &peekConditionalLevel() {
120     assert(!ConditionalStack.empty() && "No conditionals active!");
121     return ConditionalStack.back();
122   }
123 
getConditionalStackDepth()124   unsigned getConditionalStackDepth() const { return ConditionalStack.size(); }
125 
126 public:
127   PreprocessorLexer(const PreprocessorLexer &) = delete;
128   PreprocessorLexer &operator=(const PreprocessorLexer &) = delete;
129 
130   //===--------------------------------------------------------------------===//
131   // Misc. lexing methods.
132 
133   /// After the preprocessor has parsed a \#include, lex and
134   /// (potentially) macro expand the filename.
135   ///
136   /// If the sequence parsed is not lexically legal, emit a diagnostic and
137   /// return a result EOD token.
138   void LexIncludeFilename(Token &FilenameTok);
139 
140   /// Inform the lexer whether or not we are currently lexing a
141   /// preprocessor directive.
setParsingPreprocessorDirective(bool f)142   void setParsingPreprocessorDirective(bool f) {
143     ParsingPreprocessorDirective = f;
144   }
145 
146   /// Return true if this lexer is in raw mode or not.
isLexingRawMode()147   bool isLexingRawMode() const { return LexingRawMode; }
148 
149   /// Return the preprocessor object for this lexer.
getPP()150   Preprocessor *getPP() const { return PP; }
151 
getFileID()152   FileID getFileID() const {
153     assert(PP &&
154       "PreprocessorLexer::getFileID() should only be used with a Preprocessor");
155     return FID;
156   }
157 
158   /// Number of SLocEntries before lexing the file.
getInitialNumSLocEntries()159   unsigned getInitialNumSLocEntries() const {
160     return InitialNumSLocEntries;
161   }
162 
163   /// getFileEntry - Return the FileEntry corresponding to this FileID.  Like
164   /// getFileID(), this only works for lexers with attached preprocessors.
165   const FileEntry *getFileEntry() const;
166 
167   /// Iterator that traverses the current stack of preprocessor
168   /// conditional directives (\#if/\#ifdef/\#ifndef).
169   using conditional_iterator =
170       SmallVectorImpl<PPConditionalInfo>::const_iterator;
171 
conditional_begin()172   conditional_iterator conditional_begin() const {
173     return ConditionalStack.begin();
174   }
175 
conditional_end()176   conditional_iterator conditional_end() const {
177     return ConditionalStack.end();
178   }
179 
setConditionalLevels(ArrayRef<PPConditionalInfo> CL)180   void setConditionalLevels(ArrayRef<PPConditionalInfo> CL) {
181     ConditionalStack.clear();
182     ConditionalStack.append(CL.begin(), CL.end());
183   }
184 };
185 
186 } // namespace clang
187 
188 #endif // LLVM_CLANG_LEX_PREPROCESSORLEXER_H
189