Skip to content

Commit ce56308

Browse files
committed
Expand expr2statement_list
Adds support for the conversion of boolean expressions. Note that this will hardly have any effect on the output of CBMC and in the current state only be used by projects which rely on it. There are several STL-specific simplification routines integrated in the conversion, e.g. changing the conversion order of operands to avoid unnecessary nesting.
1 parent ae6dd2f commit ce56308

File tree

2 files changed

+371
-6
lines changed

2 files changed

+371
-6
lines changed

src/statement-list/converters/expr2statement_list.cpp

Lines changed: 260 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,52 @@ Author: Matthias Weiss, [email protected]
1010

1111
#include <ansi-c/expr2c.h>
1212

13+
#include <util/std_expr.h>
14+
#include <util/suffix.h>
15+
#include <util/symbol_table.h>
16+
17+
#include <algorithm>
18+
19+
/// STL code for an AND instruction.
20+
#define AND 'A'
21+
22+
/// STL code for an OR instruction.
23+
#define OR 'O'
24+
25+
/// STL code for a XOR instruction.
26+
#define XOR 'X'
27+
28+
/// Postfix for any negated boolean instruction.
29+
#define NOT_POSTFIX 'N'
30+
31+
/// STL code for a NOT instruction.
32+
#define NOT "NOT"
33+
34+
/// Separator between the instruction code and it's operand.
35+
#define OPERAND_SEPARATOR ' '
36+
37+
/// Separator between the end of an instruction and the next one.
38+
#define LINE_SEPARATOR ";\n"
39+
40+
/// Separator for the end of an instruction that introduces a new layer of
41+
/// nesting.
42+
#define NESTING_OPEN_LINE_SEPARATOR "(;\n"
43+
44+
/// Separator for the end of an instruction that closes a nesting layer. Also
45+
/// known as the NESTING CLOSED instruction.
46+
#define NESTING_CLOSED_LINE_SEPARATOR ");\n"
47+
48+
/// Prefix for the reference to any variable.
49+
#define REFERENCE_FLAG '#'
50+
51+
/// CBMC-internal separator for variable scopes.
52+
#define SCOPE_SEPARATOR "::"
53+
1354
std::string expr2stl(const exprt &expr, const namespacet &ns)
1455
{
15-
// TODO: Implement expr2stl.
16-
// Expand this section so that it is able to properly convert from
17-
// CBMC expressions to STL code.
18-
return expr2c(expr, ns);
56+
expr2stlt expr2stl{ns};
57+
58+
return expr2stl.convert(expr);
1959
}
2060

2161
std::string type2stl(const typet &type, const namespacet &ns)
@@ -25,3 +65,219 @@ std::string type2stl(const typet &type, const namespacet &ns)
2565
// CBMC types to STL code.
2666
return type2c(type, ns);
2767
}
68+
69+
expr2stlt::expr2stlt(const namespacet &ns)
70+
: inside_bit_string(false), is_reference(false), ns(ns)
71+
{
72+
}
73+
74+
std::string expr2stlt::convert(const exprt &expr)
75+
{
76+
if(ID_and == expr.id())
77+
convert_and(expr);
78+
else if(ID_or == expr.id())
79+
convert_or(expr);
80+
else if(ID_xor == expr.id() || ID_notequal == expr.id())
81+
convert_xor(expr);
82+
else if(ID_equal == expr.id())
83+
convert_equal(expr);
84+
else if(ID_symbol == expr.id())
85+
convert_symbol(expr);
86+
else if(ID_not == expr.id())
87+
convert_not(expr);
88+
else // TODO: support more instructions in expr2stl.
89+
return expr2c(expr, ns);
90+
91+
return result.str();
92+
}
93+
94+
void expr2stlt::convert_and(const exprt &expr)
95+
{
96+
if(inside_bit_string)
97+
convert_multiary_bool(expr.operands(), AND);
98+
else
99+
{
100+
std::vector<exprt> operands = expr.operands();
101+
convert_first_non_trivial_operand(operands);
102+
convert_multiary_bool(operands, AND);
103+
}
104+
}
105+
106+
void expr2stlt::convert_or(const exprt &expr)
107+
{
108+
if(inside_bit_string)
109+
convert_multiary_bool(expr.operands(), OR);
110+
else
111+
{
112+
std::vector<exprt> operands = expr.operands();
113+
convert_first_non_trivial_operand(operands);
114+
convert_multiary_bool(operands, OR);
115+
}
116+
}
117+
118+
void expr2stlt::convert_xor(const exprt &expr)
119+
{
120+
if(inside_bit_string)
121+
convert_multiary_bool(expr.operands(), XOR);
122+
else
123+
{
124+
std::vector<exprt> operands = expr.operands();
125+
convert_first_non_trivial_operand(operands);
126+
convert_multiary_bool(operands, XOR);
127+
}
128+
}
129+
130+
void expr2stlt::convert_equal(const exprt &expr)
131+
{
132+
std::vector<exprt> operands =
133+
instrument_equal_operands(expr.op0(), expr.op1());
134+
if(inside_bit_string)
135+
convert_multiary_bool(operands, XOR);
136+
else
137+
{
138+
convert_first_non_trivial_operand(operands);
139+
convert_multiary_bool(operands, XOR);
140+
}
141+
}
142+
143+
void expr2stlt::convert_not(const exprt &expr)
144+
{
145+
// If a NOT expression is being handled here it must always mark the
146+
// beginning of a new bit string.
147+
PRECONDITION(!inside_bit_string);
148+
149+
if(ID_symbol == expr.op0().id())
150+
{
151+
// Use AN to load the symbol.
152+
is_reference = true;
153+
result << AND << NOT_POSTFIX << OPERAND_SEPARATOR;
154+
convert(expr.op0());
155+
result << LINE_SEPARATOR;
156+
}
157+
else
158+
{
159+
// Use NOT to negate the RLO after the wrapped expression was loaded.
160+
convert(expr.op0());
161+
result << NOT LINE_SEPARATOR;
162+
}
163+
}
164+
165+
void expr2stlt::convert_symbol(const exprt &expr)
166+
{
167+
if(is_reference)
168+
{
169+
result << REFERENCE_FLAG;
170+
is_reference = false;
171+
}
172+
result << id2string(id_shorthand(expr.get(ID_identifier)));
173+
}
174+
175+
void expr2stlt::convert_multiary_bool(
176+
const std::vector<exprt> &operands,
177+
const char operation)
178+
{
179+
for(const exprt &op : operands)
180+
{
181+
if(op.id() == ID_not)
182+
{
183+
result << operation << NOT_POSTFIX;
184+
convert_bool_operand(op.op0());
185+
}
186+
else
187+
{
188+
result << operation;
189+
convert_bool_operand(op);
190+
}
191+
}
192+
}
193+
194+
void expr2stlt::convert_bool_operand(const exprt &op)
195+
{
196+
if(op.id() == ID_symbol)
197+
{
198+
is_reference = true;
199+
result << OPERAND_SEPARATOR;
200+
convert(op);
201+
result << LINE_SEPARATOR;
202+
}
203+
else
204+
{
205+
inside_bit_string = false;
206+
result << NESTING_OPEN_LINE_SEPARATOR;
207+
convert(op);
208+
result << NESTING_CLOSED_LINE_SEPARATOR;
209+
}
210+
}
211+
212+
void expr2stlt::convert_first_non_trivial_operand(std::vector<exprt> &operands)
213+
{
214+
exprt non_trivial_op;
215+
for(auto it(begin(operands)); it != end(operands); ++it)
216+
{
217+
if(
218+
(ID_symbol == it->id()) ||
219+
(ID_not == it->id() && ID_symbol == it->op0().id()))
220+
continue;
221+
else
222+
{
223+
non_trivial_op = *it;
224+
operands.erase(it);
225+
break;
226+
}
227+
}
228+
// Important for some scenarios: Convert complex op first, set bit string
229+
// flag to true afterwards.
230+
if(non_trivial_op.is_not_nil())
231+
convert(non_trivial_op);
232+
233+
inside_bit_string = true;
234+
}
235+
236+
std::vector<exprt>
237+
expr2stlt::instrument_equal_operands(const exprt &lhs, const exprt &rhs)
238+
{
239+
std::vector<exprt> result;
240+
if(ID_not != lhs.id() && ID_not != rhs.id())
241+
{
242+
// lhs == rhs is equivalent to X lhs; XN rhs;
243+
result.push_back(lhs);
244+
result.push_back(not_exprt{rhs});
245+
}
246+
else if(ID_not != lhs.id() && ID_not == rhs.id())
247+
{
248+
// lhs == !rhs is equivalent to X lhs; X rhs;
249+
result.push_back(lhs);
250+
result.push_back(rhs.op0());
251+
}
252+
else if(ID_not == lhs.id() && ID_not != rhs.id())
253+
{
254+
// !lhs == rhs is equivalent to X lhs; X rhs;
255+
result.push_back(lhs.op0());
256+
result.push_back(rhs);
257+
}
258+
else // ID_not == lhs.id() && ID_not == rhs.id()
259+
{
260+
// !lhs == !rhs is equivalent to X lhs; XN rhs;
261+
result.push_back(lhs.op0());
262+
result.push_back(rhs);
263+
}
264+
return result;
265+
}
266+
267+
irep_idt expr2stlt::id_shorthand(const irep_idt &identifier)
268+
{
269+
const symbolt *symbol;
270+
271+
if(
272+
!ns.lookup(identifier, symbol) && !symbol->base_name.empty() &&
273+
has_suffix(id2string(identifier), id2string(symbol->base_name)))
274+
return symbol->base_name;
275+
276+
std::string sh = id2string(identifier);
277+
278+
std::string::size_type pos = sh.rfind(SCOPE_SEPARATOR);
279+
if(pos != std::string::npos)
280+
sh.erase(0, pos + 2);
281+
282+
return sh;
283+
}

0 commit comments

Comments
 (0)