1

/********************************************************************/

2

/* */

3

/* The LustreC compiler toolset / The LustreC Development Team */

4

/* Copyright 2012   ONERA  CNRS  INPT */

5

/* */

6

/* LustreC is free software, distributed WITHOUT ANY WARRANTY */

7

/* under the terms of the GNU Lesser General Public License */

8

/* version 2.1. */

9

/* */

10

/********************************************************************/

11


12

%{

13

open Utils

14

open LustreSpec

15

open Corelang

16

open Dimension

17

open Parse

18


19

let get_loc () = Location.symbol_rloc ()

20


21

let mktyp x = mktyp (get_loc ()) x

22

let mkclock x = mkclock (get_loc ()) x

23

let mkvar_decl x = mkvar_decl (get_loc ()) ~orig:true x

24

let mkexpr x = mkexpr (get_loc ()) x

25

let mkeexpr x = mkeexpr (get_loc ()) x

26

let mkeq x = mkeq (get_loc ()) x

27

let mkassert x = mkassert (get_loc ()) x

28

let mktop_decl itf x = mktop_decl (get_loc ()) (Location.get_module ()) itf x

29

let mkpredef_call x = mkpredef_call (get_loc ()) x

30

(*let mkpredef_unary_call x = mkpredef_unary_call (get_loc ()) x*)

31


32

let mkdim_int i = mkdim_int (get_loc ()) i

33

let mkdim_bool b = mkdim_bool (get_loc ()) b

34

let mkdim_ident id = mkdim_ident (get_loc ()) id

35

let mkdim_appl f args = mkdim_appl (get_loc ()) f args

36

let mkdim_ite i t e = mkdim_ite (get_loc ()) i t e

37


38

let mkannots annots = { annots = annots; annot_loc = get_loc () }

39


40

let node_stack : ident list ref = ref []

41

let debug_calls () = Format.eprintf "call stack: %a@.@?" (Utils.fprintf_list ~sep:", " Format.pp_print_string) !node_stack

42

let push_node nd = node_stack:= nd :: !node_stack

43

let pop_node () = try node_stack := List.tl !node_stack with _ > assert false

44

let get_current_node () = try List.hd !node_stack with _ > assert false

45


46

let rec fby expr n init =

47

if n<=1 then

48

mkexpr (Expr_arrow (init, mkexpr (Expr_pre expr)))

49

else

50

mkexpr (Expr_arrow (init, mkexpr (Expr_pre (fby expr (n1) init))))

51


52

%}

53


54

%token <int> INT

55

%token <string> REAL

56

%token <float> FLOAT

57

%token <string> STRING

58

%token AUTOMATON STATE UNTIL UNLESS RESTART RESUME LAST

59

%token STATELESS ASSERT OPEN QUOTE FUNCTION

60

%token <string> IDENT

61

%token <string> UIDENT

62

%token TRUE FALSE

63

%token <LustreSpec.expr_annot> ANNOT

64

%token <LustreSpec.node_annot> NODESPEC

65

%token LBRACKET RBRACKET LCUR RCUR LPAR RPAR SCOL COL COMMA COLCOL

66

%token AMPERAMPER BARBAR NOT POWER

67

%token IF THEN ELSE

68

%token UCLOCK DCLOCK PHCLOCK TAIL

69

%token MERGE FBY WHEN WHENNOT EVERY

70

%token NODE LET TEL RETURNS VAR IMPORTED SENSOR ACTUATOR WCET TYPE CONST

71

%token STRUCT ENUM

72

%token TINT TFLOAT TREAL TBOOL TCLOCK

73

%token RATE DUE

74

%token EQ LT GT LTE GTE NEQ

75

%token AND OR XOR IMPL

76

%token MULT DIV MOD

77

%token MINUS PLUS UMINUS

78

%token PRE ARROW

79

%token REQUIRES ENSURES OBSERVER

80

%token INVARIANT BEHAVIOR ASSUMES

81

%token EXISTS FORALL

82

%token PROTOTYPE LIB

83

%token EOF

84


85

%nonassoc prec_exists prec_forall

86

%nonassoc COMMA

87

%nonassoc EVERY

88

%left MERGE IF

89

%nonassoc ELSE

90

%right ARROW FBY

91

%left WHEN WHENNOT UCLOCK DCLOCK PHCLOCK

92

%right COLCOL

93

%right IMPL

94

%left OR XOR BARBAR

95

%left AND AMPERAMPER

96

%left NOT

97

%nonassoc INT

98

%nonassoc EQ LT GT LTE GTE NEQ

99

%left MINUS PLUS

100

%left MULT DIV MOD

101

%left UMINUS

102

%left POWER

103

%left PRE LAST

104

%nonassoc RBRACKET

105

%nonassoc LBRACKET

106


107

%start prog

108

%type <LustreSpec.top_decl list> prog

109


110

%start header

111

%type <LustreSpec.top_decl list> header

112


113

%start lustre_annot

114

%type <LustreSpec.expr_annot> lustre_annot

115


116

%start lustre_spec

117

%type <LustreSpec.node_annot> lustre_spec

118


119

%%

120


121

module_ident:

122

UIDENT { $1 }

123

 IDENT { $1 }

124


125

tag_ident:

126

UIDENT { $1 }

127

 TRUE { tag_true }

128

 FALSE { tag_false }

129


130

node_ident:

131

UIDENT { $1 }

132

 IDENT { $1 }

133


134

node_ident_decl:

135

node_ident { push_node $1; $1 }

136


137

vdecl_ident:

138

UIDENT { $1 }

139

 IDENT { $1 }

140


141

const_ident:

142

UIDENT { $1 }

143

 IDENT { $1 }

144


145

type_ident:

146

IDENT { $1 }

147


148

prog:

149

open_list typ_def_prog top_decl_list EOF { $1 @ $2 @ (List.rev $3) }

150


151

typ_def_prog:

152

typ_def_list { $1 false }

153


154

header:

155

open_list typ_def_header top_decl_header_list EOF { $1 @ $2 @ (List.rev $3) }

156


157

typ_def_header:

158

typ_def_list { $1 true }

159


160

open_list:

161

{ [] }

162

 open_lusi open_list { $1 :: $2 }

163


164

open_lusi:

165

 OPEN QUOTE module_ident QUOTE { mktop_decl false (Open (true, $3))}

166

 OPEN LT module_ident GT { mktop_decl false (Open (false, $3)) }

167


168

top_decl_list:

169

{[]}

170

 top_decl_list top_decl {$2@$1}

171


172


173

top_decl_header_list:

174

{ [] }

175

 top_decl_header_list top_decl_header { $2@$1 }

176


177

state_annot:

178

FUNCTION { true }

179

 NODE { false }

180


181

top_decl_header:

182

 CONST cdecl_list { List.rev ($2 true) }

183

 nodespec_list state_annot node_ident LPAR vdecl_list SCOL_opt RPAR RETURNS LPAR vdecl_list SCOL_opt RPAR prototype_opt in_lib_opt SCOL

184

{let nd = mktop_decl true (ImportedNode

185

{nodei_id = $3;

186

nodei_type = Types.new_var ();

187

nodei_clock = Clocks.new_var true;

188

nodei_inputs = List.rev $5;

189

nodei_outputs = List.rev $10;

190

nodei_stateless = $2;

191

nodei_spec = $1;

192

nodei_prototype = $13;

193

nodei_in_lib = $14;})

194

in

195

(*add_imported_node $3 nd;*) [nd] }

196


197

prototype_opt:

198

{ None }

199

 PROTOTYPE node_ident { Some $2}

200


201

in_lib_opt:

202

{ None }

203

 LIB module_ident {Some $2}

204


205

top_decl:

206

 CONST cdecl_list { List.rev ($2 false) }

207

 nodespec_list state_annot node_ident_decl LPAR vdecl_list SCOL_opt RPAR RETURNS LPAR vdecl_list SCOL_opt RPAR SCOL_opt locals LET stmt_list TEL

208

{

209

let stmts, asserts, annots = $16 in

210

(* Declaring eqs annots *)

211

List.iter (fun ann >

212

List.iter (fun (key, _) >

213

Annotations.add_node_ann $3 key

214

) ann.annots

215

) annots;

216

(* Building the node *)

217

let nd = mktop_decl false (Node

218

{node_id = $3;

219

node_type = Types.new_var ();

220

node_clock = Clocks.new_var true;

221

node_inputs = List.rev $5;

222

node_outputs = List.rev $10;

223

node_locals = List.rev $14;

224

node_gencalls = [];

225

node_checks = [];

226

node_asserts = asserts;

227

node_stmts = stmts;

228

node_dec_stateless = $2;

229

node_stateless = None;

230

node_spec = $1;

231

node_annot = annots})

232

in

233

pop_node ();

234

(*add_node $3 nd;*) [nd] }

235


236

nodespec_list:

237

{ None }

238

 NODESPEC nodespec_list {

239

(function

240

 None > (fun s1 > Some s1)

241

 Some s2 > (fun s1 > Some (merge_node_annot s1 s2))) $2 $1 }

242


243

typ_def_list:

244

/* empty */ { (fun itf > []) }

245

 typ_def SCOL typ_def_list { (fun itf > let ty1 = ($1 itf) in ty1 :: ($3 itf)) }

246


247

typ_def:

248

TYPE type_ident EQ typ_def_rhs { (fun itf >

249

let typ = mktop_decl itf (TypeDef { tydef_id = $2;

250

tydef_desc = $4

251

})

252

in (*add_type itf $2 typ;*) typ) }

253


254

typ_def_rhs:

255

typeconst { $1 }

256

 ENUM LCUR tag_list RCUR { Tydec_enum (List.rev $3) }

257

 STRUCT LCUR field_list RCUR { Tydec_struct (List.rev $3) }

258


259

array_typ_decl:

260

%prec POWER { fun typ > typ }

261

 POWER dim array_typ_decl { fun typ > $3 (Tydec_array ($2, typ)) }

262


263

typeconst:

264

TINT array_typ_decl { $2 Tydec_int }

265

 TBOOL array_typ_decl { $2 Tydec_bool }

266

 TREAL array_typ_decl { $2 Tydec_real }

267

 TFLOAT array_typ_decl { $2 Tydec_float }

268

 type_ident array_typ_decl { $2 (Tydec_const $1) }

269

 TBOOL TCLOCK { Tydec_clock Tydec_bool }

270

 IDENT TCLOCK { Tydec_clock (Tydec_const $1) }

271


272

tag_list:

273

UIDENT { $1 :: [] }

274

 tag_list COMMA UIDENT { $3 :: $1 }

275


276

field_list: { [] }

277

 field_list IDENT COL typeconst SCOL { ($2, $4) :: $1 }

278


279

stmt_list:

280

{ [], [], [] }

281

 eq stmt_list {let eql, assertl, annotl = $2 in ((Eq $1)::eql), assertl, annotl}

282

 assert_ stmt_list {let eql, assertl, annotl = $2 in eql, ($1::assertl), annotl}

283

 ANNOT stmt_list {let eql, assertl, annotl = $2 in eql, assertl, $1::annotl}

284

 automaton stmt_list {let eql, assertl, annotl = $2 in ((Aut $1)::eql), assertl, annotl}

285


286

automaton:

287

AUTOMATON type_ident handler_list { Automata.mkautomata (get_loc ()) $2 $3 }

288


289

handler_list:

290

{ [] }

291

 handler handler_list { $1::$2 }

292


293

handler:

294

STATE UIDENT COL unless_list locals LET stmt_list TEL until_list { Automata.mkhandler (get_loc ()) $2 $4 $9 $5 $7 }

295


296

unless_list:

297

{ [] }

298

 unless unless_list { $1::$2 }

299


300

until_list:

301

{ [] }

302

 until until_list { $1::$2 }

303


304

unless:

305

UNLESS expr RESTART UIDENT { (get_loc (), $2, true, $4) }

306

 UNLESS expr RESUME UIDENT { (get_loc (), $2, false, $4) }

307


308

until:

309

UNTIL expr RESTART UIDENT { (get_loc (), $2, true, $4) }

310

 UNTIL expr RESUME UIDENT { (get_loc (), $2, false, $4) }

311


312

assert_:

313

 ASSERT expr SCOL {mkassert ($2)}

314


315

eq:

316

ident_list EQ expr SCOL {mkeq (List.rev $1,$3)}

317

 LPAR ident_list RPAR EQ expr SCOL {mkeq (List.rev $2,$5)}

318


319

lustre_spec:

320

 contract EOF { $1 }

321


322

contract:

323

requires ensures behaviors { { requires = $1; ensures = $2; behaviors = $3; spec_loc = get_loc () } }

324


325

requires:

326

{ [] }

327

 REQUIRES qexpr SCOL requires { $2::$4 }

328


329

ensures:

330

{ [] }

331

 ENSURES qexpr SCOL ensures { $2 :: $4 }

332

 OBSERVER node_ident LPAR tuple_expr RPAR SCOL ensures {

333

mkeexpr (mkexpr ((Expr_appl ($2, mkexpr (Expr_tuple $4), None)))) :: $7

334

}

335


336

behaviors:

337

{ [] }

338

 BEHAVIOR IDENT COL assumes ensures behaviors { ($2,$4,$5,get_loc ())::$6 }

339


340

assumes:

341

{ [] }

342

 ASSUMES qexpr SCOL assumes { $2::$4 }

343


344

/* WARNING: UNUSED RULES */

345

tuple_qexpr:

346

 qexpr COMMA qexpr {[$3;$1]}

347

 tuple_qexpr COMMA qexpr {$3::$1}

348


349

qexpr:

350

 expr { mkeexpr $1 }

351

/* Quantifiers */

352

 EXISTS vdecl SCOL qexpr %prec prec_exists { extend_eexpr [Exists, $2] $4 }

353

 FORALL vdecl SCOL qexpr %prec prec_forall { extend_eexpr [Forall, $2] $4 }

354


355


356

tuple_expr:

357

expr COMMA expr {[$3;$1]}

358

 tuple_expr COMMA expr {$3::$1}

359


360

// Same as tuple expr but accepting lists with single element

361

array_expr:

362

expr {[$1]}

363

 expr COMMA array_expr {$1::$3}

364


365

dim_list:

366

dim RBRACKET { fun base > mkexpr (Expr_access (base, $1)) }

367

 dim RBRACKET LBRACKET dim_list { fun base > $4 (mkexpr (Expr_access (base, $1))) }

368


369

expr:

370

/* constants */

371

INT {mkexpr (Expr_const (Const_int $1))}

372

 REAL {mkexpr (Expr_const (Const_real $1))}

373

 FLOAT {mkexpr (Expr_const (Const_float $1))}

374

/* Idents or type enum tags */

375

 IDENT { mkexpr (Expr_ident $1) }

376

 tag_ident { mkexpr (Expr_ident $1) (*(Expr_const (Const_tag $1))*) }

377

 LPAR ANNOT expr RPAR

378

{update_expr_annot (get_current_node ()) $3 $2}

379

 LPAR expr RPAR

380

{$2}

381

 LPAR tuple_expr RPAR

382

{mkexpr (Expr_tuple (List.rev $2))}

383


384

/* Array expressions */

385

 LBRACKET array_expr RBRACKET { mkexpr (Expr_array $2) }

386

 expr POWER dim { mkexpr (Expr_power ($1, $3)) }

387

 expr LBRACKET dim_list { $3 $1 }

388


389

/* Temporal operators */

390

 PRE expr

391

{mkexpr (Expr_pre $2)}

392

 expr ARROW expr

393

{mkexpr (Expr_arrow ($1,$3))}

394

 expr FBY expr

395

{(*mkexpr (Expr_fby ($1,$3))*)

396

mkexpr (Expr_arrow ($1, mkexpr (Expr_pre $3)))}

397

 expr WHEN vdecl_ident

398

{mkexpr (Expr_when ($1,$3,tag_true))}

399

 expr WHENNOT vdecl_ident

400

{mkexpr (Expr_when ($1,$3,tag_false))}

401

 expr WHEN tag_ident LPAR vdecl_ident RPAR

402

{mkexpr (Expr_when ($1, $5, $3))}

403

 MERGE vdecl_ident handler_expr_list

404

{mkexpr (Expr_merge ($2,$3))}

405


406

/* Applications */

407

 node_ident LPAR expr RPAR

408

{mkexpr (Expr_appl ($1, $3, None))}

409

 node_ident LPAR expr RPAR EVERY expr

410

{mkexpr (Expr_appl ($1, $3, Some $6))}

411

 node_ident LPAR tuple_expr RPAR

412

{

413

let id=$1 in

414

let args=List.rev $3 in

415

match id, args with

416

 "fbyn", [expr;n;init] >

417

let n = match n.expr_desc with

418

 Expr_const (Const_int n) > n

419

 _ > assert false

420

in

421

fby expr n init

422

 _ > mkexpr (Expr_appl ($1, mkexpr (Expr_tuple args), None))

423

}

424

 node_ident LPAR tuple_expr RPAR EVERY expr

425

{

426

let id=$1 in

427

let args=List.rev $3 in

428

let clock=$6 in

429

if id="fby" then

430

assert false (* TODO Ca veut dire quoi fby (e,n,init) every c *)

431

else

432

mkexpr (Expr_appl (id, mkexpr (Expr_tuple args), Some clock))

433

}

434


435

/* Boolean expr */

436

 expr AND expr

437

{mkpredef_call "&&" [$1;$3]}

438

 expr AMPERAMPER expr

439

{mkpredef_call "&&" [$1;$3]}

440

 expr OR expr

441

{mkpredef_call "" [$1;$3]}

442

 expr BARBAR expr

443

{mkpredef_call "" [$1;$3]}

444

 expr XOR expr

445

{mkpredef_call "xor" [$1;$3]}

446

 NOT expr

447

{mkpredef_call "not" [$2]}

448

 expr IMPL expr

449

{mkpredef_call "impl" [$1;$3]}

450


451

/* Comparison expr */

452

 expr EQ expr

453

{mkpredef_call "=" [$1;$3]}

454

 expr LT expr

455

{mkpredef_call "<" [$1;$3]}

456

 expr LTE expr

457

{mkpredef_call "<=" [$1;$3]}

458

 expr GT expr

459

{mkpredef_call ">" [$1;$3]}

460

 expr GTE expr

461

{mkpredef_call ">=" [$1;$3]}

462

 expr NEQ expr

463

{mkpredef_call "!=" [$1;$3]}

464


465

/* Arithmetic expr */

466

 expr PLUS expr

467

{mkpredef_call "+" [$1;$3]}

468

 expr MINUS expr

469

{mkpredef_call "" [$1;$3]}

470

 expr MULT expr

471

{mkpredef_call "*" [$1;$3]}

472

 expr DIV expr

473

{mkpredef_call "/" [$1;$3]}

474

 MINUS expr %prec UMINUS

475

{mkpredef_call "uminus" [$2]}

476

 expr MOD expr

477

{mkpredef_call "mod" [$1;$3]}

478


479

/* If */

480

 IF expr THEN expr ELSE expr

481

{mkexpr (Expr_ite ($2, $4, $6))}

482


483

handler_expr_list:

484

{ [] }

485

 handler_expr handler_expr_list { $1 :: $2 }

486


487

handler_expr:

488

LPAR tag_ident ARROW expr RPAR { ($2, $4) }

489


490

signed_const_array:

491

 signed_const { [$1] }

492

 signed_const COMMA signed_const_array { $1 :: $3 }

493


494

signed_const_struct:

495

 IDENT EQ signed_const { [ ($1, $3) ] }

496

 IDENT EQ signed_const COMMA signed_const_struct { ($1, $3) :: $5 }

497


498

signed_const:

499

INT {Const_int $1}

500

 REAL {Const_real $1}

501

 FLOAT {Const_float $1}

502

 tag_ident {Const_tag $1}

503

 MINUS INT {Const_int (1 * $2)}

504

 MINUS REAL {Const_real ("" ^ $2)}

505

 MINUS FLOAT {Const_float (1. *. $2)}

506

 LCUR signed_const_struct RCUR { Const_struct $2 }

507

 LBRACKET signed_const_array RBRACKET { Const_array $2 }

508


509

dim:

510

INT { mkdim_int $1 }

511

 LPAR dim RPAR { $2 }

512

 UIDENT { mkdim_ident $1 }

513

 IDENT { mkdim_ident $1 }

514

 dim AND dim

515

{mkdim_appl "&&" [$1;$3]}

516

 dim AMPERAMPER dim

517

{mkdim_appl "&&" [$1;$3]}

518

 dim OR dim

519

{mkdim_appl "" [$1;$3]}

520

 dim BARBAR dim

521

{mkdim_appl "" [$1;$3]}

522

 dim XOR dim

523

{mkdim_appl "xor" [$1;$3]}

524

 NOT dim

525

{mkdim_appl "not" [$2]}

526

 dim IMPL dim

527

{mkdim_appl "impl" [$1;$3]}

528


529

/* Comparison dim */

530

 dim EQ dim

531

{mkdim_appl "=" [$1;$3]}

532

 dim LT dim

533

{mkdim_appl "<" [$1;$3]}

534

 dim LTE dim

535

{mkdim_appl "<=" [$1;$3]}

536

 dim GT dim

537

{mkdim_appl ">" [$1;$3]}

538

 dim GTE dim

539

{mkdim_appl ">=" [$1;$3]}

540

 dim NEQ dim

541

{mkdim_appl "!=" [$1;$3]}

542


543

/* Arithmetic dim */

544

 dim PLUS dim

545

{mkdim_appl "+" [$1;$3]}

546

 dim MINUS dim

547

{mkdim_appl "" [$1;$3]}

548

 dim MULT dim

549

{mkdim_appl "*" [$1;$3]}

550

 dim DIV dim

551

{mkdim_appl "/" [$1;$3]}

552

 MINUS dim %prec UMINUS

553

{mkdim_appl "uminus" [$2]}

554

 dim MOD dim

555

{mkdim_appl "mod" [$1;$3]}

556

/* If */

557

 IF dim THEN dim ELSE dim

558

{mkdim_ite $2 $4 $6}

559


560

locals:

561

{[]}

562

 VAR local_vdecl_list SCOL {$2}

563


564

vdecl_list:

565

vdecl {$1}

566

 vdecl_list SCOL vdecl {$3 @ $1}

567


568

vdecl:

569

ident_list COL typeconst clock

570

{ List.map (fun id > mkvar_decl (id, mktyp $3, $4, false, None)) $1 }

571

 CONST ident_list /* static parameters don't have clocks */

572

{ List.map (fun id > mkvar_decl (id, mktyp Tydec_any, mkclock Ckdec_any, true, None)) $2 }

573

 CONST ident_list COL typeconst /* static parameters don't have clocks */

574

{ List.map (fun id > mkvar_decl (id, mktyp $4, mkclock Ckdec_any, true, None)) $2 }

575


576

local_vdecl_list:

577

local_vdecl {$1}

578

 local_vdecl_list SCOL local_vdecl {$3 @ $1}

579


580

local_vdecl:

581

/* Useless no ?*/ ident_list

582

{ List.map (fun id > mkvar_decl (id, mktyp Tydec_any, mkclock Ckdec_any, false, None)) $1 }

583

 ident_list COL typeconst clock

584

{ List.map (fun id > mkvar_decl (id, mktyp $3, $4, false, None)) $1 }

585

 CONST vdecl_ident EQ expr /* static parameters don't have clocks */

586

{ [ mkvar_decl ($2, mktyp Tydec_any, mkclock Ckdec_any, true, Some $4) ] }

587

 CONST vdecl_ident COL typeconst EQ expr /* static parameters don't have clocks */

588

{ [ mkvar_decl ($2, mktyp $4, mkclock Ckdec_any, true, Some $6) ] }

589


590

cdecl_list:

591

cdecl SCOL { (fun itf > [$1 itf]) }

592

 cdecl cdecl_list SCOL { (fun itf > let c1 = ($1 itf) in c1::($2 itf)) }

593


594

cdecl:

595

const_ident EQ signed_const {

596

(fun itf >

597

let c = mktop_decl itf (Const {

598

const_id = $1;

599

const_loc = Location.symbol_rloc ();

600

const_type = Types.new_var ();

601

const_value = $3})

602

in

603

(*add_const itf $1 c;*) c)

604

}

605


606

clock:

607

{mkclock Ckdec_any}

608

 when_list

609

{mkclock (Ckdec_bool (List.rev $1))}

610


611

when_cond:

612

WHEN IDENT {($2, tag_true)}

613

 WHENNOT IDENT {($2, tag_false)}

614

 WHEN tag_ident LPAR IDENT RPAR {($4, $2)}

615


616

when_list:

617

when_cond {[$1]}

618

 when_list when_cond {$2::$1}

619


620

ident_list:

621

vdecl_ident {[$1]}

622

 ident_list COMMA vdecl_ident {$3::$1}

623


624

SCOL_opt:

625

SCOL {}  {}

626


627


628

lustre_annot:

629

lustre_annot_list EOF { { annots = $1; annot_loc = get_loc () } }

630


631

lustre_annot_list:

632

{ [] }

633

 kwd COL qexpr SCOL lustre_annot_list { ($1,$3)::$5 }

634

 IDENT COL qexpr SCOL lustre_annot_list { ([$1],$3)::$5 }

635

 INVARIANT COL qexpr SCOL lustre_annot_list{ (["invariant"],$3)::$5 }

636

 OBSERVER COL qexpr SCOL lustre_annot_list { (["observer"],$3)::$5 }

637


638

kwd:

639

DIV { [] }

640

 DIV IDENT kwd { $2::$3}

641


642

%%

643

(* Local Variables: *)

644

(* compilecommand:"make C .." *)

645

(* End: *)

646


647

