]> matita.cs.unibo.it Git - pkg-cerco/acc.git/blob - src/cminor/cminorParser.mly
Package description and copyright added.
[pkg-cerco/acc.git] / src / cminor / cminorParser.mly
1 /* Adapted from Leroy's CompCert */
2 /* TODO: check coherence with CminorPrinter */
3
4 /* tokens ALLOC, DOLLAR, IN, LET, p_let were unused and have been removed */
5 /* precedence levels unused were also removed */
6
7 /* *********************************************************************/
8 /*                                                                     */
9 /*              The Compcert verified compiler                         */
10 /*                                                                     */
11 /*          Xavier Leroy, INRIA Paris-Rocquencourt                     */
12 /*                                                                     */
13 /*  Copyright Institut National de Recherche en Informatique et en     */
14 /*  Automatique.  All rights reserved.  This file is distributed       */
15 /*  under the terms of the GNU General Public License as published by  */
16 /*  the Free Software Foundation, either version 2 of the License, or  */
17 /*  (at your option) any later version.  This file is also distributed */
18 /*  under the terms of the INRIA Non-Commercial License Agreement.     */
19 /*                                                                     */
20 /* *********************************************************************/
21
22 %{
23
24   open AST
25   open Cminor
26   open Memory
27
28   let error_prefix = "Cminor parser"
29   let error s = Error.global_error error_prefix s
30   let warning s = Error.warning error_prefix s
31   let error_float () = error "float not supported."
32
33   let uint32 = (4, Unsigned)
34   let int32 = (4, Signed)
35
36   (* Function calls are not allowed in the AST of expressions, but function
37      calls in the AST of statements have a special argument which can be used to
38      store the result of the function call in a side-effect manner.
39      Example: the statement
40        x = y + f(z,g(t));
41      will be transformed into the (simplified syntax) AST statements
42        g(_t1,t)
43        f(_t2,y,_t1);
44        x = y + _t2
45      where _t1 and _t2 are fresh temporary variables. *)
46
47
48   (* Thus, to deal with function calls in expressions, we need to create fresh
49      temporary variables *)
50
51   let temp_counter = ref 0
52   let temporaries = ref []
53
54   let mktemp () =
55     incr temp_counter;
56     let id = Printf.sprintf "_t%d" !temp_counter in
57       temporaries := id :: !temporaries;
58       id
59
60
61   (* Expressions with function calls *)
62
63   type rexpr =
64     | RId of ident
65     | RCst of cst
66     | ROp1 of op1 * rexpr
67     | ROp2 of op2 * rexpr * rexpr
68     | RMem of Memory.quantity * rexpr
69     | RCond of rexpr * rexpr * rexpr
70     | RCall of rexpr * rexpr list * signature
71
72   (* [convert_accu] stores the function calls of expressions with function
73      calls being converted to expressions without function calls *)
74   let convert_accu = ref []
75
76   (* [convert_rexpr rexpr] converts the expression with function calls [rexpr]
77      into an expression without function calls. The function calls in [rexpr]
78      are stored in [convert_accu] *)
79   let rec convert_rexpr = function
80     | RId id -> Id id
81     | RCst c -> Cst c
82     | ROp1 (op, e1) -> Op1 (op, convert_rexpr e1)
83     | ROp2 (op, e1, e2) -> Op2 (op, convert_rexpr e1, convert_rexpr e2)
84     | RMem (chunk, e1) -> Mem (chunk, convert_rexpr e1)
85     | RCond (e1, e2, e3) ->
86         Cond (convert_rexpr e1, convert_rexpr e2, convert_rexpr e3)
87     | RCall(e1, el, sg) ->
88         let c1 = convert_rexpr e1 in
89         let cl = convert_rexpr_list el in
90         let t = mktemp() in
91           convert_accu := St_call (Some t, c1, cl, sg) :: !convert_accu;
92           Id t
93
94   and convert_rexpr_list el = List.map convert_rexpr el
95
96   (* [prepend_seq stmts last] reverses and sequences the list of statements
97      [stmts] and puts [last] at the end *)
98   let rec prepend_seq stmts last =
99     match stmts with
100       | [] -> last
101       | s1 :: sl -> prepend_seq sl (St_seq (s1, last))
102
103   (* [mkeval e] creates the AST statement associated to the Cminor instruction
104        e;
105      where [e] is an expression with possible function calls *)
106   let mkeval e =
107     convert_accu := [];
108     match e with
109       | RCall (e1, el, sg) ->
110           let c1 = convert_rexpr e1 in
111           let cl = convert_rexpr_list el in
112             prepend_seq !convert_accu (St_call (None, c1, cl, sg))
113       | _ ->
114           ignore (convert_rexpr e);
115           prepend_seq !convert_accu St_skip
116
117   (* [mkeval id e] creates the AST statement associated to the Cminor
118      instruction
119        id = e;
120      where [e] is an expression with possible function calls *)
121   let mkassign id e =
122     convert_accu := [];
123     match e with
124       | RCall (e1, el, sg) ->
125           let c1 = convert_rexpr e1 in
126           let cl = convert_rexpr_list el in
127             prepend_seq !convert_accu (St_call (Some id, c1, cl, sg))
128       | _ ->
129           let c = convert_rexpr e in
130             prepend_seq !convert_accu (St_assign (id, c))
131
132   (* [mkstore size e1 e2] creates the AST statement associated to the Cminor
133      instruction
134        size[e1] = e2;
135      where [e1] and [e2] are expressions with possible function calls *)
136   let mkstore size e1 e2 =
137     convert_accu := [];
138     let c1 = convert_rexpr e1 in
139     let c2 = convert_rexpr e2 in
140       prepend_seq !convert_accu (St_store (size, c1, c2))
141
142   (* [mkifthenelse e s1 s2] creates the AST statement associated to the Cminor
143      instruction
144        if (e) { s1 } else { s2 }
145      where [e] is an expression with possible function calls *)
146   let mkifthenelse e s1 s2 =
147     convert_accu := [];
148     let c = convert_rexpr e in
149       prepend_seq !convert_accu (St_ifthenelse (c, s1, s2))
150
151   (* [mkreturn_some e] creates the AST statement associated to the Cminor
152      instruction
153        return e;
154      where [e] is an expression with possible function calls *)
155   let mkreturn_some e =
156     convert_accu := [];
157     let c = convert_rexpr e in
158       prepend_seq !convert_accu (St_return (Some c))
159
160   (* [mkswitch e (cases, dfl)] creates the AST statement associated to the
161      Cminor instruction
162        switch (e) {
163          case i: exit j_i;
164          ...
165          default: exit j_default; }
166      where [e] is an expression with possible function calls *)
167   let mkswitch e (cases, dfl) =
168     convert_accu := [];
169     let c = convert_rexpr e in
170       prepend_seq !convert_accu (St_switch (c, cases, dfl))
171
172   (* The Cminor instruction
173       match (e) {
174         case 0: s0;
175         case 1: s1;
176         case 2: s2; }
177      is syntaxic sugar for the Cminor instruction
178        block {
179          block {
180            block {
181              block {
182                switch (e) {
183                  case 0: exit 0;
184                  case 1: exit 1;
185                  default: exit 2; }
186              } s0; exit 2;
187            } s1; exit 1;
188          } s2;
189        }
190      Note that matches are assumed to be exhaustive *)
191
192   let mkmatch_aux e cases =
193     let ncases = List.length cases in
194     let rec mktable n = function
195       | [] -> assert false
196       | [key, action] -> []
197       | (key, action) :: rem -> (key, n) :: mktable (n+1) rem in
198     let sw =
199       St_switch (e, mktable 0 cases, pred ncases) in
200     let rec mkblocks body n = function
201       | [] -> assert false
202       | [key, action] -> St_block (St_seq (body, action))
203       | (key, action) :: rem ->
204           mkblocks
205             (St_block (St_seq (body, St_seq (action, St_exit n))))
206             (pred n) rem in
207       mkblocks (St_block sw) (pred ncases) cases
208
209   (* [mkmatch e cases] creates the AST statement associated to the Cminor
210      instruction
211        match (e) {
212          case i: s_i;
213          ... }
214      where [e] is an expression with possible function calls *)
215   let mkmatch e cases =
216     convert_accu := [];
217     let c = convert_rexpr e in
218     let s =
219       match cases with
220         | [] -> St_skip (* ??? *)
221         | [key, action] -> action
222         | _ -> mkmatch_aux c cases in
223       prepend_seq !convert_accu s
224
225   (* [mktailcall f [e1;e2;...] sig] creates the AST statement associated to the
226      Cminor instruction
227      tailcall f(e1,e2,...): sig
228      where [e], [e1], [e2], ... are expressions with possible function calls *)
229   let mktailcall e1 el sg =
230     convert_accu := [];
231     let c1 = convert_rexpr e1 in
232     let cl = convert_rexpr_list el in
233       prepend_seq !convert_accu (St_tailcall (c1, cl, sg))
234
235   (* Parse error handler *)
236   let raise_error (_, pos) s = Error.error "parse error" pos (s ^ "\n")
237
238 %}
239
240 %token ABSF
241 %token AMPERSAND
242 %token AMPERSANDAMPERSAND
243 %token BANG
244 %token BANGEQUAL
245 %token BANGEQUALF
246 %token BANGEQUALU
247 %token BAR
248 %token BARBAR
249 %token CARET
250 %token CASE
251 %token COLON
252 %token COMMA
253 %token DEFAULT
254 %token ELSE
255 %token EQUAL
256 %token EQUALEQUAL
257 %token EQUALEQUALF
258 %token EQUALEQUALU
259 %token EOF
260 %token EXIT
261 %token EXTERN
262 %token FLOAT
263 %token FLOAT32
264 %token FLOAT64
265 %token <float> FLOATLIT
266 %token FLOATOFINT
267 %token FLOATOFINTU
268 %token GREATER
269 %token GREATERF
270 %token GREATERU
271 %token GREATEREQUAL
272 %token GREATEREQUALF
273 %token GREATEREQUALU
274 %token GREATERGREATER
275 %token GREATERGREATERU
276 %token <string> IDENT
277 %token IF
278 %token INT
279 %token INT8
280 %token INT16
281 %token INT32
282 %token INT8STO8
283 %token INT8STO16
284 %token INT8STO32
285 %token INT8UTO8
286 %token INT8UTO16
287 %token INT8UTO32
288 %token INT16STO8
289 %token INT16STO16
290 %token INT16STO32
291 %token INT16UTO8
292 %token INT16UTO16
293 %token INT16UTO32
294 %token INT32STO8
295 %token INT32STO16
296 %token INT32STO32
297 %token INT32UTO8
298 %token INT32UTO16
299 %token INT32UTO32
300 %token <int> INTLIT
301 %token INTOFFLOAT
302 %token INTUOFFLOAT
303 %token LBRACE
304 /* %token LBRACELBRACE */
305 %token LBRACKET
306 %token LESS
307 %token LESSU
308 %token LESSF
309 %token LESSEQUAL
310 %token LESSEQUALU
311 %token LESSEQUALF
312 %token LESSLESS
313 %token LOOP
314 %token LPAREN
315 %token MATCH
316 %token MINUS
317 %token MINUSF
318 %token MINUSGREATER
319 %token PERCENT
320 %token PERCENTU
321 %token PLUS
322 %token PLUSF
323 %token QUESTION
324 %token RBRACE
325 /* %token RBRACERBRACE */
326 %token RBRACKET
327 %token RETURN
328 %token RPAREN
329 %token SEMICOLON
330 %token SLASH
331 %token SLASHF
332 %token SLASHU
333 %token STACK
334 %token STAR
335 %token STARF
336 %token <string> STRINGLIT
337 %token SWITCH
338 %token TILDE
339 %token TAILCALL
340 %token VAR
341 %token VOID
342 %token GOTO BLOCK
343 %token PTR
344
345 /* Unused */
346 /* %token ALLOC DOLLAR IN LET p_let */
347
348 /* Precedences from low to high */
349
350 /* %left COMMA */
351 /* %left p_let */
352 /* %right EQUAL */
353 %right QUESTION COLON
354 %left BARBAR
355 %left AMPERSANDAMPERSAND
356 %left BAR
357 %left CARET
358 %left AMPERSAND
359 %left EQUALEQUAL BANGEQUAL LESS LESSEQUAL GREATER GREATEREQUAL EQUALEQUALU BANGEQUALU LESSU LESSEQUALU GREATERU GREATEREQUALU EQUALEQUALF BANGEQUALF LESSF LESSEQUALF GREATERF GREATEREQUALF 
360 %left LESSLESS GREATERGREATER GREATERGREATERU
361 %left PLUS PLUSF MINUS MINUSF
362 %left STAR SLASH PERCENT STARF SLASHF SLASHU PERCENTU
363 %nonassoc BANG TILDE p_uminus ABSF INTOFFLOAT INTUOFFLOAT FLOATOFINT FLOATOFINTU FLOAT32 /* ALLOC */
364 %left LPAREN
365
366 /* Entry point */
367
368 %start program
369 %type <Cminor.program> program
370
371 %%
372
373 %inline position(X): x = X { (x, Position.lex_join $startpos $endpos) }
374
375 /* Programs */
376
377 program:
378     global_declarations proc_list EOF { { vars   = List.rev $1 ;
379                                           functs = List.rev $2 ;
380                                           main   = Some "main" } }
381 ;
382
383 global_declarations:
384     /* empty */                            { [] }
385   | global_declarations global_declaration { $2 :: $1 }
386 ;
387
388 global_declaration:
389     VAR STRINGLIT init_datas { ($2, List.rev $3) }
390   | pos = position(error)    { raise_error pos
391                                  "Global declaration syntax error" }
392 ;
393
394 init_datas:
395     /* empty */                  { [] }
396   | init_data                    { [$1] }
397   | LBRACE init_data_list RBRACE { $2 }
398 ;
399
400 init_data:
401     INTLIT                         { AST.Data_int32 $1 }
402   | FLOATLIT                       { AST.Data_float32 $1 }
403   | LPAREN INT8 RPAREN INTLIT      { AST.Data_int8 $4 }
404   | LPAREN INT16 RPAREN INTLIT     { AST.Data_int16 $4 }
405   | LPAREN INT32 RPAREN INTLIT     { AST.Data_int32 $4 }
406   | LPAREN FLOAT32 RPAREN FLOATLIT { AST.Data_float32 $4 }
407   | LPAREN FLOAT64 RPAREN FLOATLIT { AST.Data_float64 $4 }
408   | LBRACKET INTLIT RBRACKET       { AST.Data_reserve $2 }
409 ;
410
411 quantity:
412     INTLIT { Memory.QInt $1 }
413   | PTR    { Memory.QPtr }
414
415 init_data_list:
416     init_data                      { [$1] }
417   | init_data COMMA init_data_list { $1 :: $3 }
418 ;
419
420 proc_list:
421     /* empty */    { [] }
422   | proc_list proc { $2 :: $1 }
423 ;
424
425 /* Procedures */
426
427 proc:
428     STRINGLIT LPAREN parameters RPAREN COLON signature
429     LBRACE
430       stack_declaration
431       var_declarations
432       stmt_list
433     RBRACE
434   { let tmp = !temporaries in
435       temporaries := [];
436       temp_counter := 0;
437       ($1, F_int { f_sig = $6 ;
438                    f_params = List.rev $3 ;
439                    f_vars = List.rev (tmp @ $9) ;
440                    f_ptrs = [] (* TODO *) ;
441                    f_stacksize = $8 ;
442                    f_body = $10 }) }
443   | EXTERN STRINGLIT COLON signature { ($2, F_ext { ef_tag = $2 ;
444                                                     ef_sig = $4 }) }
445   | pos = position(error) { raise_error pos
446                             "Procedure or function declaration syntax error" }
447 ;
448
449 parameters:
450     /* empty */    { [] }
451   | parameter_list { $1 }
452 ;
453
454 parameter_list:
455     IDENT                      { $1 :: [] }
456   | parameter_list COMMA IDENT { $3 :: $1 }
457   | pos = position(error) { raise_error pos
458                             "Parameter declaration syntax error" }
459 ;
460
461 signature:
462     type_  { { args = [] ; res = Type_ret $1 } }
463   | VOID
464       { { args = [] ; res = Type_void } }
465   | type_ MINUSGREATER signature
466           { let s = $3 in {s with args = $1 :: s.args } }
467   | pos = position(error) { raise_error pos "Signature syntax error" }
468 ;
469
470 stack_declaration:
471     /* empty */            { 0 }
472   | STACK INTLIT SEMICOLON { $2 }
473   | pos = position(error)  { raise_error pos "Stack declaration syntax error" }
474 ;
475
476 var_declarations:
477     /* empty */                      { [] }
478   | var_declarations var_declaration { $2 @ $1 }
479   | pos = position(error)            { raise_error pos
480                                          "Variable declaration syntax error" }
481 ;
482
483 var_declaration:
484     VAR parameter_list SEMICOLON { $2 }
485 ;
486
487 /* Statements */
488
489 stmt:
490     expr SEMICOLON                         { mkeval $1 }
491   | IDENT EQUAL expr SEMICOLON             { mkassign $1 $3 }
492   | quantity LBRACKET expr RBRACKET EQUAL expr SEMICOLON
493       { mkstore $1 $3 $6 }
494   | IF LPAREN expr RPAREN stmts ELSE stmts { mkifthenelse $3 $5 $7 }
495   | IF LPAREN expr RPAREN stmts            { mkifthenelse $3 $5 St_skip }
496   | LOOP stmts                             { St_loop $2 }
497   | BLOCK LBRACE stmt_list RBRACE          { St_block $3 }
498   | EXIT SEMICOLON                         { St_exit 0 }
499   | EXIT INTLIT SEMICOLON                  { St_exit $2 }
500   | RETURN SEMICOLON                       { St_return None }
501   | RETURN expr SEMICOLON                  { mkreturn_some $2 }
502   | GOTO IDENT SEMICOLON                   { St_goto $2 }
503   | IDENT COLON stmt                       { St_label ($1, $3) }
504   | SWITCH LPAREN expr RPAREN LBRACE switch_cases RBRACE
505         { mkswitch $3 $6 }
506   | MATCH LPAREN expr RPAREN LBRACE match_cases RBRACE
507           { mkmatch $3 $6 }
508   | TAILCALL expr LPAREN expr_list RPAREN COLON signature SEMICOLON
509               { mktailcall $2 $4 $7 }
510 ;
511
512 stmt_list:
513     /* empty */    { St_skip }
514   | stmt stmt_list { St_seq ($1, $2) }
515   | pos = position(error) { raise_error pos "Statement syntax error" }
516 ;
517
518 stmts:
519     LBRACE stmt_list RBRACE { $2 }
520   | stmt                    { $1 }
521 ;
522
523 switch_cases:
524     DEFAULT COLON EXIT INTLIT SEMICOLON
525     { ([], $4) }
526   | CASE INTLIT COLON EXIT INTLIT SEMICOLON switch_cases
527         { let (cases, dfl) = $7 in (($2, $5) :: cases, dfl) }
528   | pos = position(error) { raise_error pos "Syntax error in switch construct" }
529 ;
530
531 match_cases:
532     /* empty */                             { [] }
533   | CASE INTLIT COLON stmt_list match_cases { ($2, $4) :: $5 }
534   | pos = position(error) { raise_error pos "Syntax error in match construct" }
535 ;
536
537 /* Expressions */
538
539 expr:
540     LPAREN expr RPAREN                      { $2 }
541   | IDENT                               { RId $1 }
542   | INTLIT                              { RCst (Cst_int $1) }
543   | FLOATLIT                            { RCst (Cst_float $1) }
544   | STRINGLIT                           { RCst (Cst_addrsymbol $1) }
545   | AMPERSAND INTLIT                    { RCst (Cst_stackoffset $2) }
546   | MINUS expr    %prec p_uminus        { ROp1 (Op_negint int32, $2) }
547   | MINUSF expr   %prec p_uminus        { error_float () }
548   | ABSF expr                           { error_float () }
549   | INTOFFLOAT expr                     { error_float () }
550   | INTUOFFLOAT expr                    { error_float () }
551   | FLOATOFINT expr                     { error_float () }
552   | FLOATOFINTU expr                    { error_float () }
553   | TILDE expr                          { ROp1 (Op_notint int32, $2) }
554   | BANG expr                           { ROp1 (Op_notbool, $2) }
555   | INT8STO8 expr                       { ROp1 (Op_cast ((8, Signed), 8), $2) }
556   | INT8STO16 expr                      { ROp1 (Op_cast ((8, Signed), 16), $2) }
557   | INT8STO32 expr                      { ROp1 (Op_cast ((8, Signed), 32), $2) }
558   | INT8UTO8 expr                      { ROp1 (Op_cast ((8, Unsigned), 8), $2) }
559   | INT8UTO16 expr                    { ROp1 (Op_cast ((8, Unsigned), 16), $2) }
560   | INT8UTO32 expr                    { ROp1 (Op_cast ((8, Unsigned), 32), $2) }
561   | INT16STO8 expr                     { ROp1 (Op_cast ((16, Signed), 16), $2) }
562   | INT16STO16 expr                    { ROp1 (Op_cast ((16, Signed), 16), $2) }
563   | INT16STO32 expr                    { ROp1 (Op_cast ((16, Signed), 32), $2) }
564   | INT16UTO8 expr                    { ROp1 (Op_cast ((16, Unsigned), 8), $2) }
565   | INT16UTO16 expr                  { ROp1 (Op_cast ((16, Unsigned), 16), $2) }
566   | INT16UTO32 expr                  { ROp1 (Op_cast ((16, Unsigned), 32), $2) }
567   | INT32STO8 expr                      { ROp1 (Op_cast ((32, Signed), 8), $2) }
568   | INT32STO16 expr                    { ROp1 (Op_cast ((32, Signed), 16), $2) }
569   | INT32STO32 expr                    { ROp1 (Op_cast ((32, Signed), 32), $2) }
570   | INT32UTO8 expr                    { ROp1 (Op_cast ((32, Unsigned), 8), $2) }
571   | INT32UTO16 expr                  { ROp1 (Op_cast ((32, Unsigned), 16), $2) }
572   | INT32UTO32 expr                  { ROp1 (Op_cast ((32, Unsigned), 32), $2) }
573   | FLOAT32 expr                        { error_float () }
574   | expr PLUS expr                      { ROp2 (Op_add int32, $1, $3) }
575   | expr MINUS expr                     { ROp2 (Op_sub int32, $1, $3) }
576   | expr STAR expr                      { ROp2 (Op_mul int32, $1, $3) }
577   | expr SLASH expr                     { ROp2 (Op_div int32, $1, $3) }
578   | expr PERCENT expr                   { ROp2 (Op_mod int32, $1, $3) }
579   | expr SLASHU expr                    { ROp2 (Op_div uint32, $1, $3) }
580   | expr PERCENTU expr                  { ROp2 (Op_mod uint32, $1, $3) }
581   | expr AMPERSAND expr                 { ROp2 (Op_and, $1, $3) }
582   | expr BAR expr                       { ROp2 (Op_or, $1, $3) }
583   | expr CARET expr                     { ROp2 (Op_xor, $1, $3) }
584   | expr LESSLESS expr                  { ROp2 (Op_shl int32, $1, $3) }
585   | expr GREATERGREATER expr            { ROp2 (Op_shr int32, $1, $3) }
586   | expr GREATERGREATERU expr           { ROp2 (Op_shr uint32, $1, $3) }
587   | expr PLUSF expr                     { error_float () }
588   | expr MINUSF expr                    { error_float () }
589   | expr STARF expr                     { error_float () }
590   | expr SLASHF expr                    { error_float () }
591   | expr EQUALEQUAL expr               { ROp2 (Op_cmp (Cmp_eq, int32), $1, $3) }
592   | expr BANGEQUAL expr                { ROp2 (Op_cmp (Cmp_ne, int32), $1, $3) }
593   | expr LESS expr                     { ROp2 (Op_cmp (Cmp_lt, int32), $1, $3) }
594   | expr LESSEQUAL expr                { ROp2 (Op_cmp (Cmp_le, int32), $1, $3) }
595   | expr GREATER expr                  { ROp2 (Op_cmp (Cmp_gt, int32), $1, $3) }
596   | expr GREATEREQUAL expr             { ROp2 (Op_cmp (Cmp_ge, int32), $1, $3) }
597   | expr EQUALEQUALU expr             { ROp2 (Op_cmp (Cmp_eq, uint32), $1, $3) }
598   | expr BANGEQUALU expr              { ROp2 (Op_cmp (Cmp_ne, uint32), $1, $3) }
599   | expr LESSU expr                   { ROp2 (Op_cmp (Cmp_lt, uint32), $1, $3) }
600   | expr LESSEQUALU expr              { ROp2 (Op_cmp (Cmp_le, uint32), $1, $3) }
601   | expr GREATERU expr                { ROp2 (Op_cmp (Cmp_gt, uint32), $1, $3) }
602   | expr GREATEREQUALU expr           { ROp2 (Op_cmp (Cmp_ge, uint32), $1, $3) }
603   | expr EQUALEQUALF expr               { error_float () }
604   | expr BANGEQUALF expr                { error_float () }
605   | expr LESSF expr                     { error_float () }
606   | expr LESSEQUALF expr                { error_float () }
607   | expr GREATERF expr                  { error_float () }
608   | expr GREATEREQUALF expr             { error_float () }
609   | quantity LBRACKET expr RBRACKET       { RMem ($1, $3) }
610   | expr AMPERSANDAMPERSAND expr        { RCond ($1, $3, RCst (Cst_int 0)) }
611   | expr BARBAR expr                    { RCond ($1, RCst (Cst_int 1), $3) }
612   | expr QUESTION expr COLON expr       { RCond ($1, $3, $5) }
613   | expr LPAREN expr_list RPAREN COLON signature
614       { RCall ($1, $3, $6) }
615   | pos = position(error) { raise_error pos "Expression syntax error" }
616 ;
617
618 expr_list:
619     /* empty */ { [] }
620   | expr_list_1 { $1 }
621 ;
622
623 expr_list_1:
624     expr /* %prec COMMA */ { $1 :: [] }
625   | expr COMMA expr_list_1 { $1 :: $3 }
626 ;
627
628 type_:
629     INT   { Sig_int }
630   | FLOAT { Sig_float }
631 ;
632