mirror of
https://github.com/corda/corda.git
synced 2025-01-07 13:38:47 +00:00
9441de4c38
This release is used in conjunction with the linux-sgx-driver Intial release: https://github.com/01org/linux-sgx-driver commit-id: 0e865ce5e6b297a787bcdc12d98bada8174be6d7 Intel-id: 33399 Signed-off-by: Angie Chinchilla <angie.v.chinchilla@intel.com>
607 lines
21 KiB
OCaml
607 lines
21 KiB
OCaml
/*
|
|
* Copyright (C) 2011-2016 Intel Corporation. All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
*
|
|
* * Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* * Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in
|
|
* the documentation and/or other materials provided with the
|
|
* distribution.
|
|
* * Neither the name of Intel Corporation nor the names of its
|
|
* contributors may be used to endorse or promote products derived
|
|
* from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
*/
|
|
|
|
%{
|
|
open Util (* for failwithf *)
|
|
|
|
(* Here we defined some helper routines to check attributes.
|
|
*
|
|
* An alternative approach is to code these rules in Lexer/Parser but
|
|
* it has several drawbacks:
|
|
*
|
|
* 1. Bad extensibility;
|
|
* 2. It grows the table size and down-graded the parsing time;
|
|
* 3. It makes error reporting rigid this way.
|
|
*)
|
|
|
|
let get_string_from_attr (v: Ast.attr_value) (err_func: int -> string) =
|
|
match v with
|
|
Ast.AString s -> s
|
|
| Ast.ANumber n -> err_func n
|
|
|
|
(* Check whether 'size' or 'sizefunc' is specified. *)
|
|
let has_size (sattr: Ast.ptr_size) =
|
|
sattr.Ast.ps_size <> None || sattr.Ast.ps_sizefunc <> None
|
|
|
|
(* Pointers can have the following attributes:
|
|
*
|
|
* 'size' - specifies the size of the pointer.
|
|
* e.g. size = 4, size = val ('val' is a parameter);
|
|
*
|
|
* 'count' - indicates how many of items is managed by the pointer
|
|
* e.g. count = 100, count = n ('n' is a parameter);
|
|
*
|
|
* 'sizefunc' - use a function to compute the size of the pointer.
|
|
* e.g. sizefunc = get_ptr_size
|
|
*
|
|
* 'string' - indicate the pointer is managing a C string;
|
|
* 'wstring' - indicate the pointer is managing a wide char string.
|
|
*
|
|
* 'isptr' - to specify that the foreign type is a pointer.
|
|
* 'isary' - to specify that the foreign type is an array.
|
|
* 'readonly' - to specify that the foreign type has a 'const' qualifier.
|
|
*
|
|
* 'user_check' - inhibit Edger8r from generating code to check the pointer.
|
|
*
|
|
* 'in' - the pointer is used as input
|
|
* 'out' - the pointer is used as output
|
|
*
|
|
* Note that 'size' and 'sizefunc' are mutual exclusive (but they can
|
|
* be used together with 'count'. 'string' and 'wstring' indicates 'isptr',
|
|
* and they cannot use with only an 'out' attribute.
|
|
*)
|
|
let get_ptr_attr (attr_list: (string * Ast.attr_value) list) =
|
|
let get_new_dir (cds: string) (cda: Ast.ptr_direction) (old: Ast.ptr_direction) =
|
|
if old = Ast.PtrNoDirection then cda
|
|
else if old = Ast.PtrInOut then failwithf "duplicated attribute: `%s'" cds
|
|
else if old = cda then failwithf "duplicated attribute: `%s'" cds
|
|
else Ast.PtrInOut
|
|
in
|
|
let update_attr (key: string) (value: Ast.attr_value) (res: Ast.ptr_attr) =
|
|
match key with
|
|
"size" ->
|
|
{ res with Ast.pa_size = { res.Ast.pa_size with Ast.ps_size = Some value }}
|
|
| "count" ->
|
|
{ res with Ast.pa_size = { res.Ast.pa_size with Ast.ps_count = Some value }}
|
|
| "sizefunc" ->
|
|
let efn n = failwithf "invalid function name (%d) for `sizefunc'" n in
|
|
let funcname = get_string_from_attr value efn
|
|
in { res with Ast.pa_size =
|
|
{ res.Ast.pa_size with Ast.ps_sizefunc = Some funcname }}
|
|
| "string" -> { res with Ast.pa_isptr = true; Ast.pa_isstr = true; }
|
|
| "wstring" -> { res with Ast.pa_isptr = true; Ast.pa_iswstr = true; }
|
|
| "isptr" -> { res with Ast.pa_isptr = true }
|
|
| "isary" -> { res with Ast.pa_isary = true }
|
|
|
|
| "readonly" -> { res with Ast.pa_rdonly = true }
|
|
| "user_check" -> { res with Ast.pa_chkptr = false }
|
|
|
|
| "in" ->
|
|
let newdir = get_new_dir "in" Ast.PtrIn res.Ast.pa_direction
|
|
in { res with Ast.pa_direction = newdir }
|
|
| "out" ->
|
|
let newdir = get_new_dir "out" Ast.PtrOut res.Ast.pa_direction
|
|
in { res with Ast.pa_direction = newdir }
|
|
| _ -> failwithf "unknown attribute: %s" key
|
|
in
|
|
let rec do_get_ptr_attr alist res_attr =
|
|
match alist with
|
|
[] -> res_attr
|
|
| (k,v) :: xs -> do_get_ptr_attr xs (update_attr k v res_attr)
|
|
in
|
|
let has_str_attr (pattr: Ast.ptr_attr) =
|
|
if pattr.Ast.pa_isstr && pattr.Ast.pa_iswstr
|
|
then failwith "`string' and `wstring' are mutual exclusive"
|
|
else (pattr.Ast.pa_isstr || pattr.Ast.pa_iswstr)
|
|
in
|
|
let check_invalid_ptr_size (pattr: Ast.ptr_attr) =
|
|
let ps = pattr.Ast.pa_size in
|
|
if ps.Ast.ps_size <> None && ps.Ast.ps_sizefunc <> None
|
|
then failwith "`size' and `sizefunc' cannot be used at the same time"
|
|
else
|
|
if ps <> Ast.empty_ptr_size && has_str_attr pattr
|
|
then failwith "size attributes are mutual exclusive with (w)string attribute"
|
|
else
|
|
if (ps <> Ast.empty_ptr_size || has_str_attr pattr) &&
|
|
pattr.Ast.pa_direction = Ast.PtrNoDirection
|
|
then failwith "size/string attributes must be used with pointer direction"
|
|
else pattr
|
|
in
|
|
let check_ptr_dir (pattr: Ast.ptr_attr) =
|
|
if pattr.Ast.pa_direction <> Ast.PtrNoDirection && pattr.Ast.pa_chkptr = false
|
|
then failwith "pointer direction and `user_check' are mutual exclusive"
|
|
else
|
|
if pattr.Ast.pa_direction = Ast.PtrNoDirection && pattr.Ast.pa_chkptr
|
|
then failwith "pointer/array should have direction attribute or `user_check'"
|
|
else
|
|
if pattr.Ast.pa_direction = Ast.PtrOut && (has_str_attr pattr || pattr.Ast.pa_size.Ast.ps_sizefunc <> None)
|
|
then failwith "string/wstring/sizefunc should be used with an `in' attribute"
|
|
else pattr
|
|
in
|
|
let check_invalid_ary_attr (pattr: Ast.ptr_attr) =
|
|
if pattr.Ast.pa_size <> Ast.empty_ptr_size
|
|
then failwith "Pointer size attributes cannot be used with foreign array"
|
|
else
|
|
if not pattr.Ast.pa_isptr
|
|
then
|
|
(* 'pa_chkptr' is default to true unless user specifies 'user_check' *)
|
|
if pattr.Ast.pa_chkptr && pattr.Ast.pa_direction = Ast.PtrNoDirection
|
|
then failwith "array must have direction attribute or `user_check'"
|
|
else pattr
|
|
else
|
|
if has_str_attr pattr
|
|
then failwith "`isary' cannot be used with `string/wstring' together"
|
|
else failwith "`isary' cannot be used with `isptr' together"
|
|
in
|
|
let pattr = do_get_ptr_attr attr_list { Ast.pa_direction = Ast.PtrNoDirection;
|
|
Ast.pa_size = Ast.empty_ptr_size;
|
|
Ast.pa_isptr = false;
|
|
Ast.pa_isary = false;
|
|
Ast.pa_isstr = false;
|
|
Ast.pa_iswstr = false;
|
|
Ast.pa_rdonly = false;
|
|
Ast.pa_chkptr = true;
|
|
}
|
|
in
|
|
if pattr.Ast.pa_isary
|
|
then check_invalid_ary_attr pattr
|
|
else check_invalid_ptr_size pattr |> check_ptr_dir
|
|
|
|
(* Untrusted functions can have these attributes:
|
|
*
|
|
* a. 3 mutual exclusive calling convention specifier:
|
|
* 'stdcall', 'fastcall', 'cdecl'.
|
|
*
|
|
* b. 'dllimport' - to import a public symbol.
|
|
*)
|
|
let get_func_attr (attr_list: (string * Ast.attr_value) list) =
|
|
let get_new_callconv (key: string) (cur: Ast.call_conv) (old: Ast.call_conv) =
|
|
if old <> Ast.CC_NONE then
|
|
failwithf "unexpected `%s', conflict with `%s'." key (Ast.get_call_conv_str old)
|
|
else cur
|
|
in
|
|
let update_attr (key: string) (value: Ast.attr_value) (res: Ast.func_attr) =
|
|
match key with
|
|
| "stdcall" ->
|
|
let callconv = get_new_callconv key Ast.CC_STDCALL res.Ast.fa_convention
|
|
in { res with Ast.fa_convention = callconv}
|
|
| "fastcall" ->
|
|
let callconv = get_new_callconv key Ast.CC_FASTCALL res.Ast.fa_convention
|
|
in { res with Ast.fa_convention = callconv}
|
|
| "cdecl" ->
|
|
let callconv = get_new_callconv key Ast.CC_CDECL res.Ast.fa_convention
|
|
in { res with Ast.fa_convention = callconv}
|
|
| "dllimport" ->
|
|
if res.Ast.fa_dllimport then failwith "duplicated attribute: `dllimport'"
|
|
else { res with Ast.fa_dllimport = true }
|
|
| _ -> failwithf "invalid function attribute: %s" key
|
|
in
|
|
let rec do_get_func_attr alist res_attr =
|
|
match alist with
|
|
[] -> res_attr
|
|
| (k,v) :: xs -> do_get_func_attr xs (update_attr k v res_attr)
|
|
in do_get_func_attr attr_list { Ast.fa_dllimport = false;
|
|
Ast.fa_convention= Ast.CC_NONE;
|
|
}
|
|
|
|
(* Some syntax checking against pointer attributes.
|
|
* range: (Lexing.position * Lexing.position)
|
|
*)
|
|
let check_ptr_attr (fd: Ast.func_decl) range =
|
|
let fname = fd.Ast.fname in
|
|
let check_const (pattr: Ast.ptr_attr) (identifier: string) =
|
|
let raise_err_direction (direction:string) =
|
|
failwithf "`%s': `%s' is readonly - cannot be used with `%s'"
|
|
fname identifier direction
|
|
in
|
|
if pattr.Ast.pa_rdonly
|
|
then
|
|
match pattr.Ast.pa_direction with
|
|
Ast.PtrOut | Ast.PtrInOut -> raise_err_direction "out"
|
|
| _ -> ()
|
|
else ()
|
|
in
|
|
let check_void_ptr_size (pattr: Ast.ptr_attr) (identifier: string) =
|
|
if pattr.Ast.pa_chkptr && (not (has_size pattr.Ast.pa_size))
|
|
then failwithf "`%s': void pointer `%s' - buffer size unknown" fname identifier
|
|
else ()
|
|
in
|
|
let checker (pd: Ast.pdecl) =
|
|
let pt, declr = pd in
|
|
let identifier = declr.Ast.identifier in
|
|
match pt with
|
|
Ast.PTVal _ -> ()
|
|
| Ast.PTPtr(atype, pattr) ->
|
|
if atype <> Ast.Ptr(Ast.Void) then check_const pattr identifier
|
|
else (* 'void' pointer, check there is a size or 'user_check' *)
|
|
check_void_ptr_size pattr identifier
|
|
in
|
|
List.iter checker fd.Ast.plist
|
|
%}
|
|
|
|
%token EOF
|
|
%token TDot TComma TSemicolon TPtr TEqual
|
|
%token TLParen TRParen
|
|
%token TLBrace TRBrace
|
|
%token TLBrack TRBrack
|
|
%token Tpublic
|
|
%token Tinclude
|
|
%token Tconst
|
|
%token <string>Tidentifier
|
|
%token <int>Tnumber
|
|
%token <string>Tstring
|
|
%token Tchar Tshort Tunsigned Tint Tfloat Tdouble
|
|
Tint8 Tint16 Tint32 Tint64
|
|
Tuint8 Tuint16 Tuint32 Tuint64
|
|
Tsizet Twchar Tvoid Tlong Tstruct Tunion Tenum
|
|
%token Tenclave Tfrom Timport Ttrusted Tuntrusted Tallow Tpropagate_errno
|
|
|
|
%start start_parsing
|
|
%type <Ast.enclave> start_parsing
|
|
|
|
/* Grammar follows */
|
|
%%
|
|
|
|
/* Type definitions
|
|
* ------------------------------------------------------------------------
|
|
*/
|
|
char_type: Tchar { Ast.Char Ast.Signed }
|
|
| Tunsigned Tchar { Ast.Char Ast.Unsigned }
|
|
;
|
|
|
|
/* Explicit shortness. */
|
|
ex_shortness: Tshort { Ast.IShort }
|
|
| Tlong { Ast.ILong }
|
|
;
|
|
|
|
longlong: Tlong Tlong { Ast.LLong Ast.Signed }
|
|
| Tunsigned Tlong Tlong { Ast.LLong Ast.Unsigned }
|
|
|
|
shortness: /* empty */ { Ast.INone }
|
|
| ex_shortness { $1 }
|
|
;
|
|
|
|
int_type: shortness Tint {
|
|
Ast.Int { Ast.ia_signedness = Ast.Signed; Ast.ia_shortness = $1 }
|
|
}
|
|
| Tunsigned shortness Tint {
|
|
Ast.Int { Ast.ia_signedness = Ast.Unsigned; Ast.ia_shortness = $2 }
|
|
}
|
|
| Tunsigned shortness {
|
|
Ast.Int { Ast.ia_signedness = Ast.Unsigned; Ast.ia_shortness = $2 }
|
|
}
|
|
| longlong { $1 }
|
|
| ex_shortness {
|
|
Ast.Int { Ast.ia_signedness = Ast.Signed; Ast.ia_shortness = $1 }
|
|
}
|
|
;
|
|
|
|
type_spec:
|
|
char_type { $1 }
|
|
| int_type { $1 }
|
|
|
|
| Tfloat { Ast.Float }
|
|
| Tdouble { Ast.Double }
|
|
| Tlong Tdouble { Ast.LDouble }
|
|
|
|
| Tint8 { Ast.Int8 }
|
|
| Tint16 { Ast.Int16 }
|
|
| Tint32 { Ast.Int32 }
|
|
| Tint64 { Ast.Int64 }
|
|
| Tuint8 { Ast.UInt8 }
|
|
| Tuint16 { Ast.UInt16 }
|
|
| Tuint32 { Ast.UInt32 }
|
|
| Tuint64 { Ast.UInt64 }
|
|
| Tsizet { Ast.SizeT }
|
|
| Twchar { Ast.WChar }
|
|
| Tvoid { Ast.Void }
|
|
|
|
| struct_specifier { $1 }
|
|
| union_specifier { $1 }
|
|
| enum_specifier { $1 }
|
|
| Tidentifier { Ast.Foreign($1) } /* User defined types in C header */
|
|
;
|
|
|
|
pointer: TPtr { fun ii -> Ast.Ptr(ii) }
|
|
| pointer TPtr { fun ii -> Ast.Ptr($1 ii) }
|
|
;
|
|
|
|
empty_dimension: TLBrack TRBrack { failwith "Flexible array is not supported." }
|
|
fixed_dimension: TLBrack Tnumber TRBrack { if $2 <> 0 then [$2]
|
|
else failwith "Zero-length array is not supported." }
|
|
|
|
fixed_size_array: fixed_dimension { $1 }
|
|
| fixed_size_array fixed_dimension { $1 @ $2 }
|
|
;
|
|
|
|
array_size: fixed_size_array { $1 }
|
|
| empty_dimension { $1 }
|
|
| empty_dimension fixed_size_array { $1 @ $2 }
|
|
;
|
|
|
|
all_type: type_spec { $1 }
|
|
| type_spec pointer { $2 $1 }
|
|
;
|
|
|
|
declarator: Tidentifier { { Ast.identifier = $1; Ast.array_dims = []; } }
|
|
| Tidentifier array_size { { Ast.identifier = $1; Ast.array_dims = $2; } }
|
|
;
|
|
|
|
/* Available types as parameter.
|
|
*
|
|
* Instead of returning an value of 'Ast.parameter_type', we return
|
|
* a lambda which wraps the actual type since so far there is no way
|
|
* to tell whether the identifier is followed by array dimensions.
|
|
*/
|
|
param_type: attr_block all_type {
|
|
match $2 with
|
|
Ast.Ptr _ -> fun x -> Ast.PTPtr($2, get_ptr_attr $1)
|
|
| _ ->
|
|
if $1 <> [] then
|
|
let attr = get_ptr_attr $1 in
|
|
match $2 with
|
|
Ast.Foreign s ->
|
|
if attr.Ast.pa_isptr || attr.Ast.pa_isary then fun x -> Ast.PTPtr($2, attr)
|
|
else
|
|
(* thinking about 'user_defined_type var[4]' *)
|
|
fun is_ary ->
|
|
if is_ary then Ast.PTPtr($2, attr)
|
|
else failwithf "`%s' is considerred plain type but decorated with pointer attributes" s
|
|
| _ ->
|
|
fun is_ary ->
|
|
if is_ary then Ast.PTPtr($2, attr)
|
|
else failwithf "unexpected pointer attributes for `%s'" (Ast.get_tystr $2)
|
|
else
|
|
fun is_ary ->
|
|
if is_ary then Ast.PTPtr($2, get_ptr_attr [])
|
|
else Ast.PTVal $2
|
|
}
|
|
| all_type {
|
|
match $1 with
|
|
Ast.Ptr _ -> fun x -> Ast.PTPtr($1, get_ptr_attr [])
|
|
| _ ->
|
|
fun is_ary ->
|
|
if is_ary then Ast.PTPtr($1, get_ptr_attr [])
|
|
else Ast.PTVal $1
|
|
}
|
|
| attr_block Tconst type_spec pointer {
|
|
let attr = get_ptr_attr $1
|
|
in fun x -> Ast.PTPtr($4 $3, { attr with Ast.pa_rdonly = true })
|
|
}
|
|
| Tconst type_spec pointer {
|
|
let attr = get_ptr_attr []
|
|
in fun x -> Ast.PTPtr($3 $2, { attr with Ast.pa_rdonly = true })
|
|
}
|
|
;
|
|
|
|
|
|
attr_block: TLBrack TRBrack { failwith "no attribute specified." }
|
|
| TLBrack key_val_pairs TRBrack { $2 }
|
|
;
|
|
|
|
key_val_pairs: key_val_pair { [$1] }
|
|
| key_val_pairs TComma key_val_pair { $3 :: $1 }
|
|
;
|
|
|
|
key_val_pair: Tidentifier TEqual Tidentifier { ($1, Ast.AString($3)) }
|
|
| Tidentifier TEqual Tnumber { ($1, Ast.ANumber($3)) }
|
|
| Tidentifier { ($1, Ast.AString("")) }
|
|
;
|
|
|
|
struct_specifier: Tstruct Tidentifier { Ast.Struct($2) }
|
|
union_specifier: Tunion Tidentifier { Ast.Union($2) }
|
|
enum_specifier: Tenum Tidentifier { Ast.Enum($2) }
|
|
|
|
struct_definition: struct_specifier TLBrace member_list TRBrace {
|
|
let s = { Ast.sname = (match $1 with Ast.Struct s -> s | _ -> "");
|
|
Ast.mlist = List.rev $3; }
|
|
in Ast.StructDef(s)
|
|
}
|
|
|
|
union_definition: union_specifier TLBrace member_list TRBrace {
|
|
let s = { Ast.sname = (match $1 with Ast.Union s -> s | _ -> "");
|
|
Ast.mlist = List.rev $3; }
|
|
in Ast.UnionDef(s)
|
|
}
|
|
|
|
/* enum can be anonymous. */
|
|
enum_definition: Tenum TLBrace enum_body TRBrace {
|
|
let e = { Ast.enname = ""; Ast.enbody = $3; }
|
|
in Ast.EnumDef(e)
|
|
}
|
|
| enum_specifier TLBrace enum_body TRBrace {
|
|
let e = { Ast.enname = (match $1 with Ast.Enum s -> s | _ -> "");
|
|
Ast.enbody = $3; }
|
|
in Ast.EnumDef(e)
|
|
}
|
|
;
|
|
|
|
enum_body: /* empty */ { [] }
|
|
| enum_eles { List.rev $1 }
|
|
;
|
|
|
|
enum_eles: enum_ele { [$1] }
|
|
| enum_eles TComma enum_ele { $3 :: $1 }
|
|
;
|
|
|
|
enum_ele: Tidentifier { ($1, Ast.EnumValNone) }
|
|
| Tidentifier TEqual Tidentifier { ($1, Ast.EnumVal (Ast.AString $3)) }
|
|
| Tidentifier TEqual Tnumber { ($1, Ast.EnumVal (Ast.ANumber $3)) }
|
|
;
|
|
|
|
composite_defs: struct_definition { $1 }
|
|
| union_definition { $1 }
|
|
| enum_definition { $1 }
|
|
;
|
|
|
|
member_list: member_def TSemicolon { [$1] }
|
|
| member_list member_def TSemicolon { $2 :: $1 }
|
|
;
|
|
|
|
member_def: all_type declarator { ($1, $2) }
|
|
|
|
/* Importing declarations.
|
|
* ------------------------------------------------------------------------
|
|
*/
|
|
func_list: Tidentifier { [$1] }
|
|
| func_list TComma Tidentifier { $3 :: $1 }
|
|
;
|
|
|
|
module_path: Tstring { $1 }
|
|
|
|
import_declaration: Tfrom module_path Timport func_list {
|
|
{ Ast.mname = $2; Ast.flist = List.rev $4; }
|
|
}
|
|
| Tfrom module_path Timport TPtr {
|
|
{ Ast.mname = $2; Ast.flist = ["*"]; }
|
|
}
|
|
;
|
|
|
|
include_declaration: Tinclude Tstring { $2 }
|
|
|
|
include_declarations: include_declaration { [$1] }
|
|
| include_declarations include_declaration { $2 :: $1 }
|
|
;
|
|
|
|
/* Enclave function declarations.
|
|
* ------------------------------------------------------------------------
|
|
*/
|
|
enclave_functions: Ttrusted TLBrace trusted_block TRBrace TSemicolon {
|
|
List.rev $3
|
|
}
|
|
| Tuntrusted TLBrace untrusted_block TRBrace TSemicolon {
|
|
List.rev $3
|
|
}
|
|
;
|
|
|
|
trusted_block: trusted_functions { $1 }
|
|
| include_declarations trusted_functions {
|
|
trusted_headers := !trusted_headers @ List.rev $1; $2
|
|
}
|
|
;
|
|
|
|
untrusted_block: untrusted_functions { $1 }
|
|
| include_declarations untrusted_functions {
|
|
untrusted_headers := !untrusted_headers @ List.rev $1; $2
|
|
}
|
|
;
|
|
|
|
/* is_priv? Default to true. */
|
|
access_modifier: /* nothing */ { true }
|
|
| Tpublic { false }
|
|
;
|
|
|
|
trusted_functions: /* nothing */ { [] }
|
|
| trusted_functions access_modifier func_def TSemicolon {
|
|
check_ptr_attr $3 (symbol_start_pos(), symbol_end_pos());
|
|
Ast.Trusted { Ast.tf_fdecl = $3; Ast.tf_is_priv = $2 } :: $1
|
|
}
|
|
;
|
|
|
|
untrusted_functions: /* nothing */ { [] }
|
|
| untrusted_functions untrusted_func_def TSemicolon { $2 :: $1 }
|
|
;
|
|
|
|
func_def: all_type Tidentifier parameter_list {
|
|
{ Ast.fname = $2; Ast.rtype = $1; Ast.plist = List.rev $3 ; }
|
|
}
|
|
| all_type array_size Tidentifier parameter_list {
|
|
failwithf "%s: returning an array is not supported - use pointer instead." $3
|
|
}
|
|
;
|
|
|
|
parameter_list: TLParen TRParen { [] }
|
|
| TLParen Tvoid TRParen { [] } /* Make C programers comfortable */
|
|
| TLParen parameter_defs TRParen { $2 }
|
|
;
|
|
|
|
parameter_defs: parameter_def { [$1] }
|
|
| parameter_defs TComma parameter_def { $3 :: $1 }
|
|
;
|
|
|
|
parameter_def: param_type declarator {
|
|
let pt = $1 (Ast.is_array $2) in
|
|
let is_void =
|
|
match pt with
|
|
Ast.PTVal v -> v = Ast.Void
|
|
| _ -> false
|
|
in
|
|
if is_void then
|
|
failwithf "parameter `%s' has `void' type." $2.Ast.identifier
|
|
else
|
|
(pt, $2)
|
|
}
|
|
|
|
/* propagate_errno? Default to false. */
|
|
propagate_errno: /* nothing */ { false }
|
|
| Tpropagate_errno { true }
|
|
;
|
|
|
|
untrusted_func_def: attr_block func_def allow_list propagate_errno {
|
|
check_ptr_attr $2 (symbol_start_pos(), symbol_end_pos());
|
|
let fattr = get_func_attr $1 in
|
|
Ast.Untrusted { Ast.uf_fdecl = $2; Ast.uf_fattr = fattr; Ast.uf_allow_list = $3; Ast.uf_propagate_errno = $4 }
|
|
}
|
|
| func_def allow_list propagate_errno {
|
|
check_ptr_attr $1 (symbol_start_pos(), symbol_end_pos());
|
|
let fattr = get_func_attr [] in
|
|
Ast.Untrusted { Ast.uf_fdecl = $1; Ast.uf_fattr = fattr; Ast.uf_allow_list = $2; Ast.uf_propagate_errno = $3 }
|
|
}
|
|
;
|
|
|
|
allow_list: /* nothing */ { [] }
|
|
| Tallow TLParen TRParen { [] }
|
|
| Tallow TLParen func_list TRParen { $3 }
|
|
;
|
|
|
|
/* Enclave definition
|
|
* ------------------------------------------------------------------------
|
|
*/
|
|
expressions: /* nothing */ { [] }
|
|
| expressions include_declaration { Ast.Include($2) :: $1 }
|
|
| expressions import_declaration TSemicolon { Ast.Importing($2) :: $1 }
|
|
| expressions composite_defs TSemicolon { Ast.Composite($2) :: $1 }
|
|
| expressions enclave_functions { Ast.Interface($2) :: $1 }
|
|
;
|
|
|
|
enclave_def: Tenclave TLBrace expressions TRBrace {
|
|
{ Ast.ename = "";
|
|
Ast.eexpr = List.rev $3 }
|
|
}
|
|
;
|
|
|
|
/* The entry point of parser.
|
|
* ------------------------------------------------------------------------
|
|
*/
|
|
start_parsing: enclave_def TSemicolon EOF { $1 }
|
|
|
|
%%
|