Skip to content

Commit

Permalink
[flang] Replay a FORMAT at the right position
Browse files Browse the repository at this point in the history
When FORMAT control reaches the final parenthesis and data items
remain, we advance a record and revert to the beginning of the
FORMAT for further items.  But when the FORMAT contains any
nested parenthesized group of editing descriptors, possibly
repeated, reversion must be to the beginning of the last such
top-level parenthesized group, including its repetition count.

Reviewed By: sscalpone, PeteSteinfeld

Differential Revision: https://reviews.llvm.org/D84281
  • Loading branch information
klausler committed Jul 22, 2020
1 parent 320389e commit c6cb726
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 8 deletions.
15 changes: 12 additions & 3 deletions flang/runtime/format-implementation.h
Expand Up @@ -225,6 +225,7 @@ int FormatControl<CONTEXT>::CueUpNextDataEdit(Context &context, bool stop) {
while (true) {
std::optional<int> repeat;
bool unlimited{false};
auto maybeReversionPoint{offset_};
CharType ch{GetNextChar(context)};
while (ch == ',' || ch == ':') {
// Skip commas, and don't complain if they're missing; the format
Expand Down Expand Up @@ -254,6 +255,7 @@ int FormatControl<CONTEXT>::CueUpNextDataEdit(Context &context, bool stop) {
return 0;
}
stack_[height_].start = offset_ - 1; // the '('
RUNTIME_CHECK(context, format_[stack_[height_].start] == '(');
if (unlimited || height_ == 0) {
stack_[height_].remaining = Iteration::unlimited;
unlimitedLoopCheck = offset_ - 1;
Expand All @@ -265,6 +267,12 @@ int FormatControl<CONTEXT>::CueUpNextDataEdit(Context &context, bool stop) {
} else {
stack_[height_].remaining = 0;
}
if (height_ == 1) {
// Subtle point (F'2018 13.4 para 9): tha last parenthesized group
// at height 1 becomes the restart point after control reaches the
// end of the format, including its repeat count.
stack_[0].start = maybeReversionPoint - 1;
}
++height_;
} else if (height_ == 0) {
context.SignalError(IostatErrorInFormat, "FORMAT lacks initial '('");
Expand All @@ -276,14 +284,15 @@ int FormatControl<CONTEXT>::CueUpNextDataEdit(Context &context, bool stop) {
}
context.AdvanceRecord(); // implied / before rightmost )
}
auto restart{stack_[height_ - 1].start + 1};
if (stack_[height_ - 1].remaining == Iteration::unlimited) {
offset_ = stack_[height_ - 1].start + 1;
offset_ = restart;
if (offset_ == unlimitedLoopCheck) {
context.SignalError(IostatErrorInFormat,
"Unlimited repetition in FORMAT lacks data edit descriptors");
}
} else if (stack_[height_ - 1].remaining-- > 0) {
offset_ = stack_[height_ - 1].start + 1;
offset_ = restart;
} else {
--height_;
}
Expand Down Expand Up @@ -396,7 +405,7 @@ DataEdit FormatControl<CONTEXT>::GetNextDataEdit(
++height_;
}
edit.repeat = 1;
if (height_ > 1) {
if (height_ > 1) { // Subtle: stack_[0].start doesn't necessarily point to '('
int start{stack_[height_ - 1].start};
if (format_[start] != '(') {
if (stack_[height_ - 1].remaining > maxRepeat) {
Expand Down
15 changes: 10 additions & 5 deletions flang/unittests/Runtime/hello.cpp
Expand Up @@ -38,16 +38,16 @@ static void hello() {
}

static void multiline() {
char buffer[4][32];
char buffer[5][32];
StaticDescriptor<1> staticDescriptor[2];
Descriptor &whole{staticDescriptor[0].descriptor()};
SubscriptValue extent[]{4};
SubscriptValue extent[]{5};
whole.Establish(TypeCode{CFI_type_char}, sizeof buffer[0], &buffer, 1, extent,
CFI_attribute_pointer);
whole.Dump();
whole.Check();
Descriptor &section{staticDescriptor[1].descriptor()};
SubscriptValue lowers[]{0}, uppers[]{3}, strides[]{1};
SubscriptValue lowers[]{0}, uppers[]{4}, strides[]{1};
section.Establish(whole.type(), whole.ElementBytes(), nullptr, 1, extent,
CFI_attribute_pointer);
if (auto error{
Expand All @@ -57,20 +57,25 @@ static void multiline() {
}
section.Dump();
section.Check();
const char *format{"('?abcde,',T1,'>',T9,A,TL12,A,TR25,'<'//G0,25X,'done')"};
const char *format{
"('?abcde,',T1,'>',T9,A,TL12,A,TR25,'<'//G0,17X,'abcd',1(2I4))"};
auto cookie{IONAME(BeginInternalArrayFormattedOutput)(
section, format, std::strlen(format))};
IONAME(OutputAscii)(cookie, "WORLD", 5);
IONAME(OutputAscii)(cookie, "HELLO", 5);
IONAME(OutputInteger64)(cookie, 789);
for (int j{666}; j <= 999; j += 111) {
IONAME(OutputInteger64)(cookie, j);
}
if (auto status{IONAME(EndIoStatement)(cookie)}) {
Fail() << "multiline: '" << format << "' failed, status "
<< static_cast<int>(status) << '\n';
} else {
test(format,
">HELLO, WORLD <"
" "
"789 done"
"789 abcd 666 777"
" 888 999 "
" ",
std::string{buffer[0], sizeof buffer});
}
Expand Down

0 comments on commit c6cb726

Please sign in to comment.