Skip to content

Commit 0eed7fc

Browse files
committed
Updates parser and type checking to handle ranges
We now support ranges on code contracts when specifiying which portions of an array should or should not change. We update the parser and type checking to support this new annotations within assigns clauses. Signed-off-by: Felipe R. Monteiro <[email protected]>
1 parent f899754 commit 0eed7fc

File tree

5 files changed

+149
-1
lines changed

5 files changed

+149
-1
lines changed

src/ansi-c/c_typecheck_base.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ class c_typecheck_baset:
163163
virtual void typecheck_expr_operands(exprt &expr);
164164
virtual void typecheck_expr_comma(exprt &expr);
165165
virtual void typecheck_expr_constant(exprt &expr);
166+
virtual void typecheck_expr_range(exprt &expr);
166167
virtual void typecheck_expr_side_effect(side_effect_exprt &expr);
167168
virtual void typecheck_expr_unary_arithmetic(exprt &expr);
168169
virtual void typecheck_expr_unary_boolean(exprt &expr);

src/ansi-c/c_typecheck_expr.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,10 @@ void c_typecheck_baset::typecheck_expr_main(exprt &expr)
491491
{
492492
// already type checked
493493
}
494+
else if(expr.id() == ID_range)
495+
{
496+
typecheck_expr_range(expr);
497+
}
494498
else
495499
{
496500
error().source_location = expr.source_location();
@@ -499,6 +503,16 @@ void c_typecheck_baset::typecheck_expr_main(exprt &expr)
499503
}
500504
}
501505

506+
void c_typecheck_baset::typecheck_expr_range(exprt &expr)
507+
{
508+
// Already type checked
509+
exprt &lower = to_range_exprt(expr).lower();
510+
exprt &upper = to_range_exprt(expr).upper();
511+
512+
implicit_typecast_arithmetic(lower);
513+
implicit_typecast_arithmetic(upper);
514+
}
515+
502516
void c_typecheck_baset::typecheck_expr_comma(exprt &expr)
503517
{
504518
expr.type() = to_binary_expr(expr).op1().type();

src/ansi-c/parser.y

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ extern char *yyansi_ctext;
102102
%token TOK_ANDAND "&&"
103103
%token TOK_OROR "||"
104104
%token TOK_ELLIPSIS "..."
105+
%token TOK_RANGE ".."
105106

106107
/*** modifying assignment operators ***/
107108

@@ -3243,7 +3244,7 @@ cprover_contract:
32433244
set($$, ID_C_spec_requires);
32443245
mto($$, $3);
32453246
}
3246-
| TOK_CPROVER_ASSIGNS '(' argument_expression_list ')'
3247+
| TOK_CPROVER_ASSIGNS '(' target_list ')'
32473248
{
32483249
$$=$1;
32493250
set($$, ID_C_spec_assigns);
@@ -3252,6 +3253,76 @@ cprover_contract:
32523253
}
32533254
;
32543255

3256+
target_list:
3257+
target
3258+
{
3259+
init($$, ID_target_list);
3260+
mto($$, $1);
3261+
}
3262+
| target_list ',' target
3263+
{
3264+
$$=$1;
3265+
mto($$, $3);
3266+
}
3267+
;
3268+
3269+
target:
3270+
deref_target
3271+
| target '[' array_index ']'
3272+
{ binary($$, $1, $2, ID_range, $3); }
3273+
| target '[' array_range ']'
3274+
{ binary($$, $1, $2, ID_range, $3); }
3275+
;
3276+
3277+
array_index:
3278+
identifier
3279+
| integer
3280+
;
3281+
3282+
array_range:
3283+
array_index TOK_RANGE array_index
3284+
{
3285+
$$=$2;
3286+
set($$, ID_range);
3287+
mto($$, $1);
3288+
mto($$, $3);
3289+
}
3290+
;
3291+
3292+
deref_target:
3293+
member_target
3294+
| '*' deref_target
3295+
{
3296+
$$=$1;
3297+
set($$, ID_dereference);
3298+
mto($$, $2);
3299+
}
3300+
;
3301+
3302+
member_target:
3303+
primary_target
3304+
| member_target '.' member_name
3305+
{
3306+
$$=$2;
3307+
set($$, ID_member);
3308+
mto($$, $1);
3309+
parser_stack($$).set(ID_component_name, parser_stack($3).get(ID_C_base_name));
3310+
}
3311+
| member_target TOK_ARROW member_name
3312+
{
3313+
$$=$2;
3314+
set($$, ID_ptrmember);
3315+
mto($$, $1);
3316+
parser_stack($$).set(ID_component_name, parser_stack($3).get(ID_C_base_name));
3317+
}
3318+
;
3319+
3320+
primary_target:
3321+
identifier
3322+
| '(' target ')'
3323+
{ $$ = $2; }
3324+
;
3325+
32553326
cprover_contract_sequence:
32563327
cprover_contract
32573328
| cprover_contract_sequence cprover_contract

src/ansi-c/scanner.l

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1517,6 +1517,7 @@ __decltype { if(PARSER.cpp98 &&
15171517
"&&" { loc(); return TOK_ANDAND; }
15181518
"||" { loc(); return TOK_OROR; }
15191519
"..." { loc(); return TOK_ELLIPSIS; }
1520+
".." { loc(); return TOK_RANGE; }
15201521

15211522
"*=" { loc(); return TOK_MULTASSIGN; }
15221523
"/=" { loc(); return TOK_DIVASSIGN; }

src/util/std_expr.h

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -824,6 +824,67 @@ inline multi_ary_exprt &to_multi_ary_expr(exprt &expr)
824824
return static_cast<multi_ary_exprt &>(expr);
825825
}
826826

827+
/// \brief A base class for int-range expressions
828+
class range_exprt : public expr_protectedt
829+
{
830+
public:
831+
range_exprt(exprt &lower, exprt &upper, typet _type)
832+
: expr_protectedt(
833+
ID_range,
834+
std::move(_type),
835+
{std::move(lower), std::move(upper)})
836+
{
837+
}
838+
839+
exprt &lower()
840+
{
841+
return op0();
842+
}
843+
844+
const exprt &lower() const
845+
{
846+
return op0();
847+
}
848+
849+
exprt &upper()
850+
{
851+
return op1();
852+
}
853+
854+
const exprt &upper() const
855+
{
856+
return op1();
857+
}
858+
859+
const exprt &op2() const = delete;
860+
exprt &op2() = delete;
861+
const exprt &op3() const = delete;
862+
exprt &op3() = delete;
863+
};
864+
865+
/// \brief Cast an exprt to a \ref range_exprt
866+
///
867+
/// \a expr must be known to be \ref range_exprt.
868+
///
869+
/// \param expr: Source expression
870+
/// \return Object of type \ref range_exprt
871+
inline const range_exprt &to_range_exprt(const exprt &expr)
872+
{
873+
PRECONDITION(expr.id() == ID_range);
874+
return static_cast<const range_exprt &>(expr);
875+
}
876+
877+
/// \brief Cast an exprt to a \ref range_exprt
878+
///
879+
/// \a expr must be known to be \ref range_exprt.
880+
///
881+
/// \param expr: Source expression
882+
/// \return Object of type \ref range_exprt
883+
inline range_exprt &to_range_exprt(exprt &expr)
884+
{
885+
PRECONDITION(expr.id() == ID_range);
886+
return static_cast<range_exprt &>(expr);
887+
}
827888

828889
/// \brief The plus expression
829890
/// Associativity is not specified.

0 commit comments

Comments
 (0)