Skip to content

Commit 27d6ec8

Browse files
author
Daniel Kroening
committed
added format() for exprt and typet
1 parent a7cc2a0 commit 27d6ec8

File tree

5 files changed

+284
-9
lines changed

5 files changed

+284
-9
lines changed

src/util/expr.cpp

Lines changed: 187 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,21 @@ Author: Daniel Kroening, kroening@kroening.com
99
/// \file
1010
/// Expression Representation
1111

12+
#include "arith_tools.h"
1213
#include "expr.h"
13-
#include <cassert>
14-
#include <stack>
15-
#include "string2int.h"
16-
#include "mp_arith.h"
14+
#include "expr_iterator.h"
1715
#include "fixedbv.h"
1816
#include "ieee_float.h"
1917
#include "invariant.h"
20-
#include "expr_iterator.h"
18+
#include "mp_arith.h"
2119
#include "rational.h"
2220
#include "rational_tools.h"
23-
#include "arith_tools.h"
2421
#include "std_expr.h"
22+
#include "string2int.h"
23+
24+
#include <cassert>
25+
#include <stack>
26+
#include <ostream>
2527

2628
void exprt::move_to_operands(exprt &expr)
2729
{
@@ -535,3 +537,182 @@ const_unique_depth_iteratort exprt::unique_depth_cbegin() const
535537
{ return const_unique_depth_iteratort(*this); }
536538
const_unique_depth_iteratort exprt::unique_depth_cend() const
537539
{ return const_unique_depth_iteratort(); }
540+
541+
/// We use the precendences that most readers expect
542+
/// (i.e., the ones you learn in primary school),
543+
/// and stay clear of the surprising ones that C has.
544+
static bool bracket_subexpression(const exprt &sub_expr, const exprt &expr)
545+
{
546+
// no need for parentheses whenever the subexpression
547+
// doesn't have operands
548+
if(!sub_expr.has_operands())
549+
return false;
550+
551+
// * and / bind stronger than + and -
552+
if(
553+
(sub_expr.id() == ID_mult || sub_expr.id() == ID_div) &&
554+
(expr.id() == ID_plus || expr.id() == ID_minus))
555+
return false;
556+
557+
// ==, !=, <, <=, >, >= bind stronger than && and ||
558+
if(
559+
(sub_expr.id() == ID_equal || sub_expr.id() == ID_notequal ||
560+
sub_expr.id() == ID_lt || sub_expr.id() == ID_gt ||
561+
sub_expr.id() == ID_le || sub_expr.id() == ID_ge) &&
562+
(expr.id() == ID_and || expr.id() == ID_or))
563+
return false;
564+
565+
return true;
566+
}
567+
568+
/// This formats turns a multi-ary expression,
569+
/// adding parentheses where indicated by the precedence.
570+
static std::ostream &format_rec(std::ostream &os, const multi_ary_exprt &src)
571+
{
572+
bool first = true;
573+
574+
for(const auto &op : src.operands())
575+
{
576+
if(first)
577+
first = false;
578+
else
579+
os << ' ' << src.id() << ' ';
580+
581+
const bool need_parentheses = bracket_subexpression(op, src);
582+
583+
if(need_parentheses)
584+
os << '(';
585+
586+
os << format(op);
587+
588+
if(need_parentheses)
589+
os << ')';
590+
}
591+
592+
return os;
593+
}
594+
595+
/// This formats a binary expression
596+
static std::ostream &format_rec(std::ostream &os, const binary_exprt &src)
597+
{
598+
return format_rec(os, to_multi_ary_expr(src));
599+
}
600+
601+
/// This formats a unary expression,
602+
/// adding parentheses very aggressively.
603+
static std::ostream &format_rec(std::ostream &os, const unary_exprt &src)
604+
{
605+
if(src.id() == ID_not)
606+
os << '!';
607+
else if(src.id() == ID_unary_minus)
608+
os << '-';
609+
else
610+
return os << src.pretty();
611+
612+
if(src.op0().has_operands())
613+
return os << '(' << format(src.op0()) << ')';
614+
else
615+
return os << format(src.op0());
616+
}
617+
618+
static std::ostream &format_rec(std::ostream &os, const constant_exprt &src)
619+
{
620+
auto type = src.type().id();
621+
622+
if(type == ID_bool)
623+
{
624+
if(src.is_true())
625+
return os << "true";
626+
else if(src.is_false())
627+
return os << "false";
628+
else
629+
return os << src.pretty();
630+
}
631+
else if(type == ID_unsignedbv || type == ID_signedbv)
632+
return os << *numeric_cast<mp_integer>(src);
633+
else if(type == ID_integer)
634+
return os << src.get_value();
635+
else if(type == ID_floatbv)
636+
return os << ieee_floatt(src);
637+
else
638+
return os << src.pretty();
639+
}
640+
641+
// The below generates a string in a generic syntax
642+
// that is inspired by C/C++/Java, and is meant for debugging
643+
// purposes.
644+
std::ostream &format_rec(std::ostream &os, const exprt &expr)
645+
{
646+
const auto &id = expr.id();
647+
648+
if(id == ID_plus || id == ID_mult || id == ID_and || id == ID_or)
649+
return format_rec(os, to_multi_ary_expr(expr));
650+
else if(
651+
id == ID_lt || id == ID_gt || id == ID_ge || id == ID_le ||
652+
id == ID_minus || id == ID_implies || id == ID_equal || id == ID_notequal)
653+
return format_rec(os, to_binary_expr(expr));
654+
else if(id == ID_not || id == ID_unary_minus)
655+
return format_rec(os, to_unary_expr(expr));
656+
else if(id == ID_constant)
657+
return format_rec(os, to_constant_expr(expr));
658+
else if(id == ID_typecast)
659+
return os << "cast(" << format(to_typecast_expr(expr).op()) << ", "
660+
<< format(expr.type()) << ')';
661+
else if(id == ID_member)
662+
return os << format(to_member_expr(expr).op()) << '.'
663+
<< to_member_expr(expr).get_component_name();
664+
else if(id == ID_symbol)
665+
return os << to_symbol_expr(expr).get_identifier();
666+
else if(id == ID_forall || id == ID_exists)
667+
return os << id << ' ' << format(to_quantifier_expr(expr).symbol()) << " : "
668+
<< format(to_quantifier_expr(expr).symbol().type()) << " . "
669+
<< format(to_quantifier_expr(expr).where());
670+
else if(id == ID_let)
671+
return os << "LET " << format(to_let_expr(expr).symbol()) << " = "
672+
<< format(to_let_expr(expr).value()) << " IN "
673+
<< format(to_let_expr(expr).where());
674+
else if(id == ID_array || id == ID_struct)
675+
{
676+
os << "{ ";
677+
678+
bool first = true;
679+
680+
for(const auto &op : expr.operands())
681+
{
682+
if(first)
683+
first = false;
684+
else
685+
os << ", ";
686+
687+
os << format(op);
688+
}
689+
690+
return os << '}';
691+
}
692+
else if(id == ID_if)
693+
{
694+
const auto &if_expr = to_if_expr(expr);
695+
return os << format(if_expr.cond()) << '?' << format(if_expr.true_case())
696+
<< ':' << format(if_expr.false_case());
697+
}
698+
else
699+
{
700+
if(!expr.has_operands())
701+
return os << id;
702+
703+
os << id << '(';
704+
bool first = true;
705+
706+
for(const auto &op : expr.operands())
707+
{
708+
if(first)
709+
first = false;
710+
else
711+
os << ", ";
712+
713+
os << format(op);
714+
}
715+
716+
return os << ')';
717+
}
718+
}

src/util/expr.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,12 @@ Author: Daniel Kroening, kroening@kroening.com
66
77
\*******************************************************************/
88

9-
109
#ifndef CPROVER_UTIL_EXPR_H
1110
#define CPROVER_UTIL_EXPR_H
1211

13-
#include <functional>
1412
#include "type.h"
1513

14+
#include <functional>
1615
#include <list>
1716

1817
#define forall_operands(it, expr) \
@@ -164,6 +163,10 @@ class exprt:public irept
164163
const_unique_depth_iteratort unique_depth_cend() const;
165164
};
166165

166+
//! Formats an expression in a generic syntax
167+
//! that is inspired by C/C++/Java, and is meant for debugging
168+
std::ostream &format_rec(std::ostream &, const exprt &);
169+
167170
class expr_visitort
168171
{
169172
public:

src/util/format.h

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*******************************************************************\
2+
3+
Module:
4+
5+
Author: Daniel Kroening, kroening@kroening.com
6+
7+
\*******************************************************************/
8+
9+
#ifndef CPROVER_UTIL_FORMAT_H
10+
#define CPROVER_UTIL_FORMAT_H
11+
12+
#include <iosfwd>
13+
14+
//! The below enables convenient syntax for feeding
15+
//! objects into streams, via stream << format(o)
16+
template <typename T>
17+
class format_containert
18+
{
19+
public:
20+
explicit format_containert(const T &_o) : o(_o)
21+
{
22+
}
23+
24+
const T &o;
25+
};
26+
27+
template <typename T>
28+
static inline std::ostream &
29+
operator<<(std::ostream &os, const format_containert<T> &f)
30+
{
31+
return format_rec(os, f.o);
32+
}
33+
34+
template <typename T>
35+
static inline format_containert<T> format(const T &o)
36+
{
37+
return format_containert<T>(o);
38+
}
39+
40+
#endif // CPROVER_UTIL_FORMAT_H

src/util/type.cpp

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ Author: Daniel Kroening, kroening@kroening.com
1010
#include "std_types.h"
1111
#include "namespace.h"
1212

13+
#include <ostream>
14+
1315
void typet::copy_to_subtypes(const typet &type)
1416
{
1517
subtypes().push_back(type);
@@ -106,3 +108,47 @@ bool is_constant_or_has_constant_components(
106108

107109
return false;
108110
}
111+
112+
static std::ostream &format_rec(std::ostream &os, const struct_typet &src)
113+
{
114+
os << "struct"
115+
<< " {";
116+
bool first = true;
117+
118+
for(const auto &c : src.components())
119+
{
120+
if(first)
121+
first = false;
122+
else
123+
os << ',';
124+
125+
os << ' ' << format(c.type()) << ' ' << c.get_name();
126+
}
127+
128+
return os << " }";
129+
}
130+
131+
// The below generates a string in a generic syntax
132+
// that is inspired by C/C++/Java, and is meant for debugging
133+
// purposes.
134+
std::ostream &format_rec(std::ostream &os, const typet &type)
135+
{
136+
const auto &id = type.id();
137+
138+
if(id == ID_pointer)
139+
return os << '*' << format(type.subtype());
140+
else if(id == ID_array)
141+
{
142+
const auto &t = to_array_type(type);
143+
if(t.is_complete())
144+
return os << format(type.subtype()) << '[' << format(t.size()) << ']';
145+
else
146+
return os << format(type.subtype()) << "[]";
147+
}
148+
else if(id == ID_struct)
149+
return format_rec(os, to_struct_type(type));
150+
else if(id == ID_symbol)
151+
return os << "symbol_type " << to_symbol_type(type).get_identifier();
152+
else
153+
return os << id;
154+
}

src/util/type.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ Author: Daniel Kroening, kroening@kroening.com
1010
#ifndef CPROVER_UTIL_TYPE_H
1111
#define CPROVER_UTIL_TYPE_H
1212

13-
#include <util/source_location.h>
13+
#include "format.h"
14+
#include "source_location.h"
1415

1516
#define SUBTYPE_IN_GETSUB
1617
#define SUBTYPES_IN_GETSUB
@@ -115,6 +116,10 @@ class typet:public irept
115116
}
116117
};
117118

119+
//! Formats a type in a generic syntax
120+
//! that is inspired by C/C++/Java, and is meant for debugging
121+
std::ostream &format_rec(std::ostream &, const typet &);
122+
118123
class type_with_subtypet:public typet
119124
{
120125
public:

0 commit comments

Comments
 (0)