diff options
author | Peter Klausler <35819229+klausler@users.noreply.github.com> | 2024-06-03 11:58:18 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-06-03 11:58:18 -0700 |
commit | 68f4e46c432ea2f1f8d33c6dc9345f6e2afeec4a (patch) | |
tree | 3e1aa1b44a58c91e3829f4404cb400bac2a36113 /flang/lib/Parser/expr-parsers.cpp | |
parent | e44cea597cd835af9cbbd154f812aea3151af18b (diff) | |
download | llvm-68f4e46c432ea2f1f8d33c6dc9345f6e2afeec4a.zip llvm-68f4e46c432ea2f1f8d33c6dc9345f6e2afeec4a.tar.gz llvm-68f4e46c432ea2f1f8d33c6dc9345f6e2afeec4a.tar.bz2 |
[flang] Adjust "doubled operator" expression extension (#93353)
Most Fortran compilers accept "doubled operators" as a language
extension. This is the use of a unary '+' or '-' operator that is not
the first unparenthesized operator in an expression, as in 'x*-y'.
This compiler has implemented this extension, but in a way that's
different from other compilers' behavior. I interpreted the unary
'+'/'-' as a unary operator in the sense of C/C++, giving it a higher
priority than any binary (dyadic) operator.
All other compilers with this extension, however, give a unary '+'/'-' a
lower precedence than exponentiation ('**'), a binary operator that
C/C++ lacks. And this interpretation makes more sense for Fortran,
anyway, where the standard conforming '-x**y' must mean '-(x**y)'
already.
This patch makes 'x*-y**z' parse as 'x*-(y**z)', not 'x*(-y)**z)', and
adds a test to ensure that it does.
Diffstat (limited to 'flang/lib/Parser/expr-parsers.cpp')
-rw-r--r-- | flang/lib/Parser/expr-parsers.cpp | 24 |
1 files changed, 15 insertions, 9 deletions
diff --git a/flang/lib/Parser/expr-parsers.cpp b/flang/lib/Parser/expr-parsers.cpp index b27366d..a47aae1 100644 --- a/flang/lib/Parser/expr-parsers.cpp +++ b/flang/lib/Parser/expr-parsers.cpp @@ -87,14 +87,8 @@ constexpr auto primary{instrumented("primary"_en_US, // R1002 level-1-expr -> [defined-unary-op] primary // TODO: Reasonable extension: permit multiple defined-unary-ops constexpr auto level1Expr{sourced( - first(primary, // must come before define op to resolve .TRUE._8 ambiguity - construct<Expr>(construct<Expr::DefinedUnary>(definedOpName, primary)), - extension<LanguageFeature::SignedPrimary>( - "nonstandard usage: signed primary"_port_en_US, - construct<Expr>(construct<Expr::UnaryPlus>("+" >> primary))), - extension<LanguageFeature::SignedPrimary>( - "nonstandard usage: signed primary"_port_en_US, - construct<Expr>(construct<Expr::Negate>("-" >> primary)))))}; + primary || // must come before define op to resolve .TRUE._8 ambiguity + construct<Expr>(construct<Expr::DefinedUnary>(definedOpName, primary)))}; // R1004 mult-operand -> level-1-expr [power-op mult-operand] // R1007 power-op -> ** @@ -105,7 +99,19 @@ struct MultOperand { static inline std::optional<Expr> Parse(ParseState &); }; -static constexpr auto multOperand{sourced(MultOperand{})}; +// Extension: allow + or - before a mult-operand +// Such a unary operand has lower precedence than exponentiation, +// so -x**2 is -(x**2), not (-x)**2; this matches all other +// compilers with this extension. +static constexpr auto standardMultOperand{sourced(MultOperand{})}; +static constexpr auto multOperand{standardMultOperand || + extension<LanguageFeature::SignedMultOperand>( + "nonstandard usage: signed mult-operand"_port_en_US, + construct<Expr>( + construct<Expr::UnaryPlus>("+" >> standardMultOperand))) || + extension<LanguageFeature::SignedMultOperand>( + "nonstandard usage: signed mult-operand"_port_en_US, + construct<Expr>(construct<Expr::Negate>("-" >> standardMultOperand)))}; inline std::optional<Expr> MultOperand::Parse(ParseState &state) { std::optional<Expr> result{level1Expr.Parse(state)}; |