llvm-project/flang/tools/f18/f18.cpp

824 lines
30 KiB
C++

//===-- tools/f18/f18.cpp -------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// Temporary Fortran front end driver main program for development scaffolding.
#include "flang/Common/Fortran-features.h"
#include "flang/Common/default-kinds.h"
#include "flang/Evaluate/expression.h"
#include "flang/Lower/PFTBuilder.h"
#include "flang/Parser/characters.h"
#include "flang/Parser/dump-parse-tree.h"
#include "flang/Parser/message.h"
#include "flang/Parser/parse-tree-visitor.h"
#include "flang/Parser/parse-tree.h"
#include "flang/Parser/parsing.h"
#include "flang/Parser/provenance.h"
#include "flang/Parser/unparse.h"
#include "flang/Semantics/expression.h"
#include "flang/Semantics/runtime-type-info.h"
#include "flang/Semantics/semantics.h"
#include "flang/Semantics/unparse-with-symbols.h"
#include "flang/Version.inc"
#include "llvm/Support/Errno.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/FileUtilities.h"
#include "llvm/Support/Program.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/raw_ostream.h"
#include <cstdio>
#include <cstring>
#include <fstream>
#include <list>
#include <memory>
#include <optional>
#include <stdlib.h>
#include <string>
#include <vector>
static std::list<std::string> argList(int argc, char *const argv[]) {
std::list<std::string> result;
for (int j = 0; j < argc; ++j) {
result.emplace_back(argv[j]);
}
return result;
}
struct MeasurementVisitor {
template <typename A> bool Pre(const A &) { return true; }
template <typename A> void Post(const A &) {
++objects;
bytes += sizeof(A);
}
size_t objects{0}, bytes{0};
};
void MeasureParseTree(const Fortran::parser::Program &program) {
MeasurementVisitor visitor;
Fortran::parser::Walk(program, visitor);
llvm::outs() << "Parse tree comprises " << visitor.objects
<< " objects and occupies " << visitor.bytes
<< " total bytes.\n";
}
std::vector<std::string> filesToDelete;
void CleanUpAtExit() {
for (const auto &path : filesToDelete) {
if (!path.empty()) {
llvm::sys::fs::remove(path);
}
}
}
struct GetDefinitionArgs {
int line, startColumn, endColumn;
};
struct DriverOptions {
DriverOptions() {}
bool verbose{false}; // -v
bool compileOnly{false}; // -c
std::string outputPath; // -o path
std::vector<std::string> searchDirectories; // -I dir
std::string moduleDirectory{"."s}; // -module dir
std::string moduleFileSuffix{".mod"}; // -moduleSuffix suff
bool forcedForm{false}; // -Mfixed or -Mfree appeared
bool warnOnNonstandardUsage{false}; // -Mstandard
bool warningsAreErrors{false}; // -Werror
bool byteswapio{false}; // -byteswapio
Fortran::parser::Encoding encoding{Fortran::parser::Encoding::UTF_8};
bool syntaxOnly{false};
bool dumpProvenance{false};
bool dumpCookedChars{false};
bool dumpUnparse{false};
bool dumpUnparseWithSymbols{false};
bool dumpParseTree{false};
bool dumpPreFirTree{false};
bool dumpSymbols{false};
bool debugNoSemantics{false};
bool debugModuleWriter{false};
bool defaultReal8{false};
bool measureTree{false};
bool unparseTypedExprsToF18_FC{false};
std::vector<std::string> F18_FCArgs;
const char *prefix{nullptr};
bool getDefinition{false};
GetDefinitionArgs getDefinitionArgs{0, 0, 0};
bool getSymbolsSources{false};
std::optional<bool> forcePreprocessing; // -cpp & -nocpp
};
void Exec(std::vector<llvm::StringRef> &argv, bool verbose = false) {
if (verbose) {
for (size_t j{0}; j < argv.size(); ++j) {
llvm::errs() << (j > 0 ? " " : "") << argv[j];
}
llvm::errs() << '\n';
}
std::string ErrMsg;
llvm::ErrorOr<std::string> Program = llvm::sys::findProgramByName(argv[0]);
if (!Program)
ErrMsg = Program.getError().message();
if (!Program ||
llvm::sys::ExecuteAndWait(
Program.get(), argv, llvm::None, {}, 0, 0, &ErrMsg)) {
llvm::errs() << "execvp(" << argv[0] << ") failed: " << ErrMsg << '\n';
exit(EXIT_FAILURE);
}
}
void RunOtherCompiler(DriverOptions &driver, char *source, char *relo) {
std::vector<llvm::StringRef> argv;
for (size_t j{0}; j < driver.F18_FCArgs.size(); ++j) {
argv.push_back(driver.F18_FCArgs[j]);
}
char dashC[3] = "-c", dashO[3] = "-o";
argv.push_back(dashC);
argv.push_back(dashO);
argv.push_back(relo);
argv.push_back(source);
Exec(argv, driver.verbose);
}
std::string RelocatableName(const DriverOptions &driver, std::string path) {
if (driver.compileOnly && !driver.outputPath.empty()) {
return driver.outputPath;
}
std::string base{path};
auto slash{base.rfind("/")};
if (slash != std::string::npos) {
base = base.substr(slash + 1);
}
std::string relo{base};
auto dot{base.rfind(".")};
if (dot != std::string::npos) {
relo = base.substr(0, dot);
}
relo += ".o";
return relo;
}
int exitStatus{EXIT_SUCCESS};
static Fortran::parser::AnalyzedObjectsAsFortran asFortran{
[](llvm::raw_ostream &o, const Fortran::evaluate::GenericExprWrapper &x) {
if (x.v) {
x.v->AsFortran(o);
} else {
o << "(bad expression)";
}
},
[](llvm::raw_ostream &o,
const Fortran::evaluate::GenericAssignmentWrapper &x) {
if (x.v) {
x.v->AsFortran(o);
} else {
o << "(bad assignment)";
}
},
[](llvm::raw_ostream &o, const Fortran::evaluate::ProcedureRef &x) {
x.AsFortran(o << "CALL ");
},
};
std::string CompileFortran(std::string path, Fortran::parser::Options options,
DriverOptions &driver,
const Fortran::common::IntrinsicTypeDefaultKinds &defaultKinds) {
Fortran::parser::AllSources allSources;
Fortran::parser::AllCookedSources allCookedSources{allSources};
allSources.set_encoding(driver.encoding);
Fortran::semantics::SemanticsContext semanticsContext{
defaultKinds, options.features, allCookedSources};
semanticsContext.set_moduleDirectory(driver.moduleDirectory)
.set_moduleFileSuffix(driver.moduleFileSuffix)
.set_searchDirectories(driver.searchDirectories)
.set_warnOnNonstandardUsage(driver.warnOnNonstandardUsage)
.set_warningsAreErrors(driver.warningsAreErrors);
if (!driver.forcedForm) {
auto dot{path.rfind(".")};
if (dot != std::string::npos) {
std::string suffix{path.substr(dot + 1)};
options.isFixedForm = suffix == "f" || suffix == "F" || suffix == "ff";
}
}
options.searchDirectories = driver.searchDirectories;
Fortran::parser::Parsing parsing{allCookedSources};
parsing.Prescan(path, options);
if (!parsing.messages().empty() &&
(driver.warningsAreErrors || parsing.messages().AnyFatalError())) {
llvm::errs() << driver.prefix << "Could not scan " << path << '\n';
parsing.messages().Emit(llvm::errs(), allCookedSources);
exitStatus = EXIT_FAILURE;
return {};
}
if (driver.dumpProvenance) {
parsing.DumpProvenance(llvm::outs());
return {};
}
if (driver.dumpCookedChars) {
parsing.messages().Emit(llvm::errs(), allCookedSources);
parsing.DumpCookedChars(llvm::outs());
return {};
}
parsing.Parse(llvm::outs());
if (options.instrumentedParse) {
parsing.DumpParsingLog(llvm::outs());
return {};
}
parsing.ClearLog();
parsing.messages().Emit(llvm::errs(), allCookedSources);
if (!parsing.consumedWholeFile()) {
parsing.EmitMessage(llvm::errs(), parsing.finalRestingPlace(),
"Parser FAIL (final position)");
exitStatus = EXIT_FAILURE;
return {};
}
if ((!parsing.messages().empty() &&
(driver.warningsAreErrors || parsing.messages().AnyFatalError())) ||
!parsing.parseTree()) {
llvm::errs() << driver.prefix << "Could not parse " << path << '\n';
exitStatus = EXIT_FAILURE;
return {};
}
auto &parseTree{*parsing.parseTree()};
if (driver.measureTree) {
MeasureParseTree(parseTree);
}
if (!driver.debugNoSemantics || driver.dumpSymbols ||
driver.dumpUnparseWithSymbols || driver.getDefinition ||
driver.getSymbolsSources) {
Fortran::semantics::Semantics semantics{semanticsContext, parseTree,
parsing.cooked().AsCharBlock(), driver.debugModuleWriter};
semantics.Perform();
Fortran::semantics::RuntimeDerivedTypeTables tables;
if (!semantics.AnyFatalError()) {
tables =
Fortran::semantics::BuildRuntimeDerivedTypeTables(semanticsContext);
if (!tables.schemata) {
llvm::errs() << driver.prefix
<< "could not find module file for __fortran_type_info\n";
}
}
semantics.EmitMessages(llvm::errs());
if (semantics.AnyFatalError()) {
if (driver.dumpSymbols) {
semantics.DumpSymbols(llvm::outs());
}
llvm::errs() << driver.prefix << "Semantic errors in " << path << '\n';
exitStatus = EXIT_FAILURE;
if (driver.dumpParseTree) {
Fortran::parser::DumpTree(llvm::outs(), parseTree, &asFortran);
}
return {};
}
if (driver.dumpSymbols) {
semantics.DumpSymbols(llvm::outs());
}
if (driver.dumpUnparseWithSymbols) {
Fortran::semantics::UnparseWithSymbols(
llvm::outs(), parseTree, driver.encoding);
return {};
}
if (driver.getSymbolsSources) {
semantics.DumpSymbolsSources(llvm::outs());
return {};
}
if (driver.getDefinition) {
if (auto cb{allCookedSources.GetCharBlockFromLineAndColumns(
driver.getDefinitionArgs.line,
driver.getDefinitionArgs.startColumn,
driver.getDefinitionArgs.endColumn)}) {
llvm::errs() << "String range: >" << cb->ToString() << "<\n";
if (auto symbol{semanticsContext.FindScope(*cb).FindSymbol(*cb)}) {
llvm::errs() << "Found symbol name: " << symbol->name().ToString()
<< "\n";
if (auto sourceInfo{
allCookedSources.GetSourcePositionRange(symbol->name())}) {
llvm::outs() << symbol->name().ToString() << ": "
<< sourceInfo->first.file.path() << ", "
<< sourceInfo->first.line << ", "
<< sourceInfo->first.column << "-"
<< sourceInfo->second.column << "\n";
exitStatus = EXIT_SUCCESS;
return {};
}
}
}
llvm::errs() << "Symbol not found.\n";
exitStatus = EXIT_FAILURE;
return {};
}
}
if (driver.dumpParseTree) {
Fortran::parser::DumpTree(llvm::outs(), parseTree, &asFortran);
}
if (driver.dumpUnparse) {
Unparse(llvm::outs(), parseTree, driver.encoding, true /*capitalize*/,
options.features.IsEnabled(
Fortran::common::LanguageFeature::BackslashEscapes),
nullptr /* action before each statement */, &asFortran);
return {};
}
if (driver.dumpPreFirTree) {
if (auto ast{Fortran::lower::createPFT(parseTree, semanticsContext)}) {
Fortran::lower::dumpPFT(llvm::outs(), *ast);
} else {
llvm::errs() << "Pre FIR Tree is NULL.\n";
exitStatus = EXIT_FAILURE;
}
}
if (driver.syntaxOnly) {
return {};
}
std::string relo{RelocatableName(driver, path)};
llvm::SmallString<32> tmpSourcePath;
{
int fd;
std::error_code EC =
llvm::sys::fs::createUniqueFile("f18-%%%%.f90", fd, tmpSourcePath);
if (EC) {
llvm::errs() << EC.message() << "\n";
std::exit(EXIT_FAILURE);
}
llvm::raw_fd_ostream tmpSource(fd, /*shouldClose*/ true);
Unparse(tmpSource, parseTree, driver.encoding, true /*capitalize*/,
options.features.IsEnabled(
Fortran::common::LanguageFeature::BackslashEscapes),
nullptr /* action before each statement */,
driver.unparseTypedExprsToF18_FC ? &asFortran : nullptr);
}
RunOtherCompiler(driver, tmpSourcePath.data(), relo.data());
filesToDelete.emplace_back(tmpSourcePath);
if (!driver.compileOnly && driver.outputPath.empty()) {
filesToDelete.push_back(relo);
}
return relo;
}
std::string CompileOtherLanguage(std::string path, DriverOptions &driver) {
std::string relo{RelocatableName(driver, path)};
RunOtherCompiler(driver, path.data(), relo.data());
if (!driver.compileOnly && driver.outputPath.empty()) {
filesToDelete.push_back(relo);
}
return relo;
}
void Link(std::vector<std::string> &liblist, std::vector<std::string> &objects,
DriverOptions &driver) {
std::vector<llvm::StringRef> argv;
for (size_t j{0}; j < driver.F18_FCArgs.size(); ++j) {
argv.push_back(driver.F18_FCArgs[j].data());
}
for (auto &obj : objects) {
argv.push_back(obj.data());
}
if (!driver.outputPath.empty()) {
char dashO[3] = "-o";
argv.push_back(dashO);
argv.push_back(driver.outputPath.data());
}
for (auto &lib : liblist) {
argv.push_back(lib.data());
}
Exec(argv, driver.verbose);
}
int printVersion() {
llvm::errs() << "\nf18 compiler (under development), version "
<< FLANG_VERSION_STRING << "\n";
return exitStatus;
}
// Generate the path to look for intrinsic modules
static std::string getIntrinsicDir() {
// TODO: Find a system independent API
llvm::SmallString<128> driverPath;
driverPath.assign(llvm::sys::fs::getMainExecutable(nullptr, nullptr));
llvm::sys::path::remove_filename(driverPath);
driverPath.append("/../include/flang/");
return std::string(driverPath);
}
int main(int argc, char *const argv[]) {
atexit(CleanUpAtExit);
DriverOptions driver;
const char *F18_FC{getenv("F18_FC")};
driver.F18_FCArgs.push_back(F18_FC ? F18_FC : "gfortran");
bool isPGF90{driver.F18_FCArgs.back().rfind("pgf90") != std::string::npos};
std::list<std::string> args{argList(argc, argv)};
std::vector<std::string> objlist, liblist;
std::string prefix{args.front()};
args.pop_front();
prefix += ": ";
driver.prefix = prefix.data();
Fortran::parser::Options options;
std::vector<Fortran::parser::Options::Predefinition> predefinitions;
predefinitions.emplace_back("__F18", "1");
predefinitions.emplace_back("__F18_MAJOR__", "1");
predefinitions.emplace_back("__F18_MINOR__", "1");
predefinitions.emplace_back("__F18_PATCHLEVEL__", "1");
predefinitions.emplace_back("__flang__", FLANG_VERSION_STRING);
predefinitions.emplace_back("__flang_major__", FLANG_VERSION_MAJOR_STRING);
predefinitions.emplace_back("__flang_minor__", FLANG_VERSION_MINOR_STRING);
predefinitions.emplace_back(
"__flang_patchlevel__", FLANG_VERSION_PATCHLEVEL_STRING);
#if __x86_64__
predefinitions.emplace_back("__x86_64__", "1");
#endif
Fortran::common::IntrinsicTypeDefaultKinds defaultKinds;
std::vector<std::string> fortranSources, otherSources;
bool anyFiles{false};
// Add the default intrinsic module directory to the list of search
// directories
driver.searchDirectories.push_back(getIntrinsicDir());
while (!args.empty()) {
std::string arg{std::move(args.front())};
auto dot{arg.rfind(".")};
std::string suffix{arg.substr(dot + 1)};
std::string prefix{arg.substr(0, 2)};
args.pop_front();
if (arg.empty()) {
} else if (arg.at(0) != '-') {
anyFiles = true;
if (dot == std::string::npos) {
driver.F18_FCArgs.push_back(arg);
} else {
if (suffix == "f" || suffix == "F" || suffix == "ff" ||
suffix == "f90" || suffix == "F90" || suffix == "ff90" ||
suffix == "f95" || suffix == "F95" || suffix == "ff95" ||
suffix == "cuf" || suffix == "CUF" || suffix == "f18" ||
suffix == "F18" || suffix == "ff18") {
fortranSources.push_back(arg);
} else if (suffix == "o" || suffix == "so") {
objlist.push_back(arg);
} else if (suffix == "a") {
liblist.push_back(arg);
} else {
otherSources.push_back(arg);
}
}
} else if (prefix == "-l" || suffix == "a") {
liblist.push_back(arg);
} else if (arg == "-") {
fortranSources.push_back("-");
} else if (arg == "--") {
while (!args.empty()) {
fortranSources.emplace_back(std::move(args.front()));
args.pop_front();
}
break;
} else if (arg == "-Mfixed" || arg == "-ffixed-form") {
driver.forcedForm = true;
options.isFixedForm = true;
} else if (arg == "-Mfree" || arg == "-ffree-form") {
driver.forcedForm = true;
options.isFixedForm = false;
} else if (arg == "-Mextend" || arg == "-ffixed-line-length-132") {
options.fixedFormColumns = 132;
} else if (arg == "-Munlimited" || arg == "-ffree-line-length-none" ||
arg == "-ffree-line-length-0" || arg == "-ffixed-line-length-none" ||
arg == "-ffixed-line-length-0") {
// For reparsing f18's -E output of fixed-form cooked character stream
options.fixedFormColumns = 1000000;
} else if (arg == "-Mbackslash") {
options.features.Enable(
Fortran::common::LanguageFeature::BackslashEscapes, false);
} else if (arg == "-Mnobackslash") {
options.features.Enable(
Fortran::common::LanguageFeature::BackslashEscapes, true);
} else if (arg == "-Mstandard" || arg == "-std=f95" ||
arg == "-std=f2003" || arg == "-std=f2008" || arg == "-std=legacy" ||
arg == "-std=f2018" || arg == "-pedantic") {
driver.warnOnNonstandardUsage = true;
} else if (arg == "-fopenacc") {
options.features.Enable(Fortran::common::LanguageFeature::OpenACC);
predefinitions.emplace_back("_OPENACC", "202011");
} else if (arg == "-fopenmp") {
options.features.Enable(Fortran::common::LanguageFeature::OpenMP);
predefinitions.emplace_back("_OPENMP", "201511");
} else if (arg.find("-W") != std::string::npos) {
if (arg == "-Werror")
driver.warningsAreErrors = true;
} else if (arg == "-ed") {
options.features.Enable(Fortran::common::LanguageFeature::OldDebugLines);
} else if (arg == "-E") {
driver.dumpCookedChars = true;
} else if (arg == "-fbackslash" || arg == "-fno-backslash") {
options.features.Enable(
Fortran::common::LanguageFeature::BackslashEscapes,
arg == "-fbackslash");
} else if (arg == "-fxor-operator" || arg == "-fno-xor-operator") {
options.features.Enable(Fortran::common::LanguageFeature::XOROperator,
arg == "-fxor-operator");
} else if (arg == "-flogical-abbreviations" ||
arg == "-fno-logical-abbreviations") {
options.features.Enable(
Fortran::parser::LanguageFeature::LogicalAbbreviations,
arg == "-flogical-abbreviations");
} else if (arg == "-fimplicit-none-type-always" ||
arg == "-fimplicit-none") {
options.features.Enable(
Fortran::common::LanguageFeature::ImplicitNoneTypeAlways);
} else if (arg == "-fno-implicit-none") {
options.features.Enable(
Fortran::common::LanguageFeature::ImplicitNoneTypeAlways, false);
} else if (arg == "-fimplicit-none-type-never") {
options.features.Enable(
Fortran::common::LanguageFeature::ImplicitNoneTypeNever);
} else if (arg == "-falternative-parameter-statement") {
options.features.Enable(
Fortran::common::LanguageFeature::OldStyleParameter, true);
} else if (arg == "-fdebug-dump-provenance") {
driver.dumpProvenance = true;
options.needProvenanceRangeToCharBlockMappings = true;
} else if (arg == "-fdebug-dump-parse-tree") {
driver.dumpParseTree = true;
driver.syntaxOnly = true;
} else if (arg == "-fdebug-pre-fir-tree") {
driver.dumpPreFirTree = true;
} else if (arg == "-fdebug-dump-symbols") {
driver.dumpSymbols = true;
driver.syntaxOnly = true;
} else if (arg == "-fdebug-module-writer") {
driver.debugModuleWriter = true;
} else if (arg == "-fdebug-measure-parse-tree") {
driver.measureTree = true;
} else if (arg == "-fdebug-instrumented-parse" ||
arg == "-fdebug-dump-parsing-log") {
options.instrumentedParse = true;
} else if (arg == "-fdebug-no-semantics") {
driver.debugNoSemantics = true;
} else if (arg == "-fdebug-unparse-no-sema") {
driver.debugNoSemantics = true;
driver.dumpUnparse = true;
} else if (arg == "-fdebug-dump-parse-tree-no-sema") {
driver.debugNoSemantics = true;
driver.dumpParseTree = true;
driver.syntaxOnly = true;
} else if (arg == "-funparse" || arg == "-fdebug-unparse") {
driver.dumpUnparse = true;
} else if (arg == "-funparse-with-symbols" ||
arg == "-fdebug-unparse-with-symbols") {
driver.dumpUnparseWithSymbols = true;
} else if (arg == "-funparse-typed-exprs-to-f18-fc") {
driver.unparseTypedExprsToF18_FC = true;
} else if (arg == "-fparse-only" || arg == "-fsyntax-only") {
driver.syntaxOnly = true;
} else if (arg == "-c") {
driver.compileOnly = true;
} else if (arg == "-o") {
driver.outputPath = args.front();
args.pop_front();
} else if (arg.substr(0, 2) == "-D") {
auto eq{arg.find('=')};
if (eq == std::string::npos) {
predefinitions.emplace_back(arg.substr(2), "1");
} else {
predefinitions.emplace_back(arg.substr(2, eq - 2), arg.substr(eq + 1));
}
} else if (arg.substr(0, 2) == "-U") {
predefinitions.emplace_back(arg.substr(2), std::optional<std::string>{});
} else if (arg == "-r8" || arg == "-fdefault-real-8") {
driver.defaultReal8 = true;
defaultKinds.set_defaultRealKind(8);
defaultKinds.set_doublePrecisionKind(16);
} else if (arg == "-fdefault-double-8") {
if (!driver.defaultReal8) {
// -fdefault-double-8 has to be used with -fdefault-real-8
// to be compatible with gfortran. See:
// https://gcc.gnu.org/onlinedocs/gfortran/Fortran-Dialect-Options.html
llvm::errs()
<< "Use of `-fdefault-double-8` requires `-fdefault-real-8`\n";
return EXIT_FAILURE;
}
defaultKinds.set_doublePrecisionKind(8);
} else if (arg == "-i8" || arg == "-fdefault-integer-8") {
defaultKinds.set_defaultIntegerKind(8);
defaultKinds.set_subscriptIntegerKind(8);
defaultKinds.set_sizeIntegerKind(8);
if (isPGF90) {
driver.F18_FCArgs.push_back("-i8");
} else {
driver.F18_FCArgs.push_back("-fdefault-integer-8");
}
} else if (arg == "-flarge-sizes") {
defaultKinds.set_sizeIntegerKind(8);
} else if (arg == "-fno-large-sizes") {
defaultKinds.set_sizeIntegerKind(4);
} else if (arg == "-module") {
driver.moduleDirectory = args.front();
args.pop_front();
} else if (arg == "-module-dir") {
driver.moduleDirectory = args.front();
driver.searchDirectories.push_back(driver.moduleDirectory);
args.pop_front();
} else if (arg == "-module-suffix") {
driver.moduleFileSuffix = args.front();
args.pop_front();
} else if (arg == "-intrinsic-module-directory" ||
arg == "-fintrinsic-modules-path") {
// prepend to the list of search directories
driver.searchDirectories.insert(
driver.searchDirectories.begin(), args.front());
args.pop_front();
} else if (arg == "-futf-8") {
driver.encoding = Fortran::parser::Encoding::UTF_8;
} else if (arg == "-flatin") {
driver.encoding = Fortran::parser::Encoding::LATIN_1;
} else if (arg == "-fget-definition") {
// Receives 3 arguments: line, startColumn, endColumn.
options.needProvenanceRangeToCharBlockMappings = true;
driver.getDefinition = true;
char *endptr;
int arguments[3];
for (int i = 0; i < 3; i++) {
if (args.empty()) {
llvm::errs() << "Must provide 3 arguments for -fget-definitions.\n";
return EXIT_FAILURE;
}
arguments[i] = std::strtol(args.front().c_str(), &endptr, 10);
if (*endptr != '\0') {
llvm::errs() << "error: invalid value '" << args.front()
<< "' in 'fget-definition'" << '\n';
return EXIT_FAILURE;
}
args.pop_front();
}
driver.getDefinitionArgs = {arguments[0], arguments[1], arguments[2]};
} else if (arg == "-fget-symbols-sources") {
driver.getSymbolsSources = true;
} else if (arg == "-byteswapio") {
driver.byteswapio = true; // TODO: Pass to lowering, generate call
} else if (arg == "-cpp") {
driver.forcePreprocessing = true;
} else if (arg == "-nocpp") {
driver.forcePreprocessing = false;
} else if (arg == "-h" || arg == "-help" || arg == "--help" ||
arg == "-?") {
llvm::errs()
<< "f18: LLVM Fortran compiler\n"
<< "\n"
<< "Usage: f18 [options] <input files>\n"
<< "\n"
<< "Defaults:\n"
<< " When invoked with input files, and no options to tell\n"
<< " it otherwise, f18 will unparse its input and pass that on to "
"an\n"
<< " external compiler to continue the compilation.\n"
<< " The external compiler is specified by the F18_FC environment\n"
<< " variable. The default is 'gfortran'.\n"
<< " If invoked with no input files, f18 reads source code from\n"
<< " stdin and runs with -fdebug-measure-parse-tree -funparse.\n"
<< "\n"
<< "f18 options:\n"
<< " -Mfixed | -Mfree | -ffixed-form | -ffree-form force the "
"source form\n"
<< " -Mextend | -ffixed-line-length-132 132-column fixed form\n"
<< " -f[no-]backslash enable[disable] \\escapes in literals\n"
<< " -M[no]backslash disable[enable] \\escapes in literals\n"
<< " -Mstandard enable conformance warnings\n"
<< " -std=<standard> enable conformance warnings\n"
<< " -r8 | -fdefault-real-8 | -i8 | -fdefault-integer-8 | "
"-fdefault-double-8 change default kinds of intrinsic types\n"
<< " -Werror treat warnings as errors\n"
<< " -ed enable fixed form D lines\n"
<< " -E prescan & preprocess only\n"
<< " -module dir module output directory (default .)\n"
<< " -module-dir/-J <dir> Put MODULE files in <dir>\n"
<< " -flatin interpret source as Latin-1 (ISO 8859-1) "
"rather than UTF-8\n"
<< " -fsyntax-only parsing and semantics only, no output "
"except messages\n"
<< " -funparse parse & reformat only, no code "
"generation\n"
<< " -funparse-with-symbols parse, resolve symbols, and unparse\n"
<< " -fdebug-measure-parse-tree\n"
<< " -fdebug-dump-provenance\n"
<< " -fdebug-dump-parse-tree\n"
<< " -fdebug-dump-symbols\n"
<< " -fdebug-instrumented-parse\n"
<< " -fdebug-no-semantics disable semantic checks\n"
<< " -fget-definition\n"
<< " -fget-symbols-sources\n"
<< " -v -c -o -I -D -U have their usual meanings\n"
<< " -cpp / -nocpp force / inhibit macro replacement\n"
<< " -help print this again\n"
<< "Unrecognised options are passed through to the external "
"compiler\n"
<< "set by F18_FC (see defaults).\n";
return exitStatus;
} else if (arg == "-V" || arg == "--version") {
return printVersion();
} else if (arg == "-fdebug-stack-trace") {
llvm::sys::PrintStackTraceOnErrorSignal(llvm::StringRef{}, true);
} else {
driver.F18_FCArgs.push_back(arg);
if (arg == "-v") {
if (args.size() > 1) {
driver.verbose = true;
} else {
return printVersion();
}
} else if (arg == "-I") {
driver.F18_FCArgs.push_back(args.front());
driver.searchDirectories.push_back(args.front());
args.pop_front();
} else if (arg.substr(0, 2) == "-I") {
driver.searchDirectories.push_back(arg.substr(2));
} else if (arg == "-J") {
driver.F18_FCArgs.push_back(args.front());
driver.moduleDirectory = args.front();
driver.searchDirectories.push_back(driver.moduleDirectory);
args.pop_front();
} else if (arg.substr(0, 2) == "-J") {
driver.moduleDirectory = arg.substr(2);
driver.searchDirectories.push_back(driver.moduleDirectory);
}
}
}
if (driver.warnOnNonstandardUsage) {
options.features.WarnOnAllNonstandard();
}
if (isPGF90) {
if (!options.features.IsEnabled(
Fortran::common::LanguageFeature::BackslashEscapes)) {
driver.F18_FCArgs.push_back(
"-Mbackslash"); // yes, this *disables* them in pgf90
}
if (options.features.IsEnabled(Fortran::common::LanguageFeature::OpenMP)) {
driver.F18_FCArgs.push_back("-mp");
}
Fortran::parser::useHexadecimalEscapeSequences = false;
} else {
if (options.features.IsEnabled(
Fortran::common::LanguageFeature::BackslashEscapes)) {
driver.F18_FCArgs.push_back("-fbackslash");
}
if (options.features.IsEnabled(Fortran::common::LanguageFeature::OpenMP)) {
driver.F18_FCArgs.push_back("-fopenmp");
}
Fortran::parser::useHexadecimalEscapeSequences = true;
}
if (!anyFiles) {
driver.measureTree = true;
driver.dumpUnparse = true;
llvm::outs() << "Enter Fortran source\n"
<< "Use EOF character (^D) to end file\n";
CompileFortran("-", options, driver, defaultKinds);
return exitStatus;
}
for (const auto &path : fortranSources) {
options.predefinitions.clear();
if (driver.forcePreprocessing) {
if (*driver.forcePreprocessing) {
options.predefinitions = predefinitions;
}
} else {
auto dot{path.rfind(".")};
if (dot != std::string::npos) {
std::string suffix{path.substr(dot + 1)};
if (suffix == "F" || suffix == "F90" || suffix == "F95" ||
suffix == "CUF" || suffix == "F18") {
options.predefinitions = predefinitions;
}
}
}
std::string relo{CompileFortran(path, options, driver, defaultKinds)};
if (!driver.compileOnly && !relo.empty()) {
objlist.push_back(relo);
}
}
for (const auto &path : otherSources) {
std::string relo{CompileOtherLanguage(path, driver)};
if (!driver.compileOnly && !relo.empty()) {
objlist.push_back(relo);
}
}
if (!driver.compileOnly && !objlist.empty()) {
Link(liblist, objlist, driver);
}
return exitStatus;
}