Skip to content

Commit 183180f

Browse files
committed
smt2_parser: introduce table of commands
This refactors the SMT2 parser to use hash tables instead of chains of if()...else if()... for commands. This enables extensions, and may have a performance benefit as the number of commands grows.
1 parent 507c6f8 commit 183180f

File tree

3 files changed

+72
-57
lines changed

3 files changed

+72
-57
lines changed

src/solvers/smt2/smt2_parser.cpp

Lines changed: 31 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1259,21 +1259,36 @@ typet smt2_parsert::function_signature_declaration()
12591259

12601260
void smt2_parsert::command(const std::string &c)
12611261
{
1262-
if(c == "declare-const" || c == "declare-var")
1262+
auto c_it = commands.find(c);
1263+
if(c_it == commands.end())
12631264
{
1264-
// declare-var appears to be a synonym for declare-const that is
1265-
// accepted by Z3 and CVC4
1265+
// silently ignore
1266+
ignore_command();
1267+
}
1268+
else
1269+
c_it->second();
1270+
}
1271+
1272+
void smt2_parsert::setup_commands()
1273+
{
1274+
commands["declare-const"] = [this]() {
1275+
const auto s = smt2_tokenizer.get_buffer();
1276+
12661277
if(next_token() != smt2_tokenizert::SYMBOL)
1267-
throw error() << "expected a symbol after '" << c << '\'';
1278+
throw error() << "expected a symbol after " << s;
12681279

12691280
irep_idt id = smt2_tokenizer.get_buffer();
12701281
auto type = sort();
12711282

12721283
if(add_fresh_id(id, exprt(ID_nil, type)) != id)
12731284
throw error() << "identifier '" << id << "' defined twice";
1274-
}
1275-
else if(c=="declare-fun")
1276-
{
1285+
};
1286+
1287+
// declare-var appears to be a synonym for declare-const that is
1288+
// accepted by Z3 and CVC4
1289+
commands["declare-var"] = commands["declare-const"];
1290+
1291+
commands["declare-fun"] = [this]() {
12771292
if(next_token() != smt2_tokenizert::SYMBOL)
12781293
throw error("expected a symbol after declare-fun");
12791294

@@ -1282,9 +1297,9 @@ void smt2_parsert::command(const std::string &c)
12821297

12831298
if(add_fresh_id(id, exprt(ID_nil, type)) != id)
12841299
throw error() << "identifier '" << id << "' defined twice";
1285-
}
1286-
else if(c == "define-const")
1287-
{
1300+
};
1301+
1302+
commands["define-const"] = [this]() {
12881303
if(next_token() != smt2_tokenizert::SYMBOL)
12891304
throw error("expected a symbol after define-const");
12901305

@@ -1304,9 +1319,9 @@ void smt2_parsert::command(const std::string &c)
13041319
// create the entry
13051320
if(add_fresh_id(id, value) != id)
13061321
throw error() << "identifier '" << id << "' defined twice";
1307-
}
1308-
else if(c=="define-fun")
1309-
{
1322+
};
1323+
1324+
commands["define-fun"] = [this]() {
13101325
if(next_token() != smt2_tokenizert::SYMBOL)
13111326
throw error("expected a symbol after define-fun");
13121327

@@ -1345,11 +1360,7 @@ void smt2_parsert::command(const std::string &c)
13451360

13461361
id_map.at(id).type = signature.type;
13471362
id_map.at(id).parameters = signature.parameters;
1348-
}
1349-
else if(c=="exit")
1350-
{
1351-
exit=true;
1352-
}
1353-
else
1354-
ignore_command();
1363+
};
1364+
1365+
commands["exit"] = [this]() { exit = true; };
13551366
}

src/solvers/smt2/smt2_parser.h

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ Author: Daniel Kroening, kroening@kroening.com
1010
#define CPROVER_SOLVERS_SMT2_SMT2_PARSER_H
1111

1212
#include <map>
13+
#include <unordered_map>
1314

1415
#include <util/mathematical_types.h>
1516
#include <util/std_expr.h>
@@ -22,6 +23,7 @@ class smt2_parsert
2223
explicit smt2_parsert(std::istream &_in)
2324
: exit(false), smt2_tokenizer(_in), parenthesis_level(0)
2425
{
26+
setup_commands();
2527
}
2628

2729
virtual ~smt2_parsert() = default;
@@ -82,10 +84,6 @@ class smt2_parsert
8284
std::size_t parenthesis_level;
8385
smt2_tokenizert::tokent next_token();
8486

85-
void command_sequence();
86-
87-
virtual void command(const std::string &);
88-
8987
// for let/quantifier bindings, function parameters
9088
using renaming_mapt=std::map<irep_idt, irep_idt>;
9189
renaming_mapt renaming_map;
@@ -116,7 +114,6 @@ class smt2_parsert
116114
}
117115
};
118116

119-
void ignore_command();
120117
exprt expression();
121118
exprt function_application();
122119
exprt function_application_ieee_float_op(
@@ -144,6 +141,14 @@ class smt2_parsert
144141

145142
/// Apply typecast to unsignedbv to given expression
146143
exprt cast_bv_to_unsigned(const exprt &);
144+
145+
// hashtable for all commands
146+
std::unordered_map<std::string, std::function<void()>> commands;
147+
148+
void command_sequence();
149+
void command(const std::string &);
150+
void ignore_command();
151+
void setup_commands();
147152
};
148153

149154
#endif // CPROVER_SOLVERS_SMT2_SMT2_PARSER_H

src/solvers/smt2/smt2_solver.cpp

Lines changed: 31 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,13 @@ class smt2_solvert:public smt2_parsert
2828
smt2_solvert(std::istream &_in, decision_proceduret &_solver)
2929
: smt2_parsert(_in), solver(_solver), status(NOT_SOLVED)
3030
{
31+
setup_commands();
3132
}
3233

3334
protected:
3435
decision_proceduret &solver;
3536

36-
void command(const std::string &) override;
37+
void setup_commands();
3738
void define_constants();
3839
void expand_function_applications(exprt &);
3940

@@ -118,20 +119,19 @@ void smt2_solvert::expand_function_applications(exprt &expr)
118119
}
119120
}
120121

121-
void smt2_solvert::command(const std::string &c)
122+
void smt2_solvert::setup_commands()
122123
{
123124
{
124-
if(c == "assert")
125-
{
125+
commands["assert"] = [this]() {
126126
exprt e = expression();
127127
if(e.is_not_nil())
128128
{
129129
expand_function_applications(e);
130130
solver.set_to_true(e);
131131
}
132-
}
133-
else if(c == "check-sat")
134-
{
132+
};
133+
134+
commands["check-sat"] = [this]() {
135135
// add constant definitions as constraints
136136
define_constants();
137137

@@ -151,20 +151,20 @@ void smt2_solvert::command(const std::string &c)
151151
std::cout << "error\n";
152152
status = NOT_SOLVED;
153153
}
154-
}
155-
else if(c == "check-sat-assuming")
156-
{
154+
};
155+
156+
commands["check-sat-assuming"] = [this]() {
157157
throw error("not yet implemented");
158-
}
159-
else if(c == "display")
160-
{
158+
};
159+
160+
commands["display"] = [this]() {
161161
// this is a command that Z3 appears to implement
162162
exprt e = expression();
163163
if(e.is_not_nil())
164164
std::cout << smt2_format(e) << '\n';
165-
}
166-
else if(c == "get-value")
167-
{
165+
};
166+
167+
commands["get-value"] = [this]() {
168168
std::vector<exprt> ops;
169169

170170
if(next_token() != smt2_tokenizert::OPEN)
@@ -217,18 +217,18 @@ void smt2_solvert::command(const std::string &c)
217217
}
218218

219219
std::cout << ")\n";
220-
}
221-
else if(c == "echo")
222-
{
220+
};
221+
222+
commands["echo"] = [this]() {
223223
if(next_token() != smt2_tokenizert::STRING_LITERAL)
224224
throw error("expected string literal");
225225

226226
std::cout << smt2_format(constant_exprt(
227227
smt2_tokenizer.get_buffer(), string_typet()))
228228
<< '\n';
229-
}
230-
else if(c == "get-assignment")
231-
{
229+
};
230+
231+
commands["get-assignment"] = [this]() {
232232
// print satisfying assignment for all named expressions
233233

234234
if(status != SAT)
@@ -256,9 +256,9 @@ void smt2_solvert::command(const std::string &c)
256256
}
257257
}
258258
std::cout << ')' << '\n';
259-
}
260-
else if(c == "get-model")
261-
{
259+
};
260+
261+
commands["get-model"] = [this]() {
262262
// print a model for all identifiers
263263

264264
if(status != SAT)
@@ -293,9 +293,9 @@ void smt2_solvert::command(const std::string &c)
293293
}
294294
}
295295
std::cout << ')' << '\n';
296-
}
297-
else if(c == "simplify")
298-
{
296+
};
297+
298+
commands["simplify"] = [this]() {
299299
// this is a command that Z3 appears to implement
300300
exprt e = expression();
301301
if(e.is_not_nil())
@@ -305,7 +305,9 @@ void smt2_solvert::command(const std::string &c)
305305
exprt e_simplified = simplify_expr(e, ns);
306306
std::cout << smt2_format(e) << '\n';
307307
}
308-
}
308+
};
309+
}
310+
309311
#if 0
310312
// TODO:
311313
| ( declare-const hsymboli hsorti )
@@ -330,9 +332,6 @@ void smt2_solvert::command(const std::string &c)
330332
| ( set-info hattributei )
331333
| ( set-option hoptioni )
332334
#endif
333-
else
334-
smt2_parsert::command(c);
335-
}
336335
}
337336

338337
class smt2_message_handlert : public message_handlert

0 commit comments

Comments
 (0)