608075aa33d52c385b5c8d8c57460a08212914fc
[platform/upstream/llvm.git] / flang / tools / f18 / f18.cpp
1 //===-- tools/f18/f18.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 // Temporary Fortran front end driver main program for development scaffolding.
10
11 #include "flang/Common/Fortran-features.h"
12 #include "flang/Common/default-kinds.h"
13 #include "flang/Evaluate/expression.h"
14 #include "flang/Lower/PFTBuilder.h"
15 #include "flang/Parser/characters.h"
16 #include "flang/Parser/dump-parse-tree.h"
17 #include "flang/Parser/message.h"
18 #include "flang/Parser/parse-tree-visitor.h"
19 #include "flang/Parser/parse-tree.h"
20 #include "flang/Parser/parsing.h"
21 #include "flang/Parser/provenance.h"
22 #include "flang/Parser/unparse.h"
23 #include "flang/Semantics/expression.h"
24 #include "flang/Semantics/semantics.h"
25 #include "flang/Semantics/unparse-with-symbols.h"
26 #include "llvm/Support/raw_ostream.h"
27 #include <cerrno>
28 #include <cstdio>
29 #include <cstring>
30 #include <fstream>
31 #include <iostream>
32 #include <list>
33 #include <memory>
34 #include <optional>
35 #include <stdlib.h>
36 #include <string>
37 #include <sys/wait.h>
38 #include <unistd.h>
39 #include <vector>
40
41 static std::list<std::string> argList(int argc, char *const argv[]) {
42   std::list<std::string> result;
43   for (int j = 0; j < argc; ++j) {
44     result.emplace_back(argv[j]);
45   }
46   return result;
47 }
48
49 struct MeasurementVisitor {
50   template<typename A> bool Pre(const A &) { return true; }
51   template<typename A> void Post(const A &) {
52     ++objects;
53     bytes += sizeof(A);
54   }
55   size_t objects{0}, bytes{0};
56 };
57
58 void MeasureParseTree(const Fortran::parser::Program &program) {
59   MeasurementVisitor visitor;
60   Fortran::parser::Walk(program, visitor);
61   std::cout << "Parse tree comprises " << visitor.objects
62             << " objects and occupies " << visitor.bytes << " total bytes.\n";
63 }
64
65 std::vector<std::string> filesToDelete;
66
67 void CleanUpAtExit() {
68   for (const auto &path : filesToDelete) {
69     if (!path.empty()) {
70       unlink(path.data());
71     }
72   }
73 }
74
75 struct GetDefinitionArgs {
76   int line, startColumn, endColumn;
77 };
78
79 struct DriverOptions {
80   DriverOptions() {}
81   bool verbose{false};  // -v
82   bool compileOnly{false};  // -c
83   std::string outputPath;  // -o path
84   std::vector<std::string> searchDirectories{"."s};  // -I dir
85   std::string moduleDirectory{"."s};  // -module dir
86   std::string moduleFileSuffix{".mod"};  // -moduleSuffix suff
87   bool forcedForm{false};  // -Mfixed or -Mfree appeared
88   bool warnOnNonstandardUsage{false};  // -Mstandard
89   bool warningsAreErrors{false};  // -Werror
90   Fortran::parser::Encoding encoding{Fortran::parser::Encoding::UTF_8};
91   bool parseOnly{false};
92   bool dumpProvenance{false};
93   bool dumpCookedChars{false};
94   bool dumpUnparse{false};
95   bool dumpUnparseWithSymbols{false};
96   bool dumpParseTree{false};
97   bool dumpPreFirTree{false};
98   bool dumpSymbols{false};
99   bool debugResolveNames{false};
100   bool debugNoSemantics{false};
101   bool measureTree{false};
102   bool unparseTypedExprsToPGF90{false};
103   std::vector<std::string> pgf90Args;
104   const char *prefix{nullptr};
105   bool getDefinition{false};
106   GetDefinitionArgs getDefinitionArgs{0, 0, 0};
107   bool getSymbolsSources{false};
108 };
109
110 bool ParentProcess() {
111   if (fork() == 0) {
112     return false;  // in child process
113   }
114   int childStat{0};
115   wait(&childStat);
116   if (!WIFEXITED(childStat) || WEXITSTATUS(childStat) != 0) {
117     exit(EXIT_FAILURE);
118   }
119   return true;
120 }
121
122 void Exec(std::vector<char *> &argv, bool verbose = false) {
123   if (verbose) {
124     for (size_t j{0}; j < argv.size(); ++j) {
125       std::cerr << (j > 0 ? " " : "") << argv[j];
126     }
127     std::cerr << '\n';
128   }
129   argv.push_back(nullptr);
130   execvp(argv[0], &argv[0]);
131   std::cerr << "execvp(" << argv[0] << ") failed: " << std::strerror(errno)
132             << '\n';
133   exit(EXIT_FAILURE);
134 }
135
136 void RunOtherCompiler(DriverOptions &driver, char *source, char *relo) {
137   std::vector<char *> argv;
138   for (size_t j{0}; j < driver.pgf90Args.size(); ++j) {
139     argv.push_back(driver.pgf90Args[j].data());
140   }
141   char dashC[3] = "-c", dashO[3] = "-o";
142   argv.push_back(dashC);
143   argv.push_back(dashO);
144   argv.push_back(relo);
145   argv.push_back(source);
146   Exec(argv, driver.verbose);
147 }
148
149 std::string RelocatableName(const DriverOptions &driver, std::string path) {
150   if (driver.compileOnly && !driver.outputPath.empty()) {
151     return driver.outputPath;
152   }
153   std::string base{path};
154   auto slash{base.rfind("/")};
155   if (slash != std::string::npos) {
156     base = base.substr(slash + 1);
157   }
158   std::string relo{base};
159   auto dot{base.rfind(".")};
160   if (dot != std::string::npos) {
161     relo = base.substr(0, dot);
162   }
163   relo += ".o";
164   return relo;
165 }
166
167 int exitStatus{EXIT_SUCCESS};
168
169 static Fortran::parser::AnalyzedObjectsAsFortran asFortran{
170     [](std::ostream &o, const Fortran::evaluate::GenericExprWrapper &x) {
171       if (x.v) {
172         x.v->AsFortran(o);
173       } else {
174         o << "(bad expression)";
175       }
176     },
177     [](std::ostream &o, const Fortran::evaluate::GenericAssignmentWrapper &x) {
178       if (x.v) {
179         x.v->AsFortran(o);
180       } else {
181         o << "(bad assignment)";
182       }
183     },
184     [](std::ostream &o, const Fortran::evaluate::ProcedureRef &x) {
185       x.AsFortran(o << "CALL ");
186     },
187 };
188
189 std::string CompileFortran(std::string path, Fortran::parser::Options options,
190     DriverOptions &driver,
191     const Fortran::common::IntrinsicTypeDefaultKinds &defaultKinds) {
192   Fortran::parser::AllSources allSources;
193   allSources.set_encoding(driver.encoding);
194   Fortran::semantics::SemanticsContext semanticsContext{
195       defaultKinds, options.features, allSources};
196   semanticsContext.set_moduleDirectory(driver.moduleDirectory)
197       .set_moduleFileSuffix(driver.moduleFileSuffix)
198       .set_searchDirectories(driver.searchDirectories)
199       .set_warnOnNonstandardUsage(driver.warnOnNonstandardUsage)
200       .set_warningsAreErrors(driver.warningsAreErrors);
201   if (!driver.forcedForm) {
202     auto dot{path.rfind(".")};
203     if (dot != std::string::npos) {
204       std::string suffix{path.substr(dot + 1)};
205       options.isFixedForm = suffix == "f" || suffix == "F" || suffix == "ff";
206     }
207   }
208   options.searchDirectories = driver.searchDirectories;
209   Fortran::parser::Parsing parsing{semanticsContext.allSources()};
210   parsing.Prescan(path, options);
211   if (!parsing.messages().empty() &&
212       (driver.warningsAreErrors || parsing.messages().AnyFatalError())) {
213     std::cerr << driver.prefix << "could not scan " << path << '\n';
214     parsing.messages().Emit(std::cerr, parsing.cooked());
215     exitStatus = EXIT_FAILURE;
216     return {};
217   }
218   if (driver.dumpProvenance) {
219     parsing.DumpProvenance(std::cout);
220     return {};
221   }
222   if (driver.dumpCookedChars) {
223     parsing.messages().Emit(std::cerr, parsing.cooked());
224     parsing.DumpCookedChars(std::cout);
225     return {};
226   }
227   parsing.Parse(&std::cout);
228   if (options.instrumentedParse) {
229     parsing.DumpParsingLog(std::cout);
230     return {};
231   }
232   parsing.ClearLog();
233   parsing.messages().Emit(std::cerr, parsing.cooked());
234   if (!parsing.consumedWholeFile()) {
235     parsing.EmitMessage(
236         std::cerr, parsing.finalRestingPlace(), "parser FAIL (final position)");
237     exitStatus = EXIT_FAILURE;
238     return {};
239   }
240   if ((!parsing.messages().empty() &&
241           (driver.warningsAreErrors || parsing.messages().AnyFatalError())) ||
242       !parsing.parseTree()) {
243     std::cerr << driver.prefix << "could not parse " << path << '\n';
244     exitStatus = EXIT_FAILURE;
245     return {};
246   }
247   auto &parseTree{*parsing.parseTree()};
248   if (driver.measureTree) {
249     MeasureParseTree(parseTree);
250   }
251   if (!driver.debugNoSemantics || driver.debugResolveNames ||
252       driver.dumpSymbols || driver.dumpUnparseWithSymbols ||
253       driver.getDefinition || driver.getSymbolsSources) {
254     Fortran::semantics::Semantics semantics{
255         semanticsContext, parseTree, parsing.cooked()};
256     semantics.Perform();
257     semantics.EmitMessages(std::cerr);
258     if (driver.dumpSymbols) {
259       semantics.DumpSymbols(std::cout);
260     }
261     if (semantics.AnyFatalError()) {
262       std::cerr << driver.prefix << "semantic errors in " << path << '\n';
263       exitStatus = EXIT_FAILURE;
264       if (driver.dumpParseTree) {
265         Fortran::parser::DumpTree(std::cout, parseTree, &asFortran);
266       }
267       return {};
268     }
269     if (driver.dumpUnparseWithSymbols) {
270       Fortran::semantics::UnparseWithSymbols(
271           std::cout, parseTree, driver.encoding);
272       return {};
273     }
274     if (driver.getSymbolsSources) {
275       semantics.DumpSymbolsSources(std::cout);
276       return {};
277     }
278     if (driver.getDefinition) {
279       if (auto cb{parsing.cooked().GetCharBlockFromLineAndColumns(
280               driver.getDefinitionArgs.line,
281               driver.getDefinitionArgs.startColumn,
282               driver.getDefinitionArgs.endColumn)}) {
283         std::cerr << "String range: >" << cb->ToString() << "<\n";
284         if (auto symbol{semanticsContext.FindScope(*cb).FindSymbol(*cb)}) {
285           std::cerr << "Found symbol name: " << symbol->name().ToString()
286                     << "\n";
287           if (auto sourceInfo{
288                   parsing.cooked().GetSourcePositionRange(symbol->name())}) {
289             std::cout << symbol->name().ToString() << ": "
290                       << sourceInfo->first.file.path() << ", "
291                       << sourceInfo->first.line << ", "
292                       << sourceInfo->first.column << "-"
293                       << sourceInfo->second.column << "\n";
294             exitStatus = EXIT_SUCCESS;
295             return {};
296           }
297         }
298       }
299       std::cerr << "Symbol not found.\n";
300       exitStatus = EXIT_FAILURE;
301       return {};
302     }
303   }
304   if (driver.dumpParseTree) {
305     Fortran::parser::DumpTree(std::cout, parseTree, &asFortran);
306   }
307   if (driver.dumpUnparse) {
308     Unparse(std::cout, parseTree, driver.encoding, true /*capitalize*/,
309         options.features.IsEnabled(
310             Fortran::common::LanguageFeature::BackslashEscapes),
311         nullptr /* action before each statement */, &asFortran);
312     return {};
313   }
314   if (driver.dumpPreFirTree) {
315     if (auto ast{Fortran::lower::createPFT(parseTree)}) {
316       Fortran::lower::annotateControl(*ast);
317       Fortran::lower::dumpPFT(llvm::outs(), *ast);
318     } else {
319       std::cerr << "Pre FIR Tree is NULL.\n";
320       exitStatus = EXIT_FAILURE;
321     }
322   }
323   if (driver.parseOnly) {
324     return {};
325   }
326
327   std::string relo{RelocatableName(driver, path)};
328
329   char tmpSourcePath[32];
330   std::snprintf(tmpSourcePath, sizeof tmpSourcePath, "/tmp/f18-%lx.f90",
331       static_cast<unsigned long>(getpid()));
332   {
333     std::ofstream tmpSource;
334     tmpSource.open(tmpSourcePath);
335     Fortran::evaluate::formatForPGF90 = true;
336     Unparse(tmpSource, parseTree, driver.encoding, true /*capitalize*/,
337         options.features.IsEnabled(
338             Fortran::common::LanguageFeature::BackslashEscapes),
339         nullptr /* action before each statement */,
340         driver.unparseTypedExprsToPGF90 ? &asFortran : nullptr);
341     Fortran::evaluate::formatForPGF90 = false;
342   }
343
344   if (ParentProcess()) {
345     filesToDelete.push_back(tmpSourcePath);
346     if (!driver.compileOnly && driver.outputPath.empty()) {
347       filesToDelete.push_back(relo);
348     }
349     return relo;
350   }
351   RunOtherCompiler(driver, tmpSourcePath, relo.data());
352   return {};
353 }
354
355 std::string CompileOtherLanguage(std::string path, DriverOptions &driver) {
356   std::string relo{RelocatableName(driver, path)};
357   if (ParentProcess()) {
358     if (!driver.compileOnly && driver.outputPath.empty()) {
359       filesToDelete.push_back(relo);
360     }
361     return relo;
362   }
363   RunOtherCompiler(driver, path.data(), relo.data());
364   return {};
365 }
366
367 void Link(std::vector<std::string> &relocatables, DriverOptions &driver) {
368   if (!ParentProcess()) {
369     std::vector<char *> argv;
370     for (size_t j{0}; j < driver.pgf90Args.size(); ++j) {
371       argv.push_back(driver.pgf90Args[j].data());
372     }
373     for (auto &relo : relocatables) {
374       argv.push_back(relo.data());
375     }
376     if (!driver.outputPath.empty()) {
377       char dashO[3] = "-o";
378       argv.push_back(dashO);
379       argv.push_back(driver.outputPath.data());
380     }
381     Exec(argv, driver.verbose);
382   }
383 }
384
385 int main(int argc, char *const argv[]) {
386
387   atexit(CleanUpAtExit);
388
389   DriverOptions driver;
390   const char *pgf90{getenv("F18_FC")};
391   driver.pgf90Args.push_back(pgf90 ? pgf90 : "pgf90");
392   bool isPGF90{driver.pgf90Args.back().rfind("pgf90") != std::string::npos};
393
394   std::list<std::string> args{argList(argc, argv)};
395   std::string prefix{args.front()};
396   args.pop_front();
397   prefix += ": ";
398   driver.prefix = prefix.data();
399
400   Fortran::parser::Options options;
401   options.predefinitions.emplace_back("__F18", "1");
402   options.predefinitions.emplace_back("__F18_MAJOR__", "1");
403   options.predefinitions.emplace_back("__F18_MINOR__", "1");
404   options.predefinitions.emplace_back("__F18_PATCHLEVEL__", "1");
405 #if __x86_64__
406   options.predefinitions.emplace_back("__x86_64__", "1");
407 #endif
408
409   Fortran::common::IntrinsicTypeDefaultKinds defaultKinds;
410
411   std::vector<std::string> fortranSources, otherSources, relocatables;
412   bool anyFiles{false};
413
414   while (!args.empty()) {
415     std::string arg{std::move(args.front())};
416     args.pop_front();
417     if (arg.empty()) {
418     } else if (arg.at(0) != '-') {
419       anyFiles = true;
420       auto dot{arg.rfind(".")};
421       if (dot == std::string::npos) {
422         driver.pgf90Args.push_back(arg);
423       } else {
424         std::string suffix{arg.substr(dot + 1)};
425         if (suffix == "f" || suffix == "F" || suffix == "ff" ||
426             suffix == "f90" || suffix == "F90" || suffix == "ff90" ||
427             suffix == "f95" || suffix == "F95" || suffix == "ff95" ||
428             suffix == "cuf" || suffix == "CUF" || suffix == "f18" ||
429             suffix == "F18" || suffix == "ff18") {
430           fortranSources.push_back(arg);
431         } else if (suffix == "o" || suffix == "a") {
432           relocatables.push_back(arg);
433         } else {
434           otherSources.push_back(arg);
435         }
436       }
437     } else if (arg == "-") {
438       fortranSources.push_back("-");
439     } else if (arg == "--") {
440       while (!args.empty()) {
441         fortranSources.emplace_back(std::move(args.front()));
442         args.pop_front();
443       }
444       break;
445     } else if (arg == "-Mfixed") {
446       driver.forcedForm = true;
447       options.isFixedForm = true;
448     } else if (arg == "-Mfree") {
449       driver.forcedForm = true;
450       options.isFixedForm = false;
451     } else if (arg == "-Mextend") {
452       options.fixedFormColumns = 132;
453     } else if (arg == "-Munlimited") {
454       // For reparsing f18's -E output of fixed-form cooked character stream
455       options.fixedFormColumns = 1000000;
456     } else if (arg == "-Mbackslash") {
457       options.features.Enable(
458           Fortran::common::LanguageFeature::BackslashEscapes, false);
459     } else if (arg == "-Mnobackslash") {
460       options.features.Enable(
461           Fortran::common::LanguageFeature::BackslashEscapes, true);
462     } else if (arg == "-Mstandard") {
463       driver.warnOnNonstandardUsage = true;
464     } else if (arg == "-fopenmp") {
465       options.features.Enable(Fortran::common::LanguageFeature::OpenMP);
466       options.predefinitions.emplace_back("_OPENMP", "201511");
467     } else if (arg == "-Werror") {
468       driver.warningsAreErrors = true;
469     } else if (arg == "-ed") {
470       options.features.Enable(Fortran::common::LanguageFeature::OldDebugLines);
471     } else if (arg == "-E") {
472       driver.dumpCookedChars = true;
473     } else if (arg == "-fbackslash" || arg == "-fno-backslash") {
474       options.features.Enable(
475           Fortran::common::LanguageFeature::BackslashEscapes,
476           arg == "-fbackslash");
477     } else if (arg == "-fxor-operator" || arg == "-fno-xor-operator") {
478       options.features.Enable(Fortran::common::LanguageFeature::XOROperator,
479           arg == "-fxor-operator");
480     } else if (arg == "-flogical-abbreviations" ||
481         arg == "-fno-logical-abbreviations") {
482       options.features.Enable(
483           Fortran::parser::LanguageFeature::LogicalAbbreviations,
484           arg == "-flogical-abbreviations");
485     } else if (arg == "-fdebug-dump-provenance") {
486       driver.dumpProvenance = true;
487       options.needProvenanceRangeToCharBlockMappings = true;
488     } else if (arg == "-fdebug-dump-parse-tree") {
489       driver.dumpParseTree = true;
490     } else if (arg == "-fdebug-pre-fir-tree") {
491       driver.dumpPreFirTree = true;
492     } else if (arg == "-fdebug-dump-symbols") {
493       driver.dumpSymbols = true;
494     } else if (arg == "-fdebug-resolve-names") {
495       driver.debugResolveNames = true;
496     } else if (arg == "-fdebug-measure-parse-tree") {
497       driver.measureTree = true;
498     } else if (arg == "-fdebug-instrumented-parse") {
499       options.instrumentedParse = true;
500     } else if (arg == "-fdebug-semantics") {
501     } else if (arg == "-fdebug-no-semantics") {
502       driver.debugNoSemantics = true;
503     } else if (arg == "-funparse") {
504       driver.dumpUnparse = true;
505     } else if (arg == "-funparse-with-symbols") {
506       driver.dumpUnparseWithSymbols = true;
507     } else if (arg == "-funparse-typed-exprs-to-pgf90") {
508       driver.unparseTypedExprsToPGF90 = true;
509     } else if (arg == "-fparse-only") {
510       driver.parseOnly = true;
511     } else if (arg == "-c") {
512       driver.compileOnly = true;
513     } else if (arg == "-o") {
514       driver.outputPath = args.front();
515       args.pop_front();
516     } else if (arg.substr(0, 2) == "-D") {
517       auto eq{arg.find('=')};
518       if (eq == std::string::npos) {
519         options.predefinitions.emplace_back(arg.substr(2), "1");
520       } else {
521         options.predefinitions.emplace_back(
522             arg.substr(2, eq - 2), arg.substr(eq + 1));
523       }
524     } else if (arg.substr(0, 2) == "-U") {
525       options.predefinitions.emplace_back(
526           arg.substr(2), std::optional<std::string>{});
527     } else if (arg == "-r8" || arg == "-fdefault-real-8") {
528       defaultKinds.set_defaultRealKind(8);
529     } else if (arg == "-i8" || arg == "-fdefault-integer-8") {
530       defaultKinds.set_defaultIntegerKind(8);
531       defaultKinds.set_subscriptIntegerKind(8);
532       defaultKinds.set_sizeIntegerKind(8);
533     } else if (arg == "-Mlargearray") {
534     } else if (arg == "-Mnolargearray") {
535     } else if (arg == "-flarge-sizes") {
536       defaultKinds.set_sizeIntegerKind(8);
537     } else if (arg == "-fno-large-sizes") {
538       defaultKinds.set_sizeIntegerKind(4);
539     } else if (arg == "-module") {
540       driver.moduleDirectory = args.front();
541       args.pop_front();
542     } else if (arg == "-module-suffix") {
543       driver.moduleFileSuffix = args.front();
544       args.pop_front();
545     } else if (arg == "-intrinsic-module-directory") {
546       driver.searchDirectories.push_back(args.front());
547       args.pop_front();
548     } else if (arg == "-futf-8") {
549       driver.encoding = Fortran::parser::Encoding::UTF_8;
550     } else if (arg == "-flatin") {
551       driver.encoding = Fortran::parser::Encoding::LATIN_1;
552     } else if (arg == "-fget-definition") {
553       // Receives 3 arguments: line, startColumn, endColumn.
554       options.needProvenanceRangeToCharBlockMappings = true;
555       driver.getDefinition = true;
556       char *endptr;
557       int arguments[3];
558       for (int i = 0; i < 3; i++) {
559         if (args.empty()) {
560           std::cerr << "Must provide 3 arguments for -fget-definitions.\n";
561           return EXIT_FAILURE;
562         }
563         arguments[i] = std::strtol(args.front().c_str(), &endptr, 10);
564         if (*endptr != '\0') {
565           std::cerr << "Invalid argument to -fget-definitions: " << args.front()
566                     << '\n';
567           return EXIT_FAILURE;
568         }
569         args.pop_front();
570       }
571       driver.getDefinitionArgs = {arguments[0], arguments[1], arguments[2]};
572     } else if (arg == "-fget-symbols-sources") {
573       driver.getSymbolsSources = true;
574     } else if (arg == "-help" || arg == "--help" || arg == "-?") {
575       std::cerr
576           << "f18 options:\n"
577           << "  -Mfixed | -Mfree     force the source form\n"
578           << "  -Mextend             132-column fixed form\n"
579           << "  -f[no-]backslash     enable[disable] \\escapes in literals\n"
580           << "  -M[no]backslash      disable[enable] \\escapes in literals\n"
581           << "  -Mstandard           enable conformance warnings\n"
582           << "  -fenable=<feature>   enable a language feature\n"
583           << "  -fdisable=<feature>  disable a language feature\n"
584           << "  -r8 | -fdefault-real-8 | -i8 | -fdefault-integer-8  "
585              "change default kinds of intrinsic types\n"
586           << "  -Werror              treat warnings as errors\n"
587           << "  -ed                  enable fixed form D lines\n"
588           << "  -E                   prescan & preprocess only\n"
589           << "  -module dir          module output directory (default .)\n"
590           << "  -flatin              interpret source as Latin-1 (ISO 8859-1) "
591              "rather than UTF-8\n"
592           << "  -fparse-only         parse only, no output except messages\n"
593           << "  -funparse            parse & reformat only, no code "
594              "generation\n"
595           << "  -funparse-with-symbols  parse, resolve symbols, and unparse\n"
596           << "  -fdebug-measure-parse-tree\n"
597           << "  -fdebug-dump-provenance\n"
598           << "  -fdebug-dump-parse-tree\n"
599           << "  -fdebug-dump-symbols\n"
600           << "  -fdebug-resolve-names\n"
601           << "  -fdebug-instrumented-parse\n"
602           << "  -fdebug-no-semantics  disable semantic checks\n"
603           << "  -fget-definition\n"
604           << "  -fget-symbols-sources\n"
605           << "  -v -c -o -I -D -U    have their usual meanings\n"
606           << "  -help                print this again\n"
607           << "Other options are passed through to the compiler.\n";
608       return exitStatus;
609     } else if (arg == "-V") {
610       std::cerr << "\nf18 compiler (under development)\n";
611       return exitStatus;
612     } else {
613       driver.pgf90Args.push_back(arg);
614       if (arg == "-v") {
615         driver.verbose = true;
616       } else if (arg == "-I") {
617         driver.pgf90Args.push_back(args.front());
618         driver.searchDirectories.push_back(args.front());
619         args.pop_front();
620       } else if (arg.substr(0, 2) == "-I") {
621         driver.searchDirectories.push_back(arg.substr(2));
622       }
623     }
624   }
625
626   if (driver.warnOnNonstandardUsage) {
627     options.features.WarnOnAllNonstandard();
628   }
629   if (options.features.IsEnabled(Fortran::common::LanguageFeature::OpenMP)) {
630     driver.pgf90Args.push_back("-mp");
631   }
632   if (isPGF90) {
633     if (!options.features.IsEnabled(
634             Fortran::common::LanguageFeature::BackslashEscapes)) {
635       driver.pgf90Args.push_back(
636           "-Mbackslash");  // yes, this *disables* them in pgf90
637     }
638     Fortran::parser::useHexadecimalEscapeSequences = false;
639   } else {
640     if (options.features.IsEnabled(
641             Fortran::common::LanguageFeature::BackslashEscapes)) {
642       driver.pgf90Args.push_back("-fbackslash");
643     }
644     Fortran::parser::useHexadecimalEscapeSequences = true;
645   }
646
647   if (!anyFiles) {
648     driver.measureTree = true;
649     driver.dumpUnparse = true;
650     CompileFortran("-", options, driver, defaultKinds);
651     return exitStatus;
652   }
653   for (const auto &path : fortranSources) {
654     std::string relo{CompileFortran(path, options, driver, defaultKinds)};
655     if (!driver.compileOnly && !relo.empty()) {
656       relocatables.push_back(relo);
657     }
658   }
659   for (const auto &path : otherSources) {
660     std::string relo{CompileOtherLanguage(path, driver)};
661     if (!driver.compileOnly && !relo.empty()) {
662       relocatables.push_back(relo);
663     }
664   }
665   if (!relocatables.empty()) {
666     Link(relocatables, driver);
667   }
668   return exitStatus;
669 }