-
Notifications
You must be signed in to change notification settings - Fork 16.6k
[flang][flang-rt] Implement F202X leading-zero control edit descriptors LZ, LZS, and LZP for formatted output (F, E, D, and G editing) #183500
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 12 commits
e2922a1
0bc9c91
e148a59
4955f1d
3895bfe
84552d4
b4a013f
deaaf8a
4e7bdca
9d45382
786c706
c733fab
5b68726
29253ec
9a45c38
f357187
4ced144
ee77ec7
bfe2a4e
3947f5b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -193,7 +193,7 @@ static RT_API_ATTRS bool AbsoluteTabbing(CONTEXT &context, int n) { | |
|
|
||
| template <typename CONTEXT> | ||
| static RT_API_ATTRS void HandleControl( | ||
| CONTEXT &context, char ch, char next, int n) { | ||
| CONTEXT &context, char ch, char next, int n, char next2 = '\0') { | ||
| MutableModes &modes{context.mutableModes()}; | ||
| switch (ch) { | ||
| case 'B': | ||
|
|
@@ -251,6 +251,21 @@ static RT_API_ATTRS void HandleControl( | |
| return; | ||
| } | ||
| break; | ||
| case 'L': | ||
| if (next == 'Z') { | ||
| if (next2 == 'S') { | ||
| // LZS - suppress leading zeros | ||
| modes.leadingZero = MutableModes::LeadingZeroMode::Suppress; | ||
| } else if (next2 == 'P') { | ||
| // LZP - print leading zero | ||
| modes.leadingZero = MutableModes::LeadingZeroMode::Print; | ||
| } else { | ||
| // LZ - processor-dependent (default behavior) | ||
|
||
| modes.leadingZero = MutableModes::LeadingZeroMode::Processor; | ||
| } | ||
| return; | ||
| } | ||
| break; | ||
| case 'S': | ||
| if (next == 'P') { | ||
| modes.editingFlags |= signPlus; | ||
|
|
@@ -455,6 +470,7 @@ RT_API_ATTRS int FormatControl<CONTEXT>::CueUpNextDataEdit( | |
| } else if (ch >= 'A' && ch <= 'Z') { | ||
| int start{offset_ - 1}; | ||
| CharType next{'\0'}; | ||
| CharType next2{'\0'}; | ||
| if (ch != 'P') { // 1PE5.2 - comma not required (C1302) | ||
| CharType peek{Capitalize(PeekNext())}; | ||
| if (peek >= 'A' && peek <= 'Z') { | ||
|
|
@@ -464,6 +480,15 @@ RT_API_ATTRS int FormatControl<CONTEXT>::CueUpNextDataEdit( | |
| // Assume a two-letter edit descriptor | ||
| next = peek; | ||
| ++offset_; | ||
| } else if (ch == 'L' && peek == 'Z') { | ||
| // LZ, LZS, or LZP control edit descriptor | ||
| next = peek; | ||
| ++offset_; | ||
| CharType peek2{Capitalize(PeekNext())}; | ||
| if (peek2 == 'S' || peek2 == 'P') { | ||
| next2 = peek2; | ||
| ++offset_; | ||
| } | ||
| } else { | ||
| // extension: assume a comma between 'ch' and 'peek' | ||
| } | ||
|
|
@@ -484,7 +509,7 @@ RT_API_ATTRS int FormatControl<CONTEXT>::CueUpNextDataEdit( | |
| repeat = GetIntField(context); | ||
| } | ||
| HandleControl(context, static_cast<char>(ch), static_cast<char>(next), | ||
| repeat ? *repeat : 1); | ||
| repeat ? *repeat : 1, static_cast<char>(next2)); | ||
| } | ||
| } else if (ch == '/') { | ||
| context.AdvanceRecord(repeat && *repeat > 0 ? *repeat : 1); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -44,6 +44,12 @@ struct MutableModes { | |
| return editingFlags & decimalComma ? char32_t{','} : char32_t{'.'}; | ||
| } | ||
|
|
||
| enum class LeadingZeroMode : std::uint8_t { | ||
|
||
| Processor, // LZ: processor-dependent (default) | ||
| Suppress, // LZS: suppress optional leading zero | ||
| Print, // LZP: print optional leading zero | ||
| }; | ||
|
|
||
| std::uint8_t editingFlags{0}; // BN, DP, SS | ||
| enum decimal::FortranRounding round{ | ||
| executionEnvironment | ||
|
|
@@ -53,6 +59,7 @@ struct MutableModes { | |
| short scale{0}; // kP | ||
| bool inNamelist{false}; // skip ! comments | ||
| bool nonAdvancing{false}; // ADVANCE='NO', or $ or \ in FORMAT | ||
| LeadingZeroMode leadingZero{LeadingZeroMode::Processor}; // LZ/LZS/LZP | ||
| }; | ||
|
|
||
| // A single edit descriptor extracted from a FORMAT | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -419,10 +419,28 @@ RT_API_ATTRS bool RealOutputEditing<KIND>::EditEorDOutput( | |
| if (totalLength > width || !exponent) { | ||
| return EmitRepeated(io_, '*', width); | ||
| } | ||
| if (totalLength < width && digitsBeforePoint == 0 && | ||
| zeroesBeforePoint == 0) { | ||
| zeroesBeforePoint = 1; | ||
| ++totalLength; | ||
| if (digitsBeforePoint == 0 && zeroesBeforePoint == 0 && scale <= 0) { | ||
| // Optional leading zero position (F202X leading zero control). | ||
| // When scale > 0 (kP with k > 0), digits are moved before the decimal | ||
| // point, so the leading zero position is not optional -- skip this. | ||
| // Value has no digits before the decimal point: "0.xxxE+yy" vs ".xxxE+yy" | ||
| switch (edit.modes.leadingZero) { | ||
| case MutableModes::LeadingZeroMode::Print: | ||
|
||
| // LZP: always print the optional leading zero | ||
| zeroesBeforePoint = 1; | ||
| ++totalLength; | ||
| break; | ||
| case MutableModes::LeadingZeroMode::Suppress: | ||
| // LZS: never print the optional leading zero | ||
| break; | ||
| case MutableModes::LeadingZeroMode::Processor: | ||
| // LZ: processor-defined; add leading zero only when field has room | ||
| if (totalLength < width) { | ||
| zeroesBeforePoint = 1; | ||
| ++totalLength; | ||
| } | ||
| break; | ||
| } | ||
| } | ||
| if (totalLength < width && editWidth == 0) { | ||
| width = totalLength; | ||
|
|
@@ -552,7 +570,21 @@ RT_API_ATTRS bool RealOutputEditing<KIND>::EditFOutput(const DataEdit &edit) { | |
| if (digitsBeforePoint + zeroesBeforePoint + zeroesAfterPoint + | ||
| digitsAfterPoint + trailingZeroes == | ||
| 0) { | ||
| zeroesBeforePoint = 1; // "." -> "0." | ||
| zeroesBeforePoint = 1; // "."--> "0." (bare decimal point) | ||
|
||
| } else if (digitsBeforePoint == 0 && zeroesBeforePoint == 0 && expo <= 0) { | ||
| // Optional leading zero position (F202X leading zero control). | ||
| // Value magnitude < 1: "0.xxx" vs ".xxx" | ||
| switch (edit.modes.leadingZero) { | ||
| case MutableModes::LeadingZeroMode::Print: | ||
|
||
| // LZP: always print the optional leading zero | ||
| zeroesBeforePoint = 1; | ||
| break; | ||
| case MutableModes::LeadingZeroMode::Suppress: | ||
| // LZS: never print the optional leading zero | ||
| break; | ||
| case MutableModes::LeadingZeroMode::Processor: | ||
| break; // handled below after width computation | ||
| } | ||
| } | ||
| int totalLength{signLength + digitsBeforePoint + zeroesBeforePoint + | ||
| 1 /*'.'*/ + zeroesAfterPoint + digitsAfterPoint + trailingZeroes + | ||
|
|
@@ -561,7 +593,8 @@ RT_API_ATTRS bool RealOutputEditing<KIND>::EditFOutput(const DataEdit &edit) { | |
| if (totalLength > width) { | ||
| return EmitRepeated(io_, '*', width); | ||
| } | ||
| if (totalLength < width && digitsBeforePoint + zeroesBeforePoint == 0) { | ||
| if (edit.modes.leadingZero == MutableModes::LeadingZeroMode::Processor && | ||
| totalLength < width && digitsBeforePoint + zeroesBeforePoint == 0) { | ||
| zeroesBeforePoint = 1; | ||
| ++totalLength; | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are there calls to
HandleControl()that need this default value for the new parameter?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch. The default value is unnecessary. Will remove it.