forked from OSchip/llvm-project
[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:
parent
31cfbeab42
commit
f701b42920
|
@ -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
|
||||
---------------------------------------------------------
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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_
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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>())) /
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue