blob: d4cd111ea1a9da51871deb96a70cad14cef378fa [file] [log] [blame]
peter klausler79d044e2018-03-01 00:56:101#include "parsing.h"
2#include "grammar.h"
peter klausler2c06be32018-04-19 20:03:233#include "instrumented-parser.h"
peter klausler79d044e2018-03-01 00:56:104#include "message.h"
5#include "preprocessor.h"
6#include "prescan.h"
7#include "provenance.h"
8#include "source.h"
9#include <sstream>
10
11namespace Fortran {
12namespace parser {
13
peter klausleraf22e07f2018-04-02 22:51:0414void Parsing::Prescan(const std::string &path, Options options) {
peter klausler79d044e2018-03-01 00:56:1015 options_ = options;
16
17 std::stringstream fileError;
peter klausler21699932018-04-06 17:34:5918 const SourceFile *sourceFile;
19 if (path == "-") {
20 sourceFile = allSources_.ReadStandardInput(&fileError);
21 } else {
22 sourceFile = allSources_.Open(path, &fileError);
23 }
peter klausler79d044e2018-03-01 00:56:1024 if (sourceFile == nullptr) {
25 ProvenanceRange range{allSources_.AddCompilerInsertion(path)};
peter klausleraf22e07f2018-04-02 22:51:0426 MessageFormattedText msg("%s"_err_en_US, fileError.str().data());
peter klausler79d044e2018-03-01 00:56:1027 messages_.Put(Message(range.start(), std::move(msg)));
peter klausleraf22e07f2018-04-02 22:51:0428 return;
peter klausler79d044e2018-03-01 00:56:1029 }
peter klausler424ec7b2018-03-20 17:59:0730 if (sourceFile->bytes() == 0) {
31 ProvenanceRange range{allSources_.AddCompilerInsertion(path)};
peter klausleraf22e07f2018-04-02 22:51:0432 messages_.Put(Message{range.start(), "file is empty"_err_en_US});
33 return;
peter klausler424ec7b2018-03-20 17:59:0734 }
peter klausler79d044e2018-03-01 00:56:1035
peter klausler21699932018-04-06 17:34:5936 // N.B. Be sure to not push the search directory paths until the primary
37 // source file has been opened. If foo.f is missing from the current
38 // working directory, we don't want to accidentally read another foo.f
39 // from another directory that's on the search path.
peter klausler0983fbc2018-03-16 23:13:4940 for (const auto &path : options.searchDirectories) {
41 allSources_.PushSearchPathDirectory(path);
42 }
43
peter klausler75b29332018-03-23 22:14:5244 Preprocessor preprocessor{allSources_};
peter klausler0983fbc2018-03-16 23:13:4945 for (const auto &predef : options.predefinitions) {
46 if (predef.second.has_value()) {
47 preprocessor.Define(predef.first, *predef.second);
48 } else {
49 preprocessor.Undefine(predef.first);
50 }
51 }
peter klausler75b29332018-03-23 22:14:5252 Prescanner prescanner{messages_, cooked_, preprocessor};
peter klausler79d044e2018-03-01 00:56:1053 prescanner.set_fixedForm(options.isFixedForm)
54 .set_fixedFormColumnLimit(options.fixedFormColumns)
55 .set_encoding(options.encoding)
56 .set_enableBackslashEscapesInCharLiterals(options.enableBackslashEscapes)
peter klausler75b29332018-03-23 22:14:5257 .set_enableOldDebugLines(options.enableOldDebugLines)
peter klauslerd5a084c2018-03-30 23:21:1258 .set_warnOnNonstandardUsage(options_.isStrictlyStandard)
peter klausler75b29332018-03-23 22:14:5259 .AddCompilerDirectiveSentinel("dir$");
peter klausler79d044e2018-03-01 00:56:1060 ProvenanceRange range{
61 allSources_.AddIncludedFile(*sourceFile, ProvenanceRange{})};
peter klausleraf22e07f2018-04-02 22:51:0462 prescanner.Prescan(range);
peter klausler79d044e2018-03-01 00:56:1063 cooked_.Marshal();
peter klausler79d044e2018-03-01 00:56:1064}
65
66void Parsing::DumpCookedChars(std::ostream &out) const {
peter klausler79d044e2018-03-01 00:56:1067 UserState userState;
68 ParseState parseState{cooked_};
69 parseState.set_inFixedForm(options_.isFixedForm).set_userState(&userState);
peter klausler10907c72018-04-02 23:33:1070 while (std::optional<const char *> p{parseState.GetNextChar()}) {
71 out << **p;
peter klausler79d044e2018-03-01 00:56:1072 }
73}
74
75void Parsing::DumpProvenance(std::ostream &out) const { cooked_.Dump(out); }
76
peter klausler56b09e02018-04-19 22:46:0277void Parsing::DumpParsingLog(std::ostream &out) const {
78 log_.Dump(out, cooked_);
79}
peter klausler2c06be32018-04-19 20:03:2380
peter klausleraf22e07f2018-04-02 22:51:0481void Parsing::Parse() {
peter klausler79d044e2018-03-01 00:56:1082 UserState userState;
peter klausler56b09e02018-04-19 22:46:0283 if (options_.instrumentedParse || true /*pmk*/) {
peter klausler2c06be32018-04-19 20:03:2384 userState.set_log(&log_);
85 }
peter klausler79d044e2018-03-01 00:56:1086 ParseState parseState{cooked_};
87 parseState.set_inFixedForm(options_.isFixedForm)
88 .set_encoding(options_.encoding)
89 .set_warnOnNonstandardUsage(options_.isStrictlyStandard)
90 .set_warnOnDeprecatedUsage(options_.isStrictlyStandard)
91 .set_userState(&userState);
92 parseTree_ = program.Parse(&parseState);
peter klausleraf22e07f2018-04-02 22:51:0493 CHECK(
peter klauslerf5954622018-04-13 23:00:0394 !parseState.anyErrorRecovery() || parseState.messages().AnyFatalError());
peter klausler79d044e2018-03-01 00:56:1095 consumedWholeFile_ = parseState.IsAtEnd();
peter klausler79d044e2018-03-01 00:56:1096 messages_.Annex(parseState.messages());
peter klausler43c64d22018-04-17 22:47:5197 finalRestingPlace_ = parseState.GetLocation();
peter klausleraf22e07f2018-04-02 22:51:0498}
99
peter klausler1e1ea722018-04-02 23:06:18100bool Parsing::ForTesting(std::string path, std::ostream &err) {
101 Prescan(path, Options{});
102 if (messages_.AnyFatalError()) {
peter klausler56b09e02018-04-19 22:46:02103 messages_.Emit(err, cooked_);
peter klausleraf22e07f2018-04-02 22:51:04104 err << "could not scan " << path << '\n';
peter klausler1e1ea722018-04-02 23:06:18105 return false;
peter klausleraf22e07f2018-04-02 22:51:04106 }
peter klausler1e1ea722018-04-02 23:06:18107 Parse();
peter klausler56b09e02018-04-19 22:46:02108 messages_.Emit(err, cooked_);
peter klausler1e1ea722018-04-02 23:06:18109 if (!consumedWholeFile_) {
peter klausleraf22e07f2018-04-02 22:51:04110 err << "f18 parser FAIL; final position: ";
peter klausler1e1ea722018-04-02 23:06:18111 Identify(err, finalRestingPlace_, " ");
112 return false;
peter klausleraf22e07f2018-04-02 22:51:04113 }
peter klausler1e1ea722018-04-02 23:06:18114 if (messages_.AnyFatalError() || !parseTree_.has_value()) {
peter klausleraf22e07f2018-04-02 22:51:04115 err << "could not parse " << path << '\n';
peter klausler1e1ea722018-04-02 23:06:18116 return false;
peter klausleraf22e07f2018-04-02 22:51:04117 }
peter klausler1e1ea722018-04-02 23:06:18118 return true;
peter klausler79d044e2018-03-01 00:56:10119}
120} // namespace parser
121} // namespace Fortran