简体   繁体   English

如何证明SPARK.Text_IO过程的前提条件成立

[英]How to prove a SPARK.Text_IO procedure precondition will hold

I'm using SPARK.Text_IO from the spark_io example in SPARK Discovery 2017. 我正在使用SPARK Discovery 2017中spark_io示例中的SPARK.Text_IO。

My problem is that many of the SPARK.Text_IO procedures have a precondition that I do not know how to begin to try to prove namely that the standard input is readable and we're not at end of file. 我的问题是,许多SPARK.Text_IO过程都有一个前提条件,即我不知道如何开始尝试证明标准输入是可读的,而我们不在文件末尾。 My attempt, as displayed in the code below, was to add the precondition of the SPARK.Text_IO procedure (Get_Immediate in this case) to the precondition of the calling procedure, thinking that maybe that would guarantee to the prover that that precondition would be true. 如下面代码所示,我的尝试是将SPARK.Text_IO过程的前提条件(在本例中为Get_Immediate)添加到调用过程的前提条件中,认为可能会向证明者保证该前提条件为真。 It didn't work. 没用 Here's an example of what I'm talking about: 这是我正在谈论的示例:

Test spec: 测试规格:

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;

Test body: 测试体:

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;

The error the prover gives is on the Get_Immediate line "medium: precondition might fail" The prototype and contract of the Get_Immediate procedure is below: 证明者给出的错误位于Get_Immediate行上“ medium:前提条件可能失败”。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);

How do you prove to SPARK that Standard_Input is readable and that it's not end of file? 您如何向SPARK证明Standard_Input可读且不是文件结尾?

Let me start by saying I haven't used SPARK since the days of special comments, so my answer may not reflect current usage. 首先,我要说自特别评论之日起就没有使用过SPARK,因此我的回答可能无法反映当前的使用情况。

One way to look at SPARK is that it makes you think about every thing that your program might encounter. 查看SPARK的一种方法是,它使您考虑程序可能遇到的每件事。 What should your program do if the precondition is False? 如果前提为False,您的程序应该怎么做? You have to show that you've considered this possibility. 您必须证明您已经考虑过这种可能性。

Presuming that all SPARK.Ada.Text_IO operations on Standard_Input have a postcondition including Is_Readable (Standard_Input) as Get_Immediate does, then it should suffice to put something like 假定Standard_Input上的所有SPARK.Ada.Text_IO操作都具有包括Is_Readable (Standard_Input)在内的后置条件,如Get_Immediate一样,那么只要放置类似以下内容就足够了

pragma Assert (Is_Readable (Standard_Input) );

at the beginning of your program and add this to the postcondition of your procedure (and any other subprograms you have that read Standard_Input). 在程序的开头,并将其添加到过程的后置条件(以及您拥有读取Standard_Input的任何其他子程序)中。 Then you should be sure that that part of the precondition holds throughout your program. 然后,您应该确保前提条件的这一部分在整个程序中都适用。 (The assertion may not be needed if SPARK initially guarantees that Standard_Input is readable.) (如果SPARK最初保证Standard_Input是可读的,则可能不需要断言。)

not End_Of_File is a bit more complicated. not End_Of_File有点复杂。 It's possible for it to be False, at least on some platforms. 至少在某些平台上,它可能为False。 Linux, for example, treats Ctrl-D as EOF when entered as the first thing on a line. 例如,Linux在输入第一行时会将Ctrl-D视为EOF。 There's also the cases where you're reading from a pipe or input redirection. 在某些情况下,您正在从管道读取或输入重定向。 Your procedure may call Get_Immediate when End_Of_File is True if the user enters EOF during the loop, so it's not surprising SPARK can't prove otherwise. 如果用户在循环期间输入EOF,则当End_Of_File为True时,您的过程可能会调用Get_Immediate,因此SPARK不能证明否则就不足为奇了。 Probably you need to take this part off the precondition of your procedure and change your body to something like 可能您需要从手术的先决条件中脱身,然后将身体改变为类似

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;

Then you'll be sure the precondition of Get_Immediate is satisfied and have the apparently desired behavior (infinite loop) if End_Of_File becomes True (presuming that some field of IR fails one of your checks in that case). 然后,如果End_Of_File变为True(假设IR的某些字段在这种情况下无法通过您的一项检查),则可以确保Get_Immediate的前提条件得到满足,并具有明显的预期行为(无限循环)。

There are some puzzling things about your code. 关于您的代码,有些令人困惑的事情。 First is the global variable. 首先是全局变量。 Global variables are the Root of All Evil, or at least guarantee unreadable code. 全局变量是万恶之源,或至少保证不可读的代码。 Then there's the specificity of the procedure. 然后是该程序的特殊性。 Wouldn't something more general, like 不会更一般的东西,例如

procedure Wait_For_Key (Key : in Character);

be just as easy to write and prove, and more useful? 一样容易编写和证明,更有用吗? Then there's the string of nested if statements, which I find harder to read than the equivalent conditions connected with and then . 然后是一串嵌套的if语句,我发现它比and then连接的等效条件更难读。 Finally, there's comparing a Boolean to True. 最后,将Boolean与True进行比较。 Since "=" returns Boolean, doesn't that indicate that what's needed is a Boolean, which is what is already on the left side of "="? 由于“ =”返回布尔值,这是否表示所需的是布尔值,即“ =”的左侧已经存在?

Perhaps it means that the result of "=" must also be compared to True. 也许这意味着“ =”的结果也必须与True进行比较。 Then the result of that "=" must also be compared to True. 然后,该“ =”的结果也必须与True进行比较。 This might be better, since it ensures that whoever is writing this will never finish. 这样做可能会更好,因为它可以确保无论谁编写的内容都永远不会完成。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM