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