[flang] Add top-level Semantics class

Refactor to create the Semantics class that is responsible for holding
state during semantics (the scope tree and messages) and managing the
logic of the various phases of semantic processing. Eliminate static
Scope::globalScope.

The messages generated during semantic processing are accumulated in a
Messages data member of Semantics so that individual phases don't need
to emit them to std::cerr. This is now done by the driver so that it has
control over where they go and eliminates other includes of iostream.
To do this, the messages object is passed in to the various semantics
operations.

Move DumpSymbols into semantics.cc: it doesn't belong in resolve-names.cc
and it depends on the global scope, so it's as good a place as any.
The call to RewriteParseTree is also moved to Semantics.

Original-commit: flang-compiler/f18@771d0e1293
Reviewed-on: https://github.com/flang-compiler/f18/pull/186
Tree-same-pre-rewrite: false
This commit is contained in:
Tim Keith 2018-09-14 15:04:50 -07:00
parent cd839623ec
commit 7edb7ec69b
16 changed files with 244 additions and 147 deletions

View File

@ -17,10 +17,11 @@ add_library(FortranSemantics
attr.cc
expression.cc
mod-file.cc
resolve-names.cc
resolve-labels.cc
resolve-names.cc
rewrite-parse-tree.cc
scope.cc
semantics.cc
symbol.cc
type.cc
unparse-with-symbols.cc

View File

@ -14,6 +14,7 @@
#include "attr.h"
#include "../common/idioms.h"
#include <ostream>
#include <stddef.h>
namespace Fortran::semantics {

View File

@ -18,7 +18,6 @@
#include "../common/enum-set.h"
#include "../common/idioms.h"
#include <cinttypes>
#include <iostream>
#include <string>
namespace Fortran::semantics {

View File

@ -15,15 +15,11 @@
#include "mod-file.h"
#include "scope.h"
#include "symbol.h"
#include "../parser/message.h"
#include "../parser/parsing.h"
#include <algorithm>
#include <cerrno>
#include <cstring>
#include <fstream>
#include <functional>
#include <ostream>
#include <sstream>
#include <sys/stat.h>
#include <sys/types.h>
#include <vector>
@ -57,15 +53,11 @@ static bool FileContentsMatch(
static std::string GetHeader(const std::string &);
static std::size_t GetFileSize(const std::string &);
bool ModFileWriter::WriteAll() {
WriteChildren(Scope::globalScope);
return errors_.empty();
}
void ModFileWriter::WriteChildren(const Scope &scope) {
bool ModFileWriter::WriteAll(const Scope &scope) {
for (const auto &child : scope.children()) {
WriteOne(child);
}
return errors_.empty();
}
void ModFileWriter::WriteOne(const Scope &scope) {
@ -74,7 +66,7 @@ void ModFileWriter::WriteOne(const Scope &scope) {
if (!symbol->test(Symbol::Flag::ModFile)) {
Write(*symbol);
}
WriteChildren(scope); // write out submodules
WriteAll(scope); // write out submodules
}
}
@ -463,7 +455,8 @@ static std::size_t GetFileSize(const std::string &path) {
}
}
Scope *ModFileReader::Read(const SourceName &name, Scope *ancestor) {
Scope *ModFileReader::Read(
Scope &globalScope, const SourceName &name, Scope *ancestor) {
std::string ancestorName; // empty for module
if (ancestor) {
if (auto *scope{ancestor->FindSubmodule(name)}) {
@ -471,8 +464,8 @@ Scope *ModFileReader::Read(const SourceName &name, Scope *ancestor) {
}
ancestorName = ancestor->name().ToString();
} else {
auto it{Scope::globalScope.find(name)};
if (it != Scope::globalScope.end()) {
auto it{globalScope.find(name)};
if (it != globalScope.end()) {
return it->second->scope();
}
}
@ -492,7 +485,7 @@ Scope *ModFileReader::Read(const SourceName &name, Scope *ancestor) {
parser::Options options;
options.isModuleFile = true;
parsing.Prescan(*path, options);
parsing.Parse(&std::cout);
parsing.Parse(nullptr);
auto &parseTree{parsing.parseTree()};
if (!parsing.messages().empty() || !parsing.consumedWholeFile() ||
!parseTree.has_value()) {
@ -502,13 +495,13 @@ Scope *ModFileReader::Read(const SourceName &name, Scope *ancestor) {
}
Scope *parentScope; // the scope this module/submodule goes into
if (!ancestor) {
parentScope = &Scope::globalScope;
parentScope = &globalScope;
} else if (auto *parent{GetSubmoduleParent(*parseTree)}) {
parentScope = Read(*parent, ancestor);
parentScope = Read(globalScope, *parent, ancestor);
} else {
parentScope = ancestor;
}
ResolveNames(*parentScope, *parseTree, parsing.cooked(), directories_);
ResolveNames(errors_, *parentScope, *parseTree, directories_);
const auto &it{parentScope->find(name)};
if (it == parentScope->end()) {
return nullptr;

View File

@ -18,8 +18,6 @@
#include "attr.h"
#include "resolve-names.h"
#include "../parser/message.h"
#include "../parser/provenance.h"
#include <iosfwd>
#include <set>
#include <sstream>
#include <string>
@ -41,10 +39,10 @@ public:
void set_directory(const std::string &dir) { dir_ = dir; }
// Errors encountered during writing. Non-empty if WriteAll returns false.
parser::Messages &errors() { return errors_; }
parser::Messages &&errors() { return std::move(errors_); }
// Write out all .mod files; if error return false.
bool WriteAll();
bool WriteAll(const Scope &);
private:
std::string dir_{"."};
@ -56,7 +54,6 @@ private:
// Any errors encountered during writing:
parser::Messages errors_;
void WriteChildren(const Scope &);
void WriteOne(const Scope &);
void Write(const Symbol &);
std::string GetAsString(const Symbol &);
@ -77,7 +74,7 @@ public:
// Find and read the module file for a module or submodule.
// If ancestor is specified, look for a submodule of that module.
// Return the Scope for that module/submodule or nullptr on error.
Scope *Read(const SourceName &, Scope *ancestor = nullptr);
Scope *Read(Scope &, const SourceName &, Scope *ancestor = nullptr);
// Errors that occurred when Read returns nullptr.
parser::Messages &errors() { return errors_; }

View File

@ -18,7 +18,6 @@
#include "../parser/parse-tree-visitor.h"
#include <cctype>
#include <cstdarg>
#include <iostream>
namespace Fortran::semantics {
@ -217,12 +216,8 @@ struct UnitAnalysis {
class ParseTreeAnalyzer {
public:
ParseTreeAnalyzer() {}
ParseTreeAnalyzer(ParseTreeAnalyzer &&that)
: programUnits_{std::move(that.programUnits_)},
errorHandler_{std::move(that.errorHandler_)}, currentPosition_{std::move(
that.currentPosition_)},
constructNames_{std::move(that.constructNames_)} {}
ParseTreeAnalyzer(parser::Messages &errorHandler)
: errorHandler_{errorHandler} {}
template<typename A> constexpr bool Pre(const A &) { return true; }
template<typename A> constexpr void Post(const A &) {}
@ -827,7 +822,7 @@ private:
}
std::vector<UnitAnalysis> programUnits_;
parser::Messages errorHandler_;
parser::Messages &errorHandler_;
parser::CharBlock currentPosition_{nullptr};
ProxyForScope currentScope_{0};
std::vector<std::string> constructNames_;
@ -843,8 +838,9 @@ bool InInclusiveScope(const std::vector<ProxyForScope> &scopes,
return true;
}
ParseTreeAnalyzer LabelAnalysis(const parser::Program &program) {
ParseTreeAnalyzer analysis;
ParseTreeAnalyzer LabelAnalysis(
parser::Messages &errorHandler, const parser::Program &program) {
ParseTreeAnalyzer analysis{errorHandler};
Walk(program, analysis);
return analysis;
}
@ -1040,8 +1036,7 @@ void CheckDataTransferConstraints(const SourceStmtList &dataTransfers,
CheckDataXferTargetConstraints(dataTransfers, labels, errorHandler);
}
bool CheckConstraints(ParseTreeAnalyzer &&parseTreeAnalysis,
const parser::CookedSource &cookedSource) {
bool CheckConstraints(ParseTreeAnalyzer &&parseTreeAnalysis) {
auto &errorHandler{parseTreeAnalysis.errorHandler()};
for (const auto &programUnit : parseTreeAnalysis.programUnits()) {
const auto &dos{programUnit.doStmtSources};
@ -1053,15 +1048,12 @@ bool CheckConstraints(ParseTreeAnalyzer &&parseTreeAnalysis,
const auto &dataTransfers{programUnit.formatStmtSources};
CheckDataTransferConstraints(dataTransfers, labels, scopes, errorHandler);
}
if (!errorHandler.empty()) {
errorHandler.Emit(std::cerr, cookedSource);
}
return !errorHandler.AnyFatalError();
}
bool ValidateLabels(
const parser::Program &program, const parser::CookedSource &cookedSource) {
return CheckConstraints(LabelAnalysis(program), cookedSource);
parser::Messages &errorHandler, const parser::Program &program) {
return CheckConstraints(LabelAnalysis(errorHandler, program));
}
} // namespace Fortran::semantics

View File

@ -16,18 +16,17 @@
#define FORTRAN_SEMANTICS_RESOLVE_LABELS_H_
namespace Fortran::parser {
class Messages;
struct Program;
class CookedSource;
} // namespace Fortran::parser
namespace Fortran::semantics {
/// \brief Validate the labels in the program
/// \param ParseTree the parse tree
/// \param Source the cooked source
/// \param messages where to emit messages
/// \param program the parse tree of the program
/// \return true, iff the program's labels pass semantics checks
bool ValidateLabels(
const parser::Program &ParseTree, const parser::CookedSource &Source);
} // namespace Fortran::semantics
bool ValidateLabels(parser::Messages &messages, const parser::Program &program);
} // namespace Fortran::semantics
#endif // FORTRAN_SEMANTICS_RESOLVE_LABELS_H_

View File

@ -187,7 +187,7 @@ public:
using Message = parser::Message;
using MessageFixedText = parser::MessageFixedText;
const parser::Messages &messages() const { return messages_; }
void set_messages(parser::Messages &messages) { messages_ = &messages; }
template<typename T> bool Pre(const parser::Statement<T> &x) {
currStmtSource_ = &x.source;
@ -218,14 +218,13 @@ public:
private:
// Where messages are emitted:
parser::Messages messages_;
parser::Messages *messages_;
// Source location of current statement; null if not in a statement
const SourceName *currStmtSource_{nullptr};
};
// Visit ImplicitStmt and related parse tree nodes and updates implicit rules.
class ImplicitRulesVisitor : public DeclTypeSpecVisitor,
public virtual MessageHandler {
class ImplicitRulesVisitor : public DeclTypeSpecVisitor, public MessageHandler {
public:
using DeclTypeSpecVisitor::Post;
using DeclTypeSpecVisitor::Pre;
@ -301,12 +300,13 @@ private:
};
// Manage a stack of Scopes
class ScopeHandler : public virtual ImplicitRulesVisitor {
class ScopeHandler : public ImplicitRulesVisitor {
public:
void set_rootScope(Scope &scope) { PushScope(scope); }
Scope &currScope() { return *currScope_; }
// The enclosing scope, skipping blocks and derived types.
Scope &InclusiveScope();
// The global scope, containing program units.
Scope &GlobalScope();
// Create a new scope and push it on the scope stack.
void PushScope(Scope::Kind kind, Symbol *symbol);
@ -646,6 +646,11 @@ public:
using SubprogramVisitor::Post;
using SubprogramVisitor::Pre;
ResolveNamesVisitor(parser::Messages &messages, Scope &rootScope) {
set_messages(messages);
PushScope(rootScope);
}
// Default action for a parse tree node is to visit children.
template<typename T> bool Pre(const T &) { return true; }
template<typename T> void Post(const T &) {}
@ -963,7 +968,7 @@ int DeclTypeSpecVisitor::GetKindParamValue(
MessageHandler::Message &MessageHandler::Say(MessageFixedText &&msg) {
CHECK(currStmtSource_);
return messages_.Say(*currStmtSource_, std::move(msg));
return messages_->Say(*currStmtSource_, std::move(msg));
}
MessageHandler::Message &MessageHandler::Say(
const SourceName &name, MessageFixedText &&msg) {
@ -971,15 +976,15 @@ MessageHandler::Message &MessageHandler::Say(
}
MessageHandler::Message &MessageHandler::Say(
const parser::Name &name, MessageFixedText &&msg) {
return messages_.Say(name.source, std::move(msg), name.ToString().c_str());
return messages_->Say(name.source, std::move(msg), name.ToString().c_str());
}
MessageHandler::Message &MessageHandler::Say(const SourceName &location,
MessageFixedText &&msg, const std::string &arg1) {
return messages_.Say(location, std::move(msg), arg1.c_str());
return messages_->Say(location, std::move(msg), arg1.c_str());
}
MessageHandler::Message &MessageHandler::Say(const SourceName &location,
MessageFixedText &&msg, const SourceName &arg1, const SourceName &arg2) {
return messages_.Say(location, std::move(msg), arg1.ToString().c_str(),
return messages_->Say(location, std::move(msg), arg1.ToString().c_str(),
arg2.ToString().c_str());
}
void MessageHandler::SayAlreadyDeclared(
@ -992,7 +997,7 @@ void MessageHandler::Say2(const SourceName &name1, MessageFixedText &&msg1,
Say(name1, std::move(msg1)).Attach(name2, msg2, name2.ToString().c_str());
}
void MessageHandler::Annex(parser::Messages &&msgs) {
messages_.Annex(std::move(msgs));
messages_->Annex(std::move(msgs));
}
// ImplicitRulesVisitor implementation
@ -1184,6 +1189,15 @@ Scope &ScopeHandler::InclusiveScope() {
return *scope;
}
}
common::die("inclusive scope not found");
}
Scope &ScopeHandler::GlobalScope() {
for (auto *scope = currScope_; scope; scope = &scope->parent()) {
if (scope->kind() == Scope::Kind::Global) {
return *scope;
}
}
common::die("global scope not found");
}
void ScopeHandler::PushScope(Scope::Kind kind, Symbol *symbol) {
PushScope(currScope().MakeScope(kind, symbol));
@ -1411,7 +1425,7 @@ Symbol &ModuleVisitor::BeginModule(const SourceName &name, bool isSubmodule,
// If an error occurs, report it and return nullptr.
Scope *ModuleVisitor::FindModule(const SourceName &name, Scope *ancestor) {
ModFileReader reader{searchDirectories_};
auto *scope{reader.Read(name, ancestor)};
auto *scope{reader.Read(GlobalScope(), name, ancestor)};
if (!scope) {
Annex(std::move(reader.errors()));
return nullptr;
@ -2842,20 +2856,14 @@ void ResolveNamesVisitor::Post(const parser::Program &) {
CHECK(!GetDeclTypeSpec());
}
void ResolveNames(Scope &rootScope, parser::Program &program,
const parser::CookedSource &cookedSource,
void ResolveNames(parser::Messages &messages, Scope &rootScope,
const parser::Program &program,
const std::vector<std::string> &searchDirectories) {
ResolveNamesVisitor visitor;
visitor.set_rootScope(rootScope);
ResolveNamesVisitor visitor{messages, rootScope};
for (auto &dir : searchDirectories) {
visitor.add_searchDirectory(dir);
}
parser::Walk(const_cast<const parser::Program &>(program), visitor);
if (!visitor.messages().empty()) {
visitor.messages().Emit(std::cerr, cookedSource);
return;
}
RewriteParseTree(program, cookedSource);
parser::Walk(program, visitor);
}
// Map the enum in the parser to the one in GenericSpec
@ -2940,37 +2948,4 @@ static GenericSpec MapGenericSpec(const parser::GenericSpec &genericSpec) {
genericSpec.u);
}
static void PutIndent(std::ostream &os, int indent) {
for (int i = 0; i < indent; ++i) {
os << " ";
}
}
static void DumpSymbols(std::ostream &os, const Scope &scope, int indent = 0) {
PutIndent(os, indent);
os << Scope::EnumToString(scope.kind()) << " scope:";
if (const auto *symbol{scope.symbol()}) {
os << ' ' << symbol->name().ToString();
}
os << '\n';
++indent;
for (const auto &pair : scope) {
const auto &symbol{*pair.second};
PutIndent(os, indent);
os << symbol << '\n';
if (const auto *details{symbol.detailsIf<GenericDetails>()}) {
if (const auto &type{details->derivedType()}) {
PutIndent(os, indent);
os << *type << '\n';
}
}
}
for (const auto &child : scope.children()) {
DumpSymbols(os, child, indent);
}
--indent;
}
void DumpSymbols(std::ostream &os) { DumpSymbols(os, Scope::globalScope); }
} // namespace Fortran::semantics

View File

@ -16,19 +16,20 @@
#define FORTRAN_SEMANTICS_RESOLVE_NAMES_H_
#include <iosfwd>
#include <string>
#include <vector>
namespace Fortran::parser {
class Messages;
struct Program;
class CookedSource;
} // namespace Fortran::parser
namespace Fortran::semantics {
class Scope;
void ResolveNames(Scope &rootScope, parser::Program &,
const parser::CookedSource &, const std::vector<std::string> &);
void ResolveNames(parser::Messages &, Scope &, const parser::Program &,
const std::vector<std::string> &);
void DumpSymbols(std::ostream &);
} // namespace Fortran::semantics

View File

@ -31,9 +31,8 @@ using symbolMap = std::map<const char *, Symbol *>;
/// Convert mis-identified statement functions to array element assignments.
class RewriteMutator {
public:
RewriteMutator(const symbolMap &symbols) : symbols_{symbols} {}
const parser::Messages &messages() const { return messages_; }
RewriteMutator(parser::Messages &messages, const symbolMap &symbols)
: messages_{messages}, symbols_{symbols} {}
// Default action for a parse tree node is to visit children.
template<typename T> bool Pre(T &) { return true; }
@ -67,9 +66,9 @@ private:
using stmtFuncType =
parser::Statement<common::Indirection<parser::StmtFunctionStmt>>;
bool errorOnUnresolvedName_{true};
parser::Messages &messages_;
const symbolMap &symbols_;
std::list<stmtFuncType> stmtFuncsToConvert_;
parser::Messages messages_;
// For T = Variable or Expr, if x has a function reference that really
// should be an array element reference (i.e. the name occurs in an
@ -95,7 +94,7 @@ void RewriteMutator::Post(parser::Name &name) {
if (it != symbols_.end()) {
name.symbol = it->second;
} else if (errorOnUnresolvedName_) {
messages_.Say(name.source, "Internal: no symbol found for '%s'"_err_en_US,
messages_.Say(name.source, "Internal: no symbol found for '%s'"_en_US,
name.ToString().c_str());
}
}
@ -136,7 +135,7 @@ static void CollectSymbol(Symbol &symbol, symbolMap &symbols) {
}
}
static void CollectSymbols(Scope &scope, symbolMap &symbols) {
static void CollectSymbols(const Scope &scope, symbolMap &symbols) {
for (auto &pair : scope) {
Symbol *symbol{pair.second};
CollectSymbol(*symbol, symbols);
@ -152,12 +151,11 @@ static void CollectSymbols(Scope &scope, symbolMap &symbols) {
}
void RewriteParseTree(
parser::Program &program, const parser::CookedSource &cookedSource) {
parser::Messages &messages, const Scope &scope, parser::Program &program) {
symbolMap symbols;
CollectSymbols(Scope::globalScope, symbols);
RewriteMutator mutator{symbols};
CollectSymbols(scope, symbols);
RewriteMutator mutator{messages, symbols};
parser::Walk(program, mutator);
mutator.messages().Emit(std::cerr, cookedSource);
}
} // namespace Fortran::semantics

View File

@ -16,12 +16,15 @@
#define FORTRAN_SEMANTICS_REWRITE_PARSE_TREE_H_
namespace Fortran::parser {
class Messages;
struct Program;
class CookedSource;
} // namespace Fortran::parser
namespace Fortran::semantics {
class Scope;
} // namespace Fortran::semantics
namespace Fortran::semantics {
void RewriteParseTree(parser::Program &, const parser::CookedSource &);
void RewriteParseTree(parser::Messages &, const Scope &, parser::Program &);
} // namespace Fortran::semantics
#endif // FORTRAN_SEMANTICS_REWRITE_PARSE_TREE_H_

View File

@ -18,9 +18,6 @@
namespace Fortran::semantics {
Scope Scope::systemScope{Scope::systemScope, Scope::Kind::System, nullptr};
Scope Scope::globalScope{Scope::systemScope, Scope::Kind::Global, nullptr};
Symbols<1024> Scope::allSymbols;
bool Scope::IsModule() const {

View File

@ -33,14 +33,12 @@ class Scope {
using mapType = std::map<SourceName, Symbol *>;
public:
// root of the scope tree; contains intrinsics:
static Scope systemScope;
static Scope globalScope; // contains program-units
ENUM_CLASS(
Kind, System, Global, Module, MainProgram, Subprogram, DerivedType, Block)
using ImportKind = common::ImportKind;
// Create the Global scope -- the root of the scope tree
Scope() : Scope{*this, Kind::Global, nullptr} {}
Scope(Scope &parent, Kind kind, Symbol *symbol)
: parent_{parent}, kind_{kind}, symbol_{symbol} {
if (symbol) {

View File

@ -0,0 +1,99 @@
// Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "semantics.h"
#include "mod-file.h"
#include "resolve-labels.h"
#include "resolve-names.h"
#include "rewrite-parse-tree.h"
#include "scope.h"
#include "symbol.h"
namespace Fortran::semantics {
static void DoDumpSymbols(std::ostream &, const Scope &, int indent = 0);
static void PutIndent(std::ostream &, int indent);
Semantics &Semantics::set_searchDirectories(
const std::vector<std::string> &directories) {
for (auto directory : directories) {
directories_.push_back(directory);
}
return *this;
}
Semantics &Semantics::set_moduleDirectory(const std::string &directory) {
moduleDirectory_ = directory;
directories_.insert(directories_.begin(), directory);
return *this;
}
bool Semantics::Perform(parser::Program &program) {
ValidateLabels(messages_, program);
if (AnyFatalError()) {
return false;
}
ResolveNames(messages_, globalScope_, program, directories_);
if (AnyFatalError()) {
return false;
}
RewriteParseTree(messages_, globalScope_, program);
if (AnyFatalError()) {
return false;
}
ModFileWriter writer;
writer.set_directory(moduleDirectory_);
if (!writer.WriteAll(globalScope_)) {
messages_.Annex(writer.errors());
return false;
}
return true;
}
void Semantics::DumpSymbols(std::ostream &os) {
DoDumpSymbols(os, globalScope_);
}
void DoDumpSymbols(std::ostream &os, const Scope &scope, int indent) {
PutIndent(os, indent);
os << Scope::EnumToString(scope.kind()) << " scope:";
if (const auto *symbol{scope.symbol()}) {
os << ' ' << symbol->name().ToString();
}
os << '\n';
++indent;
for (const auto &pair : scope) {
const auto &symbol{*pair.second};
PutIndent(os, indent);
os << symbol << '\n';
if (const auto *details{symbol.detailsIf<GenericDetails>()}) {
if (const auto &type{details->derivedType()}) {
PutIndent(os, indent);
os << *type << '\n';
}
}
}
for (const auto &child : scope.children()) {
DoDumpSymbols(os, child, indent);
}
--indent;
}
static void PutIndent(std::ostream &os, int indent) {
for (int i = 0; i < indent; ++i) {
os << " ";
}
}
} // namespace Fortran::semantics

View File

@ -0,0 +1,47 @@
// Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef FORTRAN_SEMANTICS_SEMANTICS_H_
#define FORTRAN_SEMANTICS_SEMANTICS_H_
#include "scope.h"
#include "../parser/message.h"
#include <string>
#include <vector>
namespace Fortran::parser {
struct Program;
}
namespace Fortran::semantics {
class Semantics {
public:
Semantics() { directories_.push_back("."s); }
const parser::Messages &messages() const { return messages_; }
Semantics &set_searchDirectories(const std::vector<std::string> &);
Semantics &set_moduleDirectory(const std::string &);
bool AnyFatalError() const { return messages_.AnyFatalError(); }
bool Perform(parser::Program &);
void DumpSymbols(std::ostream &);
private:
Scope globalScope_;
std::vector<std::string> directories_;
std::string moduleDirectory_{"."s};
parser::Messages messages_;
};
} // namespace Fortran::semantics
#endif

View File

@ -24,10 +24,7 @@
#include "../../lib/parser/unparse.h"
#include "../../lib/semantics/dump-parse-tree.h"
#include "../../lib/semantics/expression.h"
#include "../../lib/semantics/mod-file.h"
#include "../../lib/semantics/resolve-labels.h"
#include "../../lib/semantics/resolve-names.h"
#include "../../lib/semantics/scope.h"
#include "../../lib/semantics/semantics.h"
#include "../../lib/semantics/unparse-with-symbols.h"
#include <cerrno>
#include <cstdio>
@ -159,8 +156,8 @@ std::string RelocatableName(const DriverOptions &driver, std::string path) {
int exitStatus{EXIT_SUCCESS};
std::string CompileFortran(
std::string path, Fortran::parser::Options options, DriverOptions &driver) {
std::string CompileFortran(std::string path, Fortran::parser::Options options,
DriverOptions &driver, Fortran::semantics::Semantics &semantics) {
if (!driver.forcedForm) {
auto dot{path.rfind(".")};
if (dot != std::string::npos) {
@ -211,20 +208,17 @@ std::string CompileFortran(
}
if (driver.debugResolveNames || driver.dumpSymbols ||
driver.dumpUnparseWithSymbols || driver.debugExpressions) {
std::vector<std::string> directories{options.searchDirectories};
directories.insert(directories.begin(), "."s);
if (driver.moduleDirectory != "."s) {
directories.insert(directories.begin(), driver.moduleDirectory);
}
(void)Fortran::semantics::ValidateLabels(parseTree, parsing.cooked());
Fortran::semantics::ResolveNames(Fortran::semantics::Scope::globalScope,
parseTree, parsing.cooked(), directories);
Fortran::semantics::ModFileWriter writer;
writer.set_directory(driver.moduleDirectory);
writer.WriteAll();
writer.errors().Emit(std::cerr, parsing.cooked());
semantics.Perform(parseTree);
auto &messages{semantics.messages()};
messages.Emit(std::cerr, parsing.cooked());
if (driver.dumpSymbols) {
Fortran::semantics::DumpSymbols(std::cout);
semantics.DumpSymbols(std::cout);
}
if (!messages.empty() &&
(driver.warningsAreErrors || messages.AnyFatalError())) {
std::cerr << driver.prefix << "semantic errors in " << path << '\n';
exitStatus = EXIT_FAILURE;
return {};
}
if (driver.dumpUnparseWithSymbols) {
Fortran::semantics::UnparseWithSymbols(
@ -493,14 +487,17 @@ int main(int argc, char *const argv[]) {
driver.pgf90Args.push_back("-Mbackslash");
}
Fortran::semantics::Semantics semantics;
semantics.set_searchDirectories(options.searchDirectories);
semantics.set_moduleDirectory(driver.moduleDirectory);
if (!anyFiles) {
driver.measureTree = true;
driver.dumpUnparse = true;
CompileFortran("-", options, driver);
CompileFortran("-", options, driver, semantics);
return exitStatus;
}
for (const auto &path : fortranSources) {
std::string relo{CompileFortran(path, options, driver)};
std::string relo{CompileFortran(path, options, driver, semantics)};
if (!driver.compileOnly && !relo.empty()) {
relocatables.push_back(relo);
}