1 /* Adapted from Leroy's CompCert */
2 /* TODO: check coherence with CminorPrinter */
4 /* tokens ALLOC, DOLLAR, IN, LET, p_let were unused and have been removed */
5 /* precedence levels unused were also removed */
7 /* *********************************************************************/
9 /* The Compcert verified compiler */
11 /* Xavier Leroy, INRIA Paris-Rocquencourt */
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. */
20 /* *********************************************************************/
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."
33 let uint32 = (4, Unsigned)
34 let int32 = (4, Signed)
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
41 will be transformed into the (simplified syntax) AST statements
45 where _t1 and _t2 are fresh temporary variables. *)
48 (* Thus, to deal with function calls in expressions, we need to create fresh
49 temporary variables *)
51 let temp_counter = ref 0
52 let temporaries = ref []
56 let id = Printf.sprintf "_t%d" !temp_counter in
57 temporaries := id :: !temporaries;
61 (* Expressions with function calls *)
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
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 []
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
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
91 convert_accu := St_call (Some t, c1, cl, sg) :: !convert_accu;
94 and convert_rexpr_list el = List.map convert_rexpr el
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 =
101 | s1 :: sl -> prepend_seq sl (St_seq (s1, last))
103 (* [mkeval e] creates the AST statement associated to the Cminor instruction
105 where [e] is an expression with possible function calls *)
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))
114 ignore (convert_rexpr e);
115 prepend_seq !convert_accu St_skip
117 (* [mkeval id e] creates the AST statement associated to the Cminor
120 where [e] is an expression with possible function calls *)
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))
129 let c = convert_rexpr e in
130 prepend_seq !convert_accu (St_assign (id, c))
132 (* [mkstore size e1 e2] creates the AST statement associated to the Cminor
135 where [e1] and [e2] are expressions with possible function calls *)
136 let mkstore size e1 e2 =
138 let c1 = convert_rexpr e1 in
139 let c2 = convert_rexpr e2 in
140 prepend_seq !convert_accu (St_store (size, c1, c2))
142 (* [mkifthenelse e s1 s2] creates the AST statement associated to the Cminor
144 if (e) { s1 } else { s2 }
145 where [e] is an expression with possible function calls *)
146 let mkifthenelse e s1 s2 =
148 let c = convert_rexpr e in
149 prepend_seq !convert_accu (St_ifthenelse (c, s1, s2))
151 (* [mkreturn_some e] creates the AST statement associated to the Cminor
154 where [e] is an expression with possible function calls *)
155 let mkreturn_some e =
157 let c = convert_rexpr e in
158 prepend_seq !convert_accu (St_return (Some c))
160 (* [mkswitch e (cases, dfl)] creates the AST statement associated to the
165 default: exit j_default; }
166 where [e] is an expression with possible function calls *)
167 let mkswitch e (cases, dfl) =
169 let c = convert_rexpr e in
170 prepend_seq !convert_accu (St_switch (c, cases, dfl))
172 (* The Cminor instruction
177 is syntaxic sugar for the Cminor instruction
190 Note that matches are assumed to be exhaustive *)
192 let mkmatch_aux e cases =
193 let ncases = List.length cases in
194 let rec mktable n = function
196 | [key, action] -> []
197 | (key, action) :: rem -> (key, n) :: mktable (n+1) rem in
199 St_switch (e, mktable 0 cases, pred ncases) in
200 let rec mkblocks body n = function
202 | [key, action] -> St_block (St_seq (body, action))
203 | (key, action) :: rem ->
205 (St_block (St_seq (body, St_seq (action, St_exit n))))
207 mkblocks (St_block sw) (pred ncases) cases
209 (* [mkmatch e cases] creates the AST statement associated to the Cminor
214 where [e] is an expression with possible function calls *)
215 let mkmatch e cases =
217 let c = convert_rexpr e in
220 | [] -> St_skip (* ??? *)
221 | [key, action] -> action
222 | _ -> mkmatch_aux c cases in
223 prepend_seq !convert_accu s
225 (* [mktailcall f [e1;e2;...] sig] creates the AST statement associated to the
227 tailcall f(e1,e2,...): sig
228 where [e], [e1], [e2], ... are expressions with possible function calls *)
229 let mktailcall e1 el sg =
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))
235 (* Parse error handler *)
236 let raise_error (_, pos) s = Error.error "parse error" pos (s ^ "\n")
242 %token AMPERSANDAMPERSAND
265 %token <float> FLOATLIT
274 %token GREATERGREATER
275 %token GREATERGREATERU
276 %token <string> IDENT
304 /* %token LBRACELBRACE */
325 /* %token RBRACERBRACE */
336 %token <string> STRINGLIT
346 /* %token ALLOC DOLLAR IN LET p_let */
348 /* Precedences from low to high */
353 %right QUESTION COLON
355 %left AMPERSANDAMPERSAND
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 */
369 %type <Cminor.program> program
373 %inline position(X): x = X { (x, Position.lex_join $startpos $endpos) }
378 global_declarations proc_list EOF { { vars = List.rev $1 ;
379 functs = List.rev $2 ;
380 main = Some "main" } }
385 | global_declarations global_declaration { $2 :: $1 }
389 VAR STRINGLIT init_datas { ($2, List.rev $3) }
390 | pos = position(error) { raise_error pos
391 "Global declaration syntax error" }
397 | LBRACE init_data_list RBRACE { $2 }
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 }
412 INTLIT { Memory.QInt $1 }
413 | PTR { Memory.QPtr }
417 | init_data COMMA init_data_list { $1 :: $3 }
422 | proc_list proc { $2 :: $1 }
428 STRINGLIT LPAREN parameters RPAREN COLON signature
434 { let tmp = !temporaries in
437 ($1, F_int { f_sig = $6 ;
438 f_params = List.rev $3 ;
439 f_vars = List.rev (tmp @ $9) ;
440 f_ptrs = [] (* TODO *) ;
443 | EXTERN STRINGLIT COLON signature { ($2, F_ext { ef_tag = $2 ;
445 | pos = position(error) { raise_error pos
446 "Procedure or function declaration syntax error" }
451 | parameter_list { $1 }
456 | parameter_list COMMA IDENT { $3 :: $1 }
457 | pos = position(error) { raise_error pos
458 "Parameter declaration syntax error" }
462 type_ { { args = [] ; res = Type_ret $1 } }
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" }
472 | STACK INTLIT SEMICOLON { $2 }
473 | pos = position(error) { raise_error pos "Stack declaration syntax error" }
478 | var_declarations var_declaration { $2 @ $1 }
479 | pos = position(error) { raise_error pos
480 "Variable declaration syntax error" }
484 VAR parameter_list SEMICOLON { $2 }
490 expr SEMICOLON { mkeval $1 }
491 | IDENT EQUAL expr SEMICOLON { mkassign $1 $3 }
492 | quantity LBRACKET expr RBRACKET EQUAL expr SEMICOLON
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
506 | MATCH LPAREN expr RPAREN LBRACE match_cases RBRACE
508 | TAILCALL expr LPAREN expr_list RPAREN COLON signature SEMICOLON
509 { mktailcall $2 $4 $7 }
513 /* empty */ { St_skip }
514 | stmt stmt_list { St_seq ($1, $2) }
515 | pos = position(error) { raise_error pos "Statement syntax error" }
519 LBRACE stmt_list RBRACE { $2 }
524 DEFAULT COLON EXIT INTLIT SEMICOLON
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" }
533 | CASE INTLIT COLON stmt_list match_cases { ($2, $4) :: $5 }
534 | pos = position(error) { raise_error pos "Syntax error in match construct" }
540 LPAREN expr RPAREN { $2 }
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" }
624 expr /* %prec COMMA */ { $1 :: [] }
625 | expr COMMA expr_list_1 { $1 :: $3 }
630 | FLOAT { Sig_float }