8. Other Input Formats¶
Why3 can be used to verify programs written in languages other than WhyML. Currently, Why3 supports tiny subsets of C and Python, respectively coined micro-C and micro-Python below. These were designed for teaching purposes. They come with their own specification languages, written in special comments. These input formats are described below.
Any Why3 tool (why3 prove
, why3 ide
, etc.) can be passed a file
with a suffix .c
or .py
, which triggers the corresponding input format.
These input formats can also be used in on-line versions of Why3, at
http://why3.lri.fr/micro-C/ and http://why3.lri.fr/python/, respectively.
8.1. micro-C¶
Micro-C is a valid subset of ANSI C. Hence, micro-C files can be passed to a C compiler.
8.1.1. Syntax of micro-C¶
Logical annotations are inserted in special comments starting
with //@
or /*@
. In the following grammar, we
only use the former kind, for simplicity, but both kinds are allowed.
file ::=decl
* decl ::=c_include
|c_function
|logic_declaration
c_include ::= "#include" "<" file-name ">"
Directives #include
are ignored during the translation to
Why3. They are allowed anyway, such that a C source code using
functions such as printf
(see below) is accepted by a C compiler.
Function definition
c_function ::=return_type
identifier "("params
? ")"spec
*block
return_type ::= "void" | "int" params ::=param
(","param
)* param ::= "int" identifier | "int" identifier "[]"
Function specification
spec ::= "//@" "requires"term
";" | "//@" "ensures"term
";" | "//@" "variant"term
(","term
)* ";"
C expression
expr ::= integer-literal | string-literal | identifier | identifier ( "++" | "--" ) | ( "++" | "--" ) identifier | identifier "["expr
"]" | identifier "["expr
"]" ( "++" | "--") | ( "++" | "--") identifier "["expr
"]" | "-"expr
| "!"expr
|expr
( "+" | "-" | "*" | "/" | "%" | "==" | "!=" | "<" | "<=" | ">" | ">=" | "&&" | "||" )expr
| identifier "(" (expr
(","expr
)*)? ")" | "scanf" "(" "\"%d\"" "," "&" identifier ")" | "("expr
")"
C statement
stmt ::= ";" | "return"expr
";" | "int" identifier ";" | "int" identifier "["expr
"]" ";" | "break" ";" | "if" "("expr
")"stmt
| "if" "("expr
")"stmt
"else"stmt
| "while" "("expr
")"loop_body
| "for" "("expr_stmt
";"expr
";"expr_stmt
")"loop_body
|expr_stmt
";" |block
| "//@" "label" identifier ";" | "//@" ( "assert" | "assume" | "check" )term
";" block ::= "{"stmt
* "}" expr_stmt ::= "int" identifier "="expr
| identifierassignop
expr
| identifier "["expr
"]"assignop
expr
|expr
assignop ::= "=" | "+=" | "-=" | "*=" | "/=" loop_body ::=loop_annot
*stmt
| "{"loop_annot
*stmt
* "}" loop_annot ::= "//@" "invariant"term
";" | "//@" "variant"term
(","term
)* ";"
Note that the syntax for loop bodies allows the loop annotations to be placed either before the block or right at the beginning of the block.
Logic declarations
logic_declaration ::= "//@" "function" "int" identifier "("params
")" ";" | "//@" "function" "int" identifier "("params
")" "="term
";" | "//@" "predicate" identifier "("params
")" ";" | "//@" "predicate" identifier "("params
")" "="term
";" | "//@" "axiom" identifier ":"term
";" | "//@" "lemma" identifier ":"term
";" | "//@" "goal" identifier ":"term
";"
Logic functions are limited to a return type int
.
Logical term
term ::= identifier | integer-literal | "true" | "false" | "("term
")" |term
"["term
"]" |term
"["term
"<-"term
"]" | "!"term
| "old" "("term
")" | "at" "("term
"," identifier ")" | "-"term
|term
( "->" | "<->" | "||" | "&&" )term
|term
( "==" | "!=" | "<" | "<=" | ">" | ">=" )term
|term
( "+" | "-" | "*" | "/" | "% )term
| "if"term
"then"term
"elseterm
| "let" identifier "="term
"in"term
| ( "forall" | "exists" )binder
(","binder
)* "."term
| identifier "(" (term
(","term
)*)? ")" binder ::= identifier | identifier "[]"
8.1.2. Built-in functions and predicates¶
C code
scanf
, with a syntax limited toscanf("%d", &x)
printf
, limited toprintf(string-literal, expr1, ..., exprn)
and assuming that the string literal contains exactly n occurrences of%d
(not checked by Why3).rand()
, returns a pseudo-random integer in the range 0 toRAND_MAX
inclusive.
Logic
int length(int[] a)
, the length of arraya
int occurrence(int v, int[] a)
, the number of occurrences of the valuev
in arraya
8.2. micro-Python¶
Micro-Python is a valid subset of Python 3. Hence, micro-Python files can be passed to a Python interpreter.
8.2.1. Syntax of micro-Python¶
Notation: In the grammar of micro-Python given below,
special symbols NEWLINE
, INDENT
,
and DEDENT
mark an end of line, the beginning of a new
indentation block, and its end, respectively.
Logical annotations are inserted in special comments starting with #@
.
file ::=decl
* decl ::=py_import
|py_function
|stmt
|logic_declaration
py_import ::= "from" identifier "import" identifier ("," identifier)* NEWLINE
Directives import
are ignored during the translation to
Why3. They are allowed anyway, such that a Python source code using
functions such as randint
is accepted by a Python
interpreter (see below).
Function definition
py_function ::= "def" identifier "(" [params
] ")" ":" NEWLINE INDENTspec
*stmt
* DEDENT params ::= identifier ("," identifier)*
Function specification
spec ::= "#@" "requires"term
NEWLINE | "#@" "ensures"term
NEWLINE | "#@" "variant"term
(","term
)* NEWLINE
Python expression
expr ::= "None" | "True" | "False" | integer-literal | string-literal | identifier | identifier "["expr
"]" | "-"expr
| "not"expr
|expr
( "+" | "-" | "*" | "//" | "%" | "==" | "!=" | "<" | "<=" | ">" | ">=" | "and" | "or" )expr
| identifier "(" (expr
(","expr
)*)? ")" | "[" (expr
(","expr
)*)? "]" | "("expr
")"
Python statement
stmt ::=simple_stmt
NEWLINE | "if"expr
":"suite
else_branch
| "while"expr
":"loop_body
| "for" identifier "in"expr
":"loop_body
else_branch ::= /* nothing */ | "else:"suite
| "elif"expr
":"suite
else_branch
suite ::=simple_stmt
NEWLINE | NEWLINE INDENTstmt
stmt
* DEDENT simple_stmt ::=expr
| "return"expr
| identifier "="expr
| identifier "["expr
"]" "="expr
| "break" | "#@" "label" identifier | "#@" ( "assert" | "assume" | "check" )term
loop_body ::=simple_stmt
NEWLINE | NEWLINE INDENTloop_annot
*stmt
stmt
* DEDENT loop_annot ::= "#@" "invariant"term
NEWLINE | "#@" "variant"term
(","term
)* NEWLINE
Logic declaration
logic-declaration ::= "#@" "function" identifier "("params
")" NEWLINE | "#@" "predicate" identifier "("params
")" NEWLINE
Note that logic functions and predicates cannot be given definitions.
Yet, they can be axiomatized, using toplevel assume
statements.
Logical term
term ::= identifier | integer-literal | "None" | "True" | "False" | "("term
")" |term
"["term
"]" |term
"["term
"<-"term
"]" | "not"term
| "old" "("term
")" | "at" "("term
"," identifier ")" | "-"term
|term
( "->" | "<->" | "or" | "and" )term
|term
( "==" | "!=" | "<" | "<=" | ">" | ">=" )term
|term
( "+" | "-" | "*" | "//" | "% )term
| "if"term
"then"term
"elseterm
| "let" identifier "="term
"in"term
| ( "forall" | "exists" ) identifier ("," identifier)* "."term
| identifier "(" (term
(","term
)*)? ")"
8.2.2. Built-in functions and predicates¶
Python code
len(l)
, the length of listl
int(input())
, reads an integer from standard inputrange(l, u)
, returns the list of integers froml
inclusive tou
exclusive <br> (in particular,for x in range(l, u):
is supported)randint(l, u)
, returns a pseudo-random integer in the rangel
tou
inclusive
Logic
len(l)
, the length of listl
occurrence(v, l)
, the number of occurrences of the valuev
in listl
8.2.3. Limitations¶
Python lists are modeled as arrays, whose size cannot be modified.