[flang] Preserve some minor changes that accumulated as I was implementing

an unparsing feature.

Enum classes in parse tree node class types are now defined with
a macro so that the names of the enumerations can be captured for
formatting purposes.

Add a TODO comment.

Rebase to new master with parse tree traversal code.

Original-commit: flang-compiler/f18@d6bfcfd526
Reviewed-on: https://github.com/flang-compiler/f18/pull/16
This commit is contained in:
peter klausler 2018-02-16 11:14:11 -08:00
parent c36ac6b185
commit 03aecfc336
15 changed files with 220 additions and 370 deletions

View File

@ -894,8 +894,8 @@ TYPE_PARSER("SEQUENCE" >> construct<SequenceStmt>{})
// integer-type-spec , type-param-attr-spec :: type-param-decl-list
// R734 type-param-attr-spec -> KIND | LEN
TYPE_PARSER(construct<TypeParamDefStmt>{}(integerTypeSpec / ",",
"KIND" >> pure(TypeParamDefStmt::KindOrLength::Kind) ||
"LEN" >> pure(TypeParamDefStmt::KindOrLength::Length),
"KIND" >> pure(TypeParamDefStmt::KindOrLen::Kind) ||
"LEN" >> pure(TypeParamDefStmt::KindOrLen::Len),
"::" >> nonemptyList(Parser<TypeParamDecl>{})))
// R733 type-param-decl -> type-param-name [= scalar-int-constant-expr]
@ -1138,6 +1138,8 @@ TYPE_PARSER(construct<TypeDeclarationStmt>{}(declarationTypeSpec,
optionalBeforeColons(nonemptyList(Parser<AttrSpec>{})),
nonemptyList(entityDecl)) ||
// PGI-only extension: don't require the colons
// TODO: The standard requires the colons if the entity
// declarations contain initializers.
extension(construct<TypeDeclarationStmt>{}(declarationTypeSpec,
defaulted("," >> nonemptyList(Parser<AttrSpec>{})),
"," >> nonemptyList(entityDecl))))
@ -2663,6 +2665,7 @@ TYPE_PARSER(maybe("UNIT ="_tok) >> construct<ConnectSpec>{}(fileUnitNumber) ||
"FORM =" >>
construct<ConnectSpec>{}(construct<ConnectSpec::CharExpr>{}(
pure(ConnectSpec::CharExpr::Kind::Form), scalarDefaultCharExpr)) ||
"IOMSG =" >> construct<ConnectSpec>{}(msgVariable) ||
"IOSTAT =" >> construct<ConnectSpec>{}(statVariable) ||
"NEWUNIT =" >> construct<ConnectSpec>{}(construct<ConnectSpec::Newunit>{}(
scalar(integer(variable)))) ||
@ -3187,15 +3190,18 @@ TYPE_PARSER(
// R1401 main-program ->
// [program-stmt] [specification-part] [execution-part]
// [internal-subprogram-part] end-program-stmt
// R1402 program-stmt -> PROGRAM program-name
TYPE_CONTEXT_PARSER("main program"_en_US,
construct<MainProgram>{}(maybe(statement("PROGRAM" >> name)),
construct<MainProgram>{}(maybe(statement(Parser<ProgramStmt>{})),
specificationPart, executionPart, maybe(internalSubprogramPart),
unterminatedStatement(endProgramStmt)))
// R1402 program-stmt -> PROGRAM program-name
TYPE_CONTEXT_PARSER(
"PROGRAM statement"_en_US, construct<ProgramStmt>{}("PROGRAM" >> name))
// R1403 end-program-stmt -> END [PROGRAM [program-name]]
TYPE_CONTEXT_PARSER("END PROGRAM statement"_en_US,
"END" >> construct<EndProgramStmt>{}(defaulted("PROGRAM" >> maybe(name))))
construct<EndProgramStmt>{}("END" >> defaulted("PROGRAM" >> maybe(name))))
// R1404 module ->
// module-stmt [specification-part] [module-subprogram-part]

View File

@ -31,8 +31,6 @@ public:
: cooked_{that.cooked_}, p_{that.p_}, limit_{that.limit_},
column_{that.column_}, messages_{*that.cooked_.allSources()},
userState_{that.userState_}, inFixedForm_{that.inFixedForm_},
enableBackslashEscapesInCharLiterals_{
that.enableBackslashEscapesInCharLiterals_},
strictConformance_{that.strictConformance_},
warnOnNonstandardUsage_{that.warnOnNonstandardUsage_},
warnOnDeprecatedUsage_{that.warnOnDeprecatedUsage_},
@ -42,8 +40,6 @@ public:
column_{that.column_}, messages_{std::move(that.messages_)},
context_{std::move(that.context_)}, userState_{that.userState_},
inFixedForm_{that.inFixedForm_},
enableBackslashEscapesInCharLiterals_{
that.enableBackslashEscapesInCharLiterals_},
strictConformance_{that.strictConformance_},
warnOnNonstandardUsage_{that.warnOnNonstandardUsage_},
warnOnDeprecatedUsage_{that.warnOnDeprecatedUsage_},
@ -83,14 +79,6 @@ public:
return *this;
}
bool enableBackslashEscapesInCharLiterals() const {
return enableBackslashEscapesInCharLiterals_;
}
ParseState &set_enableBackslashEscapesInCharLiterals(bool yes) {
enableBackslashEscapesInCharLiterals_ = yes;
return *this;
}
bool strictConformance() const { return strictConformance_; }
ParseState &set_strictConformance(bool yes) {
strictConformance_ = yes;
@ -179,7 +167,6 @@ private:
UserState *userState_{nullptr};
bool inFixedForm_{false};
bool enableBackslashEscapesInCharLiterals_{true};
bool strictConformance_{false};
bool warnOnNonstandardUsage_{false};
bool warnOnDeprecatedUsage_{false};

View File

@ -382,12 +382,6 @@ template<typename V> void Walk(const Suffix &x, V &visitor) {
visitor.Post(x);
}
}
template<typename V> void Walk(const TypeAttrSpec::Extends &x, V &visitor) {
if (visitor.Pre(x)) {
Walk(x.name, visitor);
visitor.Post(x);
}
}
template<typename V>
void Walk(const TypeBoundProcedureStmt::WithInterface &x, V &visitor) {
if (visitor.Pre(x)) {
@ -1524,6 +1518,9 @@ template<typename V> void Walk(const PointerStmt &x, V &visitor) {
template<typename V> void Walk(const Program &x, V &visitor) {
WalkWrapperClass(x, visitor);
}
template<typename V> void Walk(const ProgramStmt &x, V &visitor) {
WalkWrapperClass(x, visitor);
}
template<typename V> void Walk(const ProtectedStmt &x, V &visitor) {
WalkWrapperClass(x, visitor);
}
@ -1551,6 +1548,9 @@ template<typename V> void Walk(const SyncMemoryStmt &x, V &visitor) {
template<typename V> void Walk(const TargetStmt &x, V &visitor) {
WalkWrapperClass(x, visitor);
}
template<typename V> void Walk(const TypeAttrSpec::Extends &x, V &visitor) {
WalkWrapperClass(x, visitor);
}
template<typename V> void Walk(const TypeParamInquiry &x, V &visitor) {
WalkWrapperClass(x, visitor);
}

View File

@ -311,6 +311,29 @@ std::ostream &operator<<(std::ostream &o, const FormatSpecification &x) {
<< ')';
}
#define NESTED_ENUM_FORMATTER(T) \
NESTED_ENUM_TO_STRING(T) \
std::ostream &operator<<(std::ostream &o, const T &x) { \
return o << ToString(x); \
}
NESTED_ENUM_FORMATTER(DefinedOperator::IntrinsicOperator) // R608
NESTED_ENUM_FORMATTER(TypeParamDefStmt::KindOrLen) // R734
NESTED_ENUM_FORMATTER(AccessSpec::Kind) // R807
NESTED_ENUM_FORMATTER(IntentSpec::Intent) // R826
NESTED_ENUM_FORMATTER(ImplicitStmt::ImplicitNoneNameSpec) // R866
NESTED_ENUM_FORMATTER(ImportStmt::Kind) // R867
NESTED_ENUM_FORMATTER(StopStmt::Kind) // R1160, R1161
NESTED_ENUM_FORMATTER(ConnectSpec::CharExpr::Kind) // R1205
NESTED_ENUM_FORMATTER(IoControlSpec::CharExpr::Kind) // R1213
NESTED_ENUM_FORMATTER(InquireSpec::CharVar::Kind) // R1231
NESTED_ENUM_FORMATTER(InquireSpec::IntVar::Kind) // R1231
NESTED_ENUM_FORMATTER(InquireSpec::LogVar::Kind) // R1231
NESTED_ENUM_FORMATTER(UseStmt::ModuleNature) // R1410
NESTED_ENUM_FORMATTER(ProcedureStmt::Kind) // R1506
#undef NESTED_ENUM_FORMATTER
// Wrapper class formatting
#define WRAPPER_FORMATTER(TYPE) \
std::ostream &operator<<(std::ostream &o, const TYPE &x) { \
@ -327,6 +350,7 @@ WRAPPER_FORMATTER(IntegerTypeSpec) // R705
WRAPPER_FORMATTER(KindSelector) // R706
WRAPPER_FORMATTER(HollerithLiteralConstant) // extension
WRAPPER_FORMATTER(LogicalLiteralConstant) // R725
WRAPPER_FORMATTER(TypeAttrSpec::Extends) // R728
WRAPPER_FORMATTER(EndTypeStmt) // R730
WRAPPER_FORMATTER(Pass) // R742 & R752
WRAPPER_FORMATTER(FinalProcedureStmt) // R753
@ -334,12 +358,14 @@ WRAPPER_FORMATTER(ComponentDataSource) // R758
WRAPPER_FORMATTER(EnumeratorDefStmt) // R761
WRAPPER_FORMATTER(BOZLiteralConstant) // R764, R765, R766, R767
WRAPPER_FORMATTER(ArrayConstructor) // R769
WRAPPER_FORMATTER(AccessSpec) // R807
WRAPPER_FORMATTER(LanguageBindingSpec) // R808 & R1528
WRAPPER_FORMATTER(DeferredCoshapeSpecList) // R810
WRAPPER_FORMATTER(AssumedShapeSpec) // R819
WRAPPER_FORMATTER(DeferredShapeSpecList) // R820
WRAPPER_FORMATTER(AssumedImpliedSpec) // R821
WRAPPER_FORMATTER(ImpliedShapeSpec) // R823 & R824
WRAPPER_FORMATTER(IntentSpec) // R826
WRAPPER_FORMATTER(AllocatableStmt) // R829
WRAPPER_FORMATTER(AsynchronousStmt) // R831
WRAPPER_FORMATTER(CodimensionStmt) // R834
@ -413,6 +439,7 @@ WRAPPER_FORMATTER(IdVariable) // R1214
WRAPPER_FORMATTER(WaitStmt) // R1222
WRAPPER_FORMATTER(IdExpr) // R1223 & R1231
WRAPPER_FORMATTER(FormatStmt) // R1301
WRAPPER_FORMATTER(ProgramStmt) // R1402
WRAPPER_FORMATTER(EndProgramStmt) // R1403
WRAPPER_FORMATTER(ModuleStmt) // R1405
WRAPPER_FORMATTER(EndModuleStmt) // R1406
@ -495,32 +522,6 @@ EMPTY_TYPE_FORMATTER(Map::EndMapStmt)
#undef EMPTY_TYPE_FORMATTER
// R609
std::ostream &operator<<(
std::ostream &o, DefinedOperator::IntrinsicOperator x) {
switch (x) {
case DefinedOperator::IntrinsicOperator::Power: return o << "Power";
case DefinedOperator::IntrinsicOperator::Multiply: return o << "Multiply";
case DefinedOperator::IntrinsicOperator::Divide: return o << "Divide";
case DefinedOperator::IntrinsicOperator::Add: return o << "Add";
case DefinedOperator::IntrinsicOperator::Subtract: return o << "Subtract";
case DefinedOperator::IntrinsicOperator::Concat: return o << "Concat";
case DefinedOperator::IntrinsicOperator::LT: return o << "LT";
case DefinedOperator::IntrinsicOperator::LE: return o << "LE";
case DefinedOperator::IntrinsicOperator::EQ: return o << "EQ";
case DefinedOperator::IntrinsicOperator::NE: return o << "NE";
case DefinedOperator::IntrinsicOperator::GE: return o << "GE";
case DefinedOperator::IntrinsicOperator::GT: return o << "GT";
case DefinedOperator::IntrinsicOperator::NOT: return o << "NOT";
case DefinedOperator::IntrinsicOperator::AND: return o << "AND";
case DefinedOperator::IntrinsicOperator::OR: return o << "OR";
case DefinedOperator::IntrinsicOperator::EQV: return o << "EQV";
case DefinedOperator::IntrinsicOperator::NEQV: return o << "NEQV";
default: CRASH_NO_CASE;
}
return o;
}
// R703
std::ostream &operator<<(std::ostream &o, const DeclarationTypeSpec::Type &x) {
return o << "(DeclarationTypeSpec TYPE " << x.derived << ')';
@ -602,22 +603,6 @@ std::ostream &operator<<(
return o << "(LengthAndKind " << x.length << ' ' << x.kind << ')';
}
// R728 type-attr-spec
std::ostream &operator<<(std::ostream &o, const TypeAttrSpec::Extends &x) {
return o << "(Extends " << x.name << ')';
}
// R734 type-param-attr-spec
std::ostream &operator<<(
std::ostream &o, const TypeParamDefStmt::KindOrLength &x) {
switch (x) {
case TypeParamDefStmt::KindOrLength::Kind: o << "Kind"; break;
case TypeParamDefStmt::KindOrLength::Length: o << "Length"; break;
default: CRASH_NO_CASE;
}
return o;
}
// R749 type-bound-procedure-stmt
std::ostream &operator<<(
std::ostream &o, const TypeBoundProcedureStmt::WithoutInterface &x) {
@ -636,27 +621,6 @@ std::ostream &operator<<(std::ostream &o, const AcSpec &x) {
return o << "(AcSpec " << x.type << ' ' << x.values << ')';
}
// R807 access-spec
std::ostream &operator<<(std::ostream &o, const AccessSpec &x) {
switch (x.v) {
case AccessSpec::Kind::Public: return o << "(Public)";
case AccessSpec::Kind::Private: return o << "(Private)";
default: CRASH_NO_CASE;
}
return o;
}
// R826 intent-spec
std::ostream &operator<<(std::ostream &o, const IntentSpec &x) {
switch (x.v) {
case IntentSpec::Intent::In: return o << "(Intent In)";
case IntentSpec::Intent::Out: return o << "(Intent Out)";
case IntentSpec::Intent::InOut: return o << "(Intent InOut)";
default: CRASH_NO_CASE;
}
return o;
}
// R863 implicit-stmt
std::ostream &operator<<(std::ostream &o, const ImplicitStmt &x) {
o << "(ImplicitStmt ";
@ -664,21 +628,10 @@ std::ostream &operator<<(std::ostream &o, const ImplicitStmt &x) {
x.u)) {
o << "NONE ";
}
std::visit([&o](auto &&y) { o << y; }, x.u);
std::visit([&o](const auto &y) { o << y; }, x.u);
return o << ')';
}
// R866
std::ostream &operator<<(
std::ostream &o, ImplicitStmt::ImplicitNoneNameSpec x) {
switch (x) {
case ImplicitStmt::ImplicitNoneNameSpec::External: return o << "External";
case ImplicitStmt::ImplicitNoneNameSpec::Type: return o << "Type";
default: CRASH_NO_CASE;
}
return o;
}
// R867
ImportStmt::ImportStmt(Kind &&k, std::list<Name> &&n)
: kind{k}, names(std::move(n)) {
@ -687,14 +640,10 @@ ImportStmt::ImportStmt(Kind &&k, std::list<Name> &&n)
std::ostream &operator<<(std::ostream &o, const ImportStmt &x) {
o << "(ImportStmt ";
switch (x.kind) {
case ImportStmt::Kind::Default: return o << x.names << ')';
case ImportStmt::Kind::Only: return o << "Only " << x.names << ')';
case ImportStmt::Kind::None: return o << "None)";
case ImportStmt::Kind::All: return o << "All)";
default: CRASH_NO_CASE;
if (x.kind != ImportStmt::Kind::Default) {
o << x.kind;
}
return o;
return o << x.names << ')';
}
// R901 designator
@ -871,95 +820,6 @@ std::ostream &operator<<(std::ostream &o, const CaseValueRange::Range &x) {
return o << "(Range " << x.lower << ' ' << x.upper << ')';
}
// R1205
std::ostream &operator<<(std::ostream &o, const ConnectSpec::CharExpr::Kind x) {
switch (x) {
case ConnectSpec::CharExpr::Kind::Access: o << "Access"; break;
case ConnectSpec::CharExpr::Kind::Action: o << "Action"; break;
case ConnectSpec::CharExpr::Kind::Asynchronous: o << "Asynchronous"; break;
case ConnectSpec::CharExpr::Kind::Blank: o << "Blank"; break;
case ConnectSpec::CharExpr::Kind::Decimal: o << "Decimal"; break;
case ConnectSpec::CharExpr::Kind::Delim: o << "Delim"; break;
case ConnectSpec::CharExpr::Kind::Encoding: o << "Encoding"; break;
case ConnectSpec::CharExpr::Kind::Form: o << "Form"; break;
case ConnectSpec::CharExpr::Kind::Pad: o << "Pad"; break;
case ConnectSpec::CharExpr::Kind::Position: o << "Position"; break;
case ConnectSpec::CharExpr::Kind::Round: o << "Round"; break;
case ConnectSpec::CharExpr::Kind::Sign: o << "Sign"; break;
case ConnectSpec::CharExpr::Kind::Dispose: o << "Dispose"; break;
default: CRASH_NO_CASE;
}
return o;
}
// R1213
std::ostream &operator<<(std::ostream &o, IoControlSpec::CharExpr::Kind x) {
switch (x) {
case IoControlSpec::CharExpr::Kind::Advance: o << "Advance"; break;
case IoControlSpec::CharExpr::Kind::Blank: o << "Blank"; break;
case IoControlSpec::CharExpr::Kind::Decimal: o << "Decimal"; break;
case IoControlSpec::CharExpr::Kind::Delim: o << "Delim"; break;
case IoControlSpec::CharExpr::Kind::Pad: o << "Pad"; break;
case IoControlSpec::CharExpr::Kind::Round: o << "Round"; break;
case IoControlSpec::CharExpr::Kind::Sign: o << "Sign"; break;
default: CRASH_NO_CASE;
}
return o;
}
// R1231
std::ostream &operator<<(std::ostream &o, const InquireSpec::CharVar::Kind x) {
switch (x) {
case InquireSpec::CharVar::Kind::Access: o << "Access"; break;
case InquireSpec::CharVar::Kind::Action: o << "Action"; break;
case InquireSpec::CharVar::Kind::Asynchronous: o << "Asynchronous"; break;
case InquireSpec::CharVar::Kind::Blank: o << "Blank"; break;
case InquireSpec::CharVar::Kind::Decimal: o << "Decimal"; break;
case InquireSpec::CharVar::Kind::Delim: o << "Delim"; break;
case InquireSpec::CharVar::Kind::Encoding: o << "Encoding"; break;
case InquireSpec::CharVar::Kind::Form: o << "Form"; break;
case InquireSpec::CharVar::Kind::Formatted: o << "Formatted"; break;
case InquireSpec::CharVar::Kind::Iomsg: o << "Iomsg"; break;
case InquireSpec::CharVar::Kind::Name: o << "Name"; break;
case InquireSpec::CharVar::Kind::Pad: o << "Pad"; break;
case InquireSpec::CharVar::Kind::Position: o << "Position"; break;
case InquireSpec::CharVar::Kind::Read: o << "Read"; break;
case InquireSpec::CharVar::Kind::Readwrite: o << "Readwrite"; break;
case InquireSpec::CharVar::Kind::Round: o << "Round"; break;
case InquireSpec::CharVar::Kind::Sequential: o << "Sequential"; break;
case InquireSpec::CharVar::Kind::Sign: o << "Sign"; break;
case InquireSpec::CharVar::Kind::Stream: o << "Stream"; break;
case InquireSpec::CharVar::Kind::Status: o << "Status"; break;
case InquireSpec::CharVar::Kind::Write: o << "Write"; break;
default: CRASH_NO_CASE;
}
return o;
}
std::ostream &operator<<(std::ostream &o, const InquireSpec::IntVar::Kind x) {
switch (x) {
case InquireSpec::IntVar::Kind::Iostat: o << "Iostat"; break;
case InquireSpec::IntVar::Kind::Nextrec: o << "Nextrec"; break;
case InquireSpec::IntVar::Kind::Number: o << "Number"; break;
case InquireSpec::IntVar::Kind::Pos: o << "Pos"; break;
case InquireSpec::IntVar::Kind::Recl: o << "Recl"; break;
case InquireSpec::IntVar::Kind::Size: o << "Size"; break;
default: CRASH_NO_CASE;
}
return o;
}
std::ostream &operator<<(std::ostream &o, const InquireSpec::LogVar::Kind x) {
switch (x) {
case InquireSpec::LogVar::Kind::Exist: o << "Exist"; break;
case InquireSpec::LogVar::Kind::Named: o << "Named"; break;
case InquireSpec::LogVar::Kind::Opened: o << "Opened"; break;
case InquireSpec::LogVar::Kind::Pending: o << "Pending"; break;
default: CRASH_NO_CASE;
}
return o;
}
// R1307 data-edit-desc (part 1 of 2)
std::ostream &operator<<(std::ostream &o, const IntrinsicTypeDataEditDesc &x) {
o << "(IntrinsicTypeDataEditDesc ";
@ -982,16 +842,6 @@ std::ostream &operator<<(std::ostream &o, const IntrinsicTypeDataEditDesc &x) {
return o << x.width << ' ' << x.digits << ' ' << x.exponentWidth << ')';
}
// R1160, R1161
std::ostream &operator<<(std::ostream &o, StopStmt::Kind x) {
switch (x) {
case StopStmt::Kind::Stop: o << "Stop"; break;
case StopStmt::Kind::ErrorStop: o << "ErrorStop"; break;
default: CRASH_NO_CASE;
}
return o;
}
// R1210 read-stmt
std::ostream &operator<<(std::ostream &o, const ReadStmt &x) {
return o << "(ReadStmt " << x.iounit << ' ' << x.format << ' ' << x.controls
@ -1045,19 +895,9 @@ std::ostream &operator<<(std::ostream &o, const FormatItem &x) {
return o << ')';
}
// R1409, R1410
// R1409
std::ostream &operator<<(std::ostream &o, const UseStmt &x) {
o << "(UseStmt ";
if (x.nature) {
switch (*x.nature) {
case UseStmt::ModuleNature::Intrinsic: o << "Intrinsic"; break;
case UseStmt::ModuleNature::Non_Intrinsic: o << "Non_Intrinsic"; break;
default: CRASH_NO_CASE;
}
} else {
o << "()";
}
o << ' ' << x.moduleName << ' ';
o << "(UseStmt " << x.nature << ' ' << x.moduleName << ' ';
std::visit(
visitors{
[&o](const std::list<Rename> &y) -> void { o << "RENAME " << y; },
@ -1068,15 +908,6 @@ std::ostream &operator<<(std::ostream &o, const UseStmt &x) {
}
// R1506
std::ostream &operator<<(std::ostream &o, const ProcedureStmt::Kind &x) {
switch (x) {
case ProcedureStmt::Kind::ModuleProcedure: return o << "ModuleProcedure";
case ProcedureStmt::Kind::Procedure: return o << "Procedure";
default: CRASH_NO_CASE;
}
return o;
}
std::ostream &operator<<(std::ostream &o, const ProcedureStmt &x) {
return o << "(ProcedureStmt " << std::get<0>(x.t) << ' ' << std::get<1>(x.t)
<< ')';

View File

@ -82,6 +82,14 @@
WRAPPER_CLASS_BOILERPLATE(classname, type); \
}
// Enumeration types in classes can be defined with this macro,
// which also captures the names of the enums for formatting.
// Invocations an be followed by declarators and must be followed by
// a semicolon.
#define DEFINE_NESTED_ENUM_CLASS(ENUMTYPE, ...) \
static constexpr const char *ENUMTYPE##AsString{#__VA_ARGS__}; \
enum class ENUMTYPE { __VA_ARGS__ }
namespace Fortran {
namespace parser {
@ -477,30 +485,16 @@ WRAPPER_CLASS(NamedConstant, Name);
// The Name here is stored without the dots; e.g., FOO, not .FOO.
WRAPPER_CLASS(DefinedOpName, Name);
// R608 intrinsic-operator ->
// ** | * | / | + | - | // | .LT. | .LE. | .EQ. | .NE. | .GE. | .GT. |
// .NOT. | .AND. | .OR. | .EQV. | .NEQV.
// R609 defined-operator ->
// defined-unary-op | defined-binary-op | extended-intrinsic-op
// R610 extended-intrinsic-op -> intrinsic-operator
struct DefinedOperator {
UNION_CLASS_BOILERPLATE(DefinedOperator);
enum class IntrinsicOperator { // R608 intrinsic-operator
Power,
Multiply,
Divide,
Add,
Subtract,
Concat,
LT,
LE,
EQ,
NE,
GE,
GT,
NOT,
AND,
OR,
EQV,
NEQV
};
DEFINE_NESTED_ENUM_CLASS(IntrinsicOperator, Power, Multiply, Divide, Add,
Subtract, Concat, LT, LE, EQ, NE, GE, GT, NOT, AND, OR, EQV, NEQV);
std::variant<DefinedOpName, IntrinsicOperator> u;
};
@ -512,7 +506,7 @@ using ObjectName = Name;
// IMPORT , ONLY : import-name-list | IMPORT , NONE | IMPORT , ALL
struct ImportStmt {
BOILERPLATE(ImportStmt);
enum class Kind { Default, Only, None, All } kind{Kind::Default};
DEFINE_NESTED_ENUM_CLASS(Kind, Default, Only, None, All) kind{Kind::Default};
ImportStmt(Kind &&k) : kind{k} {}
ImportStmt(std::list<Name> &&n) : names(std::move(n)) {}
ImportStmt(Kind &&, std::list<Name> &&);
@ -552,7 +546,7 @@ WRAPPER_CLASS(IntegerTypeSpec, std::optional<KindSelector>);
// R723 char-length -> ( type-param-value ) | digit-string
struct CharLength {
UNION_CLASS_BOILERPLATE(CharLength);
std::variant<TypeParamValue, int64_t> u;
std::variant<TypeParamValue, std::int64_t> u;
};
// R722 length-selector -> ( [LEN =] type-param-value ) | * char-length [,]
@ -782,7 +776,7 @@ struct ConstantValue {
// R807 access-spec -> PUBLIC | PRIVATE
struct AccessSpec {
enum class Kind { Public, Private };
DEFINE_NESTED_ENUM_CLASS(Kind, Public, Private);
WRAPPER_CLASS_BOILERPLATE(AccessSpec, Kind);
};
@ -792,11 +786,7 @@ EMPTY_CLASS(Abstract);
struct TypeAttrSpec {
UNION_CLASS_BOILERPLATE(TypeAttrSpec);
EMPTY_CLASS(BindC);
struct Extends {
BOILERPLATE(Extends);
Extends(Name &&n) : name(std::move(n)) {}
Name name;
};
WRAPPER_CLASS(Extends, Name);
std::variant<Abstract, AccessSpec, BindC, Extends> u;
};
@ -830,9 +820,9 @@ struct TypeParamDecl {
// integer-type-spec , type-param-attr-spec :: type-param-decl-list
// R734 type-param-attr-spec -> KIND | LEN
struct TypeParamDefStmt {
enum class KindOrLength { Kind, Length }; // R734
DEFINE_NESTED_ENUM_CLASS(KindOrLen, Kind, Len); // R734
TUPLE_CLASS_BOILERPLATE(TypeParamDefStmt);
std::tuple<IntegerTypeSpec, KindOrLength, std::list<TypeParamDecl>> t;
std::tuple<IntegerTypeSpec, KindOrLen, std::list<TypeParamDecl>> t;
};
// R1028 specification-expr -> scalar-int-expr
@ -1209,7 +1199,7 @@ struct ArraySpec {
// R826 intent-spec -> IN | OUT | INOUT
struct IntentSpec {
enum class Intent { In, Out, InOut };
DEFINE_NESTED_ENUM_CLASS(Intent, In, Out, InOut);
WRAPPER_CLASS_BOILERPLATE(IntentSpec, Intent);
};
@ -1445,8 +1435,7 @@ struct ImplicitSpec {
// R866 implicit-name-spec -> EXTERNAL | TYPE
struct ImplicitStmt {
UNION_CLASS_BOILERPLATE(ImplicitStmt);
enum class ImplicitNoneNameSpec { External, Type }; // R866
friend std::ostream &operator<<(std::ostream &, ImplicitNoneNameSpec);
DEFINE_NESTED_ENUM_CLASS(ImplicitNoneNameSpec, External, Type); // R866
std::variant<std::list<ImplicitSpec>, std::list<ImplicitNoneNameSpec>> u;
};
@ -2332,7 +2321,7 @@ struct StopCode {
// R1161 error-stop-stmt ->
// ERROR STOP [stop-code] [, QUIET = scalar-logical-expr]
struct StopStmt {
enum class Kind { Stop, ErrorStop };
DEFINE_NESTED_ENUM_CLASS(Kind, Stop, ErrorStop);
TUPLE_CLASS_BOILERPLATE(StopStmt);
std::tuple<Kind, std::optional<StopCode>, std::optional<ScalarLogicalExpr>> t;
};
@ -2448,28 +2437,16 @@ WRAPPER_CLASS(ErrLabel, Label);
struct ConnectSpec {
UNION_CLASS_BOILERPLATE(ConnectSpec);
struct CharExpr {
enum class Kind {
Access,
Action,
Asynchronous,
Blank,
Decimal,
Delim,
Encoding,
Form,
Pad,
Position,
Round,
Sign,
Dispose /*extension*/
};
DEFINE_NESTED_ENUM_CLASS(Kind, Access, Action, Asynchronous, Blank, Decimal,
Delim, Encoding, Form, Pad, Position, Round, Sign,
Dispose /*extension*/);
TUPLE_CLASS_BOILERPLATE(CharExpr);
std::tuple<Kind, ScalarDefaultCharExpr> t;
};
WRAPPER_CLASS(Recl, ScalarIntExpr);
WRAPPER_CLASS(Newunit, ScalarIntVariable);
std::variant<FileUnitNumber, FileNameExpr, CharExpr, StatVariable, Recl,
Newunit, ErrLabel, StatusExpr>
std::variant<FileUnitNumber, FileNameExpr, CharExpr, MsgVariable,
StatVariable, Recl, Newunit, ErrLabel, StatusExpr>
u;
};
@ -2517,7 +2494,8 @@ WRAPPER_CLASS(EorLabel, Label);
struct IoControlSpec {
UNION_CLASS_BOILERPLATE(IoControlSpec);
struct CharExpr {
enum class Kind { Advance, Blank, Decimal, Delim, Pad, Round, Sign };
DEFINE_NESTED_ENUM_CLASS(
Kind, Advance, Blank, Decimal, Delim, Pad, Round, Sign);
TUPLE_CLASS_BOILERPLATE(CharExpr);
std::tuple<Kind, ScalarDefaultCharExpr> t;
};
@ -2680,39 +2658,19 @@ struct FlushStmt {
struct InquireSpec {
UNION_CLASS_BOILERPLATE(InquireSpec);
struct CharVar {
enum class Kind {
Access,
Action,
Asynchronous,
Blank,
Decimal,
Delim,
Encoding,
Form,
Formatted,
Iomsg,
Name,
Pad,
Position,
Read,
Readwrite,
Round,
Sequential,
Sign,
Stream,
Status,
Write
};
DEFINE_NESTED_ENUM_CLASS(Kind, Access, Action, Asynchronous, Blank, Decimal,
Delim, Encoding, Form, Formatted, Iomsg, Name, Pad, Position, Read,
Readwrite, Round, Sequential, Sign, Stream, Status, Write);
TUPLE_CLASS_BOILERPLATE(CharVar);
std::tuple<Kind, ScalarDefaultCharVariable> t;
};
struct IntVar {
enum class Kind { Iostat, Nextrec, Number, Pos, Recl, Size };
DEFINE_NESTED_ENUM_CLASS(Kind, Iostat, Nextrec, Number, Pos, Recl, Size);
TUPLE_CLASS_BOILERPLATE(IntVar);
std::tuple<Kind, ScalarIntVariable> t;
};
struct LogVar {
enum class Kind { Exist, Named, Opened, Pending };
DEFINE_NESTED_ENUM_CLASS(Kind, Exist, Named, Opened, Pending);
TUPLE_CLASS_BOILERPLATE(LogVar);
std::tuple<Kind, Scalar<Logical<Variable>>> t;
};
@ -2736,17 +2694,20 @@ struct InquireStmt {
// R1301 format-stmt -> FORMAT format-specification
WRAPPER_CLASS(FormatStmt, FormatSpecification);
// R1402 program-stmt -> PROGRAM program-name
WRAPPER_CLASS(ProgramStmt, Name);
// R1403 end-program-stmt -> END [PROGRAM [program-name]]
WRAPPER_CLASS(EndProgramStmt, std::optional<Name>);
// R1401 main-program ->
// [program-stmt] [specification-part] [execution-part]
// [internal-subprogram-part] end-program-stmt
// R1402 program-stmt -> PROGRAM program-name
struct MainProgram {
TUPLE_CLASS_BOILERPLATE(MainProgram);
std::tuple<std::optional<Statement<Name>>, SpecificationPart, ExecutionPart,
std::optional<InternalSubprogramPart>, Statement<EndProgramStmt>>
std::tuple<std::optional<Statement<ProgramStmt>>, SpecificationPart,
ExecutionPart, std::optional<InternalSubprogramPart>,
Statement<EndProgramStmt>>
t;
};
@ -2882,7 +2843,7 @@ struct Only {
// R1410 module-nature -> INTRINSIC | NON_INTRINSIC
struct UseStmt {
BOILERPLATE(UseStmt);
enum class ModuleNature { Intrinsic, Non_Intrinsic }; // R1410
DEFINE_NESTED_ENUM_CLASS(ModuleNature, Intrinsic, Non_Intrinsic); // R1410
template<typename A>
UseStmt(std::optional<ModuleNature> &&nat, Name &&n, std::list<A> &&x)
: nature(std::move(nat)), moduleName(std::move(n)), u(std::move(x)) {}
@ -2995,7 +2956,7 @@ struct InterfaceBody {
// R1506 procedure-stmt -> [MODULE] PROCEDURE [::] specific-procedure-list
struct ProcedureStmt {
enum class Kind { ModuleProcedure, Procedure };
DEFINE_NESTED_ENUM_CLASS(Kind, ModuleProcedure, Procedure);
TUPLE_CLASS_BOILERPLATE(ProcedureStmt);
std::tuple<Kind, std::list<Name>> t;
};
@ -3184,7 +3145,6 @@ struct AssignedGotoStmt {
WRAPPER_CLASS(PauseStmt, std::optional<StopCode>);
// Formatting of template types
// TODO move elsewhere?
template<typename A>
std::ostream &operator<<(std::ostream &o, const Statement<A> &x) {
return o << "(Statement " << x.label << ' '
@ -3222,6 +3182,20 @@ std::ostream &operator<<(std::ostream &o, const LoopBounds<A> &x) {
return o << "(LoopBounds " << x.name << ' ' << x.lower << ' ' << x.upper
<< ' ' << x.step << ')';
}
// Formatting enumerations defined via DEFINE_NESTED_ENUM_CLASS
#define NESTED_ENUM_TO_STRING(ENUMTYPE) \
static std::string ToString(ENUMTYPE x) { \
std::string str{ENUMTYPE##AsString}; \
size_t start{0}; \
for (int j{static_cast<int>(x)}; j-- > 0;) { \
start = str.find(',', start) + 1; \
} \
while (str[start] == ' ') { \
++start; \
} \
return str.substr(start, str.find(',', start)); \
}
} // namespace parser
} // namespace Fortran
#endif // FORTRAN_PARSER_PARSE_TREE_H_

View File

@ -68,8 +68,39 @@ TokenSequence Definition::Tokenize(const std::vector<std::string> &argNames,
return result;
}
static size_t AfterLastNonBlank(const TokenSequence &tokens) {
for (size_t j{tokens.size()}; j > 0; --j) {
if (!tokens[j - 1].IsBlank()) {
return j;
}
}
return 0;
}
static TokenSequence Stringify(
const TokenSequence &tokens, AllSources *allSources) {
TokenSequence result;
Provenance quoteProvenance{allSources->CompilerInsertionProvenance('"')};
result.PutNextTokenChar('"', quoteProvenance);
for (size_t j{0}; j < tokens.size(); ++j) {
const CharPointerWithLength &token{tokens[j]};
size_t bytes{token.size()};
for (size_t k{0}; k < bytes; ++k) {
char ch{token[k]};
Provenance from{tokens.GetTokenProvenance(j, k)};
if (ch == '"' || ch == '\\') {
result.PutNextTokenChar(ch, from);
}
result.PutNextTokenChar(ch, from);
}
}
result.PutNextTokenChar('"', quoteProvenance);
result.CloseToken();
return result;
}
TokenSequence Definition::Apply(
const std::vector<TokenSequence> &args, const AllSources &allSources) {
const std::vector<TokenSequence> &args, AllSources *allSources) {
TokenSequence result;
bool pasting{false};
bool skipping{false};
@ -93,35 +124,16 @@ TokenSequence Definition::Apply(
if (index >= args.size()) {
continue;
}
size_t afterLastNonBlank{result.size()};
for (; afterLastNonBlank > 0; --afterLastNonBlank) {
if (!result[afterLastNonBlank - 1].IsBlank()) {
break;
}
}
size_t argTokens{args[index].size()};
size_t afterLastNonBlank{AfterLastNonBlank(result)};
if (afterLastNonBlank > 0 &&
result[afterLastNonBlank - 1].ToString() == "#") {
// stringifying
while (result.size() >= afterLastNonBlank) {
result.pop_back();
}
Provenance quoteProvenance{allSources.CompilerInsertionProvenance('"')};
result.PutNextTokenChar('"', quoteProvenance);
for (size_t k{0}; k < argTokens; ++k) {
const CharPointerWithLength &arg{args[index][k]};
size_t argBytes{args[index][k].size()};
for (size_t n{0}; n < argBytes; ++n) {
char ch{arg[n]};
Provenance from{args[index].GetTokenProvenance(k, n)};
if (ch == '"' || ch == '\\') {
result.PutNextTokenChar(ch, from);
}
result.PutNextTokenChar(ch, from);
}
}
result.PutNextTokenChar('"', quoteProvenance);
result.CloseToken();
result.Put(Stringify(args[index], allSources));
} else {
size_t argTokens{args[index].size()};
for (size_t k{0}; k < argTokens; ++k) {
if (!pasting || !args[index][k].IsBlank()) {
result.Put(args[index], k);
@ -143,9 +155,10 @@ TokenSequence Definition::Apply(
// Delete whitespace immediately following ## in the body.
} else if (bytes == 11 && isVariadic_ &&
token.ToString() == "__VA_ARGS__") {
Provenance commaProvenance{allSources->CompilerInsertionProvenance(',')};
for (size_t k{argumentCount_}; k < args.size(); ++k) {
if (k > argumentCount_) {
result.Put(","s, allSources.CompilerInsertionProvenance(','));
result.Put(","s, commaProvenance);
}
result.Put(args[k]);
}
@ -205,7 +218,7 @@ bool Preprocessor::MacroReplacement(const TokenSequence &input,
}
}
if (j == tokens) {
return false; // nothing appeared that could be replaced
return false; // contains nothing that would be replaced
}
result->Put(input, 0, j);
for (; j < tokens; ++j) {
@ -300,7 +313,7 @@ bool Preprocessor::MacroReplacement(const TokenSequence &input,
}
def.set_isDisabled(true);
TokenSequence replaced{
ReplaceMacros(def.Apply(args, *allSources_), prescanner)};
ReplaceMacros(def.Apply(args, allSources_), prescanner)};
def.set_isDisabled(false);
if (!replaced.empty()) {
ProvenanceRange from{def.replacement().GetProvenanceRange()};

View File

@ -37,8 +37,7 @@ public:
bool set_isDisabled(bool disable);
TokenSequence Apply(
const std::vector<TokenSequence> &args, const AllSources &);
TokenSequence Apply(const std::vector<TokenSequence> &args, AllSources *);
private:
static TokenSequence Tokenize(const std::vector<std::string> &argNames,

View File

@ -161,8 +161,11 @@ void Prescanner::NextChar() {
}
}
while (*at_ == '\n' || *at_ == '&') {
if ((inFixedForm_ && !FixedFormContinuation()) ||
(!inFixedForm_ && !FreeFormContinuation())) {
if (inFixedForm_) {
if (!FixedFormContinuation()) {
return;
}
} else if (!FreeFormContinuation()) {
return;
}
}
@ -220,9 +223,7 @@ bool Prescanner::NextToken(TokenSequence *tokens) {
EmitCharAndAdvance(tokens, 'h');
inCharLiteral_ = true;
while (n-- > 0) {
if (PadOutCharacterLiteral()) {
tokens->PutNextTokenChar(' ', spaceProvenance_);
} else {
if (!PadOutCharacterLiteral(tokens)) {
if (*at_ == '\n') {
break; // TODO error
}
@ -306,20 +307,42 @@ bool Prescanner::ExponentAndKind(TokenSequence *tokens) {
return true;
}
void Prescanner::EmitQuotedCharacter(TokenSequence *tokens, char ch) {
switch (ch) {
case '\a': EmitEscapedChar(tokens, 'a'); break;
case '\b': EmitEscapedChar(tokens, 'b'); break;
case '\f': EmitEscapedChar(tokens, 'f'); break;
case '\r': EmitEscapedChar(tokens, 'r'); break;
case '\t': EmitEscapedChar(tokens, 't'); break;
case '\v': EmitEscapedChar(tokens, 'v'); break;
case '\\':
if (!enableBackslashEscapesInCharLiterals_) {
EmitInsertedChar(tokens, '\\');
}
EmitChar(tokens, '\\');
break;
default:
if (ch < ' ') {
// emit an octal escape sequence
EmitInsertedChar(tokens, '\\');
EmitInsertedChar(tokens, '0' + ((ch >> 6) & 3));
EmitInsertedChar(tokens, '0' + ((ch >> 3) & 7));
EmitInsertedChar(tokens, '0' + (ch & 7));
} else {
EmitChar(tokens, ch);
}
}
}
void Prescanner::QuotedCharacterLiteral(TokenSequence *tokens) {
char quote{*at_};
inCharLiteral_ = true;
do {
EmitCharAndAdvance(tokens, *at_);
while (PadOutCharacterLiteral()) {
tokens->PutNextTokenChar(' ', spaceProvenance_);
EmitQuotedCharacter(tokens, *at_);
NextChar();
while (PadOutCharacterLiteral(tokens)) {
}
if (*at_ == '\\' && enableBackslashEscapesInCharLiterals_) {
EmitCharAndAdvance(tokens, '\\');
while (PadOutCharacterLiteral()) {
tokens->PutNextTokenChar(' ', spaceProvenance_);
}
} else if (*at_ == quote) {
if (*at_ == quote) {
// A doubled quote mark becomes a single instance of the quote character
// in the literal later.
EmitCharAndAdvance(tokens, quote);
@ -334,9 +357,10 @@ void Prescanner::QuotedCharacterLiteral(TokenSequence *tokens) {
inCharLiteral_ = false;
}
bool Prescanner::PadOutCharacterLiteral() {
bool Prescanner::PadOutCharacterLiteral(TokenSequence *tokens) {
if (inFixedForm_ && !tabInCurrentLine_ && *at_ == '\n' &&
column_ < fixedFormColumnLimit_) {
tokens->PutNextTokenChar(' ', spaceProvenance_);
++column_;
return true;
}
@ -502,7 +526,7 @@ bool Prescanner::CommentLinesAndPreprocessorDirectives() {
const char *Prescanner::FixedFormContinuationLine() {
const char *p{lineStart_};
if (p >= limit_) {
if (p >= limit_ || !inFixedForm_) {
return nullptr;
}
tabInCurrentLine_ = false;
@ -539,6 +563,9 @@ bool Prescanner::FixedFormContinuation() {
}
bool Prescanner::FreeFormContinuation() {
if (inFixedForm_) {
return false;
}
while (*at_ == ' ' || *at_ == '\t') {
++at_;
}

View File

@ -74,6 +74,17 @@ private:
tokens->PutNextTokenChar(ch, GetCurrentProvenance());
}
void EmitInsertedChar(TokenSequence *tokens, char ch) {
Provenance provenance{
cooked_->allSources()->CompilerInsertionProvenance(ch)};
tokens->PutNextTokenChar(ch, provenance);
}
void EmitEscapedChar(TokenSequence *tokens, char ch) {
EmitInsertedChar(tokens, '\\');
EmitChar(tokens, ch);
}
char EmitCharAndAdvance(TokenSequence *tokens, char ch) {
EmitChar(tokens, ch);
NextChar();
@ -86,8 +97,9 @@ private:
void SkipSpaces();
bool NextToken(TokenSequence *);
bool ExponentAndKind(TokenSequence *);
void EmitQuotedCharacter(TokenSequence *, char);
void QuotedCharacterLiteral(TokenSequence *);
bool PadOutCharacterLiteral();
bool PadOutCharacterLiteral(TokenSequence *);
bool CommentLines();
bool CommentLinesAndPreprocessorDirectives();
bool IsFixedFormCommentLine(const char *);
@ -123,6 +135,8 @@ private:
int delimiterNesting_{0};
Provenance spaceProvenance_{
cooked_->allSources()->CompilerInsertionProvenance(' ')};
Provenance backslashProvenance_{
cooked_->allSources()->CompilerInsertionProvenance('\\')};
};
} // namespace parser
} // namespace Fortran

View File

@ -66,11 +66,6 @@ AllSources::AllSources() : range_{1, 1} {
// so that provenance offset 0 remains reserved as an uninitialized
// value.
origin_.emplace_back(range_, std::string{'?'});
for (char ch : " ,\"01\n"s) {
compilerInsertionProvenance_[ch] =
AddCompilerInsertion(std::string{ch}).LocalOffsetToProvenance(0);
}
}
AllSources::~AllSources() {}
@ -231,8 +226,15 @@ int AllSources::GetLineNumber(Provenance at) const {
return source ? source->FindOffsetLineAndColumn(offset).first : 0;
}
Provenance AllSources::CompilerInsertionProvenance(char ch) const {
return compilerInsertionProvenance_.find(ch)->second;
Provenance AllSources::CompilerInsertionProvenance(char ch) {
auto iter = compilerInsertionProvenance_.find(ch);
if (iter != compilerInsertionProvenance_.end()) {
return iter->second;
}
ProvenanceRange newCharRange{AddCompilerInsertion(std::string{ch})};
Provenance newCharProvenance{newCharRange.LocalOffsetToProvenance(0)};
compilerInsertionProvenance_.insert(std::make_pair(ch, newCharProvenance));
return newCharProvenance;
}
AllSources::Origin::Origin(ProvenanceRange r, const SourceFile &source)

View File

@ -176,7 +176,7 @@ public:
ProvenanceRange GetContiguousRangeAround(ProvenanceRange) const;
std::string GetPath(Provenance) const; // __FILE__
int GetLineNumber(Provenance) const; // __LINE__
Provenance CompilerInsertionProvenance(char ch) const;
Provenance CompilerInsertionProvenance(char ch);
void Dump(std::ostream &) const;
private:

View File

@ -199,7 +199,7 @@ struct CharLiteralChar {
state->PutMessage(at, "unclosed character constant"_en_US);
return {};
}
if (ch != '\\' || !state->enableBackslashEscapesInCharLiterals()) {
if (ch != '\\') {
return {Result::Bare(ch)};
}
if (!(och = nextChar.Parse(state)).has_value()) {

View File

@ -165,11 +165,9 @@ public:
Put("END MODULE");
return true;
}
bool Pre(const MainProgram &x) {
if (std::get<std::optional<Statement<Name>>>(x.t)) {
Put("PROGRAM ");
Indent();
}
bool Pre(const ProgramStmt &x) {
Put("PROGRAM ");
Indent();
return true;
}
bool Pre(const EndProgramStmt &x) {

View File

@ -147,7 +147,6 @@ int main(int argc, char *const argv[]) {
Fortran::parser::ParseState state{cooked};
Fortran::parser::UserState ustate;
state.set_inFixedForm(fixedForm)
.set_enableBackslashEscapesInCharLiterals(backslashEscapes)
.set_strictConformance(standard)
.set_userState(&ustate);

View File

@ -202,7 +202,7 @@ static void visitDerivedTypeDef(const DerivedTypeDef &dtd) {
std::visit(
visitors{
[&](const TypeAttrSpec::Extends &extends) {
builder.extends(extends.name);
builder.extends(extends.v);
},
[&](const TypeAttrSpec::BindC &) {
builder.attr(semantics::Attr::BIND_C);