From 8745f421b4cf7e1d54c17a360d46fab889ca12cc Mon Sep 17 00:00:00 2001 From: _ov4 Date: Thu, 22 Oct 2026 15:33:17 +0000 Subject: feat(input)!: validate INPUT and read whole lines into STRING Scalar INPUT now reads one whitespace-delimited token through module-local IR helpers instead of scanf, then skips spaces and tabs and consumes one newline. INTEGER, REAL, BOOLEAN (TRUE or FALSE in any case) and CHAR are validated, and bad input or end of input is a runtime error. STRING INPUT reads the rest of the line. The unused scanf and REAL printf format globals are removed. Co-Authored-By: Claude Sonnet 5.5 --- tests/ii/strings/generate.pl | 14 +++++++------- tests/ii/strings/notes.md | 2 +- tests/ii/strings/program.cps | 2 +- tests/ii/strings/reference.cc | 5 ++++- 4 files changed, 13 insertions(+), 10 deletions(-) (limited to 'tests/ii/strings') diff --git a/tests/ii/strings/generate.pl b/tests/ii/strings/generate.pl index f3ac098..57aeef0 100644 --- a/tests/ii/strings/generate.pl +++ b/tests/ii/strings/generate.pl @@ -6,18 +6,18 @@ use Random; my ($seed, $count) = @ARGV; my $rng = Random->new($seed, "strings"); my @edges = ( - '1 placeholder 1 0', - '0 A 1 1', - '0 Ab09 4 1', - '0 Ab09 1 4', - '0 Ab09 2 0', + '1 1 0 placeholder', + '0 1 1 A', + '0 4 1 Ab09', + '0 1 4 Ab09', + '0 2 0 Ab09', ); $rng->emit($count, \@edges, sub { my $size = $rng->integer(0,24); -return '1 placeholder 1 0' if $size == 0; +return '1 1 0 placeholder' if $size == 0; my @alphabet = split //, 'ABCXYZabcxyz019@_-'; my $text = join '', map { $alphabet[$rng->integer(0,$#alphabet)] } 1 .. $size; my $start = $rng->integer(1,$size); my $width = $rng->integer(0,$size-$start+1); -return "0 $text $start $width"; +return "0 $start $width $text"; }); diff --git a/tests/ii/strings/notes.md b/tests/ii/strings/notes.md index 01ea90a..468cff4 100644 --- a/tests/ii/strings/notes.md +++ b/tests/ii/strings/notes.md @@ -1,5 +1,5 @@ # strings -CIE pp. 16-17 for LENGTH/MID/RIGHT/concatenation; full-STRING LCASE/UCASE is a project extension. Inputs are ASCII under the default C locale. Empty input is encoded with a flag because project INPUT reads tokens. Substrings remain in range; zero width is a documented project boundary. +CIE pp. 16-17 for LENGTH/MID/RIGHT/concatenation; full-STRING LCASE/UCASE is a project extension. Inputs are ASCII under the default C locale. The text is the last field of each record because INPUT into a STRING reads the rest of the line; empty text is still encoded with a flag so that every record has a visible text field. Substrings remain in range; zero width is a documented project boundary. Each record produces exactly one output line. Random records are preceded by fixed boundary records; every arithmetic intermediate is bounded. diff --git a/tests/ii/strings/program.cps b/tests/ii/strings/program.cps index 55e7541..8a5e509 100644 --- a/tests/ii/strings/program.cps +++ b/tests/ii/strings/program.cps @@ -7,9 +7,9 @@ DECLARE Width : INTEGER INPUT Count FOR Index <- 1 TO Count INPUT Empty - INPUT Text INPUT Start INPUT Width + INPUT Text IF Empty = 1 THEN Text <- "" ENDIF diff --git a/tests/ii/strings/reference.cc b/tests/ii/strings/reference.cc index 54d6efc..ec67b8c 100644 --- a/tests/ii/strings/reference.cc +++ b/tests/ii/strings/reference.cc @@ -8,7 +8,10 @@ int main() { for (int i = 0; i < count; ++i) { int empty, start, width; std::string text; - if (!(std::cin >> empty >> text >> start >> width)) return 1; + if (!(std::cin >> empty >> start >> width)) return 1; + // The text is the rest of the line, as for INPUT into a STRING. + if (!std::getline(std::cin >> std::ws, text)) return 1; + if (!text.empty() && text.back() == '\r') text.pop_back(); if (empty) text.clear(); auto lower = text, upper = text; for (auto &c : lower) c = static_cast(std::tolower(static_cast(c))); -- cgit v1.3.1-4-g156e