Skip to content

Commit 82a0a5e

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 29a323f commit 82a0a5e

File tree

5 files changed

+126
-1
lines changed

5 files changed

+126
-1
lines changed

src/ansi-c/c_typecheck_base.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ class c_typecheck_baset:
168168
virtual void typecheck_expr_operands(exprt &expr);
169169
virtual void typecheck_expr_comma(exprt &expr);
170170
virtual void typecheck_expr_constant(exprt &expr);
171+
virtual void typecheck_expr_range(exprt &expr);
171172
virtual void typecheck_expr_side_effect(side_effect_exprt &expr);
172173
virtual void typecheck_expr_unary_arithmetic(exprt &expr);
173174
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: 49 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

@@ -532,15 +533,62 @@ target_list:
532533
;
533534

534535
target:
536+
deref_target
537+
| target '[' array_index ']'
538+
{ binary($$, $1, $2, ID_range, $3); }
539+
| target '[' array_range ']'
540+
{ binary($$, $1, $2, ID_range, $3); }
541+
;
542+
543+
array_index:
535544
identifier
536-
| '*' target
545+
| integer
546+
;
547+
548+
array_range:
549+
array_index TOK_RANGE array_index
550+
{
551+
$$=$2;
552+
set($$, ID_range);
553+
mto($$, $1);
554+
mto($$, $3);
555+
}
556+
;
557+
558+
deref_target:
559+
member_target
560+
| '*' deref_target
537561
{
538562
$$=$1;
539563
set($$, ID_dereference);
540564
mto($$, $2);
541565
}
542566
;
543567

568+
member_target:
569+
primary_target
570+
| member_target '.' member_name
571+
{
572+
$$=$2;
573+
set($$, ID_member);
574+
mto($$, $1);
575+
parser_stack($$).set(ID_component_name, parser_stack($3).get(ID_C_base_name));
576+
}
577+
| member_target TOK_ARROW member_name
578+
{
579+
$$=$2;
580+
set($$, ID_ptrmember);
581+
mto($$, $1);
582+
parser_stack($$).set(ID_component_name, parser_stack($3).get(ID_C_base_name));
583+
}
584+
;
585+
586+
primary_target:
587+
identifier
588+
| '(' target ')'
589+
{ $$ = $2; }
590+
;
591+
544592
statement_expression: '(' compound_statement ')'
545593
{
546594
$$=$1;

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)