Project

General

Profile

Download (33.9 KB) Statistics
| Branch: | Tag: | Revision:
1
(* This file is part of the Kind 2 model checker.
2

    
3
   Copyright (c) 2015 by the Board of Trustees of the University of Iowa
4

    
5
   Licensed under the Apache License, Version 2.0 (the "License"); you
6
   may not use this file except in compliance with the License.  You
7
   may obtain a copy of the License at
8

    
9
   http://www.apache.org/licenses/LICENSE-2.0 
10

    
11
   Unless required by applicable law or agreed to in writing, software
12
   distributed under the License is distributed on an "AS IS" BASIS,
13
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
14
   implied. See the License for the specific language governing
15
   permissions and limitations under the License. 
16

    
17
*)
18

    
19

    
20
%{
21
open KindLib
22

    
23
module A = KindLustreAst
24

    
25
let mk_pos = position_of_lexing 
26

    
27

    
28
let rec add_else_branch b belse =
29
  match b with
30
  | A.Target _ -> failwith "Cannot add else branch to unconditional target"
31
  | A.TransIf (p, e, b1, None) -> A.TransIf (p, e, b1, Some belse)
32
  | A.TransIf (p, e, b1, Some b2) ->
33
     A.TransIf (p, e, b1, Some (add_else_branch b2 belse))
34
     
35
           
36
let merge_branches transitions =
37
  List.fold_right (fun (p, b) acc ->
38
      match acc, b with
39
      | None, _ -> Some (p, b)
40
      | Some (_, b2), b1 -> Some (p, add_else_branch b1 b2)
41
    ) transitions None
42
  
43
%}
44

    
45
(* Special characters *)
46
%token SEMICOLON 
47
%token EQUALS 
48
%token COLON 
49
%token COMMA 
50
%token LSQBRACKET 
51
%token RSQBRACKET 
52
%token LPAREN 
53
%token RPAREN 
54
%token DOTPERCENT
55

    
56
(* Tokens for enumerated types *)
57
%token ENUM
58

    
59
(* Tokens for records *)
60
%token STRUCT
61
%token DOT
62
%token LCURLYBRACKET 
63
%token RCURLYBRACKET 
64

    
65
(* Tokens for decimals and numerals *)
66
%token <string>DECIMAL
67
%token <string>NUMERAL
68

    
69
%token <string>STRING
70

    
71
(* Identifier token *)
72
%token <string>SYM 
73
%token <string>QUOTSYM 
74
      
75
(* Tokens for types *)
76
%token TYPE
77
%token INT
78
%token REAL
79
%token BOOL
80
%token SUBRANGE
81
%token OF
82
    
83
(* Tokens for arrays *)
84
(* %token ARRAY *)
85
%token CARET
86
%token DOTDOT
87
%token PIPE
88

    
89
(* Token for constant declarations *)
90
%token CONST
91
    
92
(* Tokens for node declarations *)
93
%token IMPORTED
94
%token NODE
95
%token LPARAMBRACKET
96
%token RPARAMBRACKET
97
%token FUNCTION
98
%token RETURNS
99
%token VAR
100
%token LET
101
%token TEL
102
    
103
(* Tokens for annotations *)
104

    
105
(* Inline annotations. *)
106
%token PERCENTANNOT
107
%token BANGANNOT
108
(* %token ATANNOT *)
109
(* Parenthesis star (PS) block annotations. *)
110
%token PSBLOCKSTART
111
%token PSATBLOCK
112
%token PSBLOCKEND
113
(* Slash star (PS) block annotations. *)
114
%token SSBLOCKSTART
115
%token SSATBLOCK
116
%token SSBLOCKEND
117
(* Generic annotations. *)
118
%token PROPERTY
119
%token MAIN
120
(* Contract annotations. *)
121
%token CONTRACT
122
%token IMPORTCONTRACT
123
(* %token IMPORTMODE *)
124
%token ASSUME
125
%token GUARANTEE
126
%token MODE
127
%token REQUIRE
128
%token ENSURE
129

    
130
(* Token for assertions *)
131
%token ASSERT
132
    
133
(* Token for check *)
134
%token CHECK
135

    
136
(* Tokens for Boolean operations *)
137
%token TRUE
138
%token FALSE
139
%token NOT
140
%token AND
141
%token XOR
142
%token OR
143
%token IF
144
%token WITH
145
%token THEN
146
%token ELSE
147
%token IMPL
148
%token HASH
149
%token FORALL
150
%token EXISTS
151
    
152
(* Tokens for relations *)
153
%token LTE
154
%token GTE
155
%token LT
156
%token GT
157
%token NEQ
158
    
159
(* Tokens for arithmetic operators *)
160
%token MINUS
161
%token PLUS
162
%token DIV
163
%token MULT
164
%token INTDIV
165
%token MOD
166
    
167
(* Tokens for clocks *)
168
%token WHEN
169
%token CURRENT
170
%token CONDACT
171
%token ACTIVATE
172
%token INITIAL
173
%token DEFAULT
174
%token EVERY
175
%token RESTART
176
%token MERGE
177

    
178
(* Tokens for automata *)
179
%token AUTOMATON
180
%token STATE
181
%token UNLESS
182
%token UNTIL
183
%token RESUME
184
%token ELSIF
185
%token END
186

    
187
(* Tokens for temporal operators *)
188
%token PRE
189
%token LAST
190
%token FBY
191
%token ARROW
192
    
193
(* Token for end of file marker *)
194
%token EOF
195
    
196
(* Priorities and associativity of operators, lowest first *)
197
%nonassoc WHEN CURRENT 
198
%left PIPE
199
%nonassoc ELSE
200
%right ARROW
201
%nonassoc prec_forall prec_exists
202
%right IMPL
203
%left OR XOR
204
%left AND
205
%left LT LTE EQUALS NEQ GTE GT
206
%left PLUS MINUS
207
%left MULT INTDIV MOD DIV
208
%nonassoc PRE 
209
%nonassoc INT REAL 
210
%nonassoc NOT 
211
%left CARET 
212
%left LSQBRACKET DOT DOTPERCENT
213

    
214
(* Start token *)
215
%start <KindLustreAst.t> main
216
%start <KindLustreAst.expr> one_expr
217
%start <KindLustreAst.contract> contract_in_block
218
%%
219
(** Parser for lustre systems. *)
220

    
221
one_expr: e = expr EOF { e }
222

    
223

    
224
(* A Lustre program is a list of declarations *)
225
main: p = list(decl) EOF { List.flatten p }
226

    
227
(* A declaration is a type, a constant, a node or a function declaration *)
228
decl:
229
  | d = const_decl { List.map 
230
                       (function e -> A.ConstDecl (mk_pos $startpos, e)) 
231
                       d }
232
  | d = type_decl { List.map 
233
                      (function e -> A.TypeDecl (mk_pos $startpos, e)) 
234
                      d }
235
  | NODE ; decl = node_decl ; def = node_def {
236
    let (n, p, i, o, r) = decl in
237
    let (l, e) = def in
238
    [A.NodeDecl ( mk_pos $startpos, (n, false, p, i, o, l, e, r) )]
239
  }
240
  | FUNCTION ; decl = node_decl ; def = node_def {
241
    let (n, p, i, o, r) = decl in
242
    let (l, e) = def in
243
    [A.FuncDecl (mk_pos $startpos, (n, false, p, i, o, l, e, r))]
244
  }
245
  | NODE ; IMPORTED ; decl = node_decl {
246
    let (n, p, i, o, r) = decl in
247
    [A.NodeDecl ( mk_pos $startpos, (n, true, p, i, o, [], [], r) )]
248
  }
249
  | FUNCTION ; IMPORTED ; decl = node_decl {
250
    let (n, p, i, o, r) = decl in
251
    [A.FuncDecl (mk_pos $startpos, (n, true, p, i, o, [], [], r))]
252
  }
253
  | d = contract_decl { [A.ContractNodeDecl (mk_pos $startpos, d)] }
254
  | d = node_param_inst { [A.NodeParamInst (mk_pos $startpos, d)] }
255

    
256

    
257
(* ********************************************************************** *)
258

    
259

    
260
(* A constant declaration *)
261
const_decl: CONST; l = nonempty_list(const_decl_body) { List.flatten l }
262

    
263
(* The body of a constant declaration *)
264
const_decl_body:
265

    
266
  (* Imported (free) constant 
267

    
268
     Separate rule for singleton list to avoid shift/reduce conflict *)
269
  | h = ident; COLON; t = lustre_type; SEMICOLON 
270
    { [A.FreeConst (mk_pos $startpos, h, t)] } 
271

    
272
  (* Imported (free) constant *)
273
  | h = ident; COMMA; l = ident_list; COLON; t = lustre_type; SEMICOLON 
274
    { List.map (function e -> A.FreeConst (mk_pos $startpos, e, t)) (h :: l) } 
275

    
276
  (* Defined constant without a type *)
277
  | s = ident; EQUALS; e = expr; SEMICOLON 
278
    { [A.UntypedConst (mk_pos $startpos, s, e)] }
279

    
280
  (* Defined constant with a type *)
281
  | c = typed_ident; EQUALS; e = expr; SEMICOLON 
282
    { let (_, s, t) = c in [A.TypedConst (mk_pos $startpos, s, e, t)] }
283

    
284

    
285
(* ********************************************************************** *)
286

    
287

    
288
(* A type declaration *) 
289
type_decl: 
290

    
291
  (* A free type *)
292
  | TYPE; l = ident_list; SEMICOLON 
293
     { List.map (fun e -> A.FreeType (mk_pos $startpos, e)) l }
294

    
295
  (* A type alias *)
296
  | TYPE; l = ident_list; EQUALS; t = lustre_type; SEMICOLON
297
     { List.map (fun e -> match t with 
298
                 | A.EnumType (p, _, cs) ->
299
                    A.AliasType (mk_pos $startpos, e,
300
                                 A.EnumType (p, Some e, cs))
301
                 | _ -> A.AliasType (mk_pos $startpos, e, t)) l }
302

    
303
  (* A record type, can only be defined as alias *)
304
  | TYPE; l = ident_list; EQUALS; t = record_type; SEMICOLON
305
     { List.map 
306
         (function e -> 
307
           A.AliasType (mk_pos $startpos, 
308
                        e, 
309
                        A.RecordType (mk_pos $startpos, t))) 
310
         l }
311

    
312

    
313
(* A type *)
314
lustre_type:
315

    
316
  (* Predefined types *)
317
  | BOOL { A.Bool (mk_pos $startpos) }
318
  | INT { A.Int (mk_pos $startpos)}
319
  | REAL { A.Real (mk_pos $startpos)}
320

    
321
  | SUBRANGE;
322
    LSQBRACKET;
323
    l = expr; 
324
    COMMA; 
325
    u = expr; 
326
    RSQBRACKET 
327
    OF
328
    INT 
329
    { A.IntRange (mk_pos $startpos, l, u)}
330

    
331
  (* User-defined type *)
332
  | s = ident { A.UserType (mk_pos $startpos, s) }
333

    
334
  (* Tuple type *)
335
  | t = tuple_type { A.TupleType (mk_pos $startpos, t) } 
336

    
337
(* Record types can only be defined as aliases 
338
  (* Record type (V6) *)
339
  | t = record_type { A.RecordType t } 
340
*)
341

    
342
  (* Array type (V6) *)
343
  | t = array_type { A.ArrayType (mk_pos $startpos, t) }
344

    
345
  (* Enum type (V6) *)
346
  | t = enum_type { A.EnumType (mk_pos $startpos, None, t) }
347

    
348

    
349
(* A tuple type *)
350
tuple_type:
351

    
352
  (* Tuples are between square brackets *)
353
  | LSQBRACKET; l = lustre_type_list; RSQBRACKET { l } 
354

    
355

    
356
(* A record type (V6) *)
357
record_type:
358

    
359
  (* Keyword "struct" is optional *)
360
  | option(STRUCT); 
361
    f = tlist(LCURLYBRACKET, SEMICOLON, RCURLYBRACKET, typed_idents)
362
  
363
    { List.flatten f  }
364

    
365

    
366
(* An array type (V6) *)
367
array_type: 
368
  | t = lustre_type; CARET; s = expr { t, s }
369

    
370
(*
371
  (* Alternate syntax: array [size] of type *)
372
  | ARRAY; s = expr; OF; LSQBRACKET; t = lustre_type; RSQBRACKET { t, s }
373
*)
374

    
375
(* An enum type (V6) *)
376
enum_type: ENUM LCURLYBRACKET; l = ident_list; RCURLYBRACKET { l } 
377

    
378

    
379
(* ********************************************************************** *)
380

    
381

    
382
(* A node declaration and contract. *)
383
node_decl:
384
| n = ident;
385
  p = loption(static_params);
386
  i = tlist(LPAREN, SEMICOLON, RPAREN, const_clocked_typed_idents);
387
  RETURNS;
388
  o = tlist(LPAREN, SEMICOLON, RPAREN, clocked_typed_idents);
389
  option(SEMICOLON);
390
  r = option(contract_spec)
391
  {
392
    (n, p, List.flatten i, List.flatten o, r)
393
  }
394

    
395
(* A node definition (locals + body). *)
396
node_def:
397
  l = list(node_local_decl);
398
  LET;
399
  e = list(node_item);
400
  TEL
401
  option(node_sep)
402

    
403
  { (List.flatten l, e) }
404

    
405

    
406
contract_ghost_var:
407
  | VAR ;
408
    i = ident ; COLON ; t = lustre_type; EQUALS ; e = qexpr ;
409
    SEMICOLON 
410
    { A.GhostVar (A.TypedConst (mk_pos $startpos, i, e, t)) }
411
(*  | VAR ; i = ident ; EQUALS ; e = expr ; SEMICOLON 
412
    { A.GhostVar (A.UntypedConst (mk_pos $startpos, i, e)) } *)
413

    
414
contract_ghost_const:
415
  | CONST; i = ident; COLON; t = lustre_type; EQUALS; e = qexpr; SEMICOLON 
416
    { A.GhostConst (A.TypedConst (mk_pos $startpos, i, e, t)) }
417
  | CONST; i = ident; EQUALS; e = qexpr; SEMICOLON 
418
    { A.GhostConst (A.UntypedConst (mk_pos $startpos, i, e)) }
419

    
420
contract_assume:
421
  ASSUME; name = option(STRING); e = qexpr; SEMICOLON
422
  { A.Assume (mk_pos $startpos, name, e) }
423

    
424
contract_guarantee:
425
  GUARANTEE; name = option(STRING); e = qexpr; SEMICOLON
426
  { A.Guarantee (mk_pos $startpos, name, e) }
427

    
428
contract_require:
429
  REQUIRE; name = option(STRING); e = qexpr; SEMICOLON
430
  { mk_pos $startpos, name, e }
431

    
432
contract_ensure:
433
  ENSURE; name = option(STRING); e = qexpr; SEMICOLON
434
  { mk_pos $startpos, name, e }
435

    
436
mode_equation:
437
  MODE; n = ident; LPAREN;
438
  reqs = list(contract_require);
439
  enss = list(contract_ensure);
440
  RPAREN; SEMICOLON {
441
    A.Mode (mk_pos $startpos, n, reqs, enss)
442
  }
443

    
444
contract_import:
445
  IMPORTCONTRACT ; n = ident ;
446
  LPAREN ; in_params = separated_list(COMMA, qexpr) ; RPAREN ; RETURNS ;
447
  LPAREN ; out_params = separated_list(COMMA, qexpr) ; RPAREN ; SEMICOLON ; {
448
    A.ContractCall (mk_pos $startpos, n, in_params, out_params)
449
  }
450

    
451

    
452
contract_item:
453
  | v = contract_ghost_var { v } 
454
  | c = contract_ghost_const { c }
455
  | a = contract_assume { a }
456
  | g = contract_guarantee { g }
457
  | m = mode_equation { m }
458
  | i = contract_import { i }
459

    
460
contract_in_block:
461
  | c = nonempty_list(contract_item) { c }
462

    
463

    
464
(* A contract node declaration. *)
465
contract_decl:
466
  | CONTRACT;
467
    n = ident; 
468
    p = loption(static_params);
469
    i = tlist(LPAREN, SEMICOLON, RPAREN, const_clocked_typed_idents); 
470
    RETURNS; 
471
    o = tlist(LPAREN, SEMICOLON, RPAREN, clocked_typed_idents); 
472
    SEMICOLON;
473
    LET;
474
      e = contract_in_block;
475
    TEL
476
    option(node_sep) 
477

    
478
    { (n,
479
       p,
480
       List.flatten i,
481
       List.flatten o,
482
       e) }
483

    
484

    
485
contract_spec:
486
  (* Block contract, parenthesis star (PS). *)
487
  | PSATBLOCK ; CONTRACT ;
488
    eqs = contract_in_block
489
    PSBLOCKEND
490
    { eqs }
491
  (* Block contract, slash star (SS). *)
492
  | SSATBLOCK ; CONTRACT ;
493
    eqs = contract_in_block
494
    SSBLOCKEND
495
    { eqs }
496

    
497

    
498
(* A node declaration as an instance of a paramterized node *)
499
node_param_inst: 
500
  | NODE; 
501
    n = ident; 
502
    EQUALS;
503
    s = ident; 
504
    p = tlist 
505
         (LPARAMBRACKET, SEMICOLON, RPARAMBRACKET, node_call_static_param); 
506
    SEMICOLON
507
        
508
    { (n, s, p) } 
509

    
510

    
511
(* A node declaration is optionally terminated by a period or a semicolon *)
512
node_sep: DOT | SEMICOLON { }
513

    
514

    
515
(* A static parameter is a type *)
516
static_param:
517
  | TYPE; t = ident { A.TypeParam t }
518

    
519

    
520
(* The static parameters of a node *)
521
static_params:
522
  | l = tlist (LPARAMBRACKET, SEMICOLON, RPARAMBRACKET, static_param)
523
    
524
    { l }  
525

    
526

    
527
(* A node-local declaration of constants or variables *)
528
node_local_decl:
529
  | c = const_decl { List.map 
530
                       (function e -> A.NodeConstDecl (mk_pos $startpos, e))
531
                       c }
532
  | v = var_decls { List.map 
533
                      (function e -> A.NodeVarDecl (mk_pos $startpos, e)) 
534
                      v }
535

    
536

    
537
(* A variable declaration section of a node *)
538
var_decls: 
539
  | VAR; l = nonempty_list(var_decl) { List.flatten l }
540

    
541

    
542
(* A declaration of variables *)
543
var_decl:
544
  | l = clocked_typed_idents; SEMICOLON { l }
545

    
546

    
547
boolean:
548
  | TRUE { true }
549
  | FALSE { false }
550

    
551
percent_or_bang:
552
  | PERCENTANNOT { }
553
  | BANGANNOT { }
554

    
555

    
556
    
557
main_annot:
558
  | PERCENTANNOT ; MAIN ; SEMICOLON { A.AnnotMain true }
559
  | PSBLOCKSTART ; MAIN ; option (SEMICOLON) ; PSBLOCKEND { A.AnnotMain true }
560
  | SSBLOCKSTART ; MAIN ; option (SEMICOLON) ; SSBLOCKEND { A.AnnotMain true }
561
  | BANGANNOT ; MAIN ; COLON ; b = boolean ; SEMICOLON { A.AnnotMain b }
562
  | PSBLOCKSTART ; MAIN ; COLON ; b = boolean ; option (SEMICOLON) ; PSBLOCKEND {
563
    A.AnnotMain b
564
  }
565
  | SSBLOCKSTART ; MAIN ; COLON ; b = boolean ; option (SEMICOLON) ; SSBLOCKEND {
566
    A.AnnotMain b
567
  }
568

    
569
property:
570
  | percent_or_bang ; PROPERTY ; name = option(STRING) ; e = qexpr ; SEMICOLON
571
    { A.AnnotProperty (mk_pos $startpos, name, e) }
572
  | PSBLOCKSTART ; PROPERTY ; name = option(STRING);
573
    e = qexpr; SEMICOLON ; PSBLOCKEND
574
    { A.AnnotProperty (mk_pos $startpos, name, e) }
575
  | PSBLOCKSTART ; PROPERTY ; name = option(STRING);
576
    COLON; e = qexpr; SEMICOLON ; PSBLOCKEND
577
    { A.AnnotProperty (mk_pos $startpos, name, e) }
578
  | SSBLOCKSTART ; PROPERTY ; name = option(STRING);
579
    e = qexpr ; SEMICOLON; SSBLOCKEND
580
    { A.AnnotProperty (mk_pos $startpos, name, e) }
581
  | SSBLOCKSTART ; PROPERTY ; name = option(STRING);
582
    COLON; e = qexpr ; SEMICOLON; SSBLOCKEND
583
    { A.AnnotProperty (mk_pos $startpos, name, e) }
584

    
585
check:
586
  | CHECK ; name = option(STRING) ; e = qexpr ; SEMICOLON
587
    { A.AnnotProperty (mk_pos $startpos, name, e) }
588

    
589
node_item:
590
  | e = node_equation { A.Body e }
591
  | a = main_annot { a }
592
  | p = property { p }
593
  | p = check { p }
594

    
595

    
596
(* An equations of a node *)
597
node_equation:
598

    
599
  (* An assertion *)
600
  | ASSERT; e = qexpr; SEMICOLON
601
    { A.Assert (mk_pos $startpos, e) }
602

    
603
  (* An equation, multiple (optionally parenthesized) identifiers on 
604
     the left-hand side, an expression on the right *)
605
  | l = left_side; EQUALS; e = expr; SEMICOLON
606
    { A.Equation (mk_pos $startpos, l, e) }
607

    
608
  (* An automaton *)
609
  | AUTOMATON; i = option(ident); s = list(state);
610
    RETURNS; out = ident_list; SEMICOLON
611
    { A.Automaton (mk_pos $startpos, i, s, A.Given out) }
612

    
613
  | AUTOMATON; i = option(ident); s = list(state);
614
    RETURNS DOTDOT SEMICOLON
615
    { A.Automaton (mk_pos $startpos, i, s, A.Inferred) }
616

    
617
  | AUTOMATON; i = option(ident); s = nonempty_list(state)
618
    { A.Automaton (mk_pos $startpos, i, s, A.Inferred) }
619

    
620

    
621
state_decl:
622
  | STATE; i = ident { i, false }
623
  | INITIAL STATE; i = ident { i, true }
624

    
625
state:
626
  | ii = state_decl; option(COLON)
627
    us = unless_transitions;
628
    l = list(node_local_decl);
629
    LET;
630
    e = list(node_equation);
631
    TEL;
632
    ul = until_transitions
633
    { let i, init = ii in
634
      A.State (mk_pos $startpos, i, init, List.flatten l, e,
635
               merge_branches us, merge_branches ul) }
636

    
637
  | ii = state_decl; option(COLON)
638
    us = unless_transitions;
639
    ul = until_transitions
640
    { let i, init = ii in
641
      A.State (mk_pos $startpos, i, init, [], [],
642
               merge_branches us, merge_branches ul) }
643

    
644

    
645
unless_transitions:
646
  | { [] }
647
  | UNLESS; b = transition_branch; u = unless_transitions
648
    { (mk_pos $startpos, b) :: u }
649

    
650

    
651
until_transitions:
652
  | { [] }
653
  | UNTIL; b = transition_branch; u = until_transitions
654
    { (mk_pos $startpos, b) :: u }
655

    
656

    
657
transition_branch:
658
  | b = branch; option(SEMICOLON)
659
    { b }
660
  | e = expr; t = target; option(SEMICOLON)
661
    { A.TransIf (mk_pos $startpos, e, A.Target t, None) }
662
  | IF; e = expr; t = target; option(SEMICOLON)
663
    { A.TransIf (mk_pos $startpos, e, A.Target t, None) }
664

    
665

    
666
branch:
667
  | t = target
668
    { A.Target t }
669
  | IF; e = expr; b = branch; END
670
    { A.TransIf (mk_pos $startpos, e, b, None) }
671
  | IF; e = expr; b = branch; b2 = elsif_branch; END
672
    { A.TransIf (mk_pos $startpos, e, b, Some b2) }
673
    
674
elsif_branch:
675
  | ELSE; b = branch
676
    { b } 
677
  | ELSIF; e = expr; b = branch
678
    { A.TransIf (mk_pos $startpos, e, b, None) }
679
  | ELSIF; e = expr; b = branch; b2 = elsif_branch
680
    { A.TransIf (mk_pos $startpos, e, b, Some b2) }
681

    
682
target_state:
683
  | s = ident
684
    { mk_pos $startpos, s }
685

    
686
target:
687
  | RESTART; s = target_state
688
    { A.TransRestart (mk_pos $startpos, s) }
689

    
690
  | RESUME; s = target_state
691
    { A.TransResume (mk_pos $startpos, s) }
692

    
693
left_side:
694

    
695
  (* List without parentheses *)
696
  | l = struct_item_list { A.StructDef (mk_pos $startpos, l) }
697

    
698
  (* Parenthesized list *)
699
  | LPAREN; l = struct_item_list; RPAREN { A.StructDef (mk_pos $startpos, l) }
700

    
701
  (* Empty list *)
702
  | LPAREN; RPAREN { A.StructDef (mk_pos $startpos, []) }
703

    
704

    
705
(* Item in a structured equation *)
706
struct_item:
707

    
708
  (* Single identifier *)
709
  | s = ident
710
      { A.SingleIdent (mk_pos $startpos, s) }
711
          
712
  (* Recursive array definition *)
713
  | s = ident; l = nonempty_list(index_var)
714
     { A.ArrayDef (mk_pos $startpos, s, l)}
715

    
716
(*
717
  (* Filter array values *)
718
  | LSQBRACKET; l = struct_item_list; RSQBRACKET 
719
    { A.TupleStructItem (mk_pos $startpos, l) }
720

    
721
  (* Select from tuple *)
722
  | e = ident; LSQBRACKET; i = expr; RSQBRACKET 
723
    { A.TupleSelection (mk_pos $startpos, e, i) }
724

    
725
  (* Select from record *)
726
  | e = ident; DOT; i = ident 
727
    { A.FieldSelection (mk_pos $startpos, e, i) }
728
 
729
  | e = ident; LSQBRACKET; s = array_slice_list; RSQBRACKET 
730
    { A.ArraySliceStructItem (mk_pos $startpos, e, s) }
731
*)
732

    
733
(* List of structured items *)
734
struct_item_list:
735
 | l = separated_nonempty_list(COMMA, struct_item) { l }
736

    
737
(* Running variable for index *)
738
index_var:
739
  | LSQBRACKET; s = ident; RSQBRACKET { s }
740

    
741
(* Two colons (for mode reference). *)
742
two_colons:
743
  | COLON ; COLON {}
744

    
745
(* ********************************************************************** *)
746

    
747
(* dummy rule for parameter of pexpr to signal we allow quantifiers *)
748
%inline quantified:
749
  | { true }
750

    
751
(* dummy rule for parameter of pexpr to signal we do not allow quantifiers *)
752
%inline nonquantified:
753
  | { false }
754
  
755
(* An possibly quantified expression *)
756
pexpr(Q): 
757
  
758
  (* An identifier *)
759
  | s = ident { A.Ident (mk_pos $startpos, s) } 
760

    
761
  (* A mode reference. *)
762
  | two_colons ; mode_ref = separated_nonempty_list(two_colons, ident) {
763
    A.ModeRef (mk_pos $startpos, mode_ref)
764
  }
765

    
766
  (* A propositional constant *)
767
  | TRUE { A.True (mk_pos $startpos) }
768
  | FALSE { A.False (mk_pos $startpos) }
769

    
770
  (* An integer numeral or a floating-point decimal constant *)
771
  | s = NUMERAL { A.Num (mk_pos $startpos, s) } 
772
  | s = DECIMAL { A.Dec (mk_pos $startpos, s) } 
773

    
774
  (* Conversions *)
775
  | INT; e = expr { A.ToInt (mk_pos $startpos, e) }
776
  | REAL; e = expr { A.ToReal (mk_pos $startpos, e) }
777

    
778
  (* A parenthesized single expression *)
779
  | LPAREN; e = pexpr(Q); RPAREN { e } 
780

    
781
  (* An expression list (not quantified)
782

    
783
     Singleton list is in production above *)
784
  | LPAREN; h = pexpr(Q); COMMA; l = pexpr_list(Q); RPAREN 
785
    { A.ExprList (mk_pos $startpos, h :: l) } 
786

    
787
  (* A tuple expression (not quantified) *)
788
  (* | LSQBRACKET; l = qexpr_list; RSQBRACKET { A.TupleExpr (mk_pos $startpos, l) } *)
789
  | LCURLYBRACKET; l = pexpr_list(Q); RCURLYBRACKET { A.TupleExpr (mk_pos $startpos, l) }
790

    
791
  (* An array expression (not quantified) *)
792
  | LSQBRACKET; l = pexpr_list(Q); RSQBRACKET { A.ArrayExpr (mk_pos $startpos, l) }
793

    
794
  (* An array constructor (not quantified) *)
795
  | e1 = pexpr(Q); CARET; e2 = expr { A.ArrayConstr (mk_pos $startpos, e1, e2) }
796

    
797
  (* An array slice or tuple projection (not quantified) *)
798
  | e = pexpr(Q); DOTPERCENT; i = expr 
799
    { A.TupleProject (mk_pos $startpos, e, i) }
800

    
801
  (* An array slice (not quantified) *)
802
  | e = pexpr(Q); LSQBRACKET; s = array_slice; RSQBRACKET
803
    { A.ArraySlice (mk_pos $startpos, e, s) }
804

    
805
  (* A record field projection (not quantified) *)
806
  | s = pexpr(Q); DOT; t = ident 
807
    { A.RecordProject (mk_pos $startpos, s, t) }
808

    
809
  (* A record (not quantified) *)
810
  | t = ident; 
811
    f = tlist(LCURLYBRACKET, SEMICOLON, RCURLYBRACKET, record_field_assign)
812
    { A.RecordExpr (mk_pos $startpos, t, f) }
813

    
814
  (* An array concatenation *)
815
  | e1 = pexpr(Q); PIPE; e2 = pexpr(Q) { A.ArrayConcat (mk_pos $startpos, e1, e2) } 
816

    
817
  (* with operator for updating fields of a structure (not quantified) *)
818
  | LPAREN; 
819
    e1 = pexpr(Q); 
820
    WITH; 
821
    i = nonempty_list(label_or_index); 
822
    EQUALS; 
823
    e2 = pexpr(Q); 
824
    RPAREN
825

    
826
    { A.StructUpdate (mk_pos $startpos, e1, i, e2) } 
827

    
828
  (* An arithmetic operation *)
829
  | e1 = pexpr(Q); MINUS; e2 = pexpr(Q) { A.Minus (mk_pos $startpos, e1, e2) }
830
  | MINUS; e = expr { A.Uminus (mk_pos $startpos, e) } 
831
  | e1 = pexpr(Q); PLUS; e2 = pexpr(Q) { A.Plus (mk_pos $startpos, e1, e2) }
832
  | e1 = pexpr(Q); MULT; e2 = pexpr(Q) { A.Times (mk_pos $startpos, e1, e2) }
833
  | e1 = pexpr(Q); DIV; e2 = pexpr(Q) { A.Div (mk_pos $startpos, e1, e2) }
834
  | e1 = pexpr(Q); INTDIV; e2 = pexpr(Q) { A.IntDiv (mk_pos $startpos, e1, e2) }
835
  | e1 = pexpr(Q); MOD; e2 = pexpr(Q) { A.Mod (mk_pos $startpos, e1, e2) }
836

    
837
  (* A Boolean operation *)
838
  | NOT; e = pexpr(Q) { A.Not (mk_pos $startpos, e) } 
839
  | e1 = pexpr(Q); AND; e2 = pexpr(Q) { A.And (mk_pos $startpos, e1, e2) }
840
  | e1 = pexpr(Q); OR; e2 = pexpr(Q) { A.Or (mk_pos $startpos, e1, e2) }
841
  | e1 = pexpr(Q); XOR; e2 = pexpr(Q) { A.Xor (mk_pos $startpos, e1, e2) }
842
  | e1 = pexpr(Q); IMPL; e2 = pexpr(Q) { A.Impl (mk_pos $startpos, e1, e2) }
843
  | HASH; LPAREN; e = pexpr_list(Q); RPAREN { A.OneHot (mk_pos $startpos, e) }
844

    
845
  (* A quantified expression *)
846
  | FORALL; q = Q;
847
    vars = tlist(LPAREN, SEMICOLON, RPAREN, typed_idents); e = pexpr(Q)
848
    %prec prec_forall
849
    { let pos = mk_pos $startpos in
850
      if not q then
851
        assert false
852
               (*LustreContext.fail_at_position
853
          pos "Quantifiers not allowed in this position" *);
854
      A.Forall (pos, List.flatten vars, e) }
855
  | EXISTS; q = Q;
856
    vars = tlist(LPAREN, SEMICOLON, RPAREN, typed_idents); e = pexpr(Q)
857
    %prec prec_exists
858
    { let pos = mk_pos $startpos in
859
      if not q then
860
        assert false 
861
               (* LustreContext.fail_at_position
862
          pos "Quantifiers not allowed in this position" *);
863
      A.Exists (pos, List.flatten vars, e) }
864
                                                                       
865
  (* A relation *)
866
  | e1 = pexpr(Q); LT; e2 = pexpr(Q) { A.Lt (mk_pos $startpos, e1, e2) }
867
  | e1 = pexpr(Q); GT; e2 = pexpr(Q) { A.Gt (mk_pos $startpos, e1, e2) }
868
  | e1 = pexpr(Q); LTE; e2 = pexpr(Q) { A.Lte (mk_pos $startpos, e1, e2) }
869
  | e1 = pexpr(Q); GTE; e2 = pexpr(Q) { A.Gte (mk_pos $startpos, e1, e2) }
870
  | e1 = pexpr(Q); EQUALS; e2 = pexpr(Q) { A.Eq (mk_pos $startpos, e1, e2) } 
871
  | e1 = pexpr(Q); NEQ; e2 = pexpr(Q) { A.Neq (mk_pos $startpos, e1, e2) } 
872

    
873
  (* An if operation *)
874
  | IF; e1 = pexpr(Q); THEN; e2 = pexpr(Q); ELSE; e3 = pexpr(Q) 
875
    { A.Ite (mk_pos $startpos, e1, e2, e3) }
876

    
877
  (* Recursive node call *)
878
  | WITH; e1 = pexpr(Q); THEN; e2 = pexpr(Q); ELSE; e3 = pexpr(Q) 
879
    { A.With (mk_pos $startpos, e1, e2, e3) }
880

    
881
  (* when operator on qexpression  *)
882
  | e1 = pexpr(Q); WHEN; e2 = clock_expr { A.When (mk_pos $startpos, e1, e2) }
883

    
884
  (* current operator on qexpression *)
885
  | CURRENT; e = pexpr(Q) { A.Current (mk_pos $startpos, e) }
886

    
887
  (* condact call with defaults *)
888
  | CONDACT 
889
    LPAREN; 
890
    e1 = pexpr(Q); 
891
    COMMA; 
892
    s = ident; LPAREN; a = separated_list(COMMA, pexpr(Q)); RPAREN; 
893
    COMMA; 
894
    d = pexpr_list(Q)
895
    RPAREN
896
    { let pos = mk_pos $startpos in
897
      A.Condact (pos, e1, A.False pos, s, a, d) } 
898

    
899
  (* condact call may have no return values and therefore no defaults *)
900
  | CONDACT 
901
    LPAREN; 
902
    c = pexpr(Q); 
903
    COMMA; 
904
    s = ident; LPAREN; a = separated_list(COMMA, pexpr(Q)); RPAREN; 
905
    RPAREN
906

    
907
    { let pos = mk_pos $startpos in
908
      A.Condact (pos, c, A.False pos, s, a, []) } 
909

    
910
  (* condact call with defaults and restart *)
911
  | CONDACT LPAREN;
912
    c = pexpr(Q); 
913
    COMMA;
914
    LPAREN RESTART; s = ident; EVERY; r = pexpr(Q); RPAREN;
915
    LPAREN; a = separated_list(COMMA, pexpr(Q)); RPAREN; 
916
    COMMA; 
917
    d = pexpr_list(Q);
918
    RPAREN
919
    { let pos = mk_pos $startpos in
920
      A.Condact (pos, c, r, s, a, d) } 
921

    
922
  (* condact call with no return values and restart *)
923
  | CONDACT ; LPAREN;
924
    c = pexpr(Q); 
925
    COMMA; 
926
    LPAREN RESTART; s = ident; EVERY; r = pexpr(Q); RPAREN
927
    LPAREN; a = separated_list(COMMA, pexpr(Q)); RPAREN; 
928
    RPAREN
929
    { let pos = mk_pos $startpos in
930
      A.Condact (pos, c, r, s, a, []) } 
931

    
932
  (* [(activate N every h initial default (d1, ..., dn)) (e1, ..., en)] 
933
     is an alias for [condact(h, N(e1, ..., en), d1, ,..., dn) ]*)
934
  | LPAREN; ACTIVATE; s = ident; EVERY; c = pexpr(Q); 
935
    INITIAL DEFAULT; d = separated_list(COMMA, pexpr(Q)); RPAREN; 
936
    LPAREN; a = separated_list(COMMA, pexpr(Q)); RPAREN
937

    
938
    { let pos = mk_pos $startpos in
939
      A.Condact (pos, c, A.False pos, s, a, d) }
940
    
941
  (* activate operator without initial defaults
942

    
943
     Only supported inside a merge *)
944
  | LPAREN; ACTIVATE; s = ident; EVERY; c = pexpr(Q); RPAREN; 
945
    LPAREN; a = separated_list(COMMA, pexpr(Q)); RPAREN
946

    
947
    { let pos = mk_pos $startpos in
948
      A.Activate (pos, s, c, A.False pos, a) }
949

    
950
  (* activate restart *)
951
  | LPAREN; ACTIVATE;
952
    LPAREN RESTART; s = ident; EVERY; r = pexpr(Q); RPAREN;
953
    EVERY; c = pexpr(Q); 
954
    INITIAL DEFAULT; d = separated_list(COMMA, pexpr(Q)); RPAREN; 
955
    LPAREN; a = separated_list(COMMA, pexpr(Q)); RPAREN
956

    
957
    { let pos = mk_pos $startpos in
958
      A.Condact (pos, c, r, s, a, d) }
959
    
960
  (* alternative syntax for activate restart *)
961
  | LPAREN; ACTIVATE; s = ident; EVERY; c = pexpr(Q); 
962
    INITIAL DEFAULT; d = separated_list(COMMA, pexpr(Q));
963
    RESTART EVERY; r = pexpr(Q); RPAREN;
964
    LPAREN; a = separated_list(COMMA, pexpr(Q)); RPAREN
965

    
966
    { let pos = mk_pos $startpos in
967
      A.Condact (pos, c, r, s, a, d) }
968
    
969
  (* activate operator without initial defaults and restart
970

    
971
     Only supported inside a merge *)
972
  | LPAREN; ACTIVATE;
973
    LPAREN RESTART; s = ident; EVERY; r = pexpr(Q); RPAREN;
974
    EVERY; c = pexpr(Q); RPAREN; 
975
    LPAREN; a = separated_list(COMMA, pexpr(Q)); RPAREN
976

    
977
    { let pos = mk_pos $startpos in
978
      A.Activate (pos, s, c, r, a) }
979
    
980
  (* alternative syntax of previous construct  *)
981
  | LPAREN; ACTIVATE; s = ident; EVERY; c = pexpr(Q);
982
    RESTART EVERY; r = pexpr(Q); RPAREN;
983
    LPAREN; a = separated_list(COMMA, pexpr(Q)); RPAREN
984

    
985
    { let pos = mk_pos $startpos in
986
      A.Activate (pos, s, c, r, a) }
987

    
988
    
989
  (* restart node call *)
990
  (*| RESTART; s = ident;
991
    LPAREN; a = separated_list(COMMA, pexpr(Q)); RPAREN;
992
    EVERY; c = clock_expr
993

    
994
    { A.RestartEvery (mk_pos $startpos, s, a, c) }
995
   *)
996
    
997
  (* alternative syntax for restart node call *)
998
  | LPAREN; RESTART; s = ident; EVERY; c = pexpr(Q); RPAREN; 
999
    LPAREN; a = separated_list(COMMA, pexpr(Q)); RPAREN
1000

    
1001
    { A.RestartEvery (mk_pos $startpos, s, a, c) }
1002
    
1003
        
1004
  (* Binary merge operator *)
1005
  | MERGE; LPAREN;
1006
    c = ident; SEMICOLON;
1007
    pos = pexpr(Q); SEMICOLON;
1008
    neg = pexpr(Q); RPAREN 
1009
    { A.Merge (mk_pos $startpos, c, ["true", pos; "false", neg]) }
1010

    
1011
  (* N-way merge operator *)
1012
  | MERGE; 
1013
    c = ident;
1014
    l = nonempty_list(merge_case);
1015
    { A.Merge (mk_pos $startpos, c, l) }
1016
    
1017
  (* A temporal operation *)
1018
  | PRE; e = pexpr(Q) { A.Pre (mk_pos $startpos, e) }
1019
  | FBY LPAREN; e1 = pexpr(Q) COMMA; s = NUMERAL; COMMA; e2 = pexpr(Q) RPAREN
1020
    { A.Fby (mk_pos $startpos, e2, (int_of_string s), e2) } 
1021

    
1022
  | e1 = pexpr(Q); ARROW; e2 = pexpr(Q) { A.Arrow (mk_pos $startpos, e1, e2) }
1023

    
1024
  | LAST; i = ident_or_quotident { A.Last (mk_pos $startpos, i) }
1025
    
1026
  (* A node or function call *)
1027
  | e = node_call { e } 
1028

    
1029

    
1030
%inline qexpr:
1031
  | e = pexpr(quantified) { e }
1032

    
1033
%inline expr:
1034
  | e = pexpr(nonquantified) { e }
1035

    
1036

    
1037
(* A list of expressions *)
1038
pexpr_list(Q): l = separated_nonempty_list(COMMA, pexpr(Q)) { l }
1039

    
1040

    
1041
(* Static parameters are only types *)
1042
node_call_static_param:
1043
  | t = lustre_type { t }
1044
      
1045

    
1046
(* A node or function call *)
1047
node_call:
1048

    
1049
  (* Call a node without static parameters *)
1050
  | s = ident; LPAREN; a = separated_list(COMMA, expr); RPAREN 
1051
    { A.Call (mk_pos $startpos, s, a) }
1052

    
1053
  (* Call a node with static parameters *)
1054
  | s = ident; 
1055
    p = tlist 
1056
         (LPARAMBRACKET, SEMICOLON, RPARAMBRACKET, node_call_static_param); 
1057
    LPAREN; 
1058
    a = separated_list(COMMA, expr); 
1059
    RPAREN 
1060
    { A.CallParam (mk_pos $startpos, s, p, a) }
1061

    
1062

    
1063
(* An array slice *)
1064
array_slice:
1065
  | il = expr; DOTDOT; iu = expr { il, iu }
1066
  | i = expr { i, i }
1067

    
1068

    
1069
(* An assignment to a record field *)
1070
record_field_assign: s = ident; EQUALS; e = expr { (s, e) } 
1071

    
1072

    
1073
(* ********************************************************************** *)
1074

    
1075

    
1076
clock_expr:
1077
  | c = ident { A.ClockPos c } 
1078
  | NOT; c = ident { A.ClockNeg c } 
1079
  | NOT; LPAREN; c = ident; RPAREN { A.ClockNeg c } 
1080
  | cs = ident; LPAREN; c = ident; RPAREN { A.ClockConstr (cs, c) } 
1081
  | TRUE { A.ClockTrue }
1082

    
1083
merge_case_id:
1084
  | TRUE { "true" }
1085
  | FALSE { "false" }
1086
  | c = ident { c }
1087

    
1088
merge_case :
1089
  | LPAREN; c = merge_case_id; ARROW; e = expr; RPAREN { c, e }
1090

    
1091
    
1092
(* ********************************************************************** *)
1093

    
1094

    
1095
(* An identifier *)
1096
ident:
1097
  (* Contract tokens are not keywords. *)
1098
  | MODE { "mode" }
1099
  | ASSUME { "assume" }
1100
  | GUARANTEE { "guarantee" }
1101
  | REQUIRE { "require" }
1102
  | ENSURE { "ensure" }
1103
  | s = SYM { s }
1104

    
1105
ident_or_quotident:
1106
  | id = ident { id }
1107
  | s = QUOTSYM { s }
1108

    
1109
(* An identifier with a type *)
1110
typed_ident: s = ident; COLON; t = lustre_type { (mk_pos $startpos, s, t) }
1111

    
1112

    
1113
(* A comma-separated list of identifiers *)
1114
ident_list:
1115
  | l = separated_nonempty_list(COMMA, ident) { l }
1116

    
1117

    
1118
(* A comma-separated list of types *)
1119
lustre_type_list:
1120
  | l = separated_nonempty_list(COMMA, lustre_type) { l }
1121
  
1122

    
1123
(* A comma-separated list of identifiers with position information *)
1124
ident_list_pos :
1125
  | i = ident { [mk_pos $startpos, i] }
1126
  | i = ident; COMMA; l = ident_list_pos
1127
    { (mk_pos $startpos, i) :: l }
1128

    
1129

    
1130
(* A list of comma-separated identifiers with a type *)
1131
typed_idents: 
1132
  | l = ident_list_pos; COLON; t = lustre_type 
1133
    (* Pair each identifier with the type *)
1134
    { List.map (function (pos, e) -> (pos, e, t)) l }
1135

    
1136
(*
1137
(* A list of lists of typed identifiers *)
1138
typed_idents_list:
1139
  | a = separated_list(SEMICOLON, typed_idents) 
1140

    
1141
    (* Return a flat list *)
1142
    { List.flatten a }
1143
*)
1144

    
1145
(* Typed identifiers that may be constant *)
1146
const_typed_idents: 
1147
  | o = boption(CONST); l = typed_idents 
1148

    
1149
    (* Pair each typed identifier with a flag *)
1150
    { List.map (function (_, e, t) -> (e, t, o)) l }
1151

    
1152
(*
1153
(* A list of lists of typed identifiers that may be constant *)
1154
const_typed_idents_list: 
1155
  | a = separated_list(SEMICOLON, const_typed_idents)
1156

    
1157
    (* Return a flat list *)
1158
    { List.flatten a }
1159
*)
1160

    
1161
(* A list of comma-separated identifiers with a type *)
1162
clocked_typed_idents: 
1163

    
1164
  (* Unclocked typed identifiers *)
1165
  | l = typed_idents
1166

    
1167
    (* Pair each typed identifier with the base clock *)
1168
    { List.map (function (pos, e, t) -> (pos, e, t, A.ClockTrue)) l }
1169

    
1170
  (* Clocked typed identifiers *)
1171
  | l = typed_idents; WHEN; c = clock_expr
1172
  | LPAREN; l = typed_idents; RPAREN; WHEN; c = clock_expr
1173

    
1174
    (* Pair each types identifier the given clock *)
1175
    { List.map (function (pos, e, t) -> (pos, e, t, c)) l }
1176

    
1177
  (* Separate rule for non-singleton list to avoid shift/reduce conflict *)
1178
  | LPAREN; 
1179
    h = typed_idents; 
1180
    SEMICOLON; 
1181
    l = tlist_tail(SEMICOLON, RPAREN, typed_idents); 
1182
    WHEN; 
1183
    c = clock_expr
1184

    
1185
    (* Pair each types identifier the given clock *)
1186
    { List.map
1187
        (function (pos, e, t) -> (pos, e, t, c)) 
1188
        (h @ (List.flatten l)) }
1189

    
1190

    
1191
(*
1192
(* A list of lists of typed and clocked identifiers *)
1193
clocked_typed_idents_list: 
1194
  | a = separated_list(SEMICOLON, clocked_typed_idents)
1195

    
1196
    (* Return a flat list *)
1197
    { List.flatten a }
1198
*)
1199

    
1200
(* A list of comma-separated identifiers with a type and a clock that may be constant *)
1201
const_clocked_typed_idents: 
1202

    
1203
  (* Unclocked typed identifiers *)
1204
  | l = const_typed_idents
1205

    
1206
    (* Pair each typed identifier with the base clock *)
1207
    { List.map
1208
        (function (e, t, o) -> (mk_pos $startpos, e, t, A.ClockTrue, o)) 
1209
        l }
1210

    
1211
  (* Clocked typed identifiers *)
1212
  | l = const_typed_idents; WHEN; c = clock_expr
1213
  | LPAREN; l = const_typed_idents; RPAREN; WHEN; c = clock_expr
1214

    
1215
    (* Pair each types identifier the given clock *)
1216
    { List.map
1217
        (function (e, t, o) -> (mk_pos $startpos, e, t, c, o)) 
1218
        l }
1219

    
1220
  (* Separate rule for non-singleton list to avaoid shift/reduce conflict *)
1221
  | LPAREN; 
1222
    h = const_typed_idents; 
1223
    SEMICOLON; 
1224
    l = tlist_tail(SEMICOLON, RPAREN, const_typed_idents); 
1225
    WHEN; 
1226
    c = clock_expr
1227

    
1228
    (* Pair each types identifier the given clock *)
1229
    { List.map (function (e, t, o) -> (mk_pos $startpos, e, t, c, o)) (h @ (List.flatten l)) }
1230

    
1231
(*
1232
(* A list of lists of typed and clocked identifiers that may be constant *)
1233
const_clocked_typed_idents_list: 
1234
  | a = separated_list(SEMICOLON, const_clocked_typed_idents)
1235

    
1236
      { List.flatten a }
1237
*)
1238

    
1239
(* The tail of a list of X *)
1240
tlist_tail(separator, closing, X):
1241
  | x = X; option(separator); closing { [ x ] }
1242
  | x = X; separator; xs = tlist_tail(separator, closing, X)
1243
    { x :: xs }
1244

    
1245
(* A list of elements between opening and closing, separated by separator, 
1246
   the separator may occur at the end of the list *)
1247
tlist(opening, separator, closing, X):
1248
  | opening; l = tlist_tail(separator, closing, X) { l }
1249
  | opening; closing { [ ] }
1250

    
1251
(* ********************************************************************** *)
1252

    
1253

    
1254
(* An index *)
1255
label_or_index: 
1256

    
1257
  (* An index into a record *)
1258
  | DOT; i = ident
1259
     { A.Label (mk_pos $startpos, i) } 
1260

    
1261
  (* An index into an array with a variable or constant *)
1262
  | LSQBRACKET; e = expr; RSQBRACKET
1263
     { A.Index (mk_pos $startpos, e) }
1264

    
1265
  (* An index into a tuple with a variable or constant *)
1266
  | DOTPERCENT; e = expr; 
1267
     { A.Index (mk_pos $startpos, e) }
1268

    
1269

    
1270

    
1271
(* 
1272
   Local Variables:
1273
   compile-command: "make -k"
1274
   indent-tabs-mode: nil
1275
   End: 
1276
*)
1277
  
(10-10/12)