1 //===-- lib/Parser/parsing.cpp --------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "flang/Parser/parsing.h"
10 #include "preprocessor.h"
12 #include "type-parsers.h"
13 #include "flang/Parser/message.h"
14 #include "flang/Parser/provenance.h"
15 #include "flang/Parser/source.h"
16 #include "llvm/Support/raw_ostream.h"
18 namespace Fortran::parser
{
20 Parsing::Parsing(AllCookedSources
&allCooked
) : allCooked_
{allCooked
} {}
21 Parsing::~Parsing() {}
23 const SourceFile
*Parsing::Prescan(const std::string
&path
, Options options
) {
25 AllSources
&allSources
{allCooked_
.allSources()};
26 if (options
.isModuleFile
) {
27 for (const auto &path
: options
.searchDirectories
) {
28 allSources
.AppendSearchPathDirectory(path
);
33 llvm::raw_string_ostream fileError
{buf
};
34 const SourceFile
*sourceFile
;
36 sourceFile
= allSources
.ReadStandardInput(fileError
);
38 std::optional
<std::string
> currentDirectory
{"."};
39 sourceFile
= allSources
.Open(path
, fileError
, std::move(currentDirectory
));
41 if (!fileError
.str().empty()) {
42 ProvenanceRange range
{allSources
.AddCompilerInsertion(path
)};
43 messages_
.Say(range
, "%s"_err_en_US
, fileError
.str());
48 if (!options
.isModuleFile
) {
49 // For .mod files we always want to look in the search directories.
50 // For normal source files we don't add them until after the primary
51 // source file has been opened. If foo.f is missing from the current
52 // working directory, we don't want to accidentally read another foo.f
53 // from another directory that's on the search path.
54 for (const auto &path
: options
.searchDirectories
) {
55 allSources
.AppendSearchPathDirectory(path
);
59 Preprocessor preprocessor
{allSources
};
60 if (!options
.predefinitions
.empty()) {
61 preprocessor
.DefineStandardMacros();
62 for (const auto &predef
: options
.predefinitions
) {
64 preprocessor
.Define(predef
.first
, *predef
.second
);
66 preprocessor
.Undefine(predef
.first
);
70 currentCooked_
= &allCooked_
.NewCookedSource();
71 Prescanner prescanner
{
72 messages_
, *currentCooked_
, preprocessor
, options
.features
};
73 prescanner
.set_fixedForm(options
.isFixedForm
)
74 .set_fixedFormColumnLimit(options
.fixedFormColumns
)
75 .AddCompilerDirectiveSentinel("dir$");
76 if (options
.features
.IsEnabled(LanguageFeature::OpenACC
)) {
77 prescanner
.AddCompilerDirectiveSentinel("$acc");
79 if (options
.features
.IsEnabled(LanguageFeature::OpenMP
)) {
80 prescanner
.AddCompilerDirectiveSentinel("$omp");
81 prescanner
.AddCompilerDirectiveSentinel("$"); // OMP conditional line
83 ProvenanceRange range
{allSources
.AddIncludedFile(
84 *sourceFile
, ProvenanceRange
{}, options
.isModuleFile
)};
85 prescanner
.Prescan(range
);
86 if (currentCooked_
->BufferedBytes() == 0 && !options
.isModuleFile
) {
87 // Input is empty. Append a newline so that any warning
88 // message about nonstandard usage will have provenance.
89 currentCooked_
->Put('\n', range
.start());
91 currentCooked_
->Marshal(allCooked_
);
92 if (options
.needProvenanceRangeToCharBlockMappings
) {
93 currentCooked_
->CompileProvenanceRangeToOffsetMappings(allSources
);
98 void Parsing::DumpCookedChars(llvm::raw_ostream
&out
) const {
99 UserState userState
{allCooked_
, common::LanguageFeatureControl
{}};
100 ParseState parseState
{cooked()};
101 parseState
.set_inFixedForm(options_
.isFixedForm
).set_userState(&userState
);
102 while (std::optional
<const char *> p
{parseState
.GetNextChar()}) {
107 void Parsing::DumpProvenance(llvm::raw_ostream
&out
) const {
108 allCooked_
.Dump(out
);
111 void Parsing::DumpParsingLog(llvm::raw_ostream
&out
) const {
112 log_
.Dump(out
, allCooked_
);
115 void Parsing::Parse(llvm::raw_ostream
&out
) {
116 UserState userState
{allCooked_
, options_
.features
};
117 userState
.set_debugOutput(out
)
118 .set_instrumentedParse(options_
.instrumentedParse
)
120 ParseState parseState
{cooked()};
121 parseState
.set_inFixedForm(options_
.isFixedForm
).set_userState(&userState
);
122 parseTree_
= program
.Parse(parseState
);
124 !parseState
.anyErrorRecovery() || parseState
.messages().AnyFatalError());
125 consumedWholeFile_
= parseState
.IsAtEnd();
126 messages_
.Annex(std::move(parseState
.messages()));
127 finalRestingPlace_
= parseState
.GetLocation();
130 void Parsing::ClearLog() { log_
.clear(); }
132 } // namespace Fortran::parser