Skip to content

Commit 4e5d8cc

Browse files
author
Owen Jones
committed
add_axioms_for_parse_int can take optional radix
Updated add_axioms_for_correct_number_format and add_axioms_for_parse_int, and created helper function get_numeric_value_from_character.
1 parent 50732ee commit 4e5d8cc

File tree

4 files changed

+109
-30
lines changed

4 files changed

+109
-30
lines changed

src/solvers/refinement/string_constraint_generator.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,7 @@ class string_constraint_generatort
294294

295295
exprt add_axioms_for_parse_int(const function_application_exprt &f);
296296
exprt add_axioms_for_correct_number_format(
297-
const string_exprt &str, std::size_t max_size=10);
297+
const string_exprt &str, const exprt &radix, std::size_t max_size=10);
298298
exprt add_axioms_for_to_char_array(const function_application_exprt &f);
299299
exprt add_axioms_for_compare_to(const function_application_exprt &f);
300300

@@ -329,5 +329,7 @@ class string_constraint_generatort
329329
};
330330

331331
exprt is_digit_with_radix(exprt chr, exprt radix);
332+
exprt get_numeric_value_from_character(
333+
const exprt &chr, const typet &char_type, const typet &type);
332334

333335
#endif

src/solvers/refinement/string_constraint_generator_valueof.cpp

+64-29
Original file line numberDiff line numberDiff line change
@@ -357,11 +357,14 @@ string_exprt string_constraint_generatort::add_axioms_for_value_of(
357357
}
358358

359359
/// Add axioms making the return value true if the given string is a correct
360-
/// number.
361-
/// \param f: function application with one string expression
362-
/// \return an boolean expression
360+
/// number in the given radix
361+
/// \param str: string expression
362+
/// \param radix: the radix
363+
/// \param max_size: maximum number of characters
364+
/// \return a boolean expression saying whether the string does represent a
365+
/// number with the given radix
363366
exprt string_constraint_generatort::add_axioms_for_correct_number_format(
364-
const string_exprt &str, std::size_t max_size)
367+
const string_exprt &str, const exprt &radix, std::size_t max_size)
365368
{
366369
symbol_exprt correct=fresh_boolean("correct_number_format");
367370
const refined_string_typet &ref_type=to_refined_string_type(str.type());
@@ -375,16 +378,14 @@ exprt string_constraint_generatort::add_axioms_for_correct_number_format(
375378
exprt chr=str[0];
376379
equal_exprt starts_with_minus(chr, minus_char);
377380
equal_exprt starts_with_plus(chr, plus_char);
378-
and_exprt starts_with_digit(
379-
binary_relation_exprt(chr, ID_ge, zero_char),
380-
binary_relation_exprt(chr, ID_le, nine_char));
381+
exprt starts_with_digit=is_digit_with_radix(chr, radix);
381382

382383
// TODO: we should have implications in the other direction for correct
383384
// correct => |str| > 0
384385
exprt non_empty=str.axiom_for_is_longer_than(from_integer(1, index_type));
385386
axioms.push_back(implies_exprt(correct, non_empty));
386387

387-
// correct => (str[0] = '+' or '-' || '0' <= str[0] <= '9')
388+
// correct => (str[0] = '+' or '-' || is_digit_with_radix(str[0], radix))
388389
or_exprt correct_first(
389390
or_exprt(starts_with_minus, starts_with_plus), starts_with_digit);
390391
axioms.push_back(implies_exprt(correct, correct_first));
@@ -399,11 +400,9 @@ exprt string_constraint_generatort::add_axioms_for_correct_number_format(
399400
axioms.push_back(
400401
implies_exprt(correct, str.axiom_for_is_shorter_than(max_size)));
401402

402-
// forall 1 <= qvar < |str| . correct => '0'<= str[qvar] <= '9'
403+
// forall 1 <= qvar < |str| . correct => is_digit_with_radix(str[qvar], radix)
403404
symbol_exprt qvar=fresh_univ_index("number_format", index_type);
404-
and_exprt is_digit(
405-
binary_relation_exprt(str[qvar], ID_ge, zero_char),
406-
binary_relation_exprt(str[qvar], ID_le, nine_char));
405+
exprt is_digit=is_digit_with_radix(str[qvar], radix);
407406
string_constraintt all_digits(
408407
qvar, from_integer(1, index_type), str.length(), correct, is_digit);
409408
axioms.push_back(all_digits);
@@ -412,58 +411,66 @@ exprt string_constraint_generatort::add_axioms_for_correct_number_format(
412411
}
413412

414413
/// add axioms corresponding to the Integer.parseInt java function
415-
/// \param f: function application with one string expression
414+
/// \param f: a function application with either one string expression or one
415+
/// string expression and an expression for the radix
416416
/// \return an integer expression
417417
exprt string_constraint_generatort::add_axioms_for_parse_int(
418418
const function_application_exprt &f)
419419
{
420-
string_exprt str=get_string_expr(args(f, 1)[0]);
420+
PRECONDITION(f.arguments().size()==1 || f.arguments().size()==2);
421+
string_exprt str=get_string_expr(f.arguments()[0]);
422+
const exprt radix=
423+
f.arguments().size()==1?from_integer(10, f.type()):f.arguments()[1];
424+
421425
const typet &type=f.type();
422426
symbol_exprt i=fresh_symbol("parsed_int", type);
423427
const refined_string_typet &ref_type=to_refined_string_type(str.type());
424428
const typet &char_type=ref_type.get_char_type();
425-
exprt zero_char=constant_char('0', char_type);
426429
exprt minus_char=constant_char('-', char_type);
427430
exprt plus_char=constant_char('+', char_type);
428431
assert(type.id()==ID_signedbv);
429-
exprt ten=from_integer(10, type);
430432

431433
exprt chr=str[0];
432434
exprt starts_with_minus=equal_exprt(chr, minus_char);
433435
exprt starts_with_plus=equal_exprt(chr, plus_char);
434-
exprt starts_with_digit=binary_relation_exprt(chr, ID_ge, zero_char);
436+
exprt starts_with_digit=
437+
not_exprt(or_exprt(starts_with_minus, starts_with_plus));
435438

436-
// TODO: we should throw an exception when this does not hold:
437-
exprt correct=add_axioms_for_correct_number_format(str);
439+
/// TODO: we should throw an exception when this does not hold:
440+
exprt correct=add_axioms_for_correct_number_format(str, radix);
438441
axioms.push_back(correct);
439442

443+
/// TODO(OJones): size should depend on the radix
444+
/// TODO(OJones): we should deal with overflow properly
440445
for(unsigned size=1; size<=10; size++)
441446
{
442447
exprt sum=from_integer(0, type);
443-
exprt first_value=typecast_exprt(minus_exprt(chr, zero_char), type);
448+
exprt first_value=get_numeric_value_from_character(chr, char_type, type);
449+
equal_exprt premise=str.axiom_for_has_length(size);
444450

445451
for(unsigned j=1; j<size; j++)
446452
{
447-
mult_exprt ten_sum(sum, ten);
453+
mult_exprt radix_sum(sum, radix);
448454
if(j>=9)
449455
{
450456
// We have to be careful about overflows
451-
div_exprt div(sum, ten);
452-
equal_exprt no_overflow(div, sum);
457+
div_exprt div(sum, radix);
458+
implies_exprt no_overflow(premise, (equal_exprt(div, sum)));
453459
axioms.push_back(no_overflow);
454460
}
455461

456462
sum=plus_exprt_with_overflow_check(
457-
ten_sum,
458-
typecast_exprt(minus_exprt(str[j], zero_char), type));
463+
radix_sum,
464+
get_numeric_value_from_character(str[j], char_type, type));
459465

460-
mult_exprt first(first_value, ten);
466+
mult_exprt first(first_value, radix);
461467
if(j>=9)
462468
{
463469
// We have to be careful about overflows
464-
div_exprt div_first(first, ten);
470+
div_exprt div_first(first, radix);
465471
implies_exprt no_overflow_first(
466-
starts_with_digit, equal_exprt(div_first, first_value));
472+
and_exprt(starts_with_digit, premise),
473+
equal_exprt(div_first, first_value));
467474
axioms.push_back(no_overflow_first);
468475
}
469476
first_value=first;
@@ -474,7 +481,6 @@ exprt string_constraint_generatort::add_axioms_for_parse_int(
474481
// a2 : starts_with_plus => i=sum
475482
// a3 : starts_with_minus => i=-sum
476483

477-
equal_exprt premise=str.axiom_for_has_length(size);
478484
implies_exprt a1(
479485
and_exprt(premise, starts_with_digit),
480486
equal_exprt(i, plus_exprt(sum, first_value)));
@@ -528,3 +534,32 @@ exprt is_digit_with_radix(exprt chr, exprt radix)
528534
is_digit_when_radix_le_10,
529535
is_digit_when_radix_gt_10);
530536
}
537+
538+
/// Get the numeric value of a character, assuming that the radix is large
539+
/// enough
540+
/// \param chr: the character to get the numeric value of
541+
/// \param char_type: the type to use for characters
542+
/// \param type: the type to use for the return value
543+
/// \return an integer expression of the given type with the numeric value of
544+
/// the char
545+
exprt get_numeric_value_from_character(
546+
const exprt &chr, const typet &char_type, const typet &type)
547+
{
548+
constant_exprt zero_char=from_integer('0', char_type);
549+
constant_exprt a_char=from_integer('a', char_type);
550+
constant_exprt A_char=from_integer('A', char_type);
551+
constant_exprt ten_int=from_integer(10, char_type);
552+
553+
binary_relation_exprt upper_case(chr, ID_ge, A_char);
554+
binary_relation_exprt lower_case(chr, ID_ge, a_char);
555+
556+
return typecast_exprt(
557+
if_exprt(
558+
lower_case,
559+
plus_exprt(minus_exprt(chr, a_char), ten_int),
560+
if_exprt(
561+
upper_case,
562+
plus_exprt(minus_exprt(chr, A_char), ten_int),
563+
minus_exprt(chr, zero_char))),
564+
type);
565+
}

unit/Makefile

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
SRC = unit_tests.cpp \
44
catch_example.cpp \
55
solvers/refinement/string_constraint_generator_valueof/is_digit_with_radix.cpp \
6+
solvers/refinement/string_constraint_generator_valueof/get_numeric_value_from_character.cpp \
67
# Empty last line
78

89
INCLUDES= -I ../src/ -I.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*******************************************************************\
2+
3+
Module: Unit tests for get_numeric_value_from_character in
4+
solvers/refinement/string_constraint_generator_valueof.cpp
5+
6+
Author: DiffBlue Limited. All rights reserved.
7+
8+
\*******************************************************************/
9+
10+
#include <catch.hpp>
11+
12+
#include <solvers/refinement/string_constraint_generator.h>
13+
#include <util/namespace.h>
14+
#include <util/symbol_table.h>
15+
#include <util/simplify_expr.h>
16+
#include <util/std_types.h>
17+
18+
SCENARIO("get_numeric_value_from_character",
19+
"[core][solvers][refinement][string_constraint_generator_valueof]")
20+
{
21+
typet char_type=unsignedbv_typet(16);
22+
typet int_type=signedbv_typet(32);
23+
symbol_tablet symtab;
24+
namespacet ns(symtab);
25+
26+
REQUIRE(from_integer(0, int_type)==simplify_expr(
27+
get_numeric_value_from_character(
28+
from_integer('0', char_type), char_type, int_type),ns));
29+
REQUIRE(from_integer(9, int_type)==simplify_expr(
30+
get_numeric_value_from_character(
31+
from_integer('9', char_type),
32+
char_type, int_type), ns));
33+
REQUIRE(from_integer(10, int_type)==simplify_expr(
34+
get_numeric_value_from_character(
35+
from_integer('A', char_type),
36+
char_type, int_type), ns));
37+
REQUIRE(from_integer(35, int_type)==simplify_expr(
38+
get_numeric_value_from_character(
39+
from_integer('z', char_type),
40+
char_type, int_type), ns));
41+
}

0 commit comments

Comments
 (0)