blob: aed818f64e4bdc557d88d6258ca016d13eae0f54 [file] [log] [blame]
Tim Keith18cee3e2018-05-01 19:50:341// Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
peter klausler79d044e2018-03-01 00:56:1015#include "parsing.h"
16#include "grammar.h"
peter klausler2c06be32018-04-19 20:03:2317#include "instrumented-parser.h"
peter klausler79d044e2018-03-01 00:56:1018#include "message.h"
peter klauslerefed3002018-06-14 16:35:3819#include "openmp-grammar.h"
peter klausler79d044e2018-03-01 00:56:1020#include "preprocessor.h"
21#include "prescan.h"
22#include "provenance.h"
23#include "source.h"
24#include <sstream>
25
Tim Keith7f66c0a2018-05-02 20:48:1226namespace Fortran::parser {
peter klausler79d044e2018-03-01 00:56:1027
peter klausleraf22e07f2018-04-02 22:51:0428void Parsing::Prescan(const std::string &path, Options options) {
peter klausler79d044e2018-03-01 00:56:1029 options_ = options;
30
31 std::stringstream fileError;
peter klausler21699932018-04-06 17:34:5932 const SourceFile *sourceFile;
33 if (path == "-") {
34 sourceFile = allSources_.ReadStandardInput(&fileError);
35 } else {
36 sourceFile = allSources_.Open(path, &fileError);
37 }
peter klausler79d044e2018-03-01 00:56:1038 if (sourceFile == nullptr) {
39 ProvenanceRange range{allSources_.AddCompilerInsertion(path)};
peter klausleraf22e07f2018-04-02 22:51:0440 MessageFormattedText msg("%s"_err_en_US, fileError.str().data());
peter klauslere6b1f1f2018-04-23 19:17:1141 messages_.Put(Message{range, std::move(msg)});
peter klausleraf22e07f2018-04-02 22:51:0442 return;
peter klausler79d044e2018-03-01 00:56:1043 }
peter klausler424ec7b2018-03-20 17:59:0744 if (sourceFile->bytes() == 0) {
45 ProvenanceRange range{allSources_.AddCompilerInsertion(path)};
peter klauslere6b1f1f2018-04-23 19:17:1146 messages_.Put(Message{range, "file is empty"_err_en_US});
peter klausleraf22e07f2018-04-02 22:51:0447 return;
peter klausler424ec7b2018-03-20 17:59:0748 }
peter klausler79d044e2018-03-01 00:56:1049
peter klausler21699932018-04-06 17:34:5950 // N.B. Be sure to not push the search directory paths until 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.
peter klausler0983fbc2018-03-16 23:13:4954 for (const auto &path : options.searchDirectories) {
55 allSources_.PushSearchPathDirectory(path);
56 }
57
peter klausler75b29332018-03-23 22:14:5258 Preprocessor preprocessor{allSources_};
peter klausler0983fbc2018-03-16 23:13:4959 for (const auto &predef : options.predefinitions) {
60 if (predef.second.has_value()) {
61 preprocessor.Define(predef.first, *predef.second);
62 } else {
63 preprocessor.Undefine(predef.first);
64 }
65 }
peter klausler75b29332018-03-23 22:14:5266 Prescanner prescanner{messages_, cooked_, preprocessor};
peter klausler79d044e2018-03-01 00:56:1067 prescanner.set_fixedForm(options.isFixedForm)
68 .set_fixedFormColumnLimit(options.fixedFormColumns)
69 .set_encoding(options.encoding)
peter klauslerf701b422018-07-17 23:58:2170 .set_enableBackslashEscapesInCharLiterals( // TODO pmk
71 options.enabled.test(LanguageFeature::BackslashEscapes))
72 .set_enableOldDebugLines(
73 options.enabled.test(LanguageFeature::OldDebugLines))
peter klauslerd5a084c2018-03-30 23:21:1274 .set_warnOnNonstandardUsage(options_.isStrictlyStandard)
peter klausler75b29332018-03-23 22:14:5275 .AddCompilerDirectiveSentinel("dir$");
peter klauslerf701b422018-07-17 23:58:2176 if (options.enabled.test(LanguageFeature::OpenMP)) {
Hongyon Suauthai6f7b4fa2018-05-16 14:28:5477 prescanner.AddCompilerDirectiveSentinel("$omp");
78 }
peter klausler79d044e2018-03-01 00:56:1079 ProvenanceRange range{
80 allSources_.AddIncludedFile(*sourceFile, ProvenanceRange{})};
peter klausleraf22e07f2018-04-02 22:51:0481 prescanner.Prescan(range);
peter klausler79d044e2018-03-01 00:56:1082 cooked_.Marshal();
peter klausler79d044e2018-03-01 00:56:1083}
84
85void Parsing::DumpCookedChars(std::ostream &out) const {
peter klauslerc387b6d2018-04-20 18:23:5186 UserState userState{cooked_};
peter klausler79d044e2018-03-01 00:56:1087 ParseState parseState{cooked_};
88 parseState.set_inFixedForm(options_.isFixedForm).set_userState(&userState);
peter klausler10907c72018-04-02 23:33:1089 while (std::optional<const char *> p{parseState.GetNextChar()}) {
90 out << **p;
peter klausler79d044e2018-03-01 00:56:1091 }
92}
93
94void Parsing::DumpProvenance(std::ostream &out) const { cooked_.Dump(out); }
95
peter klausler56b09e02018-04-19 22:46:0296void Parsing::DumpParsingLog(std::ostream &out) const {
97 log_.Dump(out, cooked_);
98}
peter klausler2c06be32018-04-19 20:03:2399
peter klausler30f337a2018-04-20 23:14:57100void Parsing::Parse(std::ostream *out) {
peter klauslerc387b6d2018-04-20 18:23:51101 UserState userState{cooked_};
peter klausler30f337a2018-04-20 23:14:57102 userState.set_debugOutput(out)
103 .set_instrumentedParse(options_.instrumentedParse)
104 .set_log(&log_);
peter klauslerf701b422018-07-17 23:58:21105 userState.Enable(options_.enabled);
106 userState.EnableWarnings(options_.warning);
peter klausler79d044e2018-03-01 00:56:10107 ParseState parseState{cooked_};
108 parseState.set_inFixedForm(options_.isFixedForm)
109 .set_encoding(options_.encoding)
peter klausler79d044e2018-03-01 00:56:10110 .set_userState(&userState);
peter klauslerc387b6d2018-04-20 18:23:51111 parseTree_ = program.Parse(parseState);
peter klausleraf22e07f2018-04-02 22:51:04112 CHECK(
peter klauslerf5954622018-04-13 23:00:03113 !parseState.anyErrorRecovery() || parseState.messages().AnyFatalError());
peter klausler79d044e2018-03-01 00:56:10114 consumedWholeFile_ = parseState.IsAtEnd();
peter klausler79d044e2018-03-01 00:56:10115 messages_.Annex(parseState.messages());
peter klausler43c64d22018-04-17 22:47:51116 finalRestingPlace_ = parseState.GetLocation();
peter klausleraf22e07f2018-04-02 22:51:04117}
118
peter klausler73354822018-04-20 00:02:12119void Parsing::ClearLog() { log_.clear(); }
120
peter klausler1e1ea722018-04-02 23:06:18121bool Parsing::ForTesting(std::string path, std::ostream &err) {
122 Prescan(path, Options{});
123 if (messages_.AnyFatalError()) {
peter klausler56b09e02018-04-19 22:46:02124 messages_.Emit(err, cooked_);
peter klausleraf22e07f2018-04-02 22:51:04125 err << "could not scan " << path << '\n';
peter klausler1e1ea722018-04-02 23:06:18126 return false;
peter klausleraf22e07f2018-04-02 22:51:04127 }
peter klausler1e1ea722018-04-02 23:06:18128 Parse();
peter klausler56b09e02018-04-19 22:46:02129 messages_.Emit(err, cooked_);
peter klausler1e1ea722018-04-02 23:06:18130 if (!consumedWholeFile_) {
peter klausler5e69a752018-05-02 19:07:49131 EmitMessage(err, finalRestingPlace_, "parser FAIL; final position");
peter klausler1e1ea722018-04-02 23:06:18132 return false;
peter klausleraf22e07f2018-04-02 22:51:04133 }
peter klausler1e1ea722018-04-02 23:06:18134 if (messages_.AnyFatalError() || !parseTree_.has_value()) {
peter klausleraf22e07f2018-04-02 22:51:04135 err << "could not parse " << path << '\n';
peter klausler1e1ea722018-04-02 23:06:18136 return false;
peter klausleraf22e07f2018-04-02 22:51:04137 }
peter klausler1e1ea722018-04-02 23:06:18138 return true;
peter klausler79d044e2018-03-01 00:56:10139}
Tim Keith7f66c0a2018-05-02 20:48:12140
141} // namespace Fortran::parser