Warning: This file is not a C or C++ file. It does not have highlighting.
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 | |
53 | void Print(llvm::raw_ostream &out, const char *macroName = "") const; |
54 | |
55 | private: |
56 | static TokenSequence Tokenize(const std::vector<std::string> &argNames, |
57 | const TokenSequence &token, std::size_t firstToken, std::size_t tokens); |
58 | // For a given token, return the index of the argument to which the token |
59 | // corresponds, or `argumentCount` if the token does not correspond to any |
60 | // argument. |
61 | std::size_t GetArgumentIndex(const CharBlock &token) const; |
62 | |
63 | bool isFunctionLike_{false}; |
64 | bool isVariadic_{false}; |
65 | bool isDisabled_{false}; |
66 | bool isPredefined_{false}; |
67 | std::vector<std::string> argNames_; |
68 | TokenSequence replacement_; |
69 | }; |
70 | |
71 | // Preprocessing state |
72 | class Preprocessor { |
73 | public: |
74 | explicit Preprocessor(AllSources &); |
75 | |
76 | const AllSources &allSources() const { return allSources_; } |
77 | AllSources &allSources() { return allSources_; } |
78 | |
79 | void DefineStandardMacros(); |
80 | void Define(const std::string ¯o, const std::string &value); |
81 | void Undefine(std::string macro); |
82 | bool IsNameDefined(const CharBlock &); |
83 | bool IsFunctionLikeDefinition(const CharBlock &); |
84 | |
85 | // When called with partialFunctionLikeMacro not null, MacroReplacement() |
86 | // and ReplaceMacros() handle an unclosed function-like macro reference |
87 | // by terminating macro replacement at the name of the FLM and returning |
88 | // its index in the result. This allows the recursive call sites in |
89 | // MacroReplacement to append any remaining tokens in their inputs to |
90 | // that result and try again. All other Fortran preprocessors share this |
91 | // behavior. |
92 | std::optional<TokenSequence> MacroReplacement(const TokenSequence &, |
93 | Prescanner &, |
94 | std::optional<std::size_t> *partialFunctionLikeMacro = nullptr); |
95 | |
96 | // Implements a preprocessor directive. |
97 | void Directive(const TokenSequence &, Prescanner &); |
98 | |
99 | void PrintMacros(llvm::raw_ostream &out) const; |
100 | |
101 | private: |
102 | enum class IsElseActive { No, Yes }; |
103 | enum class CanDeadElseAppear { No, Yes }; |
104 | |
105 | CharBlock SaveTokenAsName(const CharBlock &); |
106 | TokenSequence ReplaceMacros(const TokenSequence &, Prescanner &, |
107 | std::optional<std::size_t> *partialFunctionLikeMacro = nullptr); |
108 | void SkipDisabledConditionalCode( |
109 | const std::string &, IsElseActive, Prescanner &, ProvenanceRange); |
110 | bool IsIfPredicateTrue(const TokenSequence &expr, std::size_t first, |
111 | std::size_t exprTokens, Prescanner &); |
112 | void LineDirective(const TokenSequence &, std::size_t, Prescanner &); |
113 | |
114 | AllSources &allSources_; |
115 | std::list<std::string> names_; |
116 | std::unordered_map<CharBlock, Definition> definitions_; |
117 | std::stack<CanDeadElseAppear> ifStack_; |
118 | }; |
119 | } // namespace Fortran::parser |
120 | #endif // FORTRAN_PARSER_PREPROCESSOR_H_ |
121 |
Warning: This file is not a C or C++ file. It does not have highlighting.