@@ -357,11 +357,14 @@ string_exprt string_constraint_generatort::add_axioms_for_value_of(
357
357
}
358
358
359
359
// / 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
363
366
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)
365
368
{
366
369
symbol_exprt correct=fresh_boolean (" correct_number_format" );
367
370
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(
375
378
exprt chr=str[0 ];
376
379
equal_exprt starts_with_minus (chr, minus_char);
377
380
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);
381
382
382
383
// TODO: we should have implications in the other direction for correct
383
384
// correct => |str| > 0
384
385
exprt non_empty=str.axiom_for_is_longer_than (from_integer (1 , index_type));
385
386
axioms.push_back (implies_exprt (correct, non_empty));
386
387
387
- // correct => (str[0] = '+' or '-' || '0' <= str[0] <= '9' )
388
+ // correct => (str[0] = '+' or '-' || is_digit_with_radix( str[0], radix) )
388
389
or_exprt correct_first (
389
390
or_exprt (starts_with_minus, starts_with_plus), starts_with_digit);
390
391
axioms.push_back (implies_exprt (correct, correct_first));
@@ -399,11 +400,9 @@ exprt string_constraint_generatort::add_axioms_for_correct_number_format(
399
400
axioms.push_back (
400
401
implies_exprt (correct, str.axiom_for_is_shorter_than (max_size)));
401
402
402
- // forall 1 <= qvar < |str| . correct => '0'<= str[qvar] <= '9'
403
+ // forall 1 <= qvar < |str| . correct => is_digit_with_radix( str[qvar], radix)
403
404
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);
407
406
string_constraintt all_digits (
408
407
qvar, from_integer (1 , index_type), str.length (), correct, is_digit);
409
408
axioms.push_back (all_digits);
@@ -412,58 +411,66 @@ exprt string_constraint_generatort::add_axioms_for_correct_number_format(
412
411
}
413
412
414
413
// / 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
416
416
// / \return an integer expression
417
417
exprt string_constraint_generatort::add_axioms_for_parse_int (
418
418
const function_application_exprt &f)
419
419
{
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
+
421
425
const typet &type=f.type ();
422
426
symbol_exprt i=fresh_symbol (" parsed_int" , type);
423
427
const refined_string_typet &ref_type=to_refined_string_type (str.type ());
424
428
const typet &char_type=ref_type.get_char_type ();
425
- exprt zero_char=constant_char (' 0' , char_type);
426
429
exprt minus_char=constant_char (' -' , char_type);
427
430
exprt plus_char=constant_char (' +' , char_type);
428
431
assert (type.id ()==ID_signedbv);
429
- exprt ten=from_integer (10 , type);
430
432
431
433
exprt chr=str[0 ];
432
434
exprt starts_with_minus=equal_exprt (chr, minus_char);
433
435
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));
435
438
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 );
438
441
axioms.push_back (correct);
439
442
443
+ // / TODO(OJones): size should depend on the radix
444
+ // / TODO(OJones): we should deal with overflow properly
440
445
for (unsigned size=1 ; size<=10 ; size++)
441
446
{
442
447
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);
444
450
445
451
for (unsigned j=1 ; j<size; j++)
446
452
{
447
- mult_exprt ten_sum (sum, ten );
453
+ mult_exprt radix_sum (sum, radix );
448
454
if (j>=9 )
449
455
{
450
456
// 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)) );
453
459
axioms.push_back (no_overflow);
454
460
}
455
461
456
462
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));
459
465
460
- mult_exprt first (first_value, ten );
466
+ mult_exprt first (first_value, radix );
461
467
if (j>=9 )
462
468
{
463
469
// We have to be careful about overflows
464
- div_exprt div_first (first, ten );
470
+ div_exprt div_first (first, radix );
465
471
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));
467
474
axioms.push_back (no_overflow_first);
468
475
}
469
476
first_value=first;
@@ -474,7 +481,6 @@ exprt string_constraint_generatort::add_axioms_for_parse_int(
474
481
// a2 : starts_with_plus => i=sum
475
482
// a3 : starts_with_minus => i=-sum
476
483
477
- equal_exprt premise=str.axiom_for_has_length (size);
478
484
implies_exprt a1 (
479
485
and_exprt (premise, starts_with_digit),
480
486
equal_exprt (i, plus_exprt (sum, first_value)));
@@ -490,3 +496,70 @@ exprt string_constraint_generatort::add_axioms_for_parse_int(
490
496
}
491
497
return i;
492
498
}
499
+
500
+ // / Check if a character is a digit with respect to the given radix, e.g. if the
501
+ // / radix is 10 then check if the character is in the range 0-9.
502
+ // / \param chr: the character
503
+ // / \param radix: the radix
504
+ // / \return an expression for the condition
505
+ exprt is_digit_with_radix (exprt chr, exprt radix)
506
+ {
507
+ const typet &char_type=chr.type ();
508
+ exprt zero_char=from_integer (' 0' , char_type);
509
+ exprt nine_char=from_integer (' 9' , char_type);
510
+ exprt a_char=from_integer (' a' , char_type);
511
+ exprt A_char=from_integer (' A' , char_type);
512
+
513
+ and_exprt is_digit_when_radix_le_10 (
514
+ binary_relation_exprt (chr, ID_ge, zero_char),
515
+ binary_relation_exprt (
516
+ chr, ID_lt, plus_exprt (zero_char, typecast_exprt (radix, char_type))));
517
+
518
+ minus_exprt radix_minus_ten (
519
+ typecast_exprt (radix, char_type), from_integer (10 , char_type));
520
+
521
+ or_exprt is_digit_when_radix_gt_10 (
522
+ and_exprt (
523
+ binary_relation_exprt (chr, ID_ge, zero_char),
524
+ binary_relation_exprt (chr, ID_le, nine_char)),
525
+ and_exprt (
526
+ binary_relation_exprt (chr, ID_ge, a_char),
527
+ binary_relation_exprt (chr, ID_lt, plus_exprt (a_char, radix_minus_ten))),
528
+ and_exprt (
529
+ binary_relation_exprt (chr, ID_ge, A_char),
530
+ binary_relation_exprt (chr, ID_lt, plus_exprt (A_char, radix_minus_ten))));
531
+
532
+ return if_exprt (
533
+ binary_relation_exprt (radix, ID_le, from_integer (10 , radix.type ())),
534
+ is_digit_when_radix_le_10,
535
+ is_digit_when_radix_gt_10);
536
+ }
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
+ }
0 commit comments