10
10
11
11
#include < ansi-c/expr2c.h>
12
12
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
+
13
54
std::string expr2stl (const exprt &expr, const namespacet &ns)
14
55
{
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);
19
59
}
20
60
21
61
std::string type2stl (const typet &type, const namespacet &ns)
@@ -25,3 +65,219 @@ std::string type2stl(const typet &type, const namespacet &ns)
25
65
// CBMC types to STL code.
26
66
return type2c (type, ns);
27
67
}
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