proof/: migrate cell from int to 64-bit signed word, full suite verifies
cell_t is a 64-bit signed C long; the formal model previously used unbounded HOL int, hiding wraparound and signed/unsigned distinctions entirely. Switches cell to "64 word" throughout and fixes every proof site that assumed int semantics: - StarForth_Base.thy: cell_safe/cell_abs/cell_sdiv/cell_smod plus the sint-bridging lemmas used across the suite - StarForth_Loop1_Heat.thy, StarForth_Loop3_Decay.thy: heat tracking converted to signed word comparisons (<s/\<le>s) - StarForth_Stack_Words.thy: PICK/ROLL against real C ground truth - StarForth_Arithmetic_Words.thy: ABS/MIN/MAX/div/mod rebuilt on signed word semantics (cell_sdiv/cell_smod match C99 truncating division; 2/ uses signed_drop_bit to match "n >> 1"); documents a genuine ABS(INT64_MIN) wraparound hazard mirroring the real C behavior - StarForth_Memory_Words.thy: @/!/C@/C! address checks converted to the signed order All 23 theory files verify with zero errors, including StarForth_Concurrent and StarForth_Correctness. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
9b4bbc9de6
commit
fe6e705867
@@ -295,11 +295,11 @@ definition forth_depth :: "vm_state \<Rightarrow> vm_state" where
|
||||
"forth_depth vm =
|
||||
(if ds_full vm
|
||||
then set_error vm
|
||||
else vm\<lparr>data_stack := int (length (data_stack vm)) # data_stack vm\<rparr>)"
|
||||
else vm\<lparr>data_stack := word_of_nat (length (data_stack vm)) # data_stack vm\<rparr>)"
|
||||
|
||||
lemma depth_pushes_count:
|
||||
assumes "\<not> ds_full vm"
|
||||
shows "hd (data_stack (forth_depth vm)) = int (length (data_stack vm))"
|
||||
shows "hd (data_stack (forth_depth vm)) = word_of_nat (length (data_stack vm))"
|
||||
by (simp add: forth_depth_def assms)
|
||||
|
||||
lemma depth_rest_preserved:
|
||||
@@ -327,7 +327,7 @@ lemma depth_overflow:
|
||||
val = data_stack[dsp - n]
|
||||
data_stack[dsp] = val (replace TOS with val)
|
||||
|
||||
Bounds check: n \<ge> 0 and n < length (data_stack vm) *)
|
||||
Bounds check: 0 \<le>s n and n < length (data_stack vm) *)
|
||||
|
||||
(* CORRECTED 2026-08-13, against src/word_source/stack_words.c:265-282 and
|
||||
its passing tests (test_runner/modules/stack_words_test.c: pick_0,
|
||||
@@ -338,7 +338,7 @@ lemma depth_overflow:
|
||||
convention. The theory's original definition indexed into
|
||||
"data_stack vm" (the PRE-pop stack, still containing n as its own head)
|
||||
instead of "xs" (post-pop) -- off by one position, and its bound check
|
||||
"nat n \<ge> length (data_stack vm)" used the pre-pop length too, one too
|
||||
"unat n \<ge> length (data_stack vm)" used the pre-pop length too, one too
|
||||
permissive (C's own bound is against post-pop depth, vm->dsp+1 = length
|
||||
xs). Confirmed against the real test vectors: "1 2 3 0 PICK" expects
|
||||
TOS=3 (xs!0), "1 2 3 1 PICK" expects 2 (xs!1), "1 2 3 2 PICK" expects 1
|
||||
@@ -348,37 +348,37 @@ definition forth_pick :: "vm_state \<Rightarrow> vm_state" where
|
||||
(case data_stack vm of
|
||||
[] \<Rightarrow> set_error vm
|
||||
| n # xs \<Rightarrow>
|
||||
if n < 0 \<or> nat n \<ge> length xs
|
||||
if n <s 0 \<or> unat n \<ge> length xs
|
||||
then set_error vm
|
||||
else vm\<lparr>data_stack := xs ! nat n # xs\<rparr>)"
|
||||
else vm\<lparr>data_stack := xs ! unat n # xs\<rparr>)"
|
||||
|
||||
lemma pick_normal:
|
||||
assumes "data_stack vm = n # xs"
|
||||
assumes "n \<ge> 0"
|
||||
assumes "nat n < length xs"
|
||||
shows "data_stack (forth_pick vm) = xs ! nat n # xs"
|
||||
assumes "0 \<le>s n"
|
||||
assumes "unat n < length xs"
|
||||
shows "data_stack (forth_pick vm) = xs ! unat n # xs"
|
||||
using assms by (auto simp: forth_pick_def)
|
||||
|
||||
lemma pick_depth_unchanged:
|
||||
assumes "data_stack vm = n # xs"
|
||||
assumes "n \<ge> 0"
|
||||
assumes "nat n < length xs"
|
||||
assumes "0 \<le>s n"
|
||||
assumes "unat n < length xs"
|
||||
shows "length (data_stack (forth_pick vm)) = length (data_stack vm)"
|
||||
using assms by (auto simp: forth_pick_def)
|
||||
using assms by (auto simp: forth_pick_def word_sless_alt word_sle_eq)
|
||||
|
||||
(* 0 PICK: pushes a copy of the post-pop TOS (xs!0) -- equivalent to DUP.
|
||||
Matches the real test vector "1 2 3 0 PICK" => prints 3. *)
|
||||
lemma pick_zero_dup:
|
||||
assumes "data_stack vm = 0 # x # xs"
|
||||
shows "data_stack (forth_pick vm) = x # x # xs"
|
||||
using assms by (auto simp: forth_pick_def)
|
||||
using assms by (auto simp: forth_pick_def word_sless_alt word_sle_eq)
|
||||
|
||||
(* 1 PICK: pushes a copy of the item one below TOS (xs!1).
|
||||
Matches the real test vector "1 2 3 1 PICK" => prints 2. *)
|
||||
lemma pick_one:
|
||||
assumes "data_stack vm = 1 # x # y # xs"
|
||||
shows "data_stack (forth_pick vm) = y # x # y # xs"
|
||||
using assms by (auto simp: forth_pick_def)
|
||||
using assms by (auto simp: forth_pick_def word_sless_alt word_sle_eq)
|
||||
|
||||
lemma pick_underflow:
|
||||
assumes "data_stack vm = []"
|
||||
@@ -387,13 +387,13 @@ lemma pick_underflow:
|
||||
|
||||
lemma pick_bounds_neg:
|
||||
assumes "data_stack vm = n # xs"
|
||||
assumes "n < 0"
|
||||
assumes "n <s 0"
|
||||
shows "vm_error (forth_pick vm)"
|
||||
by (simp add: forth_pick_def set_error_def assms)
|
||||
|
||||
lemma pick_bounds_high:
|
||||
assumes "data_stack vm = n # xs"
|
||||
assumes "nat n \<ge> length xs"
|
||||
assumes "unat n \<ge> length xs"
|
||||
shows "vm_error (forth_pick vm)"
|
||||
using assms by (auto simp: forth_pick_def set_error_def)
|
||||
|
||||
@@ -434,11 +434,11 @@ definition forth_roll :: "vm_state \<Rightarrow> vm_state" where
|
||||
(case data_stack vm of
|
||||
[] \<Rightarrow> set_error vm
|
||||
| n # xs \<Rightarrow>
|
||||
if n < 0 \<or> nat n > length xs
|
||||
if n <s 0 \<or> unat n > length xs
|
||||
then set_error vm
|
||||
else if n = 0
|
||||
then vm\<lparr>data_stack := xs\<rparr>
|
||||
else let i = length xs - nat n;
|
||||
else let i = length xs - unat n;
|
||||
item = xs ! i;
|
||||
rest = take i xs @ drop (i + 1) xs
|
||||
in vm\<lparr>data_stack := item # rest\<rparr>)"
|
||||
@@ -456,10 +456,11 @@ lemma roll_one_moves_bottom:
|
||||
assumes "xs \<noteq> []"
|
||||
shows "data_stack (forth_roll vm) = last xs # butlast xs"
|
||||
proof -
|
||||
have i: "length xs - nat (1::int) = length xs - 1" by simp
|
||||
have i: "length xs - unat (1::cell) = length xs - 1" by simp
|
||||
show ?thesis
|
||||
using assms
|
||||
by (simp add: forth_roll_def Let_def i last_conv_nth butlast_conv_take)
|
||||
by (simp add: forth_roll_def Let_def i last_conv_nth butlast_conv_take
|
||||
word_sless_alt word_sle_eq)
|
||||
qed
|
||||
|
||||
(* Ground-truth test vectors, proved symbolically (no need to construct a
|
||||
@@ -470,14 +471,14 @@ qed
|
||||
lemma roll_test_vector_1:
|
||||
assumes "data_stack vm = [1, 3, 2, 1]"
|
||||
shows "data_stack (forth_roll vm) = [1, 3, 2]"
|
||||
using assms by (simp add: forth_roll_def)
|
||||
using assms by (simp add: forth_roll_def word_sless_alt word_sle_eq)
|
||||
|
||||
(* "1 2 3 2 ROLL . . . CR" => prints "2 3 1": xs=[3,2,1] after popping the
|
||||
count 2; 2 ROLL moves the 2nd-from-bottom item (2) to top. *)
|
||||
lemma roll_test_vector_2:
|
||||
assumes "data_stack vm = [2, 3, 2, 1]"
|
||||
shows "data_stack (forth_roll vm) = [2, 3, 1]"
|
||||
using assms by (simp add: forth_roll_def)
|
||||
using assms by (simp add: forth_roll_def word_sless_alt word_sle_eq)
|
||||
|
||||
lemma roll_underflow:
|
||||
assumes "data_stack vm = []"
|
||||
@@ -486,13 +487,13 @@ lemma roll_underflow:
|
||||
|
||||
lemma roll_bounds_neg:
|
||||
assumes "data_stack vm = n # xs"
|
||||
assumes "n < 0"
|
||||
assumes "n <s 0"
|
||||
shows "vm_error (forth_roll vm)"
|
||||
by (simp add: forth_roll_def set_error_def assms)
|
||||
|
||||
lemma roll_bounds_high:
|
||||
assumes "data_stack vm = n # xs"
|
||||
assumes "nat n > length xs"
|
||||
assumes "unat n > length xs"
|
||||
shows "vm_error (forth_roll vm)"
|
||||
by (simp add: forth_roll_def set_error_def assms)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user