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