Skip to content

Commit 225d1cf

Browse files
author
Daniel Kroening
committed
quantifiers are variable bindings
This commit makes the quantifier base class use the bindings base class. Methods and constructor for the special case of quantifying over one variable are retained.
1 parent 439bf5b commit 225d1cf

File tree

6 files changed

+50
-38
lines changed

6 files changed

+50
-38
lines changed

src/ansi-c/c_typecheck_expr.cpp

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -292,12 +292,12 @@ void c_typecheck_baset::typecheck_expr_main(exprt &expr)
292292
else if(expr.id()==ID_forall ||
293293
expr.id()==ID_exists)
294294
{
295-
// op0 is a declaration,
296-
// op1 the bound expression
295+
// op0 is a tuple with one declaration,
296+
// op1 is the bound expression
297297
assert(expr.operands().size()==2);
298298
expr.type()=bool_typet();
299299

300-
if(expr.op0().get(ID_statement)!=ID_decl)
300+
if(expr.op0().op0().get(ID_statement) != ID_decl)
301301
{
302302
error().source_location = expr.source_location();
303303
error() << "expected declaration as operand of quantifier" << eom;
@@ -311,9 +311,8 @@ void c_typecheck_baset::typecheck_expr_main(exprt &expr)
311311
throw 0;
312312
}
313313

314-
// replace declaration by symbol expression
315-
symbol_exprt bound=to_symbol_expr(expr.op0().op0());
316-
expr.op0().swap(bound);
314+
// replace declarations by symbol expressions
315+
expr.op0().op0() = to_symbol_expr(expr.op0().op0().op0());
317316

318317
implicit_typecast_bool(expr.op1());
319318
}
@@ -738,10 +737,16 @@ void c_typecheck_baset::typecheck_expr_operands(exprt &expr)
738737
}
739738
else if(expr.id()==ID_forall || expr.id()==ID_exists)
740739
{
741-
assert(expr.operands().size()==2);
740+
// These introduce new symbols, which need to be added to the symbol table
741+
// before the second operand is typechecked.
742+
743+
DATA_INVARIANT(expr.operands().size() == 2, "forall/exists are binary");
744+
DATA_INVARIANT(
745+
to_binary_expr(expr).op0().operands().size() == 1,
746+
"forall/exists have one declaration as first operand");
742747

743-
ansi_c_declarationt &declaration=
744-
to_ansi_c_declaration(expr.op0());
748+
ansi_c_declarationt &declaration =
749+
to_ansi_c_declaration(to_binary_expr(expr).op0().op0());
745750

746751
typecheck_declaration(declaration);
747752

@@ -762,7 +767,7 @@ void c_typecheck_baset::typecheck_expr_operands(exprt &expr)
762767
if(s_it==symbol_table.symbols.end())
763768
{
764769
error().source_location = expr.source_location();
765-
error() << "failed to find decl symbol '" << identifier
770+
error() << "failed to find bound symbol `" << identifier
766771
<< "' in symbol table" << eom;
767772
throw 0;
768773
}
@@ -780,7 +785,7 @@ void c_typecheck_baset::typecheck_expr_operands(exprt &expr)
780785
code_declt decl(symbol.symbol_expr());
781786
decl.add_source_location()=declaration.source_location();
782787

783-
expr.op0()=decl;
788+
expr.op0().op0() = decl;
784789

785790
typecheck_expr(expr.op1());
786791
}

src/ansi-c/expr2c.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -798,13 +798,17 @@ std::string expr2ct::convert_quantifier(
798798
if(src.operands().size()!=2)
799799
return convert_norep(src, precedence);
800800

801+
// our made-up syntax can only do one symbol
802+
if(src.op0().operands().size() != 1)
803+
return convert_norep(src, precedence);
804+
801805
unsigned p0, p1;
802806

803-
std::string op0=convert_with_precedence(src.op0(), p0);
807+
std::string op0 = convert_with_precedence(src.op0().op0(), p0);
804808
std::string op1=convert_with_precedence(src.op1(), p1);
805809

806810
std::string dest=symbol+" { ";
807-
dest+=convert(src.op0().type());
811+
dest += convert(src.op0().op0().type());
808812
dest+=" "+op0+"; ";
809813
dest+=op1;
810814
dest+=" }";

src/ansi-c/parser.y

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ extern char *yyansi_ctext;
2626

2727
#include "ansi_c_y.tab.h"
2828

29+
#include <util/mathematical_expr.h>
30+
2931
#ifdef _MSC_VER
3032
// possible loss of data
3133
#pragma warning(disable:4242)
@@ -468,15 +470,15 @@ quantifier_expression:
468470
{
469471
$$=$1;
470472
set($$, ID_forall);
471-
mto($$, $4);
473+
parser_stack($$).add_to_operands(tuple_exprt( { std::move(parser_stack($4)) } ));
472474
mto($$, $5);
473475
PARSER.pop_scope();
474476
}
475477
| TOK_EXISTS compound_scope '{' declaration comma_expression '}'
476478
{
477479
$$=$1;
478480
set($$, ID_exists);
479-
mto($$, $4);
481+
parser_stack($$).add_to_operands(tuple_exprt( { std::move(parser_stack($4)) } ));
480482
mto($$, $5);
481483
PARSER.pop_scope();
482484
}
@@ -806,15 +808,15 @@ ACSL_binding_expression:
806808
{
807809
$$=$1;
808810
set($$, ID_forall);
809-
mto($$, $3);
811+
parser_stack($$).add_to_operands(tuple_exprt( { std::move(parser_stack($3)) } ));
810812
mto($$, $4);
811813
PARSER.pop_scope();
812814
}
813815
| TOK_ACSL_EXISTS compound_scope declaration ACSL_binding_expression
814816
{
815817
$$=$1;
816818
set($$, ID_exists);
817-
mto($$, $3);
819+
parser_stack($$).add_to_operands(tuple_exprt( { std::move(parser_stack($3)) } ));
818820
mto($$, $4);
819821
PARSER.pop_scope();
820822
}

src/solvers/smt2/smt2_conv.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1807,7 +1807,7 @@ void smt2_convt::convert_expr(const exprt &expr)
18071807
else if(quantifier_expr.id() == ID_exists)
18081808
out << "(exists ";
18091809

1810-
exprt bound=expr.op0();
1810+
exprt bound=quantifier_expr.symbol();
18111811

18121812
out << "((";
18131813
convert_expr(bound);

src/solvers/smt2/smt2_parser.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,7 @@ exprt smt2_parsert::quantifier_expression(irep_idt id)
283283
// go backwards, build quantified expression
284284
for(auto r_it=bindings.rbegin(); r_it!=bindings.rend(); r_it++)
285285
{
286-
binary_predicate_exprt quantifier(*r_it, id, result);
286+
quantifier_exprt quantifier(id, *r_it, result);
287287
result=quantifier;
288288
}
289289

src/util/mathematical_expr.h

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -313,35 +313,35 @@ class binding_exprt : public binary_exprt
313313
};
314314

315315
/// \brief A base class for quantifier expressions
316-
class quantifier_exprt : public binary_predicate_exprt
316+
class quantifier_exprt : public binding_exprt
317317
{
318318
public:
319-
quantifier_exprt(
320-
const irep_idt &_id,
321-
const symbol_exprt &_symbol,
322-
const exprt &_where)
323-
: binary_predicate_exprt(_symbol, _id, _where)
324-
{
325-
}
326-
327-
symbol_exprt &symbol()
319+
/// constructor for single variable
320+
quantifier_exprt(irep_idt _id, symbol_exprt _symbol, exprt _where)
321+
: binding_exprt(_id, {std::move(_symbol)}, std::move(_where), bool_typet())
328322
{
329-
return static_cast<symbol_exprt &>(op0());
330323
}
331324

332-
const symbol_exprt &symbol() const
325+
/// constructor for multiple variables
326+
quantifier_exprt(irep_idt _id, const variablest &_variables, exprt _where)
327+
: binding_exprt(_id, _variables, std::move(_where), bool_typet())
333328
{
334-
return static_cast<const symbol_exprt &>(op0());
335329
}
336330

337-
exprt &where()
331+
// for the special case of one variable
332+
symbol_exprt &symbol()
338333
{
339-
return op1();
334+
auto &variables = this->variables();
335+
PRECONDITION(variables.size() == 1);
336+
return variables.front();
340337
}
341338

342-
const exprt &where() const
339+
// for the special case of one variable
340+
const symbol_exprt &symbol() const
343341
{
344-
return op1();
342+
auto &variables = this->variables();
343+
PRECONDITION(variables.size() == 1);
344+
return variables.front();
345345
}
346346
};
347347

@@ -354,8 +354,9 @@ inline bool can_cast_expr<quantifier_exprt>(const exprt &base)
354354
inline void validate_expr(const quantifier_exprt &value)
355355
{
356356
validate_operands(value, 2, "quantifier expressions must have two operands");
357-
DATA_INVARIANT(
358-
value.op0().id() == ID_symbol, "quantified variable shall be a symbol");
357+
for(auto &op : value.variables())
358+
DATA_INVARIANT(
359+
op.id() == ID_symbol, "quantified variable shall be a symbol");
359360
}
360361

361362
/// \brief Cast an exprt to a \ref quantifier_exprt

0 commit comments

Comments
 (0)