CBMC
Loading...
Searching...
No Matches
smt2_parser.cpp
Go to the documentation of this file.
1/*******************************************************************\
2
3Module:
4
5Author: Daniel Kroening, kroening@kroening.com
6
7\*******************************************************************/
8
9#include "smt2_parser.h"
10
11#include "smt2_format.h"
12
13#include <util/arith_tools.h>
14#include <util/bitvector_expr.h>
16#include <util/floatbv_expr.h>
17#include <util/ieee_float.h>
18#include <util/invariant.h>
20#include <util/prefix.h>
21#include <util/range.h>
22
23#include <numeric>
24
26{
27 auto token = smt2_tokenizer.next_token();
28
29 if(token == smt2_tokenizert::OPEN)
31 else if(token == smt2_tokenizert::CLOSE)
33
34 return token;
35}
36
38{
39 while(parenthesis_level > 0)
40 if(next_token() == smt2_tokenizert::END_OF_FILE)
41 return;
42}
43
45{
46 exit=false;
47
48 while(!exit)
49 {
50 if(smt2_tokenizer.peek() == smt2_tokenizert::END_OF_FILE)
51 {
52 exit = true;
53 return;
54 }
55
56 if(next_token() != smt2_tokenizert::OPEN)
57 throw error("command must start with '('");
58
59 auto cmd_token = next_token();
60 if(cmd_token != smt2_tokenizert::SYMBOL)
61 {
63 throw error("expected symbol as command");
64 }
65
66 command(cmd_token.text);
67
68 switch(next_token())
69 {
70 case smt2_tokenizert::END_OF_FILE:
71 throw error(
72 "expected closing parenthesis at end of command,"
73 " but got EOF");
74
75 case smt2_tokenizert::CLOSE:
76 // what we expect
77 break;
78
79 case smt2_tokenizert::OPEN:
80 case smt2_tokenizert::SYMBOL:
81 case smt2_tokenizert::NUMERAL:
82 case smt2_tokenizert::STRING_LITERAL:
83 case smt2_tokenizert::NONE:
84 case smt2_tokenizert::KEYWORD:
85 throw error("expected ')' at end of command");
86 }
87 }
88}
89
91{
92 std::size_t parentheses=0;
93 while(true)
94 {
95 switch(smt2_tokenizer.peek())
96 {
97 case smt2_tokenizert::OPEN:
98 next_token();
100 break;
101
102 case smt2_tokenizert::CLOSE:
103 if(parentheses==0)
104 return; // done
105
106 next_token();
107 parentheses--;
108 break;
109
110 case smt2_tokenizert::END_OF_FILE:
111 throw error("unexpected EOF in command");
112
113 case smt2_tokenizert::SYMBOL:
114 case smt2_tokenizert::NUMERAL:
115 case smt2_tokenizert::STRING_LITERAL:
116 case smt2_tokenizert::NONE:
117 case smt2_tokenizert::KEYWORD:
118 next_token();
119 }
120 }
121}
122
124{
125 exprt::operandst result;
126
127 while(smt2_tokenizer.peek() != smt2_tokenizert::CLOSE)
128 result.push_back(expression());
129
130 next_token(); // eat the ')'
131
132 return result;
133}
134
136{
137 if(!id_map
138 .emplace(
139 std::piecewise_construct,
140 std::forward_as_tuple(id),
141 std::forward_as_tuple(idt::VARIABLE, std::move(expr)))
142 .second)
143 {
144 // id already used
145 throw error() << "identifier '" << id << "' defined twice";
146 }
147}
148
150{
151 if(next_token() != smt2_tokenizert::OPEN)
152 throw error("expected bindings after let");
153
154 std::vector<std::pair<irep_idt, exprt>> bindings;
155
156 while(smt2_tokenizer.peek() == smt2_tokenizert::OPEN)
157 {
158 next_token();
159
160 auto binding_token = next_token();
161 if(binding_token != smt2_tokenizert::SYMBOL)
162 throw error("expected symbol in binding");
163
164 irep_idt identifier = binding_token.text;
165
166 // note that the previous bindings are _not_ visible yet
167 exprt value=expression();
168
169 if(next_token() != smt2_tokenizert::CLOSE)
170 throw error("expected ')' after value in binding");
171
172 bindings.push_back(
173 std::pair<irep_idt, exprt>(identifier, value));
174 }
175
176 if(next_token() != smt2_tokenizert::CLOSE)
177 throw error("expected ')' at end of bindings");
178
179 // we may hide identifiers in outer scopes
180 std::vector<std::pair<irep_idt, idt>> saved_ids;
181
182 // add the bindings to the id_map
183 for(auto &b : bindings)
184 {
185 auto insert_result = id_map.insert({b.first, idt{idt::BINDING, b.second}});
186 if(!insert_result.second) // already there
187 {
188 auto &id_entry = *insert_result.first;
189 saved_ids.emplace_back(id_entry.first, std::move(id_entry.second));
190 id_entry.second = idt{idt::BINDING, b.second};
191 }
192 }
193
194 // now parse, with bindings in place
195 exprt where = expression();
196
197 if(next_token() != smt2_tokenizert::CLOSE)
198 throw error("expected ')' after let");
199
201 exprt::operandst values;
202
203 for(const auto &b : bindings)
204 {
205 variables.push_back(symbol_exprt(b.first, b.second.type()));
206 values.push_back(b.second);
207 }
208
209 // delete the bindings from the id_map
210 for(const auto &binding : bindings)
211 id_map.erase(binding.first);
212
213 // restore any previous ids
214 for(auto &saved_id : saved_ids)
215 id_map.insert(std::move(saved_id));
216
217 return let_exprt(variables, values, where);
218}
219
220std::pair<binding_exprt::variablest, exprt> smt2_parsert::binding(irep_idt id)
221{
222 if(next_token() != smt2_tokenizert::OPEN)
223 throw error() << "expected bindings after " << id;
224
226
227 while(smt2_tokenizer.peek() == smt2_tokenizert::OPEN)
228 {
229 next_token();
230
231 auto binding_token = next_token();
232 if(binding_token != smt2_tokenizert::SYMBOL)
233 throw error("expected symbol in binding");
234
235 irep_idt identifier = binding_token.text;
236
237 typet type=sort();
238
239 if(next_token() != smt2_tokenizert::CLOSE)
240 throw error("expected ')' after sort in binding");
241
242 bindings.push_back(symbol_exprt(identifier, type));
243 }
244
245 if(next_token() != smt2_tokenizert::CLOSE)
246 throw error("expected ')' at end of bindings");
247
248 // we may hide identifiers in outer scopes
249 std::vector<std::pair<irep_idt, idt>> saved_ids;
250
251 // add the bindings to the id_map
252 for(auto &b : bindings)
253 {
254 auto insert_result =
255 id_map.insert({b.identifier(), idt{idt::BINDING, b.type()}});
256 if(!insert_result.second) // already there
257 {
258 auto &id_entry = *insert_result.first;
259 saved_ids.emplace_back(id_entry.first, std::move(id_entry.second));
260 id_entry.second = idt{idt::BINDING, b.type()};
261 }
262 }
263
264 // now parse, with bindings in place
265 exprt expr=expression();
266
267 if(next_token() != smt2_tokenizert::CLOSE)
268 throw error() << "expected ')' after " << id;
269
270 // remove bindings from id_map
271 for(const auto &b : bindings)
272 id_map.erase(b.identifier());
273
274 // restore any previous ids
275 for(auto &saved_id : saved_ids)
276 id_map.insert(std::move(saved_id));
277
278 return {std::move(bindings), std::move(expr)};
279}
280
282{
283 auto binding = this->binding(ID_lambda);
284 return lambda_exprt(binding.first, binding.second);
285}
286
288{
289 auto binding = this->binding(id);
290
291 if(!binding.second.is_boolean())
292 throw error() << id << " expects a boolean term";
293
294 return quantifier_exprt(id, binding.first, binding.second);
295}
296
298 const symbol_exprt &function,
299 const exprt::operandst &op)
300{
301 const auto &function_type = to_mathematical_function_type(function.type());
302
303 // check the arguments
304 if(op.size() != function_type.domain().size())
305 throw error("wrong number of arguments for function");
306
307 for(std::size_t i=0; i<op.size(); i++)
308 {
309 if(op[i].type() != function_type.domain()[i])
310 throw error("wrong type for arguments for function");
311 }
312
313 return function_application_exprt(function, op);
314}
315
317{
318 exprt::operandst result = op;
319
320 for(auto &expr : result)
321 {
322 if(expr.type().id() == ID_signedbv) // no need to cast
323 {
324 }
325 else if(expr.type().id() != ID_unsignedbv)
326 {
327 throw error("expected unsigned bitvector");
328 }
329 else
330 {
331 const auto width = to_unsignedbv_type(expr.type()).get_width();
332 expr = typecast_exprt(expr, signedbv_typet(width));
333 }
334 }
335
336 return result;
337}
338
340{
341 if(expr.type().id()==ID_unsignedbv) // no need to cast
342 return expr;
343
344 if(expr.type().id()!=ID_signedbv)
345 throw error("expected signed bitvector");
346
347 const auto width=to_signedbv_type(expr.type()).get_width();
348 return typecast_exprt(expr, unsignedbv_typet(width));
349}
350
352 const exprt::operandst &op) const
353{
354 for(std::size_t i = 1; i < op.size(); i++)
355 {
356 if(op[i].type() != op[0].type())
357 {
358 throw error() << "expression must have operands with matching types,"
359 " but got '"
360 << smt2_format(op[0].type()) << "' and '"
361 << smt2_format(op[i].type()) << '\'';
362 }
363 }
364}
365
367{
368 if(op.empty())
369 throw error("expression must have at least one operand");
370
372
373 exprt result(id, op[0].type());
374 result.operands() = op;
375 return result;
376}
377
379{
380 if(op.size()!=2)
381 throw error("expression must have two operands");
382
384
385 return binary_predicate_exprt(op[0], id, op[1]);
386}
387
389{
390 if(op.size()!=1)
391 throw error("expression must have one operand");
392
393 return unary_exprt(id, op[0], op[0].type());
394}
395
397{
398 if(op.size()!=2)
399 throw error("expression must have two operands");
400
402
403 return binary_exprt(op[0], id, op[1], op[0].type());
404}
405
407 const exprt::operandst &op)
408{
409 if(op.size() != 2)
410 throw error() << "FloatingPoint equality takes two operands";
411
412 if(op[0].type().id() != ID_floatbv || op[1].type().id() != ID_floatbv)
413 throw error() << "FloatingPoint equality takes FloatingPoint operands";
414
415 if(op[0].type() != op[1].type())
416 {
417 throw error() << "FloatingPoint equality takes FloatingPoint operands with "
418 << "matching sort, but got " << smt2_format(op[0].type())
419 << " vs " << smt2_format(op[1].type());
420 }
421
422 return ieee_float_equal_exprt(op[0], op[1]);
423}
424
426 const irep_idt &id,
427 const exprt::operandst &op)
428{
429 if(op.size() != 3)
430 throw error() << id << " takes three operands";
431
432 if(op[1].type().id() != ID_floatbv || op[2].type().id() != ID_floatbv)
433 throw error() << id << " takes FloatingPoint operands";
434
435 if(op[1].type() != op[2].type())
436 {
437 throw error() << id << " takes FloatingPoint operands with matching sort, "
438 << "but got " << smt2_format(op[1].type()) << " vs "
439 << smt2_format(op[2].type());
440 }
441
442 // clang-format off
443 const irep_idt expr_id =
444 id == "fp.add" ? ID_floatbv_plus :
445 id == "fp.sub" ? ID_floatbv_minus :
446 id == "fp.mul" ? ID_floatbv_mult :
447 id == "fp.div" ? ID_floatbv_div :
448 throw error("unsupported floating-point operation");
449 // clang-format on
450
451 return ieee_float_op_exprt(op[1], expr_id, op[2], op[0]);
452}
453
455{
456 // floating-point from bit-vectors
457 if(op.size() != 3)
458 throw error("fp takes three operands");
459
460 if(op[0].type().id() != ID_unsignedbv)
461 throw error("fp takes BitVec as first operand");
462
463 if(op[1].type().id() != ID_unsignedbv)
464 throw error("fp takes BitVec as second operand");
465
466 if(op[2].type().id() != ID_unsignedbv)
467 throw error("fp takes BitVec as third operand");
468
469 if(to_unsignedbv_type(op[0].type()).get_width() != 1)
470 throw error("fp takes BitVec of size 1 as first operand");
471
472 const auto width_e = to_unsignedbv_type(op[1].type()).get_width();
473 const auto width_f = to_unsignedbv_type(op[2].type()).get_width();
474
475 // stitch the bits together
476 const auto concat_type = unsignedbv_typet(width_f + width_e + 1);
477
478 // We need a bitvector type without numerical interpretation
479 // to do this conversion.
480 const auto bv_type = bv_typet(concat_type.get_width());
481
482 // The target type
484
485 return typecast_exprt(
488 fp_type);
489}
490
492{
493 auto token = next_token();
494
495 switch(token)
496 {
497 case smt2_tokenizert::SYMBOL:
498 if(token.text == "_") // indexed identifier
499 {
500 // indexed identifier
501 auto id_token = next_token();
502 if(id_token != smt2_tokenizert::SYMBOL)
503 throw error("expected symbol after '_'");
504
505 const auto id = id_token.text;
506
507 if(has_prefix(id, "bv"))
508 {
509 mp_integer i = string2integer(std::string(id, 2, std::string::npos));
510
511 auto width_token = next_token();
512 if(width_token != smt2_tokenizert::NUMERAL)
513 throw error("expected numeral as bitvector literal width");
514
515 auto width = std::stoll(width_token.text);
516
517 if(next_token() != smt2_tokenizert::CLOSE)
518 throw error("expected ')' after bitvector literal");
519
520 return from_integer(i, unsignedbv_typet(width));
521 }
522 else if(id == "+oo" || id == "-oo" || id == "NaN")
523 {
524 // These are the "plus infinity", "minus infinity" and NaN
525 // floating-point literals.
526 auto e_token = next_token();
527 if(e_token != smt2_tokenizert::NUMERAL)
528 throw error() << "expected number after " << id;
529
530 auto width_e = std::stoll(e_token.text);
531
532 auto f_token = next_token();
533 if(f_token != smt2_tokenizert::NUMERAL)
534 throw error() << "expected second number after " << id;
535
536 auto width_f = std::stoll(f_token.text);
537
538 if(next_token() != smt2_tokenizert::CLOSE)
539 throw error() << "expected ')' after " << id;
540
541 // width_f *includes* the hidden bit
542 const ieee_float_spect spec(width_f - 1, width_e);
543
544 if(id == "+oo")
545 return ieee_floatt::plus_infinity(spec).to_expr();
546 else if(id == "-oo")
547 return ieee_floatt::minus_infinity(spec).to_expr();
548 else // NaN
549 return ieee_floatt::NaN(spec).to_expr();
550 }
551 else
552 {
553 throw error() << "unknown indexed identifier " << id;
554 }
555 }
556 else if(token.text == "!")
557 {
558 // these are "term attributes"
559 const auto term = expression();
560
561 while(smt2_tokenizer.peek() == smt2_tokenizert::KEYWORD)
562 {
563 auto kw_token = next_token(); // eat the keyword
564 if(kw_token.text == "named")
565 {
566 // 'named terms' must be Boolean
567 if(!term.is_boolean())
568 throw error("named terms must be Boolean");
569
570 auto name_token = next_token();
571 if(name_token == smt2_tokenizert::SYMBOL)
572 {
573 const symbol_exprt symbol_expr(name_token.text, bool_typet());
574 named_terms.emplace(
575 symbol_expr.identifier(), named_termt(term, symbol_expr));
576 }
577 else
578 throw error("invalid name attribute, expected symbol");
579 }
580 else
581 throw error("unknown term attribute");
582 }
583
584 if(next_token() != smt2_tokenizert::CLOSE)
585 throw error("expected ')' at end of term attribute");
586 else
587 return term;
588 }
589 else
590 {
591 // non-indexed symbol, look up in expression table
592 const auto &id = token.text;
593 const auto e_it = expressions.find(id);
594 if(e_it != expressions.end())
595 return e_it->second();
596
597 // get the operands
598 auto op = operands();
599
600 // rummage through id_map
601 auto id_it = id_map.find(id);
602 if(id_it != id_map.end())
603 {
604 if(id_it->second.type.id() == ID_mathematical_function)
605 {
606 return function_application(symbol_exprt(id, id_it->second.type), op);
607 }
608 else
609 return symbol_exprt(id, id_it->second.type);
610 }
611 else
612 throw error() << "unknown function symbol '" << id << '\'';
613 }
614 break;
615
616 case smt2_tokenizert::OPEN: // likely indexed identifier
617 if(smt2_tokenizer.peek() == smt2_tokenizert::SYMBOL)
618 {
619 auto sym_token = next_token(); // eat symbol
620 if(sym_token.text == "_")
621 {
622 // indexed identifier
623 auto id_token = next_token();
624 if(id_token != smt2_tokenizert::SYMBOL)
625 throw error("expected symbol after '_'");
626
627 irep_idt id = id_token.text; // hash it
628
629 if(id=="extract")
630 {
631 auto upper_token = next_token();
632 if(upper_token != smt2_tokenizert::NUMERAL)
633 throw error("expected numeral after extract");
634
635 auto upper = std::stoll(upper_token.text);
636
637 auto lower_token = next_token();
638 if(lower_token != smt2_tokenizert::NUMERAL)
639 throw error("expected two numerals after extract");
640
641 auto lower = std::stoll(lower_token.text);
642
643 if(next_token() != smt2_tokenizert::CLOSE)
644 throw error("expected ')' after extract");
645
646 auto op=operands();
647
648 if(op.size()!=1)
649 throw error("extract takes one operand");
650
651 if(upper<lower)
652 throw error("extract got bad indices");
653
654 auto lower_e = from_integer(lower, integer_typet());
655
656 unsignedbv_typet t(upper-lower+1);
657
658 return extractbits_exprt(op[0], lower_e, t);
659 }
660 else if(id=="rotate_left" ||
661 id=="rotate_right" ||
662 id == ID_repeat ||
663 id=="sign_extend" ||
664 id=="zero_extend")
665 {
666 auto index_token = next_token();
667 if(index_token != smt2_tokenizert::NUMERAL)
668 throw error() << "expected numeral after " << id;
669
670 auto index = string2integer(index_token.text);
671
672 if(next_token() != smt2_tokenizert::CLOSE)
673 throw error() << "expected ')' after " << id << " index";
674
675 auto op=operands();
676
677 if(op.size()!=1)
678 throw error() << id << " takes one operand";
679
680 if(id=="rotate_left")
681 {
682 auto dist=from_integer(index, integer_typet());
683 return binary_exprt(op[0], ID_rol, dist, op[0].type());
684 }
685 else if(id=="rotate_right")
686 {
687 auto dist=from_integer(index, integer_typet());
688 return binary_exprt(op[0], ID_ror, dist, op[0].type());
689 }
690 else if(id=="sign_extend")
691 {
692 // we first convert to a signed type of the original width,
693 // then extend to the new width, and then go to unsigned
694 const auto width = to_unsignedbv_type(op[0].type()).get_width();
696 const signedbv_typet large_signed_type{width + index};
697 const unsignedbv_typet unsigned_type{width + index};
698
699 return typecast_exprt(
703 }
704 else if(id == ID_zero_extend)
705 {
706 auto width=to_unsignedbv_type(op[0].type()).get_width();
707 unsignedbv_typet unsigned_type{width + index};
708
709 return zero_extend_exprt{op[0], unsigned_type};
710 }
711 else if(id == ID_repeat)
712 {
713 auto i = from_integer(index, integer_typet());
714 auto width = to_unsignedbv_type(op[0].type()).get_width() * index;
715 return replication_exprt(i, op[0], unsignedbv_typet(width));
716 }
717 else
718 return nil_exprt();
719 }
720 else if(id == "to_fp")
721 {
722 auto e_token = next_token();
723 if(e_token != smt2_tokenizert::NUMERAL)
724 throw error("expected number after to_fp");
725
726 auto width_e = std::stoll(e_token.text);
727
728 auto f_token = next_token();
729 if(f_token != smt2_tokenizert::NUMERAL)
730 throw error("expected second number after to_fp");
731
732 auto width_f = std::stoll(f_token.text);
733
734 if(next_token() != smt2_tokenizert::CLOSE)
735 throw error("expected ')' after to_fp");
736
737 // width_f *includes* the hidden bit
738 const ieee_float_spect spec(width_f - 1, width_e);
739
740 auto first_operand = expression();
741
742 // The SMT-LIB FloatingPoint theory gives `to_fp` several
743 // overloads. All but one take a rounding mode followed by a
744 // source operand; the exception is the bit-pattern
745 // reinterpretation
746 // ((_ to_fp eb sb) (_ BitVec eb+sb))
747 // which takes a single bit-vector operand and no rounding mode,
748 // interpreting those bits directly as the IEEE-754 interchange
749 // encoding. If the form closes after the first operand, this
750 // is what we just parsed; otherwise the first operand was the
751 // rounding mode (bound below) and a source operand follows.
752 if(smt2_tokenizer.peek() == smt2_tokenizert::CLOSE)
753 {
754 next_token(); // eat the ')'
755
756 if(
757 first_operand.type().id() != ID_unsignedbv ||
758 to_unsignedbv_type(first_operand.type()).get_width() !=
759 spec.width())
760 {
761 throw error() << "to_fp bit-pattern reinterpretation expects a "
762 "bit-vector operand of width "
763 << spec.width();
764 }
765
766 // Reinterpret the bits as a float. Routing through a generic
767 // bit-vector type makes the conversion a bit-level reinterpret
768 // (see boolbv_typecastt) rather than a numeric integer-to-float
769 // conversion.
770 return typecast_exprt{
771 typecast_exprt{std::move(first_operand), bv_typet{spec.width()}},
772 spec.to_type()};
773 }
774
775 // The genuine rounding-mode + source-operand path.
776 const exprt &rounding_mode = first_operand;
777
778 auto source_op = expression();
779
780 if(next_token() != smt2_tokenizert::CLOSE)
781 throw error("expected ')' at the end of to_fp");
782
783 // There are several options for the source operand:
784 // 1) real or integer
785 // 2) bit-vector, which is interpreted as signed 2's complement
786 // 3) another floating-point format
787 if(
788 source_op.type().id() == ID_real ||
789 source_op.type().id() == ID_integer)
790 {
791 // For now, we can only do this when
792 // the source operand is a constant.
793 if(source_op.is_constant())
794 {
795 mp_integer significand, exponent;
796
797 const auto &real_number =
799 auto dot_pos = real_number.find('.');
800 if(dot_pos == std::string::npos)
801 {
802 exponent = 0;
803 significand = string2integer(real_number);
804 }
805 else
806 {
807 // remove the '.'
808 std::string significand_str;
809 significand_str.reserve(real_number.size());
810 for(auto ch : real_number)
811 {
812 if(ch != '.')
814 }
815
816 exponent =
818 significand = string2integer(significand_str);
819 }
820
822 spec,
823 static_cast<ieee_floatt::rounding_modet>(
824 numeric_cast_v<int>(to_constant_expr(rounding_mode))));
825 a.from_base10(significand, exponent);
826 return a.to_expr();
827 }
828 else
829 throw error()
830 << "to_fp for non-constant real expressions is not implemented";
831 }
832 else if(source_op.type().id() == ID_unsignedbv)
833 {
834 // The operand is hard-wired to be interpreted as a signed number.
837 source_op,
839 to_unsignedbv_type(source_op.type()).get_width())),
840 rounding_mode,
841 spec.to_type());
842 }
843 else if(source_op.type().id() == ID_floatbv)
844 {
846 source_op, rounding_mode, spec.to_type());
847 }
848 else
849 throw error() << "unexpected sort given as operand to to_fp";
850 }
851 else if(id == "to_fp_unsigned")
852 {
853 auto e_token = next_token();
854 if(e_token != smt2_tokenizert::NUMERAL)
855 throw error("expected number after to_fp_unsigned");
856
857 auto width_e = std::stoll(e_token.text);
858
859 auto f_token = next_token();
860 if(f_token != smt2_tokenizert::NUMERAL)
861 throw error("expected second number after to_fp_unsigned");
862
863 auto width_f = std::stoll(f_token.text);
864
865 if(next_token() != smt2_tokenizert::CLOSE)
866 throw error("expected ')' after to_fp_unsigned");
867
868 // width_f *includes* the hidden bit
869 const ieee_float_spect spec(width_f - 1, width_e);
870
871 auto rounding_mode = expression();
872
873 auto source_op = expression();
874
875 if(next_token() != smt2_tokenizert::CLOSE)
876 throw error("expected ')' at the end of to_fp_unsigned");
877
878 if(source_op.type().id() == ID_unsignedbv)
879 {
880 // The operand is hard-wired to be interpreted
881 // as an unsigned number.
883 source_op, rounding_mode, spec.to_type());
884 }
885 else
886 throw error()
887 << "unexpected sort given as operand to to_fp_unsigned";
888 }
889 else if(id == "fp.to_sbv" || id == "fp.to_ubv")
890 {
891 // These are indexed by the number of bits of the result.
892 auto width_token = next_token();
893 if(width_token != smt2_tokenizert::NUMERAL)
894 throw error() << "expected number after " << id;
895
896 auto width = std::stoll(width_token.text);
897
898 if(next_token() != smt2_tokenizert::CLOSE)
899 throw error() << "expected ')' after " << id;
900
901 auto op = operands();
902
903 if(op.size() != 2)
904 throw error() << id << " takes two operands";
905
906 if(op[1].type().id() != ID_floatbv)
907 throw error() << id << " takes a FloatingPoint operand";
908
909 if(id == "fp.to_sbv")
910 return typecast_exprt(
911 floatbv_typecast_exprt(op[1], op[0], signedbv_typet(width)),
912 unsignedbv_typet(width));
913 else
915 op[1], op[0], unsignedbv_typet(width));
916 }
917 else
918 {
919 throw error() << "unknown indexed identifier '" << id << '\'';
920 }
921 }
922 else if(sym_token.text == "as")
923 {
924 // This is an extension understood by Z3 and CVC4.
925 if(
926 smt2_tokenizer.peek() == smt2_tokenizert::SYMBOL &&
927 smt2_tokenizer.peek().text == "const")
928 {
929 next_token(); // eat the "const"
930 auto sort = this->sort();
931
932 if(sort.id() != ID_array)
933 {
934 throw error()
935 << "unexpected 'as const' expression expects array type";
936 }
937
938 const auto &array_sort = to_array_type(sort);
939
940 if(next_token() != smt2_tokenizert::CLOSE)
941 throw error() << "expecting ')' after sort in 'as const'";
942
943 auto value = expression();
944
945 if(value.type() != array_sort.element_type())
946 throw error() << "unexpected 'as const' with wrong element type";
947
948 if(next_token() != smt2_tokenizert::CLOSE)
949 throw error() << "expecting ')' at the end of 'as const'";
950
951 return array_of_exprt(value, array_sort);
952 }
953 else
954 throw error() << "unexpected 'as' expression";
955 }
956 else
957 {
958 // just double parentheses
960
961 if(
962 next_token() != smt2_tokenizert::CLOSE &&
963 next_token() != smt2_tokenizert::CLOSE)
964 {
965 throw error("mismatched parentheses in an expression");
966 }
967
968 return tmp;
969 }
970 }
971 else
972 {
973 // just double parentheses
975
976 if(
977 next_token() != smt2_tokenizert::CLOSE &&
978 next_token() != smt2_tokenizert::CLOSE)
979 {
980 throw error("mismatched parentheses in an expression");
981 }
982
983 return tmp;
984 }
985 break;
986
987 case smt2_tokenizert::CLOSE:
988 case smt2_tokenizert::NUMERAL:
989 case smt2_tokenizert::STRING_LITERAL:
990 case smt2_tokenizert::END_OF_FILE:
991 case smt2_tokenizert::NONE:
992 case smt2_tokenizert::KEYWORD:
993 // just parentheses
995 if(next_token() != smt2_tokenizert::CLOSE)
996 throw error("mismatched parentheses in an expression");
997
998 return tmp;
999 }
1000
1002}
1003
1005 const exprt::operandst &operands,
1006 bool is_signed)
1007{
1008 if(operands.size() != 2)
1009 throw error() << "bitvector division expects two operands";
1010
1011 // SMT-LIB2 defines the result of division by 0 to be 1....1
1012 auto divisor = symbol_exprt("divisor", operands[1].type());
1013 auto divisor_is_zero = equal_exprt(divisor, from_integer(0, divisor.type()));
1014 auto all_ones = to_unsignedbv_type(operands[0].type()).largest_expr();
1015
1017
1018 if(is_signed)
1019 {
1020 auto signed_operands = cast_bv_to_signed({operands[0], divisor});
1023 }
1024 else
1025 division_result = div_exprt(operands[0], divisor);
1026
1027 return let_exprt(
1028 {divisor},
1029 operands[1],
1031}
1032
1034{
1035 if(operands.size() != 2)
1036 throw error() << "bitvector modulo expects two operands";
1037
1038 // SMT-LIB2 defines the result of "lhs modulo 0" to be "lhs"
1039 auto dividend = symbol_exprt("dividend", operands[0].type());
1040 auto divisor = symbol_exprt("divisor", operands[1].type());
1041 auto divisor_is_zero = equal_exprt(divisor, from_integer(0, divisor.type()));
1042
1044
1045 // bvurem and bvsrem match our mod_exprt.
1046 // bvsmod doesn't.
1047 if(is_signed)
1048 {
1049 auto signed_operands = cast_bv_to_signed({dividend, divisor});
1050 mod_result =
1052 }
1053 else
1054 mod_result = mod_exprt(dividend, divisor);
1055
1056 return let_exprt(
1057 {dividend, divisor},
1058 {operands[0], operands[1]},
1059 if_exprt(divisor_is_zero, dividend, mod_result));
1060}
1061
1063{
1064 auto token = next_token();
1065
1066 switch(token)
1067 {
1068 case smt2_tokenizert::SYMBOL:
1069 {
1070 const auto &identifier = token.text;
1071
1072 // in the expression table?
1073 const auto e_it = expressions.find(identifier);
1074 if(e_it != expressions.end())
1075 return e_it->second();
1076
1077 // rummage through id_map
1078 auto id_it = id_map.find(identifier);
1079 if(id_it != id_map.end())
1080 {
1081 symbol_exprt symbol_expr(identifier, id_it->second.type);
1082 if(token.quoted_symbol)
1083 symbol_expr.set(ID_C_quoted, true);
1084 return std::move(symbol_expr);
1085 }
1086
1087 // don't know, give up
1088 throw error() << "unknown expression '" << identifier << '\'';
1089 }
1090
1091 case smt2_tokenizert::NUMERAL:
1092 {
1093 const std::string &buffer = token.text;
1094 if(buffer.size() >= 2 && buffer[0] == '#' && buffer[1] == 'x')
1095 {
1096 mp_integer value =
1097 string2integer(std::string(buffer, 2, std::string::npos), 16);
1098 const std::size_t width = 4 * (buffer.size() - 2);
1099 CHECK_RETURN(width != 0 && width % 4 == 0);
1100 unsignedbv_typet type(width);
1101 return from_integer(value, type);
1102 }
1103 else if(buffer.size() >= 2 && buffer[0] == '#' && buffer[1] == 'b')
1104 {
1105 mp_integer value =
1106 string2integer(std::string(buffer, 2, std::string::npos), 2);
1107 const std::size_t width = buffer.size() - 2;
1108 CHECK_RETURN(width != 0);
1109 unsignedbv_typet type(width);
1110 return from_integer(value, type);
1111 }
1112 else
1113 {
1115 }
1116 }
1117
1118 case smt2_tokenizert::OPEN: // function application
1119 return function_application();
1120
1121 case smt2_tokenizert::END_OF_FILE:
1122 throw error("EOF in an expression");
1123
1124 case smt2_tokenizert::CLOSE:
1125 case smt2_tokenizert::STRING_LITERAL:
1126 case smt2_tokenizert::NONE:
1127 case smt2_tokenizert::KEYWORD:
1128 throw error("unexpected token in an expression");
1129 }
1130
1132}
1133
1135{
1136 expressions["true"] = [] { return true_exprt(); };
1137 expressions["false"] = [] { return false_exprt(); };
1138
1139 expressions["roundNearestTiesToEven"] = [] {
1140 // we encode as 32-bit unsignedbv
1142 };
1143
1144 expressions["RNE"] = [] {
1145 // we encode as 32-bit unsignedbv
1147 };
1148
1149 expressions["roundNearestTiesToAway"] = [] {
1150 // we encode as 32-bit unsignedbv
1152 };
1153
1154 expressions["RNA"] = [] {
1155 // we encode as 32-bit unsignedbv
1157 };
1158
1159 expressions["roundTowardPositive"] = [] {
1160 // we encode as 32-bit unsignedbv
1162 };
1163
1164 expressions["RTP"] = [] {
1165 // we encode as 32-bit unsignedbv
1167 };
1168
1169 expressions["roundTowardNegative"] = [] {
1170 // we encode as 32-bit unsignedbv
1172 };
1173
1174 expressions["RTN"] = [] {
1175 // we encode as 32-bit unsignedbv
1177 };
1178
1179 expressions["roundTowardZero"] = [] {
1180 // we encode as 32-bit unsignedbv
1182 };
1183
1184 expressions["RTZ"] = [] {
1185 // we encode as 32-bit unsignedbv
1187 };
1188
1189 expressions["lambda"] = [this] { return lambda_expression(); };
1190 expressions["let"] = [this] { return let_expression(); };
1191 expressions["exists"] = [this] { return quantifier_expression(ID_exists); };
1192 expressions["forall"] = [this] { return quantifier_expression(ID_forall); };
1193 expressions["and"] = [this] { return multi_ary(ID_and, operands()); };
1194 expressions["or"] = [this] { return multi_ary(ID_or, operands()); };
1195 expressions["xor"] = [this] { return multi_ary(ID_xor, operands()); };
1196 expressions["not"] = [this] { return unary(ID_not, operands()); };
1197 expressions["="] = [this] { return binary_predicate(ID_equal, operands()); };
1198 expressions["<="] = [this] { return binary_predicate(ID_le, operands()); };
1199 expressions[">="] = [this] { return binary_predicate(ID_ge, operands()); };
1200 expressions["<"] = [this] { return binary_predicate(ID_lt, operands()); };
1201 expressions[">"] = [this] { return binary_predicate(ID_gt, operands()); };
1202
1203 expressions["bvule"] = [this] { return binary_predicate(ID_le, operands()); };
1204
1205 expressions["bvsle"] = [this] {
1207 };
1208
1209 expressions["bvuge"] = [this] { return binary_predicate(ID_ge, operands()); };
1210
1211 expressions["bvsge"] = [this] {
1213 };
1214
1215 expressions["bvult"] = [this] { return binary_predicate(ID_lt, operands()); };
1216
1217 expressions["bvslt"] = [this] {
1219 };
1220
1221 expressions["bvugt"] = [this] { return binary_predicate(ID_gt, operands()); };
1222
1223 expressions["bvsgt"] = [this] {
1225 };
1226
1227 expressions["bvcomp"] = [this] {
1228 auto b0 = from_integer(0, unsignedbv_typet(1));
1229 auto b1 = from_integer(1, unsignedbv_typet(1));
1231 };
1232
1233 expressions["bvashr"] = [this] {
1235 };
1236
1237 expressions["bvlshr"] = [this] { return binary(ID_lshr, operands()); };
1238 expressions["bvshr"] = [this] { return binary(ID_lshr, operands()); };
1239 expressions["bvlshl"] = [this] { return binary(ID_shl, operands()); };
1240 expressions["bvashl"] = [this] { return binary(ID_shl, operands()); };
1241 expressions["bvshl"] = [this] { return binary(ID_shl, operands()); };
1242 expressions["bvand"] = [this] { return multi_ary(ID_bitand, operands()); };
1243 expressions["bvnand"] = [this] { return multi_ary(ID_bitnand, operands()); };
1244 expressions["bvor"] = [this] { return multi_ary(ID_bitor, operands()); };
1245 expressions["bvnor"] = [this] { return multi_ary(ID_bitnor, operands()); };
1246 expressions["bvxor"] = [this] { return multi_ary(ID_bitxor, operands()); };
1247 expressions["bvxnor"] = [this] { return multi_ary(ID_bitxnor, operands()); };
1248 expressions["bvnot"] = [this] { return unary(ID_bitnot, operands()); };
1249 expressions["bvneg"] = [this] { return unary(ID_unary_minus, operands()); };
1250 expressions["bvadd"] = [this] { return multi_ary(ID_plus, operands()); };
1251 expressions["+"] = [this] { return multi_ary(ID_plus, operands()); };
1252 expressions["bvsub"] = [this] { return binary(ID_minus, operands()); };
1253 expressions["bvmul"] = [this] { return multi_ary(ID_mult, operands()); };
1254 expressions["*"] = [this] { return multi_ary(ID_mult, operands()); };
1255
1256 expressions["-"] = [this] {
1257 auto op = operands();
1258 if(op.size() == 1)
1259 return unary(ID_unary_minus, op);
1260 else
1261 return binary(ID_minus, op);
1262 };
1263
1264 expressions["bvsdiv"] = [this] { return bv_division(operands(), true); };
1265 expressions["bvudiv"] = [this] { return bv_division(operands(), false); };
1266 expressions["/"] = [this] { return binary(ID_div, operands()); };
1267 expressions["div"] = [this] { return binary(ID_div, operands()); };
1268
1269 expressions["bvsrem"] = [this] { return bv_mod(operands(), true); };
1270 expressions["bvurem"] = [this] { return bv_mod(operands(), false); };
1271
1272 // 2's complement signed remainder (sign follows divisor)
1273 // We don't have that.
1274 expressions["bvsmod"] = [this] { return bv_mod(operands(), true); };
1275
1276 expressions["mod"] = [this] {
1277 // SMT-LIB2 uses Boute's Euclidean definition for mod,
1278 // which is never negative and undefined when the second
1279 // argument is zero.
1280 return binary(ID_euclidean_mod, operands());
1281 };
1282
1283 expressions["concat"] = [this] {
1284 auto op = operands();
1285
1286 // add the widths
1287 auto op_width = make_range(op).map(
1288 [](const exprt &o) { return to_bitvector_type(o.type()).get_width(); });
1289
1290 const std::size_t total_width =
1291 std::accumulate(op_width.begin(), op_width.end(), 0);
1292
1293 return concatenation_exprt(std::move(op), unsignedbv_typet(total_width));
1294 };
1295
1296 expressions["distinct"] = [this] {
1297 // pair-wise different constraint, multi-ary
1298 auto op = operands();
1299 if(op.size() == 2)
1300 return binary_predicate(ID_notequal, op);
1301 else
1302 {
1303 std::vector<exprt> pairwise_constraints;
1304 for(std::size_t i = 0; i < op.size(); i++)
1305 {
1306 for(std::size_t j = i; j < op.size(); j++)
1307 {
1308 if(i != j)
1309 pairwise_constraints.push_back(
1310 binary_exprt(op[i], ID_notequal, op[j], bool_typet()));
1311 }
1312 }
1314 }
1315 };
1316
1317 expressions["ite"] = [this] {
1318 auto op = operands();
1319
1320 if(op.size() != 3)
1321 throw error("ite takes three operands");
1322
1323 if(!op[0].is_boolean())
1324 throw error("ite takes a boolean as first operand");
1325
1326 if(op[1].type() != op[2].type())
1327 throw error("ite needs matching types");
1328
1329 return if_exprt(op[0], op[1], op[2]);
1330 };
1331
1332 expressions["implies"] = [this] { return binary(ID_implies, operands()); };
1333
1334 expressions["=>"] = [this] { return binary(ID_implies, operands()); };
1335
1336 expressions["select"] = [this] {
1337 auto op = operands();
1338
1339 // array index
1340 if(op.size() != 2)
1341 throw error("select takes two operands");
1342
1343 if(op[0].type().id() != ID_array)
1344 throw error("select expects array operand");
1345
1346 return index_exprt(op[0], op[1]);
1347 };
1348
1349 expressions["store"] = [this] {
1350 auto op = operands();
1351
1352 // array update
1353 if(op.size() != 3)
1354 throw error("store takes three operands");
1355
1356 if(op[0].type().id() != ID_array)
1357 throw error("store expects array operand");
1358
1359 if(to_array_type(op[0].type()).element_type() != op[2].type())
1360 throw error("store expects value that matches array element type");
1361
1362 return with_exprt(op[0], op[1], op[2]);
1363 };
1364
1365 // Helper: parse and validate a single FloatingPoint operand.
1366 auto fp_unary_operand = [this](const std::string &name)
1367 {
1368 auto op = operands();
1369
1370 if(op.size() != 1)
1371 throw error(name + " takes one operand");
1372
1373 if(op[0].type().id() != ID_floatbv)
1374 throw error(name + " takes FloatingPoint operand");
1375
1376 return std::move(op[0]);
1377 };
1378
1379 expressions["fp.abs"] = [fp_unary_operand]
1380 { return abs_exprt{fp_unary_operand("fp.abs")}; };
1381
1382 expressions["fp.isNaN"] = [fp_unary_operand]
1383 { return isnan_exprt{fp_unary_operand("fp.isNaN")}; };
1384
1385 expressions["fp.isInfinite"] = [fp_unary_operand]
1386 { return isinf_exprt{fp_unary_operand("fp.isInfinite")}; };
1387
1388 expressions["fp.isNormal"] = [fp_unary_operand]
1389 { return isnormal_exprt{fp_unary_operand("fp.isNormal")}; };
1390
1391 expressions["fp.isZero"] = [fp_unary_operand]
1392 {
1393 return not_exprt{
1394 typecast_exprt{fp_unary_operand("fp.isZero"), bool_typet{}}};
1395 };
1396
1397 expressions["fp.isSubnormal"] = [fp_unary_operand]
1398 {
1399 auto op = fp_unary_operand("fp.isSubnormal");
1400
1401 // subnormal iff finite, non-zero, and not normal -- mirrors
1402 // SMT-LIB's own definition of fp.isSubnormal (Theory of
1403 // Floating-Point Numbers).
1404 //
1405 // Do *not* turn the third reference to `op` below into
1406 // `std::move(op)` to avoid the extra copy. Although C++17
1407 // [dcl.init.list]/4 mandates left-to-right evaluation of the
1408 // initializer-clauses of a braced-init-list, MSVC's
1409 // implementation has been unreliable for direct-list-init of a
1410 // constructor (observed under cl.exe on the windows-2022 and
1411 // windows-2025 GitHub Actions runners). With the move, the
1412 // last clause is sequenced before the earlier clauses read
1413 // `op`; the earlier clauses then see a moved-from `op` whose
1414 // `type()` is `nil`, which trips
1415 // `boolbv_widtht::get_entry(nil)` further down the conversion
1416 // pipeline. Three copies are correct, portable, and cheap
1417 // (irept uses sharing, so each copy is a refcount bump).
1418 return and_exprt{
1419 isfinite_exprt{op},
1420 typecast_exprt{op, bool_typet{}}, // != 0
1422 };
1423
1424 expressions["fp.isNegative"] = [fp_unary_operand]
1425 {
1426 auto op = fp_unary_operand("fp.isNegative");
1427
1428 // negative iff sign bit is 1 and not NaN. The explicit
1429 // not(isnan) is required: float_bvt::sign_bit returns the raw
1430 // top bit of the bit-vector encoding (true for -NaN), whereas
1431 // SMT-LIB's fp.isNegative is false for any NaN. Do not drop the
1432 // NaN guard.
1433 return and_exprt{not_exprt{isnan_exprt{op}}, sign_exprt{op}};
1434 };
1435
1436 expressions["fp.isPositive"] = [fp_unary_operand]
1437 {
1438 auto op = fp_unary_operand("fp.isPositive");
1439
1440 // positive iff sign bit is 0 and not NaN
1442 };
1443
1444 expressions["fp"] = [this] { return function_application_fp(operands()); };
1445
1446 expressions["fp.add"] = [this] {
1447 return function_application_ieee_float_op("fp.add", operands());
1448 };
1449
1450 expressions["fp.mul"] = [this] {
1451 return function_application_ieee_float_op("fp.mul", operands());
1452 };
1453
1454 expressions["fp.sub"] = [this] {
1455 return function_application_ieee_float_op("fp.sub", operands());
1456 };
1457
1458 expressions["fp.div"] = [this] {
1459 return function_application_ieee_float_op("fp.div", operands());
1460 };
1461
1462 expressions["fp.rem"] = [this] {
1463 auto op = operands();
1464
1465 // Note that these do not have a rounding mode.
1466 if(op.size() != 2)
1467 throw error() << "fp.rem takes three operands";
1468
1469 if(op[0].type().id() != ID_floatbv || op[1].type().id() != ID_floatbv)
1470 throw error() << "fp.rem takes FloatingPoint operands";
1471
1472 if(op[0].type() != op[1].type())
1473 {
1474 throw error()
1475 << "fp.rem takes FloatingPoint operands with matching sort, "
1476 << "but got " << smt2_format(op[0].type()) << " vs "
1477 << smt2_format(op[1].type());
1478 }
1479
1480 return binary_exprt(op[0], ID_floatbv_rem, op[1]);
1481 };
1482
1483 expressions["fp.fma"] = [this]
1484 {
1485 auto op = operands();
1486
1487 if(op.size() != 4)
1488 throw error() << "fp.fma takes four operands";
1489
1490 if(
1491 op[1].type().id() != ID_floatbv || op[2].type().id() != ID_floatbv ||
1492 op[3].type().id() != ID_floatbv)
1493 {
1494 throw error() << "fp.fma takes FloatingPoint operands";
1495 }
1496
1497 // op[0] = rounding mode, op[1..3] = FP operands
1498 return floatbv_fma_exprt(op[1], op[2], op[3], op[0]);
1499 };
1500
1501 expressions["fp.roundToIntegral"] = [this]
1502 {
1503 auto op = operands();
1504
1505 if(op.size() != 2)
1506 throw error() << "fp.roundToIntegral takes two operands";
1507
1508 if(op[1].type().id() != ID_floatbv)
1509 throw error() << "fp.roundToIntegral takes a FloatingPoint operand";
1510
1511 // Note swapped order.
1512 return floatbv_round_to_integral_exprt(op[1], op[0]);
1513 };
1514
1515 expressions["fp.eq"] = [this] {
1517 };
1518
1519 expressions["fp.leq"] = [this] {
1520 return binary_predicate(ID_le, operands());
1521 };
1522
1523 expressions["fp.lt"] = [this] { return binary_predicate(ID_lt, operands()); };
1524
1525 expressions["fp.geq"] = [this] {
1526 return binary_predicate(ID_ge, operands());
1527 };
1528
1529 expressions["fp.gt"] = [this] { return binary_predicate(ID_gt, operands()); };
1530
1531 expressions["fp.neg"] = [this] { return unary(ID_unary_minus, operands()); };
1532}
1533
1535{
1536 std::vector<typet> sorts;
1537
1538 // (-> sort+ sort)
1539 // The last sort is the co-domain.
1540
1541 while(smt2_tokenizer.peek() != smt2_tokenizert::CLOSE)
1542 {
1543 if(smt2_tokenizer.peek() == smt2_tokenizert::END_OF_FILE)
1544 throw error() << "unexpected end-of-file in a function sort";
1545
1546 sorts.push_back(sort()); // recursive call
1547 }
1548
1549 next_token(); // eat the ')'
1550
1551 if(sorts.size() < 2)
1552 throw error() << "expected function sort to have at least 2 type arguments";
1553
1554 auto codomain = std::move(sorts.back());
1555 sorts.pop_back();
1556
1557 return mathematical_function_typet(std::move(sorts), std::move(codomain));
1558}
1559
1561{
1562 // a sort is one of the following three cases:
1563 // SYMBOL
1564 // ( _ SYMBOL ...
1565 // ( SYMBOL ...
1566 auto sort_token = next_token();
1567
1568 switch(sort_token)
1569 {
1570 case smt2_tokenizert::SYMBOL:
1571 break;
1572
1573 case smt2_tokenizert::OPEN:
1574 {
1575 auto inner_token = next_token();
1576 if(inner_token != smt2_tokenizert::SYMBOL)
1577 throw error("expected symbol after '(' in a sort ");
1578
1579 if(inner_token.text == "_")
1580 {
1582 if(sort_token != smt2_tokenizert::SYMBOL)
1583 throw error("expected symbol after '_' in a sort");
1584 }
1585 else
1586 {
1587 sort_token = std::move(inner_token);
1588 }
1589 break;
1590 }
1591
1592 case smt2_tokenizert::CLOSE:
1593 case smt2_tokenizert::NUMERAL:
1594 case smt2_tokenizert::STRING_LITERAL:
1595 case smt2_tokenizert::NONE:
1596 case smt2_tokenizert::KEYWORD:
1597 throw error() << "unexpected token in a sort: '" << sort_token.text << '\'';
1598
1599 case smt2_tokenizert::END_OF_FILE:
1600 throw error() << "unexpected end-of-file in a sort";
1601 }
1602
1603 // now we have a SYMBOL
1604 const auto &token = sort_token.text;
1605
1606 const auto s_it = sorts.find(token);
1607
1608 if(s_it == sorts.end())
1609 throw error() << "unexpected sort: '" << token << '\'';
1610
1611 return s_it->second();
1612}
1613
1615{
1616 sorts["Bool"] = [] { return bool_typet(); };
1617 sorts["Int"] = [] { return integer_typet(); };
1618 sorts["Real"] = [] { return real_typet(); };
1619
1620 sorts["Float16"] = [] {
1621 return ieee_float_spect::half_precision().to_type();
1622 };
1623 sorts["Float32"] = [] {
1624 return ieee_float_spect::single_precision().to_type();
1625 };
1626 sorts["Float64"] = [] {
1627 return ieee_float_spect::double_precision().to_type();
1628 };
1629 sorts["Float128"] = [] {
1630 return ieee_float_spect::quadruple_precision().to_type();
1631 };
1632
1633 sorts["BitVec"] = [this]
1634 {
1635 auto width_token = next_token();
1636 if(width_token != smt2_tokenizert::NUMERAL)
1637 throw error("expected numeral as bit-width");
1638
1639 auto width = std::stoll(width_token.text);
1640
1641 // eat the ')'
1642 if(next_token() != smt2_tokenizert::CLOSE)
1643 throw error("expected ')' at end of sort");
1644
1645 return unsignedbv_typet(width);
1646 };
1647
1648 sorts["FloatingPoint"] = [this]
1649 {
1650 auto e_token = next_token();
1651 if(e_token != smt2_tokenizert::NUMERAL)
1652 throw error("expected numeral as bit-width");
1653
1654 const auto width_e = std::stoll(e_token.text);
1655
1656 auto f_token = next_token();
1657 if(f_token != smt2_tokenizert::NUMERAL)
1658 throw error("expected numeral as bit-width");
1659
1660 const auto width_f = std::stoll(f_token.text);
1661
1662 // consume the ')'
1663 if(next_token() != smt2_tokenizert::CLOSE)
1664 throw error("expected ')' at end of sort");
1665
1666 return ieee_float_spect(width_f - 1, width_e).to_type();
1667 };
1668
1669 sorts["Array"] = [this] {
1670 // this gets two sorts as arguments, domain and range
1671 auto domain = sort();
1672 auto range = sort();
1673
1674 // eat the ')'
1675 if(next_token() != smt2_tokenizert::CLOSE)
1676 throw error("expected ')' at end of Array sort");
1677
1678 // we can turn arrays that map an unsigned bitvector type
1679 // to something else into our 'array_typet'
1680 if(domain.id() == ID_unsignedbv)
1681 return array_typet(range, infinity_exprt(domain));
1682 else
1683 throw error("unsupported array sort");
1684 };
1685
1686 sorts["->"] = [this] { return function_sort(); };
1687}
1688
1691{
1692 if(next_token() != smt2_tokenizert::OPEN)
1693 throw error("expected '(' at beginning of signature");
1694
1695 if(smt2_tokenizer.peek() == smt2_tokenizert::CLOSE)
1696 {
1697 // no parameters
1698 next_token(); // eat the ')'
1700 }
1701
1703 std::vector<irep_idt> parameters;
1704
1705 while(smt2_tokenizer.peek() != smt2_tokenizert::CLOSE)
1706 {
1707 if(next_token() != smt2_tokenizert::OPEN)
1708 throw error("expected '(' at beginning of parameter");
1709
1710 auto param_token = next_token();
1711 if(param_token != smt2_tokenizert::SYMBOL)
1712 throw error("expected symbol in parameter");
1713
1714 irep_idt id = param_token.text;
1715 domain.push_back(sort());
1716 parameters.push_back(id);
1717
1718 if(next_token() != smt2_tokenizert::CLOSE)
1719 throw error("expected ')' at end of parameter");
1720 }
1721
1722 next_token(); // eat the ')'
1723
1724 typet codomain = sort();
1725
1727 mathematical_function_typet(domain, codomain), parameters);
1728}
1729
1731{
1732 if(next_token() != smt2_tokenizert::OPEN)
1733 throw error("expected '(' at beginning of signature");
1734
1735 if(smt2_tokenizer.peek() == smt2_tokenizert::CLOSE)
1736 {
1737 next_token(); // eat the ')'
1738 return sort();
1739 }
1740
1742
1743 while(smt2_tokenizer.peek() != smt2_tokenizert::CLOSE)
1744 domain.push_back(sort());
1745
1746 next_token(); // eat the ')'
1747
1748 typet codomain = sort();
1749
1750 return mathematical_function_typet(domain, codomain);
1751}
1752
1753void smt2_parsert::command(const std::string &c)
1754{
1755 auto c_it = commands.find(c);
1756 if(c_it == commands.end())
1757 {
1758 // silently ignore
1760 }
1761 else
1762 c_it->second();
1763}
1764
1766{
1767 commands["declare-const"] = [this]()
1768 {
1769 auto id_token = next_token();
1770 if(id_token != smt2_tokenizert::SYMBOL)
1771 throw error("expected a symbol after declare-const");
1772
1773 irep_idt id = id_token.text;
1774 auto type = sort();
1775
1776 add_unique_id(id, exprt(ID_nil, type));
1777 };
1778
1779 // declare-var appears to be a synonym for declare-const that is
1780 // accepted by Z3 and CVC4
1781 commands["declare-var"] = commands["declare-const"];
1782
1783 commands["declare-fun"] = [this]()
1784 {
1785 auto id_token = next_token();
1786 if(id_token != smt2_tokenizert::SYMBOL)
1787 throw error("expected a symbol after declare-fun");
1788
1789 irep_idt id = id_token.text;
1790 auto type = function_signature_declaration();
1791
1792 add_unique_id(id, exprt(ID_nil, type));
1793 };
1794
1795 commands["define-const"] = [this]()
1796 {
1797 auto id_token = next_token();
1798 if(id_token != smt2_tokenizert::SYMBOL)
1799 throw error("expected a symbol after define-const");
1800
1801 const irep_idt id = id_token.text;
1802
1803 const auto type = sort();
1804 const auto value = expression();
1805
1806 // check type of value
1807 if(value.type() != type)
1808 {
1809 throw error() << "type mismatch in constant definition: expected '"
1810 << smt2_format(type) << "' but got '"
1811 << smt2_format(value.type()) << '\'';
1812 }
1813
1814 // create the entry
1815 add_unique_id(id, value);
1816 };
1817
1818 commands["define-fun"] = [this]()
1819 {
1820 auto id_token = next_token();
1821 if(id_token != smt2_tokenizert::SYMBOL)
1822 throw error("expected a symbol after define-fun");
1823
1824 const irep_idt id = id_token.text;
1825
1826 const auto signature = function_signature_definition();
1827
1828 // put the parameters into the scope and take care of hiding
1829 std::vector<std::pair<irep_idt, idt>> hidden_ids;
1830
1831 for(const auto &pair : signature.ids_and_types())
1832 {
1833 auto insert_result =
1834 id_map.insert({pair.first, idt{idt::PARAMETER, pair.second}});
1835 if(!insert_result.second) // already there
1836 {
1837 auto &id_entry = *insert_result.first;
1838 hidden_ids.emplace_back(id_entry.first, std::move(id_entry.second));
1839 id_entry.second = idt{idt::PARAMETER, pair.second};
1840 }
1841 }
1842
1843 // now parse body with parameter ids in place
1844 auto body = expression();
1845
1846 // remove the parameter ids
1847 for(auto &id : signature.parameters)
1848 id_map.erase(id);
1849
1850 // restore the hidden ids, if any
1851 for(auto &hidden_id : hidden_ids)
1852 id_map.insert(std::move(hidden_id));
1853
1854 // check type of body
1855 if(signature.type.id() == ID_mathematical_function)
1856 {
1857 const auto &f_signature = to_mathematical_function_type(signature.type);
1858 if(body.type() != f_signature.codomain())
1859 {
1860 throw error() << "type mismatch in function definition: expected '"
1861 << smt2_format(f_signature.codomain()) << "' but got '"
1862 << smt2_format(body.type()) << '\'';
1863 }
1864 }
1865 else if(body.type() != signature.type)
1866 {
1867 throw error() << "type mismatch in function definition: expected '"
1868 << smt2_format(signature.type) << "' but got '"
1869 << smt2_format(body.type()) << '\'';
1870 }
1871
1872 // if there are parameters, this is a lambda
1873 if(!signature.parameters.empty())
1874 body = lambda_exprt(signature.binding_variables(), body);
1875
1876 // create the entry
1877 add_unique_id(id, std::move(body));
1878 };
1879
1880 commands["exit"] = [this]() { exit = true; };
1881}
constant_exprt from_integer(const mp_integer &int_value, const typet &type)
API to expression classes for bitvectors.
Pre-defined bitvector types.
const bitvector_typet & to_bitvector_type(const typet &type)
Cast a typet to a bitvector_typet.
const unsignedbv_typet & to_unsignedbv_type(const typet &type)
Cast a typet to an unsignedbv_typet.
const signedbv_typet & to_signedbv_type(const typet &type)
Cast a typet to a signedbv_typet.
Absolute value.
Definition std_expr.h:440
ait supplies three of the four components needed: an abstract interpreter (in this case handling func...
Definition ai.h:566
Boolean AND All operands must be boolean, and the result is always boolean.
Definition std_expr.h:2043
Array constructor from single element.
Definition std_expr.h:1512
Arrays with given size.
Definition std_types.h:806
A base class for binary expressions.
Definition std_expr.h:649
A base class for expressions that are predicates, i.e., Boolean-typed, and that take exactly two argu...
Definition std_expr.h:737
std::vector< symbol_exprt > variablest
Definition std_expr.h:3172
The Boolean type.
Definition std_types.h:35
Fixed-width bit-vector without numerical interpretation.
Concatenation of bit-vector operands.
A constant literal expression.
Definition std_expr.h:3007
Division.
Definition std_expr.h:1152
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition dstring.h:38
Equality.
Definition std_expr.h:1339
Base class for all expressions.
Definition expr.h:57
std::vector< exprt > operandst
Definition expr.h:59
typet & type()
Return the type of the expression.
Definition expr.h:85
operandst & operands()
Definition expr.h:95
Extracts a sub-range of a bit-vector operand.
The Boolean constant false.
Definition std_expr.h:3135
Fused multiply-add expression: round(op0 * op1 + op2) with a single rounding.
Round a floating-point number to an integral value considering the given rounding mode.
Semantic type conversion from/to floating-point formats.
Application of (mathematical) function.
IEEE-floating-point equality.
IEEE floating-point operations These have two data operands (op0 and op1) and one rounding mode (op2)...
static ieee_float_spect half_precision()
Definition ieee_float.h:63
static ieee_float_spect single_precision()
Definition ieee_float.h:70
static ieee_float_spect quadruple_precision()
Definition ieee_float.h:82
class floatbv_typet to_type() const
static ieee_float_spect double_precision()
Definition ieee_float.h:76
std::size_t width() const
Definition ieee_float.h:50
static ieee_float_valuet minus_infinity(const ieee_float_spect &_spec)
Definition ieee_float.h:209
static ieee_float_valuet NaN(const ieee_float_spect &_spec)
Definition ieee_float.h:195
static ieee_float_valuet plus_infinity(const ieee_float_spect &_spec)
Definition ieee_float.h:202
An IEEE 754 value plus a rounding mode, enabling operations with rounding on values.
Definition ieee_float.h:338
The trinary if-then-else operator.
Definition std_expr.h:2426
Array index operator.
Definition std_expr.h:1431
An expression denoting infinity.
Definition std_expr.h:3160
Unbounded, signed integers (mathematical integers, not bitvectors)
void set(const irep_idt &name, const irep_idt &value)
Definition irep.h:412
const irep_idt & id() const
Definition irep.h:388
Evaluates to true if the operand is finite.
Evaluates to true if the operand is infinite.
Evaluates to true if the operand is NaN.
Evaluates to true if the operand is a normal number.
A (mathematical) lambda expression.
A let expression.
Definition std_expr.h:3259
A type for mathematical functions (do not confuse with functions/methods in code)
Modulo defined as lhs-(rhs * truncate(lhs/rhs)).
Definition std_expr.h:1216
The NIL expression.
Definition std_expr.h:3144
Boolean negation.
Definition std_expr.h:2388
A base class for quantifier expressions.
Unbounded, signed real numbers.
Bit-vector replication.
Sign of an expression Predicate is true if _op is negative, false otherwise.
Definition std_expr.h:612
Fixed-width bit-vector with two's complement interpretation.
exprt function_application_ieee_float_op(const irep_idt &, const exprt::operandst &)
std::size_t parenthesis_level
Definition smt2_parser.h:94
void command(const std::string &)
exprt::operandst operands()
void command_sequence()
exprt bv_mod(const exprt::operandst &, bool is_signed)
exprt binary(irep_idt, const exprt::operandst &)
exprt bv_division(const exprt::operandst &, bool is_signed)
void skip_to_end_of_list()
This skips tokens until all bracketed expressions are closed.
std::unordered_map< std::string, std::function< exprt()> > expressions
exprt lambda_expression()
typet function_signature_declaration()
named_termst named_terms
Definition smt2_parser.h:74
id_mapt id_map
Definition smt2_parser.h:58
std::unordered_map< std::string, std::function< void()> > commands
exprt function_application()
void add_unique_id(irep_idt, exprt)
exprt cast_bv_to_unsigned(const exprt &)
Apply typecast to unsignedbv to given expression.
exprt::operandst cast_bv_to_signed(const exprt::operandst &)
Apply typecast to signedbv to expressions in vector.
exprt multi_ary(irep_idt, const exprt::operandst &)
void ignore_command()
exprt quantifier_expression(irep_idt)
std::pair< binding_exprt::variablest, exprt > binding(irep_idt)
exprt function_application_ieee_float_eq(const exprt::operandst &)
exprt let_expression()
void check_matching_operand_types(const exprt::operandst &) const
signature_with_parameter_idst function_signature_definition()
exprt function_application_fp(const exprt::operandst &)
typet function_sort()
smt2_tokenizert::smt2_errort error() const
Definition smt2_parser.h:83
void setup_expressions()
exprt binary_predicate(irep_idt, const exprt::operandst &)
smt2_tokenizert::tokent next_token()
std::unordered_map< std::string, std::function< typet()> > sorts
smt2_tokenizert smt2_tokenizer
Definition smt2_parser.h:92
exprt unary(irep_idt, const exprt::operandst &)
void setup_commands()
One SMT-LIB v2.6 token.
tokent next_token()
Consume and return the next token.
const tokent & peek()
Return the next token without consuming it.
Expression to hold a symbol (variable)
Definition std_expr.h:132
void identifier(const irep_idt &identifier)
Definition std_expr.h:160
The Boolean constant true.
Definition std_expr.h:3126
Semantic type conversion.
Definition std_expr.h:1995
The type of an expression, extends irept.
Definition type.h:29
Generic base class for unary expressions.
Definition std_expr.h:364
Fixed-width bit-vector with unsigned binary interpretation.
Operator to update elements in structs and arrays.
Definition std_expr.h:2520
zero extension The operand is converted to the given type by either a) truncating if the new type is ...
bool has_prefix(const std::string &s, const std::string &prefix)
Definition converter.cpp:13
API to expression classes for floating-point arithmetic.
const std::string & id2string(const irep_idt &d)
Definition irep.h:44
API to expression classes for 'mathematical' expressions.
const mathematical_function_typet & to_mathematical_function_type(const typet &type)
Cast a typet to a mathematical_function_typet.
const mp_integer string2integer(const std::string &n, unsigned base)
Definition mp_arith.cpp:54
Ranges: pair of begin and end iterators, which can be initialized from containers,...
ranget< iteratort > make_range(iteratort begin, iteratort end)
Definition range.h:522
static smt2_format_containert< T > smt2_format(const T &_o)
Definition smt2_format.h:28
BigInt mp_integer
Definition smt_terms.h:17
#define CHECK_RETURN(CONDITION)
Definition invariant.h:495
#define UNREACHABLE
This should be used to mark dead code.
Definition invariant.h:525
const constant_exprt & to_constant_expr(const exprt &expr)
Cast an exprt to a constant_exprt.
Definition std_expr.h:3078
const array_typet & to_array_type(const typet &type)
Cast a typet to an array_typet.
Definition std_types.h:887
bool is_signed(const typet &t)
Convenience function – is the type signed?
Definition util.cpp:45