1 //===-- lib/Parser/preprocessor.h -------------------------------*- 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 #ifndef FORTRAN_PARSER_PREPROCESSOR_H_ 10 #define FORTRAN_PARSER_PREPROCESSOR_H_ 11 12 // A Fortran-aware preprocessing module used by the prescanner to implement 13 // preprocessing directives and macro replacement. Intended to be efficient 14 // enough to always run on all source files even when no preprocessing is 15 // performed, so that special compiler command options &/or source file name 16 // extensions for preprocessing will not be necessary. 17 18 #include "flang/Parser/char-block.h" 19 #include "flang/Parser/provenance.h" 20 #include "flang/Parser/token-sequence.h" 21 #include "llvm/Support/raw_ostream.h" 22 #include <cstddef> 23 #include <list> 24 #include <stack> 25 #include <string> 26 #include <unordered_map> 27 #include <vector> 28 29 namespace Fortran::parser { 30 31 class Prescanner; 32 class Preprocessor; 33 34 // Defines a macro 35 class Definition { 36 public: 37 Definition(const TokenSequence &, std::size_t firstToken, std::size_t tokens); 38 Definition(const std::vector<std::string> &argNames, const TokenSequence &, 39 std::size_t firstToken, std::size_t tokens, bool isVariadic = false); 40 Definition(const std::string &predefined, AllSources &); 41 42 bool isFunctionLike() const { return isFunctionLike_; } 43 std::size_t argumentCount() const { return argNames_.size(); } 44 bool isVariadic() const { return isVariadic_; } 45 bool isDisabled() const { return isDisabled_; } 46 bool isPredefined() const { return isPredefined_; } 47 const TokenSequence &replacement() const { return replacement_; } 48 49 bool set_isDisabled(bool disable); 50 51 TokenSequence Apply(const std::vector<TokenSequence> &args, Prescanner &, 52 bool inIfExpression = false); 53 54 void Print(llvm::raw_ostream &out, const char *macroName = "") const; 55 56 private: 57 static TokenSequence Tokenize(const std::vector<std::string> &argNames, 58 const TokenSequence &token, std::size_t firstToken, std::size_t tokens); 59 // For a given token, return the index of the argument to which the token 60 // corresponds, or `argumentCount` if the token does not correspond to any 61 // argument. 62 std::size_t GetArgumentIndex(const CharBlock &token) const; 63 64 bool isFunctionLike_{false}; 65 bool isVariadic_{false}; 66 bool isDisabled_{false}; 67 bool isPredefined_{false}; 68 std::vector<std::string> argNames_; 69 TokenSequence replacement_; 70 }; 71 72 // Preprocessing state 73 class Preprocessor { 74 public: 75 explicit Preprocessor(AllSources &); 76 77 const AllSources &allSources() const { return allSources_; } 78 AllSources &allSources() { return allSources_; } 79 80 void DefineStandardMacros(); 81 void Define(const std::string ¯o, const std::string &value); 82 void Undefine(std::string macro); 83 bool IsNameDefined(const CharBlock &); 84 bool IsFunctionLikeDefinition(const CharBlock &); 85 bool AnyDefinitions() const { return !definitions_.empty(); } 86 bool InConditional() const { return !ifStack_.empty(); } 87 88 // When called with partialFunctionLikeMacro not null, MacroReplacement() 89 // and ReplaceMacros() handle an unclosed function-like macro reference 90 // by terminating macro replacement at the name of the FLM and returning 91 // its index in the result. This allows the recursive call sites in 92 // MacroReplacement to append any remaining tokens in their inputs to 93 // that result and try again. All other Fortran preprocessors share this 94 // behavior. 95 std::optional<TokenSequence> MacroReplacement(const TokenSequence &, 96 Prescanner &, 97 std::optional<std::size_t> *partialFunctionLikeMacro = nullptr, 98 bool inIfExpression = false); 99 100 // Implements a preprocessor directive. 101 void Directive(const TokenSequence &, Prescanner &); 102 103 void PrintMacros(llvm::raw_ostream &out) const; 104 105 private: 106 enum class IsElseActive { No, Yes }; 107 enum class CanDeadElseAppear { No, Yes }; 108 109 CharBlock SaveTokenAsName(const CharBlock &); 110 TokenSequence ReplaceMacros(const TokenSequence &, Prescanner &, 111 std::optional<std::size_t> *partialFunctionLikeMacro = nullptr, 112 bool inIfExpression = false); 113 void SkipDisabledConditionalCode( 114 const std::string &, IsElseActive, Prescanner &, ProvenanceRange); 115 bool IsIfPredicateTrue(const TokenSequence &expr, std::size_t first, 116 std::size_t exprTokens, Prescanner &); 117 void LineDirective(const TokenSequence &, std::size_t, Prescanner &); 118 119 AllSources &allSources_; 120 std::list<std::string> names_; 121 std::unordered_map<CharBlock, Definition> definitions_; 122 std::stack<CanDeadElseAppear> ifStack_; 123 }; 124 } // namespace Fortran::parser 125 #endif // FORTRAN_PARSER_PREPROCESSOR_H_ 126