量词公式,它可以直接支持位向量的标准操作。该语言具有很好的读写交互,并且和C++ API有非常紧密的关系。
因为是一边看一边翻译,所以有些不理解,也就只能字面意义了。文档不够详细,也没有例子,后面有时间搞清楚了我会在进行文档的修改。
原文:http://klee.github.io/docs/kquery/
1 符号
在本文档中,语法用的是扩展巴克斯范式(Extended Backup-Naur Form),例如:
"(" "Eq" [ type ] LHS RHS ")"
除非特殊说明,规则用token,而非character描述,token用空格分开。表达式用斜体。
2 结构
一个KQuery源文件包含一系列的声明,声明语法如下:
kquery={ array-declaration | query-command }
array-declaration用于定义一个位向量数组,以便在后面子序列表达式中使用;
query-command用于定义查询,且所定义的查询在约束求解器中执行。一个查询包含一个约束集(a set of constraints/ assumptions)、一个查询表达式、以及一个可选的表达式和数组以便在查询表达式不可用时加以顶替。
注释用“#”开头,直到行末。
3 表达式和版本标签
表达式常常在约束和查询表达式中共享使用,也为了使输出能够更加简洁和可读,表达式标签就被引入用来和具体的某一
个字表达式绑定,也就是表示该表达式。表达式标签是全局有效,并且使用要求在定义之后。表达式标签定义语法为:
expression = identifier ":" expression
基于同一道理,版本也常常在其中按照同样的方式加以定义和使用。
例子:
(Add w32 N0:(Add w32 1 1) N0) # Four
array const_array[] : w32 -> w8 = [5,6]
(Read w8 0 U0:[0=255] @ const_array) # U0 now refers to an array [255,6]
(Read w8 1 U0) # Read from byte offset 1 of [255,6]
4 Literals(我觉得改意为文字,不确定还是用英语吧)
Identifier(标识):用于指定数组名称,或者表达表达式标签,语法为:
identifier = "[a-zA-Z_][a-zA-Z0-9._]*"
例子(这里终于看到熟悉的东西了):
_foo
arr10_20
为了确保float类型和int类型数据的准确表达,下面两类不能为标示符:
floating-point-type = "fp[0-9]+([.].*)?"
integer-type = "i[0-9]+"
5 Numbers(数)
常量语法如下(常量可以用2、8、10、16进制表示):
number = "true" | "false" | signed-constant
signed-constant = [ "+" | "-" ] ( dec-constant | bin-constant | oct-constant | hex-constant )
dec-constant = "[0-9_]+"
bin-constant = "0b[01_]+"
oct-constant = "0o[0-7_]+"
hex-constant = "0x[0-9a-fA-F_]+"
例子:
false
-10
0b1000_0001 # 129 ,这里的_用作分割符,使表达更易读,没有特殊含义。
6 Types(类型)
类型对于大多数表达式而言就是操作数,并且用位宽度来表示类型,其语法如下:
type = "w[0-9]+"
例子:
w32
7 Arrays(数组的声明)
数组是符号变量(symbolic variable)的基础类型,定义语法为:
array-declaration = "array" name "[" [ size ] "]" ":" domain "->" range "="array-initializer
array-initializer = "symbolic" | "[" number-list "]"
number-list = number | number "," number-list
数组可以初始化为符号,也可以用常量列表进行初始化,对于常量数组,则要求初始化列表和数组大小相匹配。
例子:
array foo[10] : w32 -> w8 = symbolic # A ten element symbolic array
array foo[] : w8 -> w1 = [ true, false, false, true ] # A constant array of four booleans
8 查询命令(没用过,所以不太懂)
查询声明描述了约束求解器运行的查询(Query declarations describe the queries that the constraint solver should run, along with optional additional arguments to specify expressions and arrays for which counterexamples should be provided.)
语法:
query-command = "(" "query" constraint-list query-expression [ eval-expr-list [ eval-array-list ] ] ")"
query-expression = expression
constraint-list = "[" { expression } "]"
eval-expr-list = "[" { expression } "]"
eval-array-list = "[" { identifier } "]"
例子:
(query [] false)
(query [(Eq w8 (Read w8 0 mem) 10)] false [] [ mem ])
查询命令包括一个查询,查询由约束列表和查询表达式组成,同时在存在counterexample时还包括两个可选列表。
constraint-list是一系列假定为真的布尔类型的表达式,虽然没有明确在语言中远期,但是许多求解器要求改系列约束是一致、无矛盾的。
query-expression是用于确定可用性的表达式;
若对于invalid 查询需要counterexample,那么evel-expr-list则是一个表达式列表,其中一个可能的值会被构造;
eval-array-list是一个数组列表。
9 版本定义
版本是指一个数组,其中写入的是一个有序序列值。版本可以是一个标识,该标识用于指向一个数组或者一个带标签的版本;版本也可以是一个写入列表,和其它版本关联。
语法:
version = identifier | "[" [ update-list ] "]" "@" version
update-list = lhs-expression "=" rhs-expression [ "," update-list ]
例子:
array small_array[2] : w32 -> w8 = symbolic # The array we will read from
(Read w8 0 small_array) # No Updates to small_array
(Read w8 1 [1=0xff] @ small_array) # Read from small_array at byte offset 1with update where byte 1 set to decimal 255
10 表达式(Expression)
表达式是强类型的,并且有如下的形式:
"(" EXPR_NAME EXPR_TYPE ... arguments ... ")"
其中EXPR_NAME是表达式名,EXPR_TYPE是表达式类型(可选),后面跟着是一系列参数。
10-1 基础表达式(Primitive expression)
表达式引用:可以之前已定义过的表达式,格式为:
expression = identifier
表达式和版本标签属于两个独立的名称空间。
10-2 常量
常量用数字符号(numeric token)或者类型和加数字符号表示,格式为:
expression = number | "(" type number ")"
若指定的常量没有类型,那么要求结果表达式是well-formed,也就是说他的类型可以再上下文中推导出来;true和false两个常量的类型为w1。
例子:
true
(w32 0)
(Add w32 10 20) # The type for 10 and 20 is inferred to be w32.
10-3 数学操作
包括加Add、减Sub、乘Mul、无符号除法UDiv、无符号取余数URem、有符号除法SDiv、有符号取余数SRem。操作数要有匹配的类型
语法为:
arithmetic-expr-kind = ( "Add" | "Sub" | "Mul" | "UDiv" | "URem" | "SDiv" | "SRem" )
expression = "(" arithmetic-expr-kind type expression expression ")"
10-4 位操作(Bitwise Operation)
Not:其中type可省略,指定则需要匹配expression,取反是按位取反的方式
expression = "(" "Not" [ type ] expression ")"
And,Or,Xor语法
bitwise-expr-kind = ( "And" | "Or" | "Xor" | "Shl" | "LShr" | "AShr" )
expression = "(" bitwise-expr-kind type expression expression ")"
And:按位与
Or:按位或
Xor:按位异或
Shl:expression = "(" "Shl" type X Y ")" 表示把X的位左移Y位,移动空出的位补零
LShr:expression = "(" "LShr" type X Y ")" 右移
AShr:expression = "(" "AShr" type X Y ")" 循环右移,也就是把移除去的位补充到左边
10-5 比较
Eq, Ne, Ult, Ule, Ugt, Uge, Slt, Sle, Sgt, Sge
语法:
comparison-expr-kind = ( "Eq" | "Ne" | "Ult" | "Ule" | "Ugt" | "Uge" | "Slt" | "Sle" | "Sgt" | "Sge")
expression = "(" comparison-expr-kind [ type ] expression expression ")"
10-6 位向量操作
连接操作 Concat: expression = "(" "Concat" [type] msb-expression lsb-expression ")"
截取 Extract: expression = "(" "Extract" type offset-number child-expression ")" type用于指定结果类型,也就隐含指定截取的位数。
截取 ZExt(与上不同在于不足位补零): expression = "(" "ZExt" type child-expression ")"
截取 SExt: expression = "(" "SExt" type input-expression ")" 未定义的位用most-significant bit of input-expression补,不太理解,没有例子。
11-1 读操作
(The Read expression evaluates to the first write in version for which index-expression is equivalent to the index in the write. The type of the expression must match the range of the root array in version, and the type of index-expression must match the domain.)
语法:其中index-expression要和write中的index-expression相对应,
expression = "(" "Read" type index-expression version ")"
11-2 选择操作 Select
选择操作是指根据条件表达式,选择true-expression或者false-expression进行执行。由于expression可以用label来表示,所以可以把label看做函数名,形成更加复杂的表达式。
语法:
expression = "(" "Select" type cond-expression true-expression false-expression ")"
12 Macro expression 宏表达式
有些表达式没有在Expr库中存在,但是可以通过表达式组合的方式进行扩展,这些扩展就以宏Macros的方式完成。解析器会自动解析这些宏定义。
12-1 Neg
语法:
expression = "(" "Neg" [ type ] expression ")"
12-2 ReadLSB, ReadMSB
这两个操作用语简化邻近的数组操作
语法:
expression = "(" "ReadLSB" type index-expression version ")"
expression = "(" "ReadMSB" type index-expression version ")"