Parser.mly 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672
  1. /*
  2. * Copyright (C) 2011-2018 Intel Corporation. All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions
  6. * are met:
  7. *
  8. * * Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * * Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in
  12. * the documentation and/or other materials provided with the
  13. * distribution.
  14. * * Neither the name of Intel Corporation nor the names of its
  15. * contributors may be used to endorse or promote products derived
  16. * from this software without specific prior written permission.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  19. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  20. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  21. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  22. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  23. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  24. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  25. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  26. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  27. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  28. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29. *
  30. */
  31. %{
  32. open Util (* for failwithf *)
  33. (* Here we defined some helper routines to check attributes.
  34. *
  35. * An alternative approach is to code these rules in Lexer/Parser but
  36. * it has several drawbacks:
  37. *
  38. * 1. Bad extensibility;
  39. * 2. It grows the table size and down-graded the parsing time;
  40. * 3. It makes error reporting rigid this way.
  41. *)
  42. let get_string_from_attr (v: Ast.attr_value) (err_func: int -> string) =
  43. match v with
  44. Ast.AString s -> s
  45. | Ast.ANumber n -> err_func n
  46. (* Check whether 'size' is specified. *)
  47. let has_size (sattr: Ast.ptr_size) =
  48. sattr.Ast.ps_size <> None
  49. (* Check whether 'count' is specified. *)
  50. let has_count (sattr: Ast.ptr_size) =
  51. sattr.Ast.ps_count <> None
  52. (* Pointers can have the following attributes:
  53. *
  54. * 'size' - specifies the size of the pointer.
  55. * e.g. size = 4, size = val ('val' is a parameter);
  56. *
  57. * 'count' - indicates how many of items is managed by the pointer
  58. * e.g. count = 100, count = n ('n' is a parameter);
  59. *
  60. * 'string' - indicate the pointer is managing a C string;
  61. * 'wstring' - indicate the pointer is managing a wide char string.
  62. *
  63. * 'isptr' - to specify that the foreign type is a pointer.
  64. * 'isary' - to specify that the foreign type is an array.
  65. * 'readonly' - to specify that the foreign type has a 'const' qualifier.
  66. *
  67. * 'user_check' - inhibit Edger8r from generating code to check the pointer.
  68. *
  69. * 'in' - the pointer is used as input
  70. * 'out' - the pointer is used as output
  71. *
  72. * Note that 'size' can be used together with 'count'.
  73. * 'string' and 'wstring' indicates 'isptr',
  74. * and they cannot be used with only an 'out' attribute.
  75. *)
  76. let get_ptr_attr (attr_list: (string * Ast.attr_value) list) =
  77. let get_new_dir (cds: string) (cda: Ast.ptr_direction) (old: Ast.ptr_direction) =
  78. if old = Ast.PtrNoDirection then cda
  79. else if old = Ast.PtrInOut then failwithf "duplicated attribute: `%s'" cds
  80. else if old = cda then failwithf "duplicated attribute: `%s'" cds
  81. else Ast.PtrInOut
  82. in
  83. (* only one 'size' attribute allowed. *)
  84. let get_new_size (new_value: Ast.attr_value) (old_ptr_size: Ast.ptr_size) =
  85. if has_size old_ptr_size then
  86. failwithf "duplicated attribute: `size'"
  87. else new_value
  88. in
  89. (* only one 'count' attribute allowed. *)
  90. let get_new_count (new_value: Ast.attr_value) (old_ptr_size: Ast.ptr_size) =
  91. if has_count old_ptr_size then
  92. failwithf "duplicated attribute: `count'"
  93. else new_value
  94. in
  95. let update_attr (key: string) (value: Ast.attr_value) (res: Ast.ptr_attr) =
  96. match key with
  97. "size" ->
  98. { res with Ast.pa_size = { res.Ast.pa_size with Ast.ps_size = Some(get_new_size value res.Ast.pa_size)}}
  99. | "count" ->
  100. { res with Ast.pa_size = { res.Ast.pa_size with Ast.ps_count = Some(get_new_count value res.Ast.pa_size)}}
  101. | "sizefunc" ->
  102. failwithf "The attribute 'sizefunc' is deprecated. Please use 'size' attribute instead."
  103. | "string" -> { res with Ast.pa_isstr = true; }
  104. | "wstring" -> { res with Ast.pa_iswstr = true; }
  105. | "isptr" -> { res with Ast.pa_isptr = true }
  106. | "isary" -> { res with Ast.pa_isary = true }
  107. | "readonly" -> { res with Ast.pa_rdonly = true }
  108. | "user_check" -> { res with Ast.pa_chkptr = false }
  109. | "in" ->
  110. let newdir = get_new_dir "in" Ast.PtrIn res.Ast.pa_direction
  111. in { res with Ast.pa_direction = newdir }
  112. | "out" ->
  113. let newdir = get_new_dir "out" Ast.PtrOut res.Ast.pa_direction
  114. in { res with Ast.pa_direction = newdir }
  115. | _ -> failwithf "unknown attribute: %s" key
  116. in
  117. let rec do_get_ptr_attr alist res_attr =
  118. match alist with
  119. [] -> res_attr
  120. | (k,v) :: xs -> do_get_ptr_attr xs (update_attr k v res_attr)
  121. in
  122. let has_str_attr (pattr: Ast.ptr_attr) =
  123. if pattr.Ast.pa_isstr && pattr.Ast.pa_iswstr
  124. then failwith "`string' and `wstring' are mutual exclusive"
  125. else (pattr.Ast.pa_isstr || pattr.Ast.pa_iswstr)
  126. in
  127. let check_invalid_ptr_size (pattr: Ast.ptr_attr) =
  128. let ps = pattr.Ast.pa_size in
  129. if ps <> Ast.empty_ptr_size && has_str_attr pattr
  130. then failwith "size attributes are mutual exclusive with (w)string attribute"
  131. else
  132. if (ps <> Ast.empty_ptr_size || has_str_attr pattr) &&
  133. pattr.Ast.pa_direction = Ast.PtrNoDirection
  134. then failwith "size/string attributes must be used with pointer direction"
  135. else pattr
  136. in
  137. let check_ptr_dir (pattr: Ast.ptr_attr) =
  138. if pattr.Ast.pa_direction <> Ast.PtrNoDirection && pattr.Ast.pa_chkptr = false
  139. then failwith "pointer direction and `user_check' are mutual exclusive"
  140. else
  141. if pattr.Ast.pa_direction = Ast.PtrNoDirection && pattr.Ast.pa_chkptr
  142. then failwith "pointer/array should have direction attribute or `user_check'"
  143. else
  144. if pattr.Ast.pa_direction = Ast.PtrOut && has_str_attr pattr
  145. then failwith "string/wstring should be used with an `in' attribute"
  146. else pattr
  147. in
  148. let check_invalid_ary_attr (pattr: Ast.ptr_attr) =
  149. if pattr.Ast.pa_size <> Ast.empty_ptr_size
  150. then failwith "Pointer size attributes cannot be used with foreign array"
  151. else
  152. if not pattr.Ast.pa_isptr
  153. then
  154. (* 'pa_chkptr' is default to true unless user specifies 'user_check' *)
  155. if pattr.Ast.pa_chkptr && pattr.Ast.pa_direction = Ast.PtrNoDirection
  156. then failwith "array must have direction attribute or `user_check'"
  157. else pattr
  158. else
  159. if has_str_attr pattr
  160. then failwith "`isary' cannot be used with `string/wstring' together"
  161. else failwith "`isary' cannot be used with `isptr' together"
  162. in
  163. let pattr = do_get_ptr_attr attr_list { Ast.pa_direction = Ast.PtrNoDirection;
  164. Ast.pa_size = Ast.empty_ptr_size;
  165. Ast.pa_isptr = false;
  166. Ast.pa_isary = false;
  167. Ast.pa_isstr = false;
  168. Ast.pa_iswstr = false;
  169. Ast.pa_rdonly = false;
  170. Ast.pa_chkptr = true;
  171. }
  172. in
  173. if pattr.Ast.pa_isary
  174. then check_invalid_ary_attr pattr
  175. else check_invalid_ptr_size pattr |> check_ptr_dir
  176. (* Untrusted functions can have these attributes:
  177. *
  178. * a. 3 mutual exclusive calling convention specifier:
  179. * 'stdcall', 'fastcall', 'cdecl'.
  180. *
  181. * b. 'dllimport' - to import a public symbol.
  182. *)
  183. let get_func_attr (attr_list: (string * Ast.attr_value) list) =
  184. let get_new_callconv (key: string) (cur: Ast.call_conv) (old: Ast.call_conv) =
  185. if old <> Ast.CC_NONE then
  186. failwithf "unexpected `%s', conflict with `%s'." key (Ast.get_call_conv_str old)
  187. else cur
  188. in
  189. let update_attr (key: string) (value: Ast.attr_value) (res: Ast.func_attr) =
  190. match key with
  191. | "stdcall" ->
  192. let callconv = get_new_callconv key Ast.CC_STDCALL res.Ast.fa_convention
  193. in { res with Ast.fa_convention = callconv}
  194. | "fastcall" ->
  195. let callconv = get_new_callconv key Ast.CC_FASTCALL res.Ast.fa_convention
  196. in { res with Ast.fa_convention = callconv}
  197. | "cdecl" ->
  198. let callconv = get_new_callconv key Ast.CC_CDECL res.Ast.fa_convention
  199. in { res with Ast.fa_convention = callconv}
  200. | "dllimport" ->
  201. if res.Ast.fa_dllimport then failwith "duplicated attribute: `dllimport'"
  202. else { res with Ast.fa_dllimport = true }
  203. | _ -> failwithf "invalid function attribute: %s" key
  204. in
  205. let rec do_get_func_attr alist res_attr =
  206. match alist with
  207. [] -> res_attr
  208. | (k,v) :: xs -> do_get_func_attr xs (update_attr k v res_attr)
  209. in do_get_func_attr attr_list { Ast.fa_dllimport = false;
  210. Ast.fa_convention= Ast.CC_NONE;
  211. }
  212. (* Some syntax checking against pointer attributes.
  213. * range: (Lexing.position * Lexing.position)
  214. *)
  215. let check_ptr_attr (fd: Ast.func_decl) range =
  216. let fname = fd.Ast.fname in
  217. let check_const (pattr: Ast.ptr_attr) (identifier: string) =
  218. let raise_err_direction (direction:string) =
  219. failwithf "`%s': `%s' is readonly - cannot be used with `%s'"
  220. fname identifier direction
  221. in
  222. if pattr.Ast.pa_rdonly
  223. then
  224. match pattr.Ast.pa_direction with
  225. Ast.PtrOut | Ast.PtrInOut -> raise_err_direction "out"
  226. | _ -> ()
  227. else ()
  228. in
  229. let check_void_ptr_size (pattr: Ast.ptr_attr) (identifier: string) =
  230. if pattr.Ast.pa_chkptr && (not (has_size pattr.Ast.pa_size))
  231. then failwithf "`%s': void pointer `%s' - buffer size unknown" fname identifier
  232. else ()
  233. in
  234. let check_string_ptr_size (atype: Ast.atype) (pattr: Ast.ptr_attr) (identifier: string) =
  235. if (pattr.Ast.pa_isstr)
  236. then
  237. match atype with
  238. Ast.Ptr(Ast.Char(_)) -> ()
  239. | _ -> failwithf "`%s': invalid 'string' attribute - `%s' is not char pointer." fname identifier
  240. else
  241. if (atype <> Ast.Ptr(Ast.WChar) && pattr.Ast.pa_iswstr)
  242. then failwithf "`%s': invalid 'wstring' attribute - `%s' is not wchar_t pointer." fname identifier
  243. else ()
  244. in
  245. let check_array_dims (atype: Ast.atype) (pattr: Ast.ptr_attr) (declr: Ast.declarator) =
  246. if Ast.is_array declr then
  247. if has_size pattr.Ast.pa_size then
  248. failwithf "`%s': invalid 'size' attribute - `%s' is explicitly declared array." fname declr.Ast.identifier
  249. else if has_count pattr.Ast.pa_size then
  250. failwithf "`%s': invalid 'count' attribute - `%s' is explicitly declared array." fname declr.Ast.identifier
  251. else if pattr.Ast.pa_isary then
  252. failwithf "`%s': invalid 'isary' attribute - `%s' is explicitly declared array." fname declr.Ast.identifier
  253. else ()
  254. in
  255. let check_pointer_array (atype: Ast.atype) (pattr: Ast.ptr_attr) (declr: Ast.declarator) =
  256. let is_ary = (Ast.is_array declr || pattr.Ast.pa_isary) in
  257. let is_ptr =
  258. match atype with
  259. Ast.Ptr _ -> true
  260. | _ -> pattr.Ast.pa_isptr
  261. in
  262. if is_ary && is_ptr then
  263. failwithf "`%s': Pointer array not allowed - `%s' is a pointer array." fname declr.Ast.identifier
  264. else ()
  265. in
  266. let checker (pd: Ast.pdecl) =
  267. let pt, declr = pd in
  268. let identifier = declr.Ast.identifier in
  269. match pt with
  270. Ast.PTVal _ -> ()
  271. | Ast.PTPtr(atype, pattr) ->
  272. if atype = Ast.Ptr(Ast.Void) then (* 'void' pointer, check there is a size or 'user_check' *)
  273. check_void_ptr_size pattr identifier
  274. else
  275. check_pointer_array atype pattr declr;
  276. check_const pattr identifier;
  277. check_string_ptr_size atype pattr identifier;
  278. check_array_dims atype pattr declr
  279. in
  280. List.iter checker fd.Ast.plist
  281. %}
  282. %token EOF
  283. %token TDot TComma TSemicolon TPtr TEqual
  284. %token TLParen TRParen
  285. %token TLBrace TRBrace
  286. %token TLBrack TRBrack
  287. %token Tpublic
  288. %token Tinclude
  289. %token Tconst
  290. %token <string>Tidentifier
  291. %token <int>Tnumber
  292. %token <string>Tstring
  293. %token Tchar Tshort Tunsigned Tint Tfloat Tdouble
  294. Tint8 Tint16 Tint32 Tint64
  295. Tuint8 Tuint16 Tuint32 Tuint64
  296. Tsizet Twchar Tvoid Tlong Tstruct Tunion Tenum
  297. %token Tenclave Tfrom Timport Ttrusted Tuntrusted Tallow Tpropagate_errno
  298. %start start_parsing
  299. %type <Ast.enclave> start_parsing
  300. /* Grammar follows */
  301. %%
  302. /* Type definitions
  303. * ------------------------------------------------------------------------
  304. */
  305. char_type: Tchar { Ast.Char Ast.Signed }
  306. | Tunsigned Tchar { Ast.Char Ast.Unsigned }
  307. ;
  308. /* Explicit shortness. */
  309. ex_shortness: Tshort { Ast.IShort }
  310. | Tlong { Ast.ILong }
  311. ;
  312. longlong: Tlong Tlong { Ast.LLong Ast.Signed }
  313. | Tunsigned Tlong Tlong { Ast.LLong Ast.Unsigned }
  314. shortness: /* empty */ { Ast.INone }
  315. | ex_shortness { $1 }
  316. ;
  317. int_type: shortness Tint {
  318. Ast.Int { Ast.ia_signedness = Ast.Signed; Ast.ia_shortness = $1 }
  319. }
  320. | Tunsigned shortness Tint {
  321. Ast.Int { Ast.ia_signedness = Ast.Unsigned; Ast.ia_shortness = $2 }
  322. }
  323. | Tunsigned shortness {
  324. Ast.Int { Ast.ia_signedness = Ast.Unsigned; Ast.ia_shortness = $2 }
  325. }
  326. | longlong { $1 }
  327. | ex_shortness {
  328. Ast.Int { Ast.ia_signedness = Ast.Signed; Ast.ia_shortness = $1 }
  329. }
  330. ;
  331. type_spec:
  332. char_type { $1 }
  333. | int_type { $1 }
  334. | Tfloat { Ast.Float }
  335. | Tdouble { Ast.Double }
  336. | Tlong Tdouble { Ast.LDouble }
  337. | Tint8 { Ast.Int8 }
  338. | Tint16 { Ast.Int16 }
  339. | Tint32 { Ast.Int32 }
  340. | Tint64 { Ast.Int64 }
  341. | Tuint8 { Ast.UInt8 }
  342. | Tuint16 { Ast.UInt16 }
  343. | Tuint32 { Ast.UInt32 }
  344. | Tuint64 { Ast.UInt64 }
  345. | Tsizet { Ast.SizeT }
  346. | Twchar { Ast.WChar }
  347. | Tvoid { Ast.Void }
  348. | struct_specifier { $1 }
  349. | union_specifier { $1 }
  350. | enum_specifier { $1 }
  351. | Tidentifier { Ast.Foreign($1) } /* User defined types in C header */
  352. ;
  353. pointer: TPtr { fun ii -> Ast.Ptr(ii) }
  354. | pointer TPtr { fun ii -> Ast.Ptr($1 ii) }
  355. ;
  356. empty_dimension: TLBrack TRBrack { failwith "Flexible array is not supported." }
  357. fixed_dimension: TLBrack Tnumber TRBrack { if $2 <> 0 then [$2]
  358. else failwith "Zero-length array is not supported." }
  359. fixed_size_array: fixed_dimension { $1 }
  360. | fixed_size_array fixed_dimension { $1 @ $2 }
  361. ;
  362. array_size: fixed_size_array { $1 }
  363. | empty_dimension { $1 }
  364. | empty_dimension fixed_size_array { $1 @ $2 }
  365. ;
  366. all_type: type_spec { $1 }
  367. | type_spec pointer { $2 $1 }
  368. ;
  369. declarator: Tidentifier { { Ast.identifier = $1; Ast.array_dims = []; } }
  370. | Tidentifier array_size { { Ast.identifier = $1; Ast.array_dims = $2; } }
  371. ;
  372. /* Available types as parameter.
  373. *
  374. * Instead of returning an value of 'Ast.parameter_type', we return
  375. * a lambda which wraps the actual type since so far there is no way
  376. * to tell whether the identifier is followed by array dimensions.
  377. */
  378. param_type: attr_block all_type {
  379. let attr = get_ptr_attr $1 in
  380. (*check the type is build in type or used defined type.*)
  381. let rec is_foreign s =
  382. match s with
  383. Ast.Ptr(a) -> is_foreign a
  384. | Ast.Foreign _ -> true
  385. | _ -> false
  386. in
  387. let is_bare_foreign s =
  388. match s with
  389. | Ast.Foreign _ -> true
  390. | _ -> false
  391. in
  392. (*'isptr', 'isary', only allowed for bare user defined type.*)
  393. (*'readonly' only allowed for user defined type.*)
  394. if attr.Ast.pa_isptr && not (is_bare_foreign $2) then
  395. failwithf "'isptr', attributes are only for user defined type, not for `%s'." (Ast.get_tystr $2)
  396. else if attr.Ast.pa_isary && not (is_bare_foreign $2) then
  397. failwithf "'isary', attributes are only for user defined type, not for `%s'." (Ast.get_tystr $2)
  398. else if attr.Ast.pa_rdonly && not (is_foreign $2) then
  399. failwithf "'readonly', attributes are only for user defined type, not for `%s'." (Ast.get_tystr $2)
  400. else if attr.Ast.pa_rdonly && not (attr.Ast.pa_isptr) then
  401. failwithf "'readonly' attribute is only used with 'isptr' attribute." else
  402. match $2 with
  403. Ast.Ptr _ -> fun x -> Ast.PTPtr($2, get_ptr_attr $1)
  404. | _ ->
  405. if $1 <> [] then
  406. let attr = get_ptr_attr $1 in
  407. match $2 with
  408. Ast.Foreign s ->
  409. if attr.Ast.pa_isptr || attr.Ast.pa_isary then fun x -> Ast.PTPtr($2, attr)
  410. else
  411. (* thinking about 'user_defined_type var[4]' *)
  412. fun is_ary ->
  413. if is_ary then Ast.PTPtr($2, attr)
  414. else failwithf "`%s' is considered plain type but decorated with pointer attributes" s
  415. | _ ->
  416. fun is_ary ->
  417. if is_ary then Ast.PTPtr($2, attr)
  418. else failwithf "unexpected pointer attributes for `%s'" (Ast.get_tystr $2)
  419. else
  420. fun is_ary ->
  421. if is_ary then Ast.PTPtr($2, get_ptr_attr [])
  422. else Ast.PTVal $2
  423. }
  424. | all_type {
  425. match $1 with
  426. Ast.Ptr _ -> fun x -> Ast.PTPtr($1, get_ptr_attr [])
  427. | _ ->
  428. fun is_ary ->
  429. if is_ary then Ast.PTPtr($1, get_ptr_attr [])
  430. else Ast.PTVal $1
  431. }
  432. | attr_block Tconst type_spec pointer {
  433. let attr = get_ptr_attr $1
  434. in fun x -> Ast.PTPtr($4 $3, { attr with Ast.pa_rdonly = true })
  435. }
  436. | Tconst type_spec pointer {
  437. let attr = get_ptr_attr []
  438. in fun x -> Ast.PTPtr($3 $2, { attr with Ast.pa_rdonly = true })
  439. }
  440. ;
  441. attr_block: TLBrack TRBrack { failwith "no attribute specified." }
  442. | TLBrack key_val_pairs TRBrack { $2 }
  443. ;
  444. key_val_pairs: key_val_pair { [$1] }
  445. | key_val_pairs TComma key_val_pair { $3 :: $1 }
  446. ;
  447. key_val_pair: Tidentifier TEqual Tidentifier { ($1, Ast.AString($3)) }
  448. | Tidentifier TEqual Tnumber { ($1, Ast.ANumber($3)) }
  449. | Tidentifier { ($1, Ast.AString("")) }
  450. ;
  451. struct_specifier: Tstruct Tidentifier { Ast.Struct($2) }
  452. union_specifier: Tunion Tidentifier { Ast.Union($2) }
  453. enum_specifier: Tenum Tidentifier { Ast.Enum($2) }
  454. struct_definition: struct_specifier TLBrace member_list TRBrace {
  455. let s = { Ast.sname = (match $1 with Ast.Struct s -> s | _ -> "");
  456. Ast.mlist = List.rev $3; }
  457. in Ast.StructDef(s)
  458. }
  459. union_definition: union_specifier TLBrace member_list TRBrace {
  460. let s = { Ast.sname = (match $1 with Ast.Union s -> s | _ -> "");
  461. Ast.mlist = List.rev $3; }
  462. in Ast.UnionDef(s)
  463. }
  464. /* enum can be anonymous. */
  465. enum_definition: Tenum TLBrace enum_body TRBrace {
  466. let e = { Ast.enname = ""; Ast.enbody = $3; }
  467. in Ast.EnumDef(e)
  468. }
  469. | enum_specifier TLBrace enum_body TRBrace {
  470. let e = { Ast.enname = (match $1 with Ast.Enum s -> s | _ -> "");
  471. Ast.enbody = $3; }
  472. in Ast.EnumDef(e)
  473. }
  474. ;
  475. enum_body: /* empty */ { [] }
  476. | enum_eles { List.rev $1 }
  477. ;
  478. enum_eles: enum_ele { [$1] }
  479. | enum_eles TComma enum_ele { $3 :: $1 }
  480. ;
  481. enum_ele: Tidentifier { ($1, Ast.EnumValNone) }
  482. | Tidentifier TEqual Tidentifier { ($1, Ast.EnumVal (Ast.AString $3)) }
  483. | Tidentifier TEqual Tnumber { ($1, Ast.EnumVal (Ast.ANumber $3)) }
  484. ;
  485. composite_defs: struct_definition { $1 }
  486. | union_definition { $1 }
  487. | enum_definition { $1 }
  488. ;
  489. member_list: member_def TSemicolon { [$1] }
  490. | member_list member_def TSemicolon { $2 :: $1 }
  491. ;
  492. member_def: all_type declarator { ($1, $2) }
  493. /* Importing declarations.
  494. * ------------------------------------------------------------------------
  495. */
  496. func_list: Tidentifier { [$1] }
  497. | func_list TComma Tidentifier { $3 :: $1 }
  498. ;
  499. module_path: Tstring { $1 }
  500. import_declaration: Tfrom module_path Timport func_list {
  501. { Ast.mname = $2; Ast.flist = List.rev $4; }
  502. }
  503. | Tfrom module_path Timport TPtr {
  504. { Ast.mname = $2; Ast.flist = ["*"]; }
  505. }
  506. ;
  507. include_declaration: Tinclude Tstring { $2 }
  508. include_declarations: include_declaration { [$1] }
  509. | include_declarations include_declaration { $2 :: $1 }
  510. ;
  511. /* Enclave function declarations.
  512. * ------------------------------------------------------------------------
  513. */
  514. enclave_functions: Ttrusted TLBrace trusted_block TRBrace TSemicolon {
  515. List.rev $3
  516. }
  517. | Tuntrusted TLBrace untrusted_block TRBrace TSemicolon {
  518. List.rev $3
  519. }
  520. ;
  521. trusted_block: trusted_functions { $1 }
  522. | include_declarations trusted_functions {
  523. trusted_headers := !trusted_headers @ List.rev $1; $2
  524. }
  525. ;
  526. untrusted_block: untrusted_functions { $1 }
  527. | include_declarations untrusted_functions {
  528. untrusted_headers := !untrusted_headers @ List.rev $1; $2
  529. }
  530. ;
  531. /* is_priv? Default to true. */
  532. access_modifier: /* nothing */ { true }
  533. | Tpublic { false }
  534. ;
  535. trusted_functions: /* nothing */ { [] }
  536. | trusted_functions access_modifier func_def TSemicolon {
  537. check_ptr_attr $3 (symbol_start_pos(), symbol_end_pos());
  538. Ast.Trusted { Ast.tf_fdecl = $3; Ast.tf_is_priv = $2 } :: $1
  539. }
  540. ;
  541. untrusted_functions: /* nothing */ { [] }
  542. | untrusted_functions untrusted_func_def TSemicolon { $2 :: $1 }
  543. ;
  544. func_def: all_type Tidentifier parameter_list {
  545. { Ast.fname = $2; Ast.rtype = $1; Ast.plist = List.rev $3 ; }
  546. }
  547. | all_type array_size Tidentifier parameter_list {
  548. failwithf "%s: returning an array is not supported - use pointer instead." $3
  549. }
  550. ;
  551. parameter_list: TLParen TRParen { [] }
  552. | TLParen Tvoid TRParen { [] } /* Make C programers comfortable */
  553. | TLParen parameter_defs TRParen { $2 }
  554. ;
  555. parameter_defs: parameter_def { [$1] }
  556. | parameter_defs TComma parameter_def { $3 :: $1 }
  557. ;
  558. parameter_def: param_type declarator {
  559. let pt = $1 (Ast.is_array $2) in
  560. let is_void =
  561. match pt with
  562. Ast.PTVal v -> v = Ast.Void
  563. | _ -> false
  564. in
  565. if is_void then
  566. failwithf "parameter `%s' has `void' type." $2.Ast.identifier
  567. else
  568. (pt, $2)
  569. }
  570. /* propagate_errno? Default to false. */
  571. propagate_errno: /* nothing */ { false }
  572. | Tpropagate_errno { true }
  573. ;
  574. untrusted_func_def: attr_block func_def allow_list propagate_errno {
  575. check_ptr_attr $2 (symbol_start_pos(), symbol_end_pos());
  576. let fattr = get_func_attr $1 in
  577. Ast.Untrusted { Ast.uf_fdecl = $2; Ast.uf_fattr = fattr; Ast.uf_allow_list = $3; Ast.uf_propagate_errno = $4 }
  578. }
  579. | func_def allow_list propagate_errno {
  580. check_ptr_attr $1 (symbol_start_pos(), symbol_end_pos());
  581. let fattr = get_func_attr [] in
  582. Ast.Untrusted { Ast.uf_fdecl = $1; Ast.uf_fattr = fattr; Ast.uf_allow_list = $2; Ast.uf_propagate_errno = $3 }
  583. }
  584. ;
  585. allow_list: /* nothing */ { [] }
  586. | Tallow TLParen TRParen { [] }
  587. | Tallow TLParen func_list TRParen { $3 }
  588. ;
  589. /* Enclave definition
  590. * ------------------------------------------------------------------------
  591. */
  592. expressions: /* nothing */ { [] }
  593. | expressions include_declaration { Ast.Include($2) :: $1 }
  594. | expressions import_declaration TSemicolon { Ast.Importing($2) :: $1 }
  595. | expressions composite_defs TSemicolon { Ast.Composite($2) :: $1 }
  596. | expressions enclave_functions { Ast.Interface($2) :: $1 }
  597. ;
  598. enclave_def: Tenclave TLBrace expressions TRBrace {
  599. { Ast.ename = "";
  600. Ast.eexpr = List.rev $3 }
  601. }
  602. ;
  603. /* The entry point of parser.
  604. * ------------------------------------------------------------------------
  605. */
  606. start_parsing: enclave_def TSemicolon EOF { $1 }
  607. %%