summaryrefslogtreecommitdiff
path: root/cparser/Unblock.ml
diff options
context:
space:
mode:
authorGravatar xleroy <xleroy@fca1b0fc-160b-0410-b1d3-a4f43f01ea2e>2010-03-03 10:22:27 +0000
committerGravatar xleroy <xleroy@fca1b0fc-160b-0410-b1d3-a4f43f01ea2e>2010-03-03 10:22:27 +0000
commit891377ce1962cdb31357d6580d6546ec22df2b4f (patch)
tree4ff7c38749cc7a4c1af411c5aa3eb7225c4ae6a1 /cparser/Unblock.ml
parent018edf2d81bf94197892cf1df221f7eeac1f96f6 (diff)
Switching to the new C parser/elaborator/simplifier
git-svn-id: https://yquem.inria.fr/compcert/svn/compcert/trunk@1269 fca1b0fc-160b-0410-b1d3-a4f43f01ea2e
Diffstat (limited to 'cparser/Unblock.ml')
-rw-r--r--cparser/Unblock.ml133
1 files changed, 133 insertions, 0 deletions
diff --git a/cparser/Unblock.ml b/cparser/Unblock.ml
new file mode 100644
index 0000000..fa304b7
--- /dev/null
+++ b/cparser/Unblock.ml
@@ -0,0 +1,133 @@
+(* *********************************************************************)
+(* *)
+(* The Compcert verified compiler *)
+(* *)
+(* Xavier Leroy, INRIA Paris-Rocquencourt *)
+(* *)
+(* Copyright Institut National de Recherche en Informatique et en *)
+(* Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the GNU General Public License as published by *)
+(* the Free Software Foundation, either version 2 of the License, or *)
+(* (at your option) any later version. This file is also distributed *)
+(* under the terms of the INRIA Non-Commercial License Agreement. *)
+(* *)
+(* *********************************************************************)
+
+(* Simplification of blocks and initializers within functions *)
+
+(* Assumes: nothing
+ Produces: unblocked code *)
+
+open C
+open Cutil
+open Errors
+
+(* Convert an initializer to a list of assignments.
+ Prepend those assignments to the given statement. *)
+
+let sdoseq loc e s =
+ sseq loc {sdesc = Sdo e; sloc = loc} s
+
+let rec local_initializer loc env path init k =
+ match init with
+ | Init_single e ->
+ sdoseq loc
+ { edesc = EBinop(Oassign, path, e, path.etyp); etyp = path.etyp }
+ k
+ | Init_array il ->
+ let ty_elt =
+ match unroll env path.etyp with
+ | TArray(ty_elt, _, _) -> ty_elt
+ | _ -> fatal_error "%aWrong type for array initializer"
+ formatloc loc in
+ let rec array_init pos = function
+ | [] -> k
+ | i :: il ->
+ local_initializer loc env
+ { edesc = EBinop(Oindex, path, intconst pos IInt, TPtr(ty_elt, []));
+ etyp = ty_elt }
+ i
+ (array_init (Int64.succ pos) il) in
+ array_init 0L il
+ | Init_struct(id, fil) ->
+ let field_init (fld, i) k =
+ local_initializer loc env
+ { edesc = EUnop(Odot fld.fld_name, path); etyp = fld.fld_typ }
+ i k in
+ List.fold_right field_init fil k
+ | Init_union(id, fld, i) ->
+ local_initializer loc env
+ { edesc = EUnop(Odot fld.fld_name, path); etyp = fld.fld_typ }
+ i k
+
+(* Record new variables to be locally defined *)
+
+let local_variables = ref ([]: decl list)
+
+(* Note: "const int x = y - 1;" is legal, but we turn it into
+ "const int x; x = y - 1;", which is not. Therefore, remove
+ top-level 'const' attribute. Also remove it on element type of
+ array type. *)
+
+let remove_const env ty = remove_attributes_type env [AConst] ty
+
+(* Process a variable declaration.
+ The variable is entered in [local_variables].
+ The initializer, if any, is converted into assignments and
+ prepended to [k]. *)
+
+let process_decl loc env (sto, id, ty, optinit) k =
+ let ty' = remove_const env ty in
+ local_variables := (sto, id, ty', None) :: !local_variables;
+ match optinit with
+ | None -> k
+ | Some init ->
+ local_initializer loc env { edesc = EVar id; etyp = ty' } init k
+
+(* Simplification of blocks within a statement *)
+
+let rec unblock_stmt env s =
+ match s.sdesc with
+ | Sskip -> s
+ | Sdo e -> s
+ | Sseq(s1, s2) ->
+ {s with sdesc = Sseq(unblock_stmt env s1, unblock_stmt env s2)}
+ | Sif(e, s1, s2) ->
+ {s with sdesc = Sif(e, unblock_stmt env s1, unblock_stmt env s2)}
+ | Swhile(e, s1) ->
+ {s with sdesc = Swhile(e, unblock_stmt env s1)}
+ | Sdowhile(s1, e) ->
+ {s with sdesc = Sdowhile(unblock_stmt env s1, e)}
+ | Sfor(s1, e, s2, s3) ->
+ {s with sdesc = Sfor(unblock_stmt env s1, e, unblock_stmt env s2, unblock_stmt env s3)}
+ | Sbreak -> s
+ | Scontinue -> s
+ | Sswitch(e, s1) ->
+ {s with sdesc = Sswitch(e, unblock_stmt env s1)}
+ | Slabeled(lbl, s1) ->
+ {s with sdesc = Slabeled(lbl, unblock_stmt env s1)}
+ | Sgoto lbl -> s
+ | Sreturn opte -> s
+ | Sblock sl -> unblock_block env sl
+ | Sdecl d -> assert false
+
+and unblock_block env = function
+ | [] -> sskip
+ | {sdesc = Sdecl d; sloc = loc} :: sl ->
+ process_decl loc env d (unblock_block env sl)
+ | s :: sl ->
+ sseq s.sloc (unblock_stmt env s) (unblock_block env sl)
+
+(* Simplification of blocks within a function *)
+
+let unblock_fundef env f =
+ local_variables := [];
+ let body = unblock_stmt env f.fd_body in
+ let decls = !local_variables in
+ local_variables := [];
+ { f with fd_locals = f.fd_locals @ decls; fd_body = body }
+
+(* Entry point *)
+
+let program p =
+ Transform.program ~fundef:unblock_fundef p