From 691031a7f9bc8aa4d5fa160155c632b2728efb12 Mon Sep 17 00:00:00 2001 From: Eremey Valetov Date: Sun, 15 Feb 2026 16:22:55 -0500 Subject: [PATCH] Fix RESTORE with line number, add 8 Rosetta Code test programs RESTORE n now correctly positions past the DATA token so the next READ gets actual values instead of the token byte. New tests: Roman numerals, Luhn validator, Towers of Hanoi, 100 Doors, Pascal's triangle, type declarations, Hailstone sequence, multiplication table. 50 tests now pass. --- src/interp.c | 16 ++++++++++++++++ tests/programs/def_types.bas | 29 +++++++++++++++++++++++++++++ tests/programs/hailstone.bas | 13 +++++++++++++ tests/programs/hanoi.bas | 22 ++++++++++++++++++++++ tests/programs/hundred_doors.bas | 17 +++++++++++++++++ tests/programs/luhn.bas | 21 +++++++++++++++++++++ tests/programs/mult_table.bas | 22 ++++++++++++++++++++++ tests/programs/pascal_triangle.bas | 21 +++++++++++++++++++++ tests/programs/roman_numerals.bas | 24 ++++++++++++++++++++++++ 9 files changed, 185 insertions(+) create mode 100644 tests/programs/def_types.bas create mode 100644 tests/programs/hailstone.bas create mode 100644 tests/programs/hanoi.bas create mode 100644 tests/programs/hundred_doors.bas create mode 100644 tests/programs/luhn.bas create mode 100644 tests/programs/mult_table.bas create mode 100644 tests/programs/pascal_triangle.bas create mode 100644 tests/programs/roman_numerals.bas diff --git a/src/interp.c b/src/interp.c index cbf2e23..e386d90 100644 --- a/src/interp.c +++ b/src/interp.c @@ -279,6 +279,22 @@ static void stmt_restore(void) if (!gw.data_line_ptr) gw_error(ERR_UL); gw.data_ptr = gw.data_line_ptr->tokens; + /* Scan to the DATA token and skip past it so read_data_item + finds values, not the keyword. If the target line has no + DATA, data_ptr ends at '\0' and the next READ will call + advance_data_ptr to move to subsequent lines. */ + while (*gw.data_ptr && *gw.data_ptr != TOK_DATA) { + if (*gw.data_ptr == '"') { + gw.data_ptr++; + while (*gw.data_ptr && *gw.data_ptr != '"') + gw.data_ptr++; + if (*gw.data_ptr == '"') gw.data_ptr++; + continue; + } + gw.data_ptr++; + } + if (*gw.data_ptr == TOK_DATA) + gw.data_ptr++; } else { gw.data_line_ptr = NULL; gw.data_ptr = NULL; diff --git a/tests/programs/def_types.bas b/tests/programs/def_types.bas new file mode 100644 index 0000000..bd1a9d8 --- /dev/null +++ b/tests/programs/def_types.bas @@ -0,0 +1,29 @@ +10 REM Type declarations, RESTORE with line#, ON GOSUB +20 DEFINT A-C +30 DEFSNG D-F +40 DEFSTR S-T +50 A = 3.7 +60 IF A <> 4 THEN PRINT "FAIL: DEFINT A should round 3.7 to 4, got"; A : END +70 D = 3.14159 +80 IF D < 3.14 OR D > 3.15 THEN PRINT "FAIL: DEFSNG D unexpected"; D : END +90 S = "hello" +100 IF S <> "hello" THEN PRINT "FAIL: DEFSTR S should hold string" : END +110 REM RESTORE with line number +120 DATA 10, 20, 30 +200 DATA 40, 50, 60 +210 RESTORE 200 +220 READ X +230 IF X <> 40 THEN PRINT "FAIL: RESTORE 200 should read 40, got"; X : END +240 RESTORE 120 +250 READ Y +260 IF Y <> 10 THEN PRINT "FAIL: RESTORE 120 should read 10, got"; Y : END +270 REM ON GOSUB +280 FOR I = 1 TO 3 +290 ON I GOSUB 400, 410, 420 +300 NEXT I +310 IF R <> 6 THEN PRINT "FAIL: ON GOSUB sum should be 6, got"; R : END +320 PRINT "Type declarations OK" +330 END +400 R = R + 1 : RETURN +410 R = R + 2 : RETURN +420 R = R + 3 : RETURN diff --git a/tests/programs/hailstone.bas b/tests/programs/hailstone.bas new file mode 100644 index 0000000..233cd69 --- /dev/null +++ b/tests/programs/hailstone.bas @@ -0,0 +1,13 @@ +10 REM Hailstone (Collatz) sequence - Rosetta Code +20 N# = 27 +30 STEPS = 0 +40 MAXVAL# = N# +50 WHILE N# <> 1 +60 IF N# / 2 = INT(N# / 2) THEN N# = N# / 2 ELSE N# = 3 * N# + 1 +70 STEPS = STEPS + 1 +80 IF N# > MAXVAL# THEN MAXVAL# = N# +90 WEND +100 REM Hailstone(27) has 111 steps, max value 9232 +110 IF STEPS <> 111 THEN PRINT "FAIL: expected 111 steps, got"; STEPS : END +120 IF MAXVAL# <> 9232 THEN PRINT "FAIL: expected max 9232, got"; MAXVAL# : END +130 PRINT "Hailstone OK: 27 ->"; STEPS; "steps, max"; MAXVAL# diff --git a/tests/programs/hanoi.bas b/tests/programs/hanoi.bas new file mode 100644 index 0000000..7849da7 --- /dev/null +++ b/tests/programs/hanoi.bas @@ -0,0 +1,22 @@ +10 REM Towers of Hanoi - iterative with explicit stack - Rosetta Code +20 NDISKS = 4 +30 DIM SN(50), SF(50), ST(50), SV(50) +40 SP = 0 +50 REM Push initial call: move NDISKS from A to C via B +60 SP = SP + 1 : SN(SP) = NDISKS : SF(SP) = 1 : ST(SP) = 3 : SV(SP) = 2 +70 MOVES = 0 +80 IF SP = 0 THEN 200 +90 N = SN(SP) : F = SF(SP) : T = ST(SP) : V = SV(SP) : SP = SP - 1 +100 IF N = 0 THEN 80 +110 REM Push move(N-1, via, to, from) - this goes on stack FIRST (executed LAST) +120 SP = SP + 1 : SN(SP) = N-1 : SF(SP) = V : ST(SP) = T : SV(SP) = F +130 REM Push the actual move of disk N from F to T (sentinel N=0 above it) +140 SP = SP + 1 : SN(SP) = 0 : SF(SP) = F : ST(SP) = T : SV(SP) = 0 +150 MOVES = MOVES + 1 +160 REM Push move(N-1, from, via, to) +170 SP = SP + 1 : SN(SP) = N-1 : SF(SP) = F : ST(SP) = V : SV(SP) = T +180 GOTO 80 +200 REM Should be 2^NDISKS - 1 = 15 moves +210 EXPECTED = 2^NDISKS - 1 +220 IF MOVES <> EXPECTED THEN PRINT "FAIL: expected"; EXPECTED; "got"; MOVES : END +230 PRINT "Hanoi OK:"; MOVES; "moves" diff --git a/tests/programs/hundred_doors.bas b/tests/programs/hundred_doors.bas new file mode 100644 index 0000000..877304b --- /dev/null +++ b/tests/programs/hundred_doors.bas @@ -0,0 +1,17 @@ +10 REM 100 Doors problem - Rosetta Code +20 DIM D(100) +30 FOR PASS = 1 TO 100 +40 FOR DOOR = PASS TO 100 STEP PASS +50 D(DOOR) = 1 - D(DOOR) +60 NEXT DOOR +70 NEXT PASS +80 REM Only perfect squares should be open +90 C = 0 +100 FOR I = 1 TO 100 +110 IF D(I) = 0 THEN 150 +120 S = SQR(I) +130 IF INT(S) <> S THEN PRINT "FAIL: door"; I; "open but not perfect square" : END +140 C = C + 1 +150 NEXT I +160 IF C <> 10 THEN PRINT "FAIL: expected 10 open doors, got"; C : END +170 PRINT "100 Doors OK:"; C; "open" diff --git a/tests/programs/luhn.bas b/tests/programs/luhn.bas new file mode 100644 index 0000000..6f43d62 --- /dev/null +++ b/tests/programs/luhn.bas @@ -0,0 +1,21 @@ +10 REM Luhn algorithm - credit card validator - Rosetta Code +20 DATA "49927398716", 1, "49927398717", 0 +30 DATA "1234567812345670", 1, "1234567812345678", 0 +40 FOR T = 1 TO 4 +50 READ CARD$ +60 S = 0 +70 NDIG = LEN(CARD$) +80 PARITY = NDIG MOD 2 +90 FOR I = 1 TO NDIG +100 D = VAL(MID$(CARD$, I, 1)) +110 IF ((I-1) MOD 2) <> PARITY THEN 140 +120 D = D * 2 +130 IF D > 9 THEN D = D - 9 +140 S = S + D +150 NEXT I +160 RESULT = 0 +170 IF (S MOD 10) = 0 THEN RESULT = 1 +180 READ EXPECTED +190 IF RESULT <> EXPECTED THEN PRINT "FAIL: "; CARD$; " sum="; S : END +200 NEXT T +210 PRINT "Luhn OK" diff --git a/tests/programs/mult_table.bas b/tests/programs/mult_table.bas new file mode 100644 index 0000000..ea1f799 --- /dev/null +++ b/tests/programs/mult_table.bas @@ -0,0 +1,22 @@ +10 REM Multiplication table - Rosetta Code +20 REM Header row +30 PRINT " X"; +40 FOR J = 1 TO 12 +50 PRINT USING "####"; J; +60 NEXT J +70 PRINT +80 PRINT STRING$(51, "-"); +90 PRINT +100 REM Table body +110 CHECKSUM = 0 +120 FOR I = 1 TO 12 +130 PRINT USING "###"; I; +140 FOR J = 1 TO 12 +150 IF J < I THEN PRINT " "; ELSE PRINT USING "####"; I * J; +160 IF J >= I THEN CHECKSUM = CHECKSUM + I * J +170 NEXT J +180 PRINT +190 NEXT I +200 REM Sum of i*j for j>=i, i=1..12: known value 3367 +210 IF CHECKSUM <> 3367 THEN PRINT "FAIL: checksum"; CHECKSUM : END +220 PRINT "Multiplication table OK" diff --git a/tests/programs/pascal_triangle.bas b/tests/programs/pascal_triangle.bas new file mode 100644 index 0000000..197dc25 --- /dev/null +++ b/tests/programs/pascal_triangle.bas @@ -0,0 +1,21 @@ +10 REM Pascal's triangle - Rosetta Code +20 NROWS = 8 +30 DIM R(20) +40 FOR ROW = 0 TO NROWS - 1 +50 REM Build row right-to-left to avoid overwriting +60 R(ROW) = 1 +65 IF ROW < 2 THEN 100 +70 FOR J = ROW - 1 TO 1 STEP -1 +80 R(J) = R(J) + R(J-1) +90 NEXT J +100 R(0) = 1 +110 REM Print with spacing +120 PRINT SPACE$(2 * (NROWS - ROW)); +130 FOR J = 0 TO ROW +140 PRINT USING "####"; R(J); +150 NEXT J +160 PRINT +170 NEXT ROW +180 REM Verify a known value: row 7, col 3 = C(7,3) = 35 +190 IF R(3) <> 35 THEN PRINT "FAIL: C(7,3) should be 35, got"; R(3) : END +200 PRINT "Pascal's triangle OK" diff --git a/tests/programs/roman_numerals.bas b/tests/programs/roman_numerals.bas new file mode 100644 index 0000000..d2e78b3 --- /dev/null +++ b/tests/programs/roman_numerals.bas @@ -0,0 +1,24 @@ +10 REM Roman numeral encoder - Rosetta Code +20 DIM V(12), R$(12) +30 DATA 1000,"M",900,"CM",500,"D",400,"CD" +40 DATA 100,"C",90,"XC",50,"L",40,"XL" +50 DATA 10,"X",9,"IX",5,"V",4,"IV",1,"I" +60 FOR I = 0 TO 12 +70 READ V(I), R$(I) +80 NEXT I +90 DATA 1990, 2008, 1666, 3999, 42, 14 +100 FOR T = 1 TO 6 +110 READ N +120 ORIG = N +130 S$ = "" +140 I = 0 +150 WHILE N > 0 +160 WHILE N >= V(I) +170 S$ = S$ + R$(I) +180 N = N - V(I) +190 WEND +200 I = I + 1 +210 WEND +220 PRINT ORIG; "="; S$ +230 NEXT T +240 PRINT "Roman numerals OK"