Skip to content

Commit ac37018

Browse files
author
Daniel Kroening
committed
smt2_parser: sorts are now in a hash table
This refactors the SMT2 parser to use hash tables instead of chains of if()...else if()... for sorts. This enables extensions, and may have a performance benefit as the number of sorts grows.
1 parent 313e404 commit ac37018

File tree

2 files changed

+78
-70
lines changed

2 files changed

+78
-70
lines changed

src/solvers/smt2/smt2_parser.cpp

Lines changed: 72 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1087,99 +1087,102 @@ exprt smt2_parsert::expression()
10871087

10881088
typet smt2_parsert::sort()
10891089
{
1090+
// a sort is one of the following three cases:
1091+
// SYMBOL
1092+
// ( _ SYMBOL ...
1093+
// ( SYMBOL ...
10901094
switch(next_token())
10911095
{
10921096
case smt2_tokenizert::SYMBOL:
1093-
{
1094-
const std::string &buffer = smt2_tokenizer.get_buffer();
1095-
1096-
if(buffer=="Bool")
1097-
return bool_typet();
1098-
else if(buffer=="Int")
1099-
return integer_typet();
1100-
else if(buffer=="Real")
1101-
return real_typet();
1102-
else
1103-
throw error() << "unexpected sort: '" << buffer << '\'';
1104-
}
1097+
break;
11051098

11061099
case smt2_tokenizert::OPEN:
1107-
if(next_token() != smt2_tokenizert::SYMBOL)
1100+
if(smt2_tokenizer.next_token() != smt2_tokenizert::SYMBOL)
11081101
throw error("expected symbol after '(' in a sort ");
11091102

11101103
if(smt2_tokenizer.get_buffer() == "_")
11111104
{
1112-
// indexed identifier
11131105
if(next_token() != smt2_tokenizert::SYMBOL)
11141106
throw error("expected symbol after '_' in a sort");
1107+
}
1108+
break;
11151109

1116-
if(smt2_tokenizer.get_buffer() == "BitVec")
1117-
{
1118-
if(next_token() != smt2_tokenizert::NUMERAL)
1119-
throw error("expected numeral as bit-width");
1110+
case smt2_tokenizert::CLOSE:
1111+
case smt2_tokenizert::NUMERAL:
1112+
case smt2_tokenizert::STRING_LITERAL:
1113+
case smt2_tokenizert::NONE:
1114+
case smt2_tokenizert::KEYWORD:
1115+
throw error() << "unexpected token in a sort: '"
1116+
<< smt2_tokenizer.get_buffer() << '\'';
11201117

1121-
auto width = std::stoll(smt2_tokenizer.get_buffer());
1118+
case smt2_tokenizert::END_OF_FILE:
1119+
throw error() << "unexpected end-of-file in a sort";
1120+
}
11221121

1123-
// eat the ')'
1124-
if(next_token() != smt2_tokenizert::CLOSE)
1125-
throw error("expected ')' at end of sort");
1122+
// now we have a SYMBOL
1123+
const auto &token = smt2_tokenizer.get_buffer();
11261124

1127-
return unsignedbv_typet(width);
1128-
}
1129-
else if(smt2_tokenizer.get_buffer() == "FloatingPoint")
1130-
{
1131-
if(next_token() != smt2_tokenizert::NUMERAL)
1132-
throw error("expected numeral as bit-width");
1125+
const auto s_it = sorts.find(token);
11331126

1134-
const auto width_e = std::stoll(smt2_tokenizer.get_buffer());
1127+
if(s_it == sorts.end())
1128+
throw error() << "unexpected sort: '" << token << '\'';
11351129

1136-
if(next_token() != smt2_tokenizert::NUMERAL)
1137-
throw error("expected numeral as bit-width");
1130+
return s_it->second();
1131+
}
11381132

1139-
const auto width_f = std::stoll(smt2_tokenizer.get_buffer());
1133+
void smt2_parsert::setup_sorts()
1134+
{
1135+
sorts["Bool"] = [] { return bool_typet(); };
1136+
sorts["Int"] = [] { return integer_typet(); };
1137+
sorts["Real"] = [] { return real_typet(); };
11401138

1141-
// consume the ')'
1142-
if(next_token() != smt2_tokenizert::CLOSE)
1143-
throw error("expected ')' at end of sort");
1139+
sorts["BitVec"] = [this] {
1140+
if(next_token() != smt2_tokenizert::NUMERAL)
1141+
throw error("expected numeral as bit-width");
11441142

1145-
return ieee_float_spect(width_f - 1, width_e).to_type();
1146-
}
1147-
else
1148-
throw error() << "unexpected sort: '" << smt2_tokenizer.get_buffer()
1149-
<< '\'';
1150-
}
1151-
else if(smt2_tokenizer.get_buffer() == "Array")
1152-
{
1153-
// this gets two sorts as arguments, domain and range
1154-
auto domain = sort();
1155-
auto range = sort();
1143+
auto width = std::stoll(smt2_tokenizer.get_buffer());
11561144

1157-
// eat the ')'
1158-
if(next_token() != smt2_tokenizert::CLOSE)
1159-
throw error("expected ')' at end of Array sort");
1145+
// eat the ')'
1146+
if(next_token() != smt2_tokenizert::CLOSE)
1147+
throw error("expected ')' at end of sort");
11601148

1161-
// we can turn arrays that map an unsigned bitvector type
1162-
// to something else into our 'array_typet'
1163-
if(domain.id() == ID_unsignedbv)
1164-
return array_typet(range, infinity_exprt(domain));
1165-
else
1166-
throw error("unsupported array sort");
1167-
}
1168-
else
1169-
throw error() << "unexpected sort: '" << smt2_tokenizer.get_buffer()
1170-
<< '\'';
1149+
return unsignedbv_typet(width);
1150+
};
11711151

1172-
case smt2_tokenizert::CLOSE:
1173-
case smt2_tokenizert::NUMERAL:
1174-
case smt2_tokenizert::STRING_LITERAL:
1175-
case smt2_tokenizert::END_OF_FILE:
1176-
case smt2_tokenizert::NONE:
1177-
case smt2_tokenizert::KEYWORD:
1178-
throw error() << "unexpected token in a sort: '"
1179-
<< smt2_tokenizer.get_buffer() << '\'';
1180-
}
1152+
sorts["FloatingPoint"] = [this] {
1153+
if(next_token() != smt2_tokenizert::NUMERAL)
1154+
throw error("expected numeral as bit-width");
11811155

1182-
UNREACHABLE;
1156+
const auto width_e = std::stoll(smt2_tokenizer.get_buffer());
1157+
1158+
if(next_token() != smt2_tokenizert::NUMERAL)
1159+
throw error("expected numeral as bit-width");
1160+
1161+
const auto width_f = std::stoll(smt2_tokenizer.get_buffer());
1162+
1163+
// consume the ')'
1164+
if(next_token() != smt2_tokenizert::CLOSE)
1165+
throw error("expected ')' at end of sort");
1166+
1167+
return ieee_float_spect(width_f - 1, width_e).to_type();
1168+
};
1169+
1170+
sorts["Array"] = [this] {
1171+
// this gets two sorts as arguments, domain and range
1172+
auto domain = sort();
1173+
auto range = sort();
1174+
1175+
// eat the ')'
1176+
if(next_token() != smt2_tokenizert::CLOSE)
1177+
throw error("expected ')' at end of Array sort");
1178+
1179+
// we can turn arrays that map an unsigned bitvector type
1180+
// to something else into our 'array_typet'
1181+
if(domain.id() == ID_unsignedbv)
1182+
return array_typet(range, infinity_exprt(domain));
1183+
else
1184+
throw error("unsupported array sort");
1185+
};
11831186
}
11841187

11851188
smt2_parsert::signature_with_parameter_idst

src/solvers/smt2/smt2_parser.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ class smt2_parsert
2424
: exit(false), smt2_tokenizer(_in), parenthesis_level(0)
2525
{
2626
setup_commands();
27+
setup_sorts();
2728
}
2829

2930
virtual ~smt2_parsert() = default;
@@ -121,7 +122,6 @@ class smt2_parsert
121122
const exprt::operandst &);
122123
exprt function_application_ieee_float_eq(const exprt::operandst &);
123124
exprt function_application_fp(const exprt::operandst &);
124-
typet sort();
125125
exprt::operandst operands();
126126
typet function_signature_declaration();
127127
signature_with_parameter_idst function_signature_definition();
@@ -142,6 +142,11 @@ class smt2_parsert
142142
/// Apply typecast to unsignedbv to given expression
143143
exprt cast_bv_to_unsigned(const exprt &);
144144

145+
// sorts
146+
typet sort();
147+
std::unordered_map<std::string, std::function<typet()>> sorts;
148+
void setup_sorts();
149+
145150
// hashtable for all commands
146151
std::unordered_map<std::string, std::function<void()>> commands;
147152

0 commit comments

Comments
 (0)