CBMC
expr2statement_list.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module: Conversion from Expression or Type to Statement List
4 
5 Author: Matthias Weiss, matthias.weiss@diffblue.com
6 
7 \*******************************************************************/
8 
9 #include "expr2statement_list.h"
10 
11 #include <ansi-c/expr2c.h>
12 
13 #include <util/namespace.h>
14 #include <util/std_expr.h>
15 #include <util/suffix.h>
16 #include <util/symbol.h>
17 
18 #include <cstring>
19 #include <iostream>
20 
22 #define AND 'A'
23 
25 #define OR 'O'
26 
28 #define XOR 'X'
29 
31 #define NOT_POSTFIX 'N'
32 
34 #define NOT "NOT"
35 
37 #define OPERAND_SEPARATOR ' '
38 
40 #define LINE_SEPARATOR ";\n"
41 
44 #define NESTING_OPEN_LINE_SEPARATOR "(;\n"
45 
48 #define NESTING_CLOSED_LINE_SEPARATOR ");\n"
49 
51 #define REFERENCE_FLAG '#'
52 
54 #define SCOPE_SEPARATOR "::"
55 
63 static std::vector<exprt>
64 instrument_equal_operands(const exprt &lhs, const exprt &rhs)
65 {
66  std::vector<exprt> result;
67  if(ID_not != lhs.id() && ID_not != rhs.id())
68  {
69  // lhs == rhs is equivalent to X lhs; XN rhs;
70  result.push_back(lhs);
71  result.push_back(not_exprt{rhs});
72  }
73  else if(ID_not != lhs.id() && ID_not == rhs.id())
74  {
75  // lhs == !rhs is equivalent to X lhs; X rhs;
76  result.push_back(lhs);
77  result.push_back(to_not_expr(rhs).op());
78  }
79  else if(ID_not == lhs.id() && ID_not != rhs.id())
80  {
81  // !lhs == rhs is equivalent to X lhs; X rhs;
82  result.push_back(to_not_expr(lhs).op());
83  result.push_back(rhs);
84  }
85  else // ID_not == lhs.id() && ID_not == rhs.id()
86  {
87  // !lhs == !rhs is equivalent to X lhs; XN rhs;
88  result.push_back(to_not_expr(lhs).op());
89  result.push_back(rhs);
90  }
91  return result;
92 }
93 
98 static bool is_not_bool(const exprt &expr)
99 {
100  if(!expr.is_boolean())
101  return true;
102  for(const exprt &op : expr.operands())
103  if(!op.is_boolean())
104  return true;
105  return false;
106 }
107 
108 std::string expr2stl(const exprt &expr, const namespacet &ns)
109 {
110  expr2stlt expr2stl{ns};
111 
112  return expr2stl.convert(expr);
113 }
114 
115 std::string type2stl(const typet &type, const namespacet &ns)
116 {
117  // TODO: Implement type2stl.
118  // Expand this section so that it is able to properly convert from
119  // CBMC types to STL code.
120  return type2c(type, ns);
121 }
122 
124  : inside_bit_string(false), is_reference(false), ns(ns)
125 {
126 }
127 
128 std::string expr2stlt::convert(const exprt &expr)
129 {
130  // Redirect to expr2c if no boolean expression.
131  if(is_not_bool(expr))
132  return expr2c(expr, ns);
133 
134  if(ID_and == expr.id())
135  convert(to_and_expr(expr));
136  else if(ID_or == expr.id())
137  convert(to_or_expr(expr));
138  else if(ID_xor == expr.id())
139  convert(to_xor_expr(expr));
140  else if(ID_notequal == expr.id())
141  convert(to_notequal_expr(expr));
142  else if(ID_equal == expr.id())
143  convert(to_equal_expr(expr));
144  else if(ID_symbol == expr.id())
145  convert(to_symbol_expr(expr));
146  else if(ID_not == expr.id() && to_not_expr(expr).op().is_boolean())
147  convert(to_not_expr(expr));
148  else // TODO: support more instructions in expr2stl.
149  return expr2c(expr, ns);
150 
151  return result.str();
152 }
153 
154 void expr2stlt::convert(const and_exprt &expr)
155 {
156  std::vector<exprt> operands = expr.operands();
157  convert_multiary_bool(operands, AND);
158 }
159 
160 void expr2stlt::convert(const or_exprt &expr)
161 {
162  std::vector<exprt> operands = expr.operands();
163  convert_multiary_bool(operands, OR);
164 }
165 
166 void expr2stlt::convert(const xor_exprt &expr)
167 {
168  std::vector<exprt> operands = expr.operands();
169  convert_multiary_bool(operands, XOR);
170 }
171 
173 {
174  std::vector<exprt> operands = expr.operands();
175  convert_multiary_bool(operands, XOR);
176 }
177 
179 {
180  std::vector<exprt> operands =
181  instrument_equal_operands(expr.lhs(), expr.rhs());
182  convert_multiary_bool(operands, XOR);
183 }
184 
185 void expr2stlt::convert(const not_exprt &expr)
186 {
187  // If a NOT expression is being handled here it must always mark the
188  // beginning of a new bit string.
190 
191  if(ID_symbol == expr.op().id())
192  {
193  // Use AN to load the symbol.
194  is_reference = true;
196  convert(to_symbol_expr(expr.op()));
198  }
199  else
200  {
201  // Use NOT to negate the RLO after the wrapped expression was loaded.
202  convert(expr.op());
204  }
205 }
206 
208 {
209  if(is_reference)
210  {
212  is_reference = false;
213  }
215 }
216 
218  std::vector<exprt> &operands,
219  const char operation)
220 {
222  convert_multiary_bool_operands(operands, operation);
223  else
224  {
226  convert_multiary_bool_operands(operands, operation);
227  }
228 }
229 
231  const std::vector<exprt> &operands,
232  const char operation)
233 {
234  for(const exprt &op : operands)
235  {
236  if(ID_not == op.id())
237  {
238  result << operation << NOT_POSTFIX;
240  }
241  else
242  {
243  result << operation;
245  }
246  }
247 }
248 
250 {
251  if(op.id() == ID_symbol)
252  {
253  is_reference = true;
255  convert(to_symbol_expr(op));
257  }
258  else
259  {
260  inside_bit_string = false;
262  convert(op);
264  }
265 }
266 
267 void expr2stlt::convert_first_non_trivial_operand(std::vector<exprt> &operands)
268 {
269  exprt non_trivial_op;
270  for(auto it{begin(operands)}; it != end(operands); ++it)
271  {
272  if(
273  (ID_symbol == it->id()) ||
274  (ID_not == it->id() && ID_symbol == to_not_expr(*it).op().id()))
275  continue;
276  else
277  {
278  non_trivial_op = *it;
279  operands.erase(it);
280  break;
281  }
282  }
283  // Important for some scenarios: Convert complex op first, set bit string
284  // flag to true afterwards.
285  if(non_trivial_op.is_not_nil())
286  convert(non_trivial_op);
287 
288  inside_bit_string = true;
289 }
290 
292 {
293  const symbolt *symbol;
294  std::string shorthand = id2string(identifier);
295  if(
296  !ns.lookup(identifier, symbol) && !symbol->base_name.empty() &&
297  has_suffix(shorthand, id2string(symbol->base_name)))
298  return symbol->base_name;
299 
300  const std::string::size_type pos = shorthand.rfind(SCOPE_SEPARATOR);
301  if(pos != std::string::npos)
302  shorthand.erase(0, pos + std::strlen(SCOPE_SEPARATOR));
303 
304  return shorthand;
305 }
Boolean AND.
Definition: std_expr.h:2125
exprt & lhs()
Definition: std_expr.h:668
exprt & rhs()
Definition: std_expr.h:678
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition: dstring.h:38
bool empty() const
Definition: dstring.h:89
Equality.
Definition: std_expr.h:1366
Class for saving the internal state of the conversion process.
void convert_multiary_bool(std::vector< exprt > &operands, const char operation)
Iterates through all the given operands and converts them depending on the operation.
void convert_bool_operand(const exprt &op)
Converts a single boolean operand and introduces an additional nesting layer if needed.
std::string convert(const exprt &expr)
Invokes the conversion process for the given expression and calls itself recursively in the process.
void convert_multiary_bool_operands(const std::vector< exprt > &operands, const char operation)
Iterates through all the given operands and converts them depending on the operation.
void convert_first_non_trivial_operand(std::vector< exprt > &operands)
Iterates through all the given operands in search for the first non-trivial operand (that encloses al...
bool is_reference
Flag to specify if the next symbol to convert is a reference to a variable.
expr2stlt(const namespacet &ns)
Creates a new instance of the converter.
const namespacet & ns
Contains the symbol table of the current program to convert.
irep_idt id_shorthand(const irep_idt &identifier)
Returns the given identifier in a form that is compatible with STL by looking up the symbol or cuttin...
std::stringstream result
Used for saving intermediate results of the conversion process.
bool inside_bit_string
Internal representation of the FC bit in STL.
Base class for all expressions.
Definition: expr.h:56
bool is_boolean() const
Return whether the expression represents a Boolean.
Definition: expr.h:224
operandst & operands()
Definition: expr.h:94
bool is_not_nil() const
Definition: irep.h:372
const irep_idt & id() const
Definition: irep.h:388
A namespacet is essentially one or two symbol tables bound together, to allow for symbol lookups in t...
Definition: namespace.h:94
bool lookup(const irep_idt &name, const symbolt *&symbol) const override
See documentation for namespace_baset::lookup().
Definition: namespace.cpp:148
Boolean negation.
Definition: std_expr.h:2332
Disequality.
Definition: std_expr.h:1425
Boolean OR.
Definition: std_expr.h:2233
Expression to hold a symbol (variable)
Definition: std_expr.h:131
const irep_idt & get_identifier() const
Definition: std_expr.h:160
Symbol table entry.
Definition: symbol.h:28
irep_idt base_name
Base (non-scoped) name.
Definition: symbol.h:46
The type of an expression, extends irept.
Definition: type.h:29
const exprt & op() const
Definition: std_expr.h:391
Boolean XOR.
Definition: std_expr.h:2296
std::string expr2c(const exprt &expr, const namespacet &ns, const expr2c_configurationt &configuration)
Definition: expr2c.cpp:4155
std::string type2c(const typet &type, const namespacet &ns, const expr2c_configurationt &configuration)
Definition: expr2c.cpp:4171
#define NESTING_OPEN_LINE_SEPARATOR
Separator for the end of an instruction that introduces a new layer of nesting.
#define SCOPE_SEPARATOR
CBMC-internal separator for variable scopes.
#define NOT_POSTFIX
Postfix for any negated boolean instruction.
#define REFERENCE_FLAG
Prefix for the reference to any variable.
#define OPERAND_SEPARATOR
Separator between the instruction code and it's operand.
#define OR
STL code for an OR instruction.
#define XOR
STL code for a XOR instruction.
static std::vector< exprt > instrument_equal_operands(const exprt &lhs, const exprt &rhs)
Modifies the parameters of a binary equal expression with the help of its symmetry properties.
std::string expr2stl(const exprt &expr, const namespacet &ns)
Converts a given expression to human-readable STL code.
std::string type2stl(const typet &type, const namespacet &ns)
Converts a given type to human-readable STL code.
#define LINE_SEPARATOR
Separator between the end of an instruction and the next one.
#define NESTING_CLOSED_LINE_SEPARATOR
Separator for the end of an instruction that closes a nesting layer.
#define AND
STL code for an AND instruction.
#define NOT
STL code for a NOT instruction.
static bool is_not_bool(const exprt &expr)
Checks if the expression or one of its parameters is not of type bool.
const std::string & id2string(const irep_idt &d)
Definition: irep.h:44
literalt pos(literalt a)
Definition: literal.h:194
bool is_reference(const typet &type)
Returns true if the type is a reference.
Definition: std_types.cpp:145
#define PRECONDITION(CONDITION)
Definition: invariant.h:463
API to expression classes.
const xor_exprt & to_xor_expr(const exprt &expr)
Cast an exprt to a xor_exprt.
Definition: std_expr.h:2316
const notequal_exprt & to_notequal_expr(const exprt &expr)
Cast an exprt to an notequal_exprt.
Definition: std_expr.h:1450
const or_exprt & to_or_expr(const exprt &expr)
Cast an exprt to a or_exprt.
Definition: std_expr.h:2280
const symbol_exprt & to_symbol_expr(const exprt &expr)
Cast an exprt to a symbol_exprt.
Definition: std_expr.h:272
const and_exprt & to_and_expr(const exprt &expr)
Cast an exprt to a and_exprt.
Definition: std_expr.h:2172
const not_exprt & to_not_expr(const exprt &expr)
Cast an exprt to an not_exprt.
Definition: std_expr.h:2357
const equal_exprt & to_equal_expr(const exprt &expr)
Cast an exprt to an equal_exprt.
Definition: std_expr.h:1407
size_t strlen(const char *s)
Definition: string.c:561
bool has_suffix(const std::string &s, const std::string &suffix)
Definition: suffix.h:17
Symbol table entry.
#define size_type
Definition: unistd.c:347