CBMC
std_expr.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module:
4 
5 Author: Daniel Kroening, kroening@kroening.com
6 
7 \*******************************************************************/
8 
9 #include "std_expr.h"
10 
11 #include "namespace.h"
12 #include "pointer_expr.h"
13 #include "range.h"
14 
15 #include <map>
16 
18 {
19  const std::string val=id2string(get_value());
20  return val.find_first_not_of('0')==std::string::npos;
21 }
22 
23 void constant_exprt::check(const exprt &expr, const validation_modet vm)
24 {
25  DATA_CHECK(
26  vm, !expr.has_operands(), "constant expression must not have operands");
27 
28  DATA_CHECK(
29  vm,
31  !id2string(to_constant_expr(expr).get_value()).empty(),
32  "bitvector constant must have a non-empty value");
33 
34  DATA_CHECK(
35  vm,
39  .find_first_not_of("0123456789ABCDEF") == std::string::npos,
40  "negative bitvector constant must use two's complement");
41 
42  DATA_CHECK(
43  vm,
45  to_constant_expr(expr).get_value() == ID_0 ||
46  id2string(to_constant_expr(expr).get_value())[0] != '0',
47  "bitvector constant must not have leading zeros");
48 }
49 
51 {
52  if(op.empty())
53  return false_exprt();
54  else if(op.size()==1)
55  return op.front();
56  else
57  {
58  return or_exprt(exprt::operandst(op));
59  }
60 }
61 
63 {
64  if(op.empty())
65  return true_exprt();
66  else if(op.size()==1)
67  return op.front();
68  else
69  {
70  return and_exprt(exprt::operandst(op));
71  }
72 }
73 
74 // Implementation of struct_exprt::component for const / non const overloads.
75 template <typename T>
76 auto component(T &struct_expr, const irep_idt &name, const namespacet &ns)
77  -> decltype(struct_expr.op0())
78 {
79  static_assert(
80  std::is_base_of<struct_exprt, T>::value, "T must be a struct_exprt.");
81  const auto index =
82  to_struct_type(ns.follow(struct_expr.type())).component_number(name);
84  index < struct_expr.operands().size(),
85  "component matching index should exist");
86  return struct_expr.operands()[index];
87 }
88 
91 {
92  return ::component(*this, name, ns);
93 }
94 
96 const exprt &
97 struct_exprt::component(const irep_idt &name, const namespacet &ns) const
98 {
99  return ::component(*this, name, ns);
100 }
101 
110  const exprt &expr,
111  const namespacet &ns,
112  const validation_modet vm)
113 {
114  check(expr, vm);
115 
116  const auto &member_expr = to_member_expr(expr);
117 
118  const typet &compound_type = ns.follow(member_expr.compound().type());
119  const auto *struct_union_type =
120  type_try_dynamic_cast<struct_union_typet>(compound_type);
121  DATA_CHECK(
122  vm,
123  struct_union_type != nullptr,
124  "member must address a struct, union or compatible type");
125 
126  const auto &component =
127  struct_union_type->get_component(member_expr.get_component_name());
128 
129  DATA_CHECK(
130  vm,
131  component.is_not_nil(),
132  "member component '" + id2string(member_expr.get_component_name()) +
133  "' must exist on addressed type");
134 
135  DATA_CHECK(
136  vm,
137  component.type() == member_expr.type(),
138  "member expression's type must match the addressed struct or union "
139  "component");
140 }
141 
142 void let_exprt::validate(const exprt &expr, const validation_modet vm)
143 {
144  check(expr, vm);
145 
146  const auto &let_expr = to_let_expr(expr);
147 
148  DATA_CHECK(
149  vm,
150  let_expr.values().size() == let_expr.variables().size(),
151  "number of variables must match number of values");
152 
153  for(const auto &binding :
154  make_range(let_expr.variables()).zip(let_expr.values()))
155  {
156  DATA_CHECK(
157  vm,
158  binding.first.id() == ID_symbol,
159  "let binding symbols must be symbols");
160 
161  DATA_CHECK(
162  vm,
163  binding.first.type() == binding.second.type(),
164  "let bindings must be type consistent");
165  }
166 }
167 
169  const std::map<irep_idt, exprt> &substitutions,
170  exprt src)
171 {
172  if(src.id() == ID_symbol)
173  {
174  auto s_it = substitutions.find(to_symbol_expr(src).get_identifier());
175  if(s_it == substitutions.end())
176  return {};
177  else
178  return s_it->second;
179  }
180  else if(
181  src.id() == ID_forall || src.id() == ID_exists || src.id() == ID_lambda)
182  {
183  const auto &binding_expr = to_binding_expr(src);
184 
185  // bindings may be nested,
186  // which may hide some of our substitutions
187  auto new_substitutions = substitutions;
188  for(const auto &variable : binding_expr.variables())
189  new_substitutions.erase(variable.get_identifier());
190 
191  auto op_result =
192  substitute_symbols_rec(new_substitutions, binding_expr.where());
193  if(op_result.has_value())
194  return binding_exprt(
195  src.id(),
196  binding_expr.variables(),
197  op_result.value(),
198  binding_expr.type());
199  else
200  return {};
201  }
202  else if(src.id() == ID_let)
203  {
204  auto new_let_expr = to_let_expr(src); // copy
205  const auto &binding_expr = to_let_expr(src).binding();
206 
207  // bindings may be nested,
208  // which may hide some of our substitutions
209  auto new_substitutions = substitutions;
210  for(const auto &variable : binding_expr.variables())
211  new_substitutions.erase(variable.get_identifier());
212 
213  bool op_changed = false;
214 
215  for(auto &op : new_let_expr.values())
216  {
217  auto op_result = substitute_symbols_rec(new_substitutions, op);
218 
219  if(op_result.has_value())
220  {
221  op = op_result.value();
222  op_changed = true;
223  }
224  }
225 
226  auto op_result =
227  substitute_symbols_rec(new_substitutions, binding_expr.where());
228  if(op_result.has_value())
229  {
230  new_let_expr.where() = op_result.value();
231  op_changed = true;
232  }
233 
234  if(op_changed)
235  return std::move(new_let_expr);
236  else
237  return {};
238  }
239 
240  if(!src.has_operands())
241  return {};
242 
243  bool op_changed = false;
244 
245  for(auto &op : src.operands())
246  {
247  auto op_result = substitute_symbols_rec(substitutions, op);
248 
249  if(op_result.has_value())
250  {
251  op = op_result.value();
252  op_changed = true;
253  }
254  }
255 
256  if(op_changed)
257  return src;
258  else
259  return {};
260 }
261 
263 {
264  // number of values must match the number of bound variables
265  auto &variables = this->variables();
266  PRECONDITION(variables.size() == values.size());
267 
268  std::map<symbol_exprt, exprt> value_map;
269 
270  for(std::size_t i = 0; i < variables.size(); i++)
271  {
272  // types must match
273  PRECONDITION(variables[i].type() == values[i].type());
274  value_map[variables[i]] = values[i];
275  }
276 
277  // build a substitution map
278  std::map<irep_idt, exprt> substitutions;
279 
280  for(std::size_t i = 0; i < variables.size(); i++)
281  substitutions[variables[i].get_identifier()] = values[i];
282 
283  // now recurse downwards and substitute in 'where'
284  auto substitute_result = substitute_symbols_rec(substitutions, where());
285 
286  if(substitute_result.has_value())
287  return substitute_result.value();
288  else
289  return where(); // trivial case, variables not used
290 }
291 
292 exprt binding_exprt::instantiate(const variablest &new_variables) const
293 {
294  std::vector<exprt> values;
295  values.reserve(new_variables.size());
296  for(const auto &new_variable : new_variables)
297  values.push_back(new_variable);
298  return instantiate(values);
299 }
dstringt
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition: dstring.h:36
DATA_CHECK
#define DATA_CHECK(vm, condition, message)
This macro takes a condition which denotes a well-formedness criterion on goto programs,...
Definition: validate.h:22
conjunction
exprt conjunction(const exprt::operandst &op)
1) generates a conjunction for two or more operands 2) for one operand, returns the operand 3) return...
Definition: std_expr.cpp:62
to_struct_type
const struct_typet & to_struct_type(const typet &type)
Cast a typet to a struct_typet.
Definition: std_types.h:308
typet
The type of an expression, extends irept.
Definition: type.h:28
and_exprt
Boolean AND.
Definition: std_expr.h:2070
exprt
Base class for all expressions.
Definition: expr.h:55
component
auto component(T &struct_expr, const irep_idt &name, const namespacet &ns) -> decltype(struct_expr.op0())
Definition: std_expr.cpp:76
let_exprt::validate
static void validate(const exprt &, validation_modet)
Definition: std_expr.cpp:142
constant_exprt::check
static void check(const exprt &expr, const validation_modet vm=validation_modet::INVARIANT)
Definition: std_expr.cpp:23
namespace.h
struct_union_typet::component_number
std::size_t component_number(const irep_idt &component_name) const
Return the sequence number of the component with given name.
Definition: std_types.cpp:46
can_cast_type< pointer_typet >
bool can_cast_type< pointer_typet >(const typet &type)
Check whether a reference to a typet is a pointer_typet.
Definition: pointer_expr.h:66
binding_exprt::variables
variablest & variables()
Definition: std_expr.h:3073
substitute_symbols_rec
static optionalt< exprt > substitute_symbols_rec(const std::map< irep_idt, exprt > &substitutions, exprt src)
Definition: std_expr.cpp:168
namespacet
A namespacet is essentially one or two symbol tables bound together, to allow for symbol lookups in t...
Definition: namespace.h:90
exprt::type
typet & type()
Return the type of the expression.
Definition: expr.h:84
disjunction
exprt disjunction(const exprt::operandst &op)
1) generates a disjunction for two or more operands 2) for one operand, returns the operand 3) return...
Definition: std_expr.cpp:50
or_exprt
Boolean OR.
Definition: std_expr.h:2178
DATA_INVARIANT
#define DATA_INVARIANT(CONDITION, REASON)
This condition should be used to document that assumptions that are made on goto_functions,...
Definition: invariant.h:510
exprt::has_operands
bool has_operands() const
Return true if there is at least one operand.
Definition: expr.h:91
id2string
const std::string & id2string(const irep_idt &d)
Definition: irep.h:47
member_exprt::check
static void check(const exprt &expr, const validation_modet vm=validation_modet::INVARIANT)
Definition: std_expr.h:2853
get_identifier
static optionalt< smt_termt > get_identifier(const exprt &expr, const std::unordered_map< exprt, smt_identifier_termt, irep_hash > &expression_handle_identifiers, const std::unordered_map< exprt, smt_identifier_termt, irep_hash > &expression_identifiers)
Definition: smt2_incremental_decision_procedure.cpp:328
PRECONDITION
#define PRECONDITION(CONDITION)
Definition: invariant.h:463
to_let_expr
const let_exprt & to_let_expr(const exprt &expr)
Cast an exprt to a let_exprt.
Definition: std_expr.h:3266
pointer_expr.h
binding_exprt::variablest
std::vector< symbol_exprt > variablest
Definition: std_expr.h:3054
to_symbol_expr
const symbol_exprt & to_symbol_expr(const exprt &expr)
Cast an exprt to a symbol_exprt.
Definition: std_expr.h:222
member_exprt::validate
static void validate(const exprt &expr, const namespacet &ns, const validation_modet vm=validation_modet::INVARIANT)
Check that the member expression has the right number of operands, refers to a component that exists ...
Definition: std_expr.cpp:109
validation_modet
validation_modet
Definition: validation_mode.h:12
irept::id
const irep_idt & id() const
Definition: irep.h:396
binary_exprt::check
static void check(const exprt &expr, const validation_modet vm=validation_modet::INVARIANT)
Definition: std_expr.h:595
range.h
binding_exprt
A base class for variable bindings (quantifiers, let, lambda)
Definition: std_expr.h:3051
exprt::operandst
std::vector< exprt > operandst
Definition: expr.h:58
false_exprt
The Boolean constant false.
Definition: std_expr.h:3016
optionalt
nonstd::optional< T > optionalt
Definition: optional.h:35
binding_exprt::where
exprt & where()
Definition: std_expr.h:3083
namespace_baset::follow
const typet & follow(const typet &) const
Resolve type symbol to the type it points to.
Definition: namespace.cpp:49
constant_exprt::value_is_zero_string
bool value_is_zero_string() const
Definition: std_expr.cpp:17
binding_exprt::instantiate
exprt instantiate(const exprt::operandst &) const
substitute free occurrences of the variables in where() by the given values
Definition: std_expr.cpp:262
to_member_expr
const member_exprt & to_member_expr(const exprt &expr)
Cast an exprt to a member_exprt.
Definition: std_expr.h:2886
struct_exprt::component
exprt & component(const irep_idt &name, const namespacet &ns)
Definition: std_expr.cpp:90
exprt::operands
operandst & operands()
Definition: expr.h:94
true_exprt
The Boolean constant true.
Definition: std_expr.h:3007
to_binding_expr
const binding_exprt & to_binding_expr(const exprt &expr)
Cast an exprt to a binding_exprt.
Definition: std_expr.h:3114
std_expr.h
let_exprt::binding
binding_exprt & binding()
Definition: std_expr.h:3170
constant_exprt::get_value
const irep_idt & get_value() const
Definition: std_expr.h:2950
make_range
ranget< iteratort > make_range(iteratort begin, iteratort end)
Definition: range.h:524
can_cast_type< bitvector_typet >
bool can_cast_type< bitvector_typet >(const typet &type)
Check whether a reference to a typet is a bitvector_typet.
Definition: std_types.h:899
to_constant_expr
const constant_exprt & to_constant_expr(const exprt &expr)
Cast an exprt to a constant_exprt.
Definition: std_expr.h:2992