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_declarationc_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_typeidentifier "("params? ")"spec*blockreturn_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
| identifier assignop 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 "else term
| "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_MAXinclusive.
Logic
int length(int[] a), the length of arrayaint occurrence(int v, int[] a), the number of occurrences of the valuevin 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_declarationpy_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 INDENT spec* stmt* DEDENT
params ::= identifier ("," identifier)*
Function specification
spec ::= "#@" "requires"termNEWLINE | "#@" "ensures"termNEWLINE | "#@" "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_stmtNEWLINE | "if"expr":"suiteelse_branch| "while"expr":"loop_body| "for" identifier "in"expr":"loop_bodyelse_branch ::= /* nothing */ | "else:"suite| "elif"expr":"suiteelse_branchsuite ::=simple_stmtNEWLINE | NEWLINE INDENTstmtstmt* DEDENT simple_stmt ::=expr| "return"expr| identifier "="expr| identifier "["expr"]" "="expr| "break" | "#@" "label" identifier | "#@" ( "assert" | "assume" | "check" )termloop_body ::=simple_stmtNEWLINE | NEWLINE INDENTloop_annot*stmtstmt* DEDENT loop_annot ::= "#@" "invariant"termNEWLINE | "#@" "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 "else term
| "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 listlint(input()), reads an integer from standard inputrange(l, u), returns the list of integers fromlinclusive touexclusive <br> (in particular,for x in range(l, u):is supported)randint(l, u), returns a pseudo-random integer in the rangeltouinclusive
Logic
len(l), the length of listloccurrence(v, l), the number of occurrences of the valuevin listl
8.2.3. Limitations¶
Python lists are modeled as arrays, whose size cannot be modified.