@@ -125,7 +125,8 @@ template <typename CHAR = char> class FormatValidator {
125
125
void check_r (bool allowed = true );
126
126
bool check_w ();
127
127
void check_m ();
128
- bool check_d ();
128
+ bool check_d (bool checkScaleFactor = false );
129
+ void check_k ();
129
130
void check_e ();
130
131
131
132
const CHAR *const format_; // format text
@@ -135,11 +136,13 @@ template <typename CHAR = char> class FormatValidator {
135
136
136
137
const CHAR *cursor_{}; // current location in format_
137
138
const CHAR *laCursor_{}; // lookahead cursor
138
- Token token_{}; // current token
139
139
TokenKind previousTokenKind_{TokenKind::None};
140
- int64_t integerValue_{- 1 }; // value of UnsignedInteger token
140
+ Token token_{ }; // current token
141
141
Token knrToken_{}; // k, n, or r UnsignedInteger token
142
+ Token scaleFactorToken_{}; // most recent scale factor token P
143
+ int64_t integerValue_{-1 }; // value of UnsignedInteger token
142
144
int64_t knrValue_{-1 }; // -1 ==> not present
145
+ int64_t scaleFactorValue_{}; // signed k in kP
143
146
int64_t wValue_{-1 };
144
147
char argString_[3 ]{}; // 1-2 character msg arg; usually edit descriptor name
145
148
bool formatHasErrors_{false };
@@ -491,7 +494,8 @@ template <typename CHAR> void FormatValidator<CHAR>::check_m() {
491
494
}
492
495
493
496
// Return the predicate "d value is present" to control further processing.
494
- template <typename CHAR> bool FormatValidator<CHAR>::check_d() {
497
+ template <typename CHAR>
498
+ bool FormatValidator<CHAR>::check_d(bool checkScaleFactor) {
495
499
if (token_.kind () != TokenKind::Point ) {
496
500
ReportError (" Expected '%s' edit descriptor '.d' value" );
497
501
return false ;
@@ -501,10 +505,41 @@ template <typename CHAR> bool FormatValidator<CHAR>::check_d() {
501
505
ReportError (" Expected '%s' edit descriptor 'd' value after '.'" );
502
506
return false ;
503
507
}
508
+ if (checkScaleFactor) {
509
+ check_k ();
510
+ }
504
511
NextToken ();
505
512
return true ;
506
513
}
507
514
515
+ // Check the value of scale factor k against a field width d.
516
+ template <typename CHAR> void FormatValidator<CHAR>::check_k() {
517
+ // Limit the check to D and E edit descriptors in output statements that
518
+ // explicitly set the scale factor.
519
+ if (stmt_ != IoStmtKind::Print && stmt_ != IoStmtKind::Write) {
520
+ return ;
521
+ }
522
+ if (!scaleFactorToken_.IsSet ()) {
523
+ return ;
524
+ }
525
+ // 13.7.2.3.3p5 - The values of d and k must satisfy:
526
+ // −d < k <= 0; or
527
+ // 0 < k < d+2
528
+ const int64_t d{integerValue_};
529
+ const int64_t k{scaleFactorValue_};
530
+ // Exception: d = k = 0 is nonstandard, but has a reasonable interpretation.
531
+ if (d == 0 && k == 0 ) {
532
+ return ;
533
+ }
534
+ if (k <= 0 && !(-d < k)) {
535
+ ReportError (" Negative scale factor k (from kP) and width d in a '%s' "
536
+ " edit descriptor must satisfy '-d < k'" );
537
+ } else if (k > 0 && !(k < d + 2 )) {
538
+ ReportError (" Positive scale factor k (from kP) and width d in a '%s' "
539
+ " edit descriptor must satisfy 'k < d+2'" );
540
+ }
541
+ }
542
+
508
543
template <typename CHAR> void FormatValidator<CHAR>::check_e() {
509
544
if (token_.kind () != TokenKind::E) {
510
545
return ;
@@ -584,28 +619,32 @@ template <typename CHAR> bool FormatValidator<CHAR>::Check() {
584
619
}
585
620
break ;
586
621
case TokenKind::D:
587
- case TokenKind::F:
622
+ case TokenKind::F: {
588
623
// R1307 data-edit-desc -> D w . d | F w . d
624
+ bool isD{token_.kind () == TokenKind::D};
589
625
hasDataEditDesc = true ;
590
626
check_r ();
591
627
NextToken ();
592
628
if (check_w ()) {
593
- check_d ();
629
+ check_d (/* checkScaleFactor= */ isD );
594
630
}
595
631
break ;
632
+ }
596
633
case TokenKind::E:
597
634
case TokenKind::EN:
598
635
case TokenKind::ES:
599
- case TokenKind::EX:
636
+ case TokenKind::EX: {
600
637
// R1307 data-edit-desc ->
601
638
// E w . d [E e] | EN w . d [E e] | ES w . d [E e] | EX w . d [E e]
639
+ bool isE{token_.kind () == TokenKind::E};
602
640
hasDataEditDesc = true ;
603
641
check_r ();
604
642
NextToken ();
605
- if (check_w () && check_d ()) {
643
+ if (check_w () && check_d (/* checkScaleFactor= */ isE )) {
606
644
check_e ();
607
645
}
608
646
break ;
647
+ }
609
648
case TokenKind::G:
610
649
// R1307 data-edit-desc -> G w [. d [E e]]
611
650
hasDataEditDesc = true ;
@@ -695,6 +734,13 @@ template <typename CHAR> bool FormatValidator<CHAR>::Check() {
695
734
// R1313 control-edit-desc -> k P
696
735
if (knrValue_ < 0 ) {
697
736
ReportError (" 'P' edit descriptor must have a scale factor" );
737
+ } else {
738
+ scaleFactorToken_ = knrToken_;
739
+ if (signToken.IsSet () && format_[signToken.offset ()] == ' -' ) {
740
+ scaleFactorValue_ = -knrValue_;
741
+ } else {
742
+ scaleFactorValue_ = knrValue_;
743
+ }
698
744
}
699
745
// Diagnosing C1302 may require multiple token lookahead.
700
746
// Save current cursor position to enable backup.
0 commit comments