如何证明 SPARK.Text_IO 程序前提条件成立
How to prove a SPARK.Text_IO procedure precondition will hold
我正在使用 SPARK Discovery 2017 中 spark_io 示例中的 SPARK.Text_IO。
我的问题是许多 SPARK.Text_IO 程序都有一个先决条件,即我不知道如何开始尝试证明标准输入是可读的,并且我们不在文件末尾。如下面的代码所示,我的尝试是将 SPARK.Text_IO 过程的前提条件(在本例中为 Get_Immediate)添加到调用过程的前提条件中,认为这可能会保证证明者该先决条件为真。它没有用。这是我正在谈论的示例:
测试规范:
with SPARK.Ada.Text_IO; use SPARK.Ada.Text_IO;
package test with SPARK_Mode
is
continue_messages_key : Character := ' ';
procedure User_Wait_For_Continue_Messages_Key
with Global => (In_Out => Standard_Input,
Input => continue_messages_key),
Pre => Is_Readable (Standard_Input) and then
not End_Of_File;
end test;
测试体:
pragma SPARK_Mode(On);
package body test is
procedure User_Wait_For_Continue_Messages_Key
is
IR : Immediate_Result;
Avail : Boolean;
begin
loop
Get_Immediate(IR, Avail);
if Avail then
if IR.Status = Success then
if IR.Available = True then
if IR.Item = continue_messages_key then
return;
end if;
end if;
end if;
end if;
end loop;
end User_Wait_For_Continue_Messages_Key;
end test;
证明者给出的错误在Get_Immediate行"medium: precondition might fail"Get_Immediate程序的原型和合约如下:
procedure Get_Immediate (Item : out Character_Result)
with Global => (In_Out => Standard_Input),
Pre => Is_Readable (Standard_Input) and then
not End_Of_File,
Post => Is_Readable (Standard_Input) and
Name (Standard_Input) = Name (Standard_Input)'Old and
Form (Standard_Input) = Form (Standard_Input)'Old and
Is_Standard_Input (Standard_Input);
你如何向 SPARK 证明 Standard_Input 是可读的并且它不是文件结尾?
首先我要说的是,自从特别评论以来我就没有使用过 SPARK,所以我的回答可能无法反映当前的使用情况。
看待 SPARK 的一种方式是,它让您思考您的程序可能遇到的每一件事。如果前提条件为 False,您的程序应该做什么?你必须证明你已经考虑过这种可能性。
假设 Standard_Input 上的所有 SPARK.Ada.Text_IO 操作都有一个包括 Is_Readable (Standard_Input)
的后置条件,就像 Get_Immediate 所做的那样,那么放像
这样的东西就足够了
pragma Assert (Is_Readable (Standard_Input) );
在程序的开头,并将其添加到程序的后置条件中(以及任何其他读作 Standard_Input 的子程序)。那么你应该确保这部分前提条件在你的程序中始终成立。 (如果 SPARK 最初保证 Standard_Input 是可读的,则可能不需要断言。)
not End_Of_File
有点复杂。至少在某些平台上,它可能为 False。例如,Linux 将 Ctrl-D 作为行首输入时的 EOF。还有一些情况是您从管道或输入重定向中读取。如果用户在循环期间输入 EOF,则当 End_Of_File 为 True 时,您的过程可能会调用 Get_Immediate,因此 SPARK 无法证明其他情况也就不足为奇了。可能您需要将这部分从您的程序的前提条件中删除并将您的 body 更改为
All_Chars : loop
if not End_Of_File then
Get_Immediate (IR, Avail);
exit All_Chars when Avail and then
IR.Status = Success and then
IR.Available and then
IR.Item = Continue_Messages_Key;
end if;
end loop All_Chars;
那么如果 End_Of_File 变为 True(假设 IR 的某些字段未通过您的其中一个在这种情况下检查)。
您的代码有些令人费解的地方。首先是全局变量。全局变量是万恶之源,或者至少保证代码不可读。然后是程序的特殊性。不会是更一般的东西,比如
procedure Wait_For_Key (Key : in Character);
同样容易编写和证明,而且更有用?然后是嵌套的 if 语句字符串,我发现它比与 and then
相关的等效条件更难阅读。最后,将 Boolean 与 True 进行比较。因为“=” returns 布尔值,那不就说明需要的是布尔值,而“=”左边已经有了?
也许这意味着“=”的结果也必须与True进行比较。那么那个“=”的结果也必须与True进行比较。这可能会更好,因为它确保写这篇文章的人永远不会完成。
我正在使用 SPARK Discovery 2017 中 spark_io 示例中的 SPARK.Text_IO。
我的问题是许多 SPARK.Text_IO 程序都有一个先决条件,即我不知道如何开始尝试证明标准输入是可读的,并且我们不在文件末尾。如下面的代码所示,我的尝试是将 SPARK.Text_IO 过程的前提条件(在本例中为 Get_Immediate)添加到调用过程的前提条件中,认为这可能会保证证明者该先决条件为真。它没有用。这是我正在谈论的示例:
测试规范:
with SPARK.Ada.Text_IO; use SPARK.Ada.Text_IO;
package test with SPARK_Mode
is
continue_messages_key : Character := ' ';
procedure User_Wait_For_Continue_Messages_Key
with Global => (In_Out => Standard_Input,
Input => continue_messages_key),
Pre => Is_Readable (Standard_Input) and then
not End_Of_File;
end test;
测试体:
pragma SPARK_Mode(On);
package body test is
procedure User_Wait_For_Continue_Messages_Key
is
IR : Immediate_Result;
Avail : Boolean;
begin
loop
Get_Immediate(IR, Avail);
if Avail then
if IR.Status = Success then
if IR.Available = True then
if IR.Item = continue_messages_key then
return;
end if;
end if;
end if;
end if;
end loop;
end User_Wait_For_Continue_Messages_Key;
end test;
证明者给出的错误在Get_Immediate行"medium: precondition might fail"Get_Immediate程序的原型和合约如下:
procedure Get_Immediate (Item : out Character_Result)
with Global => (In_Out => Standard_Input),
Pre => Is_Readable (Standard_Input) and then
not End_Of_File,
Post => Is_Readable (Standard_Input) and
Name (Standard_Input) = Name (Standard_Input)'Old and
Form (Standard_Input) = Form (Standard_Input)'Old and
Is_Standard_Input (Standard_Input);
你如何向 SPARK 证明 Standard_Input 是可读的并且它不是文件结尾?
首先我要说的是,自从特别评论以来我就没有使用过 SPARK,所以我的回答可能无法反映当前的使用情况。
看待 SPARK 的一种方式是,它让您思考您的程序可能遇到的每一件事。如果前提条件为 False,您的程序应该做什么?你必须证明你已经考虑过这种可能性。
假设 Standard_Input 上的所有 SPARK.Ada.Text_IO 操作都有一个包括 Is_Readable (Standard_Input)
的后置条件,就像 Get_Immediate 所做的那样,那么放像
pragma Assert (Is_Readable (Standard_Input) );
在程序的开头,并将其添加到程序的后置条件中(以及任何其他读作 Standard_Input 的子程序)。那么你应该确保这部分前提条件在你的程序中始终成立。 (如果 SPARK 最初保证 Standard_Input 是可读的,则可能不需要断言。)
not End_Of_File
有点复杂。至少在某些平台上,它可能为 False。例如,Linux 将 Ctrl-D 作为行首输入时的 EOF。还有一些情况是您从管道或输入重定向中读取。如果用户在循环期间输入 EOF,则当 End_Of_File 为 True 时,您的过程可能会调用 Get_Immediate,因此 SPARK 无法证明其他情况也就不足为奇了。可能您需要将这部分从您的程序的前提条件中删除并将您的 body 更改为
All_Chars : loop
if not End_Of_File then
Get_Immediate (IR, Avail);
exit All_Chars when Avail and then
IR.Status = Success and then
IR.Available and then
IR.Item = Continue_Messages_Key;
end if;
end loop All_Chars;
那么如果 End_Of_File 变为 True(假设 IR 的某些字段未通过您的其中一个在这种情况下检查)。
您的代码有些令人费解的地方。首先是全局变量。全局变量是万恶之源,或者至少保证代码不可读。然后是程序的特殊性。不会是更一般的东西,比如
procedure Wait_For_Key (Key : in Character);
同样容易编写和证明,而且更有用?然后是嵌套的 if 语句字符串,我发现它比与 and then
相关的等效条件更难阅读。最后,将 Boolean 与 True 进行比较。因为“=” returns 布尔值,那不就说明需要的是布尔值,而“=”左边已经有了?
也许这意味着“=”的结果也必须与True进行比较。那么那个“=”的结果也必须与True进行比较。这可能会更好,因为它确保写这篇文章的人永远不会完成。