10
10
11
11
#include < ansi-c/expr2c.h>
12
12
13
+ #include < util/suffix.h>
14
+ #include < util/symbol_table.h>
15
+
16
+ #include < algorithm>
17
+ #include < iostream>
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
+
54
+ // / Modifies the parameters of a binary equal expression with the help of its
55
+ // / symmetry properties. This function basically converts the operands to
56
+ // / operands of a XOR expression so that the whole expression can be treated as
57
+ // / such. This can reduce complexity in some cases.
58
+ // / \param lhs: Left side of the binary expression.
59
+ // / \param rhs: Right side of the binary expression.
60
+ // / \return: List of instrumented operands.
61
+ static std::vector<exprt>
62
+ instrument_equal_operands (const exprt &lhs, const exprt &rhs)
63
+ {
64
+ std::vector<exprt> result;
65
+ if (ID_not != lhs.id () && ID_not != rhs.id ())
66
+ {
67
+ // lhs == rhs is equivalent to X lhs; XN rhs;
68
+ result.push_back (lhs);
69
+ result.push_back (not_exprt{rhs});
70
+ }
71
+ else if (ID_not != lhs.id () && ID_not == rhs.id ())
72
+ {
73
+ // lhs == !rhs is equivalent to X lhs; X rhs;
74
+ result.push_back (lhs);
75
+ result.push_back (rhs.op0 ());
76
+ }
77
+ else if (ID_not == lhs.id () && ID_not != rhs.id ())
78
+ {
79
+ // !lhs == rhs is equivalent to X lhs; X rhs;
80
+ result.push_back (lhs.op0 ());
81
+ result.push_back (rhs);
82
+ }
83
+ else // ID_not == lhs.id() && ID_not == rhs.id()
84
+ {
85
+ // !lhs == !rhs is equivalent to X lhs; XN rhs;
86
+ result.push_back (lhs.op0 ());
87
+ result.push_back (rhs);
88
+ }
89
+ return result;
90
+ }
91
+
92
+ // / Checks if the expression or one of its parameters is not of type bool.
93
+ // / \param expr: Expression to verify.
94
+ // / \return: True if the expression and its operands are not or only partially
95
+ // / of type bool, false otherwise.
96
+ static bool is_not_bool (const exprt &expr)
97
+ {
98
+ if (!expr.is_boolean ())
99
+ return true ;
100
+ for (const exprt &op : expr.operands ())
101
+ if (!op.is_boolean ())
102
+ return true ;
103
+ return false ;
104
+ }
105
+
13
106
std::string expr2stl (const exprt &expr, const namespacet &ns)
14
107
{
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);
108
+ expr2stlt expr2stl{ns};
109
+
110
+ return expr2stl.convert (expr);
19
111
}
20
112
21
113
std::string type2stl (const typet &type, const namespacet &ns)
@@ -25,3 +117,187 @@ std::string type2stl(const typet &type, const namespacet &ns)
25
117
// CBMC types to STL code.
26
118
return type2c (type, ns);
27
119
}
120
+
121
+ expr2stlt::expr2stlt (const namespacet &ns)
122
+ : inside_bit_string(false ), is_reference(false ), ns(ns)
123
+ {
124
+ }
125
+
126
+ std::string expr2stlt::convert (const exprt &expr)
127
+ {
128
+ // Redirect to expr2c if no boolean expression.
129
+ if (is_not_bool (expr))
130
+ return expr2c (expr, ns);
131
+
132
+ if (ID_and == expr.id ())
133
+ convert (to_and_expr (expr));
134
+ else if (ID_or == expr.id ())
135
+ convert (to_or_expr (expr));
136
+ else if (ID_xor == expr.id ())
137
+ convert (to_xor_expr (expr));
138
+ else if (ID_notequal == expr.id ())
139
+ convert (to_notequal_expr (expr));
140
+ else if (ID_equal == expr.id ())
141
+ convert (to_equal_expr (expr));
142
+ else if (ID_symbol == expr.id ())
143
+ convert (to_symbol_expr (expr));
144
+ else if (ID_not == expr.id () && expr.op0 ().type ().id () == ID_bool)
145
+ convert (to_not_expr (expr));
146
+ else // TODO: support more instructions in expr2stl.
147
+ return expr2c (expr, ns);
148
+
149
+ return result.str ();
150
+ }
151
+
152
+ void expr2stlt::convert (const and_exprt &expr)
153
+ {
154
+ std::vector<exprt> operands = expr.operands ();
155
+ convert_multiary_bool (operands, AND);
156
+ }
157
+
158
+ void expr2stlt::convert (const or_exprt &expr)
159
+ {
160
+ std::vector<exprt> operands = expr.operands ();
161
+ convert_multiary_bool (operands, OR);
162
+ }
163
+
164
+ void expr2stlt::convert (const xor_exprt &expr)
165
+ {
166
+ std::vector<exprt> operands = expr.operands ();
167
+ convert_multiary_bool (operands, XOR);
168
+ }
169
+
170
+ void expr2stlt::convert (const notequal_exprt &expr)
171
+ {
172
+ std::vector<exprt> operands = expr.operands ();
173
+ convert_multiary_bool (operands, XOR);
174
+ }
175
+
176
+ void expr2stlt::convert (const equal_exprt &expr)
177
+ {
178
+ std::vector<exprt> operands =
179
+ instrument_equal_operands (expr.lhs (), expr.rhs ());
180
+ convert_multiary_bool (operands, XOR);
181
+ }
182
+
183
+ void expr2stlt::convert (const not_exprt &expr)
184
+ {
185
+ // If a NOT expression is being handled here it must always mark the
186
+ // beginning of a new bit string.
187
+ PRECONDITION (!inside_bit_string);
188
+
189
+ if (ID_symbol == expr.op ().id ())
190
+ {
191
+ // Use AN to load the symbol.
192
+ is_reference = true ;
193
+ result << AND << NOT_POSTFIX << OPERAND_SEPARATOR;
194
+ convert (to_symbol_expr (expr.op ()));
195
+ result << LINE_SEPARATOR;
196
+ }
197
+ else
198
+ {
199
+ // Use NOT to negate the RLO after the wrapped expression was loaded.
200
+ convert (expr.op ());
201
+ result << NOT LINE_SEPARATOR;
202
+ }
203
+ }
204
+
205
+ void expr2stlt::convert (const symbol_exprt &expr)
206
+ {
207
+ if (is_reference)
208
+ {
209
+ result << REFERENCE_FLAG;
210
+ is_reference = false ;
211
+ }
212
+ result << id2string (id_shorthand (expr.get_identifier ()));
213
+ }
214
+
215
+ void expr2stlt::convert_multiary_bool (
216
+ std::vector<exprt> &operands,
217
+ const char operation)
218
+ {
219
+ if (inside_bit_string)
220
+ convert_multiary_bool_operands (operands, operation);
221
+ else
222
+ {
223
+ convert_first_non_trivial_operand (operands);
224
+ convert_multiary_bool_operands (operands, operation);
225
+ }
226
+ }
227
+
228
+ void expr2stlt::convert_multiary_bool_operands (
229
+ const std::vector<exprt> &operands,
230
+ const char operation)
231
+ {
232
+ for (const exprt &op : operands)
233
+ {
234
+ if (ID_not == op.id ())
235
+ {
236
+ result << operation << NOT_POSTFIX;
237
+ convert_bool_operand (op.op0 ());
238
+ }
239
+ else
240
+ {
241
+ result << operation;
242
+ convert_bool_operand (op);
243
+ }
244
+ }
245
+ }
246
+
247
+ void expr2stlt::convert_bool_operand (const exprt &op)
248
+ {
249
+ if (op.id () == ID_symbol)
250
+ {
251
+ is_reference = true ;
252
+ result << OPERAND_SEPARATOR;
253
+ convert (op);
254
+ result << LINE_SEPARATOR;
255
+ }
256
+ else
257
+ {
258
+ inside_bit_string = false ;
259
+ result << NESTING_OPEN_LINE_SEPARATOR;
260
+ convert (op);
261
+ result << NESTING_CLOSED_LINE_SEPARATOR;
262
+ }
263
+ }
264
+
265
+ void expr2stlt::convert_first_non_trivial_operand (std::vector<exprt> &operands)
266
+ {
267
+ exprt non_trivial_op;
268
+ for (auto it (begin (operands)); it != end (operands); ++it)
269
+ {
270
+ if (
271
+ (ID_symbol == it->id ()) ||
272
+ (ID_not == it->id () && ID_symbol == it->op0 ().id ()))
273
+ continue ;
274
+ else
275
+ {
276
+ non_trivial_op = *it;
277
+ operands.erase (it);
278
+ break ;
279
+ }
280
+ }
281
+ // Important for some scenarios: Convert complex op first, set bit string
282
+ // flag to true afterwards.
283
+ if (non_trivial_op.is_not_nil ())
284
+ convert (non_trivial_op);
285
+
286
+ inside_bit_string = true ;
287
+ }
288
+
289
+ irep_idt expr2stlt::id_shorthand (const irep_idt &identifier)
290
+ {
291
+ const symbolt *symbol;
292
+ std::string shorthand = id2string (identifier);
293
+ if (
294
+ !ns.lookup (identifier, symbol) && !symbol->base_name .empty () &&
295
+ has_suffix (shorthand, id2string (symbol->base_name )))
296
+ return symbol->base_name ;
297
+
298
+ const std::string::size_type pos = shorthand.rfind (SCOPE_SEPARATOR);
299
+ if (pos != std::string::npos)
300
+ shorthand.erase (0 , pos + 2 );
301
+
302
+ return shorthand;
303
+ }
0 commit comments