1 //===-- lib/Parser/parsing.cpp --------------------------------------------===// 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 #include "flang/Parser/parsing.h" 10 #include "preprocessor.h" 11 #include "prescan.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" 17 18 namespace Fortran::parser { 19 20 Parsing::Parsing(AllCookedSources &allCooked) : allCooked_{allCooked} {} 21 Parsing::~Parsing() {} 22 23 const SourceFile *Parsing::Prescan(const std::string &path, Options options) { 24 options_ = options; 25 AllSources &allSources{allCooked_.allSources()}; 26 if (options.isModuleFile) { 27 for (const auto &path : options.searchDirectories) { 28 allSources.AppendSearchPathDirectory(path); 29 } 30 } 31 32 std::string buf; 33 llvm::raw_string_ostream fileError{buf}; 34 const SourceFile *sourceFile; 35 if (path == "-") { 36 sourceFile = allSources.ReadStandardInput(fileError); 37 } else { 38 std::optional<std::string> currentDirectory{"."}; 39 sourceFile = allSources.Open(path, fileError, std::move(currentDirectory)); 40 } 41 if (!fileError.str().empty()) { 42 ProvenanceRange range{allSources.AddCompilerInsertion(path)}; 43 messages_.Say(range, "%s"_err_en_US, fileError.str()); 44 return sourceFile; 45 } 46 CHECK(sourceFile); 47 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); 56 } 57 } 58 59 Preprocessor preprocessor{allSources}; 60 if (!options.predefinitions.empty()) { 61 preprocessor.DefineStandardMacros(); 62 for (const auto &predef : options.predefinitions) { 63 if (predef.second) { 64 preprocessor.Define(predef.first, *predef.second); 65 } else { 66 preprocessor.Undefine(predef.first); 67 } 68 } 69 } 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"); 78 } 79 if (options.features.IsEnabled(LanguageFeature::OpenMP)) { 80 prescanner.AddCompilerDirectiveSentinel("$omp"); 81 prescanner.AddCompilerDirectiveSentinel("$"); // OMP conditional line 82 } 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()); 90 } 91 currentCooked_->Marshal(allCooked_); 92 if (options.needProvenanceRangeToCharBlockMappings) { 93 currentCooked_->CompileProvenanceRangeToOffsetMappings(allSources); 94 } 95 return sourceFile; 96 } 97 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()}) { 103 out << **p; 104 } 105 } 106 107 void Parsing::DumpProvenance(llvm::raw_ostream &out) const { 108 allCooked_.Dump(out); 109 } 110 111 void Parsing::DumpParsingLog(llvm::raw_ostream &out) const { 112 log_.Dump(out, allCooked_); 113 } 114 115 void Parsing::Parse(llvm::raw_ostream &out) { 116 UserState userState{allCooked_, options_.features}; 117 userState.set_debugOutput(out) 118 .set_instrumentedParse(options_.instrumentedParse) 119 .set_log(&log_); 120 ParseState parseState{cooked()}; 121 parseState.set_inFixedForm(options_.isFixedForm).set_userState(&userState); 122 parseTree_ = program.Parse(parseState); 123 CHECK( 124 !parseState.anyErrorRecovery() || parseState.messages().AnyFatalError()); 125 consumedWholeFile_ = parseState.IsAtEnd(); 126 messages_.Annex(std::move(parseState.messages())); 127 finalRestingPlace_ = parseState.GetLocation(); 128 } 129 130 void Parsing::ClearLog() { log_.clear(); } 131 132 } // namespace Fortran::parser 133