465 lines
13 KiB
OCaml
465 lines
13 KiB
OCaml
|
%{
|
||
|
|
||
|
(*
|
||
|
* Copyright (c) 2005 by Laboratoire Spécification et Vérification
|
||
|
* (LSV), UMR 8643 CNRS & ENS Cachan.
|
||
|
* Written by Jean Goubault-Larrecq. Derived from the csur project.
|
||
|
*
|
||
|
* Permission is granted to anyone to use this software for any
|
||
|
* purpose on any computer system, and to redistribute it freely,
|
||
|
* subject to the following restrictions:
|
||
|
*
|
||
|
* 1. Neither the author nor its employer is responsible for the
|
||
|
* consequences of use of this software, no matter how awful, even if
|
||
|
* they arise from defects in it.
|
||
|
*
|
||
|
* 2. The origin of this software must not be misrepresented, either
|
||
|
* by explicit claim or by omission.
|
||
|
*
|
||
|
* 3. Altered versions must be plainly marked as such, and must not
|
||
|
* be misrepresented as being the original software.
|
||
|
*
|
||
|
* 4. This software is restricted to non-commercial use only. Commercial
|
||
|
* use is subject to a specific license, obtainable from LSV.
|
||
|
*
|
||
|
*)
|
||
|
|
||
|
(* Analyse syntaxique d'un sous-ensemble (tres) reduit de C.
|
||
|
*)
|
||
|
|
||
|
open Cparse
|
||
|
open Error
|
||
|
|
||
|
let parse_error msg =
|
||
|
fatal (Some (getloc ())) msg
|
||
|
|
||
|
%}
|
||
|
|
||
|
%token <string> IDENTIFIER TYPE_NAME
|
||
|
%token <int> CONSTANT
|
||
|
%token <string> STRING_LITERAL
|
||
|
%token SIZEOF
|
||
|
%token PTR_OP INC_OP DEC_OP LEFT_OP RIGHT_OP LE_OP GE_OP EQ_OP NE_OP
|
||
|
%token AND_OP OR_OP MUL_ASSIGN DIV_ASSIGN MOD_ASSIGN ADD_ASSIGN
|
||
|
%token SUB_ASSIGN LEFT_ASSIGN RIGHT_ASSIGN AND_ASSIGN
|
||
|
%token XOR_ASSIGN OR_ASSIGN
|
||
|
%token SEMI_CHR OPEN_BRACE_CHR CLOSE_BRACE_CHR COMMA_CHR COLON_CHR
|
||
|
%token EQ_CHR OPEN_PAREN_CHR CLOSE_PAREN_CHR OPEN_BRACKET_CHR
|
||
|
%token CLOSE_BRACKET_CHR DOT_CHR AND_CHR OR_CHR XOR_CHR BANG_CHR
|
||
|
%token TILDE_CHR ADD_CHR SUB_CHR STAR_CHR DIV_CHR MOD_CHR
|
||
|
%token OPEN_ANGLE_CHR CLOSE_ANGLE_CHR QUES_CHR
|
||
|
%token TYPEDEF EXTERN STATIC AUTO REGISTER
|
||
|
%token CHAR SHORT INTEGER LONG SIGNED UNSIGNED FLOATING DOUBLE CONST VOLATILE VOID
|
||
|
%token STRUCT UNION ENUM ELLIPSIS EOF
|
||
|
%token CASE DEFAULT IF ELSE SWITCH WHILE DO FOR GOTO CONTINUE BREAK RETURN
|
||
|
%token ASM
|
||
|
|
||
|
%type <(Cparse.var_declaration list)> translation_unit
|
||
|
|
||
|
%start translation_unit
|
||
|
%%
|
||
|
|
||
|
primary_expression:
|
||
|
identifier { let loc, var = $1 in loc, VAR var }
|
||
|
| constant { let loc, cst = $1 in loc, CST cst }
|
||
|
| string_literal { let loc, s = $1 in loc, STRING s }
|
||
|
| OPEN_PAREN_CHR expression CLOSE_PAREN_CHR { $2 }
|
||
|
;
|
||
|
|
||
|
constant : CONSTANT { getloc (), $1 };
|
||
|
|
||
|
identifier : IDENTIFIER { getloc (), $1 };
|
||
|
open_brace : OPEN_BRACE_CHR { getloc () };
|
||
|
close_brace : CLOSE_BRACE_CHR { getloc () };
|
||
|
|
||
|
string_literal:
|
||
|
STRING_LITERAL { getloc (), $1 }
|
||
|
| STRING_LITERAL string_literal
|
||
|
{
|
||
|
let l, s = $2 in
|
||
|
let s2 = $1 in
|
||
|
(getloc (), s2^s)
|
||
|
}
|
||
|
|
||
|
inc_op : INC_OP { getloc () }
|
||
|
dec_op : DEC_OP { getloc () }
|
||
|
|
||
|
postfix_expression:
|
||
|
primary_expression { $1 }
|
||
|
| postfix_expression OPEN_BRACKET_CHR expression close_bracket
|
||
|
{ sup_locator (loc_of_expr $1) $4, OP2 (S_INDEX, $1, $3) }
|
||
|
| identifier OPEN_PAREN_CHR close_paren
|
||
|
{ let loc, var = $1 in
|
||
|
let loc1 = sup_locator loc $3 in
|
||
|
loc1, CALL (var, [])
|
||
|
}
|
||
|
| identifier OPEN_PAREN_CHR argument_expression_list close_paren
|
||
|
{ let loc, var = $1 in
|
||
|
let loc1 = sup_locator loc $4 in
|
||
|
loc1, CALL (var, List.rev $3)
|
||
|
}
|
||
|
| postfix_expression inc_op
|
||
|
{ sup_locator (loc_of_expr $1) $2, OP1 (M_POST_INC, $1) }
|
||
|
| postfix_expression dec_op
|
||
|
{ sup_locator (loc_of_expr $1) $2, OP1 (M_POST_DEC, $1) }
|
||
|
;
|
||
|
|
||
|
/* Les argument_expression_list sont des listes a l'envers */
|
||
|
|
||
|
argument_expression_list:
|
||
|
assignment_expression { [$1] }
|
||
|
| argument_expression_list COMMA_CHR assignment_expression {
|
||
|
$3 :: $1 }
|
||
|
;
|
||
|
|
||
|
unary_expression:
|
||
|
postfix_expression { $1 }
|
||
|
| inc_op unary_expression
|
||
|
{ sup_locator $1 (loc_of_expr $2), OP1 (M_PRE_INC, $2) }
|
||
|
| dec_op unary_expression
|
||
|
{ sup_locator $1 (loc_of_expr $2), OP1 (M_PRE_DEC, $2) }
|
||
|
| unary_operator cast_expression
|
||
|
{
|
||
|
let loc, c = $1 in
|
||
|
let loc' = sup_locator loc (loc_of_expr $2) in
|
||
|
match c with
|
||
|
ADD_CHR -> $2
|
||
|
| SUB_CHR -> loc', OP1 (M_MINUS, $2)
|
||
|
| BANG_CHR -> loc', EIF ($2, (loc', CST 0), (loc', CST 1))
|
||
|
| TILDE_CHR -> loc', OP1 (M_NOT, $2)
|
||
|
| _ -> (Error.error (Some loc) "unknown unary operator";
|
||
|
loc, CST 0) }
|
||
|
;
|
||
|
|
||
|
unary_operator:
|
||
|
add_chr { $1 }
|
||
|
| sub_chr { $1 }
|
||
|
| bang_chr { $1 }
|
||
|
| tilde_chr { $1 }
|
||
|
;
|
||
|
|
||
|
add_chr : ADD_CHR { getloc (), ADD_CHR }
|
||
|
sub_chr : SUB_CHR { getloc (), SUB_CHR }
|
||
|
bang_chr : BANG_CHR { getloc (), BANG_CHR }
|
||
|
tilde_chr : TILDE_CHR { getloc (), TILDE_CHR }
|
||
|
|
||
|
close_paren : CLOSE_PAREN_CHR { getloc () }
|
||
|
|
||
|
cast_expression:
|
||
|
unary_expression { $1 }
|
||
|
;
|
||
|
|
||
|
multiplicative_expression:
|
||
|
cast_expression { $1 }
|
||
|
| multiplicative_expression STAR_CHR cast_expression
|
||
|
{ sup_locator (loc_of_expr $1) (loc_of_expr $3),
|
||
|
OP2 (S_MUL, $1, $3)
|
||
|
}
|
||
|
| multiplicative_expression DIV_CHR cast_expression
|
||
|
{ sup_locator (loc_of_expr $1) (loc_of_expr $3),
|
||
|
OP2 (S_DIV, $1, $3)
|
||
|
}
|
||
|
| multiplicative_expression MOD_CHR cast_expression
|
||
|
{ sup_locator (loc_of_expr $1) (loc_of_expr $3),
|
||
|
OP2 (S_MOD, $1, $3)
|
||
|
}
|
||
|
;
|
||
|
|
||
|
additive_expression:
|
||
|
multiplicative_expression
|
||
|
{ $1 }
|
||
|
| additive_expression ADD_CHR multiplicative_expression
|
||
|
{ sup_locator (loc_of_expr $1) (loc_of_expr $3),
|
||
|
OP2 (S_ADD, $1, $3)
|
||
|
}
|
||
|
| additive_expression SUB_CHR multiplicative_expression
|
||
|
{ sup_locator (loc_of_expr $1) (loc_of_expr $3),
|
||
|
OP2 (S_SUB, $1, $3)
|
||
|
}
|
||
|
;
|
||
|
|
||
|
shift_expression:
|
||
|
additive_expression { $1 }
|
||
|
;
|
||
|
|
||
|
relational_expression:
|
||
|
shift_expression { $1 }
|
||
|
| relational_expression OPEN_ANGLE_CHR shift_expression
|
||
|
{ sup_locator (loc_of_expr $1) (loc_of_expr $3),
|
||
|
CMP (C_LT, $1, $3)
|
||
|
}
|
||
|
| relational_expression CLOSE_ANGLE_CHR shift_expression
|
||
|
{ sup_locator (loc_of_expr $1) (loc_of_expr $3),
|
||
|
CMP (C_LT, $3, $1)
|
||
|
}
|
||
|
| relational_expression LE_OP shift_expression
|
||
|
{ sup_locator (loc_of_expr $1) (loc_of_expr $3),
|
||
|
CMP (C_LE, $1, $3)
|
||
|
}
|
||
|
| relational_expression GE_OP shift_expression
|
||
|
{ sup_locator (loc_of_expr $1) (loc_of_expr $3),
|
||
|
CMP (C_LE, $3, $1)
|
||
|
}
|
||
|
;
|
||
|
|
||
|
equality_expression:
|
||
|
relational_expression { $1 }
|
||
|
| equality_expression EQ_OP relational_expression
|
||
|
{ sup_locator (loc_of_expr $1) (loc_of_expr $3),
|
||
|
CMP (C_EQ, $1, $3)
|
||
|
}
|
||
|
| equality_expression NE_OP relational_expression
|
||
|
{
|
||
|
let loc = sup_locator (loc_of_expr $1) (loc_of_expr $3) in
|
||
|
loc, EIF ((loc, CMP (C_EQ, $1, $3)),
|
||
|
(loc, CST 0),
|
||
|
(loc, CST 1))
|
||
|
}
|
||
|
;
|
||
|
|
||
|
and_expression:
|
||
|
equality_expression { $1 }
|
||
|
;
|
||
|
|
||
|
exclusive_or_expression:
|
||
|
and_expression { $1 }
|
||
|
;
|
||
|
|
||
|
inclusive_or_expression:
|
||
|
exclusive_or_expression { $1 }
|
||
|
;
|
||
|
|
||
|
logical_and_expression:
|
||
|
inclusive_or_expression { $1 }
|
||
|
| logical_and_expression AND_OP inclusive_or_expression
|
||
|
{ let loc = sup_locator (loc_of_expr $1) (loc_of_expr $3) in
|
||
|
loc, EIF ($1, $3, (loc, CST 0))
|
||
|
}
|
||
|
;
|
||
|
|
||
|
logical_or_expression:
|
||
|
logical_and_expression { $1 }
|
||
|
| logical_or_expression OR_OP logical_and_expression
|
||
|
{ let loc = sup_locator (loc_of_expr $1) (loc_of_expr $3) in
|
||
|
loc, EIF ($1, (loc, CST 1), $3)
|
||
|
}
|
||
|
;
|
||
|
|
||
|
conditional_expression:
|
||
|
logical_or_expression { $1 }
|
||
|
| logical_or_expression QUES_CHR expression COLON_CHR conditional_expression
|
||
|
{
|
||
|
sup_locator (loc_of_expr $1) (loc_of_expr $5),
|
||
|
EIF ($1, $3, $5)
|
||
|
}
|
||
|
;
|
||
|
|
||
|
assignment_expression:
|
||
|
conditional_expression { $1 }
|
||
|
| unary_expression EQ_CHR assignment_expression
|
||
|
{
|
||
|
let locvar, left = $1 in
|
||
|
let loc = sup_locator locvar (loc_of_expr $3) in
|
||
|
match left with
|
||
|
VAR x -> loc, SET_VAR (x, $3)
|
||
|
| OP2 (S_INDEX, (_, VAR x), i) -> loc, SET_ARRAY (x, i, $3)
|
||
|
| _ ->
|
||
|
begin
|
||
|
Error.error (Some loc)
|
||
|
"Can only write assignments of the form x=e or x[e]=e'.\n";
|
||
|
$3
|
||
|
end
|
||
|
}
|
||
|
;
|
||
|
|
||
|
expression:
|
||
|
assignment_expression { $1 }
|
||
|
| expression COMMA_CHR assignment_expression
|
||
|
{
|
||
|
sup_locator (loc_of_expr $1) (loc_of_expr $3),
|
||
|
ESEQ [$1; $3]
|
||
|
}
|
||
|
;
|
||
|
|
||
|
declaration:
|
||
|
type_specifier optional_init_declarator_list SEMI_CHR
|
||
|
{ List.rev $2 }
|
||
|
;
|
||
|
|
||
|
optional_init_declarator_list :
|
||
|
{ [] }
|
||
|
| init_declarator_list { $1 }
|
||
|
;
|
||
|
|
||
|
/* Une init_declarator_list est une liste a l'envers de declarator. */
|
||
|
init_declarator_list
|
||
|
: init_declarator
|
||
|
{ [$1] }
|
||
|
| init_declarator_list COMMA_CHR init_declarator
|
||
|
{ $3 :: $1 }
|
||
|
;
|
||
|
|
||
|
init_declarator: declarator { $1 };
|
||
|
|
||
|
declarator:
|
||
|
identifier { let loc, x = $1 in CDECL (loc, x) }
|
||
|
;
|
||
|
|
||
|
type_specifier: INTEGER { () }
|
||
|
| CHAR STAR_CHR { () }
|
||
|
| type_specifier STAR_CHR { () };
|
||
|
|
||
|
close_bracket : CLOSE_BRACKET_CHR { getloc () };
|
||
|
|
||
|
statement: compound_statement
|
||
|
{ $1 }
|
||
|
| expression_statement
|
||
|
{ loc_of_expr $1, CEXPR $1 }
|
||
|
| selection_statement
|
||
|
{ $1 }
|
||
|
| iteration_statement
|
||
|
{ $1 }
|
||
|
| jump_statement
|
||
|
{ $1 }
|
||
|
;
|
||
|
|
||
|
open_block : open_brace { $1 };
|
||
|
close_block : close_brace { $1 };
|
||
|
|
||
|
compound_statement:
|
||
|
open_block close_block
|
||
|
{ sup_locator $1 $2, CBLOCK ([], []) }
|
||
|
| open_block statement_list close_block
|
||
|
{ sup_locator $1 $3, CBLOCK ([], List.rev $2) }
|
||
|
| open_block declaration_list close_block
|
||
|
{ sup_locator $1 $3, CBLOCK ($2, []) }
|
||
|
| open_block declaration_list statement_list close_block
|
||
|
{ sup_locator $1 $4, CBLOCK ($2, List.rev $3) }
|
||
|
;
|
||
|
|
||
|
/* Une declaration_list est une liste non inversee de declaration */
|
||
|
declaration_list
|
||
|
: declaration
|
||
|
{ $1 }
|
||
|
| declaration_list declaration
|
||
|
{ $1 @ $2 }
|
||
|
;
|
||
|
|
||
|
/* Une statement_list est une liste inversee de statement */
|
||
|
statement_list
|
||
|
: statement
|
||
|
{ [$1] }
|
||
|
| statement_list statement
|
||
|
{ $2 :: $1 }
|
||
|
;
|
||
|
|
||
|
expression_statement:
|
||
|
semi_chr
|
||
|
{ $1, ESEQ [] }
|
||
|
| expression SEMI_CHR
|
||
|
{ $1 }
|
||
|
;
|
||
|
|
||
|
semi_chr : SEMI_CHR { getloc () }
|
||
|
|
||
|
ifkw : IF { getloc () };
|
||
|
|
||
|
selection_statement
|
||
|
: ifkw OPEN_PAREN_CHR expression CLOSE_PAREN_CHR statement
|
||
|
{
|
||
|
sup_locator $1 (fst $5), CIF ($3, $5,
|
||
|
(getloc (), CBLOCK ([], [])))
|
||
|
}
|
||
|
| ifkw OPEN_PAREN_CHR expression CLOSE_PAREN_CHR statement ELSE statement
|
||
|
{
|
||
|
sup_locator $1 (fst $7), CIF ($3, $5, $7)
|
||
|
}
|
||
|
;
|
||
|
|
||
|
whilekw : WHILE { getloc () };
|
||
|
forkw : FOR { getloc () };
|
||
|
|
||
|
iteration_statement: whilekw OPEN_PAREN_CHR expression close_paren statement
|
||
|
{
|
||
|
let loc = sup_locator $1 (fst $5) in
|
||
|
loc, CWHILE ($3, $5)
|
||
|
}
|
||
|
| forkw OPEN_PAREN_CHR expression_statement expression_statement close_paren statement
|
||
|
/* for (e0; e; ) c == e0; while (e) c; */
|
||
|
{
|
||
|
let loc = sup_locator $1 (fst $6) in
|
||
|
loc, CBLOCK ([], [(loc_of_expr $3, CEXPR $3);
|
||
|
loc, CWHILE ($4, $6)])
|
||
|
}
|
||
|
| forkw OPEN_PAREN_CHR expression_statement expression_statement expression close_paren statement
|
||
|
/* for (e0; e; e1) c == e0; while (e) { c; e1 } */
|
||
|
{
|
||
|
let loc = sup_locator $1 (fst $7) in
|
||
|
loc, CBLOCK ([], [(loc_of_expr $3, CEXPR $3);
|
||
|
loc, CWHILE ($4,
|
||
|
(sup_locator (loc_of_expr $5) (loc_of_expr $7),
|
||
|
CBLOCK ([], [$7; (loc_of_expr $5,
|
||
|
CEXPR $5)])))])
|
||
|
}
|
||
|
;
|
||
|
|
||
|
return : RETURN { getloc () };
|
||
|
|
||
|
jump_statement:
|
||
|
return SEMI_CHR
|
||
|
{ $1, CRETURN None }
|
||
|
| return expression SEMI_CHR
|
||
|
{ sup_locator $1 (loc_of_expr $2), CRETURN (Some $2) }
|
||
|
;
|
||
|
|
||
|
translation_unit:
|
||
|
external_declaration
|
||
|
{ $1 }
|
||
|
| translation_unit external_declaration
|
||
|
{ $1 @ $2 }
|
||
|
| EOF
|
||
|
{ [] }
|
||
|
;
|
||
|
|
||
|
external_declaration
|
||
|
: function_definition
|
||
|
{ [$1] }
|
||
|
| declaration
|
||
|
{ $1 }
|
||
|
;
|
||
|
|
||
|
parameter_declaration: type_specifier declarator { $2 };
|
||
|
|
||
|
/*!!!should check no repeated param name! */
|
||
|
/* Une parameter_list est une liste inversee de parameter_list. */
|
||
|
parameter_list: parameter_declaration
|
||
|
{ [$1] }
|
||
|
| parameter_list COMMA_CHR parameter_declaration
|
||
|
{ $3 :: $1 }
|
||
|
;
|
||
|
|
||
|
parameter_type_list
|
||
|
: parameter_list { List.rev $1}
|
||
|
| parameter_list COMMA_CHR ELLIPSIS { List.rev $1 }
|
||
|
;
|
||
|
|
||
|
parameter_declarator :
|
||
|
OPEN_PAREN_CHR CLOSE_PAREN_CHR { [] }
|
||
|
| OPEN_PAREN_CHR parameter_type_list CLOSE_PAREN_CHR { $2 }
|
||
|
;
|
||
|
|
||
|
function_declarator : type_specifier identifier parameter_declarator
|
||
|
{ $2, $3 }
|
||
|
;
|
||
|
|
||
|
function_definition
|
||
|
: function_declarator compound_statement
|
||
|
{
|
||
|
let (loc, var), decls = $1 in
|
||
|
CFUN (loc, var, decls, $2)
|
||
|
}
|
||
|
;
|
||
|
|
||
|
|
||
|
%%
|