[flang] Better language feature enablement and warnings.

Original-commit: flang-compiler/f18@359e4d2c60
Reviewed-on: https://github.com/flang-compiler/f18/pull/130
Tree-same-pre-rewrite: false
This commit is contained in:
peter klausler 2018-07-17 16:58:21 -07:00
parent 31cfbeab42
commit f701b42920
12 changed files with 207 additions and 114 deletions

View File

@ -2,20 +2,26 @@
Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.
-->
Extensions, deletions, and legacy features supported
====================================================
As a general principle, this compiler will accept by default and
without complaint many legacy features, extensions to the standard
language, and features that have been deleted from the standard,
so long as the recognition of those features would not cause a
standard-conforming program to be rejected or misinterpreted.
Other non-standard features, which do conflict with the current
standard specification of the Fortran programming language, are
accepted if enabled by command-line options.
Extensions, deletions, and legacy features supported by default
===============================================================
* Tabs in source
* `<>` as synonym for `.NE.` and `/=`
* `$` and `@` as legal characters in names
* `.T.` and `.F.`
* Initialization in type declaration statements using `/values/`
* Kind specification with `*`, e.g. `REAL*4`
* `DOUBLE COMPLEX`
* Signed complex literal constants
* `.XOR.` as predefined operator (can be overridden)
* `.N.`, `.A.`, `.O.`, `.X.` predefined operator synonyms
* `STRUCTURE`, `RECORD`, `UNION`, and `MAP`
* DEC `STRUCTURE`, `RECORD`, `UNION`, and `MAP`
* Structure field access with `.field`
* `NCHARACTER` type and `NC` Kanji character literals
* `BYTE` as synonym for `INTEGER(KIND=1)`
@ -29,7 +35,7 @@ Extensions, deletions, and legacy features supported
* Empty parentheses allowed in `PROGRAM P()`
* Missing parentheses allowed in `FUNCTION F`
* Cray based `POINTER(p,x)`
* Arithmetic `IF`. (Which branch with NaN take?)
* Arithmetic `IF`. (Which branch should NaN take? Fall through?)
* `ASSIGN` statement, assigned `GO TO`, and assigned format
* `PAUSE` statement
* Hollerith literals and edit descriptors
@ -41,11 +47,20 @@ Extensions, deletions, and legacy features supported
* `NAME=` as synonym for `FILE=`
* `DISPOSE=`
* Data edit descriptors without width or other details
* Backslash escape character sequences in quoted character literals
* `D` lines in fixed form as comments or debug code
* `CONVERT=` on the OPEN statement
* Leading semicolons are ignored before any statement that
could have a label
* The character `&` in column 1 in fixed form source is a variant form
of continuation line.
Extensions supported when enabled by options
--------------------------------------------
* C-style backslash escape sequences in quoted CHARACTER literals
(but not Hollerith) [-fbackslash]
* Logical abbreviations `.T.`, `.F.`, `.N.`, `.A.`, `.O.`, and `.X.`
[-flogical-abbreviations]
* `.XOR.` as a synonym for `.NEQV.` [-fxor-operator]
Extensions and legacy features deliberately not supported
---------------------------------------------------------

View File

@ -149,8 +149,8 @@ public:
bitset_.reset();
return *this;
}
constexpr EnumSet &reset(enumerationType x, bool value = true) {
bitset_.reset(static_cast<std::size_t>(x), value);
constexpr EnumSet &reset(enumerationType x) {
bitset_.reset(static_cast<std::size_t>(x));
return *this;
}
constexpr EnumSet &flip() {

View File

@ -29,9 +29,11 @@
// template functions. See parser-combinators.txt for documentation.
#include "char-block.h"
#include "features.h"
#include "message.h"
#include "parse-state.h"
#include "provenance.h"
#include "user-state.h"
#include "../common/idioms.h"
#include "../common/indirection.h"
#include <cstring>
@ -61,8 +63,6 @@ private:
const MessageFixedText text_;
};
class Success {}; // for when one must return something that's present
template<typename A = Success> inline constexpr auto fail(MessageFixedText t) {
return FailParser<A>{t};
}
@ -400,7 +400,8 @@ public:
messages.Annex(state.messages());
}
state.messages() = std::move(messages);
return {};
std::optional<resultType> result;
return result;
}
private:
@ -1297,26 +1298,25 @@ constexpr struct NextCh {
}
} nextCh;
// If a is a parser for nonstandard usage, extension(a) is a parser that
// is disabled in strict conformance mode and otherwise sets a violation flag
// and may emit a warning message, if those are enabled.
template<typename PA> class NonstandardParser {
// If a is a parser for some nonstandard language feature LF, extension<LF>(a)
// is a parser that optionally enabled, sets a strict conformance violation
// flag, and may emit a warning message, if those are enabled.
template<LanguageFeature LF, typename PA> class NonstandardParser {
public:
using resultType = typename PA::resultType;
constexpr NonstandardParser(const NonstandardParser &) = default;
constexpr NonstandardParser(const PA &parser) : parser_{parser} {}
std::optional<resultType> Parse(ParseState &state) const {
if (state.strictConformance()) {
return {};
if (UserState * ustate{state.userState()}) {
if (!ustate->IsEnabled(LF)) {
return {};
}
}
auto at{state.GetLocation()};
auto result{parser_.Parse(state)};
if (result.has_value()) {
state.set_anyConformanceViolation();
if (state.warnOnNonstandardUsage()) {
state.Say(
CharBlock{at, state.GetLocation()}, "nonstandard usage"_en_US);
}
state.Nonstandard(
CharBlock{at, state.GetLocation()}, LF, "nonstandard usage"_en_US);
}
return result;
}
@ -1325,29 +1325,30 @@ private:
const PA parser_;
};
template<typename PA> inline constexpr auto extension(const PA &parser) {
return NonstandardParser<PA>(parser);
template<LanguageFeature LF = LanguageFeature::Extension, typename PA>
inline constexpr auto extension(const PA &parser) {
return NonstandardParser<LF, PA>(parser);
}
// If a is a parser for deprecated usage, deprecated(a) is a parser that
// is disabled if strict standard compliance is enforced,and otherwise
// sets of violation flag and may emit a warning.
template<typename PA> class DeprecatedParser {
// If a is a parser for some deprecated or deleted language feature LF,
// deprecated<LF>(a) is a parser that is optionally enabled, sets a strict
// conformance violation flag, and may emit a warning message, if enabled.
template<LanguageFeature LF, typename PA> class DeprecatedParser {
public:
using resultType = typename PA::resultType;
constexpr DeprecatedParser(const DeprecatedParser &) = default;
constexpr DeprecatedParser(const PA &parser) : parser_{parser} {}
std::optional<resultType> Parse(ParseState &state) const {
if (state.strictConformance()) {
return {};
if (UserState * ustate{state.userState()}) {
if (!ustate->IsEnabled(LF)) {
return {};
}
}
auto at{state.GetLocation()};
auto result{parser_.Parse(state)};
if (result) {
state.set_anyConformanceViolation();
if (state.warnOnDeprecatedUsage()) {
state.Say(CharBlock{at, state.GetLocation()}, "deprecated usage"_en_US);
}
if (result.has_value()) {
state.Nonstandard(
CharBlock{at, state.GetLocation()}, LF, "deprecated usage"_en_US);
}
return result;
}
@ -1356,8 +1357,9 @@ private:
const PA parser_;
};
template<typename PA> inline constexpr auto deprecated(const PA &parser) {
return DeprecatedParser<PA>(parser);
template<LanguageFeature LF = LanguageFeature::Deprecation, typename PA>
inline constexpr auto deprecated(const PA &parser) {
return DeprecatedParser<LF, PA>(parser);
}
// Parsing objects with "source" members.

View File

@ -0,0 +1,30 @@
// 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_PARSER_FEATURES_H_
#define FORTRAN_PARSER_FEATURES_H_
#include "../common/enum-set.h"
#include "../common/idioms.h"
namespace Fortran::parser {
ENUM_CLASS(LanguageFeature, BackslashEscapes, LogicalAbbreviations, XOROperator,
PunctuationInNames, OptionalFreeFormSpace, BOZExtensions, EmptyStatement,
OldDebugLines, OpenMP, Extension, Deprecation)
using LanguageFeatures = common::EnumSet<LanguageFeature, 32>;
} // namespace Fortran::parser
#endif // FORTRAN_PARSER_FEATURES_H_

View File

@ -152,7 +152,9 @@ constexpr auto namedIntrinsicOperator{
".OR." >> pure(DefinedOperator::IntrinsicOperator::OR) ||
".EQV." >> pure(DefinedOperator::IntrinsicOperator::EQV) ||
".NEQV." >> pure(DefinedOperator::IntrinsicOperator::NEQV) ||
extension(".XOR." >> pure(DefinedOperator::IntrinsicOperator::XOR) ||
extension<LanguageFeature::XOROperator>(
".XOR." >> pure(DefinedOperator::IntrinsicOperator::XOR)) ||
extension<LanguageFeature::LogicalAbbreviations>(
".N." >> pure(DefinedOperator::IntrinsicOperator::NOT) ||
".A." >> pure(DefinedOperator::IntrinsicOperator::AND) ||
".O." >> pure(DefinedOperator::IntrinsicOperator::OR) ||
@ -635,11 +637,16 @@ TYPE_CONTEXT_PARSER(
// R725 logical-literal-constant ->
// .TRUE. [_ kind-param] | .FALSE. [_ kind-param]
// Also accept .T. and .F. as extensions.
TYPE_PARSER(construct<LogicalLiteralConstant>(
(".TRUE."_tok || extension(".T."_tok)) >> pure(true),
maybe(underscore >> kindParam)) ||
TYPE_PARSER(
construct<LogicalLiteralConstant>(
(".FALSE."_tok || extension(".F."_tok)) >> pure(false),
(".TRUE."_tok ||
extension<LanguageFeature::LogicalAbbreviations>(".T."_tok)) >>
pure(true),
maybe(underscore >> kindParam)) ||
construct<LogicalLiteralConstant>(
(".FALSE."_tok ||
extension<LanguageFeature::LogicalAbbreviations>(".F."_tok)) >>
pure(false),
maybe(underscore >> kindParam)))
// R726 derived-type-def ->
@ -1792,7 +1799,8 @@ constexpr struct Level5Expr {
}};
auto more{".EQV." >> applyLambda(eqv, equivOperand) ||
".NEQV." >> applyLambda(neqv, equivOperand) ||
extension(".XOR." >> applyLambda(logicalXor, equivOperand))};
extension<LanguageFeature::XOROperator>(
".XOR." >> applyLambda(logicalXor, equivOperand))};
while (std::optional<Expr> next{attempt(more).Parse(state)}) {
result = std::move(next);
}

View File

@ -22,8 +22,10 @@
// and recovery during parsing!
#include "characters.h"
#include "features.h"
#include "message.h"
#include "provenance.h"
#include "user-state.h"
#include "../common/idioms.h"
#include <cstddef>
#include <cstring>
@ -34,8 +36,6 @@
namespace Fortran::parser {
class UserState;
class ParseState {
public:
// TODO: Add a constructor for parsing a normalized module file.
@ -44,10 +44,7 @@ public:
ParseState(const ParseState &that)
: p_{that.p_}, limit_{that.limit_}, context_{that.context_},
userState_{that.userState_}, inFixedForm_{that.inFixedForm_},
encoding_{that.encoding_}, strictConformance_{that.strictConformance_},
warnOnNonstandardUsage_{that.warnOnNonstandardUsage_},
warnOnDeprecatedUsage_{that.warnOnDeprecatedUsage_},
anyErrorRecovery_{that.anyErrorRecovery_},
encoding_{that.encoding_}, anyErrorRecovery_{that.anyErrorRecovery_},
anyConformanceViolation_{that.anyConformanceViolation_},
deferMessages_{that.deferMessages_},
anyDeferredMessages_{that.anyDeferredMessages_},
@ -56,9 +53,6 @@ public:
: p_{that.p_}, limit_{that.limit_}, messages_{std::move(that.messages_)},
context_{std::move(that.context_)}, userState_{that.userState_},
inFixedForm_{that.inFixedForm_}, encoding_{that.encoding_},
strictConformance_{that.strictConformance_},
warnOnNonstandardUsage_{that.warnOnNonstandardUsage_},
warnOnDeprecatedUsage_{that.warnOnDeprecatedUsage_},
anyErrorRecovery_{that.anyErrorRecovery_},
anyConformanceViolation_{that.anyConformanceViolation_},
deferMessages_{that.deferMessages_},
@ -67,9 +61,7 @@ public:
ParseState &operator=(const ParseState &that) {
p_ = that.p_, limit_ = that.limit_, context_ = that.context_;
userState_ = that.userState_, inFixedForm_ = that.inFixedForm_;
encoding_ = that.encoding_, strictConformance_ = that.strictConformance_;
warnOnNonstandardUsage_ = that.warnOnNonstandardUsage_;
warnOnDeprecatedUsage_ = that.warnOnDeprecatedUsage_;
encoding_ = that.encoding_;
anyErrorRecovery_ = that.anyErrorRecovery_;
anyConformanceViolation_ = that.anyConformanceViolation_;
deferMessages_ = that.deferMessages_;
@ -81,9 +73,7 @@ public:
p_ = that.p_, limit_ = that.limit_, messages_ = std::move(that.messages_);
context_ = std::move(that.context_);
userState_ = that.userState_, inFixedForm_ = that.inFixedForm_;
encoding_ = that.encoding_, strictConformance_ = that.strictConformance_;
warnOnNonstandardUsage_ = that.warnOnNonstandardUsage_;
warnOnDeprecatedUsage_ = that.warnOnDeprecatedUsage_;
encoding_ = that.encoding_;
anyErrorRecovery_ = that.anyErrorRecovery_;
anyConformanceViolation_ = that.anyConformanceViolation_;
deferMessages_ = that.deferMessages_;
@ -116,24 +106,6 @@ public:
return *this;
}
bool strictConformance() const { return strictConformance_; }
ParseState &set_strictConformance(bool yes = true) {
strictConformance_ = yes;
return *this;
}
bool warnOnNonstandardUsage() const { return warnOnNonstandardUsage_; }
ParseState &set_warnOnNonstandardUsage(bool yes = true) {
warnOnNonstandardUsage_ = yes;
return *this;
}
bool warnOnDeprecatedUsage() const { return warnOnDeprecatedUsage_; }
ParseState &set_warnOnDeprecatedUsage(bool yes = true) {
warnOnDeprecatedUsage_ = yes;
return *this;
}
Encoding encoding() const { return encoding_; }
ParseState &set_encoding(Encoding encoding) {
encoding_ = encoding;
@ -201,6 +173,17 @@ public:
}
}
void Nonstandard(LanguageFeature lf, const MessageFixedText &msg) {
Nonstandard(p_, lf, msg);
}
void Nonstandard(
CharBlock range, LanguageFeature lf, const MessageFixedText &msg) {
anyConformanceViolation_ = true;
if (userState_ != nullptr && userState_->Warn(lf)) {
Say(range, msg);
}
}
bool IsAtEnd() const { return p_ >= limit_; }
const char *UncheckedAdvance(std::size_t n = 1) {
@ -240,9 +223,6 @@ private:
bool inFixedForm_{false};
Encoding encoding_{Encoding::UTF8};
bool strictConformance_{false};
bool warnOnNonstandardUsage_{false};
bool warnOnDeprecatedUsage_{false};
bool anyErrorRecovery_{false};
bool anyConformanceViolation_{false};
bool deferMessages_{false};

View File

@ -67,11 +67,13 @@ void Parsing::Prescan(const std::string &path, Options options) {
prescanner.set_fixedForm(options.isFixedForm)
.set_fixedFormColumnLimit(options.fixedFormColumns)
.set_encoding(options.encoding)
.set_enableBackslashEscapesInCharLiterals(options.enableBackslashEscapes)
.set_enableOldDebugLines(options.enableOldDebugLines)
.set_enableBackslashEscapesInCharLiterals( // TODO pmk
options.enabled.test(LanguageFeature::BackslashEscapes))
.set_enableOldDebugLines(
options.enabled.test(LanguageFeature::OldDebugLines))
.set_warnOnNonstandardUsage(options_.isStrictlyStandard)
.AddCompilerDirectiveSentinel("dir$");
if (options.enableOpenMP) {
if (options.enabled.test(LanguageFeature::OpenMP)) {
prescanner.AddCompilerDirectiveSentinel("$omp");
}
ProvenanceRange range{
@ -100,11 +102,11 @@ void Parsing::Parse(std::ostream *out) {
userState.set_debugOutput(out)
.set_instrumentedParse(options_.instrumentedParse)
.set_log(&log_);
userState.Enable(options_.enabled);
userState.EnableWarnings(options_.warning);
ParseState parseState{cooked_};
parseState.set_inFixedForm(options_.isFixedForm)
.set_encoding(options_.encoding)
.set_warnOnNonstandardUsage(options_.isStrictlyStandard)
.set_warnOnDeprecatedUsage(options_.isStrictlyStandard)
.set_userState(&userState);
parseTree_ = program.Parse(parseState);
CHECK(

View File

@ -16,6 +16,7 @@
#define FORTRAN_PARSER_PARSING_H_
#include "characters.h"
#include "features.h"
#include "instrumented-parser.h"
#include "message.h"
#include "parse-tree.h"
@ -35,10 +36,8 @@ struct Options {
bool isFixedForm{false};
int fixedFormColumns{72};
bool enableBackslashEscapes{true};
bool enableOldDebugLines{false};
bool isStrictlyStandard{false};
bool enableOpenMP{false};
LanguageFeatures enabled, warning;
Encoding encoding{Encoding::UTF8};
std::vector<std::string> searchDirectories;
std::vector<Predefinition> predefinitions;

View File

@ -180,7 +180,7 @@ private:
int fixedFormColumnLimit_{72};
Encoding encoding_{Encoding::UTF8};
bool enableOldDebugLines_{false};
bool enableBackslashEscapesInCharLiterals_{true};
bool enableBackslashEscapesInCharLiterals_{false};
bool warnOnNonstandardUsage_{false};
int delimiterNesting_{0};
int prescannerNesting_{0};

View File

@ -84,10 +84,8 @@ constexpr struct Space {
// character that could begin an identifier or keyword. Always succeeds.
inline void MissingSpace(ParseState &state) {
if (!state.inFixedForm()) {
state.set_anyConformanceViolation();
if (state.warnOnNonstandardUsage()) {
state.Say("expected space"_en_US);
}
state.Nonstandard(
LanguageFeature::OptionalFreeFormSpace, "missing space"_en_US);
}
}
@ -298,14 +296,14 @@ template<char quote> struct CharLiteral {
}
};
static bool IsNonstandardUsageOk(ParseState &state) {
if (state.strictConformance()) {
return false;
}
state.set_anyConformanceViolation();
if (state.warnOnNonstandardUsage()) {
state.Say("nonstandard usage"_en_US);
static bool IsNonstandardBOZOk(ParseState &state) {
if (UserState * ustate{state.userState()}) {
if (!ustate->IsEnabled(LanguageFeature::BOZExtensions)) {
return false;
}
}
state.Nonstandard(
LanguageFeature::BOZExtensions, "nonstandard BOZ literal"_en_US);
return true;
}
@ -332,7 +330,7 @@ struct BOZLiteral {
if (!at.has_value()) {
return {};
}
if (**at == 'x' && !IsNonstandardUsageOk(state)) {
if (**at == 'x' && !IsNonstandardBOZOk(state)) {
return {};
}
if (baseChar(**at)) {
@ -367,7 +365,7 @@ struct BOZLiteral {
if (!shift.has_value()) {
// extension: base allowed to appear as suffix, too
if (!IsNonstandardUsageOk(state) ||
if (!IsNonstandardBOZOk(state) ||
!(at = nextCh.Parse(state)).has_value() || !baseChar(**at)) {
return {};
}
@ -703,10 +701,8 @@ constexpr struct SkipStuffBeforeStatement {
break;
}
} else if (**at == ';') {
state.set_anyConformanceViolation();
if (state.warnOnNonstandardUsage()) {
state.Say("empty statement"_en_US);
}
state.Nonstandard(
LanguageFeature::EmptyStatement, "empty statement"_en_US);
state.UncheckedAdvance();
} else {
break;
@ -727,7 +723,8 @@ constexpr auto underscore{"_"_ch};
// PGI and ifort accept '$' in identifiers, even as the initial character.
// Cray and gfortran accept '$', but not as the first character.
// Cray accepts '@' as well.
constexpr auto otherIdChar{underscore / !"'\""_ch || extension("$@"_ch)};
constexpr auto otherIdChar{underscore / !"'\""_ch ||
extension<LanguageFeature::PunctuationInNames>("$@"_ch)};
constexpr auto nonDigitIdChar{letter || otherIdChar};
constexpr auto rawName{nonDigitIdChar >> many(nonDigitIdChar || digit)};
TYPE_PARSER(space >> sourced(rawName >> construct<Name>()))
@ -738,7 +735,8 @@ constexpr auto keyword{construct<Keyword>(name)};
// R1414 local-defined-operator -> defined-unary-op | defined-binary-op
// R1415 use-defined-operator -> defined-unary-op | defined-binary-op
// N.B. The name of the operator is captured without the periods around it.
constexpr auto definedOpNameChar{letter || extension("$@"_ch)};
constexpr auto definedOpNameChar{
letter || extension<LanguageFeature::PunctuationInNames>("$@"_ch)};
TYPE_PARSER(space >> "."_ch >>
construct<DefinedOpName>(
sourced(some(definedOpNameChar) >> construct<Name>())) /

View File

@ -20,9 +20,10 @@
// parse tree construction so as to avoid any need for representing
// state in static data.
#include "basic-parsers.h"
#include "char-block.h"
#include "features.h"
#include "parse-tree.h"
#include "../common/idioms.h"
#include <cinttypes>
#include <optional>
#include <ostream>
@ -35,6 +36,8 @@ class CookedSource;
class ParsingLog;
class ParseState;
class Success {}; // for when one must return something that's present
class UserState {
public:
explicit UserState(const CookedSource &cooked) : cooked_{cooked} {}
@ -88,6 +91,41 @@ public:
return oldStructureComponents_.find(name) != oldStructureComponents_.end();
}
UserState &Enable(LanguageFeature f) {
enabled_.set(f);
return *this;
}
UserState &Enable(LanguageFeatures fs) {
enabled_ |= fs;
return *this;
}
UserState &Disable(LanguageFeature f) {
enabled_.reset(f);
return *this;
}
UserState &Disable(LanguageFeatures fs) {
enabled_ &= ~fs;
return *this;
}
bool IsEnabled(LanguageFeature f) { return enabled_.test(f); }
UserState &EnableWarning(LanguageFeature f) {
warning_.set(f);
return *this;
}
UserState &EnableWarnings(LanguageFeatures fs) {
warning_ |= fs;
return *this;
}
UserState &DisableWarning(LanguageFeature f) {
warning_.reset(f);
return *this;
}
UserState &DisableWarnings(LanguageFeatures fs) {
warning_ &= ~fs;
return *this;
}
bool Warn(LanguageFeature f) { return warning_.test(f); }
private:
const CookedSource &cooked_;
@ -100,6 +138,8 @@ private:
int nonlabelDoConstructNestingDepth_{0};
std::set<CharBlock> oldStructureComponents_;
LanguageFeatures enabled_, warning_;
};
// Definitions of parser classes that manipulate the UserState.

View File

@ -15,6 +15,7 @@
// Temporary Fortran front end driver main program for development scaffolding.
#include "../../lib/parser/characters.h"
#include "../../lib/parser/features.h"
#include "../../lib/parser/message.h"
#include "../../lib/parser/parse-tree-visitor.h"
#include "../../lib/parser/parse-tree.h"
@ -298,6 +299,14 @@ int main(int argc, char *const argv[]) {
options.predefinitions.emplace_back("__F18_MAJOR__", "1");
options.predefinitions.emplace_back("__F18_MINOR__", "1");
options.predefinitions.emplace_back("__F18_PATCHLEVEL__", "1");
options.enabled.set(Fortran::parser::LanguageFeature::PunctuationInNames);
options.enabled.set(Fortran::parser::LanguageFeature::OptionalFreeFormSpace);
options.enabled.set(Fortran::parser::LanguageFeature::BOZExtensions);
options.enabled.set(Fortran::parser::LanguageFeature::EmptyStatement);
options.enabled.set(Fortran::parser::LanguageFeature::Extension); // pmk
options.enabled.set(Fortran::parser::LanguageFeature::Deprecation);
std::vector<std::string> fortranSources, otherSources, relocatables;
bool anyFiles{false};
@ -341,19 +350,23 @@ int main(int argc, char *const argv[]) {
} else if (arg == "-Mextend") {
options.fixedFormColumns = 132;
} else if (arg == "-Mbackslash") {
options.enableBackslashEscapes = false;
options.enabled.reset(Fortran::parser::LanguageFeature::BackslashEscapes);
} else if (arg == "-Mnobackslash") {
options.enableBackslashEscapes = true;
options.enabled.set(Fortran::parser::LanguageFeature::BackslashEscapes);
} else if (arg == "-Mstandard") {
options.isStrictlyStandard = true;
} else if (arg == "-fopenmp") {
options.enableOpenMP = true;
options.enabled.set(Fortran::parser::LanguageFeature::OpenMP);
} else if (arg == "-Werror") {
driver.warningsAreErrors = true;
} else if (arg == "-ed") {
options.enableOldDebugLines = true;
options.enabled.set(Fortran::parser::LanguageFeature::OldDebugLines);
} else if (arg == "-E") {
driver.dumpCookedChars = true;
} else if (arg == "-fbackslash") {
options.enabled.set(Fortran::parser::LanguageFeature::BackslashEscapes);
} else if (arg == "-fno-backslash") {
options.enabled.reset(Fortran::parser::LanguageFeature::BackslashEscapes);
} else if (arg == "-fdebug-dump-provenance") {
driver.dumpProvenance = true;
} else if (arg == "-fdebug-dump-parse-tree") {
@ -393,6 +406,7 @@ int main(int argc, char *const argv[]) {
<< "f18 options:\n"
<< " -Mfixed | -Mfree force the source form\n"
<< " -Mextend 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"
<< " -Mx,125,4 set bit 2 in xflag[125] (all Kanji mode)\n"
@ -433,6 +447,11 @@ int main(int argc, char *const argv[]) {
}
driver.encoding = options.encoding;
if (options.isStrictlyStandard) {
options.warning |= options.enabled;
options.warning.reset(Fortran::parser::LanguageFeature::OpenMP);
}
if (!anyFiles) {
driver.measureTree = true;
driver.dumpUnparse = true;