Initial commit
This commit is contained in:
commit
c4a6b83fdc
52 changed files with 12560 additions and 0 deletions
228
Makefile
Normal file
228
Makefile
Normal file
|
@ -0,0 +1,228 @@
|
|||
# $Id$
|
||||
|
||||
DATE = \`eval date\`
|
||||
LIBDIR = \`eval pwd\`/../lib
|
||||
BIN = hec
|
||||
TARGET = opt
|
||||
|
||||
OCAMLFLAGS = -dtypes -g
|
||||
OCAMLOPTFLAGS = -dtypes -g
|
||||
CPP = cpp
|
||||
#gcc -E
|
||||
CPPFLAGS = -P
|
||||
SED=sed
|
||||
|
||||
# lablgtk
|
||||
LABLGTKPREFIX = /usr/lib/ocaml
|
||||
LABLGTKFLAGS = -I $(LABLGTKPREFIX)/lablgtk2 -I $(LABLGTKPREFIX)/stublibs
|
||||
LABLGTKLINKFLAGS = -dllpath $(LABLGTKPREFIX)/stublibs
|
||||
|
||||
OCAMLC = ocamlc
|
||||
OCAMLLEX = ocamllex
|
||||
OCAMLYACC = ocamlyacc
|
||||
OCAMLOPT = ocamlopt
|
||||
OCAMLDEP = ocamldep
|
||||
|
||||
UNIX = str.cma unix.cma
|
||||
UNIXX = str.cmxa unix.cmxa
|
||||
INCLUDES =
|
||||
|
||||
DIRECTORIES = global parsing analysis translation dataflow sigali sequential \
|
||||
simulation main
|
||||
|
||||
INCLUDES = $(DIRECTORIES:%=-I %)
|
||||
|
||||
GENSOURCES = parsing/lexer.ml parsing/parser.mli parsing/parser.ml
|
||||
|
||||
GLOBAL = global/names.cmo \
|
||||
global/ident.cmo \
|
||||
global/static.cmo \
|
||||
global/location.cmo \
|
||||
global/misc.cmo \
|
||||
global/linearity.cmo \
|
||||
global/graph.cmo \
|
||||
global/dep.cmo \
|
||||
global/parsetree.cmo \
|
||||
global/heptagon.cmo \
|
||||
global/global.cmo \
|
||||
global/modules.cmo \
|
||||
global/printer.cmo \
|
||||
global/initial.cmo \
|
||||
global/interference_graph.cmo \
|
||||
global/scoping.cmo
|
||||
PARSING = parsing/lexer.cmo \
|
||||
parsing/parser.cmo
|
||||
ANALYSIS = analysis/typing.cmo \
|
||||
analysis/causal.cmo \
|
||||
analysis/causality.cmo \
|
||||
analysis/interface.cmo \
|
||||
analysis/initialization.cmo \
|
||||
analysis/linear_typing.cmo \
|
||||
analysis/automata_mem.cmo
|
||||
TRANSLATION = translation/completion.cmo \
|
||||
translation/automata.cmo \
|
||||
translation/present.cmo \
|
||||
translation/last.cmo \
|
||||
translation/reset.cmo \
|
||||
translation/reset_new.cmo \
|
||||
translation/every.cmo
|
||||
# translation/inline.cmo
|
||||
DATAFLOW = dataflow/minils.cmo \
|
||||
dataflow/merge.cmo \
|
||||
dataflow/dfcausality.cmo \
|
||||
dataflow/normalize.cmo \
|
||||
dataflow/schedule.cmo \
|
||||
dataflow/clocking.cmo \
|
||||
dataflow/intermediate.cmo \
|
||||
dataflow/cse.cmo \
|
||||
dataflow/cmse.cmo \
|
||||
dataflow/tomato.cmo \
|
||||
dataflow/tommls.cmo \
|
||||
dataflow/deadcode.cmo \
|
||||
dataflow/mls2dot.cmo \
|
||||
dataflow/interference2dot.cmo \
|
||||
dataflow/interference.cmo \
|
||||
dataflow/memalloc.cmo \
|
||||
dataflow/splitting.cmo \
|
||||
dataflow/schedule_interf.cmo \
|
||||
dataflow/callgraph.cmo
|
||||
# dataflow/init.cmo
|
||||
SIGALI = sigali/boolean.cmo \
|
||||
sigali/sigali.cmo \
|
||||
sigali/dynamic_system.cmo
|
||||
SEQUENTIAL = sequential/obc.cmo \
|
||||
sequential/control.cmo \
|
||||
sequential/translate.cmo \
|
||||
sequential/c_old.cmo \
|
||||
sequential/caml.cmo \
|
||||
sequential/java.cmo \
|
||||
sequential/c.cmo \
|
||||
sequential/csubst.cmo \
|
||||
sequential/rename.cmo \
|
||||
sequential/cgen.cmo \
|
||||
sequential/vhdl.cmo \
|
||||
sequential/mls2vhdl.cmo
|
||||
# sequential/lustre.cmo
|
||||
MAIN = main/compiler.cmo \
|
||||
main/main.cmo
|
||||
|
||||
OBJ = $(GLOBAL) $(MODULES) $(PARSING) $(ANALYSIS) $(TRANSLATION) \
|
||||
$(DATAFLOW) $(SEQUENTIAL) $(MAIN) \
|
||||
$(SIMULATION)
|
||||
|
||||
OBJ_OPT = $(OBJ:.cmo=.cmx)
|
||||
|
||||
SRC = $(OBJ:.cmo=.ml)
|
||||
|
||||
INTERFACES = $(SRC:.ml=.mli)
|
||||
|
||||
SIM_BIN = hes
|
||||
|
||||
# Objs needed for compiling simulator
|
||||
SIM_OBJ = global/misc.cmo \
|
||||
global/heptagon.cmo \
|
||||
global/global.cmo \
|
||||
global/modules.cmo \
|
||||
simulation/simulator.cmo
|
||||
SIM_LIBS = lablgtk.cma unix.cma
|
||||
|
||||
SIM_OBJ_OPT = $(SIM_OBJ:.cmo=.cmx)
|
||||
|
||||
SIM_LIBS_OPT = $(SIM_LIBS:.cma=.cmxa)
|
||||
|
||||
world: all
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
opt: $(BIN).opt
|
||||
byte: $(BIN).byte
|
||||
|
||||
$(BIN).opt: $(OBJ_OPT)
|
||||
$(OCAMLOPT) $(UNIXX) $(OCAMLOPTFLAGS) $(INCLUDES) $(OBJ_OPT) -o $(BIN).opt
|
||||
|
||||
$(BIN).byte: $(OBJ)
|
||||
$(OCAMLC) -custom $(UNIX) $(OCAMLFLAGS) $(INCLUDES) $(OBJ) -o $(BIN).byte
|
||||
|
||||
sim: $(SIM_BIN).byte
|
||||
simopt:$(SIM_BIN).opt
|
||||
|
||||
$(SIM_BIN).opt: $(SIM_OBJ_OPT)
|
||||
$(OCAMLOPT) $(OCAMLOPTFLAGS) \
|
||||
$(LABLGTKFLAGS) \
|
||||
$(INCLUDES) $(SIM_LIBS_OPT) $(SIM_OBJ_OPT) -o $(SIM_BIN).opt
|
||||
$(SIM_BIN).byte: $(SIM_OBJ)
|
||||
$(OCAMLC) -custom $(UNIX) $(OCAMLFLAGS) \
|
||||
$(LABLGTKFLAGS) $(LABLGTKLINKFLAGS) \
|
||||
$(INCLUDES) $(SIM_LIBS) $(SIM_OBJ) -o $(SIM_BIN).byte
|
||||
|
||||
|
||||
debug: OCAMLFLAGS += -g
|
||||
debug: byte
|
||||
|
||||
profile: OCAMLOPTFLAGS += -p
|
||||
profile: opt
|
||||
|
||||
depend .depend: $(GENSOURCES)
|
||||
(for d in $(DIRECTORIES); \
|
||||
do $(OCAMLDEP) $(INCLUDES) $$d/*.mli $$d/*.ml; \
|
||||
done) > .depend
|
||||
|
||||
interfaces: $(INTERFACES)
|
||||
|
||||
# Extra dependences
|
||||
parsing/parser.mli parsing/parser.ml: parsing/parser.mly
|
||||
$(OCAMLYACC) -v parsing/parser.mly
|
||||
|
||||
parsing/lexer.cmi: parsing/parser.mli
|
||||
|
||||
parsing/lexer.ml: parsing/lexer.mll
|
||||
$(OCAMLLEX) parsing/lexer.mll
|
||||
|
||||
global/misc.cmo: OCAMLFLAGS := \
|
||||
-pp "$(SED) -e \"s|DATE|`date`|\" -e \"s|STDLIB|$(LIBDIR)|\""
|
||||
# -pp "$(CPP) $(CPPFLAGS) -DSTDLIB=\\\"$(LIBDIR)\\\" \
|
||||
# -DDATE=\\\"\"`date`\"\\\""
|
||||
|
||||
global/misc.cmx: OCAMLOPTFLAGS := \
|
||||
-pp "$(SED) -e \"s|DATE|`date`|\" -e \"s|STDLIB|$(LIBDIR)|\""
|
||||
# -pp "$(CPP) $(CPPFLAGS) -DSTDLIB=\\\"$(LIBDIR)\\\" \
|
||||
# -DDATE=\\\"\"`date`\"\\\""
|
||||
|
||||
simulation/simulator.cmo: OCAMLFLAGS += $(LABLGTKFLAGS)
|
||||
|
||||
simulation/simulator.cmx: OCAMLOPTFLAGS += $(LABLGTKFLAGS)
|
||||
|
||||
# Common rules
|
||||
.SUFFIXES : .mli .ml .cmi .cmo .cmx
|
||||
|
||||
%.cmo: %.ml
|
||||
$(OCAMLC) $(OCAMLFLAGS) -c $(INCLUDES) $<
|
||||
|
||||
%.cmi: %.mli
|
||||
$(OCAMLC) $(OCAMLFLAGS) -c $(INCLUDES) $<
|
||||
|
||||
%.cmx: %.ml
|
||||
$(OCAMLOPT) $(OCAMLOPTFLAGS) -c $(INCLUDES) $<
|
||||
|
||||
# %.mli: %.ml
|
||||
# $(OCAMLC) $(OCAMLFLAGS) -i -c $(INCLUDES) $< > $@
|
||||
|
||||
|
||||
|
||||
# Clean up
|
||||
clean:
|
||||
rm -f $(GENSOURCES) parsing/parser.output
|
||||
# to avoid the make warnings:
|
||||
rm -f parsing/parser.ml
|
||||
rm -f parsing/lexer.ml
|
||||
(for d in $(DIRECTORIES); \
|
||||
do rm -f $$d/*.annot $$d/*.cm[iox] $$d/*.o; \
|
||||
done)
|
||||
rm -f $(BIN).byte $(BIN).opt
|
||||
|
||||
ML = $(OBJ:.cmo=.ml)
|
||||
|
||||
wc:
|
||||
wc $(ML)
|
||||
|
||||
include .depend
|
4
_tags
Normal file
4
_tags
Normal file
|
@ -0,0 +1,4 @@
|
|||
<**/*.ml>: debug, dtypes
|
||||
<global/misc.ml>: camlp4o, use_preproc
|
||||
<preproc.ml>: camlp4of, use_camlp4
|
||||
<**/*.{byte,native}>: use_unix, use_str, debug
|
68
global/global.ml
Normal file
68
global/global.ml
Normal file
|
@ -0,0 +1,68 @@
|
|||
(**************************************************************************)
|
||||
(* *)
|
||||
(* Heptagon *)
|
||||
(* *)
|
||||
(* Author : Marc Pouzet *)
|
||||
(* Organization : Demons, LRI, University of Paris-Sud, Orsay *)
|
||||
(* *)
|
||||
(**************************************************************************)
|
||||
(* global data in the symbol tables *)
|
||||
(* $Id$ *)
|
||||
open Names
|
||||
open Ident
|
||||
open Linearity
|
||||
open Heptagon
|
||||
open Static
|
||||
|
||||
(** Warning: Whenever these types are modified,
|
||||
interface_format_version in misc.ml should be incremented. *)
|
||||
type arg_dec =
|
||||
{ a_type : ty;
|
||||
a_name : name option;
|
||||
a_linearity : linearity;
|
||||
a_pass_by_ref: bool; }
|
||||
|
||||
type sig_desc =
|
||||
{ inputs : arg_dec list;
|
||||
outputs : arg_dec list;
|
||||
contract : contract option;
|
||||
node : bool;
|
||||
safe : bool;
|
||||
targeting : (int*int) list;
|
||||
params: name list;
|
||||
params_constraints : size_constr list; }
|
||||
|
||||
and field_desc =
|
||||
{ arg: base_ty; (* if x:arg then x.m: res *)
|
||||
res: base_ty;
|
||||
}
|
||||
|
||||
and struct_desc =
|
||||
{ fields : (name * base_ty) list; }
|
||||
|
||||
and typ_desc =
|
||||
| Tabstract
|
||||
| Tenum of name list
|
||||
| Tstruct of (name * base_ty) list
|
||||
|
||||
type 'a info = { qualid : qualident; info : 'a }
|
||||
|
||||
type ivar =
|
||||
| IVar of ident
|
||||
| IField of ident * longname
|
||||
|
||||
(** [filter_vars l] returns a list of variables identifiers from
|
||||
a list of ivar.*)
|
||||
let rec filter_vars = function
|
||||
| [] -> []
|
||||
| (IVar id)::l -> id::(filter_vars l)
|
||||
| _::l -> filter_vars l
|
||||
|
||||
let names l =
|
||||
List.map (fun ad -> ad.a_name) l
|
||||
|
||||
let types l =
|
||||
List.map (fun ad -> ad.a_type) l
|
||||
|
||||
let linearities l =
|
||||
List.map (fun ad -> ad.a_linearity) l
|
71
global/ident.ml
Normal file
71
global/ident.ml
Normal file
|
@ -0,0 +1,71 @@
|
|||
(* naming and local environment *)
|
||||
|
||||
type ident = {
|
||||
num : int; (* a unique index *)
|
||||
source : string; (* the original name in the source *)
|
||||
is_generated : bool;
|
||||
}
|
||||
|
||||
let compare id1 id2 = compare id1.num id2.num
|
||||
let sourcename id = id.source
|
||||
let name id =
|
||||
if id.is_generated then
|
||||
id.source ^ "_" ^ (string_of_int id.num)
|
||||
else
|
||||
id.source
|
||||
|
||||
let set_sourcename id v =
|
||||
{ id with source = v }
|
||||
|
||||
let num = ref 0
|
||||
let fresh s =
|
||||
num := !num + 1;
|
||||
{ num = !num; source = s; is_generated = true }
|
||||
|
||||
let ident_of_var s =
|
||||
num := !num + 1;
|
||||
{ num = !num; source = s; is_generated = false }
|
||||
|
||||
let fprint_t ff id = Format.fprintf ff "%s" (name id)
|
||||
|
||||
module M = struct
|
||||
type t = ident
|
||||
let compare = compare
|
||||
let fprint = fprint_t
|
||||
end
|
||||
|
||||
module Env =
|
||||
struct
|
||||
include (Map.Make(M))
|
||||
|
||||
let append env0 env =
|
||||
fold (fun key v env -> add key v env) env0 env
|
||||
|
||||
(* Environments union *)
|
||||
let union env1 env2 =
|
||||
fold (fun name elt env -> add name elt env) env2 env1
|
||||
|
||||
(* Environments difference : env1 - env2 *)
|
||||
let diff env1 env2 =
|
||||
fold (fun name _ env -> remove name env) env2 env1
|
||||
|
||||
(* Environments partition *)
|
||||
let partition p env =
|
||||
fold
|
||||
(fun key elt (env1,env2) ->
|
||||
if p(key)
|
||||
then ((add key elt env1),env2)
|
||||
else (env1,(add key elt env2)))
|
||||
env
|
||||
(empty, empty)
|
||||
end
|
||||
|
||||
module IdentSet = struct
|
||||
include (Set.Make(M))
|
||||
|
||||
let fprint_t ff s =
|
||||
Format.fprintf ff "@[<hov>{@ ";
|
||||
iter (fun e -> Format.fprintf ff "%a@ " M.fprint e) s;
|
||||
Format.fprintf ff "}@]";
|
||||
end
|
||||
|
35
global/ident.mli
Normal file
35
global/ident.mli
Normal file
|
@ -0,0 +1,35 @@
|
|||
(** The (abstract) type of identifiers*)
|
||||
type ident
|
||||
|
||||
(** Get the source name from an identifier*)
|
||||
val sourcename : ident -> string
|
||||
(** Get the full name of an identifier (it is
|
||||
guaranteed to be unique)*)
|
||||
val name : ident -> string
|
||||
(** [set_sourcename id v] returns id with its
|
||||
source name changed to v. *)
|
||||
val set_sourcename : ident -> string -> ident
|
||||
|
||||
(** [fresh n] returns a fresh identifier with source name n *)
|
||||
val fresh : string -> ident
|
||||
(** [ident_of_var n] returns an identifier corresponding
|
||||
to a _source_ variable (do not use it for generated variables). *)
|
||||
val ident_of_var : string -> ident
|
||||
|
||||
(** Maps taking an identifier as a key. *)
|
||||
module Env :
|
||||
sig
|
||||
include (Map.S with type key = ident)
|
||||
|
||||
val append : 'a t -> 'a t -> 'a t
|
||||
val union : 'a t -> 'a t -> 'a t
|
||||
val diff : 'a t -> 'b t -> 'a t
|
||||
val partition : (key -> bool) -> 'a t -> 'a t * 'a t
|
||||
end
|
||||
|
||||
(** A set of identifiers. *)
|
||||
module IdentSet :
|
||||
sig
|
||||
include (Set.S with type elt = ident)
|
||||
val fprint_t : Format.formatter -> t -> unit
|
||||
end
|
31
global/initial.ml
Normal file
31
global/initial.ml
Normal file
|
@ -0,0 +1,31 @@
|
|||
(**************************************************************************)
|
||||
(* *)
|
||||
(* Heptagon *)
|
||||
(* *)
|
||||
(* Author : Marc Pouzet *)
|
||||
(* Organization : Demons, LRI, University of Paris-Sud, Orsay *)
|
||||
(* *)
|
||||
(**************************************************************************)
|
||||
(* initialization of the typing environment *)
|
||||
|
||||
(* $Id$ *)
|
||||
|
||||
open Misc
|
||||
open Names
|
||||
open Global
|
||||
open Modules
|
||||
|
||||
let tglobal = []
|
||||
let cglobal = []
|
||||
|
||||
let pbool = Modname({ qual = "Pervasives"; id = "bool" })
|
||||
let ptrue = Modname({ qual = "Pervasives"; id = "true" })
|
||||
let pfalse = Modname({ qual = "Pervasives"; id = "false" })
|
||||
let por = Modname({ qual = "Pervasives"; id = "or" })
|
||||
let pint = Modname({ qual = "Pervasives"; id = "int" })
|
||||
let pfloat = Modname({ qual = "Pervasives"; id = "float" })
|
||||
|
||||
(* build the initial environment *)
|
||||
let initialize () =
|
||||
List.iter (fun (f, ty) -> add_type f ty) tglobal;
|
||||
List.iter (fun (f, ty) -> add_constr f ty) cglobal
|
157
global/location.ml
Normal file
157
global/location.ml
Normal file
|
@ -0,0 +1,157 @@
|
|||
(* Printing a location in the source program *)
|
||||
(* taken from the source of the Caml Light 0.73 compiler *)
|
||||
|
||||
(* $Id$ *)
|
||||
|
||||
open Lexing
|
||||
open Parsing
|
||||
|
||||
(* two important global variables: [input_name] and [input_chan] *)
|
||||
type location =
|
||||
Loc of int (* Position of the first character *)
|
||||
* int (* Position of the next character following the last one *)
|
||||
|
||||
|
||||
|
||||
let input_name = ref "" (* Input file name. *)
|
||||
|
||||
let input_chan = ref stdin (* The channel opened on the input. *)
|
||||
|
||||
let initialize iname ic =
|
||||
input_name := iname;
|
||||
input_chan := ic
|
||||
|
||||
|
||||
let no_location = Loc(0,0)
|
||||
|
||||
|
||||
let error_prompt = ">"
|
||||
|
||||
let get_current_location () =
|
||||
Loc(symbol_start(), symbol_end())
|
||||
|
||||
|
||||
let output_lines oc char1 char2 charline1 line1 line2 =
|
||||
let n1 = char1 - charline1
|
||||
and n2 = char2 - charline1 in
|
||||
if line2 > line1 then
|
||||
Printf.fprintf oc
|
||||
", line %d-%d, characters %d-%d:\n" line1 line2 n1 n2
|
||||
else
|
||||
Printf.fprintf oc ", line %d, characters %d-%d:\n" line1 n1 n2;
|
||||
()
|
||||
|
||||
|
||||
let output_loc oc input seek line_flag (Loc(pos1, pos2)) =
|
||||
let pr_chars n c =
|
||||
for i = 1 to n do output_char oc c done in
|
||||
let skip_line () =
|
||||
try
|
||||
while input() != '\n' do () done
|
||||
with End_of_file -> () in
|
||||
let copy_line () =
|
||||
let c = ref ' ' in
|
||||
begin try
|
||||
while c := input(); !c != '\n' do output_char oc !c done
|
||||
with End_of_file ->
|
||||
output_string oc "<EOF>"
|
||||
end;
|
||||
output_char oc '\n' in
|
||||
let pr_line first len ch =
|
||||
let c = ref ' '
|
||||
and f = ref first
|
||||
and l = ref len in
|
||||
try
|
||||
while c := input (); !c != '\n' do
|
||||
if !f > 0 then begin
|
||||
f := !f - 1;
|
||||
output_char oc (if !c == '\t' then !c else ' ')
|
||||
end
|
||||
else if !l > 0 then begin
|
||||
l := !l - 1;
|
||||
output_char oc (if !c == '\t' then !c else ch)
|
||||
end
|
||||
else ()
|
||||
done
|
||||
with End_of_file ->
|
||||
if !f = 0 && !l > 0 then pr_chars 5 ch in
|
||||
let pos = ref 0
|
||||
and line1 = ref 1
|
||||
and line1_pos = ref 0
|
||||
and line2 = ref 1
|
||||
and line2_pos = ref 0 in
|
||||
seek 0;
|
||||
begin try
|
||||
while !pos < pos1 do
|
||||
incr pos;
|
||||
if input() == '\n' then begin incr line1; line1_pos := !pos; () end
|
||||
done
|
||||
with End_of_file -> ()
|
||||
end;
|
||||
line2 := !line1;
|
||||
line2_pos := !line1_pos;
|
||||
begin try
|
||||
while !pos < pos2 do
|
||||
incr pos;
|
||||
if input() == '\n' then
|
||||
begin incr line2; line2_pos := !pos; () end
|
||||
done
|
||||
with End_of_file -> ()
|
||||
end;
|
||||
if line_flag then output_lines oc pos1 pos2 !line1_pos !line1 !line2;
|
||||
if !line1 == !line2 then begin
|
||||
seek !line1_pos;
|
||||
output_string oc error_prompt;
|
||||
copy_line ();
|
||||
seek !line1_pos;
|
||||
output_string oc error_prompt;
|
||||
pr_line (pos1 - !line1_pos) (pos2 - pos1) '^';
|
||||
output_char oc '\n'
|
||||
end else begin
|
||||
seek !line1_pos;
|
||||
output_string oc error_prompt;
|
||||
pr_line 0 (pos1 - !line1_pos) '.';
|
||||
seek pos1;
|
||||
copy_line();
|
||||
if !line2 - !line1 <= 8 then
|
||||
for i = !line1 + 1 to !line2 - 1 do
|
||||
output_string oc error_prompt;
|
||||
copy_line()
|
||||
done
|
||||
else
|
||||
begin
|
||||
for i = !line1 + 1 to !line1 + 3 do
|
||||
output_string oc error_prompt;
|
||||
copy_line()
|
||||
done;
|
||||
output_string oc error_prompt; output_string oc "..........\n";
|
||||
for i = !line1 + 4 to !line2 - 4 do skip_line() done;
|
||||
for i = !line2 - 3 to !line2 - 1 do
|
||||
output_string oc error_prompt;
|
||||
copy_line()
|
||||
done
|
||||
end;
|
||||
begin try
|
||||
output_string oc error_prompt;
|
||||
for i = !line2_pos to pos2 - 1 do
|
||||
output_char oc (input())
|
||||
done;
|
||||
pr_line 0 100 '.'
|
||||
with End_of_file -> output_string oc "<EOF>"
|
||||
end;
|
||||
output_char oc '\n'
|
||||
end
|
||||
|
||||
|
||||
let output_location oc loc =
|
||||
let p = pos_in !input_chan in
|
||||
Printf.fprintf oc "File \"%s\"" !input_name;
|
||||
output_loc
|
||||
oc (fun () -> input_char !input_chan) (seek_in !input_chan) true
|
||||
loc;
|
||||
seek_in !input_chan p
|
||||
|
||||
|
||||
let output_input_name oc =
|
||||
Printf.fprintf oc "File \"%s\", line 1:\n" !input_name
|
||||
|
155
global/modules.ml
Normal file
155
global/modules.ml
Normal file
|
@ -0,0 +1,155 @@
|
|||
(**************************************************************************)
|
||||
(* *)
|
||||
(* Heptagon *)
|
||||
(* *)
|
||||
(* Author : Marc Pouzet *)
|
||||
(* Organization : Demons, LRI, University of Paris-Sud, Orsay *)
|
||||
(* *)
|
||||
(**************************************************************************)
|
||||
(* global symbol tables *)
|
||||
|
||||
(* $Id$ *)
|
||||
|
||||
open Misc
|
||||
open Heptagon
|
||||
open Global
|
||||
open Names
|
||||
|
||||
exception Already_defined
|
||||
|
||||
exception Cannot_find_file of string
|
||||
|
||||
(** Warning: Whenever this type is modified,
|
||||
interface_format_version in misc.ml should be incremented. *)
|
||||
type env =
|
||||
{ mutable name: string;
|
||||
mutable values: sig_desc NamesEnv.t;
|
||||
mutable types: typ_desc NamesEnv.t;
|
||||
mutable constr: base_ty NamesEnv.t;
|
||||
mutable field: field_desc NamesEnv.t;
|
||||
mutable structs : struct_desc NamesEnv.t;
|
||||
format_version : string;
|
||||
}
|
||||
|
||||
type modules =
|
||||
{ current: env; (* associated symbol table *)
|
||||
mutable opened: env list; (* opened tables *)
|
||||
mutable modules: env NamesEnv.t; (* tables loaded in memory *)
|
||||
}
|
||||
|
||||
let current =
|
||||
{ name = ""; values = NamesEnv.empty; types = NamesEnv.empty;
|
||||
constr = NamesEnv.empty; field = NamesEnv.empty; structs = NamesEnv.empty;
|
||||
format_version = interface_format_version }
|
||||
|
||||
let modules =
|
||||
{ current = current; opened = []; modules = NamesEnv.empty }
|
||||
|
||||
let findfile filename =
|
||||
if Sys.file_exists filename then
|
||||
filename
|
||||
else if not(Filename.is_implicit filename) then
|
||||
raise(Cannot_find_file filename)
|
||||
else
|
||||
let rec find = function
|
||||
[] ->
|
||||
raise(Cannot_find_file filename)
|
||||
| a::rest ->
|
||||
let b = Filename.concat a filename in
|
||||
if Sys.file_exists b then b else find rest
|
||||
in find !load_path
|
||||
|
||||
let load_module modname =
|
||||
let name = String.uncapitalize modname in
|
||||
try
|
||||
let filename = findfile (name ^ ".epci") in
|
||||
let ic = open_in_bin filename in
|
||||
try
|
||||
let m:env = input_value ic in
|
||||
if m.format_version <> interface_format_version then (
|
||||
Printf.eprintf "The file %s was compiled with \
|
||||
an older version of the compiler.\n \
|
||||
Please recompile %s.ept first.\n" filename name;
|
||||
raise Error
|
||||
);
|
||||
close_in ic;
|
||||
m
|
||||
with
|
||||
| End_of_file | Failure _ ->
|
||||
close_in ic;
|
||||
Printf.eprintf "Corrupted compiled interface file %s.\n\
|
||||
Please recompile %s.ept first.\n" filename name;
|
||||
raise Error
|
||||
with
|
||||
| Cannot_find_file(filename) ->
|
||||
Printf.eprintf "Cannot find the compiled interface file %s.\n"
|
||||
filename;
|
||||
raise Error
|
||||
|
||||
let find_module modname =
|
||||
try
|
||||
NamesEnv.find modname modules.modules
|
||||
with
|
||||
Not_found ->
|
||||
let m = load_module modname in
|
||||
modules.modules <- NamesEnv.add modname m modules.modules;
|
||||
m
|
||||
|
||||
let find where qualname =
|
||||
let rec findrec ident = function
|
||||
| [] -> raise Not_found
|
||||
| m :: l ->
|
||||
try { qualid = { qual = m.name; id = ident };
|
||||
info = where ident m }
|
||||
with Not_found -> findrec ident l in
|
||||
|
||||
match qualname with
|
||||
| Modname({ qual = m; id = ident } as q) ->
|
||||
let current = if current.name = m then current else find_module m in
|
||||
{ qualid = q; info = where ident current }
|
||||
| Name(ident) -> findrec ident (current :: modules.opened)
|
||||
|
||||
(* exported functions *)
|
||||
let open_module modname =
|
||||
let m = find_module modname in
|
||||
modules.opened <- m :: modules.opened
|
||||
|
||||
let initialize modname =
|
||||
current.name <- modname;
|
||||
List.iter open_module !default_used_modules
|
||||
|
||||
let add_value f signature =
|
||||
if NamesEnv.mem f current.values then raise Already_defined;
|
||||
current.values <- NamesEnv.add f signature current.values
|
||||
let add_type f typ_desc =
|
||||
if NamesEnv.mem f current.types then raise Already_defined;
|
||||
current.types <- NamesEnv.add f typ_desc current.types
|
||||
let add_constr f ty_res =
|
||||
if NamesEnv.mem f current.constr then raise Already_defined;
|
||||
current.constr <- NamesEnv.add f ty_res current.constr
|
||||
let add_field f ty_arg ty_res =
|
||||
if NamesEnv.mem f current.field then raise Already_defined;
|
||||
current.field <- NamesEnv.add f { arg = ty_arg; res = ty_res } current.field
|
||||
let add_struct f fields =
|
||||
if NamesEnv.mem f current.structs then raise Already_defined;
|
||||
current.structs <- NamesEnv.add f { fields = fields } current.structs
|
||||
|
||||
let find_value = find (fun ident m -> NamesEnv.find ident m.values)
|
||||
let find_type = find (fun ident m -> NamesEnv.find ident m.types)
|
||||
let find_constr = find (fun ident m -> NamesEnv.find ident m.constr)
|
||||
let find_field = find (fun ident m -> NamesEnv.find ident m.field)
|
||||
let find_struct = find (fun ident m -> NamesEnv.find ident m.structs)
|
||||
|
||||
let replace_value f signature =
|
||||
current.values <- NamesEnv.remove f current.values;
|
||||
current.values <- NamesEnv.add f signature current.values
|
||||
|
||||
let write oc = output_value oc current
|
||||
|
||||
let longname n = Modname({ qual = current.name; id = n })
|
||||
let currentname longname =
|
||||
match longname with
|
||||
| Name(n) -> longname
|
||||
| Modname{ qual = q; id = id} ->
|
||||
if current.name = q then Name(id) else longname
|
||||
|
41
global/names.ml
Normal file
41
global/names.ml
Normal file
|
@ -0,0 +1,41 @@
|
|||
(* long identifiers *)
|
||||
|
||||
type name = string
|
||||
|
||||
type longname =
|
||||
| Name of name
|
||||
| Modname of qualident
|
||||
|
||||
and qualident = { qual: string; id: string }
|
||||
|
||||
module NamesM = struct
|
||||
type t = name
|
||||
let compare = compare
|
||||
end
|
||||
|
||||
module NamesEnv =
|
||||
struct
|
||||
include (Map.Make(NamesM))
|
||||
|
||||
let append env0 env =
|
||||
fold (fun key v env -> add key v env) env0 env
|
||||
end
|
||||
|
||||
module S = Set.Make (struct type t = string let compare = compare end)
|
||||
|
||||
let shortname = function
|
||||
| Name s -> s
|
||||
| Modname { id = id; } -> id
|
||||
|
||||
let fullname = function
|
||||
| Name s -> s
|
||||
| Modname { qual = qual; id = id; } -> qual ^ "." ^ id
|
||||
|
||||
let mk_longname s =
|
||||
try
|
||||
let ind = String.index s '.' in
|
||||
let id = String.sub s (ind + 1) (String.length s - ind - 1) in
|
||||
Modname { qual = String.sub s 0 ind; id = id; }
|
||||
with Not_found -> Name s
|
||||
|
||||
let fprint_t ff id = Format.fprintf ff "%s" (fullname id)
|
176
global/static.ml
Normal file
176
global/static.ml
Normal file
|
@ -0,0 +1,176 @@
|
|||
(** This module defines static expressions, used in arrays definition and anywhere
|
||||
a static value is expected. For instance:
|
||||
const n:int = 3;
|
||||
var x : int^n; var y : int^(n+2);
|
||||
x[n-1], x[1+3],...
|
||||
*)
|
||||
open Names
|
||||
open Format
|
||||
|
||||
type op = SPlus | SMinus | STimes | SDiv
|
||||
|
||||
type size_exp =
|
||||
| SConst of int
|
||||
| SVar of name
|
||||
| SOp of op * size_exp * size_exp
|
||||
|
||||
(** Constraints on size expressions. *)
|
||||
type size_constr =
|
||||
| Equal of size_exp * size_exp (* e1 = e2*)
|
||||
| LEqual of size_exp * size_exp (* e1 <= e2 *)
|
||||
| False (* unsatisfiable constraint *)
|
||||
|
||||
exception Instanciation_failed
|
||||
exception Not_static
|
||||
|
||||
(** Returns the op from an operator full name. *)
|
||||
let op_from_app_name n =
|
||||
match n with
|
||||
| Modname({ qual = "Pervasives"; id = "+" }) | Name "+" -> SPlus
|
||||
| Modname({ qual = "Pervasives"; id = "-" }) | Name "-" -> SMinus
|
||||
| Modname({ qual = "Pervasives"; id = "*" }) | Name "*" -> STimes
|
||||
| Modname({ qual = "Pervasives"; id = "/" }) | Name "/" -> SDiv
|
||||
| _ -> raise Not_static
|
||||
|
||||
(** [simplify env e] returns e simplified with the
|
||||
variables values taken from env (mapping vars to integers).
|
||||
Variables are replaced with their values and every operator
|
||||
that can be computed is replaced with the value of the result. *)
|
||||
let rec simplify env = function
|
||||
| SConst n -> SConst n
|
||||
| SVar id ->
|
||||
(try
|
||||
simplify env (NamesEnv.find id env)
|
||||
with
|
||||
_ -> SVar id
|
||||
)
|
||||
| SOp(op, e1, e2) ->
|
||||
let e1 = simplify env e1 in
|
||||
let e2 = simplify env e2 in
|
||||
(match e1, e2 with
|
||||
| SConst n1, SConst n2 ->
|
||||
let n = (match op with
|
||||
| SPlus -> n1 + n2
|
||||
| SMinus -> n1 - n2
|
||||
| STimes -> n1 * n2
|
||||
| SDiv ->
|
||||
if n2 = 0 then
|
||||
raise Instanciation_failed
|
||||
else
|
||||
n1 / n2
|
||||
) in
|
||||
SConst n
|
||||
| _, _ -> SOp(op, e1, e2)
|
||||
)
|
||||
|
||||
(** [int_of_size_exp env e] returns the value of the expression
|
||||
[e] in the environment [env], mapping vars to integers. Raises
|
||||
Instanciation_failed if it cannot be computed (if a var has no value).*)
|
||||
let int_of_size_exp env e =
|
||||
match simplify env e with
|
||||
| SConst n -> n
|
||||
| _ -> raise Instanciation_failed
|
||||
|
||||
(** [is_true env constr] returns whether the constraint is satisfied
|
||||
in the environment (or None if this can be decided)
|
||||
and a simplified constraint. *)
|
||||
let is_true env = function
|
||||
| Equal (e1,e2) when e1 = e2 ->
|
||||
Some true, Equal (simplify env e1, simplify env e2)
|
||||
| Equal (e1, e2) ->
|
||||
let e1 = simplify env e1 in
|
||||
let e2 = simplify env e2 in
|
||||
(match e1, e2 with
|
||||
| SConst n1, SConst n2 ->
|
||||
Some (n1 = n2), Equal (e1,e2)
|
||||
| _, _ -> None, Equal (e1,e2)
|
||||
)
|
||||
| LEqual (e1, e2) ->
|
||||
let e1 = simplify env e1 in
|
||||
let e2 = simplify env e2 in
|
||||
(match e1, e2 with
|
||||
| SConst n1, SConst n2 ->
|
||||
Some (n1 <= n2), LEqual (e1,e2)
|
||||
| _, _ -> None, LEqual (e1,e2)
|
||||
)
|
||||
| False -> None, False
|
||||
|
||||
exception Solve_failed of size_constr
|
||||
(** [solve env constr_list solves a list of constraints. It
|
||||
removes equations that can be decided and simplify others.
|
||||
If one equation cannot be satisfied, it raises Solve_failed. ]*)
|
||||
let rec solve const_env = function
|
||||
| [] -> []
|
||||
| c::l ->
|
||||
let l = solve const_env l in
|
||||
let res, c = is_true const_env c in
|
||||
(match res with
|
||||
| None -> c::l
|
||||
| Some v -> if not v then raise (Solve_failed c) else l
|
||||
)
|
||||
|
||||
(** Substitutes variables in the size exp with their value
|
||||
in the map (mapping vars to size exps). *)
|
||||
let rec size_exp_subst m = function
|
||||
| SVar n ->
|
||||
(try
|
||||
List.assoc n m
|
||||
with
|
||||
Not_found -> SVar n
|
||||
)
|
||||
| SOp(op,e1,e2) -> SOp(op, size_exp_subst m e1, size_exp_subst m e2)
|
||||
| s -> s
|
||||
|
||||
(** Substitutes variables in the constraint list with their value
|
||||
in the map (mapping vars to size exps). *)
|
||||
let instanciate_constr m constr =
|
||||
let replace_one m = function
|
||||
| Equal(e1,e2) -> Equal(size_exp_subst m e1, size_exp_subst m e2)
|
||||
| LEqual(e1,e2) -> LEqual(size_exp_subst m e1, size_exp_subst m e2)
|
||||
in
|
||||
List.map (replace_one m) constr
|
||||
|
||||
let op_to_string = function
|
||||
| SPlus -> "+"
|
||||
| SMinus -> "-"
|
||||
| STimes -> "*"
|
||||
| SDiv -> "/"
|
||||
|
||||
let rec print_size_exp ff = function
|
||||
| SConst i -> fprintf ff "%d" i
|
||||
| SVar id -> fprintf ff "%s" id
|
||||
| SOp (op, e1, e2) ->
|
||||
fprintf ff "@[(";
|
||||
print_size_exp ff e1;
|
||||
fprintf ff " %s " (op_to_string op);
|
||||
print_size_exp ff e2;
|
||||
fprintf ff ")@]"
|
||||
|
||||
let rec print_list ff print sep l =
|
||||
match l with
|
||||
| [] -> ()
|
||||
| [x] -> print ff x
|
||||
| x :: l ->
|
||||
print ff x;
|
||||
fprintf ff "%s@ " sep;
|
||||
print_list ff print sep l
|
||||
|
||||
let print_size_constr ff = function
|
||||
| Equal (e1, e2) ->
|
||||
fprintf ff "@[";
|
||||
print_size_exp ff e1;
|
||||
fprintf ff " = ";
|
||||
print_size_exp ff e2;
|
||||
fprintf ff "@]"
|
||||
| LEqual (e1, e2) ->
|
||||
fprintf ff "@[";
|
||||
print_size_exp ff e1;
|
||||
fprintf ff " <= ";
|
||||
print_size_exp ff e2;
|
||||
fprintf ff "@]"
|
||||
| False ->
|
||||
fprintf ff "False"
|
||||
|
||||
let psize_constr oc c =
|
||||
let ff = formatter_of_out_channel oc in
|
||||
print_size_constr ff c; fprintf ff "@?"
|
43
heptagon/analysis/automata_mem.ml
Normal file
43
heptagon/analysis/automata_mem.ml
Normal file
|
@ -0,0 +1,43 @@
|
|||
open Ident
|
||||
open Names
|
||||
open Heptagon
|
||||
open Interference_graph
|
||||
|
||||
let node_for_name s g =
|
||||
try
|
||||
node_for_value g s
|
||||
with
|
||||
Not_found ->
|
||||
let n = mk_node s in
|
||||
add_node g n;
|
||||
n
|
||||
|
||||
let find_reset_jumps g sh =
|
||||
let reset_escape state esc =
|
||||
if esc.e_reset = true then
|
||||
( Format.printf "Jump from %s to %s with reset\n" state esc.e_next_state;
|
||||
let n1 = node_for_name state g in
|
||||
let n2 = node_for_name esc.e_next_state g in
|
||||
add_interference_link n1 n2
|
||||
) else
|
||||
(Format.printf "Jump from %s to %s is not resetted\n" state esc.e_next_state;
|
||||
let n1 = node_for_name state g in
|
||||
let n2 = node_for_name esc.e_next_state g in
|
||||
add_affinity_link n1 n2
|
||||
)
|
||||
in
|
||||
List.iter (reset_escape sh.s_state) sh.s_until
|
||||
|
||||
let share_eq g eq =
|
||||
match eq.eq_desc with
|
||||
| Eautomaton sh_list ->
|
||||
List.iter (find_reset_jumps g) sh_list
|
||||
| _ -> Format.printf "Ignoring unsupported eq\n"
|
||||
|
||||
let node f =
|
||||
let g = mk_graph [] f.n_name in
|
||||
List.iter (share_eq g) f.n_equs;
|
||||
{ f with n_states_graph = g; }
|
||||
|
||||
let program p =
|
||||
{ p with p_nodes = List.map node p.p_nodes }
|
280
heptagon/analysis/causal.ml
Normal file
280
heptagon/analysis/causal.ml
Normal file
|
@ -0,0 +1,280 @@
|
|||
(**************************************************************************)
|
||||
(* *)
|
||||
(* Heptagon *)
|
||||
(* *)
|
||||
(* Author : Marc Pouzet *)
|
||||
(* Organization : Demons, LRI, University of Paris-Sud, Orsay *)
|
||||
(* *)
|
||||
(**************************************************************************)
|
||||
|
||||
(* causality check of scheduling constraints *)
|
||||
|
||||
(* $Id: causal.ml 615 2009-11-20 17:43:14Z pouzet $ *)
|
||||
|
||||
open Misc
|
||||
open Names
|
||||
open Ident
|
||||
open Heptagon
|
||||
open Location
|
||||
open Graph
|
||||
open Format
|
||||
|
||||
(* x = x + 1 is rejected because read(x) < write(x) is not causal *)
|
||||
(* build a dependency graph an checks for cycles *)
|
||||
(* for the moment, the # constructor is distributed which leads to a *)
|
||||
(* sub-optimal algorithm. *)
|
||||
|
||||
(* constraints [c] are normalised into [a1 # ... # an] st: *)
|
||||
(* a ::= write(x) | read(x) | last(x) | a < a | a || a *)
|
||||
(* c ::= a # ... # a *)
|
||||
(* a constraint [a] is causal if its dependence graph is acyclic *)
|
||||
|
||||
(* scheduling constraints *)
|
||||
type sc =
|
||||
| Cor of sc * sc
|
||||
| Cand of sc * sc
|
||||
| Cseq of sc * sc
|
||||
| Ctuple of sc list
|
||||
| Cwrite of ident
|
||||
| Cread of ident
|
||||
| Clinread of ident
|
||||
| Clastread of ident
|
||||
| Cempty
|
||||
|
||||
(* normalized constraints *)
|
||||
type ac =
|
||||
| Awrite of ident
|
||||
| Alinread of ident
|
||||
| Aread of ident
|
||||
| Alastread of ident
|
||||
| Aseq of ac * ac
|
||||
| Aand of ac * ac
|
||||
| Atuple of ac list
|
||||
|
||||
and nc =
|
||||
| Aor of nc * nc
|
||||
| Aac of ac
|
||||
| Aempty
|
||||
|
||||
let rec print_list ff print sep l =
|
||||
match l with
|
||||
| [] -> ()
|
||||
| [x] -> print ff x
|
||||
| x :: l ->
|
||||
print ff x;
|
||||
fprintf ff "%s@ " sep;
|
||||
print_list ff print sep l
|
||||
|
||||
let output_ac ff ac =
|
||||
let rec print priority ff ac =
|
||||
fprintf ff "@[<hov 0>";
|
||||
begin match ac with
|
||||
| Aseq(ac1, ac2) ->
|
||||
(if priority > 1
|
||||
then fprintf ff "(%a@ < %a)"
|
||||
else fprintf ff "%a@ < %a")
|
||||
(print 1) ac1 (print 1) ac2
|
||||
| Aand(ac1, ac2) ->
|
||||
(if priority > 0
|
||||
then fprintf ff "(%a || %a)"
|
||||
else fprintf ff "%a || %a")
|
||||
(print 0) ac1 (print 0) ac2
|
||||
| Atuple(acs) ->
|
||||
fprintf ff "(";
|
||||
print_list ff (print 1) ", " acs ;
|
||||
fprintf ff ")"
|
||||
| Awrite(m) -> fprintf ff "%s" (sourcename m)
|
||||
| Aread(m) -> fprintf ff "^%s" (sourcename m)
|
||||
| Alinread(m) -> fprintf ff "*%s" (sourcename m)
|
||||
| Alastread(m) -> fprintf ff "last %s" (sourcename m)
|
||||
end;
|
||||
fprintf ff "@]" in
|
||||
fprintf ff "@[%a@]@?" (print 0) ac
|
||||
|
||||
|
||||
type error = Ecausality_cycle of ac
|
||||
|
||||
exception Error of error
|
||||
|
||||
let error kind = raise (Error(kind))
|
||||
|
||||
let message loc kind =
|
||||
let output_ac oc ac =
|
||||
let ff = formatter_of_out_channel oc in output_ac ff ac in
|
||||
begin match kind with
|
||||
| Ecausality_cycle(ac) ->
|
||||
Printf.eprintf
|
||||
"%aCausality error: the following constraint is not causal.\n%a\n."
|
||||
output_location loc
|
||||
output_ac ac
|
||||
end;
|
||||
raise Misc.Error
|
||||
|
||||
let cor nc1 nc2 =
|
||||
match nc1, nc2 with
|
||||
| Aempty, Aempty -> Aempty
|
||||
| _ -> Aor(nc1, nc2)
|
||||
|
||||
let rec cseq nc1 nc2 =
|
||||
match nc1, nc2 with
|
||||
| Aempty, _ -> nc2
|
||||
| _, Aempty -> nc1
|
||||
| Aor(nc1, nc11), nc2 -> Aor(cseq nc1 nc2, cseq nc11 nc2)
|
||||
| nc1, Aor(nc2, nc22) -> Aor(cseq nc1 nc2, cseq nc1 nc22)
|
||||
| Aac(ac1), Aac(ac2) -> Aac(Aseq(ac1, ac2))
|
||||
|
||||
let rec cand nc1 nc2 =
|
||||
match nc1, nc2 with
|
||||
| Aempty, _ -> nc2 | _, Aempty -> nc1
|
||||
| Aor(nc1, nc11), nc2 -> Aor(cand nc1 nc2, cand nc11 nc2)
|
||||
| nc1, Aor(nc2, nc22) -> Aor(cand nc1 nc2, cand nc1 nc22)
|
||||
| Aac(ac1), Aac(ac2) -> Aac(Aand(ac1, ac2))
|
||||
|
||||
let rec ctuple l =
|
||||
let conv = function
|
||||
| Cwrite(n) -> Awrite(n)
|
||||
| Cread(n) -> Aread(n)
|
||||
| Clinread(n) -> Alinread(n)
|
||||
| Clastread(n) -> Alastread(n)
|
||||
| Ctuple(l) -> Atuple (ctuple l)
|
||||
| Cand _ -> Format.printf "Unexpected and\n"; assert false
|
||||
| Cseq _ -> Format.printf "Unexpected seq\n"; assert false
|
||||
| Cor _ -> Format.printf "Unexpected or\n"; assert false
|
||||
| _ -> assert false
|
||||
in
|
||||
match l with
|
||||
| [] -> []
|
||||
| Cempty::l -> ctuple l
|
||||
| v::l -> (conv v)::(ctuple l)
|
||||
|
||||
let rec norm = function
|
||||
| Cor(c1, c2) -> cor (norm c1) (norm c2)
|
||||
| Cand(c1, c2) -> cand (norm c1) (norm c2)
|
||||
| Cseq(c1, c2) -> cseq (norm c1) (norm c2)
|
||||
| Ctuple l -> Aac(Atuple (ctuple l))
|
||||
| Cwrite(n) -> Aac(Awrite(n))
|
||||
| Cread(n) -> Aac(Aread(n))
|
||||
| Clinread(n) -> Aac(Alinread(n))
|
||||
| Clastread(n) -> Aac(Alastread(n))
|
||||
| _ -> Aempty
|
||||
|
||||
(* building a dependence graph from a scheduling constraint *)
|
||||
let build ac =
|
||||
(* associate a graph node for each name declaration *)
|
||||
let nametograph n g n_to_graph = Env.add n g n_to_graph in
|
||||
|
||||
let rec associate_node g (n_to_graph,lin_map) = function
|
||||
| Awrite(n) ->
|
||||
nametograph n g n_to_graph, lin_map
|
||||
| Alinread(n) ->
|
||||
n_to_graph, nametograph n g lin_map
|
||||
| Atuple l ->
|
||||
List.fold_left (associate_node g) (n_to_graph, lin_map) l
|
||||
| _ ->
|
||||
n_to_graph, lin_map
|
||||
in
|
||||
|
||||
(* first build the association [n -> node] *)
|
||||
(* for every defined variable *)
|
||||
let rec initialize ac n_to_graph lin_map =
|
||||
match ac with
|
||||
| Aand(ac1, ac2) ->
|
||||
let n_to_graph, lin_map = initialize ac1 n_to_graph lin_map in
|
||||
initialize ac2 n_to_graph lin_map
|
||||
| Aseq(ac1, ac2) ->
|
||||
let n_to_graph, lin_map = initialize ac1 n_to_graph lin_map in
|
||||
initialize ac2 n_to_graph lin_map
|
||||
| _ ->
|
||||
let g = make ac in
|
||||
associate_node g (n_to_graph, lin_map) ac
|
||||
in
|
||||
|
||||
let make_graph ac n_to_graph lin_map =
|
||||
let attach node n =
|
||||
try
|
||||
let g = Env.find n n_to_graph in add_depends node g
|
||||
with
|
||||
| Not_found -> () in
|
||||
|
||||
let attach_lin node n =
|
||||
try
|
||||
let g = Env.find n lin_map in add_depends g node
|
||||
with
|
||||
| Not_found -> () in
|
||||
|
||||
let rec add_dependence g = function
|
||||
| Aread(n) -> attach g n; attach_lin g n
|
||||
| Alinread(n) -> let g = Env.find n lin_map in attach g n
|
||||
| Atuple l -> List.iter (add_dependence g) l
|
||||
| _ -> ()
|
||||
in
|
||||
|
||||
let rec node_for_ac ac =
|
||||
let rec node_for_tuple = function
|
||||
| [] -> raise Not_found
|
||||
| v::l ->
|
||||
(try
|
||||
node_for_ac v
|
||||
with
|
||||
Not_found -> node_for_tuple l
|
||||
)
|
||||
in
|
||||
match ac with
|
||||
| Alinread n -> Env.find n lin_map
|
||||
| Awrite n -> Env.find n n_to_graph
|
||||
| Atuple l ->
|
||||
begin try
|
||||
node_for_tuple l
|
||||
with Not_found
|
||||
_ -> make ac
|
||||
end
|
||||
| _ -> make ac
|
||||
in
|
||||
|
||||
let rec make_graph ac =
|
||||
match ac with
|
||||
| Aand(ac1, ac2) ->
|
||||
let top1, bot1 = make_graph ac1 in
|
||||
let top2, bot2 = make_graph ac2 in
|
||||
top1 @ top2, bot1 @ bot2
|
||||
| Aseq(ac1, ac2) ->
|
||||
let top1, bot1 = make_graph ac1 in
|
||||
let top2, bot2 = make_graph ac2 in
|
||||
(* add extra dependences *)
|
||||
List.iter
|
||||
(fun top -> List.iter (fun bot -> add_depends top bot) bot1)
|
||||
top2;
|
||||
top1 @ top2, bot1 @ bot2
|
||||
| Awrite(n) -> let g = Env.find n n_to_graph in [g], [g]
|
||||
| Aread(n) -> let g = make ac in attach g n; attach_lin g n; [g], [g]
|
||||
| Alinread(n) -> let g = Env.find n lin_map in attach g n; [g], [g]
|
||||
| Atuple(l) ->
|
||||
let g = node_for_ac ac in
|
||||
List.iter (add_dependence g) l;
|
||||
[g], [g]
|
||||
| _ -> [], [] in
|
||||
let top_list, bot_list = make_graph ac in
|
||||
graph top_list bot_list in
|
||||
|
||||
let n_to_graph, lin_map = initialize ac Env.empty Env.empty in
|
||||
let g = make_graph ac n_to_graph lin_map in
|
||||
g
|
||||
|
||||
(* the main entry. *)
|
||||
let check loc c =
|
||||
let check_ac ac =
|
||||
let { g_bot = g_list } = build ac in
|
||||
match cycle g_list with
|
||||
| None -> ()
|
||||
| Some _ -> error (Ecausality_cycle ac) in
|
||||
|
||||
let rec check = function
|
||||
| Aempty -> ()
|
||||
| Aac(ac) -> check_ac ac
|
||||
| Aor(nc1, nc2) -> check nc1; check nc2 in
|
||||
|
||||
let nc = norm c in
|
||||
try
|
||||
check nc
|
||||
with
|
||||
| Error(kind) -> message loc kind
|
214
heptagon/analysis/causality.ml
Normal file
214
heptagon/analysis/causality.ml
Normal file
|
@ -0,0 +1,214 @@
|
|||
(**************************************************************************)
|
||||
(* *)
|
||||
(* Heptagon *)
|
||||
(* *)
|
||||
(* Author : Marc Pouzet *)
|
||||
(* Organization : Demons, LRI, University of Paris-Sud, Orsay *)
|
||||
(* *)
|
||||
(**************************************************************************)
|
||||
|
||||
(* causality check *)
|
||||
|
||||
(* $Id: causality.ml 615 2009-11-20 17:43:14Z pouzet $ *)
|
||||
|
||||
open Misc
|
||||
open Names
|
||||
open Ident
|
||||
open Heptagon
|
||||
open Location
|
||||
open Linearity
|
||||
open Graph
|
||||
open Causal
|
||||
|
||||
let cempty = Cempty
|
||||
let is_empty c = (c = cempty)
|
||||
|
||||
let cand c1 c2 =
|
||||
match c1, c2 with
|
||||
| Cempty, _ -> c2 | _, Cempty -> c1
|
||||
| c1, c2 -> Cand(c1, c2)
|
||||
let rec candlist l =
|
||||
match l with
|
||||
| [] -> Cempty
|
||||
| c1 :: l -> cand c1 (candlist l)
|
||||
|
||||
let ctuplelist l =
|
||||
Ctuple l
|
||||
|
||||
let cor c1 c2 =
|
||||
match c1, c2 with
|
||||
| Cempty, Cempty -> Cempty
|
||||
| _ -> Cor(c1, c2)
|
||||
let rec corlist l =
|
||||
match l with
|
||||
| [] -> Cempty
|
||||
| [c1] -> c1
|
||||
| c1 :: l -> cor c1 (corlist l)
|
||||
|
||||
let cseq c1 c2 =
|
||||
match c1, c2 with
|
||||
| Cempty, _ -> c2
|
||||
| _, Cempty -> c1
|
||||
| c1, c2 -> Cseq(c1, c2)
|
||||
let rec cseqlist l =
|
||||
match l with
|
||||
| [] -> Cempty
|
||||
| c1 :: l -> cseq c1 (cseqlist l)
|
||||
|
||||
let read x = Cread(x)
|
||||
let linread x = Clinread(x)
|
||||
let lastread x = Clastread(x)
|
||||
let cwrite x = Cwrite(x)
|
||||
|
||||
(* cutting dependences with a delay operator *)
|
||||
let rec pre = function
|
||||
| Cor(c1, c2) -> Cor(pre c1, pre c2)
|
||||
| Cand(c1, c2) -> Cand(pre c1, pre c2)
|
||||
| Ctuple l -> Ctuple (List.map pre l)
|
||||
| Cseq(c1, c2) -> Cseq(pre c1, pre c2)
|
||||
| Cread(x) | Clinread (x) -> Cempty
|
||||
| (Cwrite _ | Clastread _ | Cempty) as c -> c
|
||||
|
||||
(* projection and restriction *)
|
||||
let clear env c =
|
||||
let rec clearec c =
|
||||
match c with
|
||||
| Cor(c1, c2) ->
|
||||
let c1 = clearec c1 in
|
||||
let c2 = clearec c2 in
|
||||
cor c1 c2
|
||||
| Cand(c1, c2) ->
|
||||
let c1 = clearec c1 in
|
||||
let c2 = clearec c2 in
|
||||
cand c1 c2
|
||||
| Cseq(c1, c2) ->
|
||||
let c1 = clearec c1 in
|
||||
let c2 = clearec c2 in
|
||||
cseq c1 c2
|
||||
| Ctuple l -> Ctuple (List.map clearec l)
|
||||
| Cwrite(id) | Cread(id) | Clinread(id) | Clastread(id) ->
|
||||
if IdentSet.mem id env then Cempty else c
|
||||
| Cempty -> c in
|
||||
clearec c
|
||||
|
||||
let build dec =
|
||||
List.fold_left (fun acc { v_name = n } -> IdentSet.add n acc) IdentSet.empty dec
|
||||
|
||||
(** Main typing function *)
|
||||
let rec typing e =
|
||||
match e.e_desc with
|
||||
| Econst(c) -> cempty
|
||||
| Econstvar(x) -> cempty
|
||||
| Evar(x) ->
|
||||
(match e.e_linearity with
|
||||
| At _ -> linread x
|
||||
| _ -> read x
|
||||
)
|
||||
| Elast(x) -> lastread x
|
||||
| Etuple(e_list) ->
|
||||
candlist (List.map typing e_list)
|
||||
| Eapp({a_op = op}, e_list) -> apply op e_list
|
||||
| Efield(e1, _) -> typing e1
|
||||
| Estruct(l) ->
|
||||
let l = List.map (fun (_, e) -> typing e) l in
|
||||
candlist l
|
||||
| Earray(e_list) ->
|
||||
candlist (List.map typing e_list)
|
||||
| Ereset_mem _ -> assert false
|
||||
|
||||
(** Typing an application *)
|
||||
and apply op e_list =
|
||||
match op, e_list with
|
||||
| Epre(_), [e] -> pre (typing e)
|
||||
| Efby, [e1;e2] ->
|
||||
let t1 = typing e1 in
|
||||
let t2 = pre (typing e2) in
|
||||
candlist [t1; t2]
|
||||
| Earrow, [e1;e2] ->
|
||||
let t1 = typing e1 in
|
||||
let t2 = typing e2 in
|
||||
candlist [t1; t2]
|
||||
| Eifthenelse, [e1; e2; e3] ->
|
||||
let t1 = typing e1 in
|
||||
let i2 = typing e2 in
|
||||
let i3 = typing e3 in
|
||||
cseq t1 (cor i2 i3)
|
||||
| (Enode _ | Eevery _ | Eop _ | Eiterator (_, _, _, _)
|
||||
| Econcat | Eselect_slice | Emake _ | Eflatten _
|
||||
| Eselect_dyn | Eselect _ | Erepeat | Ecopy), e_list ->
|
||||
ctuplelist (List.map typing e_list)
|
||||
| Eupdate _, [e1;e2] | Efield_update _, [e1;e2] ->
|
||||
let t1 = typing e1 in
|
||||
let t2 = typing e2 in
|
||||
cseq t2 t1
|
||||
|
||||
let rec typing_pat = function
|
||||
| Evarpat(x) -> cwrite(x)
|
||||
| Etuplepat(pat_list) ->
|
||||
candlist (List.map typing_pat pat_list)
|
||||
|
||||
(** Typing equations *)
|
||||
let rec typing_eqs eq_list = candlist (List.map typing_eq eq_list)
|
||||
|
||||
and typing_eq eq =
|
||||
match eq.eq_desc with
|
||||
| Eautomaton(handlers) -> typing_automaton handlers
|
||||
| Eswitch(e, handlers) ->
|
||||
cseq (typing e) (typing_switch handlers)
|
||||
| Epresent(handlers, b) ->
|
||||
typing_present handlers b
|
||||
| Ereset(eq_list, e) ->
|
||||
cseq (typing e) (typing_eqs eq_list)
|
||||
| Eeq(pat, e) ->
|
||||
cseq (typing e) (typing_pat pat)
|
||||
|
||||
and typing_switch handlers =
|
||||
let handler { w_block = b } = typing_block b in
|
||||
corlist (List.map handler handlers)
|
||||
|
||||
and typing_present handlers b =
|
||||
let handler { p_cond = e; p_block = b } =
|
||||
cseq (typing e) (typing_block b) in
|
||||
corlist ((typing_block b) :: (List.map handler handlers))
|
||||
|
||||
and typing_automaton state_handlers =
|
||||
(* typing the body of the automaton *)
|
||||
let handler
|
||||
{ s_state = _; s_block = b; s_until = suntil; s_unless = sunless } =
|
||||
let escape { e_cond = e } = typing e in
|
||||
|
||||
(* typing the body *)
|
||||
let tb = typing_block b in
|
||||
let t1 = candlist (List.map escape suntil) in
|
||||
let t2 = candlist (List.map escape sunless) in
|
||||
|
||||
cseq t2 (cseq tb t1) in
|
||||
corlist (List.map handler state_handlers)
|
||||
|
||||
and typing_block { b_local = dec; b_equs = eq_list; b_loc = loc } =
|
||||
let teq = typing_eqs eq_list in
|
||||
Causal.check loc teq;
|
||||
clear (build dec) teq
|
||||
|
||||
let typing_contract loc contract =
|
||||
match contract with
|
||||
| None -> cempty
|
||||
| Some { c_local = l_list; c_eq = eq_list; c_assume = e_a;
|
||||
c_enforce = e_g; c_controllables = c_list } ->
|
||||
let teq = typing_eqs eq_list in
|
||||
let t_contract = cseq (typing e_a) (cseq teq (typing e_g)) in
|
||||
Causal.check loc t_contract;
|
||||
let t_contract = clear (build l_list) t_contract in
|
||||
t_contract
|
||||
|
||||
let typing_node { n_name = f; n_input = i_list; n_output = o_list;
|
||||
n_contract = contract;
|
||||
n_local = l_list; n_equs = eq_list; n_loc = loc } =
|
||||
let _ = typing_contract loc contract in
|
||||
let teq = typing_eqs eq_list in
|
||||
Causal.check loc teq
|
||||
|
||||
let program ({ p_nodes = p_node_list } as p) =
|
||||
List.iter typing_node p_node_list;
|
||||
p
|
||||
|
374
heptagon/analysis/initialization.ml
Normal file
374
heptagon/analysis/initialization.ml
Normal file
|
@ -0,0 +1,374 @@
|
|||
(**************************************************************************)
|
||||
(* *)
|
||||
(* Heptagon *)
|
||||
(* *)
|
||||
(* Author : Marc Pouzet *)
|
||||
(* Organization : Demons, LRI, University of Paris-Sud, Orsay *)
|
||||
(* *)
|
||||
(**************************************************************************)
|
||||
|
||||
(* simple initialization analysis. This is almost trivial since *)
|
||||
(* input/outputs of a node are forced to be initialized *)
|
||||
|
||||
(* $Id: initialization.ml 615 2009-11-20 17:43:14Z pouzet $ *)
|
||||
|
||||
open Misc
|
||||
open Names
|
||||
open Ident
|
||||
open Heptagon
|
||||
open Location
|
||||
open Format
|
||||
|
||||
type typ =
|
||||
| Iproduct of typ list
|
||||
| Ileaf of init
|
||||
|
||||
and init =
|
||||
{ mutable i_desc: init_desc;
|
||||
mutable i_index: int }
|
||||
|
||||
and init_desc =
|
||||
| Izero
|
||||
| Ione
|
||||
| Ivar
|
||||
| Imax of init * init
|
||||
| Ilink of init
|
||||
|
||||
type kind = | Last of init | Var
|
||||
|
||||
type tenv = { i_kind : kind; i_typ : init }
|
||||
|
||||
(* typing errors *)
|
||||
exception Unify
|
||||
|
||||
let index = ref 0
|
||||
let gen_index () = incr index; !index
|
||||
let new_var () = { i_desc = Ivar; i_index = gen_index () }
|
||||
let izero = { i_desc = Izero; i_index = gen_index () }
|
||||
let ione = { i_desc = Ione; i_index = gen_index () }
|
||||
let imax i1 i2 = { i_desc = Imax(i1, i2); i_index = gen_index () }
|
||||
let product l = Iproduct(l)
|
||||
let leaf i = Ileaf(i)
|
||||
|
||||
(* basic operation on initialization values *)
|
||||
let rec irepr i =
|
||||
match i.i_desc with
|
||||
| Ilink(i_son) ->
|
||||
let i_son = irepr i_son in
|
||||
i.i_desc <- Ilink(i_son);
|
||||
i_son
|
||||
| _ -> i
|
||||
|
||||
(** Simplification rules for max. Nothing fancy here *)
|
||||
let max i1 i2 =
|
||||
let i1 = irepr i1 in
|
||||
let i2 = irepr i2 in
|
||||
match i1.i_desc, i2.i_desc with
|
||||
| (Izero, Izero) -> izero
|
||||
| (Izero, _) -> i2
|
||||
| (_, Izero) -> i1
|
||||
| (_, Ione) | (Ione, _) -> ione
|
||||
| _ -> imax i1 i2
|
||||
|
||||
let rec itype = function
|
||||
| Iproduct(ty_list) -> itype_list ty_list
|
||||
| Ileaf(i) -> i
|
||||
|
||||
and itype_list ty_list =
|
||||
List.fold_left (fun acc ty -> max acc (itype ty)) izero ty_list
|
||||
|
||||
(* saturate an initialization type. Every element must be initialized *)
|
||||
let rec initialized i =
|
||||
let i = irepr i in
|
||||
match i.i_desc with
|
||||
| Izero -> ()
|
||||
| Ivar -> i.i_desc <- Ilink(izero)
|
||||
| Imax(i1, i2) -> initialized i1; initialized i2
|
||||
| Ilink(i) -> initialized i
|
||||
| Ione -> raise Unify
|
||||
|
||||
(* build an initialization type from a type *)
|
||||
let rec skeleton i ty =
|
||||
match ty with
|
||||
| Tbase _ -> leaf i
|
||||
| Tprod(ty_list) -> product (List.map (skeleton i) ty_list)
|
||||
|
||||
(* sub-typing *)
|
||||
let rec less left_ty right_ty =
|
||||
if left_ty == right_ty then ()
|
||||
else
|
||||
match left_ty, right_ty with
|
||||
| Iproduct(l1), Iproduct(l2) -> List.iter2 less l1 l2
|
||||
| Ileaf(i1), Ileaf(i2) -> iless i1 i2
|
||||
| _ -> raise Unify
|
||||
|
||||
and iless left_i right_i =
|
||||
if left_i == right_i then ()
|
||||
else
|
||||
let left_i = irepr left_i in
|
||||
let right_i = irepr right_i in
|
||||
if left_i == right_i then ()
|
||||
else
|
||||
match left_i.i_desc, right_i.i_desc with
|
||||
| (Izero, _) | (_, Ione) -> ()
|
||||
| _, Izero -> initialized left_i
|
||||
| Imax(i1, i2), _ ->
|
||||
iless i1 right_i; iless i2 right_i
|
||||
| _, Ivar ->
|
||||
let left_i = occur_check right_i.i_index left_i in
|
||||
right_i.i_desc <- Ilink(left_i)
|
||||
| _, Imax(i1, i2) ->
|
||||
let i1 = occur_check left_i.i_index i1 in
|
||||
let i2 = occur_check left_i.i_index i2 in
|
||||
right_i.i_desc <- Ilink(imax left_i (imax i1 i2))
|
||||
| _ -> raise Unify
|
||||
|
||||
(* an inequation [a < t[a]] becomes [a = t[0]] *)
|
||||
and occur_check index i =
|
||||
match i.i_desc with
|
||||
| Izero | Ione -> i
|
||||
| Ivar -> if i.i_index = index then izero else i
|
||||
| Imax(i1, i2) ->
|
||||
max (occur_check index i1) (occur_check index i2)
|
||||
| Ilink(i) -> occur_check index i
|
||||
|
||||
module Printer = struct
|
||||
open Format
|
||||
|
||||
let rec print_list_r print po sep pf ff = function
|
||||
| [] -> ()
|
||||
| x :: l ->
|
||||
fprintf ff "@[%s%a" po print x;
|
||||
List.iter (fprintf ff "%s@]@ @[%a" sep print) l;
|
||||
fprintf ff "%s@]" pf
|
||||
|
||||
let rec fprint_init ff i = match i.i_desc with
|
||||
| Izero -> fprintf ff "0"
|
||||
| Ione -> fprintf ff "1"
|
||||
| Ivar -> fprintf ff "0"
|
||||
| Imax(i1, i2) -> fprintf ff "@[%a\\/%a@]" fprint_init i1 fprint_init i2
|
||||
| Ilink(i) -> fprint_init ff i
|
||||
|
||||
let rec fprint_typ ff = function
|
||||
| Ileaf(i) -> fprint_init ff i
|
||||
| Iproduct(ty_list) ->
|
||||
fprintf ff "@[%a@]" (print_list_r fprint_typ "("" *"")") ty_list
|
||||
|
||||
let output_typ oc ty =
|
||||
let ff = formatter_of_out_channel oc in
|
||||
fprintf ff "@[";
|
||||
fprint_typ ff ty;
|
||||
fprintf ff "@?@]"
|
||||
end
|
||||
|
||||
module Error = struct
|
||||
open Location
|
||||
|
||||
type error = | Eclash of typ * typ
|
||||
|
||||
exception Error of location * error
|
||||
|
||||
let error loc kind = raise (Error(loc, kind))
|
||||
|
||||
let message loc kind =
|
||||
begin match kind with
|
||||
| Eclash(left_ty, right_ty) ->
|
||||
Printf.eprintf "%aInitialization error: this expression has type \
|
||||
%a, \n\
|
||||
but is expected to have type %a\n"
|
||||
output_location loc
|
||||
Printer.output_typ left_ty
|
||||
Printer.output_typ right_ty
|
||||
end;
|
||||
raise Misc.Error
|
||||
end
|
||||
|
||||
let less_exp e actual_ty expected_ty =
|
||||
try
|
||||
less actual_ty expected_ty
|
||||
with | Unify -> Error.message e.e_loc (Error.Eclash(actual_ty, expected_ty))
|
||||
|
||||
(** Is-it a safe imported value? *)
|
||||
let safe f =
|
||||
let { Global.info = { Global.safe = s } } = Modules.find_value f in s
|
||||
|
||||
(** Main typing function *)
|
||||
let rec typing h e =
|
||||
match e.e_desc with
|
||||
| Econst _ | Econstvar _ -> leaf izero
|
||||
| Evar(x) | Elast(x) -> let { i_typ = i } = Env.find x h in leaf i
|
||||
| Etuple(e_list) ->
|
||||
product (List.map (typing h) e_list)
|
||||
| Eapp({a_op = op}, e_list) ->
|
||||
let i = apply h op e_list in
|
||||
skeleton i e.e_ty
|
||||
| Efield(e1, _) ->
|
||||
let i = itype (typing h e1) in
|
||||
skeleton i e.e_ty
|
||||
| Estruct(l) ->
|
||||
let i =
|
||||
List.fold_left
|
||||
(fun acc (_, e) -> max acc (itype (typing h e))) izero l in
|
||||
skeleton i e.e_ty
|
||||
| Earray(e_list) ->
|
||||
product (List.map (typing h) e_list)
|
||||
| Ereset_mem _ -> assert false
|
||||
|
||||
(** Typing an application *)
|
||||
and apply h op e_list =
|
||||
match op, e_list with
|
||||
| Epre(None), [e] ->
|
||||
initialized_exp h e;
|
||||
ione
|
||||
| Epre(Some _), [e] ->
|
||||
initialized_exp h e;
|
||||
izero
|
||||
| Efby, [e1;e2] ->
|
||||
initialized_exp h e2;
|
||||
itype (typing h e1)
|
||||
| Earrow, [e1;e2] ->
|
||||
let ty1 = typing h e1 in
|
||||
let _ = typing h e2 in
|
||||
itype ty1
|
||||
| Eifthenelse, [e1; e2; e3] ->
|
||||
let i1 = itype (typing h e1) in
|
||||
let i2 = itype (typing h e2) in
|
||||
let i3 = itype (typing h e3) in
|
||||
max i1 (max i2 i3)
|
||||
| (Enode(f,_) | Eevery(f,_)), e_list ->
|
||||
List.iter (fun e -> initialized_exp h e) e_list; izero
|
||||
| Eop(f,_), e_list when safe f ->
|
||||
(* unsafe primitives must have an initialized argument *)
|
||||
List.fold_left (fun acc e -> itype (typing h e)) izero e_list
|
||||
| Eop(f,_), e_list ->
|
||||
List.iter (fun e -> initialized_exp h e) e_list; izero
|
||||
(*Array operators*)
|
||||
| (Erepeat | Econcat | Eupdate _ | Efield_update _
|
||||
| Eselect _ | Eselect_dyn | Eselect_slice
|
||||
| Eiterator _ | Ecopy | Emake _ | Eflatten _), e_list ->
|
||||
List.iter (fun e -> initialized_exp h e) e_list; izero
|
||||
| _ -> assert false
|
||||
|
||||
and expect h e expected_ty =
|
||||
let actual_ty = typing h e in
|
||||
less_exp e actual_ty expected_ty
|
||||
|
||||
and initialized_exp h e = expect h e (skeleton izero e.e_ty)
|
||||
|
||||
let rec typing_pat h = function
|
||||
| Evarpat(x) -> let { i_typ = i } = Env.find x h in leaf i
|
||||
| Etuplepat(pat_list) ->
|
||||
product (List.map (typing_pat h) pat_list)
|
||||
|
||||
(** Typing equations *)
|
||||
let rec typing_eqs h eq_list = List.iter (typing_eq h) eq_list
|
||||
|
||||
and typing_eq h eq =
|
||||
match eq.eq_desc with
|
||||
| Eautomaton(handlers) -> typing_automaton h handlers
|
||||
| Eswitch(e, handlers) ->
|
||||
initialized_exp h e;
|
||||
typing_switch h handlers
|
||||
| Epresent(handlers, b) ->
|
||||
typing_present h handlers b
|
||||
| Ereset(eq_list, e) ->
|
||||
initialized_exp h e; typing_eqs h eq_list
|
||||
| Eeq(pat, e) ->
|
||||
let ty_pat = typing_pat h pat in
|
||||
expect h e ty_pat
|
||||
|
||||
and typing_switch h handlers =
|
||||
let handler { w_block = b } = ignore (typing_block h b) in
|
||||
List.iter handler handlers
|
||||
|
||||
and typing_present h handlers b =
|
||||
let handler { p_cond = e; p_block = b } =
|
||||
initialized_exp h e; ignore (typing_block h b) in
|
||||
List.iter handler handlers; ignore (typing_block h b)
|
||||
|
||||
and typing_automaton h state_handlers =
|
||||
(* we make a special treatment for state variables defined in the *)
|
||||
(* initial state *)
|
||||
let weak { s_unless = sunless } =
|
||||
match sunless with | [] -> true | _ -> false in
|
||||
|
||||
(* the set of variables which do have an initial value in the other states *)
|
||||
let initialized h { s_block = { b_defnames = l } } =
|
||||
Env.fold
|
||||
(fun elt _ h ->
|
||||
let { i_kind = k; i_typ = i } = Env.find elt h in
|
||||
match k with
|
||||
| Last _ ->
|
||||
let h = Env.remove elt h in
|
||||
Env.add elt { i_kind = Last(izero); i_typ = izero } h
|
||||
| _ -> h)
|
||||
l h in
|
||||
|
||||
(* typing the body of the automaton *)
|
||||
let handler h
|
||||
{ s_state = _; s_block = b; s_until = suntil; s_unless = sunless } =
|
||||
let escape h { e_cond = e } =
|
||||
initialized_exp h e in
|
||||
|
||||
(* typing the body *)
|
||||
let h = typing_block h b in
|
||||
List.iter (escape h) suntil;
|
||||
List.iter (escape h) sunless in
|
||||
|
||||
match state_handlers with
|
||||
(* we do a special treatment for state variables which *)
|
||||
(* are defined in the initial state if it cannot be immediately *)
|
||||
(* exited *)
|
||||
| initial :: other_handlers when weak initial ->
|
||||
let h = initialized h initial in
|
||||
handler h initial;
|
||||
List.iter (handler h) other_handlers
|
||||
| _ -> List.iter (handler h) state_handlers
|
||||
|
||||
and typing_block h { b_local = dec; b_equs = eq_list } =
|
||||
let h_extended = build h dec in
|
||||
typing_eqs h_extended eq_list;
|
||||
h_extended
|
||||
|
||||
(* build an typing environment of initialization types *)
|
||||
and build h dec =
|
||||
let kind = function
|
||||
| Heptagon.Var -> { i_kind = Var; i_typ = new_var () }
|
||||
| Heptagon.Last(Some _) -> { i_kind = Last(izero); i_typ = izero }
|
||||
| Heptagon.Last(None) -> { i_kind = Last(ione); i_typ = new_var () } in
|
||||
List.fold_left
|
||||
(fun h { v_name = n; v_last = last } -> Env.add n (kind last) h) h dec
|
||||
|
||||
let sbuild h dec =
|
||||
List.fold_left
|
||||
(fun h { v_name = n } -> Env.add n { i_kind = Var; i_typ = izero } h) h dec
|
||||
|
||||
let typing_contract h contract =
|
||||
match contract with
|
||||
| None -> h
|
||||
| Some { c_local = l_list; c_eq = eq_list; c_assume = e_a;
|
||||
c_enforce = e_g; c_controllables = c_list } ->
|
||||
let h = sbuild h c_list in
|
||||
let h' = build h l_list in
|
||||
typing_eqs h' eq_list;
|
||||
(* assumption *)
|
||||
expect h' e_a (skeleton izero e_a.e_ty);
|
||||
(* property *)
|
||||
expect h' e_g (skeleton izero e_g.e_ty);
|
||||
h
|
||||
|
||||
let typing_node { n_name = f; n_input = i_list; n_output = o_list;
|
||||
n_contract = contract;
|
||||
n_local = l_list; n_equs = eq_list } =
|
||||
let h = sbuild Env.empty i_list in
|
||||
let h = sbuild h o_list in
|
||||
let h = typing_contract h contract in
|
||||
|
||||
let h = build h l_list in
|
||||
typing_eqs h eq_list
|
||||
|
||||
let program ({ p_nodes = p_node_list } as p) =
|
||||
List.iter typing_node p_node_list;
|
||||
p
|
||||
|
||||
|
131
heptagon/analysis/interface.ml
Normal file
131
heptagon/analysis/interface.ml
Normal file
|
@ -0,0 +1,131 @@
|
|||
(**************************************************************************)
|
||||
(* *)
|
||||
(* Heptagon *)
|
||||
(* *)
|
||||
(* Author : Marc Pouzet *)
|
||||
(* Organization : Demons, LRI, University of Paris-Sud, Orsay *)
|
||||
(* *)
|
||||
(**************************************************************************)
|
||||
(* Read an interface *)
|
||||
|
||||
(* $Id$ *)
|
||||
|
||||
open Misc
|
||||
open Ident
|
||||
open Names
|
||||
open Linearity
|
||||
open Heptagon
|
||||
open Global
|
||||
open Modules
|
||||
open Typing
|
||||
|
||||
let rec split3 = function
|
||||
| [] -> [], [], []
|
||||
| (a,b,c)::l ->
|
||||
let a_list, b_list, c_list = split3 l in
|
||||
a::a_list, b::b_list, c::c_list
|
||||
|
||||
let rec combine3 l1 l2 l3 = match l1, l2, l3 with
|
||||
| [], [], [] -> []
|
||||
| a::a_list, b::b_list, c::c_list ->
|
||||
(a,b,c)::(combine3 a_list b_list c_list)
|
||||
|
||||
module Type =
|
||||
struct
|
||||
let sigtype { sig_name = name; sig_inputs = i_list; sig_outputs = o_list;
|
||||
sig_node = node; sig_safe = safe; sig_params = params } =
|
||||
let arg_dec_of_tuple (n, ty, l) =
|
||||
{ a_name = n;
|
||||
a_type = Tbase(check_type ty);
|
||||
a_linearity = l;
|
||||
a_pass_by_ref = false } in
|
||||
let i_inputs, t_inputs, l_inputs = split3 i_list in
|
||||
let o_outputs, t_outputs, l_outputs = split3 o_list in
|
||||
name, { inputs = List.map arg_dec_of_tuple i_list;
|
||||
outputs = List.map arg_dec_of_tuple o_list;
|
||||
contract = None;
|
||||
node = node;
|
||||
safe = safe;
|
||||
targeting = [];
|
||||
params = params;
|
||||
params_constraints = []; }
|
||||
|
||||
let read { interf_desc = desc; interf_loc = loc } =
|
||||
try
|
||||
match desc with
|
||||
| Iopen(n) -> open_module n
|
||||
| Itypedef(tydesc) -> deftype NamesEnv.empty tydesc
|
||||
| Isignature(s) ->
|
||||
let name, s = sigtype s in
|
||||
add_value name s
|
||||
with
|
||||
TypingError(error) -> message loc error
|
||||
|
||||
let main l =
|
||||
List.iter read l
|
||||
end
|
||||
|
||||
module Printer =
|
||||
struct
|
||||
open Format
|
||||
open Printer
|
||||
|
||||
let deftype ff name tdesc =
|
||||
match tdesc with
|
||||
| Tabstract -> fprintf ff "@[type %s@.@]" name
|
||||
| Tenum(tag_name_list) ->
|
||||
fprintf ff "@[<hov 2>type %s = " name;
|
||||
print_list ff print_name " |" tag_name_list;
|
||||
fprintf ff "@.@]"
|
||||
| Tstruct(f_ty_list) ->
|
||||
fprintf ff "@[<hov 2>type %s = " name;
|
||||
fprintf ff "@[<hov 1>{";
|
||||
print_list ff
|
||||
(fun ff (field, ty) -> print_name ff field;
|
||||
fprintf ff ": ";
|
||||
print_base_type ff ty) ";" f_ty_list;
|
||||
fprintf ff "}@]@.@]"
|
||||
|
||||
let signature ff name { inputs = inputs;
|
||||
outputs = outputs;
|
||||
contract = contract; node = node;
|
||||
safe = safe; params = params; params_constraints = constr } =
|
||||
let print ff arg =
|
||||
match arg.a_name with
|
||||
| None -> print_type ff arg.a_type
|
||||
| Some(name) ->
|
||||
print_name ff name; fprintf ff ":"; print_type ff arg.a_type;
|
||||
fprintf ff " "; print_lin ff arg.a_linearity in
|
||||
|
||||
let print_node_params ff = function
|
||||
| [] -> ()
|
||||
| l ->
|
||||
fprintf ff "<<";
|
||||
print_list ff print_name "," l;
|
||||
fprintf ff ">>" in
|
||||
|
||||
fprintf ff "@[<v 2>val ";
|
||||
if safe then fprintf ff "safe ";
|
||||
if node then fprintf ff "node " else fprintf ff "fun ";
|
||||
print_name ff name;
|
||||
print_node_params ff params;
|
||||
fprintf ff "(@[";
|
||||
print_list ff print ";" inputs;
|
||||
fprintf ff "@]) returns (@[";
|
||||
print_list ff print ";" outputs;
|
||||
fprintf ff "@])";
|
||||
(match constr with
|
||||
| [] -> ()
|
||||
| constr ->
|
||||
fprintf ff "\n with: @[";
|
||||
print_list ff Static.print_size_constr "," constr;
|
||||
fprintf ff "@]"
|
||||
);
|
||||
optunit (print_contract ff) contract;
|
||||
fprintf ff "@.@]"
|
||||
|
||||
let print oc =
|
||||
let ff = formatter_of_out_channel oc in
|
||||
NamesEnv.iter (fun key typdesc -> deftype ff key typdesc) current.types;
|
||||
NamesEnv.iter (fun key sigtype -> signature ff key sigtype) current.values;
|
||||
end
|
932
heptagon/analysis/typing.ml
Normal file
932
heptagon/analysis/typing.ml
Normal file
|
@ -0,0 +1,932 @@
|
|||
(**************************************************************************)
|
||||
(* *)
|
||||
(* Heptagon *)
|
||||
(* *)
|
||||
(* Author : Marc Pouzet *)
|
||||
(* Organization : Demons, LRI, University of Paris-Sud, Orsay *)
|
||||
(* *)
|
||||
(**************************************************************************)
|
||||
(* type checking *)
|
||||
|
||||
(* $Id$ *)
|
||||
|
||||
open Misc
|
||||
open Names
|
||||
open Ident
|
||||
open Location
|
||||
open Heptagon
|
||||
open Global
|
||||
open Modules
|
||||
open Initial
|
||||
open Static
|
||||
|
||||
type value = { ty: ty; mutable last: bool }
|
||||
|
||||
type error =
|
||||
| Emissing of name
|
||||
| Emissingcase of name
|
||||
| Eundefined of name
|
||||
| Elast_undefined of name
|
||||
| Eshould_be_last of name
|
||||
| Etype_clash of ty * ty
|
||||
| Earity_clash of int * int
|
||||
| Ealready_defined of name
|
||||
| Eshould_be_a_node of longname
|
||||
| Enon_exaustive
|
||||
| Estate_clash
|
||||
| Epartial_switch of name
|
||||
| Etwo_many_outputs
|
||||
| Esome_fields_are_missing
|
||||
| Esubscripted_value_not_an_array of ty
|
||||
| Earray_subscript_should_be_const
|
||||
| Eundefined_const of name
|
||||
| Econstraint_solve_failed of size_constr
|
||||
| Etype_should_be_static of ty
|
||||
|
||||
exception Unify
|
||||
exception TypingError of error
|
||||
|
||||
let error kind = raise (TypingError(kind))
|
||||
|
||||
let message loc kind =
|
||||
begin match kind with
|
||||
| Emissing(s) ->
|
||||
Printf.eprintf "%aNo equation is given for name %s.\n"
|
||||
output_location loc
|
||||
s;
|
||||
| Emissingcase(s) ->
|
||||
Printf.eprintf "%aCase %s not defined.\n"
|
||||
output_location loc
|
||||
s;
|
||||
| Eundefined(s) ->
|
||||
Printf.eprintf "%aThe name %s is unbound.\n"
|
||||
output_location loc
|
||||
s;
|
||||
| Elast_undefined(s) ->
|
||||
Printf.eprintf "%aThe name %s does not have a last value.\n"
|
||||
output_location loc
|
||||
s;
|
||||
| Eshould_be_last(s) ->
|
||||
Printf.eprintf "%aOnly the last value of %s can be accessed.\n"
|
||||
output_location loc
|
||||
s;
|
||||
| Etype_clash(actual_ty, expected_ty) ->
|
||||
Printf.eprintf "%aType Clash: this expression has type %a, \n\
|
||||
but is expected to have type %a.\n"
|
||||
output_location loc
|
||||
Printer.ptype actual_ty
|
||||
Printer.ptype expected_ty
|
||||
| Earity_clash(actual_arit, expected_arit) ->
|
||||
Printf.eprintf "%aType Clash: this expression expects %d arguments,\n\
|
||||
but is expected to have %d.\n"
|
||||
output_location loc
|
||||
expected_arit actual_arit
|
||||
| Ealready_defined(s) ->
|
||||
Printf.eprintf "%aThe name %s is already defined.\n"
|
||||
output_location loc
|
||||
s
|
||||
| Enon_exaustive ->
|
||||
Printf.eprintf "%aSome constructors are missing in this \
|
||||
pattern/matching.\n"
|
||||
output_location loc
|
||||
| Eshould_be_a_node(s) ->
|
||||
Printf.eprintf "%a%s should be a combinatorial function.\n"
|
||||
output_location loc
|
||||
(fullname s)
|
||||
| Estate_clash ->
|
||||
Printf.eprintf
|
||||
"%aOnly stateless expressions should appear in a function.\n"
|
||||
output_location loc
|
||||
| Epartial_switch(s) ->
|
||||
Printf.eprintf
|
||||
"%aThe case %s is missing.\n"
|
||||
output_location loc
|
||||
s
|
||||
| Etwo_many_outputs ->
|
||||
Printf.eprintf
|
||||
"%aA function may only returns a basic value.\n"
|
||||
output_location loc
|
||||
| Esome_fields_are_missing ->
|
||||
Printf.eprintf
|
||||
"%aSome fields are missing.\n"
|
||||
output_location loc
|
||||
| Esubscripted_value_not_an_array ty ->
|
||||
Printf.eprintf
|
||||
"%aSubscript used on a non array type : %a.\n"
|
||||
output_location loc
|
||||
Printer.ptype ty
|
||||
| Earray_subscript_should_be_const ->
|
||||
Printf.eprintf
|
||||
"%aSubscript has to be a static value.\n"
|
||||
output_location loc
|
||||
| Eundefined_const id ->
|
||||
Printf.eprintf
|
||||
"%aThe const name '%s' is unbound.\n"
|
||||
output_location loc
|
||||
id
|
||||
| Econstraint_solve_failed c ->
|
||||
Printf.eprintf
|
||||
"%aThe following constraint cannot be satisified:\n %a.\n"
|
||||
output_location loc
|
||||
psize_constr c
|
||||
| Etype_should_be_static ty ->
|
||||
Printf.eprintf
|
||||
"%aThis type should be static : %a.\n"
|
||||
output_location loc
|
||||
Printer.ptype ty
|
||||
end;
|
||||
raise Error
|
||||
|
||||
let add_value f signature =
|
||||
try add_value f signature with Already_defined -> error (Ealready_defined f)
|
||||
let add_type f typ_desc =
|
||||
try add_type f typ_desc with Already_defined -> error (Ealready_defined f)
|
||||
let add_constr f ty_res =
|
||||
try add_constr f ty_res with Already_defined -> error (Ealready_defined f)
|
||||
let add_field f ty_arg ty_res =
|
||||
try add_field f ty_arg ty_res
|
||||
with Already_defined -> error (Ealready_defined f)
|
||||
|
||||
let find_value f =
|
||||
try find_value f with Not_found -> error (Eundefined(fullname f))
|
||||
let find_type f =
|
||||
try find_type f with Not_found -> error (Eundefined(fullname f))
|
||||
let find_constr c =
|
||||
try find_constr c with Not_found -> error (Eundefined(fullname c))
|
||||
let find_field c =
|
||||
try find_field c with Not_found -> error (Eundefined(fullname c))
|
||||
|
||||
let (curr_size_constr : size_constr list ref) = ref []
|
||||
let add_size_constr c =
|
||||
curr_size_constr := c::(!curr_size_constr)
|
||||
let get_size_constr () =
|
||||
let l = !curr_size_constr in
|
||||
curr_size_constr := [];
|
||||
l
|
||||
|
||||
let get_number_of_fields ty =
|
||||
let { info = tydesc } =
|
||||
match ty with
|
||||
| Tid(f) -> find_type f
|
||||
| _ -> assert false in
|
||||
match tydesc with
|
||||
| Tstruct l -> List.length l
|
||||
| _ -> assert false
|
||||
|
||||
let element_type ty =
|
||||
match ty with
|
||||
| Tbase (Tarray (ty, _)) -> Tbase ty
|
||||
| _ -> error (Esubscripted_value_not_an_array ty)
|
||||
|
||||
let size_exp ty =
|
||||
match ty with
|
||||
| Tbase (Tarray (_, e)) -> e
|
||||
| _ -> error (Esubscripted_value_not_an_array ty)
|
||||
|
||||
let rec unify t1 t2 =
|
||||
match t1, t2 with
|
||||
| Tprod(t1_list), Tprod(t2_list) ->
|
||||
begin
|
||||
try List.iter2 unify t1_list t2_list with _ -> raise Unify
|
||||
end
|
||||
| Tbase(b1), Tbase(b2) when b1 = b2 -> ()
|
||||
| Tbase(Tbool), Tbase(Tid name_bool)
|
||||
| Tbase(Tid name_bool), Tbase(Tbool)
|
||||
when name_bool = pbool -> ()
|
||||
| Tbase(Tint), Tbase(Tid name_int)
|
||||
| Tbase(Tid name_int), Tbase(Tint)
|
||||
when name_int = pint -> ()
|
||||
| Tbase(Tfloat), Tbase(Tid name_float)
|
||||
| Tbase(Tid name_float), Tbase(Tfloat)
|
||||
when name_float = pfloat -> ()
|
||||
| Tbase(Tarray (ty1, e1)), Tbase(Tarray (ty2, e2)) ->
|
||||
add_size_constr (Equal(e1,e2));
|
||||
unify (Tbase ty1) (Tbase ty2)
|
||||
| _ -> raise Unify
|
||||
|
||||
let unify t1 t2 =
|
||||
try unify t1 t2 with Unify -> error (Etype_clash(t1, t2))
|
||||
|
||||
let less_than statefull = if not statefull then error Estate_clash
|
||||
|
||||
let kind f statefull = function
|
||||
| { inputs = ty_list1;
|
||||
outputs = ty_list2;
|
||||
node = n } ->
|
||||
let ty_of_arg_dec v = v.a_type in
|
||||
if n & not(statefull) then error (Eshould_be_a_node(f))
|
||||
else n, List.map ty_of_arg_dec ty_list1, List.map ty_of_arg_dec ty_list2
|
||||
|
||||
let prod = function
|
||||
| [] -> assert false
|
||||
| [ty] -> ty
|
||||
| ty_list -> Tprod(ty_list)
|
||||
|
||||
let rec typing_const c =
|
||||
let typed_c, base_ty = match c with
|
||||
| Cint _ -> c, Tid(pint)
|
||||
| Cfloat _ -> c, Tid(pfloat)
|
||||
| Cconstr(c) ->
|
||||
let { qualid = q; info = base_ty } = find_constr c in
|
||||
Cconstr(Modname(q)), base_ty
|
||||
| Cconst_array(n, c) ->
|
||||
let c, ty = typing_const c in
|
||||
Cconst_array(n,c), Tarray(base_type ty, n)
|
||||
in
|
||||
typed_c, Tbase(base_ty)
|
||||
|
||||
let typ_of_name h x =
|
||||
try
|
||||
let { ty = ty } = Env.find x h in ty
|
||||
with
|
||||
Not_found -> error (Eundefined(sourcename x))
|
||||
|
||||
let typ_of_varname h x =
|
||||
try
|
||||
let { ty = ty;last = last } = Env.find x h in
|
||||
(* Don't understand that - GD 15/02/2009 *)
|
||||
(* if last then error (Eshould_be_last(x)); *)
|
||||
ty
|
||||
with
|
||||
Not_found -> error (Eundefined(sourcename x))
|
||||
|
||||
let typ_of_last h x =
|
||||
try
|
||||
let { ty = ty; last = last } = Env.find x h in
|
||||
if not last then error (Elast_undefined(sourcename x));
|
||||
(* v.last <- true;*)
|
||||
ty
|
||||
with
|
||||
Not_found -> error (Eundefined(sourcename x))
|
||||
|
||||
let desc_of_ty = function
|
||||
| Tbase(Tid(ty_name)) ->
|
||||
let { info = tydesc } = find_type ty_name in tydesc
|
||||
| Tbase(Tbool) -> Tenum ["true";"false"]
|
||||
| _ -> Tabstract
|
||||
let set_of_constr = function
|
||||
| Tabstract | Tstruct _ -> assert false
|
||||
| Tenum(tag_list) -> List.fold_right S.add tag_list S.empty
|
||||
|
||||
let name_mem n env =
|
||||
let check_one id _ acc =
|
||||
((name id) = n) or acc
|
||||
in
|
||||
Env.fold check_one env false
|
||||
|
||||
(* [check_type t] checks that t exists *)
|
||||
let rec check_type = function
|
||||
| Tint | Tfloat | Tbool as t -> t
|
||||
| Tarray(ty, e) ->
|
||||
Tarray(check_type ty, e)
|
||||
| Tid(ty_name) ->
|
||||
try Tid(Modname((find_type ty_name).qualid))
|
||||
with Not_found -> error (Eundefined(fullname ty_name))
|
||||
|
||||
let rec simplify_type const_env = function
|
||||
| Tint | Tfloat | Tbool | Tid _ as t -> t
|
||||
| Tarray(ty, e) ->
|
||||
Tarray(simplify_type const_env ty, simplify const_env e)
|
||||
|
||||
let simplify_type loc const_env ty =
|
||||
try
|
||||
simplify_type const_env ty
|
||||
with
|
||||
Instanciation_failed -> message loc (Etype_should_be_static (Tbase ty))
|
||||
|
||||
let rec subst_base_type_vars m = function
|
||||
| Tarray(ty, e) -> Tarray(subst_base_type_vars m ty, size_exp_subst m e)
|
||||
| t -> t
|
||||
|
||||
let rec subst_type_vars m = function
|
||||
| Tbase ty -> Tbase (subst_base_type_vars m ty)
|
||||
| Tprod l -> Tprod (List.map (subst_type_vars m) l)
|
||||
|
||||
let equal expected_tag_list actual_tag_list =
|
||||
if not (List.for_all
|
||||
(fun tag -> List.mem tag actual_tag_list) expected_tag_list)
|
||||
then error Enon_exaustive
|
||||
|
||||
(* add two sets of names provided they are distinct *)
|
||||
let add env1 env2 =
|
||||
Env.fold
|
||||
(fun elt ty env ->
|
||||
if not (Env.mem elt env)
|
||||
then Env.add elt ty env
|
||||
else error (Ealready_defined(sourcename elt))) env1 env2
|
||||
|
||||
(* checks that constructors are included in constructor list from type
|
||||
def and returns the difference *)
|
||||
let included_const s1 s2 =
|
||||
S.iter
|
||||
(fun elt -> if not (S.mem elt s2) then error (Emissingcase(elt)))
|
||||
s1
|
||||
|
||||
let diff_const defined_names local_names =
|
||||
included_const local_names defined_names;
|
||||
S.diff defined_names local_names
|
||||
|
||||
(* checks that local_names are included in defined_names and returns *)
|
||||
(* the difference *)
|
||||
let included_env s1 s2 =
|
||||
Env.iter
|
||||
(fun elt _ -> if not (Env.mem elt s2) then error (Emissing(sourcename elt)))
|
||||
s1
|
||||
|
||||
let diff_env defined_names local_names =
|
||||
included_env local_names defined_names;
|
||||
Env.diff defined_names local_names
|
||||
|
||||
(* [merge [set1;...;setn]] returns a set of names defined in every seti *)
|
||||
(* and only partially defined names *)
|
||||
let rec merge local_names_list =
|
||||
let two s1 s2 =
|
||||
let total, partial = Env.partition (fun elt -> Env.mem elt s2) s1 in
|
||||
let partial =
|
||||
Env.fold (fun elt ty env ->
|
||||
if not (Env.mem elt total) then Env.add elt ty env
|
||||
else env)
|
||||
s2 partial in
|
||||
total, partial in
|
||||
match local_names_list with
|
||||
| [] -> Env.empty, Env.empty
|
||||
| [s] -> s, Env.empty
|
||||
| s :: local_names_list ->
|
||||
let total, partial1 = merge local_names_list in
|
||||
let total, partial2 = two s total in
|
||||
total, Env.union partial1 partial2
|
||||
|
||||
(* checks that every partial name has a last value *)
|
||||
let all_last h env =
|
||||
Env.iter
|
||||
(fun elt _ ->
|
||||
if not (Env.find elt h).last then error (Elast_undefined(sourcename elt)))
|
||||
env
|
||||
|
||||
let last = function | Var -> false | Last _ -> true
|
||||
|
||||
let rec typing statefull h e =
|
||||
try
|
||||
let typed_desc,ty = match e.e_desc with
|
||||
| Econst(c) ->
|
||||
let typed_c, ty = typing_const c in
|
||||
Econst(c),
|
||||
ty
|
||||
| Econstvar(x) -> Econstvar x, Tbase Tint
|
||||
| Evar(x) ->
|
||||
Evar(x),
|
||||
typ_of_varname h x
|
||||
| Elast(x) ->
|
||||
Elast(x),
|
||||
typ_of_last h x
|
||||
| Etuple(e_list) ->
|
||||
let typed_e_list,ty_list =
|
||||
List.split (List.map (typing statefull h) e_list) in
|
||||
Etuple(typed_e_list),
|
||||
Tprod(ty_list)
|
||||
| Eapp({ a_op = op } as app, e_list ) ->
|
||||
let ty, op, typed_e_list = typing_app statefull h op e_list in
|
||||
Eapp({ app with a_op = op }, typed_e_list),
|
||||
ty
|
||||
| Efield(e, field) ->
|
||||
let { qualid = q;
|
||||
info = { arg = ty_arg; res = ty_res } } = find_field field in
|
||||
let typed_e = expect statefull h (Tbase(ty_arg)) e in
|
||||
Efield(typed_e, Modname(q)),
|
||||
Tbase(ty_res)
|
||||
| Estruct(l) ->
|
||||
let { qualid = q;
|
||||
info = { arg = ty_arg } } = find_field (fst (List.hd l)) in
|
||||
let size = get_number_of_fields ty_arg in
|
||||
let rec fieldrec acc_l acc = function
|
||||
| [] ->
|
||||
List.rev acc_l,
|
||||
Tbase(ty_arg)
|
||||
| (field, e) :: l ->
|
||||
if S.mem (shortname field) acc
|
||||
then error (Ealready_defined(fullname field));
|
||||
let { qualid = q;
|
||||
info = { arg = ty; res = ty_res } } = find_field field in
|
||||
let typed_e = expect statefull h (Tbase(ty_res)) e in
|
||||
unify (Tbase(ty)) (Tbase(ty_arg));
|
||||
fieldrec
|
||||
((Modname(q),typed_e)::acc_l)
|
||||
(S.add (shortname field) acc)
|
||||
l in
|
||||
let typed_l, ty = fieldrec [] S.empty l in
|
||||
(* check that no field is missing *)
|
||||
if List.length l <> size then error Esome_fields_are_missing;
|
||||
Estruct(typed_l),
|
||||
ty
|
||||
| Earray (exp::e_list) ->
|
||||
let typed_exp, t1 = typing statefull h exp in
|
||||
let typed_e_list = List.map (expect statefull h t1) e_list in
|
||||
Earray(typed_exp::typed_e_list),
|
||||
const_array_of t1 (List.length e_list + 1)
|
||||
| Earray [] ->
|
||||
error (Earity_clash (0, 1))
|
||||
| Ereset_mem _ -> assert false
|
||||
in
|
||||
{ e with
|
||||
e_desc = typed_desc;
|
||||
e_ty = ty; },
|
||||
ty
|
||||
with
|
||||
TypingError(kind) -> message e.e_loc kind
|
||||
|
||||
and expect statefull h expected_ty e =
|
||||
let typed_e, actual_ty = typing statefull h e in
|
||||
try
|
||||
unify actual_ty expected_ty;
|
||||
typed_e
|
||||
with TypingError(kind) -> message e.e_loc kind
|
||||
|
||||
and typing_app statefull h op e_list =
|
||||
match op, e_list with
|
||||
| Epre(None), [e] ->
|
||||
less_than statefull;
|
||||
let typed_e,ty = typing statefull h e in
|
||||
ty,op,[typed_e]
|
||||
| Epre(Some(c)), [e] ->
|
||||
less_than statefull;
|
||||
let typed_c, t1 = typing_const c in
|
||||
let typed_e = expect statefull h t1 e in
|
||||
t1, Epre(Some(typed_c)), [typed_e]
|
||||
| (Efby | Earrow), [e1;e2] ->
|
||||
less_than statefull;
|
||||
let typed_e1, t1 = typing statefull h e1 in
|
||||
let typed_e2 = expect statefull h t1 e2 in
|
||||
t1, op, [typed_e1;typed_e2]
|
||||
| Eifthenelse, [e1;e2;e3] ->
|
||||
let typed_e1 = expect statefull h (Tbase tbool) e1 in
|
||||
let typed_e2, t1 = typing statefull h e2 in
|
||||
let typed_e3 = expect statefull h t1 e3 in
|
||||
t1, op, [typed_e1; typed_e2; typed_e3]
|
||||
| (Enode(f, params) | Eevery(f, params) | Eop(f, params)), e_list ->
|
||||
let { qualid = q; info = ty_desc } = find_value f in
|
||||
let k, expected_ty_list, result_ty_list = kind f statefull ty_desc in
|
||||
let m = List.combine ty_desc.params params in
|
||||
let expected_ty_list = List.map (subst_type_vars m) expected_ty_list in
|
||||
let typed_e_list = typing_args statefull h expected_ty_list e_list in
|
||||
let size_constrs = instanciate_constr m ty_desc.params_constraints in
|
||||
let result_ty_list = List.map (subst_type_vars m) result_ty_list in
|
||||
List.iter add_size_constr size_constrs;
|
||||
let f = Modname(q) in
|
||||
(prod result_ty_list,
|
||||
(if k then Enode(f, params) else Eop(f, params)),
|
||||
typed_e_list)
|
||||
(*Array operators*)
|
||||
| Erepeat, [e1; e2] ->
|
||||
let typed_e2 = expect statefull h (Tbase(Tint)) e2 in
|
||||
let e2 = size_exp_of_exp e2 in
|
||||
let typed_e1, t1 = typing statefull h e1 in
|
||||
add_size_constr (LEqual (SConst 1, e2));
|
||||
array_of t1 e2, op, [typed_e1; typed_e2]
|
||||
| Eselect idx_list, [e1] ->
|
||||
let typed_e1, t1 = typing statefull h e1 in
|
||||
typing_array_subscript statefull h idx_list t1, op, [typed_e1]
|
||||
| Eselect_dyn, e1::defe::idx_list ->
|
||||
let typed_e1, t1 = typing statefull h e1 in
|
||||
let typed_defe = expect statefull h (element_type t1) defe in
|
||||
let ty, typed_idx_list = typing_array_subscript_dyn statefull h idx_list t1 in
|
||||
ty, op, typed_e1::typed_defe::typed_idx_list
|
||||
| Eupdate idx_list, [e1;e2] ->
|
||||
let typed_e1, t1 = typing statefull h e1 in
|
||||
let base_ty = typing_array_subscript statefull h idx_list t1 in
|
||||
let typed_e2 = expect statefull h base_ty e2 in
|
||||
t1, op, [typed_e1; typed_e2]
|
||||
| Eselect_slice, [e; idx1; idx2] ->
|
||||
let typed_idx1 = expect statefull h (Tbase(Tint)) idx1 in
|
||||
let typed_idx2 = expect statefull h (Tbase(Tint)) idx2 in
|
||||
let typed_e, t1 = typing statefull h e in
|
||||
(*Create the expression to compute the size of the array *)
|
||||
let e1 = SOp (SMinus, size_exp_of_exp idx2, size_exp_of_exp idx1) in
|
||||
let e2 = SOp (SPlus, e1, SConst 1) in
|
||||
add_size_constr (LEqual (SConst 1, e2));
|
||||
array_of (element_type t1) e2, op, [typed_e; typed_idx1; typed_idx2]
|
||||
| Econcat, [e1; e2] ->
|
||||
let typed_e1, t1 = typing statefull h e1 in
|
||||
let typed_e2, t2 = typing statefull h e2 in
|
||||
begin try
|
||||
unify (element_type t1) (element_type t2)
|
||||
with
|
||||
TypingError(kind) -> message e1.e_loc kind
|
||||
end;
|
||||
let n = SOp (SPlus, size_exp t1, size_exp t2) in
|
||||
array_of (element_type t1) n, op, [typed_e1; typed_e2]
|
||||
| Eiterator (it, f, params, reset), e::e_list ->
|
||||
let { qualid = q; info = ty_desc } = find_value f in
|
||||
let f = Modname(q) in
|
||||
let _, expected_ty_list, result_ty_list = kind f statefull ty_desc in
|
||||
let m = List.combine ty_desc.params params in
|
||||
let expected_ty_list = List.map (subst_type_vars m) expected_ty_list in
|
||||
let size_constrs = instanciate_constr m ty_desc.params_constraints in
|
||||
let result_ty_list = List.map (subst_type_vars m) result_ty_list in
|
||||
let typed_e = expect statefull h (Tbase Tint) e in
|
||||
let e = size_exp_of_exp e in
|
||||
let ty, typed_e_list = typing_iterator statefull h it e
|
||||
expected_ty_list result_ty_list e_list in
|
||||
add_size_constr (LEqual (SConst 1, e));
|
||||
List.iter add_size_constr size_constrs;
|
||||
ty, Eiterator(it, f, params, reset), typed_e::typed_e_list
|
||||
| Ecopy, [e] ->
|
||||
let typed_e, ty = typing statefull h e in
|
||||
ty, op, [typed_e]
|
||||
| Efield_update field, [e1; e2] ->
|
||||
let { qualid = q;
|
||||
info = { arg = ty_arg; res = ty_res } } = find_field field in
|
||||
let typed_e1 = expect statefull h (Tbase(ty_arg)) e1 in
|
||||
let typed_e2 = expect statefull h (Tbase(ty_res)) e2 in
|
||||
Tbase(ty_arg), op, [typed_e1; typed_e2]
|
||||
| Eflatten n, [e] ->
|
||||
let { qualid = q;
|
||||
info = { fields = fields } } = find_struct n in
|
||||
let typed_e = expect statefull h (Tbase(Tid (Modname q))) e in
|
||||
prod (List.map (fun (_, ty) -> Tbase (check_type ty)) fields), op, [typed_e]
|
||||
| Emake n, e_list ->
|
||||
let { qualid = q;
|
||||
info = { fields = fields } } = find_struct n in
|
||||
if List.length e_list <> List.length fields then
|
||||
error (Earity_clash(List.length e_list, List.length fields));
|
||||
let typed_e_list = List.map2
|
||||
(fun e (_,ty) -> expect statefull h (Tbase (check_type ty)) e)
|
||||
e_list fields in
|
||||
Tbase (Tid (Modname q)), op, typed_e_list
|
||||
(*Arity problems*)
|
||||
| Epre _, _ ->
|
||||
error (Earity_clash(List.length e_list, 1))
|
||||
| (Efby | Earrow), _ ->
|
||||
error (Earity_clash(List.length e_list, 2))
|
||||
| Eifthenelse, _ ->
|
||||
error (Earity_clash(List.length e_list, 2))
|
||||
| Eiterator _, _ ->
|
||||
error (Earity_clash(List.length e_list, 1))
|
||||
| Econcat, _ ->
|
||||
error (Earity_clash(List.length e_list, 2))
|
||||
| Eselect_slice, _ ->
|
||||
error (Earity_clash(List.length e_list, 3))
|
||||
| Eupdate _, _ ->
|
||||
error (Earity_clash(List.length e_list, 2))
|
||||
| Eselect _, _ ->
|
||||
error (Earity_clash(List.length e_list, 1))
|
||||
| Eselect_dyn, _ ->
|
||||
error (Earity_clash(List.length e_list, 2))
|
||||
| Erepeat _, _ ->
|
||||
error (Earity_clash(List.length e_list, 2))
|
||||
| Ecopy, _ ->
|
||||
error (Earity_clash(List.length e_list, 1))
|
||||
| Efield_update field, _ ->
|
||||
error (Earity_clash(List.length e_list, 2))
|
||||
|
||||
and typing_iterator statefull h it n args_ty_list result_ty_list e_list =
|
||||
match it with
|
||||
| Imap ->
|
||||
let args_ty_list = List.map (fun ty -> array_of ty n) args_ty_list in
|
||||
let result_ty_list = List.map (fun ty -> array_of ty n) result_ty_list in
|
||||
let typed_e_list = typing_args statefull h args_ty_list e_list in
|
||||
prod result_ty_list, typed_e_list
|
||||
| Ifold ->
|
||||
let args_ty_list = incomplete_map (fun ty -> array_of ty n) args_ty_list in
|
||||
let typed_e_list = typing_args statefull h args_ty_list e_list in
|
||||
(*check accumulator type matches in input and output*)
|
||||
if List.length result_ty_list > 1 then
|
||||
error (Etwo_many_outputs);
|
||||
begin try
|
||||
unify (last_element args_ty_list) (List.hd result_ty_list)
|
||||
with
|
||||
TypingError(kind) -> message (List.hd e_list).e_loc kind
|
||||
end;
|
||||
(List.hd result_ty_list), typed_e_list
|
||||
| Imapfold ->
|
||||
let args_ty_list = incomplete_map (fun ty -> array_of ty n) args_ty_list in
|
||||
let result_ty_list = incomplete_map (fun ty -> array_of ty n) result_ty_list in
|
||||
let typed_e_list = typing_args statefull h args_ty_list e_list in
|
||||
(*check accumulator type matches in input and output*)
|
||||
begin try
|
||||
unify (last_element args_ty_list) (last_element result_ty_list)
|
||||
with
|
||||
TypingError(kind) -> message (List.hd e_list).e_loc kind
|
||||
end;
|
||||
prod result_ty_list, typed_e_list
|
||||
|
||||
and typing_array_subscript statefull h idx_list ty =
|
||||
match ty, idx_list with
|
||||
| ty, [] -> ty
|
||||
| Tbase(Tarray(base_ty, exp)), idx::idx_list ->
|
||||
add_size_constr (LEqual (SConst 0, idx));
|
||||
add_size_constr (LEqual (idx, SOp(SMinus, exp, SConst 1)));
|
||||
typing_array_subscript statefull h idx_list (Tbase base_ty)
|
||||
| _, _ -> error (Esubscripted_value_not_an_array ty)
|
||||
|
||||
(* This function checks that the array dimensions matches
|
||||
the subscript. It returns the base type wrt the nb of indices. *)
|
||||
and typing_array_subscript_dyn statefull h idx_list ty =
|
||||
match ty, idx_list with
|
||||
| ty, [] -> ty, []
|
||||
| Tbase(Tarray(base_ty, exp)), idx::idx_list ->
|
||||
let typed_idx = expect statefull h (Tbase(Tint)) idx in
|
||||
let ty, typed_idx_list =
|
||||
typing_array_subscript_dyn statefull h idx_list (Tbase base_ty) in
|
||||
ty, typed_idx::typed_idx_list
|
||||
| _, _ -> error (Esubscripted_value_not_an_array ty)
|
||||
|
||||
and typing_args statefull h expected_ty_list e_list =
|
||||
try
|
||||
List.map2 (expect statefull h) expected_ty_list e_list
|
||||
with Invalid_argument _ ->
|
||||
error (Earity_clash(List.length e_list, List.length expected_ty_list))
|
||||
|
||||
let rec typing_pat h acc = function
|
||||
| Evarpat(x) ->
|
||||
let ty = typ_of_name h x in
|
||||
let acc =
|
||||
if Env.mem x acc
|
||||
then error (Ealready_defined (sourcename x))
|
||||
else Env.add x ty acc in
|
||||
acc, ty
|
||||
| Etuplepat(pat_list) ->
|
||||
let acc, ty_list =
|
||||
List.fold_right
|
||||
(fun pat (acc, ty_list) ->
|
||||
let acc, ty = typing_pat h acc pat in acc, ty :: ty_list)
|
||||
pat_list (acc, []) in
|
||||
acc, Tprod(ty_list)
|
||||
|
||||
let rec typing_eq statefull h acc eq =
|
||||
let typed_desc,acc = match eq.eq_desc with
|
||||
| Eautomaton(state_handlers) ->
|
||||
let typed_sh,acc =
|
||||
typing_automaton_handlers statefull h acc state_handlers in
|
||||
Eautomaton(typed_sh),
|
||||
acc
|
||||
| Eswitch(e, switch_handlers) ->
|
||||
let typed_e,ty = typing statefull h e in
|
||||
let typed_sh,acc =
|
||||
typing_switch_handlers statefull h acc ty switch_handlers in
|
||||
Eswitch(typed_e,typed_sh),
|
||||
acc
|
||||
| Epresent(present_handlers, b) ->
|
||||
let typed_b, def_names, _ = typing_block statefull h b in
|
||||
let typed_ph, acc =
|
||||
typing_present_handlers statefull h acc def_names present_handlers in
|
||||
Epresent(typed_ph,typed_b),
|
||||
acc
|
||||
| Ereset(eq_list, e) ->
|
||||
let typed_e = expect statefull h (Tbase(tbool)) e in
|
||||
let typed_eq_list, acc = typing_eq_list statefull h acc eq_list in
|
||||
Ereset(typed_eq_list,typed_e),
|
||||
acc
|
||||
| Eeq(pat, e) ->
|
||||
let acc, ty_pat = typing_pat h acc pat in
|
||||
let typed_e = expect statefull h ty_pat e in
|
||||
Eeq(pat, typed_e),
|
||||
acc in
|
||||
{ eq with
|
||||
eq_statefull = statefull;
|
||||
eq_desc = typed_desc },
|
||||
acc
|
||||
|
||||
and typing_eq_list statefull h acc eq_list =
|
||||
let rev_typed_eq_list,acc =
|
||||
List.fold_left
|
||||
(fun (rev_eq_list,acc) eq ->
|
||||
let typed_eq, acc = typing_eq statefull h acc eq in
|
||||
(typed_eq::rev_eq_list),acc
|
||||
)
|
||||
([],acc)
|
||||
eq_list in
|
||||
((List.rev rev_typed_eq_list),
|
||||
acc)
|
||||
|
||||
and typing_automaton_handlers statefull h acc state_handlers =
|
||||
(* checks unicity of states *)
|
||||
let addname acc { s_state = n } =
|
||||
if S.mem n acc then error (Ealready_defined(n)) else S.add n acc in
|
||||
let states = List.fold_left addname S.empty state_handlers in
|
||||
|
||||
let escape statefull h ({ e_cond = e; e_next_state = n } as esc) =
|
||||
if not (S.mem n states) then error (Eundefined(n));
|
||||
let typed_e = expect statefull h (Tbase(tbool)) e in
|
||||
{ esc with e_cond = typed_e } in
|
||||
|
||||
let handler
|
||||
({ s_state = n; s_block = b; s_until = e_list1; s_unless = e_list2 } as s) =
|
||||
let typed_b, defined_names, h0 = typing_block statefull h b in
|
||||
let typed_e_list1 = List.map (escape statefull h0) e_list1 in
|
||||
let typed_e_list2 = List.map (escape false h) e_list2 in
|
||||
{ s with
|
||||
s_block = typed_b;
|
||||
s_until = typed_e_list1;
|
||||
s_unless = typed_e_list2 },
|
||||
defined_names in
|
||||
|
||||
let typed_handlers,defined_names_list =
|
||||
List.split (List.map handler state_handlers) in
|
||||
let total, partial = merge defined_names_list in
|
||||
all_last h partial;
|
||||
typed_handlers,
|
||||
(add total (add partial acc))
|
||||
|
||||
and typing_switch_handlers statefull h acc ty switch_handlers =
|
||||
(* checks unicity of states *)
|
||||
let addname acc { w_name = n } =
|
||||
let n = shortname(n) in
|
||||
if S.mem n acc then error (Ealready_defined(n)) else S.add n acc in
|
||||
let cases = List.fold_left addname S.empty switch_handlers in
|
||||
let d = diff_const (set_of_constr (desc_of_ty ty)) cases in
|
||||
if not (S.is_empty d) then error (Epartial_switch(S.choose d));
|
||||
|
||||
let handler ({ w_block = b; w_name = name }) =
|
||||
let typed_b, defined_names, _ = typing_block statefull h b in
|
||||
{ w_block = typed_b;
|
||||
(* Replace handler name with fully qualified name *)
|
||||
w_name = Modname((find_constr name).qualid)},
|
||||
defined_names in
|
||||
|
||||
let typed_switch_handlers, defined_names_list =
|
||||
List.split (List.map handler switch_handlers) in
|
||||
let total, partial = merge defined_names_list in
|
||||
all_last h partial;
|
||||
(typed_switch_handlers,
|
||||
add total (add partial acc))
|
||||
|
||||
and typing_present_handlers statefull h acc def_names present_handlers =
|
||||
let handler ({ p_cond = e; p_block = b }) =
|
||||
let typed_e = expect false h (Tbase(tbool)) e in
|
||||
let typed_b, defined_names, _ = typing_block statefull h b in
|
||||
{ p_cond = typed_e; p_block = typed_b },
|
||||
defined_names
|
||||
in
|
||||
|
||||
let typed_present_handlers, defined_names_list =
|
||||
List.split (List.map handler present_handlers) in
|
||||
let total, partial = merge (def_names :: defined_names_list) in
|
||||
all_last h partial;
|
||||
(typed_present_handlers,
|
||||
(add total (add partial acc)))
|
||||
|
||||
and typing_block statefull h
|
||||
({ b_local = l; b_equs = eq_list; b_loc = loc } as b) =
|
||||
try
|
||||
let typed_l, local_names, h0 = build h Env.empty l in
|
||||
let typed_eq_list, defined_names =
|
||||
typing_eq_list statefull h0 Env.empty eq_list in
|
||||
let defnames = diff_env defined_names local_names in
|
||||
{ b with
|
||||
b_statefull = statefull;
|
||||
b_defnames = defnames;
|
||||
b_local = typed_l;
|
||||
b_equs = typed_eq_list },
|
||||
defnames, h0
|
||||
with
|
||||
| TypingError(kind) -> message loc kind
|
||||
|
||||
and build h h0 dec =
|
||||
List.fold_left
|
||||
(fun (acc_dec, acc_defined, h)
|
||||
({ v_name = n; v_type = btype; v_last = l; v_loc = loc } as v) ->
|
||||
try
|
||||
let ty = check_type btype in
|
||||
(* update type longname with module name from check_type *)
|
||||
v.v_type <- ty;
|
||||
if (Env.mem n h0) or (Env.mem n h)
|
||||
then error (Ealready_defined(sourcename n))
|
||||
else
|
||||
({ v with v_type = ty }::acc_dec,
|
||||
Env.add n (Tbase(ty)) acc_defined,
|
||||
Env.add n { ty = Tbase(ty); last = last l } h)
|
||||
with
|
||||
| TypingError(kind) -> message loc kind)
|
||||
([], Env.empty, h) dec
|
||||
|
||||
let build_params h params =
|
||||
let add_one h param =
|
||||
if Env.mem param h then
|
||||
error (Ealready_defined(name param));
|
||||
Env.add param { ty = Tbase Tint; last = false } h
|
||||
in
|
||||
List.fold_left add_one h params
|
||||
|
||||
let typing_contract statefull h contract =
|
||||
|
||||
match contract with
|
||||
| None -> None,Env.empty,h
|
||||
| Some ({ c_local = l_list;
|
||||
c_eq = eq;
|
||||
c_assume = e_a;
|
||||
c_enforce = e_g;
|
||||
c_controllables = c_list }) ->
|
||||
let typed_c_list, controllable_names, h = build h h c_list in
|
||||
let typed_l_list, local_names, h' = build h h l_list in
|
||||
|
||||
let typed_eq, defined_names = typing_eq_list statefull h' Env.empty eq in
|
||||
|
||||
(* assumption *)
|
||||
let typed_e_a = expect statefull h' (Tbase(tbool)) e_a in
|
||||
(* property *)
|
||||
let typed_e_g = expect statefull h' (Tbase(tbool)) e_g in
|
||||
|
||||
included_env local_names defined_names;
|
||||
included_env defined_names local_names;
|
||||
|
||||
Some { c_local = typed_l_list;
|
||||
c_controllables = List.rev typed_c_list;
|
||||
c_eq = typed_eq;
|
||||
c_assume = typed_e_a;
|
||||
c_enforce = typed_e_g },
|
||||
controllable_names, h
|
||||
|
||||
let signature const_env statefull params returns contract node_params constraints =
|
||||
let arg_dec_of_var_dec vd =
|
||||
{ a_name = Some (sourcename vd.v_name);
|
||||
a_type = Tbase(check_type vd.v_type);
|
||||
a_linearity = vd.v_linearity;
|
||||
a_pass_by_ref = false; }
|
||||
in
|
||||
{ inputs = List.map arg_dec_of_var_dec params;
|
||||
outputs = List.map arg_dec_of_var_dec returns;
|
||||
contract = contract;
|
||||
node = statefull;
|
||||
safe = false;
|
||||
targeting = [];
|
||||
params = node_params;
|
||||
params_constraints = constraints; }
|
||||
|
||||
let solve loc env cl =
|
||||
try
|
||||
solve env cl
|
||||
with
|
||||
Solve_failed c -> message loc (Econstraint_solve_failed c)
|
||||
|
||||
let node const_env ({ n_name = f; n_statefull = statefull;
|
||||
n_input = i_list; n_output = o_list;
|
||||
n_contract = contract;
|
||||
n_local = l_list; n_equs = eq_list; n_loc = loc;
|
||||
n_params = node_params; } as n) =
|
||||
try
|
||||
let typed_i_list, input_names, h = build Env.empty Env.empty i_list in
|
||||
let typed_o_list, output_names, h = build h h o_list in
|
||||
|
||||
(* typing contract *)
|
||||
let typed_contract, controllable_names, h = typing_contract statefull h contract in
|
||||
|
||||
let typed_l_list, local_names, h = build h h l_list in
|
||||
let typed_eq_list, defined_names = typing_eq_list statefull h Env.empty eq_list in
|
||||
if not (statefull) & (List.length o_list <> 1)
|
||||
then error (Etwo_many_outputs);
|
||||
let expected_names = add local_names output_names in
|
||||
included_env expected_names defined_names;
|
||||
included_env defined_names expected_names;
|
||||
|
||||
let cl = get_size_constr () in
|
||||
let ff = Format.formatter_of_out_channel stdout in
|
||||
Format.fprintf ff "Gathered constraints before solving for %s: %d\n " f (List.length cl);
|
||||
print_list ff print_size_constr ", " cl;
|
||||
Format.fprintf ff "\n";
|
||||
|
||||
let cl = solve loc const_env cl in
|
||||
Format.fprintf ff "Constraints after solving for %s: %d\n " f (List.length cl);
|
||||
print_list ff print_size_constr ", " cl;
|
||||
Format.fprintf ff "\n";
|
||||
Format.fprintf ff "@?" ;
|
||||
|
||||
add_value f (signature const_env statefull i_list o_list contract node_params cl);
|
||||
|
||||
{ n with
|
||||
n_input = List.rev typed_i_list;
|
||||
n_output = List.rev typed_o_list;
|
||||
n_local = typed_l_list;
|
||||
n_contract = typed_contract;
|
||||
n_equs = typed_eq_list }
|
||||
with
|
||||
| TypingError(error) -> message loc error
|
||||
|
||||
let deftype const_env { t_name = n; t_desc = tdesc; t_loc = loc } =
|
||||
try
|
||||
match tdesc with
|
||||
| Type_abs -> add_type n Tabstract
|
||||
| Type_enum(tag_name_list) ->
|
||||
add_type n (Tenum(tag_name_list));
|
||||
List.iter (fun tag -> add_constr tag (Tid(longname n))) tag_name_list
|
||||
| Type_struct(field_ty_list) ->
|
||||
let field_ty_list =
|
||||
List.map (fun (n,ty) -> n, simplify_type loc const_env ty) field_ty_list in
|
||||
add_type n (Tstruct(field_ty_list));
|
||||
add_struct n field_ty_list;
|
||||
List.iter
|
||||
(fun (field, ty) ->
|
||||
add_field field (Tid(longname n)) (check_type ty)) field_ty_list
|
||||
with
|
||||
TypingError(error) -> message loc error
|
||||
|
||||
let build_const_env cd_list =
|
||||
List.fold_left (fun env cd -> NamesEnv.add cd.c_name cd.c_value env) NamesEnv.empty cd_list
|
||||
|
||||
let program
|
||||
({ p_opened = opened; p_types = p_type_list;
|
||||
p_nodes = p_node_list; p_consts = p_consts_list } as p) =
|
||||
let const_env = build_const_env p_consts_list in
|
||||
List.iter open_module opened;
|
||||
List.iter (deftype const_env) p_type_list;
|
||||
let typed_node_list = List.map (node const_env) p_node_list in
|
||||
{ p with p_nodes = typed_node_list }
|
370
heptagon/heptagon.ml
Normal file
370
heptagon/heptagon.ml
Normal file
|
@ -0,0 +1,370 @@
|
|||
(**************************************************************************)
|
||||
(* *)
|
||||
(* Heptagon *)
|
||||
(* *)
|
||||
(* Author : Marc Pouzet *)
|
||||
(* Organization : Demons, LRI, University of Paris-Sud, Orsay *)
|
||||
(* *)
|
||||
(**************************************************************************)
|
||||
(* the internal representation *)
|
||||
(* $Id$ *)
|
||||
|
||||
open Location
|
||||
open Misc
|
||||
open Names
|
||||
open Linearity
|
||||
open Ident
|
||||
open Interference_graph
|
||||
open Static
|
||||
|
||||
type inlining_policy =
|
||||
| Ino
|
||||
| Ione
|
||||
| Irec
|
||||
|
||||
type ty =
|
||||
| Tbase of base_ty
|
||||
| Tprod of ty list
|
||||
|
||||
and base_ty =
|
||||
| Tint | Tfloat | Tbool
|
||||
| Tid of longname
|
||||
| Tarray of base_ty * size_exp
|
||||
|
||||
and exp =
|
||||
{ e_desc: desc;
|
||||
mutable e_ty: ty;
|
||||
mutable e_linearity : linearity;
|
||||
e_loc: location }
|
||||
|
||||
and desc =
|
||||
| Econst of const
|
||||
| Evar of ident
|
||||
| Econstvar of name
|
||||
| Elast of ident
|
||||
| Etuple of exp list
|
||||
| Eapp of app * exp list
|
||||
| Efield of exp * longname
|
||||
| Estruct of (longname * exp) list
|
||||
| Earray of exp list
|
||||
| Ereset_mem of ident * exp * ident
|
||||
|
||||
and app =
|
||||
{ mutable a_op : op; (* hange of global name after typing *)
|
||||
a_inlined : inlining_policy; (* node to inline or not *)
|
||||
}
|
||||
|
||||
and op =
|
||||
| Epre of const option
|
||||
| Efby | Earrow | Eifthenelse | Enode of longname * size_exp list
|
||||
| Eevery of longname * size_exp list | Eop of longname * size_exp list
|
||||
| Erepeat | Eselect of size_exp list | Eselect_dyn
|
||||
| Eupdate of size_exp list
|
||||
| Eselect_slice
|
||||
| Econcat | Ecopy
|
||||
| Eiterator of iterator_name * longname * size_exp list * exp option
|
||||
| Efield_update of longname
|
||||
| Eflatten of longname | Emake of longname
|
||||
|
||||
and const =
|
||||
| Cint of int
|
||||
| Cfloat of float
|
||||
| Cconstr of longname
|
||||
| Cconst_array of size_exp * const
|
||||
|
||||
and pat =
|
||||
| Etuplepat of pat list
|
||||
| Evarpat of ident
|
||||
|
||||
type eq =
|
||||
{ eq_desc : eqdesc;
|
||||
mutable eq_statefull : bool;
|
||||
eq_loc : location }
|
||||
|
||||
and eqdesc =
|
||||
| Eautomaton of state_handler list
|
||||
| Eswitch of exp * switch_handler list
|
||||
| Epresent of present_handler list * block
|
||||
| Ereset of eq list * exp
|
||||
| Eeq of pat * exp
|
||||
|
||||
and block =
|
||||
{ b_local: var_dec list;
|
||||
b_equs: eq list;
|
||||
mutable b_defnames: ty Env.t;
|
||||
mutable b_statefull: bool;
|
||||
b_loc: location; }
|
||||
|
||||
and state_handler =
|
||||
{ s_state : name;
|
||||
s_block : block;
|
||||
s_until : escape list;
|
||||
s_unless : escape list; }
|
||||
|
||||
and escape =
|
||||
{ e_cond : exp;
|
||||
e_reset : bool;
|
||||
e_next_state : name; }
|
||||
|
||||
and switch_handler =
|
||||
{ w_name : longname;
|
||||
w_block : block; }
|
||||
|
||||
and present_handler =
|
||||
{ p_cond : exp;
|
||||
p_block : block; }
|
||||
|
||||
and var_dec =
|
||||
{ v_name : ident;
|
||||
mutable v_type : base_ty;
|
||||
mutable v_linearity : linearity;
|
||||
v_last : last;
|
||||
v_loc : location; }
|
||||
|
||||
and last = Var | Last of const option
|
||||
|
||||
type type_dec =
|
||||
{ t_name : name;
|
||||
t_desc : type_desc;
|
||||
t_loc : location }
|
||||
|
||||
and type_desc =
|
||||
| Type_abs
|
||||
| Type_enum of name list
|
||||
| Type_struct of (name * base_ty) list
|
||||
|
||||
type contract =
|
||||
{ c_assume : exp;
|
||||
c_enforce : exp;
|
||||
c_controllables : var_dec list;
|
||||
c_local : var_dec list;
|
||||
c_eq : eq list;
|
||||
}
|
||||
|
||||
type node_dec =
|
||||
{ n_name : name;
|
||||
n_statefull : bool;
|
||||
n_input : var_dec list;
|
||||
n_output : var_dec list;
|
||||
n_local : var_dec list;
|
||||
n_contract : contract option;
|
||||
n_equs : eq list;
|
||||
n_loc : location;
|
||||
n_states_graph : (name,name) interf_graph;
|
||||
n_params : name list;
|
||||
n_params_constraints : size_constr list;
|
||||
}
|
||||
|
||||
type const_dec =
|
||||
{ c_name : name;
|
||||
c_type : base_ty;
|
||||
c_value : size_exp;
|
||||
c_loc : location; }
|
||||
|
||||
type program =
|
||||
{ p_pragmas: (name * string) list;
|
||||
p_opened : name list;
|
||||
p_types : type_dec list;
|
||||
p_nodes : node_dec list;
|
||||
p_consts : const_dec list; }
|
||||
|
||||
type signature =
|
||||
{ sig_name : name;
|
||||
sig_inputs : (name option * base_ty * linearity) list;
|
||||
sig_outputs : (name option * base_ty * linearity) list;
|
||||
sig_node : bool;
|
||||
sig_safe : bool;
|
||||
sig_params : name list; }
|
||||
|
||||
type interface = interface_decl list
|
||||
|
||||
and interface_decl =
|
||||
{ interf_desc : interface_desc;
|
||||
interf_loc : location }
|
||||
|
||||
and interface_desc =
|
||||
| Iopen of name
|
||||
| Itypedef of type_dec
|
||||
| Isignature of signature
|
||||
|
||||
let tbool = Tbool
|
||||
|
||||
let edesc e = e.e_desc
|
||||
let eqdesc eq = eq.eq_desc
|
||||
|
||||
(* Helper functions to create AST. *)
|
||||
let pbool = Modname({ qual = "Pervasives"; id = "bool" })
|
||||
let ptrue = Modname({ qual = "Pervasives"; id = "true" })
|
||||
let pfalse = Modname({ qual = "Pervasives"; id = "false" })
|
||||
let por = Modname({ qual = "Pervasives"; id = "or" })
|
||||
let pint = Modname({ qual = "Pervasives"; id = "int" })
|
||||
let pfloat = Modname({ qual = "Pervasives"; id = "float" })
|
||||
|
||||
let emake desc ty = { e_desc = desc; e_ty = ty;
|
||||
e_linearity = NotLinear; e_loc = no_location }
|
||||
let eop op = { a_op = op; a_inlined = Ino }
|
||||
let tmake name desc = { t_name = name; t_desc = desc; t_loc = no_location }
|
||||
let eqmake desc = { eq_desc = desc; eq_statefull = true; eq_loc = no_location }
|
||||
|
||||
let tybool = Tbase(tbool)
|
||||
let cfalse = Cconstr(pfalse)
|
||||
let ctrue = Cconstr(ptrue)
|
||||
|
||||
let make_bool desc = emake desc tybool
|
||||
let bool_var n = make_bool (Evar(n))
|
||||
let bool_param n =
|
||||
{ v_name = n; v_type = tbool; v_last = Var;
|
||||
v_loc = no_location; v_linearity = NotLinear }
|
||||
|
||||
let dfalse = make_bool (Econst(Cconstr(pfalse)))
|
||||
let dtrue = make_bool (Econst(Cconstr(ptrue)))
|
||||
|
||||
let var n ty = emake (Evar(n)) ty
|
||||
let param n ty =
|
||||
{ v_name = n; v_type = ty; v_linearity = NotLinear;
|
||||
v_last = Var; v_loc = no_location }
|
||||
let fby_state initial e =
|
||||
{ e with e_desc = Eapp(eop (Epre(Some(Cconstr initial))), [e]) }
|
||||
let fby_false e = emake (Eapp(eop (Epre(Some(cfalse))), [e])) tybool
|
||||
let last_false x = emake (Elast(x)) tybool
|
||||
let ifthenelse e1 e2 e3 = emake (Eapp(eop Eifthenelse, [e1;e2;e3])) e2.e_ty
|
||||
let rec or_op e1 e2 = { e1 with e_desc = Eapp(eop (Eop(por, [])), [e1; e2]) }
|
||||
let pair e1 e2 = emake (Etuple([e1;e2])) (Tprod [e1.e_ty;e2.e_ty])
|
||||
let block defnames eqs =
|
||||
{ b_local = []; b_equs = eqs; b_defnames = defnames;
|
||||
b_statefull = true; b_loc = no_location }
|
||||
let eq pat e = eqmake (Eeq(pat, e))
|
||||
let reset eq_list e = eqmake (Ereset(eq_list, e))
|
||||
let switch e l = eqmake (Eswitch(e, l))
|
||||
|
||||
let varpat n = Evarpat(n)
|
||||
|
||||
(* Helper functions to work with type*)
|
||||
let base_type ty =
|
||||
match ty with
|
||||
| Tbase ty -> ty
|
||||
| _ -> assert false
|
||||
|
||||
let is_scalar_type ty =
|
||||
let pint = Modname({ qual = "Pervasives"; id = "int" }) in
|
||||
let pfloat = Modname({ qual = "Pervasives"; id = "float" }) in
|
||||
let pbool = Modname({ qual = "Pervasives"; id = "bool" }) in
|
||||
match ty with
|
||||
| Tbase(Tint) | Tbase(Tfloat) | Tbase(Tbool) -> true
|
||||
| Tbase(Tid name_int) when name_int = pint -> true
|
||||
| Tbase(Tid name_float) when name_float = pfloat -> true
|
||||
| Tbase(Tid name_bool) when name_bool = pbool -> true
|
||||
| _ -> false
|
||||
|
||||
let array_of ty exp =
|
||||
Tbase(Tarray (base_type ty, exp))
|
||||
|
||||
let const_array_of ty n =
|
||||
array_of ty (SConst n)
|
||||
|
||||
let op_from_app app =
|
||||
match app.a_op with
|
||||
| Eop (n,_) -> op_from_app_name n
|
||||
| _ -> raise Not_static
|
||||
|
||||
let rec size_exp_of_exp e =
|
||||
match e.e_desc with
|
||||
| Econstvar n -> SVar n
|
||||
| Econst (Cint i) -> SConst i
|
||||
| Eapp(app, [e1;e2]) ->
|
||||
let op = op_from_app app in
|
||||
SOp(op, size_exp_of_exp e1, size_exp_of_exp e2)
|
||||
| _ -> raise Not_static
|
||||
|
||||
module Vars =
|
||||
struct
|
||||
let rec vars_pat locals acc = function
|
||||
| Evarpat(x) ->
|
||||
if (IdentSet.mem x locals) or (IdentSet.mem x acc) then
|
||||
acc
|
||||
else
|
||||
IdentSet.add x acc
|
||||
| Etuplepat(pat_list) -> List.fold_left (vars_pat locals) acc pat_list
|
||||
|
||||
let rec left locals acc e =
|
||||
match e.e_desc with
|
||||
| Eapp({a_op = Epre _},[e]) -> acc
|
||||
| Eapp({a_op = Efby}, [e1;e2]) -> left locals acc e1
|
||||
| Etuple(e_list) | Eapp({a_op = _}, e_list) | Earray(e_list)->
|
||||
List.fold_left (left locals) acc e_list
|
||||
| Evar(n) | Ereset_mem (_, _, n) ->
|
||||
if (IdentSet.mem n acc) or (IdentSet.mem n locals) then
|
||||
acc
|
||||
else
|
||||
IdentSet.add n acc
|
||||
| Efield(e, _) -> left locals acc e
|
||||
| Estruct(f_e_list) ->
|
||||
List.fold_left (fun acc (_, e) -> left locals acc e) acc f_e_list
|
||||
| Elast _ | Econst _ | Econstvar _ -> acc
|
||||
|
||||
let rec read locals acc eq =
|
||||
match eq.eq_desc with
|
||||
| Eeq(pat, e) -> left locals acc e
|
||||
| Ereset(eq_list, e) ->
|
||||
List.fold_left (read locals) (left locals acc e) eq_list
|
||||
| Eautomaton(state_handlers) ->
|
||||
let escapes locals acc e_list =
|
||||
List.fold_left
|
||||
(fun acc { e_cond = e } -> left locals acc e) acc e_list in
|
||||
List.fold_left
|
||||
(fun acc {s_block = b; s_until = e_list1; s_unless = e_list2} ->
|
||||
let new_locals, acc = read_and_locals_block locals acc b in
|
||||
let acc = escapes new_locals acc e_list1 in
|
||||
escapes locals acc e_list2)
|
||||
acc state_handlers
|
||||
| Eswitch(e, switch_handlers) ->
|
||||
List.fold_left
|
||||
(fun acc { w_block = b } -> read_block locals acc b)
|
||||
(left locals acc e) switch_handlers
|
||||
| Epresent(present_handlers, b) ->
|
||||
List.fold_left
|
||||
(fun acc { p_cond = e; p_block = b } ->
|
||||
read_block locals (left locals acc e) b)
|
||||
(read_block locals acc b) present_handlers
|
||||
|
||||
and read_and_locals_block locals acc { b_local = l; b_equs = eq_list } =
|
||||
let locals =
|
||||
List.fold_left
|
||||
(fun acc { v_name = n } -> if IdentSet.mem n acc then acc else IdentSet.add n acc)
|
||||
locals l in
|
||||
locals, List.fold_left (read locals) acc eq_list
|
||||
|
||||
and read_block locals acc b =
|
||||
let _, acc = read_and_locals_block locals acc b in acc
|
||||
|
||||
let rec def locals acc eq =
|
||||
match eq.eq_desc with
|
||||
| Eeq(pat, _) -> vars_pat locals acc pat
|
||||
| Eautomaton(state_handler) ->
|
||||
List.fold_left
|
||||
(fun acc { s_block = b } ->
|
||||
def_block locals acc b) acc state_handler
|
||||
| Eswitch(_, switch_handler) ->
|
||||
List.fold_left
|
||||
(fun acc { w_block = b } ->
|
||||
def_block locals acc b) acc switch_handler
|
||||
| Epresent(present_handler, b) ->
|
||||
List.fold_left
|
||||
(fun acc { p_block = b } -> def_block locals acc b)
|
||||
(def_block locals acc b) present_handler
|
||||
| Ereset(eq_list, _) -> def_list locals acc eq_list
|
||||
|
||||
and def_block locals acc ({ b_local = l; b_equs = eq_list }) =
|
||||
let locals =
|
||||
List.fold_left
|
||||
(fun acc { v_name = n } -> if IdentSet.mem n acc then acc else IdentSet.add n acc)
|
||||
locals l in
|
||||
def_list locals acc eq_list
|
||||
|
||||
and def_list locals acc def_list = List.fold_left (def locals) acc def_list
|
||||
|
||||
let read eq = IdentSet.elements (read IdentSet.empty IdentSet.empty eq)
|
||||
let def eq = IdentSet.elements (def IdentSet.empty IdentSet.empty eq)
|
||||
let antidep eq = false
|
||||
let vars_list pat = IdentSet.elements (vars_pat IdentSet.empty IdentSet.empty pat)
|
||||
end
|
0
heptagon/main/compiler.ml
Normal file
0
heptagon/main/compiler.ml
Normal file
0
heptagon/main/hepcheck.ml
Normal file
0
heptagon/main/hepcheck.ml
Normal file
315
heptagon/parsing/lexer.mll
Normal file
315
heptagon/parsing/lexer.mll
Normal file
|
@ -0,0 +1,315 @@
|
|||
(* lexer.mll *)
|
||||
|
||||
(* $Id$ *)
|
||||
|
||||
{
|
||||
open Lexing
|
||||
open Parser
|
||||
|
||||
type lexical_error =
|
||||
Illegal_character
|
||||
| Unterminated_comment
|
||||
| Bad_char_constant
|
||||
| Unterminated_string;;
|
||||
|
||||
exception Lexical_error of lexical_error * int * int;;
|
||||
|
||||
let comment_depth = ref 0
|
||||
|
||||
let keyword_table = ((Hashtbl.create 149) : (string, token) Hashtbl.t);;
|
||||
|
||||
List.iter (fun (str,tok) -> Hashtbl.add keyword_table str tok) [
|
||||
"node", NODE;
|
||||
"fun", FUN;
|
||||
"safe", SAFE;
|
||||
"returns", RETURNS;
|
||||
"var", VAR;
|
||||
"val", VAL;
|
||||
"const", CONST;
|
||||
"unsafe", UNSAFE;
|
||||
"let", LET;
|
||||
"tel", TEL;
|
||||
"end", END;
|
||||
"fby", FBY;
|
||||
"switch", SWITCH;
|
||||
"when", WHEN;
|
||||
"type", TYPE;
|
||||
"every", EVERY;
|
||||
"true", BOOL(true);
|
||||
"false", BOOL(false);
|
||||
"pre", PRE;
|
||||
"or", OR;
|
||||
"not", NOT;
|
||||
"open", OPEN;
|
||||
"automaton", AUTOMATON;
|
||||
"switch", SWITCH;
|
||||
"present", PRESENT;
|
||||
"reset", RESET;
|
||||
"state", STATE;
|
||||
"unless", UNLESS;
|
||||
"until", UNTIL;
|
||||
"emit", EMIT;
|
||||
"last", LAST;
|
||||
"if", IF;
|
||||
"then", THEN;
|
||||
"else", ELSE;
|
||||
"default", DEFAULT;
|
||||
"continue", CONTINUE;
|
||||
"case", CASE;
|
||||
"do", DO;
|
||||
"contract", CONTRACT;
|
||||
"assume", ASSUME;
|
||||
"enforce", ENFORCE;
|
||||
"with", WITH;
|
||||
"inlined", INLINED;
|
||||
"at", AT;
|
||||
"with", WITH;
|
||||
"map", MAP;
|
||||
"fold", FOLD;
|
||||
"mapfold", MAPFOLD;
|
||||
"copy", COPY;
|
||||
"flatten", FLATTEN;
|
||||
"make", MAKE;
|
||||
"quo", INFIX3("quo");
|
||||
"mod", INFIX3("mod");
|
||||
"land", INFIX3("land");
|
||||
"lor", INFIX2("lor");
|
||||
"lxor", INFIX2("lxor");
|
||||
"lsl", INFIX4("lsl");
|
||||
"lsr", INFIX4("lsr");
|
||||
"asr", INFIX4("asr")
|
||||
]
|
||||
|
||||
|
||||
(* To buffer string literals *)
|
||||
|
||||
let initial_string_buffer = String.create 256
|
||||
let string_buff = ref initial_string_buffer
|
||||
let string_index = ref 0
|
||||
|
||||
let reset_string_buffer () =
|
||||
string_buff := initial_string_buffer;
|
||||
string_index := 0;
|
||||
()
|
||||
|
||||
(*
|
||||
let incr_linenum lexbuf =
|
||||
let pos = lexbuf.Lexing.lex_curr_p in
|
||||
lexbuf.Lexing.lex_curr_p <- { pos with
|
||||
Lexing.pos_lnum = pos.Lexing.pos_lnum + 1;
|
||||
Lexing.pos_bol = pos.Lexing.pos_cnum;
|
||||
}
|
||||
*)
|
||||
|
||||
let store_string_char c =
|
||||
if !string_index >= String.length (!string_buff) then begin
|
||||
let new_buff = String.create (String.length (!string_buff) * 2) in
|
||||
String.blit (!string_buff) 0 new_buff 0 (String.length (!string_buff));
|
||||
string_buff := new_buff
|
||||
end;
|
||||
String.set (!string_buff) (!string_index) c;
|
||||
incr string_index
|
||||
|
||||
|
||||
let get_stored_string () =
|
||||
let s = String.sub (!string_buff) 0 (!string_index) in
|
||||
string_buff := initial_string_buffer;
|
||||
s
|
||||
|
||||
let char_for_backslash = function
|
||||
'n' -> '\010'
|
||||
| 'r' -> '\013'
|
||||
| 'b' -> '\008'
|
||||
| 't' -> '\009'
|
||||
| c -> c
|
||||
|
||||
let char_for_decimal_code lexbuf i =
|
||||
let c =
|
||||
100 * (int_of_char(Lexing.lexeme_char lexbuf i) - 48) +
|
||||
10 * (int_of_char(Lexing.lexeme_char lexbuf (i+1)) - 48) +
|
||||
(int_of_char(Lexing.lexeme_char lexbuf (i+2)) - 48) in
|
||||
char_of_int(c land 0xFF)
|
||||
|
||||
|
||||
}
|
||||
|
||||
rule token = parse
|
||||
| [' ' '\010' '\013' '\009' '\012'] + { token lexbuf }
|
||||
| "." {DOT}
|
||||
| "(" {LPAREN}
|
||||
| ")" {RPAREN}
|
||||
| "*" { STAR }
|
||||
| "{" {LBRACE}
|
||||
| "}" {RBRACE}
|
||||
| ":" {COLON}
|
||||
| ";" {SEMICOL}
|
||||
| "=" {EQUAL}
|
||||
| "==" {EQUALEQUAL}
|
||||
| "&" {AMPERSAND}
|
||||
| "&&" {AMPERAMPER}
|
||||
| "||" {BARBAR}
|
||||
| "," {COMMA}
|
||||
| "->" {ARROW}
|
||||
| "|" {BAR}
|
||||
| "-" {SUBTRACTIVE "-"}
|
||||
| "-." {SUBTRACTIVE "-."}
|
||||
| "^" {POWER}
|
||||
| "[" {LBRACKET}
|
||||
| "]" {RBRACKET}
|
||||
| "@" {AROBASE}
|
||||
| ".." {DOUBLE_DOT}
|
||||
| "<<" {DOUBLE_LESS}
|
||||
| ">>" {DOUBLE_GREATER}
|
||||
| (['A'-'Z']('_' ? ['A'-'Z' 'a'-'z' ''' '0'-'9']) * as id)
|
||||
{Constructor id}
|
||||
| (['A'-'Z' 'a'-'z']('_' ? ['A'-'Z' 'a'-'z' ''' '0'-'9']) * as id)
|
||||
{ let s = Lexing.lexeme lexbuf in
|
||||
begin try
|
||||
Hashtbl.find keyword_table s
|
||||
with
|
||||
Not_found -> IDENT id
|
||||
end
|
||||
}
|
||||
| ['0'-'9']+
|
||||
| '0' ['x' 'X'] ['0'-'9' 'A'-'F' 'a'-'f']+
|
||||
| '0' ['o' 'O'] ['0'-'7']+
|
||||
| '0' ['b' 'B'] ['0'-'1']+
|
||||
{ INT (int_of_string(Lexing.lexeme lexbuf)) }
|
||||
| ['0'-'9']+ ('.' ['0'-'9']*)? (['e' 'E'] ['+' '-']? ['0'-'9']+)?
|
||||
{ FLOAT (float_of_string(Lexing.lexeme lexbuf)) }
|
||||
| "\""
|
||||
{ reset_string_buffer();
|
||||
let string_start = lexbuf.lex_start_pos + lexbuf.lex_abs_pos in
|
||||
begin try
|
||||
string lexbuf
|
||||
with Lexical_error(Unterminated_string, _, string_end) ->
|
||||
raise(Lexical_error(Unterminated_string, string_start, string_end))
|
||||
end;
|
||||
lexbuf.lex_start_pos <- string_start - lexbuf.lex_abs_pos;
|
||||
STRING (get_stored_string()) }
|
||||
| "'" [^ '\\' '\''] "'"
|
||||
{ CHAR(Lexing.lexeme_char lexbuf 1) }
|
||||
| "'" '\\' ['\\' '\'' 'n' 't' 'b' 'r'] "'"
|
||||
{ CHAR(char_for_backslash (Lexing.lexeme_char lexbuf 2)) }
|
||||
| "'" '\\' ['0'-'9'] ['0'-'9'] ['0'-'9'] "'"
|
||||
{ CHAR(char_for_decimal_code lexbuf 2) }
|
||||
| "(*@ " (['A'-'Z' 'a'-'z']('_' ? ['A'-'Z' 'a'-'z' ''' '0'-'9']) * as id)
|
||||
{
|
||||
reset_string_buffer();
|
||||
let pragma_start = lexbuf.lex_start_pos + lexbuf.lex_abs_pos in
|
||||
begin try
|
||||
pragma lexbuf
|
||||
with Lexical_error(Unterminated_comment, _, pragma_end) ->
|
||||
raise(Lexical_error(Unterminated_comment, pragma_start, pragma_end))
|
||||
end;
|
||||
lexbuf.lex_start_pos <- pragma_start - lexbuf.lex_abs_pos;
|
||||
PRAGMA(id,get_stored_string())
|
||||
}
|
||||
| "(*"
|
||||
{ let comment_start = lexbuf.lex_start_pos + lexbuf.lex_abs_pos in
|
||||
comment_depth := 1;
|
||||
begin try
|
||||
comment lexbuf
|
||||
with Lexical_error(Unterminated_comment, _, comment_end) ->
|
||||
raise(Lexical_error(Unterminated_comment,
|
||||
comment_start, comment_end))
|
||||
end;
|
||||
token lexbuf }
|
||||
| ['!' '?' '~']
|
||||
['!' '$' '%' '&' '*' '+' '-' '.' '/' ':'
|
||||
'<' '=' '>' '?' '@' '^' '|' '~'] *
|
||||
{ PREFIX(Lexing.lexeme lexbuf) }
|
||||
| ['=' '<' '>' '&' '|' '&' '$']
|
||||
['!' '$' '%' '&' '*' '+' '-' '.' '/' ':' '<' '=' '>'
|
||||
'?' '@' '^' '|' '~'] *
|
||||
{ INFIX0(Lexing.lexeme lexbuf) }
|
||||
| ['@' '^']
|
||||
['!' '$' '%' '&' '*' '+' '-' '.' '/' ':' '<' '=' '>'
|
||||
'?' '@' '^' '|' '~'] *
|
||||
{ INFIX1(Lexing.lexeme lexbuf) }
|
||||
| ['+' '-']
|
||||
['!' '$' '%' '&' '*' '+' '-' '.' '/' ':' '<' '=' '>'
|
||||
'?' '@' '^' '|' '~'] *
|
||||
{ INFIX2(Lexing.lexeme lexbuf) }
|
||||
| "**"
|
||||
['!' '$' '%' '&' '*' '+' '-' '.' '/' ':' '<' '=' '>'
|
||||
'?' '@' '^' '|' '~'] *
|
||||
{ INFIX4(Lexing.lexeme lexbuf) }
|
||||
| ['*' '/' '%']
|
||||
['!' '$' '%' '&' '*' '+' '-' '.' '/' ':' '<' '=' '>'
|
||||
'?' '@' '^' '|' '~'] *
|
||||
{ INFIX3(Lexing.lexeme lexbuf) }
|
||||
| eof {EOF}
|
||||
| _ {raise (Lexical_error (Illegal_character,
|
||||
Lexing.lexeme_start lexbuf,
|
||||
Lexing.lexeme_end lexbuf))}
|
||||
|
||||
and pragma = parse
|
||||
"(*"
|
||||
{ let comment_start = lexbuf.lex_start_pos + lexbuf.lex_abs_pos in
|
||||
comment_depth := 1;
|
||||
begin try
|
||||
comment lexbuf
|
||||
with Lexical_error(Unterminated_comment, _, comment_end) ->
|
||||
raise(Lexical_error(Unterminated_comment,
|
||||
comment_start, comment_end))
|
||||
end;
|
||||
pragma lexbuf }
|
||||
| "@*)"
|
||||
{ }
|
||||
| eof
|
||||
{ raise(Lexical_error(Unterminated_comment,0,
|
||||
Lexing.lexeme_start lexbuf)) }
|
||||
|
||||
| _
|
||||
{ store_string_char(Lexing.lexeme_char lexbuf 0);
|
||||
pragma lexbuf }
|
||||
|
||||
and comment = parse
|
||||
"(*"
|
||||
{ comment_depth := succ !comment_depth; comment lexbuf }
|
||||
| "*)"
|
||||
{ comment_depth := pred !comment_depth;
|
||||
if !comment_depth > 0 then comment lexbuf }
|
||||
| "\""
|
||||
{ reset_string_buffer();
|
||||
let string_start = lexbuf.lex_start_pos + lexbuf.lex_abs_pos in
|
||||
begin try
|
||||
string lexbuf
|
||||
with Lexical_error(Unterminated_string, _, string_end) ->
|
||||
raise(Lexical_error(Unterminated_string, string_start, string_end))
|
||||
end;
|
||||
comment lexbuf }
|
||||
| "''"
|
||||
{ comment lexbuf }
|
||||
| "'" [^ '\\' '\''] "'"
|
||||
{ comment lexbuf }
|
||||
| "'" '\\' ['\\' '\'' 'n' 't' 'b' 'r'] "'"
|
||||
{ comment lexbuf }
|
||||
| "'" '\\' ['0'-'9'] ['0'-'9'] ['0'-'9'] "'"
|
||||
{ comment lexbuf }
|
||||
| eof
|
||||
{ raise(Lexical_error(Unterminated_comment,0,
|
||||
Lexing.lexeme_start lexbuf)) }
|
||||
| _
|
||||
{ comment lexbuf }
|
||||
|
||||
and string = parse
|
||||
'"'
|
||||
{ () }
|
||||
| '\\' ("\010" | "\013" | "\013\010") [' ' '\009'] *
|
||||
{ string lexbuf }
|
||||
| '\\' ['\\' '"' 'n' 't' 'b' 'r']
|
||||
{ store_string_char(char_for_backslash(Lexing.lexeme_char lexbuf 1));
|
||||
string lexbuf }
|
||||
| '\\' ['0'-'9'] ['0'-'9'] ['0'-'9']
|
||||
{ store_string_char(char_for_decimal_code lexbuf 1);
|
||||
string lexbuf }
|
||||
| eof
|
||||
{ raise (Lexical_error
|
||||
(Unterminated_string, 0, Lexing.lexeme_start lexbuf)) }
|
||||
| _
|
||||
{ store_string_char(Lexing.lexeme_char lexbuf 0);
|
||||
string lexbuf }
|
||||
|
||||
(* eof *)
|
607
heptagon/parsing/parser.mly
Normal file
607
heptagon/parsing/parser.mly
Normal file
|
@ -0,0 +1,607 @@
|
|||
%{
|
||||
(* $Id$ *)
|
||||
|
||||
open Misc
|
||||
open Global
|
||||
open Location
|
||||
open Names
|
||||
open Linearity
|
||||
open Parsetree
|
||||
|
||||
%}
|
||||
|
||||
%token DOT LPAREN RPAREN LBRACE RBRACE COLON SEMICOL
|
||||
%token EQUAL EQUALEQUAL BARBAR COMMA BAR ARROW LET TEL
|
||||
%token <string> Constructor
|
||||
%token <string> IDENT
|
||||
%token <int> INT
|
||||
%token <float> FLOAT
|
||||
%token <bool> BOOL
|
||||
%token <char> CHAR
|
||||
%token <string> STRING
|
||||
%token <string * string> PRAGMA
|
||||
%token TYPE FUN NODE RETURNS VAR VAL UNSAFE IN OPEN SAFE END CONST
|
||||
%token FBY PRE SWITCH WHEN EVERY
|
||||
%token OR STAR NOT
|
||||
%token AMPERSAND
|
||||
%token AMPERAMPER
|
||||
%token AUTOMATON
|
||||
%token SWITCH
|
||||
%token PRESENT
|
||||
%token RESET
|
||||
%token STATE
|
||||
%token UNLESS
|
||||
%token UNTIL
|
||||
%token EMIT
|
||||
%token LAST
|
||||
%token IF
|
||||
%token THEN
|
||||
%token ELSE
|
||||
%token DEFAULT
|
||||
%token DO
|
||||
%token CONTINUE
|
||||
%token CASE
|
||||
%token CONTRACT
|
||||
%token ASSUME
|
||||
%token ENFORCE
|
||||
%token WITH
|
||||
%token INLINED
|
||||
%token AT
|
||||
%token POWER
|
||||
%token LBRACKET
|
||||
%token RBRACKET
|
||||
%token WITH DOUBLE_DOT
|
||||
%token AROBASE
|
||||
%token DOUBLE_LESS DOUBLE_GREATER
|
||||
%token MAP FOLD MAPFOLD
|
||||
%token <string> PREFIX
|
||||
%token <string> INFIX0
|
||||
%token <string> INFIX1
|
||||
%token <string> INFIX2
|
||||
%token <string> SUBTRACTIVE
|
||||
%token <string> INFIX3
|
||||
%token <string> INFIX4
|
||||
%token EOF
|
||||
%token COPY
|
||||
%token FLATTEN MAKE
|
||||
|
||||
%right AROBASE
|
||||
%left WITH
|
||||
%nonassoc prec_ident
|
||||
%nonassoc LBRACKET
|
||||
%left IF ELSE
|
||||
%right ARROW
|
||||
%nonassoc EVERY
|
||||
%left OR
|
||||
%left AMPERSAND
|
||||
%left INFIX0 EQUAL
|
||||
%right INFIX1
|
||||
%left INFIX2 SUBTRACTIVE
|
||||
%left STAR INFIX3
|
||||
%left INFIX4
|
||||
%right NOT
|
||||
%right prec_uminus
|
||||
%right FBY
|
||||
%right PRE
|
||||
%right LAST
|
||||
%right prec_apply
|
||||
%left POWER
|
||||
%right PREFIX
|
||||
%left DOT
|
||||
|
||||
%start program
|
||||
%type <Parsetree.program> program
|
||||
|
||||
%start interface
|
||||
%type <Parsetree.interface> interface
|
||||
|
||||
%%
|
||||
|
||||
program:
|
||||
| pragma_headers open_modules const_decs type_decs node_decs EOF
|
||||
{{ p_pragmas = $1;
|
||||
p_opened = List.rev $2;
|
||||
p_types = $4;
|
||||
p_nodes = $5;
|
||||
p_consts = $3; }}
|
||||
;
|
||||
|
||||
pragma_headers:
|
||||
| /* empty */ { [] }
|
||||
| PRAGMA pragma_headers { $1 :: $2 }
|
||||
|
||||
open_modules:
|
||||
| /* empty */ { [] }
|
||||
| open_modules OPEN Constructor { $3 :: $1 }
|
||||
;
|
||||
|
||||
const_decs:
|
||||
| /* empty */ { [] }
|
||||
| const_dec const_decs { $1 :: $2 }
|
||||
;
|
||||
|
||||
const_dec:
|
||||
| CONST IDENT COLON ty_ident EQUAL exp
|
||||
{ cmake $2 $4 $6 }
|
||||
;
|
||||
|
||||
type_decs:
|
||||
| /* empty */ { [] }
|
||||
| type_dec type_decs { $1 :: $2 }
|
||||
;
|
||||
|
||||
type_dec:
|
||||
| TYPE IDENT { tmake $2 Type_abs }
|
||||
| TYPE IDENT EQUAL enum_ty_desc { tmake $2 (Type_enum ($4)) }
|
||||
| TYPE IDENT EQUAL struct_ty_desc { tmake $2 (Type_struct ($4)) }
|
||||
;
|
||||
|
||||
enum_ty_desc:
|
||||
| Constructor BAR Constructor {[$1;$3]}
|
||||
| BOOL BAR BOOL {[(if $1 then "true" else "false");
|
||||
(if $3 then "true" else "false")]}
|
||||
| Constructor BAR enum_ty_desc {$1 :: $3}
|
||||
;
|
||||
|
||||
struct_ty_desc:
|
||||
| LBRACE label_ty_list RBRACE { $2 }
|
||||
;
|
||||
|
||||
label_ty_list:
|
||||
| label_ty { [$1] }
|
||||
| label_ty SEMICOL label_ty_list { $1 :: $3 }
|
||||
;
|
||||
|
||||
label_ty:
|
||||
IDENT COLON ty_ident { ($1, fst $3) }
|
||||
;
|
||||
|
||||
node_decs:
|
||||
| /* empty */ {[]}
|
||||
| node_dec node_decs {$1 :: $2}
|
||||
;
|
||||
|
||||
node_dec:
|
||||
| node_or_fun ident node_params LPAREN in_params RPAREN
|
||||
RETURNS LPAREN out_params RPAREN
|
||||
contract loc_vars LET equs TEL
|
||||
{{ n_name = $2;
|
||||
n_statefull = $1;
|
||||
n_input = $5;
|
||||
n_output = $9;
|
||||
n_contract = $11;
|
||||
n_local = $12;
|
||||
n_equs = $14;
|
||||
n_params = $3;
|
||||
n_loc = Location.get_current_location () }}
|
||||
;
|
||||
|
||||
node_or_fun:
|
||||
| NODE { true }
|
||||
| FUN { false }
|
||||
;
|
||||
|
||||
safe:
|
||||
| /* empty */ { false }
|
||||
| SAFE { true }
|
||||
;
|
||||
|
||||
in_params:
|
||||
| params {$1}
|
||||
;
|
||||
|
||||
params:
|
||||
| /* empty */ { [] }
|
||||
| nonmt_params { $1 }
|
||||
;
|
||||
|
||||
nonmt_params:
|
||||
| param { $1 }
|
||||
| param SEMICOL nonmt_params { $1 @ $3 }
|
||||
;
|
||||
|
||||
param:
|
||||
| ident_list COLON ty_ident
|
||||
{ List.map (fun id -> vmake id $3 Var) $1 }
|
||||
;
|
||||
|
||||
out_params:
|
||||
| /* empty */ { [] }
|
||||
| nonmt_out_params { $1 }
|
||||
;
|
||||
|
||||
nonmt_out_params:
|
||||
| var_last { $1 }
|
||||
| var_last SEMICOL nonmt_out_params { $1 @ $3 }
|
||||
;
|
||||
|
||||
node_params:
|
||||
| /* empty */ { [] }
|
||||
| DOUBLE_LESS ident_list DOUBLE_GREATER { $2 }
|
||||
;
|
||||
|
||||
contract:
|
||||
| /* empty */ {None}
|
||||
| CONTRACT loc_vars opt_equs opt_assume enforce opt_with
|
||||
{Some{c_local = $2;
|
||||
c_eq = $3;
|
||||
c_assume = $4;
|
||||
c_enforce = $5;
|
||||
c_controllables = $6 }}
|
||||
;
|
||||
|
||||
opt_equs:
|
||||
| /* empty */ { [] }
|
||||
| LET equs TEL { $2 }
|
||||
;
|
||||
|
||||
opt_assume:
|
||||
| /* empty */ { e_true () }
|
||||
| ASSUME exp { $2 }
|
||||
;
|
||||
|
||||
enforce:
|
||||
| ENFORCE exp { $2 }
|
||||
;
|
||||
|
||||
opt_with:
|
||||
| /* empty */ { [] }
|
||||
| WITH LPAREN params RPAREN { $3 }
|
||||
;
|
||||
|
||||
loc_vars:
|
||||
| /* empty */ { [] }
|
||||
| VAR loc_params { $2 }
|
||||
;
|
||||
|
||||
loc_params:
|
||||
| var_last SEMICOL { $1 }
|
||||
| var_last SEMICOL loc_params { $1 @ $3 }
|
||||
;
|
||||
|
||||
var_last:
|
||||
| ident_list COLON ty_ident
|
||||
{ List.map (fun id -> vmake id $3 Var) $1 }
|
||||
| LAST IDENT COLON ty_ident EQUAL const
|
||||
{ [ vmake $2 $4 (Last(Some($6))) ] }
|
||||
| LAST IDENT COLON ty_ident
|
||||
{ [ vmake $2 $4 (Last(None)) ] }
|
||||
;
|
||||
|
||||
ident_list:
|
||||
| IDENT { [$1] }
|
||||
| IDENT COMMA ident_list { $1 :: $3 }
|
||||
;
|
||||
|
||||
ty_ident:
|
||||
| ty_ident_base
|
||||
{ $1, NotLinear }
|
||||
| ty_ident_base AT ident
|
||||
{ $1, At $3 }
|
||||
;
|
||||
|
||||
ty_ident_base:
|
||||
| IDENT
|
||||
{ Tid(Name($1)) }
|
||||
| ty_ident_base POWER simple_exp
|
||||
{ Tarray ($1, $3) }
|
||||
;
|
||||
|
||||
equs:
|
||||
| /* empty */ { [] }
|
||||
| non_empty_equs opt_semi { List.rev $1 }
|
||||
;
|
||||
|
||||
non_empty_equs:
|
||||
| equ { [$1] }
|
||||
| non_empty_equs SEMICOL equ {$3 :: $1}
|
||||
;
|
||||
|
||||
opt_semi:
|
||||
| {}
|
||||
| SEMICOL {}
|
||||
;
|
||||
|
||||
opt_bar:
|
||||
| {}
|
||||
| BAR {}
|
||||
;
|
||||
|
||||
equ:
|
||||
| pat EQUAL exp { eqmake (Eeq($1, $3)) }
|
||||
| AUTOMATON automaton_handlers END
|
||||
{ eqmake (Eautomaton(List.rev $2)) }
|
||||
| SWITCH exp opt_bar switch_handlers END
|
||||
{ eqmake (Eswitch($2, List.rev $4)) }
|
||||
| PRESENT opt_bar present_handlers END
|
||||
{ eqmake (Epresent(List.rev $3, bmake [] [])) }
|
||||
| PRESENT opt_bar present_handlers DEFAULT loc_vars DO equs END
|
||||
{ eqmake (Epresent(List.rev $3, bmake $5 $7)) }
|
||||
| IF exp THEN loc_vars DO equs ELSE loc_vars DO equs END
|
||||
{ eqmake (Eswitch($2,
|
||||
[{ w_name = Name("true"); w_block = bmake $4 $6};
|
||||
{ w_name = Name("false"); w_block = bmake $8 $10 }])) }
|
||||
| RESET equs EVERY exp
|
||||
{ eqmake (Ereset($2, $4)) }
|
||||
;
|
||||
|
||||
automaton_handler:
|
||||
| STATE Constructor loc_vars DO equs opt_until_escapes opt_unless_escapes
|
||||
{ { s_state = $2; s_block = bmake $3 $5;
|
||||
s_until = $6; s_unless = $7 } }
|
||||
;
|
||||
|
||||
automaton_handlers:
|
||||
| automaton_handler
|
||||
{ [$1] }
|
||||
| automaton_handlers automaton_handler
|
||||
{ $2 :: $1 }
|
||||
;
|
||||
|
||||
opt_until_escapes:
|
||||
| { [] }
|
||||
| UNTIL escapes
|
||||
{ List.rev $2 }
|
||||
;
|
||||
|
||||
opt_unless_escapes:
|
||||
| { [] }
|
||||
| UNLESS escapes
|
||||
{ List.rev $2 }
|
||||
;
|
||||
|
||||
escape:
|
||||
| exp THEN Constructor
|
||||
{ { e_cond = $1; e_reset = true; e_next_state = $3 } }
|
||||
| exp CONTINUE Constructor
|
||||
{ { e_cond = $1; e_reset = false; e_next_state = $3 } }
|
||||
;
|
||||
|
||||
escapes:
|
||||
| escape
|
||||
{ [$1] }
|
||||
| escapes BAR escape
|
||||
{ $3 :: $1 }
|
||||
;
|
||||
|
||||
switch_handler:
|
||||
| constructor loc_vars DO equs
|
||||
{ { w_name = $1; w_block = bmake $2 $4 } }
|
||||
;
|
||||
|
||||
switch_handlers:
|
||||
| switch_handler
|
||||
{ [$1] }
|
||||
| switch_handlers BAR switch_handler
|
||||
{ $3 :: $1 }
|
||||
;
|
||||
|
||||
present_handler:
|
||||
| exp loc_vars DO equs
|
||||
{ { p_cond = $1; p_block = bmake $2 $4 } }
|
||||
;
|
||||
|
||||
present_handlers:
|
||||
| present_handler
|
||||
{ [$1] }
|
||||
| present_handlers BAR present_handler
|
||||
{ $3 :: $1 }
|
||||
;
|
||||
|
||||
pat:
|
||||
| IDENT {Evarpat $1}
|
||||
| LPAREN ids RPAREN {Etuplepat $2}
|
||||
;
|
||||
|
||||
ids:
|
||||
| pat COMMA pat {[$1; $3]}
|
||||
| pat COMMA ids {$1 :: $3}
|
||||
;
|
||||
|
||||
nonmtexps:
|
||||
| exp {[$1]}
|
||||
| exp COMMA nonmtexps {$1 :: $3}
|
||||
;
|
||||
|
||||
exps:
|
||||
| /* empty */ {[]}
|
||||
| nonmtexps {$1}
|
||||
;
|
||||
|
||||
simple_exp:
|
||||
| IDENT { emake (Evar $1) }
|
||||
| const { emake (Econst $1) }
|
||||
| LBRACE field_exp_list RBRACE
|
||||
{ emake (Estruct($2)) }
|
||||
| LBRACKET array_exp_list RBRACKET
|
||||
{ emake (Earray $2) }
|
||||
| LPAREN tuple_exp RPAREN
|
||||
{ emake (Etuple $2) }
|
||||
| LPAREN exp RPAREN
|
||||
{ $2 }
|
||||
;
|
||||
|
||||
node_name:
|
||||
| longname call_params
|
||||
{ Enode($1, $2) }
|
||||
|
||||
exp:
|
||||
| simple_exp { $1 }
|
||||
| simple_exp FBY exp
|
||||
{ emake (Eapp(eop (Efby), [$1; $3])) }
|
||||
| PRE exp
|
||||
{ emake (Eapp(eop (Epre(None)), [$2])) }
|
||||
| node_name LPAREN exps RPAREN %prec prec_apply
|
||||
{ emake (Eapp(eop $1, $3)) }
|
||||
| INLINED node_name LPAREN exps RPAREN %prec prec_apply
|
||||
{ emake (Eapp(eop_inlined $2, $4)) }
|
||||
| NOT exp
|
||||
{ emake (Eapp(eop (Eop(Name("not"),[])), [$2])) }
|
||||
| exp INFIX4 exp
|
||||
{ emake (Eapp(eop (Eop(Name($2),[])), [$1; $3])) }
|
||||
| exp INFIX3 exp
|
||||
{ emake (Eapp(eop (Eop(Name($2),[])), [$1; $3])) }
|
||||
| exp INFIX2 exp
|
||||
{ emake (Eapp(eop (Eop(Name($2),[])), [$1; $3])) }
|
||||
| exp INFIX1 exp
|
||||
{ emake (Eapp(eop (Eop(Name($2),[])), [$1; $3])) }
|
||||
| exp INFIX0 exp
|
||||
{ emake (Eapp(eop (Eop(Name($2),[])), [$1; $3])) }
|
||||
| exp EQUAL exp
|
||||
{ emake (Eapp(eop (Eop(Name("="),[])), [$1; $3])) }
|
||||
| exp OR exp
|
||||
{ emake (Eapp(eop (Eop(Name("or"),[])), [$1; $3])) }
|
||||
| exp STAR exp
|
||||
{ emake (Eapp(eop (Eop(Name("*"),[])), [$1; $3])) }
|
||||
| exp AMPERSAND exp
|
||||
{ emake (Eapp(eop (Eop(Name("&"),[])), [$1; $3])) }
|
||||
| exp SUBTRACTIVE exp
|
||||
{ emake (Eapp(eop (Eop(Name($2),[])), [$1; $3])) }
|
||||
| PREFIX exp
|
||||
{ emake (Eapp(eop (Eop(Name($1),[])), [$2])) }
|
||||
| SUBTRACTIVE exp %prec prec_uminus
|
||||
{ emake (Eapp(eop (Eop(Name("~" ^ $1),[])), [$2])) }
|
||||
| IF exp THEN exp ELSE exp
|
||||
{ emake (Eapp(eop Eifthenelse, [$2; $4; $6])) }
|
||||
| simple_exp ARROW exp
|
||||
{ emake (Eapp(eop Earrow, [$1; $3])) }
|
||||
| LAST IDENT
|
||||
{ emake (Elast($2)) }
|
||||
| exp DOT longname { emake (Efield($1, $3)) }
|
||||
/*Array operations*/
|
||||
| exp POWER simple_exp
|
||||
{ emake (Eapp(eop (Erepeat), [$1; $3])) }
|
||||
| exp indexes
|
||||
{ emake (Eapp(eop (Eselect $2), [$1])) }
|
||||
| exp DOT indexes DEFAULT exp
|
||||
{ emake (Eapp(eop (Eselect_dyn), [$1; $5]@$3)) }
|
||||
| exp WITH indexes EQUAL exp
|
||||
{ emake (Eapp(eop (Eupdate $3), [$1; $5])) }
|
||||
| exp LBRACKET exp DOUBLE_DOT exp RBRACKET
|
||||
{ emake (Eapp(eop Eselect_slice, [$1; $3; $5])) }
|
||||
| exp AROBASE exp
|
||||
{ emake (Eapp(eop Econcat, [$1; $3])) }
|
||||
/*Iterators*/
|
||||
| iterator longname DOUBLE_LESS simple_exp DOUBLE_GREATER LPAREN exps RPAREN %prec prec_apply
|
||||
{ emake (Eapp(eop (Eiterator ($1, $2, [])), $4::$7)) }
|
||||
| iterator LPAREN longname DOUBLE_LESS array_exp_list DOUBLE_GREATER
|
||||
RPAREN DOUBLE_LESS simple_exp DOUBLE_GREATER LPAREN exps RPAREN %prec prec_apply
|
||||
{ emake (Eapp(eop (Eiterator ($1, $3, $5)), $9::$12)) }
|
||||
| COPY LPAREN exp RPAREN %prec prec_apply
|
||||
{ emake (Eapp(eop Ecopy, [$3])) }
|
||||
/*Records operators */
|
||||
| exp WITH DOT longname EQUAL exp
|
||||
{ emake (Eapp(eop (Efield_update $4), [$1; $6])) }
|
||||
| LPAREN FLATTEN longname RPAREN LPAREN exps RPAREN
|
||||
{ emake (Eapp(eop (Eflatten $3), $6)) }
|
||||
| LPAREN MAKE longname RPAREN LPAREN exps RPAREN
|
||||
{ emake (Eapp(eop (Emake $3), $6)) }
|
||||
;
|
||||
|
||||
call_params:
|
||||
| /* empty */ { [] }
|
||||
| DOUBLE_LESS array_exp_list DOUBLE_GREATER { $2 }
|
||||
;
|
||||
|
||||
iterator:
|
||||
| MAP { Imap }
|
||||
| FOLD { Ifold }
|
||||
| MAPFOLD { Imapfold }
|
||||
;
|
||||
|
||||
indexes:
|
||||
LBRACKET exp RBRACKET { [$2] }
|
||||
| LBRACKET exp RBRACKET indexes { $2::$4 }
|
||||
;
|
||||
|
||||
constructor:
|
||||
| Constructor { Name($1) } %prec prec_ident
|
||||
| Constructor DOT Constructor { Modname({qual = $1; id = $3}) }
|
||||
| BOOL { Name(if $1 then "true" else "false") }
|
||||
;
|
||||
|
||||
longname:
|
||||
| ident { Name($1) }
|
||||
| Constructor DOT ident { Modname({qual = $1; id = $3}) }
|
||||
;
|
||||
|
||||
const:
|
||||
| INT { Cint($1) }
|
||||
| FLOAT { Cfloat($1) }
|
||||
| constructor { Cconstr($1) }
|
||||
;
|
||||
|
||||
tuple_exp:
|
||||
| exp COMMA exp {[$1; $3]}
|
||||
| exp COMMA tuple_exp {$1 :: $3}
|
||||
;
|
||||
|
||||
field_exp_list:
|
||||
| field_exp { [$1] }
|
||||
| field_exp SEMICOL field_exp_list { $1 :: $3 }
|
||||
;
|
||||
|
||||
array_exp_list:
|
||||
| exp { [$1] }
|
||||
| exp COMMA array_exp_list { $1 :: $3 }
|
||||
;
|
||||
|
||||
field_exp:
|
||||
| longname EQUAL exp { ($1, $3) }
|
||||
;
|
||||
|
||||
/* identifiers */
|
||||
ident:
|
||||
| IDENT
|
||||
{ $1 }
|
||||
| LPAREN infx RPAREN
|
||||
{ $2 }
|
||||
;
|
||||
|
||||
infx:
|
||||
| INFIX0 { $1 }
|
||||
| INFIX1 { $1 } | INFIX2 { $1 }
|
||||
| INFIX3 { $1 } | INFIX4 { $1 }
|
||||
| STAR { "*" }
|
||||
| EQUAL { "=" }
|
||||
| EQUALEQUAL { "==" }
|
||||
| SUBTRACTIVE { $1 } | PREFIX { $1 }
|
||||
| AMPERSAND { "&" } | AMPERAMPER { "&&" }
|
||||
| OR { "or" } | BARBAR { "||" }
|
||||
| NOT { "not" }
|
||||
;
|
||||
|
||||
interface:
|
||||
| interface_decls EOF { List.rev $1 }
|
||||
;
|
||||
|
||||
interface_decls:
|
||||
| /* empty */ { [] }
|
||||
| interface_decls interface_decl { $2 :: $1 }
|
||||
;
|
||||
|
||||
interface_decl:
|
||||
| type_dec { imake (Itypedef($1)) }
|
||||
| OPEN Constructor { imake (Iopen($2)) }
|
||||
| VAL safe node_or_fun ident node_params LPAREN params_signature RPAREN
|
||||
RETURNS LPAREN params_signature RPAREN
|
||||
{ imake (Isignature({ sig_name = $4; sig_inputs = $7; sig_outputs = $11;
|
||||
sig_node = $3; sig_safe = $2; sig_params = $5; })) }
|
||||
;
|
||||
|
||||
params_signature:
|
||||
| /* empty */ {[]}
|
||||
| nonmt_params_signature {$1}
|
||||
;
|
||||
|
||||
nonmt_params_signature:
|
||||
| param_signature { [$1] }
|
||||
| param_signature SEMICOL nonmt_params_signature { $1 :: $3 }
|
||||
;
|
||||
|
||||
param_signature:
|
||||
| IDENT COLON ty_ident { (Some($1), $3) }
|
||||
| ty_ident { (None, $1) }
|
||||
;
|
||||
|
||||
%%
|
195
heptagon/parsing/parsetree.ml
Normal file
195
heptagon/parsing/parsetree.ml
Normal file
|
@ -0,0 +1,195 @@
|
|||
(**************************************************************************)
|
||||
(* *)
|
||||
(* Heptagon *)
|
||||
(* *)
|
||||
(* Author : Marc Pouzet *)
|
||||
(* Organization : Demons, LRI, University of Paris-Sud, Orsay *)
|
||||
(* *)
|
||||
(**************************************************************************)
|
||||
(* the internal representation *)
|
||||
(* $Id$ *)
|
||||
|
||||
open Location
|
||||
open Names
|
||||
open Linearity
|
||||
open Misc
|
||||
|
||||
type inlining_policy =
|
||||
| Ino
|
||||
| Ione
|
||||
| Irec
|
||||
|
||||
type ty =
|
||||
| Tprod of ty list
|
||||
| Tid of longname
|
||||
| Tarray of ty * exp
|
||||
|
||||
and exp =
|
||||
{ e_desc: desc;
|
||||
e_loc: location }
|
||||
|
||||
and desc =
|
||||
| Econst of const
|
||||
| Evar of name
|
||||
| Elast of name
|
||||
| Etuple of exp list
|
||||
| Eapp of app * exp list
|
||||
| Efield of exp * longname
|
||||
| Estruct of (longname * exp) list
|
||||
| Earray of exp list
|
||||
|
||||
and app =
|
||||
{ a_op : op; (* change of global name after typing *)
|
||||
a_inlined : inlining_policy; (* node to inline or not *)
|
||||
}
|
||||
|
||||
and op =
|
||||
| Epre of const option
|
||||
| Efby | Earrow | Eifthenelse | Enode of longname * exp list
|
||||
| Eevery of longname * exp list | Eop of longname * exp list
|
||||
| Erepeat | Eselect of exp list | Eselect_dyn
|
||||
| Eupdate of exp list
|
||||
| Eselect_slice
|
||||
| Econcat | Ecopy
|
||||
| Eiterator of iterator_name * longname * exp list
|
||||
| Efield_update of longname
|
||||
| Eflatten of longname | Emake of longname
|
||||
|
||||
and const =
|
||||
| Cint of int
|
||||
| Cfloat of float
|
||||
| Cconstr of longname
|
||||
|
||||
and pat =
|
||||
| Etuplepat of pat list
|
||||
| Evarpat of name
|
||||
|
||||
type eq =
|
||||
{ eq_desc : eqdesc;
|
||||
eq_loc : location }
|
||||
|
||||
and eqdesc =
|
||||
| Eautomaton of state_handler list
|
||||
| Eswitch of exp * switch_handler list
|
||||
| Epresent of present_handler list * block
|
||||
| Ereset of eq list * exp
|
||||
| Eeq of pat * exp
|
||||
|
||||
and block =
|
||||
{ b_local: var_dec list;
|
||||
b_equs: eq list;
|
||||
b_loc: location; }
|
||||
|
||||
and state_handler =
|
||||
{ s_state : name;
|
||||
s_block : block;
|
||||
s_until : escape list;
|
||||
s_unless : escape list; }
|
||||
|
||||
and escape =
|
||||
{ e_cond : exp;
|
||||
e_reset : bool;
|
||||
e_next_state : name; }
|
||||
|
||||
and switch_handler =
|
||||
{ w_name : longname;
|
||||
w_block : block; }
|
||||
|
||||
and present_handler =
|
||||
{ p_cond : exp;
|
||||
p_block : block; }
|
||||
|
||||
and var_dec =
|
||||
{ v_name : name;
|
||||
v_type : ty;
|
||||
v_linearity : linearity;
|
||||
v_last : last;
|
||||
v_loc : location; }
|
||||
|
||||
and last = Var | Last of const option
|
||||
|
||||
type type_dec =
|
||||
{ t_name : name;
|
||||
t_desc : type_desc;
|
||||
t_loc : location }
|
||||
|
||||
and type_desc =
|
||||
| Type_abs
|
||||
| Type_enum of name list
|
||||
| Type_struct of (name * ty) list
|
||||
|
||||
type contract =
|
||||
{ c_assume : exp;
|
||||
c_enforce : exp;
|
||||
c_controllables : var_dec list;
|
||||
c_local : var_dec list;
|
||||
c_eq : eq list;
|
||||
}
|
||||
|
||||
type node_dec =
|
||||
{ n_name : name;
|
||||
n_statefull : bool;
|
||||
n_input : var_dec list;
|
||||
n_output : var_dec list;
|
||||
n_local : var_dec list;
|
||||
n_contract : contract option;
|
||||
n_equs : eq list;
|
||||
n_loc : location;
|
||||
n_params : name list; }
|
||||
|
||||
type const_dec =
|
||||
{ c_name : name;
|
||||
c_type : ty;
|
||||
c_value : exp;
|
||||
c_loc : location; }
|
||||
|
||||
type program =
|
||||
{ p_pragmas: (name * string) list;
|
||||
p_opened : name list;
|
||||
p_types : type_dec list;
|
||||
p_nodes : node_dec list;
|
||||
p_consts : const_dec list; }
|
||||
|
||||
type signature =
|
||||
{ sig_name : name;
|
||||
sig_inputs : (name option * (ty * linearity)) list;
|
||||
sig_outputs : (name option * (ty * linearity)) list;
|
||||
sig_node : bool;
|
||||
sig_safe : bool;
|
||||
sig_params : name list; }
|
||||
|
||||
type interface = interface_decl list
|
||||
|
||||
and interface_decl =
|
||||
{ interf_desc : interface_desc;
|
||||
interf_loc : location }
|
||||
|
||||
and interface_desc =
|
||||
| Iopen of name
|
||||
| Itypedef of type_dec
|
||||
| Isignature of signature
|
||||
|
||||
(* Helper functions to create AST. *)
|
||||
let emake desc =
|
||||
{ e_desc = desc; e_loc = get_current_location () }
|
||||
let e_true () =
|
||||
emake (Econst(Cconstr(Modname{ qual="Pervasives"; id="true"})))
|
||||
let eop op = { a_op = op; a_inlined = Ino }
|
||||
let eop_inlined op = { a_op = op; a_inlined = Ione }
|
||||
let tmake name desc =
|
||||
{ t_name = name; t_desc = desc; t_loc = get_current_location () }
|
||||
let eqmake desc =
|
||||
{ eq_desc = desc; eq_loc = get_current_location () }
|
||||
let imake desc =
|
||||
{ interf_desc = desc; interf_loc = get_current_location () }
|
||||
let vmake name (ty, linearity) last =
|
||||
{ v_name = name; v_type = ty; v_linearity = linearity;
|
||||
v_last = last; v_loc = get_current_location () }
|
||||
|
||||
let bmake locals eqs =
|
||||
{ b_local = locals; b_equs = eqs;
|
||||
b_loc = get_current_location () }
|
||||
|
||||
let cmake id (ty,_) e =
|
||||
{ c_name = id; c_type = ty; c_value = e;
|
||||
c_loc = get_current_location (); }
|
334
heptagon/parsing/scoping.ml
Normal file
334
heptagon/parsing/scoping.ml
Normal file
|
@ -0,0 +1,334 @@
|
|||
(** Scoping. Introduces unique indexes for local names and replace global
|
||||
names by qualified names *)
|
||||
|
||||
open Location
|
||||
open Parsetree
|
||||
open Names
|
||||
open Ident
|
||||
open Format
|
||||
open Printf
|
||||
open Static
|
||||
|
||||
module Error =
|
||||
struct
|
||||
type error =
|
||||
| Evar of string
|
||||
| Econst_var of string
|
||||
| Evariable_already_defined of string
|
||||
| Econst_variable_already_defined of string
|
||||
| Estatic_exp_expected
|
||||
|
||||
let message loc kind =
|
||||
begin match kind with
|
||||
| Evar name ->
|
||||
eprintf "%aThe value identifier %s is unbound.\n"
|
||||
output_location loc
|
||||
name
|
||||
| Econst_var name ->
|
||||
eprintf "%aThe const identifier %s is unbound.\n"
|
||||
output_location loc
|
||||
name
|
||||
| Evariable_already_defined name ->
|
||||
eprintf "%aThe variable %s is already defined.\n"
|
||||
output_location loc
|
||||
name
|
||||
| Econst_variable_already_defined name ->
|
||||
eprintf "%aThe const variable %s is already defined.\n"
|
||||
output_location loc
|
||||
name
|
||||
| Estatic_exp_expected ->
|
||||
eprintf "%aA static expression was expected.\n"
|
||||
output_location loc
|
||||
end;
|
||||
raise Misc.Error
|
||||
end
|
||||
|
||||
module Rename =
|
||||
struct
|
||||
include
|
||||
(Map.Make (struct type t = string let compare = String.compare end))
|
||||
let append env0 env =
|
||||
fold (fun key v env -> add key v env) env0 env
|
||||
|
||||
let name loc env n =
|
||||
try
|
||||
find n env
|
||||
with
|
||||
Not_found -> Error.message loc (Error.Evar(n))
|
||||
end
|
||||
|
||||
(*Functions to build the renaming map*)
|
||||
let add_var loc x env =
|
||||
if Rename.mem x env then
|
||||
Error.message loc (Error.Evariable_already_defined x)
|
||||
else (* create a new id for this var and add it to the env *)
|
||||
Rename.add x (ident_of_var x) env
|
||||
|
||||
let add_const_var loc x env =
|
||||
if NamesEnv.mem x env then
|
||||
Error.message loc (Error.Econst_variable_already_defined x)
|
||||
else (* create a new id for this var and add it to the env *)
|
||||
NamesEnv.add x (ident_of_var x) env
|
||||
|
||||
let rec build_pat loc env = function
|
||||
| Evarpat x -> add_var loc x env
|
||||
| Etuplepat l ->
|
||||
List.fold_left (build_pat loc) env l
|
||||
|
||||
let build_vd_list env l =
|
||||
let build_vd env vd =
|
||||
add_var vd.v_loc vd.v_name env
|
||||
in
|
||||
List.fold_left build_vd env l
|
||||
|
||||
let build_cd_list env l =
|
||||
let build_cd env cd =
|
||||
add_const_var cd.c_loc cd.c_name env
|
||||
in
|
||||
List.fold_left build_cd env l
|
||||
|
||||
let build_id_list loc env l =
|
||||
let build_id env id =
|
||||
add_const_var loc id env
|
||||
in
|
||||
List.fold_left build_id env l
|
||||
|
||||
(* Translate the AST into Heptagon. *)
|
||||
let translate_inlining_policy = function
|
||||
| Ino -> Heptagon.Ino
|
||||
| Ione -> Heptagon.Ione
|
||||
| Irec -> Heptagon.Irec
|
||||
|
||||
let translate_const = function
|
||||
| Cint i -> Heptagon.Cint i
|
||||
| Cfloat f -> Heptagon.Cfloat f
|
||||
| Cconstr ln -> Heptagon.Cconstr ln
|
||||
|
||||
let op_from_app loc app =
|
||||
match app.a_op with
|
||||
| Eop (op,_) -> op_from_app_name op
|
||||
| _ -> Error.message loc Error.Estatic_exp_expected
|
||||
|
||||
let check_const_vars = ref true
|
||||
let rec translate_size_exp const_env e =
|
||||
match e.e_desc with
|
||||
| Evar n ->
|
||||
if !check_const_vars & not (NamesEnv.mem n const_env) then
|
||||
Error.message e.e_loc (Error.Econst_var n)
|
||||
else
|
||||
SVar n
|
||||
| Econst (Cint i) -> SConst i
|
||||
| Eapp(app, [e1;e2]) ->
|
||||
let op = op_from_app e.e_loc app in
|
||||
SOp(op, translate_size_exp const_env e1, translate_size_exp const_env e2)
|
||||
| _ -> Error.message e.e_loc Error.Estatic_exp_expected
|
||||
|
||||
let rec translate_type const_env = function
|
||||
| Tprod ty_list ->
|
||||
Heptagon.Tprod(List.map (translate_type const_env) ty_list)
|
||||
| Tid ln -> Heptagon.Tbase (Heptagon.Tid ln)
|
||||
| Tarray (ty, e) ->
|
||||
let ty = Heptagon.base_type (translate_type const_env ty) in
|
||||
Heptagon.Tbase (Heptagon.Tarray (ty, translate_size_exp const_env e))
|
||||
|
||||
and translate_exp const_env env e =
|
||||
{ Heptagon.e_desc = translate_desc e.e_loc const_env env e.e_desc;
|
||||
Heptagon.e_ty = Heptagon.Tprod [];
|
||||
Heptagon.e_linearity = Linearity.NotLinear;
|
||||
Heptagon.e_loc = e.e_loc }
|
||||
|
||||
and translate_app const_env env app =
|
||||
let op = match app.a_op with
|
||||
| Epre None -> Heptagon.Epre None
|
||||
| Epre (Some c) -> Heptagon.Epre (Some (translate_const c))
|
||||
| Efby -> Heptagon.Efby
|
||||
| Earrow -> Heptagon.Earrow
|
||||
| Eifthenelse -> Heptagon.Eifthenelse
|
||||
| Erepeat -> Heptagon.Erepeat
|
||||
| Eselect_slice -> Heptagon.Eselect_slice
|
||||
| Econcat -> Heptagon.Econcat
|
||||
| Ecopy -> Heptagon.Ecopy
|
||||
| Eselect_dyn -> Heptagon.Eselect_dyn
|
||||
| Enode (ln, params) -> Heptagon.Enode (ln, List.map (translate_size_exp const_env) params)
|
||||
| Eevery (ln, params) -> Heptagon.Eevery (ln, List.map (translate_size_exp const_env) params)
|
||||
| Eop (ln, params) -> Heptagon.Eop (ln, List.map (translate_size_exp const_env) params)
|
||||
| Eselect e_list -> Heptagon.Eselect (List.map (translate_size_exp const_env) e_list)
|
||||
| Eupdate e_list -> Heptagon.Eupdate (List.map (translate_size_exp const_env) e_list)
|
||||
| Eiterator (it, ln, params) ->
|
||||
Heptagon.Eiterator (it, ln, List.map (translate_size_exp const_env) params, None)
|
||||
| Efield_update f -> Heptagon.Efield_update f
|
||||
| Emake f -> Heptagon.Emake f
|
||||
| Eflatten f -> Heptagon.Eflatten f
|
||||
in
|
||||
{ Heptagon.a_op = op;
|
||||
Heptagon.a_inlined = translate_inlining_policy app.a_inlined }
|
||||
|
||||
and translate_desc loc const_env env = function
|
||||
| Econst c -> Heptagon.Econst (translate_const c)
|
||||
| Evar x ->
|
||||
if Rename.mem x env then
|
||||
Heptagon.Evar (Rename.name loc env x)
|
||||
else if NamesEnv.mem x const_env then (* var not defined, maybe a const var*)
|
||||
Heptagon.Econstvar x
|
||||
else
|
||||
Error.message loc (Error.Evar x)
|
||||
| Elast x -> Heptagon.Elast (Rename.name loc env x)
|
||||
| Etuple e_list -> Heptagon.Etuple (List.map (translate_exp const_env env) e_list)
|
||||
| Eapp ({ a_op = Erepeat} as app, e_list) ->
|
||||
let e_list = List.map (translate_exp const_env env) e_list in
|
||||
(match e_list with
|
||||
| [{ Heptagon.e_desc = Heptagon.Econst c }; e1 ] ->
|
||||
Heptagon.Econst (Heptagon.Cconst_array (Heptagon.size_exp_of_exp e1, c))
|
||||
| _ -> Heptagon.Eapp (translate_app const_env env app, e_list)
|
||||
)
|
||||
| Eapp (app, e_list) ->
|
||||
let e_list = List.map (translate_exp const_env env) e_list in
|
||||
Heptagon.Eapp (translate_app const_env env app, e_list)
|
||||
| Efield (e, field) -> Heptagon.Efield (translate_exp const_env env e, field)
|
||||
| Estruct f_e_list ->
|
||||
let f_e_list = List.map (fun (f,e) -> f, translate_exp const_env env e) f_e_list in
|
||||
Heptagon.Estruct f_e_list
|
||||
| Earray e_list -> Heptagon.Earray (List.map (translate_exp const_env env) e_list)
|
||||
|
||||
and translate_pat loc env = function
|
||||
| Evarpat x -> Heptagon.Evarpat (Rename.name loc env x)
|
||||
| Etuplepat l -> Heptagon.Etuplepat (List.map (translate_pat loc env) l)
|
||||
|
||||
let rec translate_eq const_env env eq =
|
||||
{ Heptagon.eq_desc = translate_eq_desc eq.eq_loc const_env env eq.eq_desc ;
|
||||
Heptagon.eq_statefull = false;
|
||||
Heptagon.eq_loc = eq.eq_loc }
|
||||
|
||||
and translate_eq_desc loc const_env env = function
|
||||
| Eswitch(e, switch_handlers) ->
|
||||
Heptagon.Eswitch (translate_exp const_env env e,
|
||||
List.map (translate_switch_handler loc const_env env) switch_handlers)
|
||||
| Eeq(p, e) ->
|
||||
Heptagon.Eeq (translate_pat loc env p, translate_exp const_env env e)
|
||||
| Epresent (present_handlers, b) ->
|
||||
Heptagon.Epresent (List.map (translate_present_handler const_env env) present_handlers,
|
||||
translate_block const_env env b)
|
||||
| Eautomaton state_handlers ->
|
||||
Heptagon.Eautomaton (List.map (translate_state_handler const_env env) state_handlers)
|
||||
| Ereset (eq_list, e) ->
|
||||
Heptagon.Ereset (List.map (translate_eq const_env env) eq_list,
|
||||
translate_exp const_env env e)
|
||||
|
||||
and translate_block const_env env b =
|
||||
let env = build_vd_list env b.b_local in
|
||||
|
||||
{ Heptagon.b_local = translate_vd_list const_env env b.b_local;
|
||||
Heptagon.b_equs = List.map (translate_eq const_env env) b.b_equs;
|
||||
Heptagon.b_defnames = Env.empty ;
|
||||
Heptagon.b_statefull = false;
|
||||
Heptagon.b_loc = b.b_loc }
|
||||
|
||||
and translate_state_handler const_env env sh =
|
||||
{ Heptagon.s_state = sh.s_state;
|
||||
Heptagon.s_block = translate_block const_env env sh.s_block;
|
||||
Heptagon.s_until = List.map (translate_escape const_env env) sh.s_until;
|
||||
Heptagon.s_unless = List.map (translate_escape const_env env) sh.s_unless; }
|
||||
|
||||
and translate_escape const_env env esc =
|
||||
{ Heptagon.e_cond = translate_exp const_env env esc.e_cond;
|
||||
Heptagon.e_reset = esc.e_reset;
|
||||
Heptagon.e_next_state = esc.e_next_state }
|
||||
|
||||
and translate_present_handler const_env env ph =
|
||||
{ Heptagon.p_cond = translate_exp const_env env ph.p_cond;
|
||||
Heptagon.p_block = translate_block const_env env ph.p_block }
|
||||
|
||||
and translate_switch_handler loc const_env env sh =
|
||||
{ Heptagon.w_name = sh.w_name;
|
||||
Heptagon.w_block = translate_block const_env env sh.w_block }
|
||||
|
||||
and translate_var_dec const_env env vd =
|
||||
{ Heptagon.v_name = Rename.name vd.v_loc env vd.v_name;
|
||||
Heptagon.v_type = Heptagon.base_type (translate_type const_env vd.v_type);
|
||||
Heptagon.v_linearity = vd.v_linearity;
|
||||
Heptagon.v_last = translate_last env vd.v_last;
|
||||
Heptagon.v_loc = vd.v_loc }
|
||||
|
||||
and translate_vd_list const_env env =
|
||||
List.map (translate_var_dec const_env env)
|
||||
|
||||
and translate_last env = function
|
||||
| Var -> Heptagon.Var
|
||||
| Last (None) -> Heptagon.Last None
|
||||
| Last (Some c) -> Heptagon.Last (Some (translate_const c))
|
||||
|
||||
let translate_contract const_env env ct =
|
||||
{ Heptagon.c_assume = translate_exp const_env env ct.c_assume;
|
||||
Heptagon.c_enforce = translate_exp const_env env ct.c_enforce;
|
||||
Heptagon.c_controllables = translate_vd_list const_env env ct.c_controllables;
|
||||
Heptagon.c_local = translate_vd_list const_env env ct.c_local;
|
||||
Heptagon.c_eq = List.map (translate_eq const_env env) ct.c_eq }
|
||||
|
||||
let translate_node const_env env node =
|
||||
let const_env = build_id_list node.n_loc const_env node.n_params in
|
||||
let env = build_vd_list env (node.n_input @ node.n_output @ node.n_local) in
|
||||
{ Heptagon.n_name = node.n_name;
|
||||
Heptagon.n_statefull = node.n_statefull;
|
||||
Heptagon.n_input = translate_vd_list const_env env node.n_input;
|
||||
Heptagon.n_output = translate_vd_list const_env env node.n_output;
|
||||
Heptagon.n_local = translate_vd_list const_env env node.n_local;
|
||||
Heptagon.n_contract = Misc.optional (translate_contract const_env env) node.n_contract;
|
||||
Heptagon.n_equs = List.map (translate_eq const_env env) node.n_equs;
|
||||
Heptagon.n_loc = node.n_loc;
|
||||
Heptagon.n_states_graph = Interference_graph.mk_graph [] "";
|
||||
Heptagon.n_params = node.n_params;
|
||||
Heptagon.n_params_constraints = []; }
|
||||
|
||||
let translate_typedec const_env ty =
|
||||
let onetype = function
|
||||
| Type_abs -> Heptagon.Type_abs
|
||||
| Type_enum(tag_list) -> Heptagon.Type_enum(tag_list)
|
||||
| Type_struct(field_ty_list) ->
|
||||
let translate_field_type (f,ty) =
|
||||
f, Heptagon.base_type (translate_type const_env ty)
|
||||
in
|
||||
Heptagon.Type_struct (List.map translate_field_type field_ty_list)
|
||||
in
|
||||
{ Heptagon.t_name = ty.t_name;
|
||||
Heptagon.t_desc = onetype ty.t_desc;
|
||||
Heptagon.t_loc = ty.t_loc }
|
||||
|
||||
let translate_const_dec const_env cd =
|
||||
{ Heptagon.c_name = cd.c_name;
|
||||
Heptagon.c_type = Heptagon.base_type (translate_type const_env cd.c_type);
|
||||
Heptagon.c_value = translate_size_exp const_env cd.c_value;
|
||||
Heptagon.c_loc = cd.c_loc; }
|
||||
|
||||
let translate_program p =
|
||||
let const_env = build_cd_list NamesEnv.empty p.p_consts in
|
||||
{ Heptagon.p_pragmas = p.p_pragmas;
|
||||
Heptagon.p_opened = p.p_opened;
|
||||
Heptagon.p_types = List.map (translate_typedec const_env) p.p_types;
|
||||
Heptagon.p_nodes = List.map (translate_node const_env Rename.empty) p.p_nodes;
|
||||
Heptagon.p_consts = List.map (translate_const_dec const_env) p.p_consts; }
|
||||
|
||||
let translate_signature const_env s =
|
||||
let translate_field_type (f,(ty,lin)) =
|
||||
f, Heptagon.base_type (translate_type const_env ty), lin
|
||||
in
|
||||
|
||||
let const_env = build_id_list no_location const_env s.sig_params in
|
||||
{ Heptagon.sig_name = s.sig_name;
|
||||
Heptagon.sig_inputs = List.map translate_field_type s.sig_inputs;
|
||||
Heptagon.sig_outputs = List.map translate_field_type s.sig_outputs;
|
||||
Heptagon.sig_node = s.sig_node;
|
||||
Heptagon.sig_safe = s.sig_safe;
|
||||
Heptagon.sig_params = s.sig_params; }
|
||||
|
||||
let translate_interface_desc const_env = function
|
||||
| Iopen n -> Heptagon.Iopen n
|
||||
| Itypedef tydec -> Heptagon.Itypedef (translate_typedec const_env tydec)
|
||||
| Isignature s -> Heptagon.Isignature (translate_signature const_env s)
|
||||
|
||||
let translate_interface_decl const_env idecl =
|
||||
{ Heptagon.interf_desc = translate_interface_desc const_env idecl.interf_desc;
|
||||
Heptagon.interf_loc = idecl.interf_loc }
|
||||
|
||||
let translate_interface =
|
||||
List.map (translate_interface_decl NamesEnv.empty)
|
||||
|
459
heptagon/printer.ml
Normal file
459
heptagon/printer.ml
Normal file
|
@ -0,0 +1,459 @@
|
|||
(**************************************************************************)
|
||||
(* *)
|
||||
(* Heptagon *)
|
||||
(* *)
|
||||
(* Author : Marc Pouzet *)
|
||||
(* Organization : Demons, LRI, University of Paris-Sud, Orsay *)
|
||||
(* *)
|
||||
(**************************************************************************)
|
||||
(* the printer *)
|
||||
|
||||
(* $Id$ *)
|
||||
|
||||
open Location
|
||||
open Misc
|
||||
open Names
|
||||
open Ident
|
||||
open Heptagon
|
||||
open Modules
|
||||
open Static
|
||||
open Format
|
||||
|
||||
let rec print_list ff print sep l =
|
||||
match l with
|
||||
| [] -> ()
|
||||
| [x] -> print ff x
|
||||
| x :: l ->
|
||||
print ff x;
|
||||
fprintf ff "%s@ " sep;
|
||||
print_list ff print sep l
|
||||
|
||||
(* Infix chars are surrounded by parenthesis *)
|
||||
let is_infix =
|
||||
let module StrSet = Set.Make(String) in
|
||||
let set_infix =
|
||||
List.fold_right
|
||||
StrSet.add
|
||||
["or"; "quo"; "mod"; "land"; "lor"; "lxor"; "lsl"; "lsr"; "asr"]
|
||||
StrSet.empty in
|
||||
fun s -> StrSet.mem s set_infix
|
||||
|
||||
let print_name ff s =
|
||||
let c = String.get s 0 in
|
||||
let s = if is_infix s then "(" ^ s ^ ")"
|
||||
else match c with
|
||||
| 'a' .. 'z' | 'A' .. 'Z' | '_' | '`' -> s
|
||||
| '*' -> "( " ^ s ^ " )"
|
||||
| _ -> if s = "()" then s else "(" ^ s ^ ")" in
|
||||
fprintf ff "%s" s
|
||||
|
||||
let print_longname ff ln =
|
||||
let ln = currentname ln in
|
||||
match ln with
|
||||
| Name(m) -> print_name ff m
|
||||
| Modname({ qual = "Pervasives"; id = m }) ->
|
||||
print_name ff m
|
||||
| Modname({ qual = m1; id = m2 }) ->
|
||||
fprintf ff "%s." m1; print_name ff m2
|
||||
|
||||
let print_ident ff id =
|
||||
fprintf ff "%s" (name id)
|
||||
|
||||
let print_iterator ff it =
|
||||
fprintf ff "%s" (iterator_to_string it)
|
||||
|
||||
let rec print_pat ff = function
|
||||
| Evarpat(n) -> print_ident ff n
|
||||
| Etuplepat(pat_list) ->
|
||||
fprintf ff "@[(";
|
||||
print_list ff print_pat "," pat_list;
|
||||
fprintf ff ")@]"
|
||||
|
||||
let rec print_base_type ff = function
|
||||
| Tint -> fprintf ff "int"
|
||||
| Tbool -> fprintf ff "bool"
|
||||
| Tfloat -> fprintf ff "float"
|
||||
| Tid(id) -> print_longname ff id
|
||||
| Tarray(ty, e) ->
|
||||
print_base_type ff ty;
|
||||
fprintf ff "^";
|
||||
print_size_exp ff e;
|
||||
|
||||
and print_type ff = function
|
||||
| Tbase(base_ty) -> print_base_type ff base_ty
|
||||
| Tprod(ty_list) ->
|
||||
fprintf ff "@[(";
|
||||
print_list ff print_type " *" ty_list;
|
||||
fprintf ff ")@]"
|
||||
|
||||
and print_c ff = function
|
||||
| Cint i -> fprintf ff "%d" i
|
||||
| Cfloat f -> fprintf ff "%f" f
|
||||
| Cconstr(tag) -> print_longname ff tag
|
||||
| Cconst_array (n, c) ->
|
||||
print_c ff c;
|
||||
fprintf ff "^";
|
||||
print_size_exp ff n
|
||||
|
||||
and print_vd ff { v_name = n; v_type = ty; v_last = last } =
|
||||
fprintf ff "@[<v>";
|
||||
begin match last with Last _ -> fprintf ff "last " | _ -> () end;
|
||||
print_ident ff n;
|
||||
fprintf ff ": ";
|
||||
print_base_type ff ty;
|
||||
begin
|
||||
match last with Last(Some(v)) -> fprintf ff "= ";print_c ff v
|
||||
| _ -> ()
|
||||
end;
|
||||
fprintf ff "@]"
|
||||
|
||||
and print_exps ff e_list =
|
||||
fprintf ff "@[("; print_list ff print_exp "," e_list; fprintf ff ")@]"
|
||||
|
||||
and print_exp ff e =
|
||||
if !Misc.full_type_info then fprintf ff "(";
|
||||
begin match e.e_desc with
|
||||
| Evar x -> print_ident ff x
|
||||
| Econstvar x -> print_name ff x
|
||||
| Elast x -> fprintf ff "last "; print_ident ff x
|
||||
| Econst c -> print_c ff c
|
||||
| Eapp({ a_op = op }, e_list) -> print_op ff op e_list
|
||||
| Etuple(e_list) ->
|
||||
fprintf ff "@[(";
|
||||
print_list ff print_exp "," e_list;
|
||||
fprintf ff ")@]"
|
||||
| Efield(e, field) ->
|
||||
print_exp ff e; fprintf ff ".";
|
||||
print_longname ff field
|
||||
| Estruct(f_e_list) ->
|
||||
fprintf ff "@[<v 1>{";
|
||||
print_list ff
|
||||
(fun ff (field, e) -> print_longname ff field;fprintf ff " = ";
|
||||
print_exp ff e)
|
||||
";" f_e_list;
|
||||
fprintf ff "}@]"
|
||||
| Earray(e_list) ->
|
||||
fprintf ff "@[[";
|
||||
print_list ff print_exp "," e_list;
|
||||
fprintf ff "]@]"
|
||||
| Ereset_mem(y,v,res) ->
|
||||
fprintf ff "@[reset_mem ";
|
||||
print_ident ff y;
|
||||
fprintf ff " = ";
|
||||
print_exp ff v;
|
||||
fprintf ff " every ";
|
||||
print_ident ff res;
|
||||
fprintf ff "@]"
|
||||
end;
|
||||
if !Misc.full_type_info then fprintf ff " : %a)" print_type e.e_ty
|
||||
|
||||
and print_call_params ff = function
|
||||
| [] -> ()
|
||||
| l ->
|
||||
fprintf ff "<<";
|
||||
print_list ff print_size_exp "," l;
|
||||
fprintf ff ">>"
|
||||
|
||||
and print_op ff op e_list =
|
||||
match op, e_list with
|
||||
| Epre(None), [e] -> fprintf ff "pre "; print_exp ff e
|
||||
| Epre(Some(c)), [e] -> print_c ff c; fprintf ff " fby "; print_exp ff e
|
||||
| Efby, [e1;e2] -> print_exp ff e1; fprintf ff " fby "; print_exp ff e2
|
||||
| Earrow, [e1;e2] -> print_exp ff e1; fprintf ff " -> "; print_exp ff e2
|
||||
| Eifthenelse,[e1;e2;e3] ->
|
||||
fprintf ff "@["; fprintf ff "if "; print_exp ff e1;
|
||||
fprintf ff "@ then@ "; print_exp ff e2;
|
||||
fprintf ff "@ else@ "; print_exp ff e3;
|
||||
fprintf ff "@]"
|
||||
| Enode(f, params), e_list ->
|
||||
print_longname ff f;
|
||||
print_call_params ff params;
|
||||
fprintf ff "(@["; print_list ff print_exp "," e_list;
|
||||
fprintf ff ")@]"
|
||||
| Eevery(f,params), e_list ->
|
||||
print_longname ff f;
|
||||
print_call_params ff params;
|
||||
fprintf ff "(@["; print_list ff print_exp "," e_list;
|
||||
fprintf ff ")@]"
|
||||
| Eop(f, params), e_list ->
|
||||
print_longname ff f;
|
||||
print_call_params ff params;
|
||||
fprintf ff "(@["; print_list ff print_exp "," e_list;
|
||||
fprintf ff ")@]"
|
||||
| Erepeat, [e1; e2] ->
|
||||
print_exp ff e1;
|
||||
fprintf ff "^";
|
||||
print_exp ff e2
|
||||
| Eselect idx_list, [e] ->
|
||||
print_exp ff e;
|
||||
fprintf ff "[";
|
||||
print_list ff print_size_exp "][" idx_list;
|
||||
fprintf ff "]"
|
||||
| Eselect_dyn, e::defe::idx_list ->
|
||||
fprintf ff "@[(";
|
||||
print_exp ff e;
|
||||
fprintf ff "[";
|
||||
print_list ff print_exp "][" idx_list;
|
||||
fprintf ff "] default ";
|
||||
print_exp ff defe;
|
||||
fprintf ff ")@]"
|
||||
| Eupdate idx_list, [e1;e2] ->
|
||||
fprintf ff "(@[";
|
||||
print_exp ff e1;
|
||||
fprintf ff " with [";
|
||||
print_list ff print_size_exp "][" idx_list;
|
||||
fprintf ff "] = ";
|
||||
print_exp ff e2;
|
||||
fprintf ff ")@]"
|
||||
| Eselect_slice, [e; idx1; idx2] ->
|
||||
print_exp ff e;
|
||||
fprintf ff "[";
|
||||
print_exp ff idx1;
|
||||
fprintf ff "..";
|
||||
print_exp ff idx2;
|
||||
fprintf ff "]"
|
||||
| Eiterator (it, op, params, reset), e::e_list ->
|
||||
fprintf ff "(";
|
||||
print_iterator ff it;
|
||||
fprintf ff " ";
|
||||
(match params with
|
||||
| [] -> print_longname ff op
|
||||
| l ->
|
||||
fprintf ff "(";
|
||||
print_longname ff op;
|
||||
print_call_params ff params;
|
||||
fprintf ff ")"
|
||||
);
|
||||
fprintf ff " <<";
|
||||
print_exp ff e;
|
||||
fprintf ff ">>) (@[";
|
||||
print_list ff print_exp "," e_list;
|
||||
fprintf ff ")@]";
|
||||
(match reset with
|
||||
| None -> ()
|
||||
| Some r -> fprintf ff " every %a" print_exp r
|
||||
)
|
||||
| Econcat, [e1;e2] ->
|
||||
fprintf ff "@[";
|
||||
print_exp ff e1;
|
||||
fprintf ff " @@ ";
|
||||
print_exp ff e2;
|
||||
fprintf ff "@]"
|
||||
| Ecopy, [e] ->
|
||||
fprintf ff "@[copy (";
|
||||
print_exp ff e;
|
||||
fprintf ff ")@]"
|
||||
| Efield_update f, [e1;e2] ->
|
||||
fprintf ff "(@[";
|
||||
print_exp ff e1;
|
||||
fprintf ff " with .";
|
||||
print_longname ff f;
|
||||
fprintf ff " = ";
|
||||
print_exp ff e2;
|
||||
fprintf ff ")@]"
|
||||
| Eflatten n, e_list ->
|
||||
fprintf ff "@[(flatten ";
|
||||
print_longname ff n;
|
||||
fprintf ff ")(";
|
||||
print_list ff print_exp "," e_list;
|
||||
fprintf ff ")@]"
|
||||
| Emake n, e_list ->
|
||||
fprintf ff "@[(make ";
|
||||
print_longname ff n;
|
||||
fprintf ff ")(";
|
||||
print_list ff print_exp "," e_list;
|
||||
fprintf ff ")@]"
|
||||
| _ -> assert false
|
||||
|
||||
let rec print_eq ff eq =
|
||||
match eq.eq_desc with
|
||||
| Eeq(p, e) ->
|
||||
fprintf ff "@[<hov 2>";
|
||||
print_pat ff p;
|
||||
fprintf ff " =@ ";
|
||||
print_exp ff e;
|
||||
fprintf ff "@]"
|
||||
| Eautomaton(state_handler_list) ->
|
||||
fprintf ff "@[<v>automaton@,";
|
||||
fprintf ff "@[<v>";
|
||||
print_list ff print_state_handler "" state_handler_list;
|
||||
fprintf ff "@]@,";
|
||||
fprintf ff "end@]"
|
||||
| Eswitch(e, switch_handler_list) ->
|
||||
fprintf ff "@[<v>switch ";
|
||||
print_exp ff e;
|
||||
fprintf ff "@,@[<v>";
|
||||
print_list ff print_switch_handler "" switch_handler_list;
|
||||
fprintf ff "@]@,";
|
||||
fprintf ff "end@]"
|
||||
| Epresent(present_handler_list, b) ->
|
||||
fprintf ff "@[<v>present@,";
|
||||
print_list ff print_present_handler "" present_handler_list;
|
||||
if b.b_equs <> [] then begin
|
||||
fprintf ff " @[<v 2>default@,";
|
||||
print_block ff b;
|
||||
fprintf ff "@]"
|
||||
end;
|
||||
fprintf ff "@,end@]"
|
||||
| Ereset(eq_list, e) ->
|
||||
fprintf ff "@[<v>reset@,";
|
||||
fprintf ff " @[<v>";
|
||||
print_eq_list ff eq_list;
|
||||
fprintf ff "@]";
|
||||
fprintf ff "@,every ";
|
||||
print_exp ff e;
|
||||
fprintf ff "@]"
|
||||
|
||||
and print_eq_list ff = function
|
||||
| [] -> ()
|
||||
| [eq] -> print_eq ff eq;fprintf ff ";"
|
||||
| eq :: l -> print_eq ff eq;fprintf ff ";@,";print_eq_list ff l
|
||||
|
||||
and print_state_handler ff
|
||||
{ s_state = s; s_block = b; s_until = until; s_unless = unless } =
|
||||
fprintf ff " @[<v 2>state ";
|
||||
fprintf ff "%s@," s;
|
||||
print_block ff b;
|
||||
if until <> [] then
|
||||
begin
|
||||
fprintf ff "@,@[<v 2>until ";
|
||||
print_list ff print_escape "" until;
|
||||
fprintf ff "@]"
|
||||
end;
|
||||
if unless <> [] then
|
||||
begin
|
||||
fprintf ff "@,@[<v 2>unless ";
|
||||
print_list ff print_escape " " unless;
|
||||
fprintf ff "@]"
|
||||
end;
|
||||
fprintf ff "@]"
|
||||
|
||||
and print_switch_handler ff { w_name = tag; w_block = b } =
|
||||
fprintf ff " @[<v 2>| ";
|
||||
print_longname ff tag;
|
||||
fprintf ff "@,";
|
||||
print_block ff b;
|
||||
fprintf ff "@]"
|
||||
|
||||
and print_present_handler ff { p_cond = e; p_block = b } =
|
||||
fprintf ff " @[<v 2>| ";
|
||||
print_exp ff e;
|
||||
fprintf ff "@,";
|
||||
print_block ff b;
|
||||
fprintf ff "@]"
|
||||
|
||||
and print_escape ff { e_cond = e; e_reset = r; e_next_state = ns} =
|
||||
fprintf ff "@,| ";
|
||||
print_exp ff e;
|
||||
if r then fprintf ff " then " else fprintf ff " continue ";
|
||||
print_name ff ns
|
||||
|
||||
and print_block ff { b_local = v_list; b_equs = eqs; b_defnames = defnames } =
|
||||
if v_list <> [] then
|
||||
begin
|
||||
fprintf ff "@[<v 2>var ";
|
||||
print_list ff print_vd ";" v_list;
|
||||
fprintf ff "@]@,"
|
||||
end;
|
||||
(* (\* DEBUG *\) *)
|
||||
(* fprintf ff "@[<hov 2>defines @,"; *)
|
||||
(* Env.iter (fun n t -> fprintf ff "%s," n) defnames; *)
|
||||
(* fprintf ff "@]@\n"; *)
|
||||
(* (\* END DEBUG *\) *)
|
||||
fprintf ff "@[<v 2>do@,";
|
||||
print_eq_list ff eqs;
|
||||
fprintf ff "@]"
|
||||
|
||||
let print_type_def ff { t_name = name; t_desc = tdesc } =
|
||||
match tdesc with
|
||||
| Type_abs -> fprintf ff "@[type %s@\n@]" name
|
||||
| Type_enum(tag_name_list) ->
|
||||
fprintf ff "@[type %s = " name;
|
||||
print_list ff print_name "| " tag_name_list;
|
||||
fprintf ff "@\n@]"
|
||||
| Type_struct(f_ty_list) ->
|
||||
fprintf ff "@[type %s = " name;
|
||||
fprintf ff "@[<v 1>{";
|
||||
print_list ff
|
||||
(fun ff (field, ty) ->
|
||||
print_name ff field;
|
||||
fprintf ff ": ";
|
||||
print_base_type ff ty) ";" f_ty_list;
|
||||
fprintf ff "}@]@.@]"
|
||||
|
||||
let print_const_dec ff c =
|
||||
fprintf ff "@[const ";
|
||||
print_name ff c.c_name;
|
||||
fprintf ff " : ";
|
||||
print_base_type ff c.c_type;
|
||||
fprintf ff " = ";
|
||||
print_size_exp ff c.c_value;
|
||||
fprintf ff "@.@]"
|
||||
|
||||
let print_contract ff {c_local = l;
|
||||
c_eq = eqs;
|
||||
c_assume = e_a;
|
||||
c_enforce = e_g;
|
||||
c_controllables = cl } =
|
||||
if l <> [] then begin
|
||||
fprintf ff "@[<v 2>contract@\n";
|
||||
fprintf ff "@[<hov 4>var ";
|
||||
print_list ff print_vd ";" l;
|
||||
fprintf ff ";@]@\n"
|
||||
end;
|
||||
if eqs <> [] then begin
|
||||
fprintf ff "@[<v 2>let @,";
|
||||
print_eq_list ff eqs;
|
||||
fprintf ff "@]"; fprintf ff "tel@\n"
|
||||
end;
|
||||
fprintf ff "assume %a@;enforce %a@;with (@[<hov>"
|
||||
print_exp e_a
|
||||
print_exp e_g;
|
||||
print_list ff print_vd ";" cl;
|
||||
fprintf ff "@])@]@\n"
|
||||
|
||||
let print_node_params ff = function
|
||||
| [] -> ()
|
||||
| l ->
|
||||
fprintf ff "<<";
|
||||
print_list ff print_name "," l;
|
||||
fprintf ff ">>"
|
||||
|
||||
let print_node ff
|
||||
{ n_name = n; n_statefull = statefull; n_input = ni;
|
||||
n_local = nl; n_output = no; n_contract = contract; n_equs = ne;
|
||||
n_params = params; } =
|
||||
fprintf ff "@[<v 2>%s " (if statefull then "node" else "fun");
|
||||
print_name ff n;
|
||||
print_node_params ff params;
|
||||
fprintf ff "(@[";
|
||||
print_list ff print_vd ";" ni;
|
||||
fprintf ff "@]) returns (@[";
|
||||
print_list ff print_vd ";" no;
|
||||
fprintf ff "@])@,";
|
||||
optunit (print_contract ff) contract;
|
||||
if nl <> [] then begin
|
||||
fprintf ff "@[<hov 4>var ";
|
||||
print_list ff print_vd ";" nl;
|
||||
fprintf ff ";@]@,"
|
||||
end;
|
||||
fprintf ff "@[<v 2>let @,";
|
||||
print_eq_list ff ne;
|
||||
fprintf ff "@]@;"; fprintf ff "tel";fprintf ff "@.@]"
|
||||
|
||||
let print_open_module ff name =
|
||||
fprintf ff "@[open ";
|
||||
print_name ff name;
|
||||
fprintf ff "@.@]"
|
||||
|
||||
let ptype oc ty =
|
||||
let ff = formatter_of_out_channel oc in
|
||||
print_type ff ty; fprintf ff "@?"
|
||||
|
||||
let print oc { p_opened = po; p_types = pt; p_nodes = pn; p_consts = pc } =
|
||||
let ff = formatter_of_out_channel oc in
|
||||
List.iter (print_open_module ff) po;
|
||||
List.iter (print_const_dec ff) pc;
|
||||
List.iter (print_type_def ff) pt;
|
||||
List.iter (print_node ff) pn;
|
||||
fprintf ff "@?"
|
204
heptagon/transformations/automata.ml
Normal file
204
heptagon/transformations/automata.ml
Normal file
|
@ -0,0 +1,204 @@
|
|||
(**************************************************************************)
|
||||
(* *)
|
||||
(* Heptagon *)
|
||||
(* *)
|
||||
(* Author : Marc Pouzet *)
|
||||
(* Organization : Demons, LRI, University of Paris-Sud, Orsay *)
|
||||
(* *)
|
||||
(**************************************************************************)
|
||||
(* removing automata statements *)
|
||||
|
||||
(* $Id$ *)
|
||||
|
||||
open Location
|
||||
open Misc
|
||||
open Names
|
||||
open Ident
|
||||
open Heptagon
|
||||
open Global
|
||||
open Initial
|
||||
open Interference_graph
|
||||
|
||||
let rename_states env g =
|
||||
let rename_one n =
|
||||
try
|
||||
let olds = List.hd n.g_content in
|
||||
let s = NamesEnv.find olds env in
|
||||
Hashtbl.remove g.g_hash olds;
|
||||
Hashtbl.add g.g_hash s n;
|
||||
n.g_content <- [s]
|
||||
with Not_found -> ()
|
||||
in
|
||||
List.iter rename_one g.g_nodes
|
||||
|
||||
(* the list of enumerated types introduced to represent states *)
|
||||
let state_type_dec_list = ref []
|
||||
|
||||
let intro_type states =
|
||||
let list env = NamesEnv.fold (fun _ state l -> state :: l) env [] in
|
||||
let n = gen_symbol () in
|
||||
let state_type = "st" ^ n in
|
||||
state_type_dec_list :=
|
||||
(tmake state_type (Type_enum(list states))) :: !state_type_dec_list;
|
||||
Name(state_type)
|
||||
|
||||
(* an automaton may be a Moore automaton, i.e., with only weak transitions; *)
|
||||
(* a Mealy one, i.e., with only strong transition or mixed *)
|
||||
let moore_mealy state_handlers =
|
||||
let handler (moore, mealy) { s_until = l1; s_unless = l2 } =
|
||||
(moore or (l1 <> []), mealy or (l2 <> [])) in
|
||||
List.fold_left handler (false, false) state_handlers
|
||||
|
||||
let rec translate_eq g (v, eq_list) eq =
|
||||
match eq.eq_desc with
|
||||
Eautomaton(state_handlers) ->
|
||||
translate_automaton g v eq_list state_handlers
|
||||
| Eswitch(e, switch_handlers) ->
|
||||
v,
|
||||
{ eq with eq_desc =
|
||||
Eswitch(e, translate_switch_handlers g switch_handlers) }
|
||||
:: eq_list
|
||||
| Epresent(present_handlers, block) ->
|
||||
v, { eq with eq_desc =
|
||||
Epresent(translate_present_handlers g present_handlers,
|
||||
translate_block g block) } :: eq_list
|
||||
| Ereset(r_eq_list, e) ->
|
||||
let v, r_eq_list = translate_eqs g v r_eq_list in
|
||||
v, { eq with eq_desc = Ereset(r_eq_list, e) } :: eq_list
|
||||
| Eeq _ -> v, eq :: eq_list
|
||||
|
||||
and translate_eqs g v eq_list = List.fold_left (translate_eq g) (v, []) eq_list
|
||||
|
||||
and translate_block g ({ b_local = v; b_equs = eq_list } as b) =
|
||||
let v, eq_list = translate_eqs g v eq_list in
|
||||
{ b with b_local = v; b_equs = eq_list }
|
||||
|
||||
and translate_switch_handlers g handlers =
|
||||
let translate_switch_handler { w_name = n; w_block = b } =
|
||||
{ w_name = n; w_block = translate_block g b } in
|
||||
List.map translate_switch_handler handlers
|
||||
|
||||
and translate_present_handlers g handlers =
|
||||
let translate_present_handler { p_cond = e; p_block = b } =
|
||||
{ p_cond = e; p_block = translate_block g b } in
|
||||
List.map translate_present_handler handlers
|
||||
|
||||
and translate_automaton g v eq_list handlers =
|
||||
let has_until, has_unless = moore_mealy handlers in
|
||||
let states =
|
||||
let suffix = gen_symbol () in
|
||||
List.fold_left
|
||||
(fun env { s_state = n } -> NamesEnv.add n (n ^ suffix) env)
|
||||
NamesEnv.empty handlers in
|
||||
|
||||
let statetype = intro_type states in
|
||||
let tstatetype = Tbase(Tid(statetype)) in
|
||||
let initial = Name(NamesEnv.find (List.hd handlers).s_state states) in
|
||||
|
||||
let statename = Ident.fresh "s" in
|
||||
let next_statename = Ident.fresh "ns" in
|
||||
let resetname = Ident.fresh "r" in
|
||||
let next_resetname = Ident.fresh "nr" in
|
||||
let pre_next_resetname = Ident.fresh "pnr" in
|
||||
|
||||
(* update the states graph with the suffixed names *)
|
||||
rename_states states g;
|
||||
|
||||
let name n = Name(NamesEnv.find n states) in
|
||||
let state n =
|
||||
emake (Econst(Cconstr(name n))) tstatetype in
|
||||
let statevar n = var n tstatetype in
|
||||
let boolvar n = var n tybool in
|
||||
|
||||
let escapes n s rcont =
|
||||
let escape { e_cond = e; e_reset = r; e_next_state = n } cont =
|
||||
ifthenelse e (pair (state n) (if r then dtrue else dfalse)) cont in
|
||||
List.fold_right escape s (pair (state n) rcont) in
|
||||
let strong { s_state = n; s_unless = su } =
|
||||
block
|
||||
(Env.add statename tstatetype
|
||||
(Env.add resetname tybool Env.empty))
|
||||
([reset(
|
||||
[eq (Etuplepat[Evarpat(statename);Evarpat(resetname)])
|
||||
(escapes n su (boolvar pre_next_resetname))])
|
||||
(boolvar pre_next_resetname)]) in
|
||||
|
||||
let weak { s_state = n; s_block = b; s_until = su } =
|
||||
let b = translate_block g b in
|
||||
{ b with b_equs =
|
||||
[reset ((eq (Etuplepat[Evarpat(next_statename);
|
||||
Evarpat(next_resetname)])
|
||||
(escapes n su dfalse)) :: b.b_equs)
|
||||
(boolvar resetname)];
|
||||
(* (or_op (boolvar pre_next_resetname) (boolvar resetname))]; *)
|
||||
b_defnames =
|
||||
Env.add next_statename tstatetype
|
||||
(Env.add next_resetname tybool
|
||||
b.b_defnames)
|
||||
} in
|
||||
let v =
|
||||
(param next_statename (Tid(statetype))) ::
|
||||
(param resetname tbool) ::
|
||||
(param next_resetname tbool) ::
|
||||
(param pre_next_resetname tbool) :: v in
|
||||
(* we optimise the case of an only strong automaton *)
|
||||
(* or only weak automaton *)
|
||||
match has_until, has_unless with
|
||||
| true, false ->
|
||||
(* a Moore automaton with only weak transitions *)
|
||||
v, (switch (fby_state initial (statevar next_statename))
|
||||
(List.map
|
||||
(fun ({ s_state = n } as case) ->
|
||||
{ w_name = name n; w_block = weak case })
|
||||
handlers)) ::
|
||||
(eq (Evarpat pre_next_resetname)
|
||||
(fby_false (boolvar (next_resetname)))) ::
|
||||
(eq (Evarpat resetname) (boolvar pre_next_resetname)) :: eq_list
|
||||
| _ ->
|
||||
(* the general case; two switch to generate,
|
||||
statename variable used and defined *)
|
||||
(param statename (Tid(statetype))) :: v,
|
||||
(switch (fby_state initial (statevar next_statename))
|
||||
(List.map
|
||||
(fun ({ s_state = n } as case) ->
|
||||
{ w_name = name n; w_block = strong case })
|
||||
handlers)) ::
|
||||
(switch (statevar statename)
|
||||
(List.map
|
||||
(fun ({ s_state = n } as case) ->
|
||||
{ w_name = name n; w_block = weak case })
|
||||
handlers)) ::
|
||||
(eq (Evarpat pre_next_resetname)
|
||||
(fby_false (boolvar (next_resetname)))) ::
|
||||
eq_list
|
||||
|
||||
let translate_contract g ({ c_local = v; c_eq = eq_list} as c) =
|
||||
let v, eq_list = translate_eqs g v eq_list in
|
||||
{ c with c_local = v; c_eq = eq_list }
|
||||
|
||||
let node ({ n_local = v; n_equs = eq_list; n_contract = contract; n_states_graph = g } as n) =
|
||||
let v, eq_list = translate_eqs g v eq_list in
|
||||
let contract = optional (translate_contract g) contract in
|
||||
{ n with n_local = v; n_equs = eq_list; n_contract = contract }
|
||||
|
||||
let program ({ p_types = pt_list; p_nodes = n_list } as p) =
|
||||
let n_list = List.map node n_list in
|
||||
{ p with p_types = !state_type_dec_list @ pt_list;
|
||||
p_nodes = n_list }
|
||||
|
||||
(*
|
||||
A -> do ... unless c1 then A1 ... until c'1 then A'1 ...
|
||||
|
||||
match A fby next_state with
|
||||
A -> resA = pre_next_res or (if c1 then ... else ..
|
||||
|
||||
match state with
|
||||
A -> reset
|
||||
next_res = if c'1 then true else ... else false
|
||||
every resA
|
||||
|
||||
if faut donc: - une memoire pour pre(next_res) + n memoires (pre(resA),...)
|
||||
|
||||
merge state
|
||||
(A -> reset ... when A(state) every pre_next_res or res)
|
||||
*)
|
86
heptagon/transformations/completion.ml
Normal file
86
heptagon/transformations/completion.ml
Normal file
|
@ -0,0 +1,86 @@
|
|||
(**************************************************************************)
|
||||
(* *)
|
||||
(* Heptagon *)
|
||||
(* *)
|
||||
(* Author : Marc Pouzet *)
|
||||
(* Organization : Demons, LRI, University of Paris-Sud, Orsay *)
|
||||
(* *)
|
||||
(**************************************************************************)
|
||||
(* complete partial definitions with [x = last(x)] *)
|
||||
|
||||
(* $Id$ *)
|
||||
|
||||
open Location
|
||||
open Ident
|
||||
open Misc
|
||||
open Heptagon
|
||||
open Global
|
||||
|
||||
(* adds an equation [x = last(x)] for every partially defined variable *)
|
||||
(* in a control structure *)
|
||||
let complete_with_last defined_names local_defined_names eq_list =
|
||||
let last n ty =
|
||||
{ e_desc = Elast(n); e_ty = ty; e_linearity = Linearity.NotLinear;
|
||||
e_loc = no_location } in
|
||||
let equation n ty eq_list =
|
||||
{ eq_desc = Eeq(Evarpat(n), last n ty); eq_statefull = false;
|
||||
eq_loc = no_location } :: eq_list in
|
||||
let d = Env.diff defined_names local_defined_names in
|
||||
Env.fold equation d eq_list
|
||||
|
||||
let rec translate_eq eq =
|
||||
match eq.eq_desc with
|
||||
| Ereset(eq_list, e) ->
|
||||
{ eq with eq_desc = Ereset(translate_eqs eq_list, e) }
|
||||
| Eeq(pat, e) ->
|
||||
{ eq with eq_desc = Eeq(pat, e) }
|
||||
| Eswitch(e, switch_handlers) ->
|
||||
let defnames =
|
||||
List.fold_left
|
||||
(fun acc { w_block = { b_defnames = d } } -> Env.union acc d)
|
||||
Env.empty switch_handlers in
|
||||
let switch_handlers =
|
||||
List.map (fun ({ w_block = b } as handler) ->
|
||||
{ handler with w_block = translate_block defnames b })
|
||||
switch_handlers in
|
||||
{ eq with eq_desc = Eswitch(e, switch_handlers) }
|
||||
| Epresent(present_handlers, b) ->
|
||||
let defnames =
|
||||
List.fold_left
|
||||
(fun acc { p_block = { b_defnames = d } } -> Env.union acc d)
|
||||
b.b_defnames present_handlers in
|
||||
let present_handlers =
|
||||
List.map (fun ({ p_block = b } as handler) ->
|
||||
{ handler with p_block = translate_block defnames b })
|
||||
present_handlers in
|
||||
let b = translate_block defnames b in
|
||||
{eq with eq_desc = Epresent(present_handlers, b)}
|
||||
| Eautomaton(state_handlers) ->
|
||||
let defnames =
|
||||
List.fold_left
|
||||
(fun acc { s_block = { b_defnames = d } } -> Env.union acc d)
|
||||
Env.empty state_handlers in
|
||||
let state_handlers =
|
||||
List.map (fun ({ s_block = b } as handler) ->
|
||||
{ handler with s_block = translate_block defnames b })
|
||||
state_handlers in
|
||||
{ eq with eq_desc = Eautomaton(state_handlers) }
|
||||
|
||||
and translate_eqs eq_list = List.map translate_eq eq_list
|
||||
|
||||
and translate_block defnames
|
||||
({ b_defnames = bdefnames; b_equs = eq_list } as b) =
|
||||
let eq_list = translate_eqs eq_list in
|
||||
let eq_list = complete_with_last defnames bdefnames eq_list in
|
||||
{ b with b_equs = eq_list; b_defnames = defnames }
|
||||
|
||||
let translate_contract ({ c_eq = eqs } as c) =
|
||||
{ c with c_eq = translate_eqs eqs }
|
||||
|
||||
let node ({ n_equs = eq_list; n_contract = contract } as n) =
|
||||
{ n with
|
||||
n_equs = translate_eqs eq_list;
|
||||
n_contract = optional translate_contract contract }
|
||||
|
||||
let program ({ p_types = pt_list; p_nodes = n_list } as p) =
|
||||
{ p with p_types = pt_list; p_nodes = List.map node n_list }
|
175
heptagon/transformations/every.ml
Normal file
175
heptagon/transformations/every.ml
Normal file
|
@ -0,0 +1,175 @@
|
|||
(**************************************************************************)
|
||||
(* *)
|
||||
(* Heptagon *)
|
||||
(* *)
|
||||
(* Author : Marc Pouzet *)
|
||||
(* Organization : Demons, LRI, University of Paris-Sud, Orsay *)
|
||||
(* *)
|
||||
(**************************************************************************)
|
||||
|
||||
(* removing complex reset expressions :
|
||||
equations
|
||||
x = (f every e) e'
|
||||
-->
|
||||
r = e;
|
||||
x = (f every r) e'
|
||||
*)
|
||||
|
||||
(* $Id$ *)
|
||||
|
||||
open Location
|
||||
open Misc
|
||||
open Ident
|
||||
open Heptagon
|
||||
open Global
|
||||
open Initial
|
||||
open Reset
|
||||
|
||||
let eq pat e =
|
||||
{ eq_desc = Eeq(pat, e); eq_statefull = false; eq_loc = no_location }
|
||||
let statefulleq = Heptagon.eq
|
||||
|
||||
(* add an equation *)
|
||||
let equation v acc_eq_list e =
|
||||
let n = Ident.fresh "r" in
|
||||
n,
|
||||
(bool_param n) :: v,
|
||||
{ eq_desc = Eeq(Evarpat(n), e); eq_statefull = true; eq_loc = e.e_loc } ::
|
||||
acc_eq_list
|
||||
|
||||
let orthen v acc_eq_list res e =
|
||||
match e.e_desc with
|
||||
Evar(n) -> v, acc_eq_list, Rorthen(res, n)
|
||||
| _ ->
|
||||
let n, v, acc_eq_list = equation v acc_eq_list e in
|
||||
v, acc_eq_list, Rorthen(res, n)
|
||||
|
||||
let add_locals m n locals =
|
||||
let rec loop locals i n =
|
||||
if i < n then
|
||||
loop ((bool_param m.(i)) :: locals) (i+1) n
|
||||
else locals in
|
||||
loop locals 0 n
|
||||
|
||||
(*
|
||||
let defnames m n d =
|
||||
let rec loop acc k = if k < n then loop (S.add m.(k) acc) (k+1) else acc in
|
||||
loop d 0
|
||||
*)
|
||||
|
||||
let statefull eq_list = List.exists (fun eq -> eq.eq_statefull) eq_list
|
||||
|
||||
let is_var = function
|
||||
| { e_desc = Evar(_) } -> true
|
||||
| _ -> false
|
||||
|
||||
let rec translate_eq v acc_eq_list eq =
|
||||
match eq.eq_desc with
|
||||
| Eeq(pat, e) ->
|
||||
let v,acc_eq_list,e = translate v acc_eq_list e in
|
||||
v, { eq with eq_desc = Eeq(pat, e) } :: acc_eq_list
|
||||
| Eswitch(e, tag_block_list) ->
|
||||
let v,acc_eq_list,e = translate v acc_eq_list e in
|
||||
let tag_block_list, acc_eq_list =
|
||||
translate_switch acc_eq_list tag_block_list in
|
||||
v, { eq with eq_desc = Eswitch(e, tag_block_list) } :: acc_eq_list
|
||||
| Ereset _ | Epresent _ | Eautomaton _ -> assert false
|
||||
|
||||
and translate_eqs v acc_eq_list eq_list =
|
||||
List.fold_left
|
||||
(fun (v,acc_eq_list) eq ->
|
||||
translate_eq v acc_eq_list eq) (v,acc_eq_list) eq_list
|
||||
|
||||
and translate_switch acc_eq_list switch_handlers =
|
||||
|
||||
let body {w_name = c;
|
||||
w_block = ({ b_local = lv; b_defnames = d; b_equs = eqs } as b)} =
|
||||
let lv,eqs = translate_eqs lv [] eqs in
|
||||
{ w_name = c;
|
||||
w_block = { b with b_local = lv; b_defnames = d; b_equs = eqs } } in
|
||||
|
||||
let rec loop switch_handlers =
|
||||
match switch_handlers with
|
||||
[] -> []
|
||||
| handler :: switch_handlers ->
|
||||
(body handler) :: (loop switch_handlers) in
|
||||
|
||||
loop switch_handlers, acc_eq_list
|
||||
|
||||
and translate v acc_eq_list e =
|
||||
match e.e_desc with
|
||||
Econst _ | Evar _ | Econstvar _ | Elast _ -> v,acc_eq_list,e
|
||||
| Etuple(e_list) ->
|
||||
let v, acc_eq_list,e_list = translate_list v acc_eq_list e_list in
|
||||
v,acc_eq_list,
|
||||
{ e with e_desc = Etuple(e_list) }
|
||||
| Eapp({ a_op = Eevery(f,params) } as op, re :: e_list)
|
||||
when not (is_var re) ->
|
||||
let v, acc_eq_list,re = translate v acc_eq_list re in
|
||||
let n, v, acc_eq_list = equation v acc_eq_list re in
|
||||
let v, acc_eq_list, e_list = translate_list v acc_eq_list e_list in
|
||||
v,acc_eq_list,
|
||||
{ e with e_desc =
|
||||
Eapp({ op with a_op = Eevery(f,params) },
|
||||
{ re with e_desc = Evar(n) } :: e_list) }
|
||||
| Eapp({ a_op = Eiterator(it, f, params, Some re) } as op, e_list)
|
||||
when not (is_var re) ->
|
||||
let v, acc_eq_list,re = translate v acc_eq_list re in
|
||||
let n, v, acc_eq_list = equation v acc_eq_list re in
|
||||
let v, acc_eq_list, e_list = translate_list v acc_eq_list e_list in
|
||||
let re = { re with e_desc = Evar n } in
|
||||
v,acc_eq_list,
|
||||
{ e with e_desc =
|
||||
Eapp({ op with a_op = Eiterator(it, f, params, Some re) },e_list) }
|
||||
| Eapp(f, e_list) ->
|
||||
let v, acc_eq_list, e_list = translate_list v acc_eq_list e_list in
|
||||
v, acc_eq_list,
|
||||
{ e with e_desc = Eapp(f, e_list) }
|
||||
| Efield(e', field) ->
|
||||
let v, acc_eq_list, e' = translate v acc_eq_list e' in
|
||||
v,acc_eq_list,
|
||||
{ e with e_desc = Efield(e', field) }
|
||||
| Estruct(e_f_list) ->
|
||||
let v,acc_eq_list,e_f_list =
|
||||
List.fold_left
|
||||
(fun (v,acc_eq_list,acc_e_f) (f,e) ->
|
||||
let v,acc_eq_list,e = translate v acc_eq_list e in
|
||||
(v,acc_eq_list,(f,e)::acc_e_f))
|
||||
(v,acc_eq_list,[]) e_f_list in
|
||||
v,acc_eq_list,
|
||||
{ e with e_desc = Estruct(List.rev e_f_list) }
|
||||
| Earray(e_list) ->
|
||||
let v, acc_eq_list,e_list = translate_list v acc_eq_list e_list in
|
||||
v,acc_eq_list,
|
||||
{ e with e_desc = Earray(e_list) }
|
||||
| Ereset_mem _ -> v,acc_eq_list,e
|
||||
|
||||
and translate_list v acc_eq_list e_list =
|
||||
let v,acc_eq_list,acc_e =
|
||||
List.fold_left
|
||||
(fun (v,acc_eq_list,acc_e) e ->
|
||||
let v,acc_eq_list,e = translate v acc_eq_list e in
|
||||
(v,acc_eq_list,e::acc_e))
|
||||
(v,acc_eq_list,[]) e_list in
|
||||
v,acc_eq_list,List.rev acc_e
|
||||
|
||||
let translate_contract ({ c_local = v;
|
||||
c_eq = eq_list;
|
||||
c_assume = e_a;
|
||||
c_enforce = e_g } as c) =
|
||||
let v,acc_eq,e_a = translate v [] e_a in
|
||||
let v,acc_eq,e_g = translate v acc_eq e_g in
|
||||
let v, eq_list = translate_eqs v acc_eq eq_list in
|
||||
{ c with
|
||||
c_local = v;
|
||||
c_eq = eq_list;
|
||||
c_assume = e_a;
|
||||
c_enforce = e_g }
|
||||
|
||||
let node ({ n_local = v; n_equs = eq_list; n_contract = contract } as n) =
|
||||
let contract = optional translate_contract contract in
|
||||
let v, eq_list = translate_eqs v [] eq_list in
|
||||
{ n with n_local = v; n_equs = eq_list; n_contract = contract }
|
||||
|
||||
let program ({ p_types = pt_list; p_nodes = n_list } as p) =
|
||||
{ p with p_types = pt_list; p_nodes = List.map node n_list }
|
111
heptagon/transformations/last.ml
Normal file
111
heptagon/transformations/last.ml
Normal file
|
@ -0,0 +1,111 @@
|
|||
(**************************************************************************)
|
||||
(* *)
|
||||
(* Heptagon *)
|
||||
(* *)
|
||||
(* Author : Marc Pouzet *)
|
||||
(* Organization : Demons, LRI, University of Paris-Sud, Orsay *)
|
||||
(* *)
|
||||
(**************************************************************************)
|
||||
(* removing accessed to shared variables (last x) *)
|
||||
|
||||
(* $Id$ *)
|
||||
|
||||
open Location
|
||||
open Misc
|
||||
open Ident
|
||||
open Heptagon
|
||||
open Global
|
||||
|
||||
(* introduce a fresh equation [last_x = pre(x)] for every *)
|
||||
(* variable declared with a last *)
|
||||
let last (eq_list, env, v) { v_name = n; v_type = t; v_last = last } =
|
||||
match last with
|
||||
| Var -> (eq_list, env, v)
|
||||
| Last(default) ->
|
||||
let lastn = Ident.fresh ("last" ^ (sourcename n)) in
|
||||
(eqmake (Eeq(Evarpat(lastn),
|
||||
emake
|
||||
(Eapp (eop (Epre(default)),
|
||||
[emake (Evar(n)) (Tbase(t))]))
|
||||
(Tbase(t)))))
|
||||
:: eq_list,
|
||||
Env.add n lastn env,
|
||||
(param lastn t) :: v
|
||||
|
||||
let extend_env env v = List.fold_left last ([], env, []) v
|
||||
|
||||
let rec translate_eq env eq =
|
||||
match eq.eq_desc with
|
||||
| Ereset(eq_list, e) ->
|
||||
{ eq with eq_desc = Ereset(translate_eqs env eq_list, translate env e) }
|
||||
| Eeq(pat, e) ->
|
||||
{ eq with eq_desc = Eeq(pat, translate env e) }
|
||||
| Eswitch(e, handler_list) ->
|
||||
let handler_list =
|
||||
List.map (fun ({ w_block = b } as handler) ->
|
||||
{ handler with w_block = translate_block env b })
|
||||
handler_list in
|
||||
{ eq with eq_desc = Eswitch(translate env e, handler_list) }
|
||||
| Epresent _ | Eautomaton _ -> assert false
|
||||
|
||||
and translate_eqs env eq_list = List.map (translate_eq env) eq_list
|
||||
|
||||
and translate_block env ({ b_local = v; b_equs = eq_list } as b) =
|
||||
let eq_lastn_n_list, env, last_v = extend_env env v in
|
||||
let eq_list = translate_eqs env eq_list in
|
||||
{ b with b_local = v @ last_v; b_equs = eq_lastn_n_list @ eq_list }
|
||||
|
||||
and translate env e =
|
||||
match e.e_desc with
|
||||
Econst _ | Evar _ | Econstvar _ -> e
|
||||
| Elast(x) ->
|
||||
let lx = Env.find x env in { e with e_desc = Evar(lx) }
|
||||
| Etuple(e_list) ->
|
||||
{ e with e_desc = Etuple(List.map (translate env) e_list) }
|
||||
| Eapp(op, e_list) ->
|
||||
{ e with e_desc = Eapp(op, List.map (translate env) e_list) }
|
||||
| Efield(e', field) ->
|
||||
{ e with e_desc = Efield(translate env e', field) }
|
||||
| Estruct(e_f_list) ->
|
||||
{ e with e_desc =
|
||||
Estruct(List.map (fun (f, e) -> (f, translate env e)) e_f_list) }
|
||||
| Earray(e_list) ->
|
||||
{ e with e_desc = Earray(List.map (translate env) e_list) }
|
||||
| Ereset_mem _ -> assert false
|
||||
|
||||
let translate_contract env contract =
|
||||
match contract with
|
||||
| None -> None, env
|
||||
| Some { c_local = v;
|
||||
c_eq = eq_list;
|
||||
c_assume = e_a;
|
||||
c_enforce = e_g;
|
||||
c_controllables = cl } ->
|
||||
let _, env, _ = extend_env env cl in
|
||||
let eq_lastn_n_list, env', last_v = extend_env env v in
|
||||
let eq_list = translate_eqs env' eq_list in
|
||||
let e_a = translate env' e_a in
|
||||
let e_g = translate env' e_g in
|
||||
Some { c_local = v @ last_v;
|
||||
c_eq = eq_lastn_n_list @ eq_list;
|
||||
c_assume = e_a;
|
||||
c_enforce = e_g;
|
||||
c_controllables = List.rev cl },
|
||||
env
|
||||
|
||||
let node ({ n_input = i; n_local = v; n_output = o;
|
||||
n_equs = eq_list; n_contract = contract } as n) =
|
||||
let _, env, _ = extend_env Env.empty i in
|
||||
let eq_lasto_list, env, last_o = extend_env env o in
|
||||
let contract, env = translate_contract env contract in
|
||||
let eq_lastn_n_list, env, last_v = extend_env env v in
|
||||
let eq_list = translate_eqs env eq_list in
|
||||
{ n with
|
||||
n_input = i;
|
||||
n_output = o;
|
||||
n_local = v @ last_o @ last_v;
|
||||
n_contract = contract;
|
||||
n_equs = eq_lasto_list @ eq_lastn_n_list @ eq_list }
|
||||
|
||||
let program ({ p_types = pt_list; p_nodes = n_list } as p) =
|
||||
{ p with p_types = pt_list; p_nodes = List.map node n_list }
|
73
heptagon/transformations/present.ml
Normal file
73
heptagon/transformations/present.ml
Normal file
|
@ -0,0 +1,73 @@
|
|||
(**************************************************************************)
|
||||
(* *)
|
||||
(* Heptagon *)
|
||||
(* *)
|
||||
(* Author : Marc Pouzet *)
|
||||
(* Organization : Demons, LRI, University of Paris-Sud, Orsay *)
|
||||
(* *)
|
||||
(**************************************************************************)
|
||||
(* removing present statements *)
|
||||
|
||||
(* $Id$ *)
|
||||
|
||||
open Misc
|
||||
open Location
|
||||
open Heptagon
|
||||
open Global
|
||||
open Initial
|
||||
|
||||
let block defnames statefull eqs =
|
||||
{ b_local = []; b_equs = eqs; b_defnames = defnames;
|
||||
b_statefull = statefull; b_loc = no_location }
|
||||
let switch statefull e l =
|
||||
{ eq_desc = Eswitch(e, l); eq_statefull = statefull; eq_loc = no_location }
|
||||
|
||||
let rec translate_eq v eq =
|
||||
match eq.eq_desc with
|
||||
| Eswitch(e, switch_handlers) ->
|
||||
v, { eq with eq_desc =
|
||||
Eswitch(e, translate_switch_handlers switch_handlers) }
|
||||
| Epresent(present_handlers, block) ->
|
||||
v,
|
||||
translate_present_handlers present_handlers (translate_block block)
|
||||
| Ereset(eq_list, e) ->
|
||||
let v, eq_list = translate_eqs v eq_list in
|
||||
v, { eq with eq_desc = Ereset(eq_list, e) }
|
||||
| Eeq _ -> v, eq
|
||||
| Eautomaton _ -> assert false
|
||||
|
||||
and translate_eqs v eq_list =
|
||||
List.fold_left
|
||||
(fun (v, eq_list) eq ->
|
||||
let v, eq = translate_eq v eq in v, eq :: eq_list)
|
||||
(v, []) eq_list
|
||||
|
||||
and translate_block ({ b_local = v; b_equs = eq_list } as b) =
|
||||
let v, eq_list = translate_eqs v eq_list in
|
||||
{ b with b_local = v; b_equs = eq_list }
|
||||
|
||||
and translate_switch_handlers handlers =
|
||||
let translate_switch_handler { w_name = n; w_block = b } =
|
||||
{ w_name = n; w_block = translate_block b } in
|
||||
List.map translate_switch_handler handlers
|
||||
|
||||
and translate_present_handlers handlers cont =
|
||||
let translate_present_handler { p_cond = e; p_block = b } cont =
|
||||
let statefull = b.b_statefull or cont.b_statefull in
|
||||
block b.b_defnames statefull
|
||||
[switch statefull e [{ w_name = ptrue; w_block = b };
|
||||
{ w_name = pfalse; w_block = cont }]] in
|
||||
let b = List.fold_right translate_present_handler handlers cont in
|
||||
List.hd (b.b_equs)
|
||||
|
||||
let translate_contract ({ c_local = v; c_eq = eq_list} as c) =
|
||||
let v, eq_list = translate_eqs v eq_list in
|
||||
{ c with c_local = v; c_eq = eq_list }
|
||||
|
||||
let node ({ n_local = v; n_equs = eq_list; n_contract = contract } as n) =
|
||||
let v, eq_list = translate_eqs v eq_list in
|
||||
let contract = optional translate_contract contract in
|
||||
{ n with n_local = v; n_equs = eq_list; n_contract = contract }
|
||||
|
||||
let program ({ p_types = pt_list; p_nodes = n_list } as p) =
|
||||
{ p with p_types = pt_list; p_nodes = List.map node n_list }
|
266
heptagon/transformations/reset.ml
Normal file
266
heptagon/transformations/reset.ml
Normal file
|
@ -0,0 +1,266 @@
|
|||
(**************************************************************************)
|
||||
(* *)
|
||||
(* Heptagon *)
|
||||
(* *)
|
||||
(* Author : Marc Pouzet *)
|
||||
(* Organization : Demons, LRI, University of Paris-Sud, Orsay *)
|
||||
(* *)
|
||||
(**************************************************************************)
|
||||
(* removing reset statements *)
|
||||
|
||||
(* $Id$ *)
|
||||
|
||||
open Location
|
||||
open Misc
|
||||
open Ident
|
||||
open Heptagon
|
||||
open Global
|
||||
open Initial
|
||||
|
||||
(* We introduce an initialization variable for each block *)
|
||||
(* Using an asynchronous reset would allow to produce *)
|
||||
(* better code avoiding to introduce n local variables and *)
|
||||
(* n state variables *)
|
||||
(* reset
|
||||
switch e with
|
||||
case C1 do ...
|
||||
| case C2 do ...
|
||||
| case C3 do ...
|
||||
end
|
||||
every r
|
||||
|
||||
switch e with
|
||||
case C1 do ... (* l_m1 *)
|
||||
m1 = false; m2 = l_m2; m3 = l_m3
|
||||
| case C2 do ... (* l_m2 *)
|
||||
m1 = l_m1; m2 = false; m3 = l_m3
|
||||
| case C3 do ... (* l_m3 *)
|
||||
m1 = l_m1; m2 = l_m2; m3 = false
|
||||
end;
|
||||
l_m1 = if res then true else true fby m1;...;
|
||||
l_m3 = if res then true else true fby m3
|
||||
|
||||
e1 -> e2 is translated into if (true fby false) then e1 else e2
|
||||
*)
|
||||
|
||||
let pre_true e =
|
||||
{ e with e_desc = Eapp(eop (Epre(Some(Cconstr(ptrue)))), [e]) }
|
||||
let init e = pre_true { dfalse with e_loc = e.e_loc }
|
||||
let ifthenelse e1 e2 e3 =
|
||||
{ e3 with e_desc = Eapp(eop Eifthenelse, [e1; e2; e3]) }
|
||||
let eq pat e =
|
||||
{ eq_desc = Eeq(pat, e); eq_statefull = false; eq_loc = no_location }
|
||||
let statefulleq = Heptagon.eq
|
||||
|
||||
(* the boolean condition for a structural reset *)
|
||||
type reset =
|
||||
| Rfalse
|
||||
| Rorthen of reset * ident
|
||||
|
||||
let rfalse = Rfalse
|
||||
let rvar n = Rorthen(Rfalse, n)
|
||||
|
||||
let true_reset = function
|
||||
| Rfalse -> false
|
||||
| _ -> true
|
||||
|
||||
let rec or_op res e =
|
||||
match res with
|
||||
| Rfalse -> e
|
||||
| Rorthen(res, n) ->
|
||||
or_op res { e with e_desc = Eapp(eop (Eop(por,[])), [bool_var n; e]) }
|
||||
|
||||
let default e =
|
||||
match e.e_desc with
|
||||
| Econst c -> Some(c)
|
||||
| _ -> None
|
||||
|
||||
let exp_of_res res =
|
||||
match res with
|
||||
| Rfalse -> dfalse
|
||||
| Rorthen(res, n) -> or_op res (bool_var n)
|
||||
|
||||
let ifres res e2 e3 =
|
||||
match res with
|
||||
| Rfalse -> ifthenelse (init e3) e2 e3
|
||||
| _ -> (* a reset occurs *)
|
||||
ifthenelse (exp_of_res res) e2 e3
|
||||
|
||||
(* add an equation *)
|
||||
let equation v acc_eq_list e =
|
||||
let n = Ident.fresh "r" in
|
||||
n,
|
||||
(bool_param n) :: v,
|
||||
{ eq_desc = Eeq(Evarpat(n), e); eq_statefull = true; eq_loc = e.e_loc } ::
|
||||
acc_eq_list
|
||||
|
||||
let orthen v acc_eq_list res e =
|
||||
match e.e_desc with
|
||||
| Evar(n) -> v, acc_eq_list, Rorthen(res, n)
|
||||
| _ ->
|
||||
let n, v, acc_eq_list = equation v acc_eq_list e in
|
||||
v, acc_eq_list, Rorthen(res, n)
|
||||
|
||||
let add_locals m n locals =
|
||||
let rec loop locals i n =
|
||||
if i < n then
|
||||
loop ((bool_param m.(i)) :: locals) (i+1) n
|
||||
else locals in
|
||||
loop locals 0 n
|
||||
|
||||
let add_local_equations i n m lm acc =
|
||||
(* [mi = false;...; m1 = l_m1;...; mn = l_mn] *)
|
||||
let rec loop acc k =
|
||||
if k < n then
|
||||
if k = i then loop ((eq (varpat(m.(k))) dfalse) :: acc) (k+1)
|
||||
else
|
||||
loop
|
||||
((eq (varpat(m.(k))) (bool_var lm.(k))) :: acc) (k+1)
|
||||
else acc
|
||||
in loop acc 0
|
||||
|
||||
let add_global_equations n m lm res acc =
|
||||
(* [ l_m1 = if res then true else true fby m1;...;
|
||||
l_mn = if res then true else true fby mn ] *)
|
||||
let rec loop acc k =
|
||||
if k < n then
|
||||
loop
|
||||
((statefulleq (varpat(lm.(k)))
|
||||
(match res with
|
||||
| Rfalse -> pre_true (bool_var m.(k))
|
||||
| _ -> ifres res dtrue (pre_true (bool_var m.(k)))
|
||||
)
|
||||
) :: acc) (k+1)
|
||||
else acc in
|
||||
loop acc 0
|
||||
|
||||
let defnames m n d =
|
||||
let rec loop acc k =
|
||||
if k < n
|
||||
then loop (Env.add m.(k) tybool acc) (k+1)
|
||||
else acc in
|
||||
loop d 0
|
||||
|
||||
let statefull eq_list = List.exists (fun eq -> eq.eq_statefull) eq_list
|
||||
|
||||
let rec translate_eq res v acc_eq_list eq =
|
||||
match eq.eq_desc with
|
||||
| Ereset(eq_list, e) ->
|
||||
let e = translate res e in
|
||||
if statefull eq_list then
|
||||
let v, acc_eq_list, res = orthen v acc_eq_list res e in
|
||||
translate_eqs res v acc_eq_list eq_list
|
||||
else
|
||||
let _, v, acc_eq_list = equation v acc_eq_list e in
|
||||
translate_eqs res v acc_eq_list eq_list
|
||||
| Eeq(pat, e) ->
|
||||
v, { eq with eq_desc = Eeq(pat, translate res e) } :: acc_eq_list
|
||||
| Eswitch(e, tag_block_list) ->
|
||||
let e = translate res e in
|
||||
let v, tag_block_list, acc_eq_list =
|
||||
translate_switch res v acc_eq_list tag_block_list in
|
||||
v, { eq with eq_desc = Eswitch(e, tag_block_list) } :: acc_eq_list
|
||||
| Epresent _ | Eautomaton _ -> assert false
|
||||
|
||||
and translate_eqs res v acc_eq_list eq_list =
|
||||
List.fold_left
|
||||
(fun (v, acc_eq_list) eq ->
|
||||
translate_eq res v acc_eq_list eq) (v, acc_eq_list) eq_list
|
||||
|
||||
and translate_switch res locals acc_eq_list switch_handlers =
|
||||
(* introduce a reset bit for each branch *)
|
||||
let tab_of_vars n = Array.init n (fun _ -> Ident.fresh "r") in
|
||||
let n = List.length switch_handlers in
|
||||
let m = tab_of_vars n in
|
||||
let lm = tab_of_vars n in
|
||||
|
||||
let locals = add_locals m n locals in
|
||||
let locals = add_locals lm n locals in
|
||||
|
||||
let body i {w_name = ci;
|
||||
w_block = ({ b_local = li; b_defnames = d; b_equs = eqi } as b)} =
|
||||
let d = defnames m n d in
|
||||
let li, eqi = translate_eqs (rvar (lm.(i))) li [] eqi in
|
||||
let eqi = add_local_equations i n m lm eqi in
|
||||
{ w_name = ci;
|
||||
w_block = { b with b_local = li; b_defnames = d; b_equs = eqi } } in
|
||||
|
||||
let rec loop i switch_handlers =
|
||||
match switch_handlers with
|
||||
[] -> []
|
||||
| handler :: switch_handlers ->
|
||||
(body i handler) :: (loop (i+1) switch_handlers) in
|
||||
|
||||
let acc_eq_list = add_global_equations n m lm res acc_eq_list in
|
||||
|
||||
locals, loop 0 switch_handlers, acc_eq_list
|
||||
|
||||
and translate res e =
|
||||
match e.e_desc with
|
||||
| Econst _ | Evar _ | Econstvar _ | Elast _ -> e
|
||||
| Etuple(e_list) ->
|
||||
{ e with e_desc = Etuple(List.map (translate res) e_list) }
|
||||
| Eapp({a_op = Efby } as op, [e1;e2]) ->
|
||||
let e1 = translate res e1 in
|
||||
let e2 = translate res e2 in
|
||||
begin
|
||||
match res, e1 with
|
||||
| Rfalse, { e_desc = Econst(c) } ->
|
||||
(* no reset *)
|
||||
{ e with e_desc =
|
||||
Eapp({ op with a_op = Epre(Some(c)) }, [e2]) }
|
||||
| _ ->
|
||||
ifres res e1
|
||||
{ e with e_desc =
|
||||
Eapp({ op with a_op = Epre(default e1) }, [e2]) }
|
||||
end
|
||||
| Eapp({ a_op = Earrow }, [e1;e2]) ->
|
||||
let e1 = translate res e1 in
|
||||
let e2 = translate res e2 in
|
||||
ifres res e1 e2
|
||||
| Eapp({ a_op = Enode(f,params) } as op, e_list) ->
|
||||
let e_list = List.map (translate res) e_list in
|
||||
if true_reset res then
|
||||
{ e with e_desc = Eapp({ op with a_op = Eevery(f, params) },
|
||||
(exp_of_res res) :: e_list) }
|
||||
else
|
||||
{ e with e_desc = Eapp({ op with a_op = Enode(f,params) }, e_list ) }
|
||||
| Eapp( { a_op = Eiterator(it,f, params, _) } as op, e_list) ->
|
||||
let e_list = List.map (translate res) e_list in
|
||||
if true_reset res then
|
||||
let r = Some (exp_of_res res) in
|
||||
{ e with e_desc = Eapp({ op with a_op = Eiterator(it,f,params,r) },
|
||||
e_list) }
|
||||
else
|
||||
{ e with e_desc = Eapp(op, e_list) }
|
||||
| Eapp({ a_op = Eevery(f, params) } as op, re :: e_list) ->
|
||||
let re = translate res re in
|
||||
let e_list = List.map (translate res) e_list in
|
||||
{ e with e_desc = Eapp({ op with a_op = Eevery(f, params)},
|
||||
(or_op res re) :: e_list) }
|
||||
| Eapp(op, e_list) ->
|
||||
{ e with e_desc = Eapp(op, List.map (translate res) e_list) }
|
||||
| Efield(e', field) ->
|
||||
{ e with e_desc = Efield(translate res e', field) }
|
||||
| Estruct(e_f_list) ->
|
||||
{ e with e_desc =
|
||||
Estruct(List.map (fun (f, e) -> (f, translate res e)) e_f_list) }
|
||||
| Earray(e_list) ->
|
||||
{ e with e_desc = Earray(List.map (translate res) e_list) }
|
||||
|
||||
let translate_contract ({ c_local = v;
|
||||
c_eq = eq_list;
|
||||
c_assume = e_a;
|
||||
c_enforce = e_g } as c) =
|
||||
let v, eq_list = translate_eqs rfalse v [] eq_list in
|
||||
let e_a = translate rfalse e_a in
|
||||
let e_g = translate rfalse e_g in
|
||||
{ c with c_local = v; c_eq = eq_list; c_assume = e_a; c_enforce = e_g }
|
||||
|
||||
let node (n) =
|
||||
let c = optional translate_contract n.n_contract in
|
||||
let var, eqs = translate_eqs rfalse n.n_local [] n.n_equs in
|
||||
{ n with n_local = var; n_equs = eqs; n_contract = c }
|
||||
|
||||
let program (p) =
|
||||
{ p with p_nodes = List.map node p.p_nodes }
|
345
main/compiler.ml
Normal file
345
main/compiler.ml
Normal file
|
@ -0,0 +1,345 @@
|
|||
(**************************************************************************)
|
||||
(* *)
|
||||
(* Heptagon *)
|
||||
(* *)
|
||||
(* Author : Marc Pouzet *)
|
||||
(* Organization : Demons, LRI, University of Paris-Sud, Orsay *)
|
||||
(* *)
|
||||
(**************************************************************************)
|
||||
(* $Id$ *)
|
||||
|
||||
open Location
|
||||
open Misc
|
||||
open Global
|
||||
|
||||
let lexical_error err loc =
|
||||
Printf.eprintf "%aIllegal character.\n" output_location loc;
|
||||
raise Error
|
||||
|
||||
let syntax_error loc =
|
||||
Printf.eprintf "%aSyntax error.\n" output_location loc;
|
||||
raise Error
|
||||
|
||||
let language_error lang =
|
||||
Printf.eprintf "Unknown language: %s.\n" lang
|
||||
|
||||
let parse parsing_fun lexing_fun lexbuf =
|
||||
try
|
||||
parsing_fun lexing_fun lexbuf
|
||||
with
|
||||
| Lexer.Lexical_error(err, pos1, pos2) ->
|
||||
lexical_error err (Loc(pos1, pos2))
|
||||
| Parsing.Parse_error ->
|
||||
let pos1 = Lexing.lexeme_start lexbuf
|
||||
and pos2 = Lexing.lexeme_end lexbuf in
|
||||
let l = Loc(pos1,pos2) in
|
||||
syntax_error l
|
||||
|
||||
let comment s = Printf.printf "** %s done **\n" s; flush stdout
|
||||
|
||||
let build_path suf =
|
||||
match !target_path with
|
||||
| None -> suf
|
||||
| Some path -> Filename.concat path suf
|
||||
|
||||
let clean_dir dir =
|
||||
if Sys.file_exists dir && Sys.is_directory dir
|
||||
then begin
|
||||
let rm_file_in_dir fn = Sys.remove (Filename.concat dir fn) in
|
||||
Array.iter rm_file_in_dir (Sys.readdir dir);
|
||||
end else Unix.mkdir dir 0o740;
|
||||
dir
|
||||
|
||||
(** Generation of a dataflow target *)
|
||||
let dataflow_target filename p target_languages =
|
||||
let rec one_target = function
|
||||
(* | "z3z" :: others ->
|
||||
let dirname = build_path (filename ^ "_z3z") in
|
||||
let dir = clean_dir dirname in
|
||||
let p = Dynamic_system.program p in
|
||||
if !verbose then
|
||||
comment "Translation into dynamic system (Z/3Z equations)";
|
||||
Sigali.Printer.print dir p;
|
||||
one_target others *)
|
||||
| ("vhdl_df" | "vhdl") :: others ->
|
||||
let dirname = build_path (filename ^ "_vhdl") in
|
||||
let dir = clean_dir dirname in
|
||||
let vhdl = Mls2vhdl.translate (Filename.basename filename) p in
|
||||
Vhdl.print dir vhdl;
|
||||
one_target others
|
||||
| unknown_lg :: others -> unknown_lg :: one_target others
|
||||
| [] -> [] in
|
||||
one_target target_languages
|
||||
|
||||
(** Generation of a sequential target *)
|
||||
let sequential_target filename o target_languages =
|
||||
let rec one_target = function
|
||||
| "c-old" :: others ->
|
||||
let dirname = build_path (filename ^ "_c-old") in
|
||||
let dir = clean_dir dirname in
|
||||
C_old.print o dir;
|
||||
one_target others
|
||||
| "java" :: others ->
|
||||
let dirname = build_path filename in
|
||||
let dir = clean_dir dirname in
|
||||
Java.print dir o;
|
||||
one_target others
|
||||
| "c" :: others ->
|
||||
let dirname = build_path (filename ^ "_c") in
|
||||
let dir = clean_dir dirname in
|
||||
let c_ast = Cgen.translate filename o in
|
||||
C.output dir c_ast;
|
||||
one_target others
|
||||
| "caml" :: others -> Caml.print filename o; one_target others
|
||||
| unknown_lg :: others -> unknown_lg :: one_target others
|
||||
| [] -> [] in
|
||||
one_target target_languages
|
||||
|
||||
(** Whole translation. *)
|
||||
let targets filename df obc target_languages =
|
||||
let target_languages = dataflow_target filename df target_languages in
|
||||
let target_languages = sequential_target filename obc target_languages in
|
||||
match target_languages with
|
||||
| [] -> ()
|
||||
| target :: _ -> language_error target
|
||||
|
||||
let parse_implementation lexbuf =
|
||||
parse Parser.program Lexer.token lexbuf
|
||||
|
||||
let parse_interface lexbuf =
|
||||
parse Parser.interface Lexer.token lexbuf
|
||||
|
||||
let interface modname filename =
|
||||
(* input and output files *)
|
||||
let source_name = filename ^ ".epi"
|
||||
and obj_interf_name = filename ^ ".epci" in
|
||||
|
||||
let ic = open_in source_name
|
||||
and itc = open_out_bin obj_interf_name in
|
||||
let close_all_files () =
|
||||
close_in ic;
|
||||
close_out itc in
|
||||
|
||||
try
|
||||
Location.initialize source_name ic;
|
||||
Modules.initialize modname;
|
||||
Initial.initialize ();
|
||||
|
||||
(* Parsing of the file *)
|
||||
let lexbuf = Lexing.from_channel ic in
|
||||
let l = parse_interface lexbuf in
|
||||
|
||||
(* Convert the parse tree to Heptagon AST *)
|
||||
let l = Scoping.translate_interface l in
|
||||
|
||||
Interface.Type.main l;
|
||||
Modules.write itc;
|
||||
if !print_types then Interface.Printer.print stdout;
|
||||
close_all_files ()
|
||||
with
|
||||
| x -> close_all_files (); raise x
|
||||
|
||||
let do_pass f d p pp enabled =
|
||||
if enabled
|
||||
then
|
||||
let r = f p in
|
||||
if !verbose
|
||||
then begin
|
||||
comment d;
|
||||
pp r;
|
||||
end;
|
||||
r
|
||||
else p
|
||||
|
||||
let do_silent_pass f d p enabled =
|
||||
if enabled
|
||||
then begin
|
||||
let r = f p in
|
||||
if !verbose then comment d; r
|
||||
end
|
||||
else p
|
||||
|
||||
let compile modname filename =
|
||||
(* input and output files *)
|
||||
let source_name = filename ^ ".ept"
|
||||
and obj_interf_name = filename ^ ".epci"
|
||||
and mls_name = filename ^ ".mls"
|
||||
and mls_norm_name = filename ^ "_norm.mls"
|
||||
and obc_name = filename ^ ".obc"
|
||||
and ml_name = filename ^ ".ml" in
|
||||
|
||||
let ic = open_in source_name
|
||||
and itc = open_out_bin obj_interf_name
|
||||
and mlsc = open_out mls_name
|
||||
and mlsnc = open_out mls_norm_name
|
||||
and obc = open_out obc_name
|
||||
and mlc = open_out ml_name in
|
||||
|
||||
let close_all_files () =
|
||||
close_in ic;
|
||||
close_out itc;
|
||||
close_out mlsc;
|
||||
close_out obc;
|
||||
close_out mlc in
|
||||
|
||||
try
|
||||
Location.initialize source_name ic;
|
||||
Modules.initialize modname;
|
||||
Initial.initialize ();
|
||||
|
||||
let pp = Printer.print stdout in
|
||||
|
||||
(* Parsing of the file *)
|
||||
let lexbuf = Lexing.from_channel ic in
|
||||
let p = parse_implementation lexbuf in
|
||||
|
||||
(* Convert the parse tree to Heptagon AST *)
|
||||
let p = Scoping.translate_program p in
|
||||
if !verbose
|
||||
then begin
|
||||
comment "Parsing";
|
||||
pp p
|
||||
end;
|
||||
|
||||
(* Misc.reset_symbol (); *)
|
||||
|
||||
(* Typing *)
|
||||
let p = do_pass Typing.program "Typing" p pp true in
|
||||
|
||||
(* Linear typing *)
|
||||
let p = do_pass Linear_typing.program "Linear Typing" p pp (not !no_mem_alloc) in
|
||||
|
||||
if !print_types then Interface.Printer.print stdout;
|
||||
Modules.write itc;
|
||||
|
||||
(* Causality check *)
|
||||
let p =
|
||||
do_silent_pass Causality.program "Causality check" p true in
|
||||
|
||||
(* Initialization check *)
|
||||
let p =
|
||||
do_silent_pass Initialization.program "Initialization check" p !init in
|
||||
|
||||
(* Mark nodes to be inlined *)
|
||||
(* let to_inline = List.map Misc.mk_longname !nodes_to_inline in
|
||||
let p = Inline.mark_calls_to to_inline p in
|
||||
let p = match !node_to_flatten with
|
||||
| None -> p
|
||||
| Some nn -> Inline.flatten nn p in
|
||||
if !verbose then comment "Inlining pre-pass";*)
|
||||
|
||||
(* Inline marked nodes *)
|
||||
(* let p = do_pass Inline.program "Inlining" p pp true in *)
|
||||
|
||||
(* Automata memory sharing *)
|
||||
let p = do_pass Automata_mem.program "Automata memory sharing" p pp (not !no_mem_alloc) in
|
||||
|
||||
(* Completion of partial definitions *)
|
||||
let p = do_pass Completion.program "Completion" p pp true in
|
||||
|
||||
(* Automata *)
|
||||
let p = do_pass Automata.program "Automata" p pp true in
|
||||
|
||||
(* Present *)
|
||||
let p = do_pass Present.program "Present" p pp true in
|
||||
|
||||
(* Shared variables (last) *)
|
||||
let p = do_pass Last.program "Last" p pp true in
|
||||
|
||||
(* Reset *)
|
||||
let reset_prog = if !use_new_reset_encoding then Reset_new.program else Reset.program in
|
||||
let p = do_pass reset_prog "Reset" p pp true in
|
||||
|
||||
(* Every *)
|
||||
let p = do_pass Every.program "Every" p pp true in
|
||||
|
||||
(* Merge and translate the heptagon program into the *)
|
||||
(* clocked data-flow language mini-ls *)
|
||||
let pp = Minils.Printer.print stdout in
|
||||
|
||||
let p = Merge.program p in
|
||||
if !verbose then comment "Translation into clocked equations";
|
||||
Minils.Printer.print mlsc p;
|
||||
|
||||
(* Annotation of expressions with their clock *)
|
||||
let p = Clocking.program p in
|
||||
|
||||
(* Mls2dot.program "" p; *)
|
||||
|
||||
(** Start of data-flow optimizations *)
|
||||
(* Normalization to maximize opportunities *)
|
||||
let p = do_pass Normalize.program "Normalization" p pp true in
|
||||
|
||||
(* Back-end causality check. Only useful to check that *)
|
||||
(* we did not make any mistake during code generation *)
|
||||
let p =
|
||||
do_silent_pass Dfcausality.program "Post-pass causality check" p true in
|
||||
|
||||
(* Check that the dataflow code is well initialized *)
|
||||
(*
|
||||
let p =
|
||||
do_silent_pass Init.program "Post-pass initialization check" p true in
|
||||
*)
|
||||
|
||||
let sigali = List.mem "z3z" !target_languages in
|
||||
|
||||
(* Boolean translation of enumerated values *)
|
||||
(* let p =
|
||||
do_pass
|
||||
Boolean.program "Boolean transformation" p pp (!boolean or sigali) in
|
||||
*)
|
||||
|
||||
(* Normalization to maximize opportunities *)
|
||||
let p = do_pass Normalize.program "Normalization" p pp true in
|
||||
|
||||
(* Mls2dot.program "normalized_" p; *)
|
||||
|
||||
let p =
|
||||
do_pass Deadcode.program "Deadcode removal" p pp !deadcode in
|
||||
|
||||
(* Automata minimization *)
|
||||
let p = do_pass Tommls.program "Automata minimization" p pp !tomato in
|
||||
|
||||
(* Common sub-expression elimination *)
|
||||
let p =
|
||||
do_pass Cmse.program "Common sub-expression elimination" p pp !cse in
|
||||
|
||||
(* Removing intermediate equations *)
|
||||
let p =
|
||||
do_pass Intermediate.program "Intermediate-equations removal"
|
||||
p pp !intermediate in
|
||||
|
||||
Mls2dot.program "optimized_" p;
|
||||
|
||||
(* Splitting *)
|
||||
let p = do_pass Splitting.program "Splitting" p pp (not !no_mem_alloc) in
|
||||
|
||||
(* Scheduling *)
|
||||
let scheduler = if !use_interf_scheduler then Schedule_interf.program else Schedule.program in
|
||||
let p = do_pass scheduler "Scheduling" p pp true in
|
||||
|
||||
(* Memory allocation *)
|
||||
Interference.world.Interference.node_is_scheduled <- true;
|
||||
let p = do_pass Memalloc.program
|
||||
"Interference graph building and Memory Allocation" p pp (not !no_mem_alloc) in
|
||||
|
||||
(* Parametrized functions instantiation *)
|
||||
let p = do_pass Callgraph.program
|
||||
"Parametrized functions instantiation" p pp true in
|
||||
|
||||
Minils.Printer.print mlsnc p;
|
||||
|
||||
(* Producing Object-based code *)
|
||||
let o = Translate.program p in
|
||||
if !verbose then comment "Translation into Object-based code";
|
||||
Obc.Printer.print obc o;
|
||||
|
||||
let pp = Obc.Printer.print stdout in
|
||||
if !verbose then pp o;
|
||||
|
||||
(* Translation into dataflow and sequential languages *)
|
||||
targets filename p o !target_languages;
|
||||
|
||||
close_all_files ();
|
||||
|
||||
with x -> close_all_files (); raise x
|
468
main/hept2mls.ml
Normal file
468
main/hept2mls.ml
Normal file
|
@ -0,0 +1,468 @@
|
|||
(**************************************************************************)
|
||||
(* *)
|
||||
(* Heptagon *)
|
||||
(* *)
|
||||
(* Author : Marc Pouzet *)
|
||||
(* Organization : Demons, LRI, University of Paris-Sud, Orsay *)
|
||||
(* *)
|
||||
(**************************************************************************)
|
||||
|
||||
(* removing switch statements and translation into Minils *)
|
||||
|
||||
(* $Id$ *)
|
||||
|
||||
open Location
|
||||
open Misc
|
||||
open Names
|
||||
open Ident
|
||||
open Linearity
|
||||
open Static
|
||||
|
||||
module HeptPrinter = Printer
|
||||
|
||||
open Minils
|
||||
open Global
|
||||
|
||||
module Env =
|
||||
(* associate a clock level [base on C1(x1) on ... Cn(xn)] to every *)
|
||||
(* local name [x] *)
|
||||
(* then [x] is translated into [x when C1(x1) ... when Cn(xn)] *)
|
||||
struct
|
||||
type env =
|
||||
| Eempty
|
||||
| Ecomp of env * IdentSet.t
|
||||
| Eon of env * longname * ident
|
||||
|
||||
let empty = Eempty
|
||||
|
||||
let push env tag c = Eon(env, tag, c)
|
||||
|
||||
let add l env =
|
||||
Ecomp(env,
|
||||
List.fold_left
|
||||
(fun acc { Heptagon.v_name = n } -> IdentSet.add n acc) IdentSet.empty l)
|
||||
|
||||
(* sample e according to the clock [base on C1(x1) on ... on Cn(xn)] *)
|
||||
let con env x e =
|
||||
let rec conrec env =
|
||||
match env with
|
||||
| Eempty -> Format.printf "%s\n" (name x); assert false
|
||||
| Eon(env, tag, name) ->
|
||||
let e, ck = conrec env in
|
||||
let ck_tag_name = Con(ck, tag, name) in
|
||||
{ e with e_desc = Ewhen(e, tag, name); e_ck = ck_tag_name },
|
||||
ck_tag_name
|
||||
| Ecomp(env, l) ->
|
||||
if IdentSet.mem x l then (e, Cbase) else conrec env in
|
||||
let e, _ = conrec env in e
|
||||
|
||||
(* a constant [c] is translated into [c when C1(x1) on ... on Cn(xn)] *)
|
||||
let const env e =
|
||||
let rec constrec env =
|
||||
match env with
|
||||
| Eempty -> e, Cbase
|
||||
| Eon(env, tag, name) ->
|
||||
let e, ck = constrec env in
|
||||
let ck_tag_name = Con(ck, tag, name) in
|
||||
{ e with e_desc = Ewhen(e, tag, name); e_ck = ck_tag_name },
|
||||
ck_tag_name
|
||||
| Ecomp(env, l) -> constrec env in
|
||||
let e, _ = constrec env in e
|
||||
end
|
||||
|
||||
(* add an equation *)
|
||||
let equation locals l_eqs e =
|
||||
let n = Ident.fresh "ck" in
|
||||
n,
|
||||
{ v_name = n; v_copy_of = None;
|
||||
v_type = exp_base_type e; v_linearity = NotLinear; v_clock = Cbase } :: locals,
|
||||
{ p_lhs = Evarpat(n); p_rhs = e } :: l_eqs
|
||||
|
||||
(* inserts the definition [x,e] into the set of shared equations *)
|
||||
let rec add x e shared =
|
||||
match shared with
|
||||
| [] -> [x, e]
|
||||
| (y, e_y) :: s ->
|
||||
if x < y then (x, e) :: shared else (y, e_y) :: add x e s
|
||||
|
||||
let add_locals ni l_eqs s_eqs s_handlers =
|
||||
let rec addrec l_eqs s_eqs s_handlers =
|
||||
match s_handlers with
|
||||
| [] -> l_eqs, s_eqs
|
||||
| (x, e) :: s_handlers ->
|
||||
if IdentSet.mem x ni then addrec l_eqs (add x e s_eqs) s_handlers
|
||||
else
|
||||
addrec ({ p_lhs = Evarpat(x); p_rhs = e } :: l_eqs)
|
||||
s_eqs s_handlers in
|
||||
addrec l_eqs s_eqs s_handlers
|
||||
|
||||
let rec translate_btype ty =
|
||||
let pint = Modname({ qual = "Pervasives"; id = "int" }) in
|
||||
let pfloat = Modname({ qual = "Pervasives"; id = "float" }) in
|
||||
let pbool = Modname({ qual = "Pervasives"; id = "bool" }) in
|
||||
match ty with
|
||||
| Heptagon.Tid (Name "int") -> Tint
|
||||
| Heptagon.Tid name_int when name_int = pint -> Tint
|
||||
| Heptagon.Tint -> Tint
|
||||
| Heptagon.Tid name_bool when name_bool = pbool -> Tid(Name("bool"))
|
||||
| Heptagon.Tbool -> Tid(Name("bool"))
|
||||
| Heptagon.Tid (Name "float") -> Tfloat
|
||||
| Heptagon.Tid name_float when name_float = pfloat -> Tfloat
|
||||
| Heptagon.Tfloat -> Tfloat
|
||||
| Heptagon.Tid(id) -> Tid(id)
|
||||
| Heptagon.Tarray(ty, exp) ->
|
||||
Tarray (translate_btype ty, exp)
|
||||
|
||||
let rec translate_type = function
|
||||
| Heptagon.Tbase(ty) -> Tbase(translate_btype ty)
|
||||
| Heptagon.Tprod(ty_list) -> Tprod(List.map translate_type ty_list)
|
||||
|
||||
let translate_var { Heptagon.v_name = n; Heptagon.v_type = t; Heptagon.v_linearity = l } =
|
||||
{ v_name = n; v_copy_of = None;
|
||||
v_type = translate_btype t; v_linearity = l;
|
||||
v_clock = Cbase }
|
||||
|
||||
let translate_locals locals l =
|
||||
List.fold_left (fun locals v -> translate_var v :: locals) locals l
|
||||
|
||||
(*transforms [c1, [(x1, e11);...;(xn, e1n)];...;ck, [(x1,ek1);...;(xn,ekn)]] *)
|
||||
(*into [x1=merge x (c1, e11)...(ck, ek1);...;xn=merge x (c1, e1n)...(ck,ekn)]*)
|
||||
let switch x ci_eqs_list =
|
||||
(* Defensive coherence check *)
|
||||
let check ci_eqs_list =
|
||||
let rec unique = function
|
||||
[] -> true
|
||||
| x :: h -> not (List.mem x h) && (unique h) in
|
||||
|
||||
let rec extract eqs_lists =
|
||||
match eqs_lists with
|
||||
| [] -> [],[]
|
||||
| []::eqs_lists' ->
|
||||
(* check length *)
|
||||
assert (List.for_all (function [] -> true | _ -> false) eqs_lists');
|
||||
[],[]
|
||||
| ((x,e)::eqs)::eqs_lists' ->
|
||||
let firsts,nexts = extract eqs_lists' in
|
||||
(x,e)::firsts,eqs::nexts in
|
||||
|
||||
let rec check_eqs eqs_lists =
|
||||
match eqs_lists with
|
||||
| [] -> ()
|
||||
| []::eqs_lists' ->
|
||||
(* check length *)
|
||||
assert (List.for_all (function [] -> true | _ -> false) eqs_lists')
|
||||
| _ ->
|
||||
let firsts,nexts = extract eqs_lists in
|
||||
(* check all firsts defining same name *)
|
||||
if (List.for_all (fun (x,e) -> x = (fst (List.hd firsts))) firsts)
|
||||
then ()
|
||||
else
|
||||
begin
|
||||
List.iter (fun (x,e) -> Printf.eprintf "|%s|, " (name x)) firsts;
|
||||
assert false
|
||||
end;
|
||||
check_eqs nexts in
|
||||
|
||||
let ci,eqs = List.split ci_eqs_list in
|
||||
(* constructors uniqueness *)
|
||||
assert (unique ci);
|
||||
check_eqs eqs in
|
||||
|
||||
let rec split ci_eqs_list =
|
||||
match ci_eqs_list with
|
||||
| [] | (_, []) :: _ -> [], []
|
||||
| (ci, (y, e) :: shared_eq_list) :: ci_eqs_list ->
|
||||
let ci_e_list, ci_eqs_list = split ci_eqs_list in
|
||||
(ci, e) :: ci_e_list, (ci, shared_eq_list) :: ci_eqs_list in
|
||||
|
||||
let rec distribute ci_eqs_list =
|
||||
match ci_eqs_list with
|
||||
| [] | (_, []) :: _ -> []
|
||||
| (ci, (y, { e_ty = ty; e_loc = loc }) :: _) :: _ ->
|
||||
let ci_e_list, ci_eqs_list = split ci_eqs_list in
|
||||
(y, make_exp (Emerge(x, ci_e_list)) ty NotLinear Cbase loc) ::
|
||||
distribute ci_eqs_list in
|
||||
|
||||
check ci_eqs_list;
|
||||
distribute ci_eqs_list
|
||||
|
||||
let rec const = function
|
||||
| Heptagon.Cint i -> Cint i
|
||||
| Heptagon.Cfloat f -> Cfloat f
|
||||
| Heptagon.Cconstr t -> Cconstr t
|
||||
| Heptagon.Cconst_array(n, c) -> Cconst_array(n, const c)
|
||||
|
||||
open Format
|
||||
|
||||
(** [mpol_of_hpol b] translates Heptagon's inlining policies (plain booleans at
|
||||
the moment) to MiniLS's subtler specifications. *)
|
||||
let mpol_of_hpol hp = match hp with
|
||||
| Heptagon.Ino -> Ino
|
||||
| Heptagon.Ione -> Ione
|
||||
| Heptagon.Irec -> Irec
|
||||
|
||||
let application env { Heptagon.a_op = op; Heptagon.a_inlined = inlined } e_list =
|
||||
match op, e_list with
|
||||
| Heptagon.Epre(None), [e] -> Efby(None, e)
|
||||
| Heptagon.Epre(Some(c)), [e] -> Efby(Some(const c), e)
|
||||
| Heptagon.Efby, [{ e_desc = Econst(c) } ; e] -> Efby(Some(c), e)
|
||||
| Heptagon.Eifthenelse, [e1;e2;e3] -> Eifthenelse(e1, e2, e3)
|
||||
| Heptagon.Enode(f, params), _ ->
|
||||
Eapp({ a_op = f; a_inlined = mpol_of_hpol inlined }, params, e_list)
|
||||
| Heptagon.Eevery(f, params), { e_desc = Evar(n) } :: e_list ->
|
||||
Eevery({ a_op = f; a_inlined = mpol_of_hpol inlined }, params, e_list, n)
|
||||
| Heptagon.Eop(f, params), _ -> Eop(f, params, e_list)
|
||||
(*Array operators*)
|
||||
| Heptagon.Erepeat, [e; idx] ->
|
||||
Erepeat (size_exp_of_exp idx, e)
|
||||
| Heptagon.Eselect idx_list, [e] ->
|
||||
Eselect (idx_list, e)
|
||||
(*Little hack: we need the to access the type of the array being accessed to
|
||||
store the bounds (which will be used at code generation time, where the types
|
||||
are harder to find). *)
|
||||
| Heptagon.Eselect_dyn, e::defe::idx_list ->
|
||||
let bounds = bounds_list (exp_base_type e) in
|
||||
Eselect_dyn (idx_list, bounds,
|
||||
e, defe)
|
||||
| Heptagon.Eupdate idx_list, [e1;e2] ->
|
||||
Eupdate (idx_list, e1, e2)
|
||||
| Heptagon.Eselect_slice, [e; idx1; idx2] ->
|
||||
Eselect_slice (size_exp_of_exp idx1, size_exp_of_exp idx2, e)
|
||||
| Heptagon.Econcat, [e1; e2] ->
|
||||
Econcat (e1, e2)
|
||||
| Heptagon.Eiterator(it, f, params, reset), idx::e_list ->
|
||||
(match reset with
|
||||
| None ->
|
||||
Eiterator(it, f, params, size_exp_of_exp idx, e_list, None)
|
||||
| Some { Heptagon.e_desc = Heptagon.Evar(n) } ->
|
||||
Eiterator(it, f, params, size_exp_of_exp idx, e_list, Some n)
|
||||
| _ -> assert false
|
||||
)
|
||||
| Heptagon.Ecopy, [e] ->
|
||||
e.e_desc
|
||||
| Heptagon.Efield_update f, [e1;e2] ->
|
||||
Efield_update(f, e1, e2)
|
||||
| _ -> assert false
|
||||
|
||||
let rec translate env
|
||||
{ Heptagon.e_desc = desc; Heptagon.e_ty = ty;
|
||||
Heptagon.e_linearity = l; Heptagon.e_loc = loc } =
|
||||
let ty = translate_type ty in
|
||||
match desc with
|
||||
| Heptagon.Econst(c) ->
|
||||
Env.const env
|
||||
{ e_desc = Econst(const c); e_ty = ty;
|
||||
e_linearity = l; e_loc = loc; e_ck = Cbase }
|
||||
| Heptagon.Evar(x) ->
|
||||
Env.con env x
|
||||
{ e_desc = Evar(x); e_ty = ty;
|
||||
e_linearity = l; e_loc = loc; e_ck = Cbase }
|
||||
| Heptagon.Econstvar(x) ->
|
||||
Env.const env
|
||||
{ e_desc = Econstvar(x); e_ty = ty;
|
||||
e_linearity = l; e_loc = loc; e_ck = Cbase }
|
||||
| Heptagon.Etuple(e_list) ->
|
||||
{ e_desc = Etuple (List.map (translate env) e_list);
|
||||
e_ty = ty; e_linearity = l; e_loc = loc; e_ck = Cbase }
|
||||
| Heptagon.Eapp ({ Heptagon.a_op = Heptagon.Eflatten n}, [e]) ->
|
||||
let { qualid = q;
|
||||
info = { fields = fields } } = Modules.find_struct n in
|
||||
let e = translate env e in
|
||||
{ e_desc = Etuple (List.map (fun (n,_) -> { e with e_desc = Efield(e, Name n) }) fields);
|
||||
e_ty = ty; e_linearity = l; e_loc = loc; e_ck = Cbase }
|
||||
| Heptagon.Eapp ({ Heptagon.a_op = Heptagon.Emake n}, e_list) ->
|
||||
let { qualid = q;
|
||||
info = { fields = fields } } = Modules.find_struct n in
|
||||
let e_list = List.map (translate env) e_list in
|
||||
{ e_desc = Estruct (List.map2 (fun (n,_) e -> Name n,e) fields e_list);
|
||||
e_ty = ty; e_linearity = l; e_loc = loc; e_ck = Cbase }
|
||||
| Heptagon.Eapp(app, e_list) ->
|
||||
{ e_desc = application env app (List.map (translate env) e_list);
|
||||
e_ty = ty; e_linearity = l; e_loc = loc; e_ck = Cbase }
|
||||
| Heptagon.Efield(e, field) ->
|
||||
{ e_desc = Efield(translate env e, field);
|
||||
e_ty = ty; e_linearity = l; e_loc = loc; e_ck = Cbase }
|
||||
| Heptagon.Estruct(f_e_list) ->
|
||||
{ e_desc = Estruct(List.map
|
||||
(fun (f, e) -> (f, translate env e))
|
||||
f_e_list);
|
||||
e_ty = ty; e_linearity = l; e_loc = loc; e_ck = Cbase }
|
||||
| Heptagon.Earray(e_list) ->
|
||||
{ e_desc = Earray (List.map (translate env) e_list);
|
||||
e_ty = ty; e_linearity = l; e_loc = loc; e_ck = Cbase }
|
||||
| Heptagon.Elast _ -> assert false
|
||||
| Heptagon.Ereset_mem (y, v, res) ->
|
||||
(match v.Heptagon.e_desc with
|
||||
| Heptagon.Econst c ->
|
||||
{ e_desc = Ereset_mem(y, const c, res);
|
||||
e_ty = ty; e_linearity = l; e_loc = loc; e_ck = Cbase }
|
||||
| _ -> assert false
|
||||
)
|
||||
|
||||
let rec translate_pat = function
|
||||
| Heptagon.Evarpat(n) -> Evarpat n
|
||||
| Heptagon.Etuplepat(l) -> Etuplepat (List.map translate_pat l)
|
||||
|
||||
let rec rename_pat ni locals s_eqs = function
|
||||
| Heptagon.Evarpat(n), Heptagon.Tbase(base_ty) ->
|
||||
if IdentSet.mem n ni then
|
||||
let n_copy = Ident.fresh (sourcename n) in
|
||||
let base_ty = translate_btype base_ty in
|
||||
Evarpat(n_copy),
|
||||
{ v_name = n_copy; v_copy_of = None;
|
||||
v_type = base_ty; v_linearity = NotLinear; v_clock = Cbase } :: locals,
|
||||
add n (make_exp (Evar n_copy) (Tbase(base_ty)) NotLinear Cbase no_location)
|
||||
s_eqs
|
||||
else Evarpat n, locals, s_eqs
|
||||
| Heptagon.Etuplepat(l), Heptagon.Tprod(l_ty) ->
|
||||
let l, locals, s_eqs =
|
||||
List.fold_right2
|
||||
(fun pat ty (p_list, locals, s_eqs) ->
|
||||
let pat, locals, s_eqs = rename_pat ni locals s_eqs (pat,ty) in
|
||||
pat :: p_list, locals, s_eqs) l l_ty
|
||||
([], locals, s_eqs) in
|
||||
Etuplepat(l), locals, s_eqs
|
||||
| _ -> assert false
|
||||
|
||||
let all_locals ni p =
|
||||
IdentSet.is_empty (IdentSet.inter (Heptagon.Vars.vars_pat IdentSet.empty IdentSet.empty p) ni)
|
||||
|
||||
let rec translate_eq env ni (locals, l_eqs, s_eqs) eq =
|
||||
match Heptagon.eqdesc eq with
|
||||
| Heptagon.Eswitch(e, switch_handlers) ->
|
||||
translate_switch_handlers env ni (locals,l_eqs,s_eqs) e switch_handlers
|
||||
| Heptagon.Eeq(Heptagon.Evarpat(n), e) when IdentSet.mem n ni ->
|
||||
locals,
|
||||
l_eqs,
|
||||
add n (translate env e) s_eqs
|
||||
| Heptagon.Eeq(p, e) when all_locals ni p ->
|
||||
(* all vars from [p] are local *)
|
||||
locals,
|
||||
{ p_lhs = translate_pat p; p_rhs = translate env e } :: l_eqs,
|
||||
s_eqs
|
||||
| Heptagon.Eeq(p, e) (* some are local *) ->
|
||||
(* transforms [p = e] into [p' = e; p = p'] *)
|
||||
let p', locals, s_eqs =
|
||||
rename_pat ni locals s_eqs (p,e.Heptagon.e_ty) in
|
||||
locals,
|
||||
{ p_lhs = p'; p_rhs = translate env e } :: l_eqs,
|
||||
s_eqs
|
||||
| Heptagon.Epresent _ | Heptagon.Eautomaton _ | Heptagon.Ereset _ ->
|
||||
assert false
|
||||
|
||||
and translate_eqs env ni (locals, local_eqs, shared_eqs) eq_list =
|
||||
List.fold_left
|
||||
(fun (locals, local_eqs, shared_eqs) eq ->
|
||||
translate_eq env ni (locals, local_eqs, shared_eqs) eq)
|
||||
(locals, local_eqs, shared_eqs) eq_list
|
||||
|
||||
and translate_block env ni (locals, l_eqs)
|
||||
{ Heptagon.b_local = l; Heptagon.b_equs = eq_list} =
|
||||
let env = Env.add l env in
|
||||
let locals = translate_locals locals l in
|
||||
let locals, local_eqs, shared_eqs =
|
||||
translate_eqs env ni (locals, l_eqs, []) eq_list in
|
||||
locals, local_eqs, shared_eqs
|
||||
|
||||
and translate_switch_handlers env ni (locals, l_eqs, s_eqs) e handlers =
|
||||
let rec transrec x ni_handlers (locals, l_eqs, ci_s_eqs_list) handlers =
|
||||
match handlers with
|
||||
[] -> locals, l_eqs, ci_s_eqs_list
|
||||
| { Heptagon.w_name = ci; Heptagon.w_block = b } :: handlers ->
|
||||
let locals, l_eqs, s_eqs =
|
||||
translate_block (Env.push env ci x) ni_handlers (locals, l_eqs) b in
|
||||
transrec x ni_handlers (locals, l_eqs, (ci, s_eqs) :: ci_s_eqs_list)
|
||||
handlers in
|
||||
|
||||
let def = function
|
||||
[] -> IdentSet.empty
|
||||
| { Heptagon.w_block = { Heptagon.b_defnames = env } } :: _ ->
|
||||
(* Create set from env *)
|
||||
(Ident.Env.fold (fun name _ set -> IdentSet.add name set) env IdentSet.empty) in
|
||||
|
||||
let ni_handlers = def handlers in
|
||||
let x, locals, l_eqs = equation locals l_eqs (translate env e) in
|
||||
let locals, l_eqs, ci_s_eqs_list =
|
||||
transrec x ni_handlers (locals, l_eqs, []) handlers in
|
||||
let s_handlers = switch x ci_s_eqs_list in
|
||||
let l_eqs, s_eqs = add_locals ni l_eqs s_eqs s_handlers in
|
||||
locals, l_eqs, s_eqs
|
||||
|
||||
let translate_contract env contract =
|
||||
match contract with
|
||||
| None -> None, env
|
||||
| Some { Heptagon.c_local = v;
|
||||
Heptagon.c_eq = eq_list;
|
||||
Heptagon.c_assume = e_a;
|
||||
Heptagon.c_enforce = e_g;
|
||||
Heptagon.c_controllables = cl } ->
|
||||
let env = Env.add cl env in
|
||||
let env' = Env.add v env in
|
||||
let locals = translate_locals [] v in
|
||||
let locals, l_eqs, s_eqs =
|
||||
translate_eqs env' IdentSet.empty (locals, [], []) eq_list in
|
||||
let l_eqs, _ = add_locals IdentSet.empty l_eqs [] s_eqs in
|
||||
let e_a = translate env' e_a in
|
||||
let e_g = translate env' e_g in
|
||||
Some { c_local = locals;
|
||||
c_eq = l_eqs;
|
||||
c_assume = e_a;
|
||||
c_enforce = e_g;
|
||||
c_controllables = List.map translate_var cl },
|
||||
env
|
||||
|
||||
|
||||
let node
|
||||
{ Heptagon.n_name = n; Heptagon.n_input = i; Heptagon.n_output = o;
|
||||
Heptagon.n_contract = contract;
|
||||
Heptagon.n_local = l; Heptagon.n_equs = eq_list;
|
||||
Heptagon.n_loc = loc; Heptagon.n_states_graph = states_graph;
|
||||
Heptagon.n_params = params; Heptagon.n_params_constraints = params_constr } =
|
||||
let env = Env.add o (Env.add i Env.empty) in
|
||||
let contract, env = translate_contract env contract in
|
||||
let env = Env.add l env in
|
||||
let locals = translate_locals [] l in
|
||||
let locals, l_eqs, s_eqs =
|
||||
translate_eqs env IdentSet.empty (locals, [], []) eq_list in
|
||||
let l_eqs, _ = add_locals IdentSet.empty l_eqs [] s_eqs in
|
||||
{ n_name = n;
|
||||
n_input = List.map translate_var i;
|
||||
n_output = List.map translate_var o;
|
||||
n_contract = contract;
|
||||
n_local = locals;
|
||||
n_equs = l_eqs;
|
||||
n_loc = loc ;
|
||||
n_targeting = [];
|
||||
n_mem_alloc = [];
|
||||
n_states_graph = states_graph;
|
||||
n_params = params;
|
||||
n_params_constraints = params_constr;
|
||||
n_params_instances = []; }
|
||||
|
||||
let typedec
|
||||
{Heptagon.t_name = n; Heptagon.t_desc = tdesc; Heptagon.t_loc = loc} =
|
||||
let onetype = function
|
||||
| Heptagon.Type_abs -> Type_abs
|
||||
| Heptagon.Type_enum(tag_list) -> Type_enum(tag_list)
|
||||
| Heptagon.Type_struct(field_ty_list) ->
|
||||
Type_struct
|
||||
(List.map (fun (f, ty) -> (f, translate_btype ty)) field_ty_list)
|
||||
in
|
||||
{ t_name = n; t_desc = onetype tdesc; t_loc = loc }
|
||||
|
||||
let const_dec cd =
|
||||
{ c_name = cd.Heptagon.c_name;
|
||||
c_value = cd.Heptagon.c_value;
|
||||
c_loc = cd.Heptagon.c_loc; }
|
||||
|
||||
let program
|
||||
{ Heptagon.p_pragmas = pragmas;
|
||||
Heptagon.p_opened = modules;
|
||||
Heptagon.p_types = pt_list;
|
||||
Heptagon.p_nodes = n_list;
|
||||
Heptagon.p_consts = c_list; } =
|
||||
{ p_pragmas = pragmas;
|
||||
p_opened = modules;
|
||||
p_types = List.map typedec pt_list;
|
||||
p_nodes = List.map node n_list;
|
||||
p_consts = List.map const_dec c_list}
|
100
main/main.ml
Normal file
100
main/main.ml
Normal file
|
@ -0,0 +1,100 @@
|
|||
(**************************************************************************)
|
||||
(* *)
|
||||
(* Heptagon *)
|
||||
(* *)
|
||||
(* Author : Marc Pouzet *)
|
||||
(* Organization : Demons, LRI, University of Paris-Sud, Orsay *)
|
||||
(* *)
|
||||
(**************************************************************************)
|
||||
(* the main *)
|
||||
|
||||
(* $Id$ *)
|
||||
|
||||
open Misc
|
||||
open Compiler
|
||||
|
||||
let compile file =
|
||||
if Filename.check_suffix file ".ept"
|
||||
then
|
||||
let filename = Filename.chop_suffix file ".ept" in
|
||||
let modname = String.capitalize(Filename.basename filename) in
|
||||
compile modname filename
|
||||
else if Filename.check_suffix file ".epi"
|
||||
then
|
||||
let filename = Filename.chop_suffix file ".epi" in
|
||||
let modname = String.capitalize(Filename.basename filename) in
|
||||
interface modname filename
|
||||
else
|
||||
raise (Arg.Bad ("don't know what to do with " ^ file))
|
||||
|
||||
let doc_verbose = "\t\t\tSet verbose mode"
|
||||
and doc_version = "\t\tThe version of the compiler"
|
||||
and doc_print_types = "\t\t\tPrint types"
|
||||
and doc_include = "<dir>\t\tAdd <dir> to the list of include directories"
|
||||
and doc_stdlib = "<dir>\t\tDirectory for the standard library"
|
||||
and doc_sim = "<node>\t\tCreate simulation for node <node>"
|
||||
and doc_locate_stdlib = "\t\tLocate standard libray"
|
||||
and doc_no_pervasives = "\tDo not load the pervasives module"
|
||||
and doc_target =
|
||||
"<lang>\tGenerate code in language <lang>\n\t\t\t(with <lang>=c, c-old,"
|
||||
^ " vhdl_seq, vhdl_df,\n\t\t\t java, caml or z3z)"
|
||||
and doc_full_type_info = "\t\t\tPrint full type information"
|
||||
and doc_target_path =
|
||||
"<path>\tGenerated files will be placed in <path>\n\t\t\t(the directory is cleaned)"
|
||||
and doc_boolean = "\t\tTranslate enumerated values towards boolean vectors"
|
||||
and doc_deadcode = "\t\tDeadcode removal"
|
||||
and doc_noinit = "\t\tDisable initialization analysis"
|
||||
and doc_cse = "\t\t\tPerform common sub-expression elimination"
|
||||
and doc_tomato = "\t\tPerform auTOMATa minimizatiOn"
|
||||
and doc_sigali = "\t\t\tGenerate symbolic equations for Sigali (Z/3Z format)"
|
||||
and doc_flatten = "<node name>\tRecursively inline all calls in specified node"
|
||||
and doc_inline = "<node list>\tInline the list of nodes, separated by commas"
|
||||
and doc_dep2dot = "<node list>\tOutput to .dot files the dependency graph of "
|
||||
^ "the list of nodes, separated by commas"
|
||||
and doc_intermediate = "\t\tPerform intermediate-equations removal (buggy)"
|
||||
and doc_nomemalloc = "\t\tDisable memory allocation algorithm"
|
||||
and doc_interfscheduler = "\tUse the new scheduler, that tries to minimise interference"
|
||||
and doc_main_node = "<node>\t\tUse <node> as the toplevel node"
|
||||
and doc_new_reset = "\t\tUse the new alternate encoding of resets"
|
||||
|
||||
let errmsg = "Options are:"
|
||||
|
||||
let main () =
|
||||
try
|
||||
Arg.parse
|
||||
[
|
||||
"-v",Arg.Set verbose, doc_verbose;
|
||||
"-version", Arg.Unit show_version, doc_version;
|
||||
"-i", Arg.Set print_types, doc_print_types;
|
||||
"-I", Arg.String add_include, doc_include;
|
||||
"-where", Arg.Unit locate_stdlib, doc_locate_stdlib;
|
||||
"-stdlib", Arg.String set_stdlib, doc_stdlib;
|
||||
"-s", Arg.String set_simulation_node, doc_sim;
|
||||
"-nopervasives", Arg.Unit set_no_pervasives, doc_no_pervasives;
|
||||
"-target", Arg.String add_target_language, doc_target;
|
||||
"-targetpath", Arg.String set_target_path, doc_target_path;
|
||||
"-bool", Arg.Set boolean, doc_boolean;
|
||||
"-deadcode", Arg.Set deadcode, doc_deadcode;
|
||||
"-noinit", Arg.Clear init, doc_noinit;
|
||||
"-fti", Arg.Set full_type_info, doc_full_type_info;
|
||||
"-cse", Arg.Set cse, doc_cse;
|
||||
"-tomato", Arg.Set tomato, doc_tomato;
|
||||
"-z3z", Arg.Unit set_sigali, doc_sigali;
|
||||
"-inter", Arg.Set intermediate, doc_intermediate;
|
||||
"-flatten", Arg.String (fun s -> node_to_flatten := Some s), doc_flatten;
|
||||
("-inline",
|
||||
Arg.String (fun s -> nodes_to_inline := Misc.split_string s ','),
|
||||
doc_inline);
|
||||
("-dep2dot",
|
||||
Arg.String (fun s -> nodes_to_display := Misc.split_string s ','),
|
||||
doc_dep2dot);
|
||||
"-nomemalloc", Arg.Set no_mem_alloc, doc_nomemalloc;
|
||||
"-interfscheduler", Arg.Set use_interf_scheduler, doc_interfscheduler;
|
||||
"-new-reset-encoding", Arg.Set use_new_reset_encoding, doc_new_reset;
|
||||
]
|
||||
compile
|
||||
errmsg;
|
||||
with
|
||||
| Misc.Error -> exit 2;;
|
||||
|
||||
main ()
|
753
minils/minils.ml
Normal file
753
minils/minils.ml
Normal file
|
@ -0,0 +1,753 @@
|
|||
(**************************************************************************)
|
||||
(* *)
|
||||
(* Heptagon *)
|
||||
(* *)
|
||||
(* Author : Marc Pouzet *)
|
||||
(* Organization : Demons, LRI, University of Paris-Sud, Orsay *)
|
||||
(* *)
|
||||
(**************************************************************************)
|
||||
|
||||
(* The internal MiniLustre representation *)
|
||||
|
||||
(* $Id$ *)
|
||||
|
||||
open Location
|
||||
open Dep
|
||||
open Misc
|
||||
open Names
|
||||
open Ident
|
||||
open Linearity
|
||||
open Interference_graph
|
||||
open Global
|
||||
open Static
|
||||
|
||||
(** Inlining policies, to be held in app records. *)
|
||||
type inlining_policy =
|
||||
| Ino (** Do not inline. *)
|
||||
| Ione (** Just inline on one step. *)
|
||||
| Irec (** Recursively inline all sub-calls. *)
|
||||
|
||||
type type_dec =
|
||||
{ t_name: name;
|
||||
t_desc: tdesc;
|
||||
t_loc: location }
|
||||
|
||||
and tdesc =
|
||||
| Type_abs
|
||||
| Type_enum of name list
|
||||
| Type_struct of (name * base_ty) list
|
||||
|
||||
and exp =
|
||||
{ e_desc: desc; (* its descriptor *)
|
||||
mutable e_ck: ck;
|
||||
mutable e_ty: ty;
|
||||
mutable e_linearity : linearity;
|
||||
e_loc: location }
|
||||
|
||||
and desc =
|
||||
| Econst of const
|
||||
| Evar of ident
|
||||
| Econstvar of name
|
||||
| Efby of const option * exp
|
||||
| Ereset_mem of ident * const * ident
|
||||
| Etuple of exp list
|
||||
| Eop of longname * size_exp list * exp list
|
||||
| Eapp of app * size_exp list * exp list
|
||||
| Eevery of app * size_exp list * exp list * ident
|
||||
| Ewhen of exp * longname * ident
|
||||
| Emerge of ident * (longname * exp) list
|
||||
| Eifthenelse of exp * exp * exp
|
||||
| Efield of exp * longname
|
||||
| Estruct of (longname * exp) list
|
||||
(*Array operators*)
|
||||
| Earray of exp list
|
||||
| Erepeat of size_exp * exp
|
||||
| Eselect of size_exp list * exp (*indices, array*)
|
||||
| Eselect_dyn of exp list * size_exp list * exp * exp (*indices, bounds, array, default*)
|
||||
| Eupdate of size_exp list * exp * exp (*indices, array, value*)
|
||||
| Eselect_slice of size_exp * size_exp * exp (*lower bound, upper bound, array*)
|
||||
| Econcat of exp * exp
|
||||
| Eiterator of iterator_name * longname * size_exp list * size_exp * exp list * ident option
|
||||
| Efield_update of longname * exp * exp (*field, record, value*)
|
||||
|
||||
and app =
|
||||
{ a_op: longname;
|
||||
a_inlined: inlining_policy
|
||||
}
|
||||
|
||||
and ct =
|
||||
| Ck of ck
|
||||
| Cprod of ct list
|
||||
|
||||
and ck =
|
||||
| Cbase
|
||||
| Cvar of link ref
|
||||
| Con of ck * longname * ident
|
||||
|
||||
and link =
|
||||
| Cindex of int
|
||||
| Clink of ck
|
||||
|
||||
and ty =
|
||||
| Tbase of base_ty
|
||||
| Tprod of ty list
|
||||
|
||||
and base_ty =
|
||||
| Tint | Tfloat
|
||||
| Tid of longname
|
||||
| Tarray of base_ty * size_exp
|
||||
|
||||
and const =
|
||||
| Cint of int
|
||||
| Cfloat of float
|
||||
| Cconstr of longname
|
||||
| Cconst_array of size_exp * const
|
||||
|
||||
and pat =
|
||||
| Etuplepat of pat list
|
||||
| Evarpat of ident
|
||||
|
||||
type eq =
|
||||
{ p_lhs : pat;
|
||||
p_rhs : exp; }
|
||||
|
||||
type var_dec =
|
||||
{ v_name : ident;
|
||||
v_copy_of : ident option;
|
||||
v_type : base_ty;
|
||||
v_linearity : linearity;
|
||||
v_clock : ck }
|
||||
|
||||
type contract =
|
||||
{ c_assume : exp;
|
||||
c_enforce : exp;
|
||||
c_controllables : var_dec list;
|
||||
c_local : var_dec list;
|
||||
c_eq : eq list;
|
||||
}
|
||||
|
||||
type node_dec =
|
||||
{ n_name : name;
|
||||
n_input : var_dec list;
|
||||
n_output : var_dec list;
|
||||
n_contract : contract option;
|
||||
n_local : var_dec list;
|
||||
n_equs : eq list;
|
||||
n_loc : location;
|
||||
n_targeting : (int*int) list;
|
||||
n_mem_alloc : (base_ty * ivar list) list;
|
||||
n_states_graph : (name,name) interf_graph;
|
||||
n_params : name list;
|
||||
n_params_constraints : size_constr list;
|
||||
n_params_instances : (int list) list; }
|
||||
|
||||
type const_dec =
|
||||
{ c_name : name;
|
||||
c_value : size_exp;
|
||||
c_loc : location; }
|
||||
|
||||
type program =
|
||||
{ p_pragmas: (name * string) list;
|
||||
p_opened : name list;
|
||||
p_types : type_dec list;
|
||||
p_nodes : node_dec list;
|
||||
p_consts : const_dec list; }
|
||||
|
||||
(*Helper functions to build the AST*)
|
||||
let make_exp desc ty l ck loc =
|
||||
{ e_desc = desc; e_ty = ty; e_linearity = l; e_ck = ck; e_loc = loc }
|
||||
|
||||
let make_dummy_exp desc ty =
|
||||
{ e_desc = desc; e_ty = ty; e_linearity = NotLinear;
|
||||
e_ck = Cbase; e_loc = no_location }
|
||||
|
||||
(* Helper functions to work with types *)
|
||||
let base_type = function
|
||||
| Tbase(bty) -> bty
|
||||
| Tprod _ -> assert false
|
||||
|
||||
(* get the type of an expression ; assuming that this type is a base type *)
|
||||
let exp_base_type e =
|
||||
base_type e.e_ty
|
||||
|
||||
let rec size_exp_of_exp e =
|
||||
match e.e_desc with
|
||||
| Econstvar n -> SVar n
|
||||
| Econst (Cint i) -> SConst i
|
||||
| Eop(op, _, [e1;e2]) ->
|
||||
let sop = op_from_app_name op in
|
||||
SOp(sop, size_exp_of_exp e1, size_exp_of_exp e2)
|
||||
| _ -> raise Not_static
|
||||
|
||||
(*Returns the list of bounds of an array type*)
|
||||
let rec bounds_list ty =
|
||||
match ty with
|
||||
| Tarray(ty, n) -> n::(bounds_list ty)
|
||||
| _ -> []
|
||||
|
||||
(** Returns the var_dec object corresponding to the name n
|
||||
in a list of var_dec. *)
|
||||
let rec vd_find n = function
|
||||
| [] -> Format.printf "Not found var %s\n" (name n); raise Not_found
|
||||
| vd::l ->
|
||||
if vd.v_name = n then vd else vd_find n l
|
||||
|
||||
(** Returns whether an object of name n belongs to
|
||||
a list of var_dec. *)
|
||||
let rec vd_mem n = function
|
||||
| [] -> false
|
||||
| vd::l -> vd.v_name = n or (vd_mem n l)
|
||||
|
||||
(** Same as vd_mem but for an ivar value. *)
|
||||
let ivar_vd_mem var vds =
|
||||
match var with
|
||||
| IVar id -> vd_mem id vds
|
||||
| _ -> false
|
||||
|
||||
(** [is_record_type ty] returns whether ty corresponds to a record type. *)
|
||||
let is_record_type ty =
|
||||
match ty with
|
||||
| Tid n ->
|
||||
(try
|
||||
ignore (Modules.find_struct n);
|
||||
true
|
||||
with
|
||||
Not_found -> false
|
||||
)
|
||||
| _ -> false
|
||||
|
||||
|
||||
module Vars =
|
||||
struct
|
||||
let rec vars_pat acc = function
|
||||
| Evarpat(x) -> x :: acc
|
||||
| Etuplepat(pat_list) -> List.fold_left vars_pat acc pat_list
|
||||
|
||||
let rec vars_ck acc = function
|
||||
| Con(ck, c, n) -> if List.mem (IVar n) acc then acc else (IVar n) :: acc
|
||||
| Cbase | Cvar { contents = Cindex _ } -> acc
|
||||
| Cvar { contents = Clink ck } -> vars_ck acc ck
|
||||
|
||||
let rec read is_left acc e =
|
||||
let add x acc = if List.mem (IVar x) acc then acc else (IVar x) :: acc in
|
||||
let acc =
|
||||
match e.e_desc with
|
||||
| Emerge(x, c_e_list) ->
|
||||
let acc = add x acc in
|
||||
List.fold_left (fun acc (_, e) -> read is_left acc e) acc c_e_list
|
||||
| Eifthenelse(e1, e2, e3) ->
|
||||
read is_left (read is_left (read is_left acc e1) e2) e3
|
||||
| Ewhen(e, c, x) ->
|
||||
let acc = add x acc in
|
||||
read is_left acc e
|
||||
| Eop(_, _, e_list)
|
||||
| Etuple(e_list) -> List.fold_left (read is_left) acc e_list
|
||||
| Eapp(_, _, e_list) -> List.fold_left (read is_left) acc e_list
|
||||
| Eevery(_, _, e_list, x) ->
|
||||
let acc = add x acc in
|
||||
List.fold_left (read is_left) acc e_list
|
||||
| Efby(_, e) ->
|
||||
if is_left then vars_ck acc e.e_ck else read is_left acc e
|
||||
| Ereset_mem (_, _,res) -> add res acc
|
||||
| Evar(n) -> add n acc
|
||||
| Efield({ e_desc = Evar x }, f) ->
|
||||
let acc = add x acc in
|
||||
let x = IField(x,f) in
|
||||
if List.mem x acc then acc else x::acc
|
||||
| Efield(e, _) -> read is_left acc e
|
||||
| Estruct(f_e_list) ->
|
||||
List.fold_left (fun acc (_, e) -> read is_left acc e) acc f_e_list
|
||||
| Econst _ | Econstvar _ -> acc
|
||||
(*Array operators*)
|
||||
| Earray e_list -> List.fold_left (read is_left) acc e_list
|
||||
| Erepeat (_,e) -> read is_left acc e
|
||||
| Eselect (_,e) -> read is_left acc e
|
||||
| Eselect_dyn (e_list, _, e1, e2) ->
|
||||
let acc = List.fold_left (read is_left) acc e_list in
|
||||
read is_left (read is_left acc e1) e2
|
||||
| Eupdate (_, e1, e2) | Efield_update (_, e1, e2) ->
|
||||
read is_left (read is_left acc e1) e2
|
||||
| Eselect_slice (_ , _, e) -> read is_left acc e
|
||||
| Econcat (e1, e2) ->
|
||||
read is_left (read is_left acc e1) e2
|
||||
| Eiterator (_, _, _, _, e_list, _) ->
|
||||
List.fold_left (read is_left) acc e_list
|
||||
in
|
||||
vars_ck acc e.e_ck
|
||||
|
||||
let rec remove x = function
|
||||
| [] -> []
|
||||
| y :: l -> if x = y then l else y :: remove x l
|
||||
|
||||
let def acc { p_lhs = pat } = vars_pat acc pat
|
||||
|
||||
let read is_left { p_lhs = pat; p_rhs = e } =
|
||||
match pat, e.e_desc with
|
||||
| Evarpat(n), Efby(_, e1) ->
|
||||
if is_left
|
||||
then remove (IVar n) (read is_left [] e1)
|
||||
else read is_left [] e1
|
||||
| _ -> read is_left [] e
|
||||
|
||||
let rec remove_records = function
|
||||
| [] -> []
|
||||
| (IVar x)::l -> (IVar x)::(remove_records l)
|
||||
| (IField(x,f))::l ->
|
||||
let l = remove (IVar x) l in
|
||||
(IField(x,f))::(remove_records l)
|
||||
|
||||
let read_ivars is_left eq =
|
||||
remove_records (read is_left eq)
|
||||
|
||||
let read is_left eq =
|
||||
filter_vars (read is_left eq)
|
||||
|
||||
let antidep { p_rhs = e } =
|
||||
match e.e_desc with Efby _ -> true | _ -> false
|
||||
let clock { p_rhs = e } =
|
||||
match e.e_desc with
|
||||
| Emerge(_, (_, e) :: _) -> e.e_ck
|
||||
| _ -> e.e_ck
|
||||
let head ck =
|
||||
let rec headrec ck l =
|
||||
match ck with
|
||||
| Cbase | Cvar { contents = Cindex _ } -> l
|
||||
| Con(ck, c, n) -> headrec ck (n :: l)
|
||||
| Cvar { contents = Clink ck } -> headrec ck l in
|
||||
headrec ck []
|
||||
|
||||
let rec linear_use acc e =
|
||||
match e.e_desc with
|
||||
| Emerge(_, c_e_list) ->
|
||||
List.fold_left (fun acc (_, e) -> linear_use acc e) acc c_e_list
|
||||
| Eifthenelse(e1, e2, e3) ->
|
||||
linear_use (linear_use (linear_use acc e1) e2) e3
|
||||
| Ewhen(e, _, _) | Efield(e, _) | Efby(_, e) -> linear_use acc e
|
||||
| Eop(_,_, e_list)
|
||||
| Etuple(e_list) | Earray e_list
|
||||
| Eapp(_,_, e_list) | Eiterator (_, _, _, _, e_list, _)
|
||||
| Eevery(_,_, e_list, _) -> List.fold_left linear_use acc e_list
|
||||
| Evar(n) ->
|
||||
(match e.e_linearity with
|
||||
| At _ -> if List.mem n acc then acc else n :: acc
|
||||
| _ -> acc
|
||||
)
|
||||
| Estruct(f_e_list) ->
|
||||
List.fold_left (fun acc (_, e) -> linear_use acc e) acc f_e_list
|
||||
| Econst _ | Econstvar _ | Ereset_mem (_, _,_) -> acc
|
||||
(*Array operators*)
|
||||
| Erepeat (_,e)
|
||||
| Eselect (_,e) | Eselect_slice (_ , _, e) -> linear_use acc e
|
||||
| Eselect_dyn (e_list, _, e1, e2) ->
|
||||
let acc = List.fold_left linear_use acc e_list in
|
||||
linear_use (linear_use acc e1) e2
|
||||
| Eupdate (_, e1, e2) | Efield_update (_, e1, e2)
|
||||
| Econcat (e1, e2) ->
|
||||
linear_use (linear_use acc e1) e2
|
||||
|
||||
let mem_reset { p_rhs = e } =
|
||||
match e.e_desc with
|
||||
| Ereset_mem (y, _, _) -> [y]
|
||||
| _ -> []
|
||||
end
|
||||
|
||||
(* data-flow dependences. pre-dependences are discarded *)
|
||||
module DataFlowDep = Make
|
||||
(struct
|
||||
type equation = eq
|
||||
let read eq = Vars.read true eq
|
||||
let def = Vars.def
|
||||
let linear_read eq = Vars.linear_use [] eq.p_rhs
|
||||
let mem_reset = Vars.mem_reset
|
||||
let antidep = Vars.antidep
|
||||
end)
|
||||
|
||||
(* all dependences between variables *)
|
||||
module AllDep = Make
|
||||
(struct
|
||||
type equation = eq
|
||||
let read eq = Vars.read false eq
|
||||
let linear_read eq = Vars.linear_use [] eq.p_rhs
|
||||
let mem_reset = Vars.mem_reset
|
||||
let def = Vars.def
|
||||
let antidep eq = false
|
||||
end)
|
||||
|
||||
module Printer =
|
||||
struct
|
||||
open Format
|
||||
|
||||
let is_infix =
|
||||
let module StrSet = Set.Make(String) in
|
||||
let set_infix = StrSet.singleton "or" in
|
||||
fun s ->
|
||||
if (StrSet.mem s set_infix) then true
|
||||
else begin
|
||||
match (String.get s 0) with
|
||||
| 'a' .. 'z' | 'A' .. 'Z' | '_' | '`' -> false
|
||||
| _ -> true
|
||||
end
|
||||
|
||||
let rec print_list ff print sep l =
|
||||
match l with
|
||||
| [] -> ()
|
||||
| [x] -> print ff x
|
||||
| x :: l ->
|
||||
print ff x;
|
||||
fprintf ff "%s@ " sep;
|
||||
print_list ff print sep l
|
||||
|
||||
let print_name ff n =
|
||||
let n = if is_infix n then
|
||||
match n with
|
||||
| "*" -> "( * )"
|
||||
| _ -> "(" ^ n ^ ")"
|
||||
else n
|
||||
in fprintf ff "%s" n
|
||||
|
||||
let print_longname ff n =
|
||||
match n with
|
||||
| Name(m) -> print_name ff m
|
||||
| Modname({ qual = "Pervasives"; id = m }) ->
|
||||
print_name ff m
|
||||
| Modname({ qual = m1; id = m2 }) ->
|
||||
fprintf ff "%s." m1; print_name ff m2
|
||||
|
||||
let print_ident ff id =
|
||||
fprintf ff "%s" (name id)
|
||||
|
||||
let rec print_pat ff = function
|
||||
| Evarpat(n) -> print_ident ff n
|
||||
| Etuplepat(pat_list) ->
|
||||
fprintf ff "@[(";
|
||||
print_list ff print_pat "," pat_list;
|
||||
fprintf ff ")@]"
|
||||
|
||||
let rec print_base_type ff = function
|
||||
| Tint -> fprintf ff "int"
|
||||
| Tfloat -> fprintf ff "float"
|
||||
| Tid(id) -> print_longname ff id
|
||||
| Tarray(ty, n) ->
|
||||
print_base_type ff ty;
|
||||
fprintf ff "^";
|
||||
print_size_exp ff n
|
||||
|
||||
let rec print_type ff = function
|
||||
| Tbase(base_ty) -> print_base_type ff base_ty
|
||||
| Tprod(ty_list) ->
|
||||
fprintf ff "@[(";
|
||||
print_list ff print_type " *" ty_list;
|
||||
fprintf ff ")@]"
|
||||
|
||||
let rec print_ck ff = function
|
||||
| Cbase -> fprintf ff "base"
|
||||
| Con(ck, c, n) ->
|
||||
print_ck ff ck; fprintf ff " on ";
|
||||
print_longname ff c; fprintf ff "(";
|
||||
print_ident ff n; fprintf ff ")"
|
||||
| Cvar { contents = Cindex n } -> fprintf ff "base"
|
||||
| Cvar { contents = Clink ck } -> print_ck ff ck
|
||||
|
||||
let rec print_clock ff = function
|
||||
| Ck(ck) -> print_ck ff ck
|
||||
| Cprod(ct_list) ->
|
||||
fprintf ff "@[(";
|
||||
print_list ff print_clock " *" ct_list;
|
||||
fprintf ff ")@]"
|
||||
|
||||
let print_vd ff { v_name = n; v_type = ty; v_clock = ck } =
|
||||
fprintf ff "@[<v>";
|
||||
print_ident ff n;
|
||||
fprintf ff ":";
|
||||
print_base_type ff ty;
|
||||
fprintf ff " at ";
|
||||
print_ck ff ck;
|
||||
fprintf ff "@]"
|
||||
|
||||
let rec print_c ff = function
|
||||
| Cint i -> fprintf ff "%d" i
|
||||
| Cfloat f -> fprintf ff "%f" f
|
||||
| Cconstr(tag) -> print_longname ff tag
|
||||
| Cconst_array (n, c) ->
|
||||
print_c ff c;
|
||||
fprintf ff "^";
|
||||
print_size_exp ff n
|
||||
|
||||
let print_call_params ff = function
|
||||
| [] -> ()
|
||||
| l ->
|
||||
fprintf ff "<<";
|
||||
print_list ff print_size_exp "," l;
|
||||
fprintf ff ">>"
|
||||
|
||||
let rec print_exps ff e_list =
|
||||
fprintf ff "@[(";print_list ff print_exp "," e_list; fprintf ff ")@]"
|
||||
|
||||
and print_exp ff e =
|
||||
if !Misc.full_type_info then fprintf ff "(";
|
||||
begin match e.e_desc with
|
||||
| Evar x -> print_ident ff x
|
||||
| Econstvar x -> print_name ff x
|
||||
| Econst c -> print_c ff c
|
||||
| Efby(Some(c), e) ->
|
||||
print_c ff c; fprintf ff " fby "; print_exp ff e
|
||||
| Ereset_mem(y,v,res) ->
|
||||
fprintf ff "@[reset_mem ";
|
||||
print_ident ff y;
|
||||
fprintf ff " = ";
|
||||
print_c ff v;
|
||||
fprintf ff " every ";
|
||||
print_ident ff res;
|
||||
fprintf ff "@]"
|
||||
| Efby(None, e) ->
|
||||
fprintf ff "pre "; print_exp ff e
|
||||
| Eop((Name(m) | Modname { qual = "Pervasives"; id = m }), params, [e1;e2])
|
||||
when is_infix m ->
|
||||
fprintf ff "(%a %s %a %a)"
|
||||
print_exp e1
|
||||
m
|
||||
print_call_params params
|
||||
print_exp e2
|
||||
| Eop(op, params, e_list) ->
|
||||
print_longname ff op;
|
||||
print_call_params ff params;
|
||||
print_exps ff e_list
|
||||
| Eapp({ a_op = f }, params, e_list) ->
|
||||
print_longname ff f;
|
||||
print_call_params ff params;
|
||||
print_exps ff e_list
|
||||
| Eevery({ a_op = f }, params, e_list, x) ->
|
||||
print_longname ff f;
|
||||
print_call_params ff params;
|
||||
print_exps ff e_list;
|
||||
fprintf ff " every "; print_ident ff x
|
||||
| Ewhen(e, c, n) ->
|
||||
fprintf ff "(";
|
||||
print_exp ff e;
|
||||
fprintf ff " when ";
|
||||
print_longname ff c; fprintf ff "(";
|
||||
print_ident ff n; fprintf ff ")";
|
||||
fprintf ff ")"
|
||||
| Eifthenelse(e1, e2, e3) ->
|
||||
fprintf ff "@[if ";print_exp ff e1;
|
||||
fprintf ff "@ then ";
|
||||
print_exp ff e2;
|
||||
fprintf ff "@ else ";
|
||||
print_exp ff e3;
|
||||
fprintf ff "@]"
|
||||
| Emerge(x, tag_e_list) ->
|
||||
fprintf ff "@[<hov 2>merge ";print_ident ff x;fprintf ff "@ ";
|
||||
fprintf ff "@[";
|
||||
print_tag_e_list ff tag_e_list;
|
||||
fprintf ff "@]@]"
|
||||
| Etuple(e_list) ->
|
||||
fprintf ff "@[(";
|
||||
print_list ff print_exp "," e_list;
|
||||
fprintf ff ")@]"
|
||||
| Efield(e, field) ->
|
||||
print_exp ff e;
|
||||
fprintf ff ".";
|
||||
print_longname ff field
|
||||
| Estruct(f_e_list) ->
|
||||
fprintf ff "@[<v 1>{";
|
||||
print_list ff
|
||||
(fun ff (field, e) -> print_longname ff field;fprintf ff " = ";
|
||||
print_exp ff e)
|
||||
";" f_e_list;
|
||||
fprintf ff "}@]"
|
||||
(*Array operators*)
|
||||
| Earray e_list ->
|
||||
fprintf ff "@[[";
|
||||
print_list ff print_exp ";" e_list;
|
||||
fprintf ff "]@]"
|
||||
| Erepeat (n,e) ->
|
||||
print_exp ff e;
|
||||
fprintf ff "^";
|
||||
print_size_exp ff n
|
||||
| Eselect (idx,e) ->
|
||||
print_exp ff e;
|
||||
fprintf ff "[";
|
||||
print_list ff print_size_exp "][" idx;
|
||||
fprintf ff "]"
|
||||
| Eselect_dyn (idx, _, e1, e2) ->
|
||||
fprintf ff "@[";
|
||||
print_exp ff e1;
|
||||
fprintf ff "[";
|
||||
print_list ff print_exp "][" idx;
|
||||
fprintf ff "] default ";
|
||||
print_exp ff e2;
|
||||
fprintf ff "@]"
|
||||
| Eupdate (idx, e1, e2) ->
|
||||
fprintf ff "@[";
|
||||
print_exp ff e1;
|
||||
fprintf ff " with [";
|
||||
print_list ff print_size_exp "][" idx;
|
||||
fprintf ff "] = ";
|
||||
print_exp ff e2;
|
||||
fprintf ff "@]"
|
||||
| Eselect_slice (idx1, idx2, e) ->
|
||||
print_exp ff e;
|
||||
fprintf ff "[";
|
||||
print_size_exp ff idx1;
|
||||
fprintf ff "..";
|
||||
print_size_exp ff idx2;
|
||||
fprintf ff "]"
|
||||
| Econcat (e1, e2) ->
|
||||
print_exp ff e1;
|
||||
fprintf ff " @@ ";
|
||||
print_exp ff e2
|
||||
| Eiterator (it, f, params, n, e_list, reset) ->
|
||||
fprintf ff "(";
|
||||
fprintf ff "%s" (iterator_to_string it);
|
||||
fprintf ff " ";
|
||||
(match params with
|
||||
| [] -> print_longname ff f
|
||||
| l ->
|
||||
fprintf ff "(";
|
||||
print_longname ff f;
|
||||
print_call_params ff params;
|
||||
fprintf ff ")"
|
||||
);
|
||||
fprintf ff " <<";
|
||||
print_size_exp ff n;
|
||||
fprintf ff ">>) (@[";
|
||||
print_list ff print_exp "," e_list;
|
||||
fprintf ff ")@]";
|
||||
(match reset with
|
||||
| None -> ()
|
||||
| Some r -> fprintf ff " every %s" (name r)
|
||||
)
|
||||
| Efield_update (f, e1, e2) ->
|
||||
fprintf ff "@[";
|
||||
print_exp ff e1;
|
||||
fprintf ff " with .";
|
||||
print_longname ff f;
|
||||
fprintf ff " = ";
|
||||
print_exp ff e2;
|
||||
fprintf ff "@]"
|
||||
end;
|
||||
if !Misc.full_type_info
|
||||
then begin
|
||||
fprintf ff " : %a)" print_type e.e_ty;
|
||||
if e.e_loc = no_location then fprintf ff " (no loc)"
|
||||
end
|
||||
and print_tag_e_list ff tag_e_list =
|
||||
print_list ff
|
||||
(fun ff (tag, e) ->
|
||||
fprintf ff "@[(";
|
||||
print_longname ff tag;
|
||||
fprintf ff " -> ";
|
||||
print_exp ff e;
|
||||
fprintf ff ")@]@,") ""
|
||||
tag_e_list
|
||||
|
||||
let print_eq ff { p_lhs = p; p_rhs = e } =
|
||||
fprintf ff "@[<hov 2>";
|
||||
print_pat ff p;
|
||||
(* (\* DEBUG *\) *)
|
||||
(* fprintf ff " : "; *)
|
||||
(* print_ck ff e.e_ck; *)
|
||||
(* (\* END DEBUG *\) *)
|
||||
fprintf ff " =@ ";
|
||||
print_exp ff e;
|
||||
if !Misc.full_type_info
|
||||
then begin fprintf ff "@ at "; print_ck ff e.e_ck end;
|
||||
fprintf ff ";@]"
|
||||
|
||||
let print_eqs ff l =
|
||||
fprintf ff "@[<v>"; print_list ff print_eq "" l; fprintf ff "@]"
|
||||
|
||||
let print_open_module ff name =
|
||||
fprintf ff "@[open ";
|
||||
print_name ff name;
|
||||
fprintf ff "@.@]"
|
||||
|
||||
let print_type_def ff { t_name = name; t_desc = tdesc } =
|
||||
match tdesc with
|
||||
| Type_abs -> fprintf ff "@[type %s@\n@]" name
|
||||
| Type_enum(tag_name_list) ->
|
||||
fprintf ff "@[type %s = " name;
|
||||
print_list ff print_name "|" tag_name_list;
|
||||
fprintf ff "@\n@]"
|
||||
| Type_struct(f_ty_list) ->
|
||||
fprintf ff "@[type %s = " name;
|
||||
fprintf ff "@[<v 1>{";
|
||||
print_list ff
|
||||
(fun ff (field, ty) -> print_name ff field;
|
||||
fprintf ff ": ";
|
||||
print_base_type ff ty) ";" f_ty_list;
|
||||
fprintf ff "}@]@\n@]"
|
||||
|
||||
let print_contract ff {c_local = l;
|
||||
c_eq = eqs;
|
||||
c_assume = e_a;
|
||||
c_enforce = e_g;
|
||||
c_controllables = cl } =
|
||||
if l <> [] then begin
|
||||
fprintf ff "contract\n";
|
||||
fprintf ff "@[<hov 4>var ";
|
||||
print_list ff print_vd ";" l;
|
||||
fprintf ff ";@]\n"
|
||||
end;
|
||||
if eqs <> [] then begin
|
||||
fprintf ff "@[<v 2>let @,";
|
||||
print_eqs ff eqs;
|
||||
fprintf ff "@]"; fprintf ff "tel\n"
|
||||
end;
|
||||
fprintf ff "assume@ %a@;enforce@ %a with ("
|
||||
print_exp e_a
|
||||
print_exp e_g;
|
||||
print_list ff print_vd ";" cl;
|
||||
fprintf ff ")"
|
||||
|
||||
let print_node_params ff = function
|
||||
| [] -> ()
|
||||
| l ->
|
||||
fprintf ff "<<";
|
||||
print_list ff print_name "," l;
|
||||
fprintf ff ">>"
|
||||
|
||||
let print_node ff
|
||||
{ n_name = n;n_input = ni;n_output = no;
|
||||
n_contract = contract;
|
||||
n_local = nl; n_equs = ne;
|
||||
n_params = params; } =
|
||||
fprintf ff "@[<v 2>node %s" n;
|
||||
print_node_params ff params;
|
||||
fprintf ff "(@[";
|
||||
print_list ff print_vd ";" ni;
|
||||
fprintf ff "@]) returns (@[";
|
||||
print_list ff print_vd ";" no;
|
||||
fprintf ff "@])@,";
|
||||
optunit (print_contract ff) contract;
|
||||
if nl <> [] then begin
|
||||
fprintf ff "@[<hov 2>var ";
|
||||
print_list ff print_vd ";" nl;
|
||||
fprintf ff ";@]@,"
|
||||
end;
|
||||
fprintf ff "@[<v 2>let @,";
|
||||
print_eqs ff ne;
|
||||
fprintf ff "@]@;"; fprintf ff "tel";fprintf ff "@.@]"
|
||||
|
||||
let print_exp oc e =
|
||||
let ff = formatter_of_out_channel oc in
|
||||
print_exp ff e;
|
||||
fprintf ff "@."
|
||||
|
||||
let print_type oc ty =
|
||||
let ff = formatter_of_out_channel oc in
|
||||
print_type ff ty;
|
||||
fprintf ff "@?"
|
||||
|
||||
let print_clock oc ct =
|
||||
let ff = formatter_of_out_channel oc in
|
||||
print_clock ff ct;
|
||||
fprintf ff "@?"
|
||||
|
||||
let print oc { p_opened = pm; p_types = pt; p_nodes = pn } =
|
||||
let ff = formatter_of_out_channel oc in
|
||||
List.iter (print_open_module ff) pm;
|
||||
List.iter (print_type_def ff) pt;
|
||||
List.iter (print_node ff) pn;
|
||||
fprintf ff "@?"
|
||||
end
|
337
minils/sequential/c.ml
Normal file
337
minils/sequential/c.ml
Normal file
|
@ -0,0 +1,337 @@
|
|||
(**************************************************************************)
|
||||
(* *)
|
||||
(* Heptagon *)
|
||||
(* *)
|
||||
(* Author : Marc Pouzet *)
|
||||
(* Organization : Demons, LRI, University of Paris-Sud, Orsay *)
|
||||
(* *)
|
||||
(**************************************************************************)
|
||||
|
||||
(* $Id$ *)
|
||||
|
||||
open Format
|
||||
open List
|
||||
open Modules
|
||||
|
||||
|
||||
let rec print_list ff print sep l =
|
||||
match l with
|
||||
| [] -> ()
|
||||
| [x] -> print ff x
|
||||
| x :: l ->
|
||||
print ff x;
|
||||
fprintf ff "%s@ " sep;
|
||||
print_list ff print sep l
|
||||
|
||||
|
||||
(******************************)
|
||||
|
||||
(** {2 C abstract syntax tree } *)
|
||||
|
||||
(** Here is the C abstract syntax tree used by MiniLS for its C backend. It does
|
||||
not try to completly model the C language, only the relatively small part
|
||||
that were are interested in (e.g. no function pointers or local variable
|
||||
initialization). *)
|
||||
|
||||
(** C types relevant for Obc. Note the absence of function pointers. *)
|
||||
type cty =
|
||||
| Cty_int (** C machine-dependent integer type. *)
|
||||
| Cty_float (** C machine-dependent single-precision floating-point type. *)
|
||||
| Cty_char (** C character type. *)
|
||||
| Cty_id of string (** Previously defined C type, such as an enum or struct. *)
|
||||
| Cty_ptr of cty (** C points-to-other-type type. *)
|
||||
| Cty_arr of int * cty (** A static array of the specified size. *)
|
||||
| Cty_void (** Well, [void] is not really a C type. *)
|
||||
|
||||
(** A C block: declarations and statements. In source code form, it begins with
|
||||
variable declarations before a list of semicolon-separated statements, the
|
||||
whole thing being enclosed in curly braces. *)
|
||||
type cblock = {
|
||||
(** Variable declarations, where each declaration consists of a variable
|
||||
name and the associated C type. *)
|
||||
var_decls : (string * cty) list;
|
||||
(** The actual statement forming our block. *)
|
||||
block_body : cstm list;
|
||||
}
|
||||
|
||||
(* TODO: The following types for C expressions would be better using polymorphic
|
||||
variants to define LHS expressions as a proper superset of general
|
||||
expressions. *)
|
||||
|
||||
(** C expressions. *)
|
||||
and cexpr =
|
||||
| Cuop of string * cexpr (** Unary operator with its name. *)
|
||||
| Cbop of string * cexpr * cexpr (** Binary operator. *)
|
||||
| Cfun_call of string * cexpr list (** Function call with its parameters. *)
|
||||
| Cconst of cconst (** Constants. *)
|
||||
| Clhs of clhs (** Left-hand-side expressions are obviously expressions! *)
|
||||
| Caddrof of clhs (** Take the address of a left-hand-side expression. *)
|
||||
| Cstructlit of string * cexpr list (** Structure literal "{ f1, f2, ... }". *)
|
||||
| Carraylit of cexpr list (** Array literal [e1, e2, ...]. *)
|
||||
and cconst =
|
||||
| Ccint of int (** Integer constant. *)
|
||||
| Ccfloat of float (** Floating-point number constant. *)
|
||||
| Ctag of string (** Tag, member of a previously declared enumeration. *)
|
||||
| Cstrlit of string (** String literal, enclosed in double-quotes. *)
|
||||
(** C left-hand-side (ie. affectable) expressions. *)
|
||||
and clhs =
|
||||
| Cvar of string (** A local variable. *)
|
||||
| Cderef of clhs (** Pointer dereference, *ptr. *)
|
||||
| Cfield of clhs * string (** Field access to left-hand-side. *)
|
||||
| Carray of clhs * cexpr (** Array access clhs[cexpr] *)
|
||||
(** C statements. *)
|
||||
and cstm =
|
||||
| Csexpr of cexpr (** Expression evaluation, may cause side-effects! *)
|
||||
| Csblock of cblock (** A local sub-block, can have its own private decls. **)
|
||||
| Cskip (** A dummy instruction that does nothing and will not be printed. *)
|
||||
| Caffect of clhs * cexpr (** Affect the result of an expression to a lhs. *)
|
||||
| Cif of cexpr * cstm list * cstm list (** Alternative *)
|
||||
| Cswitch of cexpr * (string * cstm list) list (** Case/switch over an enum. *)
|
||||
| Cwhile of cexpr * cstm list (** While loop. *)
|
||||
| Cfor of string * int * int * cstm list (** For loop. int <= string < int *)
|
||||
| Creturn of cexpr (** Ends a procedure/function by returning an expression.*)
|
||||
|
||||
(** C type declarations ; will {b always} correspond to a typedef in emitted
|
||||
source code. *)
|
||||
type cdecl =
|
||||
(** C enum declaration, with associated value tags. *)
|
||||
| Cdecl_enum of string * string list
|
||||
(** C structure declaration, with each field's name and type. *)
|
||||
| Cdecl_struct of string * (string * cty) list
|
||||
(** C function declaration. *)
|
||||
| Cdecl_function of string * cty * (string * cty) list
|
||||
|
||||
(** C function definitions *)
|
||||
type cfundef = {
|
||||
f_name : string; (** The function's name. *)
|
||||
f_retty : cty; (** The function's return type. *)
|
||||
f_args : (string * cty) list; (** Each parameter's name and type. *)
|
||||
f_body : cblock; (** Actual instructions, in the form of a block. *)
|
||||
}
|
||||
|
||||
(** C top-level definitions. *)
|
||||
type cdef =
|
||||
| Cfundef of cfundef (** Function definition, see [cfundef]. *)
|
||||
| Cvardef of string * cty (** A variable definition, with its name and type. *)
|
||||
|
||||
(** [cdecl_of_cfundef cfd] returns a declaration for the function def. [cfd]. *)
|
||||
let cdecl_of_cfundef cfd = match cfd with
|
||||
| Cfundef cfd -> Cdecl_function (cfd.f_name, cfd.f_retty, cfd.f_args)
|
||||
| _ -> invalid_arg "cdecl_of_cfundef"
|
||||
|
||||
(** A C file can be a source file, containing definitions, or a header file,
|
||||
containing declarations. *)
|
||||
type cfile = string * cfile_desc
|
||||
and cfile_desc =
|
||||
| Cheader of string list * cdecl list (** Header dependencies * declaration
|
||||
list *)
|
||||
| Csource of cdef list
|
||||
|
||||
(******************************)
|
||||
|
||||
(** {3 Pretty-printing of the C ast.} *)
|
||||
|
||||
(** [pp_list1 f sep fmt l] pretty-prints into the Format.formatter [fmt] elements
|
||||
of the list [l] via the function [f], separated by [sep] strings and
|
||||
breakable spaces. *)
|
||||
let rec pp_list1 f sep fmt l = match l with
|
||||
| [] -> fprintf fmt ""
|
||||
| [x] -> fprintf fmt "%a" f x
|
||||
| h :: t -> fprintf fmt "%a%s@ %a" f h sep (pp_list1 f sep) t
|
||||
|
||||
let rec pp_list f sep fmt l = match l with
|
||||
| [] -> fprintf fmt ""
|
||||
| h :: t -> fprintf fmt "@ %a%s%a" f h sep (pp_list f sep) t
|
||||
|
||||
let pp_string fmt s = fprintf fmt "%s" s
|
||||
|
||||
let rec pp_cty fmt cty = match cty with
|
||||
| Cty_int -> fprintf fmt "int"
|
||||
| Cty_float -> fprintf fmt "float"
|
||||
| Cty_char -> fprintf fmt "char"
|
||||
| Cty_id s -> fprintf fmt "%s" s
|
||||
| Cty_ptr cty' -> fprintf fmt "%a*" pp_cty cty'
|
||||
| Cty_arr (n, cty') -> fprintf fmt "%a[%d]" pp_cty cty' n
|
||||
| Cty_void -> fprintf fmt "void"
|
||||
|
||||
(** [pp_array_decl cty] returns the base type of a (multidimensionnal) array
|
||||
and the string of indices. *)
|
||||
let rec pp_array_decl cty =
|
||||
match cty with
|
||||
| Cty_arr(n, cty') ->
|
||||
let ty, s = pp_array_decl cty' in
|
||||
ty, sprintf "%s[%d]" s n
|
||||
| _ -> cty, ""
|
||||
|
||||
(* pp_vardecl, featuring an ugly hack coping with C's inconsistent concrete
|
||||
syntax! *)
|
||||
let rec pp_vardecl fmt (s, cty) = match cty with
|
||||
| Cty_arr (n, cty') ->
|
||||
let base_ty, indices = pp_array_decl cty in
|
||||
fprintf fmt "%a %s%s" pp_cty base_ty s indices
|
||||
| _ -> fprintf fmt "%a %s" pp_cty cty s
|
||||
and pp_paramdecl fmt (s, cty) = match cty with
|
||||
| Cty_arr (n, cty') -> fprintf fmt "%a* %s" pp_cty cty' s
|
||||
| _ -> pp_vardecl fmt (s, cty)
|
||||
and pp_param_list fmt l = pp_list1 pp_paramdecl "," fmt l
|
||||
and pp_var_list fmt l = pp_list pp_vardecl ";" fmt l
|
||||
|
||||
let rec pp_cblock fmt cb =
|
||||
let pp_varlist = pp_list pp_vardecl ";" in
|
||||
fprintf fmt "%a%a" pp_varlist cb.var_decls pp_cstm_list cb.block_body
|
||||
and pp_cstm_list fmt stml = pp_list pp_cstm ";" fmt stml
|
||||
and pp_cstm fmt stm = match stm with
|
||||
| Csexpr e -> fprintf fmt "%a" pp_cexpr e
|
||||
| Cswitch (e, cl) ->
|
||||
let pp_clause fmt (tag, stml) =
|
||||
fprintf fmt "@[<v 2>case %a:%a@ break;@]"
|
||||
pp_cexpr (Cconst (Ctag tag)) pp_cstm_list stml in
|
||||
fprintf fmt "@[<v>@[<v 2>switch (%a) {%a@]@ }@]"
|
||||
pp_cexpr e (pp_list pp_clause "") cl
|
||||
| Caffect (lhs, e) ->
|
||||
fprintf fmt "%a = %a" pp_clhs lhs pp_cexpr e
|
||||
| Cif (c, t, []) ->
|
||||
fprintf fmt "@[<v>@[<v 2>if (%a) {%a@]@ }@]"
|
||||
pp_cexpr c pp_cstm_list t
|
||||
| Cif (c, t, e) ->
|
||||
fprintf fmt "@[<v>@[<v 2>if (%a) {%a@]@ @[<v 2>} else {%a@]@ }@]"
|
||||
pp_cexpr c pp_cstm_list t pp_cstm_list e
|
||||
| Cfor(x, lower, upper, e) ->
|
||||
fprintf fmt "@[<v>@[<v 2>for (int %s = %d; %s < %d; ++%s) {%a@]@ }@]"
|
||||
x lower x upper x pp_cstm_list e
|
||||
| Cwhile (e, b) ->
|
||||
fprintf fmt "@[<v>@[<v 2>while (%a) {%a@]@ }@]" pp_cexpr e pp_cstm_list b
|
||||
| Csblock cb -> pp_cblock fmt cb
|
||||
| Cskip -> fprintf fmt ""
|
||||
| Creturn e -> fprintf fmt "return %a" pp_cexpr e
|
||||
and pp_cexpr fmt ce = match ce with
|
||||
| Cuop (s, e) -> fprintf fmt "%s(%a)" s pp_cexpr e
|
||||
| Cbop (s, l, r) -> fprintf fmt "(%a%s%a)" pp_cexpr l s pp_cexpr r
|
||||
| Cfun_call (s, el) -> fprintf fmt "%s(@[%a@])" s (pp_list1 pp_cexpr ",") el
|
||||
| Cconst (Ccint i) -> fprintf fmt "%d" i
|
||||
| Cconst (Ccfloat f) -> fprintf fmt "%f" f
|
||||
| Cconst (Ctag "true") -> fprintf fmt "TRUE"
|
||||
| Cconst (Ctag "false") -> fprintf fmt "FALSE"
|
||||
| Cconst (Ctag t) -> fprintf fmt "%s" t
|
||||
| Cconst (Cstrlit t) -> fprintf fmt "\"%s\"" t
|
||||
| Clhs lhs -> fprintf fmt "%a" pp_clhs lhs
|
||||
| Caddrof lhs -> fprintf fmt "&%a" pp_clhs lhs
|
||||
| Cstructlit (s, el) ->
|
||||
fprintf fmt "(%s){@[%a@]}" s (pp_list1 pp_cexpr ",") el
|
||||
| Carraylit el ->
|
||||
fprintf fmt "[@[%a@]]" (pp_list1 pp_cexpr ",") el
|
||||
and pp_clhs fmt lhs = match lhs with
|
||||
| Cvar s -> fprintf fmt "%s" s
|
||||
| Cderef lhs' -> fprintf fmt "*%a" pp_clhs lhs'
|
||||
| Cfield (Cderef lhs, f) -> fprintf fmt "%a->%s" pp_clhs lhs f
|
||||
| Cfield (lhs, f) -> fprintf fmt "%a.%s" pp_clhs lhs f
|
||||
| Carray (lhs, e) ->
|
||||
fprintf fmt "%a[%a]"
|
||||
pp_clhs lhs
|
||||
pp_cexpr e
|
||||
|
||||
let pp_cdecl fmt cdecl = match cdecl with
|
||||
| Cdecl_enum (s, sl) ->
|
||||
fprintf fmt "@[<v>@[<v 2>typedef enum {@ %a@]@ } %s;@ @]@\n"
|
||||
(pp_list1 pp_string ",") sl s
|
||||
| Cdecl_struct (s, fl) ->
|
||||
let pp_field fmt (s, cty) =
|
||||
fprintf fmt "@ %a;" pp_vardecl (s,cty) in
|
||||
fprintf fmt "@[<v>@[<v 2>typedef struct %s {" s;
|
||||
List.iter (pp_field fmt) fl;
|
||||
fprintf fmt "@]@ } %s;@ @]@\n" s
|
||||
| Cdecl_function (n, retty, args) ->
|
||||
fprintf fmt "@[<v>%a %s(@[<hov>%a@]);@ @]@\n"
|
||||
pp_cty retty n pp_param_list args
|
||||
|
||||
let pp_cdef fmt cdef = match cdef with
|
||||
| Cfundef cfd ->
|
||||
fprintf fmt
|
||||
"@[<v>@[<v 2>%a %s(@[<hov>%a@]) {%a@]@ }@ @]@\n"
|
||||
pp_cty cfd.f_retty cfd.f_name pp_param_list cfd.f_args
|
||||
pp_cblock cfd.f_body
|
||||
| Cvardef (s, cty) -> fprintf fmt "%a %s;@\n" pp_cty cty s
|
||||
|
||||
let pp_cfile_desc fmt filen cfile =
|
||||
(** [filen_wo_ext] is the file's name without the extension. *)
|
||||
let filen_wo_ext = String.sub filen 0 (String.length filen - 2) in
|
||||
match cfile with
|
||||
| Cheader (deps, cdecls) ->
|
||||
let headern_macro = String.uppercase filen_wo_ext in
|
||||
Misc.print_header_info fmt "/*" "*/";
|
||||
fprintf fmt "#ifndef %s_H@\n" headern_macro;
|
||||
fprintf fmt "#define %s_H@\n@\n" headern_macro;
|
||||
(* fprintf fmt "#include \"types.h\"\n"; *)
|
||||
iter (fun d -> fprintf fmt "#include \"%s.h\"@\n" d)
|
||||
deps;
|
||||
iter (pp_cdecl fmt) cdecls;
|
||||
fprintf fmt "#endif // %s_H@\n" headern_macro
|
||||
| Csource cdefs ->
|
||||
let headern = filen_wo_ext ^ ".h" in
|
||||
Misc.print_header_info fmt "/*" "*/";
|
||||
fprintf fmt "#include <stdio.h>@\n";
|
||||
fprintf fmt "#include <string.h>@\n";
|
||||
fprintf fmt "#include \"%s\"@\n@\n" headern;
|
||||
fprintf fmt "#define FALSE 0@\n#define TRUE 1@\n@\n";
|
||||
iter (pp_cdef fmt) cdefs
|
||||
|
||||
(******************************)
|
||||
|
||||
(** [output_cfile dir cfile] pretty-prints the content of [cfile] to the
|
||||
corresponding file in the [dir] directory. *)
|
||||
let output_cfile dir (filen, cfile_desc) =
|
||||
if !Misc.verbose then Printf.printf "C-NG generating %s/%s\n" dir filen;
|
||||
let buf = Buffer.create 20000 in
|
||||
let oc = open_out (Filename.concat dir filen) in
|
||||
let fmt = Format.formatter_of_buffer buf in
|
||||
pp_cfile_desc fmt filen cfile_desc;
|
||||
Buffer.output_buffer oc buf;
|
||||
close_out oc
|
||||
|
||||
let output dir cprog =
|
||||
List.iter (output_cfile dir) cprog
|
||||
|
||||
(** { Lexical conversions to C's syntax } *)
|
||||
|
||||
(** [cname_of_name name] translates the string [name] to a valid C identifier.
|
||||
Copied verbatim from the old C backend. *)
|
||||
let cname_of_name name =
|
||||
let buf = Buffer.create (String.length name) in
|
||||
let rec convert c =
|
||||
match c with
|
||||
| 'A'..'Z' | 'a'..'z' | '0'..'9' | '_' ->
|
||||
Buffer.add_char buf c
|
||||
| '\'' -> Buffer.add_string buf "_prime"
|
||||
| _ ->
|
||||
Buffer.add_string buf "lex";
|
||||
Buffer.add_string buf (string_of_int (Char.code c));
|
||||
Buffer.add_string buf "_" in
|
||||
String.iter convert name;
|
||||
Buffer.contents buf
|
||||
|
||||
(** Converts an expression to a lhs. *)
|
||||
let lhs_of_exp e =
|
||||
match e with
|
||||
| Clhs e -> e
|
||||
| _ -> assert false
|
||||
|
||||
(** Returns the type of a pointer to a type, except for
|
||||
types which are already pointers. *)
|
||||
let pointer_to ty =
|
||||
match ty with
|
||||
| Cty_arr _ | Cty_ptr _ -> ty
|
||||
| _ -> Cty_ptr ty
|
||||
|
||||
(** Returns whether a type is a pointer. *)
|
||||
let is_pointer_type = function
|
||||
| Cty_arr _ | Cty_ptr _ -> true
|
||||
| _ -> false
|
||||
|
||||
(** [array_base_ctype ty idx_list] returns the base type of an array
|
||||
type. If idx_list = [i1; ..; ip] and a is a variable of type ty,
|
||||
then it returns a[i1]..[ip]. *)
|
||||
let rec array_base_ctype ty idx_list =
|
||||
match ty, idx_list with
|
||||
| Cty_arr (n, ty), [i] -> ty
|
||||
| Cty_arr (n, ty), i::idx_list -> array_base_ctype ty idx_list
|
||||
| _ -> assert false
|
131
minils/sequential/c.mli
Normal file
131
minils/sequential/c.mli
Normal file
|
@ -0,0 +1,131 @@
|
|||
(**************************************************************************)
|
||||
(* *)
|
||||
(* Heptagon *)
|
||||
(* *)
|
||||
(* Author : Marc Pouzet *)
|
||||
(* Organization : Demons, LRI, University of Paris-Sud, Orsay *)
|
||||
(* *)
|
||||
(**************************************************************************)
|
||||
|
||||
(* $Id$ *)
|
||||
|
||||
(** Abstract syntax tree for C programs. *)
|
||||
(** {2 C abstract syntax tree } *)
|
||||
|
||||
(** Here is the C abstract syntax tree used by MiniLS for its C backend. It does
|
||||
not try to completly model the C language, only the relatively small part
|
||||
that were are interested in (e.g. no function pointers or local variable
|
||||
initialization). *)
|
||||
|
||||
(** C types relevant for Obc. Note the absence of function pointers. *)
|
||||
type cty =
|
||||
| Cty_int (** C machine-dependent integer type. *)
|
||||
| Cty_float (** C machine-dependent single-precision floating-point type. *)
|
||||
| Cty_char (** C character type. *)
|
||||
| Cty_id of string (** Previously defined C type, such as an enum or struct. *)
|
||||
| Cty_ptr of cty (** C points-to-other-type type. *)
|
||||
| Cty_arr of int * cty (** A static array of the specified size. *)
|
||||
| Cty_void (** Well, [void] is not really a C type. *)
|
||||
|
||||
(** A C block: declarations and statements. In source code form, it begins with
|
||||
variable declarations before a list of semicolon-separated statements, the
|
||||
whole thing being enclosed in curly braces. *)
|
||||
type cblock = {
|
||||
(** Variable declarations, where each declaration consists of a variable
|
||||
name and the associated C type. *)
|
||||
var_decls : (string * cty) list;
|
||||
(** The actual statement forming our block. *)
|
||||
block_body : cstm list;
|
||||
}
|
||||
|
||||
(** C expressions. *)
|
||||
and cexpr =
|
||||
| Cuop of string * cexpr (** Unary operator with its name. *)
|
||||
| Cbop of string * cexpr * cexpr (** Binary operator. *)
|
||||
| Cfun_call of string * cexpr list (** Function call with its parameters. *)
|
||||
| Cconst of cconst (** Constants. *)
|
||||
| Clhs of clhs (** Left-hand-side expressions are obviously expressions! *)
|
||||
| Caddrof of clhs (** Take the address of a left-hand-side expression. *)
|
||||
| Cstructlit of string * cexpr list (** Structure literal " \{f1, f2, ... \}". *)
|
||||
| Carraylit of cexpr list (** Array literal [e1, e2, ...]. *)
|
||||
and cconst =
|
||||
| Ccint of int (** Integer constant. *)
|
||||
| Ccfloat of float (** Floating-point number constant. *)
|
||||
| Ctag of string (** Tag, member of a previously declared enumeration. *)
|
||||
| Cstrlit of string (** String literal, enclosed in double-quotes. *)
|
||||
(** C left-hand-side (ie. affectable) expressions. *)
|
||||
and clhs =
|
||||
| Cvar of string (** A local variable. *)
|
||||
| Cderef of clhs (** Pointer dereference, *ptr. *)
|
||||
| Cfield of clhs * string (** Field access to left-hand-side. *)
|
||||
| Carray of clhs * cexpr (** Array access clhs[cexpr] *)
|
||||
(** C statements. *)
|
||||
and cstm =
|
||||
| Csexpr of cexpr (** Expression evaluation, may cause side-effects! *)
|
||||
| Csblock of cblock (** A local sub-block, can have its own private decls. **)
|
||||
| Cskip (** A dummy instruction that does nothing and will not be printed. *)
|
||||
| Caffect of clhs * cexpr (** Affect the result of an expression to a lhs. *)
|
||||
| Cif of cexpr * cstm list * cstm list (** Alternative *)
|
||||
| Cswitch of cexpr * (string * cstm list) list (** Case/switch over an enum. *)
|
||||
| Cwhile of cexpr * cstm list (** While loop. *)
|
||||
| Cfor of string * int * int * cstm list (** For loop. int <= string < int *)
|
||||
| Creturn of cexpr (** Ends a procedure/function by returning an expression.*)
|
||||
|
||||
(** C type declarations ; will {b always} correspond to a typedef in emitted
|
||||
source code. *)
|
||||
type cdecl =
|
||||
(** C enum declaration, with associated value tags. *)
|
||||
| Cdecl_enum of string * string list
|
||||
(** C structure declaration, with each field's name and type. *)
|
||||
| Cdecl_struct of string * (string * cty) list
|
||||
(** C function declaration. *)
|
||||
| Cdecl_function of string * cty * (string * cty) list
|
||||
|
||||
(** C function definition *)
|
||||
type cfundef = {
|
||||
f_name : string; (** The function's name. *)
|
||||
f_retty : cty; (** The function's return type. *)
|
||||
f_args : (string * cty) list; (** Each parameter's name and type. *)
|
||||
f_body : cblock; (** Actual instructions, in the form of a block. *)
|
||||
}
|
||||
|
||||
(** C top-level definitions. *)
|
||||
type cdef =
|
||||
| Cfundef of cfundef (** Function definition, see [cfundef]. *)
|
||||
| Cvardef of string * cty (** A variable definition, with its name and type. *)
|
||||
|
||||
val cdecl_of_cfundef : cdef -> cdecl
|
||||
|
||||
(** A C file can be a source file, containing definitions, or a header file,
|
||||
containing declarations. *)
|
||||
type cfile_desc =
|
||||
| Cheader of string list * cdecl list (** Header dependencies * declaration
|
||||
list *)
|
||||
| Csource of cdef list
|
||||
|
||||
type cfile = string * cfile_desc (** File name * file content *)
|
||||
|
||||
(** [output dir cprog] pretty-prints the C program [cprog] to new files in the
|
||||
directory [dir]. *)
|
||||
val output : string -> cfile list -> unit
|
||||
|
||||
(** [cname_of_name name] translates the string [name] to a valid C identifier.
|
||||
Copied verbatim from the old C backend. *)
|
||||
val cname_of_name : string -> string
|
||||
|
||||
(** Converts an expression to a lhs. *)
|
||||
val lhs_of_exp : cexpr -> clhs
|
||||
|
||||
(** Returns the type of a pointer to a type, except for
|
||||
types which are already pointers. *)
|
||||
val pointer_to : cty -> cty
|
||||
|
||||
(** Returns whether a type is a pointer. *)
|
||||
val is_pointer_type : cty -> bool
|
||||
|
||||
(** [array_base_ctype ty idx_list] returns the base type of an array
|
||||
type. If idx_list = [i1; ..; ip] and a is a variable of type ty,
|
||||
then it returns a[i1]..[ip]. *)
|
||||
val array_base_ctype : cty -> int list -> cty
|
||||
|
||||
|
1008
minils/sequential/cgen.ml
Normal file
1008
minils/sequential/cgen.ml
Normal file
File diff suppressed because it is too large
Load diff
81
minils/sequential/control.ml
Normal file
81
minils/sequential/control.ml
Normal file
|
@ -0,0 +1,81 @@
|
|||
(**************************************************************************)
|
||||
(* *)
|
||||
(* Heptagon *)
|
||||
(* *)
|
||||
(* Author : Marc Pouzet *)
|
||||
(* Organization : Demons, LRI, University of Paris-Sud, Orsay *)
|
||||
(* *)
|
||||
(**************************************************************************)
|
||||
|
||||
(* control optimisation *)
|
||||
|
||||
(* $Id$ *)
|
||||
|
||||
open Minils
|
||||
open Ident
|
||||
open Misc
|
||||
|
||||
let var_from_name map x =
|
||||
begin try
|
||||
Env.find x map
|
||||
with
|
||||
_ -> assert false
|
||||
end
|
||||
|
||||
let rec find c = function
|
||||
| [] -> raise Not_found
|
||||
| (c1, s1) :: h ->
|
||||
if c = c1 then s1, h else let s, h = find c h in s, (c1, s1) :: h
|
||||
|
||||
let rec control map ck s =
|
||||
match ck with
|
||||
| Cbase | Cvar { contents = Cindex _ } -> s
|
||||
| Cvar { contents = Clink ck } -> control map ck s
|
||||
| Con(ck, c, n) ->
|
||||
let e = var_from_name map n in
|
||||
control map ck (Obc.Case(Obc.Lhs e, [(c, s)]))
|
||||
|
||||
let rec simplify act =
|
||||
match act with
|
||||
| Obc.Assgn (lhs, e) ->
|
||||
(match e with
|
||||
| Obc.Lhs l when l = lhs -> Obc.Nothing
|
||||
| _ -> act
|
||||
)
|
||||
| Obc.Case(lhs, h) ->
|
||||
(match simplify_handlers h with
|
||||
| [] -> Obc.Nothing
|
||||
| h -> Obc.Case(lhs, h)
|
||||
)
|
||||
| _ -> act
|
||||
|
||||
and simplify_handlers = function
|
||||
| [] -> []
|
||||
| (n,a)::h ->
|
||||
let h = simplify_handlers h in
|
||||
(match simplify a with
|
||||
| Obc.Nothing -> h
|
||||
| a -> (n,a)::h
|
||||
)
|
||||
|
||||
let rec join s1 s2 =
|
||||
match simplify s1, simplify s2 with
|
||||
| Obc.Case(Obc.Lhs(n), h1), Obc.Case(Obc.Lhs(m), h2) when n = m ->
|
||||
Obc.Case(Obc.Lhs(n), joinhandlers h1 h2)
|
||||
| s1, Obc.Nothing -> s1
|
||||
| Obc.Nothing, s2 -> s2
|
||||
| s1, Obc.Comp(s2, s3) -> Obc.Comp(join s1 s2, s3)
|
||||
| s1, s2 -> Obc.Comp(s1, s2)
|
||||
|
||||
and joinhandlers h1 h2 =
|
||||
match h1 with
|
||||
| [] -> h2
|
||||
| (c1, s1) :: h1' ->
|
||||
let s1', h2' =
|
||||
try let s2, h2'' = find c1 h2 in join s1 s2, h2''
|
||||
with Not_found -> simplify s1, h2 in
|
||||
(c1, s1') :: joinhandlers h1' h2'
|
||||
|
||||
let rec joinlist = function
|
||||
| [] -> Obc.Nothing
|
||||
| s :: l -> join s (joinlist l)
|
65
minils/sequential/csubst.ml
Normal file
65
minils/sequential/csubst.ml
Normal file
|
@ -0,0 +1,65 @@
|
|||
open C
|
||||
open Obc
|
||||
open Ident
|
||||
open Names
|
||||
|
||||
let rec subst_stm map stm =
|
||||
match stm with
|
||||
| Csexpr e -> Csexpr (subst_exp map e)
|
||||
| Cskip -> Cskip
|
||||
| Creturn e -> Creturn (subst_exp map e)
|
||||
| Csblock cblock ->
|
||||
Csblock (subst_block map cblock)
|
||||
| Caffect (lhs, e) ->
|
||||
Caffect(subst_lhs map lhs, subst_exp map e)
|
||||
| Cif (e, truel, falsel) ->
|
||||
Cif (subst_exp map e, subst_stm_list map truel,
|
||||
subst_stm_list map falsel)
|
||||
| Cswitch (e, l) ->
|
||||
Cswitch (subst_exp map e, List.map (fun (s, sl) -> s, subst_stm_list map sl) l)
|
||||
| Cwhile (e, l) ->
|
||||
Cwhile (subst_exp map e, subst_stm_list map l)
|
||||
| Cfor (x, i1, i2, l) ->
|
||||
Cfor (x, i1, i2, subst_stm_list map l)
|
||||
|
||||
and subst_stm_list map =
|
||||
List.map (subst_stm map)
|
||||
|
||||
and subst_lhs map lhs =
|
||||
match lhs with
|
||||
| Cvar n ->
|
||||
if NamesEnv.mem n map then
|
||||
NamesEnv.find n map
|
||||
else
|
||||
lhs
|
||||
| Cfield (lhs, s) -> Cfield (subst_lhs map lhs, s)
|
||||
| Carray (lhs, n) -> Carray (subst_lhs map lhs, n)
|
||||
| Cderef lhs -> Cderef (subst_lhs map lhs)
|
||||
|
||||
and subst_exp map = function
|
||||
| Cuop (op, e) -> Cuop (op, subst_exp map e)
|
||||
| Cbop (s, l, r) -> Cbop (s, subst_exp map l, subst_exp map r)
|
||||
| Cfun_call (s, el) -> Cfun_call (s, subst_exp_list map el)
|
||||
| Cconst x -> Cconst x
|
||||
| Clhs lhs -> Clhs (subst_lhs map lhs)
|
||||
| Caddrof lhs -> Caddrof (subst_lhs map lhs)
|
||||
| Cstructlit (s, el) -> Cstructlit (s, subst_exp_list map el)
|
||||
| Carraylit el -> Carraylit (subst_exp_list map el)
|
||||
|
||||
and subst_exp_list map =
|
||||
List.map (subst_exp map)
|
||||
|
||||
and subst_block map b =
|
||||
{b with block_body = subst_stm_list map b.block_body}
|
||||
|
||||
let assoc_map_for_fun sf =
|
||||
match sf.out with
|
||||
| [] -> NamesEnv.empty
|
||||
| [vd] when Obc.is_scalar_type (List.hd sf.out) ->
|
||||
NamesEnv.empty
|
||||
| out ->
|
||||
let fill_field map vd =
|
||||
NamesEnv.add (name vd.v_name) (Cfield (Cderef (Cvar "self"), name vd.v_name)) map
|
||||
in
|
||||
List.fold_left fill_field NamesEnv.empty out
|
||||
|
596
minils/sequential/java.ml
Normal file
596
minils/sequential/java.ml
Normal file
|
@ -0,0 +1,596 @@
|
|||
(**************************************************************************)
|
||||
(* *)
|
||||
(* Heptagon *)
|
||||
(* *)
|
||||
(* Author : Marc Pouzet *)
|
||||
(* Organization : Demons, LRI, University of Paris-Sud, Orsay *)
|
||||
(* *)
|
||||
(**************************************************************************)
|
||||
(* $Id$ *)
|
||||
|
||||
open Global
|
||||
open Modules
|
||||
open Format
|
||||
open Obc
|
||||
open Misc
|
||||
open Names
|
||||
open Ident
|
||||
|
||||
let actual_type ty =
|
||||
match ty with
|
||||
| Tid(tn) when (shortname tn) = "float" -> Tfloat
|
||||
| Tid(tn) when (shortname tn) = "int" -> Tint
|
||||
| _ -> ty
|
||||
|
||||
(******************************)
|
||||
let rec print_list ff print sep l =
|
||||
match l with
|
||||
| [] -> ()
|
||||
| [x] -> print ff x
|
||||
| x :: l ->
|
||||
print ff x;
|
||||
fprintf ff "%s@ " sep;
|
||||
print_list ff print sep l
|
||||
|
||||
let jname_of_name name =
|
||||
let b = Buffer.create (String.length name) in
|
||||
let rec convert c =
|
||||
match c with
|
||||
| 'A'..'Z' | 'a'..'z' | '0'..'9' | '_' ->
|
||||
Buffer.add_char b c
|
||||
| '\'' -> Buffer.add_string b "_prime"
|
||||
| _ ->
|
||||
Buffer.add_string b "lex";
|
||||
Buffer.add_string b (string_of_int (Char.code c));
|
||||
Buffer.add_string b "_" in
|
||||
|
||||
String.iter convert name;
|
||||
Buffer.contents b
|
||||
|
||||
let print_name ff name =
|
||||
fprintf ff "%s" (jname_of_name name)
|
||||
|
||||
let print_shortname ff longname =
|
||||
print_name ff (shortname longname)
|
||||
|
||||
let o_types : type_dec list ref = ref []
|
||||
|
||||
let java_type_default_value = function
|
||||
| Tint -> "int", "0"
|
||||
| Tfloat -> "float", "0.0"
|
||||
| Tid (Name("bool"))
|
||||
| Tid (Modname({ id = "bool" })) ->
|
||||
"boolean", "false"
|
||||
| Tid t when ((shortname t) = "int") -> "int", "0"
|
||||
| Tid t when ((shortname t) = "float") -> "float", "0.0"
|
||||
| Tid t ->
|
||||
begin try
|
||||
let { info = ty_desc } = find_type (t) in
|
||||
begin match ty_desc with
|
||||
| Tenum _ ->
|
||||
"int", "0"
|
||||
| _ ->
|
||||
let t = shortname t in
|
||||
if t = "bool"
|
||||
then ("boolean", "false")
|
||||
else (t, "null")
|
||||
end
|
||||
with Not_found ->
|
||||
begin try
|
||||
let { t_desc = tdesc } =
|
||||
List.find (fun {t_name = tn} -> tn = (shortname t)) !o_types in
|
||||
begin match tdesc with
|
||||
| Type_enum _ ->
|
||||
"int", "0"
|
||||
| _ ->
|
||||
let t = shortname t in
|
||||
if t = "bool"
|
||||
then ("boolean", "false")
|
||||
else (t, "null")
|
||||
end
|
||||
with Not_found ->
|
||||
let t = shortname t in
|
||||
if t = "bool"
|
||||
then ("boolean", "false")
|
||||
else (t, "null")
|
||||
end
|
||||
end
|
||||
|
||||
let print_type ff ty =
|
||||
let jty,_ = java_type_default_value ty in
|
||||
print_name ff jty
|
||||
|
||||
let print_field ff (name,ty) =
|
||||
fprintf ff "%a %a;"
|
||||
print_type ty
|
||||
print_name name
|
||||
|
||||
let print_const_field ff (name,ty) =
|
||||
fprintf ff "%a@ %a"
|
||||
print_type ty
|
||||
print_name name
|
||||
|
||||
let print_assgt_field ff (name,_) =
|
||||
fprintf ff "this.%a = %a;"
|
||||
print_name name
|
||||
print_name name
|
||||
|
||||
(* assumes tn is already translated with jname_of_name *)
|
||||
let print_struct_type ff tn fields =
|
||||
fprintf ff "@[<v>@[<v 2>public class %s {@ " tn;
|
||||
(* fields *)
|
||||
print_list ff print_field "" fields;
|
||||
(* constructor *)
|
||||
let sorted_fields =
|
||||
List.sort
|
||||
(fun (n1,_) (n2,_) -> String.compare n1 n2)
|
||||
fields in
|
||||
fprintf ff "@ @[<v 2>public %s(@[<hov>" tn;
|
||||
print_list ff print_const_field "," sorted_fields;
|
||||
fprintf ff "@]) {@ ";
|
||||
(* constructor assignments *)
|
||||
print_list ff print_assgt_field "" fields;
|
||||
(* constructor end *)
|
||||
fprintf ff "@]@ }";
|
||||
(* class end *)
|
||||
fprintf ff "@]@ }@]"
|
||||
|
||||
|
||||
let rec print_tags ff n = function
|
||||
| [] -> ()
|
||||
| tg :: tgs' ->
|
||||
fprintf ff "@ public static final int %a = %d;"
|
||||
print_name tg
|
||||
n;
|
||||
print_tags ff (n+1) tgs'
|
||||
|
||||
(* assumes tn is already translated with jname_of_name *)
|
||||
let print_enum_type ff tn tgs =
|
||||
fprintf ff "@[<v>@[<v 2>public class %s {" tn;
|
||||
print_tags ff 1 tgs;
|
||||
fprintf ff "@]@ }@]"
|
||||
|
||||
let print_type_to_file java_dir headers { t_name = tn; t_desc = td} =
|
||||
let tn = jname_of_name tn in
|
||||
match td with
|
||||
| Type_abs -> ()
|
||||
| Type_enum tgs ->
|
||||
let out_ch = open_out (java_dir ^ "/" ^ tn ^ ".java") in
|
||||
let ff = formatter_of_out_channel out_ch in
|
||||
Misc.print_header_info ff "/*" "*/";
|
||||
List.iter (fprintf ff "%s") headers;
|
||||
(* fprintf ff "@[<v>package %s;@\n@\n" headers; *)
|
||||
print_enum_type ff tn tgs;
|
||||
fprintf ff "@.";
|
||||
close_out out_ch
|
||||
| Type_struct fields ->
|
||||
let out_ch = open_out (java_dir ^ "/" ^ tn ^ ".java") in
|
||||
let ff = formatter_of_out_channel out_ch in
|
||||
Misc.print_header_info ff "/*" "*/";
|
||||
List.iter (fprintf ff "%s") headers;
|
||||
(* fprintf ff "@[<v>package %s;@\n@\n" headers; *)
|
||||
print_struct_type ff tn fields;
|
||||
fprintf ff "@.";
|
||||
close_out out_ch
|
||||
|
||||
let print_types java_dir headers tps =
|
||||
List.iter (print_type_to_file java_dir headers) tps
|
||||
|
||||
(******************************)
|
||||
|
||||
type answer =
|
||||
| Sing of var_name
|
||||
| Mult of var_name list
|
||||
|
||||
let print_const ff c ts =
|
||||
match c with
|
||||
| Cint i -> fprintf ff "%d" i
|
||||
| Cfloat f -> fprintf ff "%f" f
|
||||
| Cconstr t ->
|
||||
let s =
|
||||
match t with
|
||||
| Name("true")
|
||||
| Modname({id = "true"}) -> "true"
|
||||
| Name("false")
|
||||
| Modname({id = "false"}) -> "false"
|
||||
| Name(tg)
|
||||
| Modname({id = tg}) ->
|
||||
(fst
|
||||
(List.find
|
||||
(fun (tn, tgs) ->
|
||||
List.exists (fun tg' -> tg = tg') tgs)
|
||||
ts))
|
||||
^ "." ^ (jname_of_name tg)
|
||||
in
|
||||
fprintf ff "%s" s
|
||||
|
||||
let position a xs =
|
||||
let rec walk i = function
|
||||
| [] -> None
|
||||
| x :: xs' -> if x = a then Some i else walk (i + 1) xs'
|
||||
in walk 1 xs
|
||||
|
||||
let print_ident ff id =
|
||||
print_name ff (name id)
|
||||
|
||||
let print_var ff x avs single =
|
||||
match (position x avs) with
|
||||
| None -> print_ident ff x
|
||||
| Some n ->
|
||||
if single then print_ident ff (List.hd avs)
|
||||
else fprintf ff "step_ans.c_%d" n
|
||||
|
||||
let javaop_of_op = function
|
||||
| "=" -> "=="
|
||||
| "<>" -> "!="
|
||||
| "or" -> "||"
|
||||
| "&" -> "&&"
|
||||
| "*." -> "*"
|
||||
| "/." -> "/"
|
||||
| "+." -> "+"
|
||||
| "-." -> "-"
|
||||
| op -> op
|
||||
|
||||
let priority = function
|
||||
| "*" | "/" | "*." | "/." -> 5
|
||||
| "+" | "-" | "+." | "-." -> 4
|
||||
| "=" | "<>" | "<=" | "=>" -> 3
|
||||
| "&" -> 2
|
||||
| "|" -> 1
|
||||
| _ -> 0
|
||||
|
||||
let rec print_lhs ff e avs single =
|
||||
match e with
|
||||
| Var x ->
|
||||
print_var ff x avs single
|
||||
| Mem x -> print_ident ff x
|
||||
| Field(e, field) ->
|
||||
print_lhs ff e avs single;
|
||||
fprintf ff ".%s" (jname_of_name (shortname field))
|
||||
|
||||
let rec print_exp ff e p avs ts single =
|
||||
match e with
|
||||
| Lhs l -> print_lhs ff l avs single
|
||||
| Const c -> print_const ff c ts
|
||||
| Op (op, es) -> print_op ff op es p avs ts single
|
||||
| Struct(type_name,fields) ->
|
||||
let fields =
|
||||
List.sort
|
||||
(fun (ln1,_) (ln2,_) -> String.compare (shortname ln1) (shortname ln2))
|
||||
fields in
|
||||
let exps = List.map (fun (_,e) -> e) fields in
|
||||
fprintf ff "new %a(@[<hov>"
|
||||
print_shortname type_name;
|
||||
print_exps ff exps 0 avs ts single;
|
||||
fprintf ff "@])"
|
||||
|
||||
and print_exps ff es p avs ts single =
|
||||
match es with
|
||||
| [] -> ()
|
||||
| [e] -> print_exp ff e p avs ts single
|
||||
| e :: es' ->
|
||||
print_exp ff e p avs ts single;
|
||||
fprintf ff ",@ ";
|
||||
print_exps ff es' p avs ts single
|
||||
|
||||
and print_op ff op es p avs ts single =
|
||||
match (shortname op), es with
|
||||
| (("+" | "-" | "*" | "/"
|
||||
|"+." | "-." | "*." | "/."
|
||||
| "=" | "<>" | "<" | "<="
|
||||
| ">" | ">=" | "&" | "or") as op_name, [e1;e2]) ->
|
||||
let p' = priority op_name in
|
||||
if p' < p then fprintf ff "(" else ();
|
||||
print_exp ff e1 p' avs ts single;
|
||||
fprintf ff " %s " (javaop_of_op op_name);
|
||||
print_exp ff e2 p' avs ts single;
|
||||
if p' < p then fprintf ff ")" else ()
|
||||
| "not", [e] ->
|
||||
fprintf ff "!";
|
||||
print_exp ff e 6 avs ts single;
|
||||
| "~-", [e] ->
|
||||
fprintf ff "-";
|
||||
print_exp ff e 6 avs ts single;
|
||||
| _ ->
|
||||
begin
|
||||
begin
|
||||
match op with
|
||||
| Name(op_name) ->
|
||||
print_name ff op_name;
|
||||
| Modname({ qual = mod_name; id = op_name }) ->
|
||||
fprintf ff "%a.%a"
|
||||
print_name (String.uncapitalize mod_name)
|
||||
print_name op_name
|
||||
end;
|
||||
fprintf ff "@[(";
|
||||
print_exps ff es 0 avs ts single;
|
||||
fprintf ff ")@]"
|
||||
end
|
||||
|
||||
let rec print_proj ff xs ao avs single =
|
||||
let rec walk ind = function
|
||||
| [] -> ()
|
||||
| x :: xs' ->
|
||||
print_lhs ff x avs single;
|
||||
fprintf ff " = %s.c_%d;@ " ao ind;
|
||||
walk (ind + 1) xs'
|
||||
in walk 1 xs
|
||||
|
||||
|
||||
let bool_case = function
|
||||
| [] -> assert false
|
||||
| ("true", _) :: _
|
||||
| ("false", _) :: _ -> true
|
||||
| _ -> false
|
||||
|
||||
let rec print_act ff a objs avs ts single =
|
||||
match a with
|
||||
| Assgn (x, e) ->
|
||||
fprintf ff "@[";
|
||||
print_asgn ff x e avs ts single;
|
||||
fprintf ff ";@]"
|
||||
| Step_ap (xs, o, es) ->
|
||||
(match xs with
|
||||
| [x] ->
|
||||
print_lhs ff x avs single;
|
||||
fprintf ff " = %s.step(" o;
|
||||
fprintf ff "@[";
|
||||
print_exps ff es 0 avs ts single;
|
||||
fprintf ff "@]";
|
||||
fprintf ff ");@ "
|
||||
| xs ->
|
||||
let cn = (List.find (fun od -> od.obj = o) objs).cls in
|
||||
let at = (jname_of_name (shortname cn)) ^ "Answer" in
|
||||
let ao = o ^ "_ans" in
|
||||
fprintf ff "%s %s = new %s();@ " at ao at;
|
||||
fprintf ff "%s = %s.step(" ao o;
|
||||
fprintf ff "@[";
|
||||
print_exps ff es 0 avs ts single;
|
||||
fprintf ff "@]";
|
||||
fprintf ff ");@ ";
|
||||
print_proj ff xs ao avs single)
|
||||
| Comp (a1, a2) ->
|
||||
print_act ff a1 objs avs ts single;
|
||||
(match a2 with
|
||||
| Nothing -> ()
|
||||
| _ -> fprintf ff "@ ");
|
||||
print_act ff a2 objs avs ts single
|
||||
| Case (e, grds) ->
|
||||
let grds =
|
||||
List.map
|
||||
(fun (ln,act) -> (shortname ln),act) grds in
|
||||
if bool_case grds
|
||||
then print_if ff e grds objs avs ts single
|
||||
else (fprintf ff "@[<v>@[<v 2>switch (%a) {@ "
|
||||
(fun ff e -> print_exp ff e 0 avs ts single) e;
|
||||
print_grds ff grds objs avs ts single;
|
||||
fprintf ff "@]@ }@]");
|
||||
| Reinit o -> fprintf ff "%s.reset();" o
|
||||
| Nothing -> ()
|
||||
|
||||
and print_grds ff grds objs avs ts single =
|
||||
match grds with
|
||||
| [] -> ()
|
||||
| [(tg, act)] ->
|
||||
(* retrieve class name *)
|
||||
let cn = (fst
|
||||
(List.find
|
||||
(fun (tn, tgs) ->
|
||||
List.exists (fun tg' -> tg = tg') tgs)
|
||||
ts)) in
|
||||
fprintf ff "@[<v 2>case %a.%a:@ "
|
||||
print_name cn
|
||||
print_name tg;
|
||||
print_act ff act objs avs ts single;
|
||||
fprintf ff "@ break;@]";
|
||||
| (tg, act) :: grds' ->
|
||||
(* retrieve class name *)
|
||||
let cn = (fst
|
||||
(List.find
|
||||
(fun (tn, tgs) ->
|
||||
List.exists (fun tg' -> tg = tg') tgs)
|
||||
ts)) in
|
||||
fprintf ff "@[<v 2>case %a.%a:@ "
|
||||
print_name cn
|
||||
print_name tg;
|
||||
print_act ff act objs avs ts single;
|
||||
fprintf ff "@ break;@ @]@ ";
|
||||
print_grds ff grds' objs avs ts single
|
||||
|
||||
and print_if ff e grds objs avs ts single =
|
||||
match grds with
|
||||
| [("true", a)] ->
|
||||
fprintf ff "@[<v>@[<v 2>if (%a) {@ "
|
||||
(fun ff e -> print_exp ff e 0 avs ts single) e;
|
||||
print_act ff a objs avs ts single;
|
||||
fprintf ff "@]@ }@]"
|
||||
| [("false", a)] ->
|
||||
fprintf ff "@[<v>@[<v 2>if (!%a) {@ "
|
||||
(fun ff e -> print_exp ff e 6 avs ts single) e;
|
||||
print_act ff a objs avs ts single;
|
||||
fprintf ff "@]@ }@]"
|
||||
| [("true", a1); ("false", a2)] ->
|
||||
fprintf ff "@[<v>@[<v 2>if (%a) {@ "
|
||||
(fun ff e -> print_exp ff e 0 avs ts single) e;
|
||||
print_act ff a1 objs avs ts single;
|
||||
fprintf ff "@]@ @[<v 2>} else {@ ";
|
||||
print_act ff a2 objs avs ts single;
|
||||
fprintf ff "@]@ }@]"
|
||||
| [("false", a2); ("true", a1)] ->
|
||||
fprintf ff "@[<v>@[<v 2>if (%a) {@ "
|
||||
(fun ff e -> print_exp ff e 0 avs ts single) e;
|
||||
print_act ff a1 objs avs ts single;
|
||||
fprintf ff "@]@ @[<v 2>} else {@ ";
|
||||
print_act ff a2 objs avs ts single;
|
||||
fprintf ff "@]@ }@]"
|
||||
| _ -> assert false
|
||||
|
||||
and print_asgn ff x e avs ts single =
|
||||
fprintf ff "@[";
|
||||
print_lhs ff x avs single;
|
||||
fprintf ff " = ";
|
||||
print_exp ff e 0 avs ts single;
|
||||
fprintf ff "@]"
|
||||
|
||||
let print_vd ff vd =
|
||||
let jty,jdv = java_type_default_value vd.v_type in
|
||||
fprintf ff "@[<v>";
|
||||
print_name ff jty;
|
||||
fprintf ff " %s = %s;"
|
||||
(jname_of_name (name vd.v_name))
|
||||
jdv;
|
||||
fprintf ff "@]"
|
||||
|
||||
let print_obj ff od =
|
||||
fprintf ff "@[<v>";
|
||||
fprintf ff "%a %a = new %a();"
|
||||
print_shortname od.cls
|
||||
print_name od.obj
|
||||
print_shortname od.cls;
|
||||
fprintf ff "@]"
|
||||
|
||||
let rec print_objs ff ods =
|
||||
match ods with
|
||||
| [] -> ()
|
||||
| od :: ods' ->
|
||||
print_obj ff od;
|
||||
fprintf ff "@ ";
|
||||
print_objs ff ods'
|
||||
|
||||
let print_comps ff fds=
|
||||
let rec walk n = function
|
||||
| [] -> ()
|
||||
| fd :: fds' ->
|
||||
fprintf ff "@ ";
|
||||
fprintf ff "public ";
|
||||
print_type ff fd.v_type;
|
||||
fprintf ff " c_%s;" (string_of_int n);
|
||||
walk (n + 1) fds'
|
||||
in walk 1 fds
|
||||
|
||||
let print_ans_struct ff name fields =
|
||||
fprintf ff "@[<v>@[<v 2>public class %s {" name;
|
||||
print_comps ff fields;
|
||||
fprintf ff "@]@ }@]@ "
|
||||
|
||||
let print_vd' ff vd =
|
||||
fprintf ff "@[";
|
||||
print_type ff vd.v_type;
|
||||
fprintf ff "@ %s" (jname_of_name (name vd.v_name));
|
||||
fprintf ff "@]"
|
||||
|
||||
let rec print_in ff = function
|
||||
| [] -> ()
|
||||
| [vd] -> print_vd' ff vd
|
||||
| vd :: vds' ->
|
||||
print_vd' ff vd;
|
||||
fprintf ff ",@ ";
|
||||
print_in ff vds'
|
||||
|
||||
let rec print_mem ff = function
|
||||
| [] -> ()
|
||||
| vd :: m' ->
|
||||
print_vd ff vd;
|
||||
fprintf ff "@ ";
|
||||
print_mem ff m'
|
||||
|
||||
let print_loc ff vds = print_mem ff vds
|
||||
|
||||
let print_step ff n s objs ts single =
|
||||
let name = jname_of_name n in
|
||||
fprintf ff "@[<v>@ @[<v 2>public ";
|
||||
if single then print_type ff (List.hd s.out).v_type
|
||||
else fprintf ff "%s" (n ^ "Answer");
|
||||
fprintf ff " step(@[";
|
||||
print_in ff s.inp;
|
||||
fprintf ff "@]) {@ ";
|
||||
let loc = if single then (List.hd s.out) :: s.local else s.local in
|
||||
if loc = [] then () else (print_loc ff loc; fprintf ff "@ ");
|
||||
if single then fprintf ff "@ "
|
||||
else fprintf ff "%sAnswer step_ans = new %sAnswer();@ @ " n n;
|
||||
print_act ff s.bd objs
|
||||
(List.map (fun vd -> vd.v_name) s.out) ts single;
|
||||
fprintf ff "@ @ return ";
|
||||
if single then fprintf ff "%s" (jname_of_name (Ident.name (List.hd s.out).v_name))
|
||||
else fprintf ff "step_ans";
|
||||
fprintf ff ";@]@ }@ @]"
|
||||
|
||||
let print_reset ff r ts =
|
||||
fprintf ff "@[<v>@ @[<v 2>public void reset() {@ ";
|
||||
print_act ff r [] [] ts false;
|
||||
fprintf ff "@]@ }@ @]"
|
||||
|
||||
let print_class ff headers ts single opened_mod cl =
|
||||
let clid = jname_of_name cl.cl_id in
|
||||
List.iter (fprintf ff "%s") headers;
|
||||
(* fprintf ff "@[<v>package %s;@\n@\n" headers; *)
|
||||
(* import opened modules *)
|
||||
List.iter
|
||||
(fun m ->
|
||||
fprintf ff "import %s.*;@\n" (String.uncapitalize m))
|
||||
opened_mod;
|
||||
|
||||
fprintf ff "@\n@[<v 2>public class %s {@ " clid;
|
||||
if cl.mem = [] then ()
|
||||
else fprintf ff "@[<v>@ "; print_mem ff cl.mem; fprintf ff "@]";
|
||||
if cl.objs = [] then ()
|
||||
else fprintf ff "@[<v>@ "; print_objs ff cl.objs; fprintf ff "@]";
|
||||
print_reset ff cl.reset ts;
|
||||
print_step ff clid cl.step cl.objs ts single;
|
||||
fprintf ff "@]@ }@]"
|
||||
|
||||
let print_class_and_answer_to_file java_dir headers ts opened_mod cl =
|
||||
let clid = jname_of_name cl.cl_id in
|
||||
let print_class_to_file single =
|
||||
let out_ch = open_out (java_dir ^ "/" ^ clid ^ ".java") in
|
||||
let ff = formatter_of_out_channel out_ch in
|
||||
Misc.print_header_info ff "/*" "*/";
|
||||
print_class ff headers ts single opened_mod cl;
|
||||
fprintf ff "@.";
|
||||
close_out out_ch
|
||||
in
|
||||
match cl.step.out with
|
||||
| [_] -> print_class_to_file true
|
||||
| _ ->
|
||||
let out_ch = open_out (java_dir ^ "/" ^ clid ^ "Answer.java") in
|
||||
let ff = formatter_of_out_channel out_ch in
|
||||
Misc.print_header_info ff "/*" "*/";
|
||||
List.iter (fprintf ff "%s") headers;
|
||||
(* fprintf ff "@[<v>package %s;@\n@\n" headers; *)
|
||||
List.iter
|
||||
(fun m ->
|
||||
fprintf ff "import %s.*;@\n" (String.uncapitalize m))
|
||||
opened_mod;
|
||||
print_ans_struct ff (clid ^ "Answer") cl.step.out;
|
||||
fprintf ff "@.";
|
||||
close_out out_ch;
|
||||
print_class_to_file false
|
||||
|
||||
let print_classes java_dir headers ts opened_mod cls =
|
||||
List.iter
|
||||
(print_class_and_answer_to_file java_dir headers ts opened_mod)
|
||||
cls
|
||||
|
||||
(******************************)
|
||||
let print java_dir p =
|
||||
let headers =
|
||||
List.map snd
|
||||
(List.filter
|
||||
(fun (tag,_) -> tag = "java")
|
||||
p.o_pragmas) in
|
||||
print_types java_dir headers p.o_types;
|
||||
o_types := p.o_types;
|
||||
print_classes
|
||||
java_dir headers
|
||||
(List.flatten
|
||||
(List.map
|
||||
(function
|
||||
| { t_desc = Type_abs } -> []
|
||||
| { t_name = tn; t_desc = Type_enum tgs } -> [tn, tgs]
|
||||
| { t_name = tn; t_desc = Type_struct fields } ->
|
||||
[tn, (List.map fst fields)])
|
||||
p.o_types))
|
||||
p.o_opened
|
||||
p.o_defs
|
||||
|
||||
(******************************)
|
414
minils/sequential/mls2obc.ml
Normal file
414
minils/sequential/mls2obc.ml
Normal file
|
@ -0,0 +1,414 @@
|
|||
(**************************************************************************)
|
||||
(* *)
|
||||
(* Heptagon *)
|
||||
(* *)
|
||||
(* Author : Marc Pouzet *)
|
||||
(* Organization : Demons, LRI, University of Paris-Sud, Orsay *)
|
||||
(* *)
|
||||
(**************************************************************************)
|
||||
|
||||
(* translation from the source language to the target *)
|
||||
|
||||
(* $Id$ *)
|
||||
|
||||
open Misc
|
||||
open Names
|
||||
open Ident
|
||||
open Global
|
||||
open Obc
|
||||
open Control
|
||||
open Normalize
|
||||
open Memalloc
|
||||
open Interference
|
||||
open Static
|
||||
|
||||
(* merge x (C1 -> (merge y (C2 -> e2)) when C1(x)) *)
|
||||
|
||||
(** Targeted inputs should be marked as passed by reference. *)
|
||||
let update_targeted_inputs targeting inv =
|
||||
let rec aux i = function
|
||||
| [] -> []
|
||||
| vd::l ->
|
||||
let vd =
|
||||
if List.mem_assoc i targeting then (*input is targeted*)
|
||||
{ vd with v_pass_by_ref = true; }
|
||||
else (*not targeted, leave it*)
|
||||
vd
|
||||
in
|
||||
vd::(aux (i+1) l)
|
||||
in
|
||||
aux 0 inv
|
||||
|
||||
let rec encode_name_params n = function
|
||||
| [] -> n
|
||||
| p::params -> encode_name_params (n^"__"^(string_of_int p)) params
|
||||
|
||||
let encode_longname_params n params =
|
||||
match n with
|
||||
| Name n -> Name (encode_name_params n params)
|
||||
| Modname { qual = qual; id = id } ->
|
||||
Modname { qual = qual; id = encode_name_params id params }
|
||||
|
||||
let is_op = function
|
||||
| Modname { qual = "Pervasives"; id = _ } -> true
|
||||
| _ -> false
|
||||
|
||||
let rec translate_type const_env = function
|
||||
| Minils.Tbase(btyp) -> translate_base_type const_env btyp
|
||||
| Minils.Tprod _ -> assert false
|
||||
|
||||
and translate_base_type const_env = function
|
||||
| Minils.Tint -> Tint
|
||||
| Minils.Tfloat -> Tfloat
|
||||
| Minils.Tid(id) -> Tid(id)
|
||||
| Minils.Tarray(ty, n) -> Tarray (translate_base_type const_env ty,
|
||||
int_of_size_exp const_env n)
|
||||
|
||||
let rec translate_const const_env = function
|
||||
| Minils.Cint(v) -> Cint(v)
|
||||
| Minils.Cfloat(v) -> Cfloat(v)
|
||||
| Minils.Cconstr(c) -> Cconstr(c)
|
||||
| Minils.Cconst_array(n,c) ->
|
||||
Cconst_array(int_of_size_exp const_env n, translate_const const_env c)
|
||||
|
||||
let rec translate_pat map = function
|
||||
| Minils.Evarpat(x) -> [var_from_name map x]
|
||||
| Minils.Etuplepat(pat_list) ->
|
||||
List.fold_right (fun pat acc -> (translate_pat map pat) @ acc) pat_list []
|
||||
|
||||
(* [translate e = c] *)
|
||||
let rec translate const_env map (m, si, j, s) ({ Minils.e_desc = desc } as e) =
|
||||
match desc with
|
||||
| Minils.Econst(v) -> Const(translate_const const_env v)
|
||||
| Minils.Evar(n) -> Lhs (var_from_name map n)
|
||||
| Minils.Econstvar(n) ->
|
||||
Const (Cint(int_of_size_exp const_env (SVar n)))
|
||||
| Minils.Eop(n, _, e_list) ->
|
||||
Op(n, List.map (translate const_env map (m, si, j, s)) e_list)
|
||||
| Minils.Ewhen(e, _, _) -> translate const_env map (m, si, j, s) (e)
|
||||
| Minils.Efield(e, field) ->
|
||||
let e = translate const_env map (m, si, j, s) e in
|
||||
Lhs (Field(lhs_of_exp e, field))
|
||||
| Minils.Estruct(f_e_list) ->
|
||||
let type_name =
|
||||
begin match e.Minils.e_ty with
|
||||
Minils.Tbase(Minils.Tid(name)) -> name
|
||||
| _ -> assert false
|
||||
end in
|
||||
let f_e_list = List.map
|
||||
(fun (f, e) -> (f,
|
||||
translate const_env map (m, si, j, s) e)) f_e_list in
|
||||
Struct(type_name,f_e_list)
|
||||
(*Array operators*)
|
||||
| Minils.Earray e_list ->
|
||||
Array (List.map (translate const_env map (m, si, j, s)) e_list)
|
||||
| Minils.Eselect (idx,e) ->
|
||||
let e = translate const_env map (m, si, j, s) e in
|
||||
Lhs ( Array (lhs_of_exp e,
|
||||
List.map (int_of_size_exp const_env) idx) )
|
||||
| _ -> Minils.Printer.print_exp stdout e; flush stdout; assert false
|
||||
|
||||
(* [translate pat act = si, j, d, s] *)
|
||||
and translate_act const_env map ((m,_,_,_) as context) pat ({ Minils.e_desc = desc } as act) =
|
||||
match pat, desc with
|
||||
| Minils.Etuplepat(p_list), Minils.Etuple(act_list) ->
|
||||
comp (List.map2 (translate_act const_env map context) p_list act_list)
|
||||
| pat, Minils.Ewhen(e, _, _) ->
|
||||
translate_act const_env map context pat e
|
||||
| pat, Minils.Emerge(x, c_act_list) ->
|
||||
let lhs = var_from_name map x in
|
||||
(Case(Lhs lhs, translate_c_act_list const_env map context pat c_act_list))
|
||||
| Minils.Evarpat(n), _ ->
|
||||
Assgn(var_from_name map n, translate const_env map context act)
|
||||
| _ ->
|
||||
Minils.Printer.print_exp stdout act;
|
||||
assert false
|
||||
|
||||
and translate_c_act_list const_env map context pat c_act_list =
|
||||
List.map
|
||||
(fun (c, act) -> (c, translate_act const_env map context pat act))
|
||||
c_act_list
|
||||
|
||||
and comp s_list =
|
||||
List.fold_right (fun s rest -> Comp(s, rest)) s_list Nothing
|
||||
|
||||
let rec translate_eq const_env map { Minils.p_lhs = pat; Minils.p_rhs = e } (m, si, j, s) =
|
||||
let { Minils.e_desc = desc; Minils.e_ty = ty; Minils.e_ck = ck } = e in
|
||||
match pat, desc with
|
||||
| Minils.Evarpat(n), Minils.Efby(opt_c, e) ->
|
||||
let x = var_from_name map n in
|
||||
let si =
|
||||
match opt_c with
|
||||
| None -> si
|
||||
| Some(c) ->
|
||||
if var_name x = n then
|
||||
(Assgn(x, Const(translate_const const_env c))) :: si
|
||||
else
|
||||
si (*this mem is shared, no need to add a reset intruction*)
|
||||
in
|
||||
let ty = translate_type const_env ty in
|
||||
let m = if var_name x = n then (n, ty) :: m else m in
|
||||
m, si, j,
|
||||
(control map ck (Assgn(var_from_name map n, translate const_env map (m, si, j, s) e))) :: s
|
||||
| pat, Minils.Eapp({ Minils.a_op = n }, params, e_list) ->
|
||||
let sig_info = (Modules.find_value n).info in
|
||||
let name_list = translate_pat map pat in
|
||||
let name_list = remove_targeted_outputs sig_info.targeting name_list in
|
||||
let c_list = List.map (translate const_env map (m, si, j, s)) e_list in
|
||||
let o = gen_symbol () in
|
||||
let si = (Reinit(o)) :: si in
|
||||
let params = List.map (int_of_size_exp const_env) params in
|
||||
let j = (o, encode_longname_params n params, 1) :: j in
|
||||
let s =
|
||||
(control map ck (Step_ap(name_list, o, c_list))) :: s in
|
||||
(m, si, j, s)
|
||||
| pat, Minils.Eevery({ Minils.a_op = n }, params, e_list, r ) ->
|
||||
let name_list = translate_pat map pat in
|
||||
let c_list = List.map (translate const_env map (m, si, j, s)) e_list in
|
||||
let o = gen_symbol () in
|
||||
let si = (Reinit(o)) :: si in
|
||||
let params = List.map (int_of_size_exp const_env) params in
|
||||
let j = (o, encode_longname_params n params, 1) :: j in
|
||||
let s =
|
||||
(control map (Minils.Con(ck, Name("true"), r)) (Reinit(o))) ::
|
||||
(control map ck (Step_ap(name_list, o, c_list))) :: s in
|
||||
(m, si, j, s)
|
||||
| Minils.Etuplepat(p_list), Minils.Etuple(act_list) ->
|
||||
List.fold_right2
|
||||
(fun pat e -> translate_eq const_env map { Minils.p_lhs = pat; Minils.p_rhs = e } )
|
||||
p_list act_list (m, si, j, s)
|
||||
| Minils.Evarpat(x), Minils.Eselect_slice(idx1, idx2, e) ->
|
||||
let idx1 = int_of_size_exp const_env idx1 in
|
||||
let idx2 = int_of_size_exp const_env idx2 in
|
||||
let idx =
|
||||
let cpt = name (Ident.fresh "i") in
|
||||
let e = translate const_env map (m, si, j, s) e in
|
||||
let action = For( cpt, 0, idx2 - idx1 + 1,
|
||||
Assgn (Array (var_from_name map x, Var cpt),
|
||||
Lhs (Array (lhs_of_exp e, idx))) )
|
||||
|
||||
let action = Array_select_slice (var_from_name map x,
|
||||
translate const_env map (m, si, j, s) e,
|
||||
int_of_size_exp const_env idx1,
|
||||
int_of_size_exp const_env idx2) in
|
||||
m, si, j, ((control map ck action)::s)
|
||||
| Minils.Evarpat(x), Minils.Eselect_dyn (idx, bounds, e1, e2) ->
|
||||
let action = Array_select_dyn (var_from_name map x,
|
||||
translate const_env map (m, si, j, s) e1,
|
||||
List.map (translate const_env map (m, si, j, s)) idx,
|
||||
List.map (int_of_size_exp const_env) bounds,
|
||||
translate const_env map (m, si, j, s) e2 ) in
|
||||
m, si, j, ((control map ck action)::s)
|
||||
| Minils.Evarpat(x), Minils.Eupdate (idx, e1, e2) ->
|
||||
let x = var_from_name map x in
|
||||
let copy = Assgn (x, translate const_env map (m, si, j, s) e1) in
|
||||
let action = Assgn (Array (x, List.map (int_of_size_exp const_env) idx),
|
||||
translate const_env map (m, si, j, s) e2) in
|
||||
m, si, j, ((control map ck copy)::(control map ck action)::s)
|
||||
| Minils.Evarpat(x), Minils.Erepeat (n, e) ->
|
||||
let cpt = name (Ident.fresh "i") in
|
||||
let action = For (cpt, 0, int_of_size_exp const_env n,
|
||||
Assgn(Lhs (var_from_name map x, Var cpt),
|
||||
translate const_env map (m, si, j, s) e) in
|
||||
m, si, j, ((control map ck action)::s)
|
||||
| Minils.Evarpat(x), Minils.Econcat(e1, e2) ->
|
||||
let action = Array_concat (var_from_name map x, translate const_env map (m, si, j, s) e1,
|
||||
translate const_env map (m, si, j, s) e2) in
|
||||
m, si, j, ((control map ck action)::s)
|
||||
| pat, Minils.Eiterator(it, f, params, n, e_list, reset) ->
|
||||
let sig_info = (Modules.find_value f).info in
|
||||
let name_list = translate_pat map pat in
|
||||
let name_list = remove_targeted_outputs sig_info.targeting name_list in
|
||||
let c_list = List.map (translate const_env map (m, si, j, s)) e_list in
|
||||
let o = gen_symbol () in
|
||||
let n = int_of_size_exp const_env n in
|
||||
let si = if is_op f then si else (Reinit(o)) :: si in
|
||||
let params = List.map (int_of_size_exp const_env) params in
|
||||
let j = (o, encode_longname_params f params, n) :: j in
|
||||
let action = Array_iterate (name_list, it, o, n, c_list) in
|
||||
let s =
|
||||
(match reset with
|
||||
| None -> (control map ck action)::s
|
||||
| Some r ->
|
||||
(control map (Minils.Con(ck, Name("true"), r)) (Reinit(o))) ::
|
||||
(control map ck action)::s
|
||||
) in
|
||||
m, si, j, s
|
||||
| Minils.Evarpat(x), Minils.Efield_update (f, e1, e2) ->
|
||||
let action = Field_update (var_from_name map x, translate const_env map (m,si,j,s) e1,
|
||||
f, translate const_env map (m,si,j,s) e2) in
|
||||
m, si, j, ((control map ck action)::s)
|
||||
| Minils.Etuplepat [], Minils.Ereset_mem(y, v, res) ->
|
||||
let h = Initial.ptrue, Assgn(var_from_name map y, Const (translate_const const_env v)) in
|
||||
let action = Case (Lhs (var_from_name map res), [h]) in
|
||||
(m, si, j, (control map ck action) :: s)
|
||||
| pat, _ ->
|
||||
let action = translate_act const_env map (m, si, j, s) pat e in
|
||||
(m, si, j, (control map ck action) :: s)
|
||||
|
||||
let translate_eq_list const_env map act_list =
|
||||
List.fold_right (translate_eq const_env map) act_list ([], [], [], [])
|
||||
|
||||
let remove m d_list =
|
||||
List.filter (fun { Minils.v_name = n } -> not (List.mem_assoc n m)) d_list
|
||||
|
||||
let var_decl l =
|
||||
List.map (fun (x, t) -> { v_name = x; v_type = t; v_pass_by_ref = false }) l
|
||||
|
||||
let obj_decl l = List.map (fun (x, t, i) -> { obj = x; cls = t; n = i }) l
|
||||
|
||||
let translate_var_dec const_env map l =
|
||||
let one_var { Minils.v_name = x; Minils.v_type = t } =
|
||||
{ v_name = x; v_type = translate_base_type const_env t; v_pass_by_ref = false }
|
||||
in
|
||||
(* remove unused vars *)
|
||||
let l = List.filter (fun { Minils.v_name = x } ->
|
||||
var_name (var_from_name map x) = x) l in
|
||||
List.map one_var l
|
||||
|
||||
let translate_contract const_env map = function
|
||||
| None ->
|
||||
[], [], [], [], [], []
|
||||
| Some({ Minils.c_eq = eq_list;
|
||||
Minils.c_local = d_list;
|
||||
Minils.c_controllables = c_list;
|
||||
Minils.c_assume = e_a;
|
||||
Minils.c_enforce = e_c }) ->
|
||||
let m, si, j, s_list = translate_eq_list const_env map eq_list in
|
||||
let d_list = remove m d_list in
|
||||
let d_list = translate_var_dec const_env map d_list in
|
||||
let c_list = translate_var_dec const_env map c_list in
|
||||
m, si, j, s_list, d_list, c_list
|
||||
|
||||
let rec choose_record_field m = function
|
||||
| [IVar x] -> Var x
|
||||
| [IField(x,f)] -> Field(var_from_name m x,f)
|
||||
| (IVar x)::l -> choose_record_field m l
|
||||
| (IField(x,f))::l ->
|
||||
if var_name (var_from_name m x) <> x then
|
||||
choose_record_field m l
|
||||
else
|
||||
Field(var_from_name m x,f)
|
||||
|
||||
(** Chooses from a list of vars (with the same color in the interference graph)
|
||||
the one that will be used to store every other. It can be either an input,
|
||||
an output or any var if there is no input or output in the list. *)
|
||||
let choose_representative m inputs outputs mems vars =
|
||||
let ivar_mem x vars =
|
||||
match x with
|
||||
| IVar x -> List.mem x vars
|
||||
| _ -> false
|
||||
in
|
||||
|
||||
let inputs = List.filter (fun var -> Minils.ivar_vd_mem var inputs) vars in
|
||||
let outputs = List.filter (fun var -> Minils.ivar_vd_mem var outputs) vars in
|
||||
let mems = List.filter (fun var -> ivar_mem var mems) vars in
|
||||
match inputs, outputs, mems with
|
||||
| [], [], [] -> choose_record_field m vars
|
||||
| [], [], (IVar m)::_ -> Mem m
|
||||
| [IVar vin], [], [] -> Var vin
|
||||
| [], [IVar vout], [] -> Var vout
|
||||
| [IVar vin], [IVar vout], [] -> Var vin
|
||||
| _, _, _ ->
|
||||
Format.printf "Something is wrong with the coloring : ";
|
||||
List.iter (fun vd -> Format.printf "%s," (ivar_to_string vd)) vars;
|
||||
Format.printf "\n Inputs : ";
|
||||
List.iter (fun vd -> Format.printf "%s," (ivar_to_string vd)) inputs;
|
||||
Format.printf "\n Outputs : ";
|
||||
List.iter (fun vd -> Format.printf "%s," (ivar_to_string vd)) outputs;
|
||||
Format.printf "\n Mem : ";
|
||||
List.iter (fun vd -> Format.printf "%s," (ivar_to_string vd)) mems;
|
||||
Format.printf "\n";
|
||||
assert false (*something went wrong in the coloring*)
|
||||
|
||||
(** Returns a map, mapping variables names to the variables
|
||||
where they will be stored, as a result of memory allocation. *)
|
||||
let subst_map_from_coloring subst_lists inputs outputs locals mems =
|
||||
let rec add_to_map map value = function
|
||||
| [] -> map
|
||||
| var::l ->
|
||||
let m = add_to_map map value l in
|
||||
(match var with
|
||||
| IVar x -> Env.add x value m
|
||||
| _ -> m
|
||||
)
|
||||
in
|
||||
let map_from_subst_lists m l =
|
||||
List.fold_left
|
||||
(fun m (_,l) -> add_to_map m (choose_representative m inputs outputs mems l) l)
|
||||
m l
|
||||
in
|
||||
if !no_mem_alloc then (
|
||||
(* Create a map that simply maps each var to itself *)
|
||||
let m = List.fold_left
|
||||
(fun m { Minils.v_name = x } -> Env.add x (Var x) m)
|
||||
Env.empty (inputs @ outputs @ locals) in
|
||||
List.fold_left (fun m x -> Env.add x (Mem x) m) m mems
|
||||
) else (
|
||||
let record_lists, other_lists = List.partition
|
||||
(fun (ty,_) -> Minils.is_record_type ty) subst_lists in
|
||||
let m = map_from_subst_lists Env.empty record_lists in
|
||||
map_from_subst_lists m other_lists
|
||||
)
|
||||
|
||||
let translate_node_aux const_env
|
||||
{ Minils.n_name = f; Minils.n_input = i_list; Minils.n_output = o_list;
|
||||
Minils.n_local = d_list; Minils.n_equs = eq_list;
|
||||
Minils.n_contract = contract ; Minils.n_targeting = targeting;
|
||||
Minils.n_mem_alloc = mem_alloc; Minils.n_params = params } =
|
||||
|
||||
let mem_vars = List.flatten (List.map InterfRead.memory_vars eq_list) in
|
||||
let subst_map = subst_map_from_coloring mem_alloc i_list o_list d_list mem_vars in
|
||||
let m, si, j, s_list = translate_eq_list const_env subst_map eq_list in
|
||||
let m', si', j', s_list', d_list', c_list = translate_contract const_env subst_map contract in
|
||||
let d_list = remove m d_list in
|
||||
let i_list = translate_var_dec const_env subst_map i_list in
|
||||
let i_list = update_targeted_inputs targeting i_list in
|
||||
let o_list = translate_var_dec const_env subst_map o_list in
|
||||
let d_list = translate_var_dec const_env subst_map d_list in
|
||||
let s = joinlist (s_list@s_list') in
|
||||
let m = var_decl (m@m') in
|
||||
let j = obj_decl (j@j') in
|
||||
let si = joinlist (si@si') in
|
||||
let step = { inp = i_list; out = o_list;
|
||||
local = (d_list@d_list'@c_list);
|
||||
controllables = c_list;
|
||||
bd = s } in
|
||||
{ cl_id = f; mem = m; objs = j; reset = si; step = step }
|
||||
|
||||
let build_params_list env params_names params_values =
|
||||
List.fold_left2 (fun env n v -> NamesEnv.add n (SConst v) env) env params_names params_values
|
||||
|
||||
let translate_node const_env n =
|
||||
let translate_one p =
|
||||
let const_env = build_params_list const_env n.Minils.n_params p in
|
||||
let c = translate_node_aux const_env n in
|
||||
{ c with cl_id = encode_name_params c.cl_id p; }
|
||||
in
|
||||
match n.Minils.n_params_instances with
|
||||
| [] -> [translate_node_aux const_env n]
|
||||
| params_lists -> List.map translate_one params_lists
|
||||
|
||||
let translate_ty_def const_env { Minils.t_name = name; Minils.t_desc = tdesc } =
|
||||
let tdesc = match tdesc with
|
||||
| Minils.Type_abs -> Type_abs
|
||||
| Minils.Type_enum(tag_name_list) -> Type_enum(tag_name_list)
|
||||
| Minils.Type_struct(field_ty_list) ->
|
||||
Type_struct
|
||||
(List.map (fun (f, ty) -> (f, translate_base_type const_env ty)) field_ty_list)
|
||||
in
|
||||
{ t_name = name; t_desc = tdesc }
|
||||
|
||||
let build_const_env cd_list =
|
||||
List.fold_left (fun env cd -> NamesEnv.add cd.Minils.c_name cd.Minils.c_value env) NamesEnv.empty cd_list
|
||||
|
||||
let program { Minils.p_pragmas = p_pragmas_list;
|
||||
Minils.p_opened = p_module_list;
|
||||
Minils.p_types = p_type_list;
|
||||
Minils.p_nodes = p_node_list;
|
||||
Minils.p_consts = p_const_list; } =
|
||||
let const_env = build_const_env p_const_list in
|
||||
{ o_pragmas = p_pragmas_list;
|
||||
o_opened = p_module_list;
|
||||
o_types = List.map (translate_ty_def const_env) p_type_list;
|
||||
o_defs = List.flatten (List.map (translate_node const_env) p_node_list) }
|
433
minils/sequential/obc.ml
Normal file
433
minils/sequential/obc.ml
Normal file
|
@ -0,0 +1,433 @@
|
|||
(**************************************************************************)
|
||||
(* *)
|
||||
(* Heptagon *)
|
||||
(* *)
|
||||
(* Author : Marc Pouzet *)
|
||||
(* Organization : Demons, LRI, University of Paris-Sud, Orsay *)
|
||||
(* *)
|
||||
(**************************************************************************)
|
||||
(* Object code internal representation *)
|
||||
|
||||
(* $Id$ *)
|
||||
|
||||
open Misc
|
||||
open Names
|
||||
open Ident
|
||||
|
||||
type var_name = ident
|
||||
type type_name = longname
|
||||
type fun_name = longname
|
||||
type class_name = name
|
||||
type instance_name = longname
|
||||
type obj_name = name
|
||||
type op_name = longname
|
||||
type field_name = longname
|
||||
|
||||
type ty =
|
||||
| Tint
|
||||
| Tfloat
|
||||
| Tid of type_name
|
||||
| Tarray of ty * int
|
||||
|
||||
type type_dec =
|
||||
{ t_name : name;
|
||||
t_desc : tdesc }
|
||||
|
||||
and tdesc =
|
||||
| Type_abs
|
||||
| Type_enum of name list
|
||||
| Type_struct of (name * ty) list
|
||||
|
||||
type const =
|
||||
| Cint of int
|
||||
| Cfloat of float
|
||||
| Cconstr of longname
|
||||
| Cconst_array of int * const
|
||||
|
||||
type lhs =
|
||||
| Var of var_name
|
||||
| Mem of var_name
|
||||
| Field of lhs * field_name
|
||||
| Array of lhs * exp
|
||||
|
||||
type exp =
|
||||
| Lhs of lhs
|
||||
| Const of const
|
||||
| Op of op_name * exp list
|
||||
| Struct of type_name * (field_name * exp) list
|
||||
| Array of exp list
|
||||
|
||||
type act =
|
||||
| Assgn of lhs * exp
|
||||
| Step_ap of lhs list * obj_name * exp list
|
||||
| Comp of act * act
|
||||
| Case of exp * (longname * act) list
|
||||
| For of var_name * int * int * act
|
||||
| Reinit of obj_name
|
||||
| Nothing
|
||||
| Array_select_slice of lhs * exp * int * int
|
||||
| Array_select_dyn of lhs * exp * exp list * int list * exp (* res, var, indices, bounds, def value*)
|
||||
| Array_iterate of lhs list * iterator_name * obj_name * int * exp list
|
||||
| Array_concat of lhs * exp * exp
|
||||
| Field_update of lhs * exp * longname * exp (* var, record, field, value*)
|
||||
|
||||
type var_dec =
|
||||
{ v_name : var_name;
|
||||
v_type : ty;
|
||||
v_pass_by_ref : bool; }
|
||||
|
||||
type obj_dec =
|
||||
{ obj : obj_name;
|
||||
cls : instance_name;
|
||||
n : int; }
|
||||
|
||||
type step_fun =
|
||||
{ inp : var_dec list;
|
||||
out : var_dec list;
|
||||
local : var_dec list;
|
||||
controllables : var_dec list; (* GD : ugly patch to delay controllable
|
||||
variables definition to target code
|
||||
generation *)
|
||||
bd : act }
|
||||
|
||||
type reset_fun = act
|
||||
|
||||
type class_def =
|
||||
{ cl_id : class_name;
|
||||
mem : var_dec list;
|
||||
objs : obj_dec list;
|
||||
reset : reset_fun;
|
||||
step : step_fun; }
|
||||
|
||||
type program =
|
||||
{ o_pragmas: (name * string) list;
|
||||
o_opened : name list;
|
||||
o_types : type_dec list;
|
||||
o_defs : class_def list }
|
||||
|
||||
(** [is_scalar_type vd] returns whether the type corresponding
|
||||
to this variable declaration is scalar (ie a type that can
|
||||
be returned by a C function). *)
|
||||
let is_scalar_type vd =
|
||||
let pint = Modname({ qual = "Pervasives"; id = "int" }) in
|
||||
let pfloat = Modname({ qual = "Pervasives"; id = "float" }) in
|
||||
let pbool = Modname({ qual = "Pervasives"; id = "bool" }) in
|
||||
match vd.v_type with
|
||||
| Tint | Tfloat -> true
|
||||
| Tid name_int when name_int = pint -> true
|
||||
| Tid name_float when name_float = pfloat -> true
|
||||
| Tid name_bool when name_bool = pbool -> true
|
||||
| _ -> false
|
||||
|
||||
let actual_type ty =
|
||||
match ty with
|
||||
| Tid(Name("float"))
|
||||
| Tid(Modname { qual = "Pervasives"; id = "float" }) -> Tfloat
|
||||
| Tid(Name("int"))
|
||||
| Tid(Modname { qual = "Pervasives"; id = "int" }) -> Tint
|
||||
| _ -> ty
|
||||
|
||||
let rec var_name x =
|
||||
match x with
|
||||
| Var x -> x
|
||||
| Mem x -> x
|
||||
| Field(x,_) -> var_name x
|
||||
|
||||
(** Returns whether an object of name n belongs to
|
||||
a list of var_dec. *)
|
||||
let rec vd_mem n = function
|
||||
| [] -> false
|
||||
| vd::l -> vd.v_name = n or (vd_mem n l)
|
||||
|
||||
(** Returns the var_dec object corresponding to the name n
|
||||
in a list of var_dec. *)
|
||||
let rec vd_find n = function
|
||||
| [] -> Format.printf "Not found var %s\n" (name n); raise Not_found
|
||||
| vd::l ->
|
||||
if vd.v_name = n then vd else vd_find n l
|
||||
|
||||
let lhs_of_exp = function
|
||||
| Lhs l -> l
|
||||
| _ -> assert false
|
||||
|
||||
module Printer =
|
||||
struct
|
||||
open Format
|
||||
|
||||
let rec print_list ff print sep = function
|
||||
| [] -> ()
|
||||
| [x] -> print ff x
|
||||
| x :: l ->
|
||||
print ff x;
|
||||
fprintf ff "%s@ " sep;
|
||||
print_list ff print sep l
|
||||
|
||||
(* Infix chars are surrounded by parenthesis *)
|
||||
let is_infix =
|
||||
let module StrSet = Set.Make(String) in
|
||||
let set_infix =
|
||||
List.fold_right
|
||||
StrSet.add
|
||||
["or"; "quo"; "mod"; "land"; "lor"; "lxor"; "lsl"; "lsr"; "asr"]
|
||||
StrSet.empty in
|
||||
fun s -> StrSet.mem s set_infix
|
||||
|
||||
let print_name ff s =
|
||||
let c = String.get s 0 in
|
||||
let s = if is_infix s then "(" ^ s ^ ")"
|
||||
else match c with
|
||||
| 'a' .. 'z' | 'A' .. 'Z' | '_' | '`' -> s
|
||||
| '*' -> "( " ^ s ^ " )"
|
||||
| _ -> if s = "()" then s else "(" ^ s ^ ")" in
|
||||
fprintf ff "%s" s
|
||||
|
||||
let print_longname ff ln =
|
||||
let ln = (* currentname ln*) ln in
|
||||
match ln with
|
||||
| Name(m) -> print_name ff m
|
||||
| Modname({ qual = "Pervasives"; id = m }) -> print_name ff m
|
||||
| Modname({ qual = m1; id = m2 }) ->
|
||||
fprintf ff "%s." m1; print_name ff m2
|
||||
|
||||
let print_ident ff id =
|
||||
fprintf ff "%s" (name id)
|
||||
|
||||
let rec print_type ff = function
|
||||
| Tint -> fprintf ff "int"
|
||||
| Tfloat -> fprintf ff "float"
|
||||
| Tid(id) -> print_longname ff id
|
||||
| Tarray(ty, n) ->
|
||||
print_type ff ty;
|
||||
fprintf ff "^%d" n
|
||||
|
||||
let print_vd ff vd =
|
||||
fprintf ff "@[<v>";
|
||||
print_ident ff vd.v_name;
|
||||
fprintf ff ": ";
|
||||
if vd.v_pass_by_ref then
|
||||
fprintf ff "&";
|
||||
print_type ff vd.v_type;
|
||||
fprintf ff "@]"
|
||||
|
||||
let print_obj ff { cls = cls; obj = obj; n = n } =
|
||||
fprintf ff "@[<v>"; print_name ff obj;
|
||||
fprintf ff " : "; print_longname ff cls;
|
||||
if n <> 1 then
|
||||
fprintf ff "[%d]" n;
|
||||
fprintf ff ";@]"
|
||||
|
||||
let rec print_c ff = function
|
||||
| Cint i -> fprintf ff "%d" i
|
||||
| Cfloat f -> fprintf ff "%f" f
|
||||
| Cconstr(tag) -> print_longname ff tag
|
||||
| Cconst_array(n,c) ->
|
||||
print_c ff c;
|
||||
fprintf ff "^%d" n
|
||||
|
||||
let rec print_lhs ff e =
|
||||
match e with
|
||||
| Var x -> print_ident ff x
|
||||
| Mem x -> fprintf ff "mem("; print_ident ff x; fprintf ff ")"
|
||||
| Field (l, f) -> print_lhs ff l; fprintf ff ".%s" (shortname f)
|
||||
|
||||
let rec print_exps ff e_list = print_list ff print_exp "," e_list
|
||||
|
||||
and print_exp ff = function
|
||||
| Lhs lhs -> print_lhs ff lhs
|
||||
| Const c -> print_c ff c
|
||||
| Op(op, e_list) -> print_op ff op e_list
|
||||
| Struct(_,f_e_list) ->
|
||||
fprintf ff "@[<v 1>{";
|
||||
print_list ff
|
||||
(fun ff (field, e) -> print_longname ff field;fprintf ff " = ";
|
||||
print_exp ff e)
|
||||
";" f_e_list;
|
||||
fprintf ff "}@]"
|
||||
| Array e_list ->
|
||||
fprintf ff "@[[";
|
||||
print_list ff print_exp ";" e_list;
|
||||
fprintf ff "]@]"
|
||||
| Array_select(x, idx) ->
|
||||
print_exp ff x;
|
||||
fprintf ff "[";
|
||||
print_list ff (fun ff -> fprintf ff "%d") "][" idx;
|
||||
fprintf ff "]"
|
||||
|
||||
and print_op ff op e_list =
|
||||
print_longname ff op;
|
||||
fprintf ff "(@["; print_list ff print_exp ", " e_list;
|
||||
fprintf ff ")@]"
|
||||
|
||||
let print_asgn ff pref x e =
|
||||
fprintf ff "@[%s" pref; print_lhs ff x; fprintf ff " = ";
|
||||
fprintf ff "@["; print_exp ff e; fprintf ff "@]";
|
||||
fprintf ff "@]"
|
||||
|
||||
let rec print_act ff a =
|
||||
match a with
|
||||
| Assgn (x, e) -> print_asgn ff "" x e
|
||||
| Comp (a1, a2) ->
|
||||
fprintf ff "@[<v>";
|
||||
print_act ff a1;
|
||||
fprintf ff ";@,";
|
||||
print_act ff a2;
|
||||
fprintf ff "@]"
|
||||
| Case(e, tag_act_list) ->
|
||||
fprintf ff "@[<v>@[<v 2>switch (";
|
||||
print_exp ff e; fprintf ff ") {@,";
|
||||
print_tag_act_list ff tag_act_list;
|
||||
fprintf ff "@]@,}@]"
|
||||
| Step_ap (var_list, o, es) ->
|
||||
fprintf ff "@[(";
|
||||
print_list ff print_lhs "," var_list;
|
||||
fprintf ff "@])";
|
||||
fprintf ff " = "; print_name ff o; fprintf ff ".step(";
|
||||
fprintf ff "@["; print_exps ff es; fprintf ff "@]";
|
||||
fprintf ff ")"
|
||||
| Reinit o ->
|
||||
print_name ff o; fprintf ff ".reset()"
|
||||
| Nothing -> fprintf ff "()"
|
||||
| Array_select_slice (var, e, idx1, idx2) ->
|
||||
fprintf ff "@[";
|
||||
print_lhs ff var;
|
||||
fprintf ff " = ";
|
||||
print_exp ff e;
|
||||
fprintf ff "[%d..%d]" idx1 idx2;
|
||||
fprintf ff "@]"
|
||||
| Array_select_dyn (var, x, idx, _, defe) ->
|
||||
fprintf ff "@[";
|
||||
print_lhs ff var;
|
||||
fprintf ff " = ";
|
||||
fprintf ff "@[";
|
||||
print_exp ff x;
|
||||
fprintf ff "[";
|
||||
print_list ff print_exp "][" idx;
|
||||
fprintf ff "] default ";
|
||||
print_exp ff defe;
|
||||
fprintf ff "@]"
|
||||
| Array_update (x, e1, idx, e2) ->
|
||||
fprintf ff "@[";
|
||||
print_lhs ff x;
|
||||
fprintf ff " = ";
|
||||
print_exp ff e1;
|
||||
fprintf ff " with [";
|
||||
print_list ff (fun ff -> fprintf ff "%d") "][" idx;
|
||||
fprintf ff "] = ";
|
||||
print_exp ff e2;
|
||||
fprintf ff "@]"
|
||||
| Array_repeat (x, n, e) ->
|
||||
fprintf ff "@[";
|
||||
print_lhs ff x;
|
||||
fprintf ff " = ";
|
||||
print_exp ff e;
|
||||
fprintf ff "^%d" n
|
||||
| Array_iterate (o_list, it, f, n, e_list) ->
|
||||
fprintf ff "@[(";
|
||||
print_list ff print_lhs ", " o_list;
|
||||
fprintf ff ") = ";
|
||||
fprintf ff "(";
|
||||
fprintf ff "%s" (iterator_to_string it);
|
||||
fprintf ff " ";
|
||||
print_name ff f;
|
||||
fprintf ff " <<%d>>) (@[" n;
|
||||
print_list ff print_exp "," e_list;
|
||||
fprintf ff ")@]@]"
|
||||
| Array_concat (x, e1, e2) ->
|
||||
fprintf ff "@[";
|
||||
print_lhs ff x;
|
||||
fprintf ff " = ";
|
||||
print_exp ff e1;
|
||||
fprintf ff " @@ ";
|
||||
print_exp ff e2
|
||||
| Field_update (x, e1, f, e2) ->
|
||||
fprintf ff "@[";
|
||||
print_lhs ff x;
|
||||
fprintf ff " = ";
|
||||
print_exp ff e1;
|
||||
fprintf ff " with .";
|
||||
print_longname ff f;
|
||||
fprintf ff " = ";
|
||||
print_exp ff e2;
|
||||
fprintf ff "@]"
|
||||
|
||||
and print_tag_act_list ff tag_act_list =
|
||||
print_list ff
|
||||
(fun ff (tag, a) ->
|
||||
fprintf ff "@[<hov 2>case@ ";
|
||||
print_longname ff tag;
|
||||
fprintf ff ":@ ";
|
||||
print_act ff a;
|
||||
fprintf ff "@]") "" tag_act_list
|
||||
|
||||
let print_step ff { inp = inp; out = out; local = nl; bd = bd } =
|
||||
fprintf ff "@[<v 2>";
|
||||
fprintf ff "step(@[";
|
||||
print_list ff print_vd ";" inp;
|
||||
fprintf ff "@]) returns (@[";
|
||||
print_list ff print_vd ";" out;
|
||||
fprintf ff "@]){@,";
|
||||
if nl <> [] then begin
|
||||
fprintf ff "@[<hov 4>var ";
|
||||
print_list ff print_vd ";" nl;
|
||||
fprintf ff ";@]@,"
|
||||
end;
|
||||
print_act ff bd;
|
||||
fprintf ff "}@]"
|
||||
|
||||
let print_reset ff act =
|
||||
fprintf ff "@[<v 2>";
|
||||
fprintf ff "reset() {@,";
|
||||
print_act ff act;
|
||||
fprintf ff "}@]"
|
||||
|
||||
let print_def ff
|
||||
{ cl_id = id; mem = mem; objs = objs; reset = reset; step = step } =
|
||||
fprintf ff "@[<v 2>machine "; print_name ff id; fprintf ff " =@,";
|
||||
if mem <> [] then begin
|
||||
fprintf ff "@[<hov 4>var ";
|
||||
print_list ff print_vd ";" mem;
|
||||
fprintf ff ";@]@,"
|
||||
end;
|
||||
if objs <> [] then begin
|
||||
fprintf ff "@[<hov 4>obj ";
|
||||
print_list ff print_obj ";" objs;
|
||||
fprintf ff ";@]@,"
|
||||
end;
|
||||
print_reset ff reset;
|
||||
fprintf ff "@,";
|
||||
print_step ff step;
|
||||
fprintf ff "@]"
|
||||
|
||||
let print_type_def ff { t_name = name; t_desc = tdesc } =
|
||||
match tdesc with
|
||||
| Type_abs -> fprintf ff "@[type %s@\n@]" name
|
||||
| Type_enum(tag_name_list) ->
|
||||
fprintf ff "@[type %s = " name;
|
||||
print_list ff print_name "| " tag_name_list;
|
||||
fprintf ff "@\n@]"
|
||||
| Type_struct(f_ty_list) ->
|
||||
fprintf ff "@[type %s = " name;
|
||||
fprintf ff "@[<v 1>{";
|
||||
print_list ff
|
||||
(fun ff (field, ty) ->
|
||||
print_name ff field;
|
||||
fprintf ff ": ";
|
||||
print_type ff ty) ";" f_ty_list;
|
||||
fprintf ff "}@]@.@]"
|
||||
|
||||
let print_open_module ff name =
|
||||
fprintf ff "@[open ";
|
||||
print_name ff name;
|
||||
fprintf ff "@.@]"
|
||||
|
||||
let print_prog ff { o_opened = modules; o_types = types; o_defs = defs } =
|
||||
List.iter (print_open_module ff) modules;
|
||||
List.iter (print_type_def ff) types;
|
||||
List.iter (fun def -> (print_def ff def; fprintf ff "@ ")) defs
|
||||
|
||||
let print oc p =
|
||||
let ff = formatter_of_out_channel oc in
|
||||
fprintf ff "@[-- Code generated by the MiniLucid Compiler@.";
|
||||
fprintf ff "@[<v>"; print_prog ff p; fprintf ff "@]@]@."
|
||||
end
|
||||
|
127
minils/transformations/callgraph.ml
Normal file
127
minils/transformations/callgraph.ml
Normal file
|
@ -0,0 +1,127 @@
|
|||
open Misc
|
||||
open Minils
|
||||
open Names
|
||||
open Ident
|
||||
open Format
|
||||
open Location
|
||||
open Printf
|
||||
open Static
|
||||
|
||||
module Error =
|
||||
struct
|
||||
type error =
|
||||
| Emain_node_no_params of name
|
||||
|
||||
let message loc kind =
|
||||
begin match kind with
|
||||
| Emain_node_no_params n ->
|
||||
eprintf "%aThe main node '%s' cannot have parameters.\n"
|
||||
output_location loc
|
||||
n
|
||||
end;
|
||||
raise Misc.Error
|
||||
end
|
||||
|
||||
let nodes_instances = ref NamesEnv.empty
|
||||
let global_env = ref NamesEnv.empty
|
||||
|
||||
let rec string_of_int_list = function
|
||||
| [] -> ""
|
||||
| [n] -> (string_of_int n)
|
||||
| n::l -> (string_of_int n)^", "^(string_of_int_list l)
|
||||
|
||||
let add_node_params n params =
|
||||
if NamesEnv.mem n !nodes_instances then
|
||||
nodes_instances := NamesEnv.add n (params::(NamesEnv.find n !nodes_instances)) !nodes_instances
|
||||
else
|
||||
nodes_instances := NamesEnv.add n [params] !nodes_instances
|
||||
|
||||
let rec node_by_name s = function
|
||||
| [] -> raise Not_found
|
||||
| n::l ->
|
||||
if n.n_name = s then
|
||||
n
|
||||
else
|
||||
node_by_name s l
|
||||
|
||||
let build env params_names params_values =
|
||||
List.fold_left2 (fun m n v -> NamesEnv.add n (SConst v) m) env params_names params_values
|
||||
|
||||
let rec collect_exp nodes env e =
|
||||
match e.e_desc with
|
||||
| Emerge(_, c_e_list) ->
|
||||
List.iter (fun (_, e) -> collect_exp nodes env e) c_e_list
|
||||
| Eifthenelse(e1, e2, e3) ->
|
||||
collect_exp nodes env e1;
|
||||
collect_exp nodes env e2;
|
||||
collect_exp nodes env e3
|
||||
| Ewhen(e, _, _) | Efby(_, e) | Efield(e, _) | Erepeat (_,e)
|
||||
| Eselect (_,e) | Eselect_slice (_ , _, e) ->
|
||||
collect_exp nodes env e
|
||||
| Etuple e_list | Earray e_list
|
||||
| Eop(_, _, e_list) ->
|
||||
List.iter (collect_exp nodes env) e_list
|
||||
| Evar _ | Econstvar _ | Econst _ | Ereset_mem _ -> ()
|
||||
| Estruct(f_e_list) ->
|
||||
List.iter (fun (_, e) -> collect_exp nodes env e) f_e_list
|
||||
| Eselect_dyn (e_list, _, e1, e2) ->
|
||||
List.iter (collect_exp nodes env) e_list;
|
||||
collect_exp nodes env e1;
|
||||
collect_exp nodes env e2
|
||||
| Eupdate (_, e1, e2) | Econcat (e1, e2) | Efield_update(_, e1, e2) ->
|
||||
collect_exp nodes env e1;
|
||||
collect_exp nodes env e2
|
||||
(* Do the real work: call node *)
|
||||
| Eevery(ln, params, e_list, _)
|
||||
| Eapp(ln, params, e_list) ->
|
||||
List.iter (collect_exp nodes env) e_list;
|
||||
let params = List.map (int_of_size_exp env) params in
|
||||
(match params with
|
||||
| [] -> ()
|
||||
| params ->
|
||||
let n = node_by_name (shortname ln.a_op) nodes in
|
||||
node_call nodes n params
|
||||
)
|
||||
| Eiterator (_, ln, params, _, e_list, _) ->
|
||||
List.iter (collect_exp nodes env) e_list;
|
||||
let params = List.map (int_of_size_exp env) params in
|
||||
(match params with
|
||||
| [] -> ()
|
||||
| params ->
|
||||
let n = node_by_name (shortname ln) nodes in
|
||||
node_call nodes n params
|
||||
)
|
||||
|
||||
and collect_eqs nodes env eq =
|
||||
collect_exp nodes env eq.p_rhs
|
||||
|
||||
and node_call nodes n params =
|
||||
match params with
|
||||
| [] ->
|
||||
List.iter (collect_eqs nodes !global_env) n.n_equs
|
||||
| params ->
|
||||
add_node_params n.n_name params;
|
||||
let env = build !global_env n.n_params params in
|
||||
List.iter (collect_eqs nodes env) n.n_equs
|
||||
|
||||
let node n =
|
||||
let inst =
|
||||
if NamesEnv.mem n.n_name !nodes_instances then
|
||||
NamesEnv.find n.n_name !nodes_instances
|
||||
else
|
||||
[] in
|
||||
{ n with n_params_instances = inst }
|
||||
|
||||
let build_const_env cd_list =
|
||||
List.fold_left (fun env cd -> NamesEnv.add cd.Minils.c_name cd.Minils.c_value env) NamesEnv.empty cd_list
|
||||
|
||||
let program p =
|
||||
let try_call_node n =
|
||||
match n.n_params with
|
||||
| [] -> node_call p.p_nodes n []
|
||||
| _ -> ()
|
||||
in
|
||||
global_env := build_const_env p.p_consts;
|
||||
List.iter try_call_node p.p_nodes;
|
||||
{ p with p_nodes = List.map node p.p_nodes }
|
||||
|
295
minils/transformations/clocking.ml
Normal file
295
minils/transformations/clocking.ml
Normal file
|
@ -0,0 +1,295 @@
|
|||
(**************************************************************************)
|
||||
(* *)
|
||||
(* MiniLustre *)
|
||||
(* *)
|
||||
(* Author : Marc Pouzet *)
|
||||
(* Organization : Demons, LRI, University of Paris-Sud, Orsay *)
|
||||
(* *)
|
||||
(**************************************************************************)
|
||||
|
||||
(* clock checking *)
|
||||
|
||||
(* $Id$ *)
|
||||
|
||||
open Misc
|
||||
open Ident
|
||||
open Minils
|
||||
open Global
|
||||
open Location
|
||||
|
||||
type error = | Etypeclash of ct * ct
|
||||
|
||||
exception TypingError of error
|
||||
exception Unify
|
||||
|
||||
let error kind = raise (TypingError(kind))
|
||||
|
||||
let message e kind =
|
||||
begin match kind with
|
||||
Etypeclash(actual_ct, expected_ct) ->
|
||||
Printf.eprintf "%aClock Clash: this expression has clock %a, \n\
|
||||
but is expected to have clock %a.\n"
|
||||
Printer.print_exp e
|
||||
Printer.print_clock actual_ct
|
||||
Printer.print_clock expected_ct
|
||||
end;
|
||||
raise Error
|
||||
|
||||
let index = ref 0
|
||||
let gen_index () = incr index; !index
|
||||
let new_var () = Cvar { contents = Cindex (gen_index ()) }
|
||||
|
||||
let rec repr ck =
|
||||
match ck with
|
||||
Cbase | Con _ | Cvar { contents = Cindex _ } -> ck
|
||||
| Cvar ({ contents = Clink(ck) } as link) ->
|
||||
let ck = repr ck in
|
||||
link.contents <- Clink(ck);
|
||||
ck
|
||||
|
||||
let rec occur_check index ck =
|
||||
let ck = repr ck in
|
||||
match ck with
|
||||
Cbase -> ()
|
||||
| Cvar { contents = Cindex n } when index <> n -> ()
|
||||
| Con(ck, _, _) -> occur_check index ck
|
||||
| _ -> raise Unify
|
||||
|
||||
let rec ck_value ck =
|
||||
match ck with
|
||||
| Cbase | Con _ | Cvar { contents = Cindex _ } -> ck
|
||||
| Cvar { contents = Clink(ck) } ->
|
||||
ck_value ck
|
||||
|
||||
let rec unify t1 t2 =
|
||||
if t1 == t2 then ()
|
||||
else match t1, t2 with
|
||||
Ck(ck1), Ck(ck2) -> unify_ck ck1 ck2
|
||||
| Cprod(ct_list1), Cprod(ct_list2) ->
|
||||
begin try
|
||||
List.iter2 unify ct_list1 ct_list2
|
||||
with
|
||||
_ -> raise Unify
|
||||
end
|
||||
| _ -> raise Unify
|
||||
|
||||
and unify_ck ck1 ck2 =
|
||||
let ck1 = repr ck1 in
|
||||
let ck2 = repr ck2 in
|
||||
if ck1 == ck2 then ()
|
||||
else match ck1, ck2 with
|
||||
Cbase, Cbase -> ()
|
||||
| Cvar { contents = Cindex n1 }, Cvar { contents = Cindex n2 }
|
||||
when n1 = n2 -> ()
|
||||
| Cvar ({ contents = Cindex n1 } as v), _ ->
|
||||
occur_check n1 ck2;
|
||||
v.contents <- Clink(ck2)
|
||||
| _, Cvar ({contents = Cindex n2 } as v) ->
|
||||
occur_check n2 ck1;
|
||||
v.contents <- Clink(ck1)
|
||||
| Con(ck1, c1, n1), Con(ck2, c2, n2) when (c1 = c2) & (n1 = n2) ->
|
||||
unify_ck ck1 ck2
|
||||
| _ -> raise Unify
|
||||
|
||||
let rec eq ck1 ck2 =
|
||||
match repr ck1, repr ck2 with
|
||||
| Cbase, Cbase -> true
|
||||
| Cvar { contents = Cindex n1 }, Cvar { contents = Cindex n2 } -> true
|
||||
| Con(ck1, _, n1), Con(ck2, _, n2) when (n1 = n2) -> eq ck1 ck2
|
||||
| _ -> false
|
||||
|
||||
let rec unify t1 t2 =
|
||||
match t1, t2 with
|
||||
Ck(ck1), Ck(ck2) -> unify_ck ck1 ck2
|
||||
| Cprod(t1_list), Cprod(t2_list) -> unify_list t1_list t2_list
|
||||
| _ -> raise Unify
|
||||
|
||||
and unify_list t1_list t2_list =
|
||||
try
|
||||
List.iter2 unify t1_list t2_list
|
||||
with
|
||||
_ -> raise Unify
|
||||
|
||||
let rec skeleton ck = function
|
||||
| Tprod(ty_list) -> Cprod(List.map (skeleton ck) ty_list)
|
||||
| Tbase _ -> Ck(ck)
|
||||
|
||||
let ckofct = function
|
||||
| Ck(ck) -> repr ck
|
||||
| Cprod(ct_list) -> Cbase
|
||||
|
||||
let prod = function
|
||||
| [] -> assert false
|
||||
| [ty] -> ty
|
||||
| ty_list -> Tprod(ty_list)
|
||||
|
||||
let typ_of_name h x = Env.find x h
|
||||
|
||||
let rec typing h e =
|
||||
let ct = match e.e_desc with
|
||||
| Econst _ | Econstvar _ -> Ck(new_var ())
|
||||
| Evar(x) -> Ck(typ_of_name h x)
|
||||
| Efby(c, e) -> typing h e
|
||||
| Etuple(e_list) ->
|
||||
Cprod(List.map (typing h) e_list)
|
||||
| Eop(_,_, e_list) ->
|
||||
let ck = new_var () in
|
||||
List.iter (expect h (Ck(ck))) e_list;
|
||||
skeleton ck e.e_ty
|
||||
| Eapp(_,_, e_list) ->
|
||||
let ck_r = new_var () in
|
||||
List.iter (expect h (Ck(ck_r))) e_list;
|
||||
skeleton ck_r e.e_ty
|
||||
| Eevery(_,_, e_list, n) ->
|
||||
let ck_r = typ_of_name h n in
|
||||
List.iter (expect h (Ck(ck_r))) e_list;
|
||||
skeleton ck_r e.e_ty
|
||||
| Ewhen(e, c, n) ->
|
||||
let ck_n = typ_of_name h n in
|
||||
expect h (skeleton ck_n e.e_ty) e;
|
||||
skeleton (Con(ck_n, c, n)) e.e_ty
|
||||
| Eifthenelse(e1, e2, e3) ->
|
||||
let ck = new_var () in
|
||||
let ct = skeleton ck e.e_ty in
|
||||
expect h (Ck(ck)) e1;
|
||||
expect h ct e2;
|
||||
expect h ct e3; ct
|
||||
| Emerge(n, c_e_list) ->
|
||||
let ck_c = typ_of_name h n in
|
||||
typing_c_e_list h ck_c n c_e_list;
|
||||
skeleton ck_c e.e_ty
|
||||
| Efield(e1,n) ->
|
||||
let ck = new_var () in
|
||||
let ct = skeleton ck e1.e_ty in
|
||||
expect h (Ck(ck)) e1;
|
||||
ct
|
||||
| Estruct(l) ->
|
||||
let ck = new_var () in
|
||||
List.iter
|
||||
(fun (n,e) ->
|
||||
let ct = skeleton ck e.e_ty in
|
||||
expect h ct e)
|
||||
l;
|
||||
Ck(ck)
|
||||
(*Array operators*)
|
||||
| Earray e_list ->
|
||||
let ck = new_var () in
|
||||
List.iter (expect h (Ck(ck))) e_list;
|
||||
skeleton ck e.e_ty
|
||||
| Erepeat (_,e) ->
|
||||
typing h e
|
||||
| Eselect (_,e) ->
|
||||
typing h e
|
||||
| Eselect_dyn (e_list, _, e, defe) ->
|
||||
let ck = new_var () in
|
||||
let ct = skeleton ck e.e_ty in
|
||||
expect h ct e;
|
||||
List.iter (expect h ct) e_list;
|
||||
ct
|
||||
| Eupdate (_, e1, e2) | Efield_update (_, e1, e2) ->
|
||||
let ck = new_var () in
|
||||
let ct = skeleton ck e.e_ty in
|
||||
expect h (Ck(ck)) e1;
|
||||
expect h ct e2;
|
||||
ct
|
||||
| Eselect_slice (_ , _, e) ->
|
||||
typing h e
|
||||
| Econcat (e1, e2) ->
|
||||
let ck = new_var () in
|
||||
let ct = skeleton ck e.e_ty in
|
||||
expect h (Ck(ck)) e1;
|
||||
expect h ct e2;
|
||||
ct
|
||||
| Eiterator (_, f, _, _, e_list, _) ->
|
||||
let ck_r = new_var () in
|
||||
List.iter (expect h (Ck(ck_r))) e_list;
|
||||
skeleton ck_r e.e_ty
|
||||
| Ereset_mem (_, _, x) -> assert false
|
||||
in
|
||||
e.e_ck <- ckofct ct;
|
||||
ct
|
||||
|
||||
and expect h expected_ty e =
|
||||
let actual_ty = typing h e in
|
||||
try unify actual_ty expected_ty
|
||||
with Unify -> message e (Etypeclash(actual_ty, expected_ty))
|
||||
|
||||
and typing_c_e_list h ck_c n c_e_list =
|
||||
let rec typrec = function
|
||||
| [] -> ()
|
||||
| (c, e) :: c_e_list ->
|
||||
expect h (skeleton (Con(ck_c, c, n)) e.e_ty) e;
|
||||
typrec c_e_list in
|
||||
typrec c_e_list
|
||||
|
||||
let rec typing_pat h = function
|
||||
| Evarpat(x) -> Ck(typ_of_name h x)
|
||||
| Etuplepat(pat_list) -> Cprod(List.map (typing_pat h) pat_list)
|
||||
|
||||
let typing_eqs h eq_list =
|
||||
List.iter
|
||||
(fun { p_lhs = pat; p_rhs = e } ->
|
||||
(match e.e_desc with
|
||||
| Ereset_mem (_, _, x) ->
|
||||
let ck = typ_of_name h x in
|
||||
e.e_ck <- ck;
|
||||
| _ ->
|
||||
let ty_pat = typing_pat h pat in
|
||||
try
|
||||
expect h ty_pat e
|
||||
with Error ->
|
||||
(* DEBUG *)
|
||||
Printf.eprintf "Complete expression: %a\n"
|
||||
Printer.print_exp e;
|
||||
Printf.eprintf "Clock pattern: %a\n"
|
||||
Printer.print_clock ty_pat;
|
||||
raise Error
|
||||
)
|
||||
) eq_list
|
||||
|
||||
let build h dec =
|
||||
List.fold_left (fun h { v_name = n } -> Env.add n (new_var ()) h) h dec
|
||||
|
||||
let sbuild h dec base =
|
||||
List.fold_left (fun h { v_name = n } -> Env.add n base h) h dec
|
||||
|
||||
let typing_contract h contract base =
|
||||
match contract with
|
||||
| None -> h
|
||||
| Some { c_local = l_list;
|
||||
c_eq = eq_list;
|
||||
c_assume = e_a;
|
||||
c_enforce = e_g;
|
||||
c_controllables = c_list } ->
|
||||
let h = sbuild h c_list base in
|
||||
let h' = build h l_list in
|
||||
typing_eqs h' eq_list;
|
||||
(* assumption *)
|
||||
expect h' (Ck base) e_a;
|
||||
(* property *)
|
||||
expect h' (Ck base) e_g;
|
||||
h
|
||||
|
||||
let typing_node ({ n_name = f; n_input = i_list; n_output = o_list;
|
||||
n_contract = contract;
|
||||
n_local = l_list; n_equs = eq_list } as node) =
|
||||
let base = Cbase in
|
||||
let h = sbuild Env.empty i_list base in
|
||||
let h = sbuild h o_list base in
|
||||
|
||||
let h = typing_contract h contract base in
|
||||
|
||||
let h = build h l_list in
|
||||
typing_eqs h eq_list;
|
||||
|
||||
(*update clock info in variables descriptions *)
|
||||
let set_clock vd =
|
||||
{ vd with v_clock = ck_value (Env.find vd.v_name h) } in
|
||||
|
||||
{ node with n_input = List.map set_clock i_list;
|
||||
n_output = List.map set_clock o_list;
|
||||
n_local = List.map set_clock l_list; }
|
||||
|
||||
|
||||
let program ({ p_nodes = p_node_list } as p) =
|
||||
{ p with p_nodes = List.map typing_node p_node_list }
|
314
minils/transformations/init.ml
Normal file
314
minils/transformations/init.ml
Normal file
|
@ -0,0 +1,314 @@
|
|||
(**************************************************************************)
|
||||
(* *)
|
||||
(* Heptagon *)
|
||||
(* *)
|
||||
(* Author : Marc Pouzet *)
|
||||
(* Organization : Demons, LRI, University of Paris-Sud, Orsay *)
|
||||
(* *)
|
||||
(**************************************************************************)
|
||||
|
||||
(* simple initialization analysis. This is almost trivial since *)
|
||||
(* input/outputs of a node are forced to be initialized *)
|
||||
(* add a special treatment of clock state variables whose initial *)
|
||||
(* values are known. This allows to accept code generated *)
|
||||
(* for automata *)
|
||||
(* if [clock c = C fby ec] then [merge c (C -> e) ...] is initialized *)
|
||||
(* if [e] is initialized only *)
|
||||
|
||||
(* $Id: init.ml 615 2009-11-20 17:43:14Z pouzet $ *)
|
||||
|
||||
open Misc
|
||||
open Names
|
||||
open Ident
|
||||
open Minils
|
||||
open Location
|
||||
open Format
|
||||
|
||||
type typ =
|
||||
| Iproduct of typ list
|
||||
| Ileaf of init
|
||||
|
||||
and init =
|
||||
{ mutable i_desc: init_desc;
|
||||
mutable i_index: int }
|
||||
|
||||
and init_desc =
|
||||
| Izero
|
||||
| Ione
|
||||
| Ivar
|
||||
| Imax of init * init
|
||||
| Ilink of init
|
||||
|
||||
type typ_env =
|
||||
{ t_init: init; (* its initialisation type *)
|
||||
t_value: longname option; (* its initial value *)
|
||||
}
|
||||
|
||||
(* typing errors *)
|
||||
exception Unify
|
||||
|
||||
let index = ref 0
|
||||
let gen_index () = incr index; !index
|
||||
let new_var () = { i_desc = Ivar; i_index = gen_index () }
|
||||
let izero = { i_desc = Izero; i_index = gen_index () }
|
||||
let ione = { i_desc = Ione; i_index = gen_index () }
|
||||
let imax i1 i2 = { i_desc = Imax(i1, i2); i_index = gen_index () }
|
||||
let product l = Iproduct(l)
|
||||
let leaf i = Ileaf(i)
|
||||
|
||||
(* basic operation on initialization values *)
|
||||
let rec irepr i =
|
||||
match i.i_desc with
|
||||
| Ilink(i_son) ->
|
||||
let i_son = irepr i_son in
|
||||
i.i_desc <- Ilink(i_son);
|
||||
i_son
|
||||
| _ -> i
|
||||
|
||||
(** Simplification rules for max. Nothing fancy here *)
|
||||
let max i1 i2 =
|
||||
let i1 = irepr i1 in
|
||||
let i2 = irepr i2 in
|
||||
match i1.i_desc, i2.i_desc with
|
||||
| (Izero, Izero) -> izero
|
||||
| (Izero, _) -> i2
|
||||
| (_, Izero) -> i1
|
||||
| (_, Ione) | (Ione, _) -> ione
|
||||
| _ -> imax i1 i2
|
||||
|
||||
let rec itype = function
|
||||
| Iproduct(ty_list) -> itype_list ty_list
|
||||
| Ileaf(i) -> i
|
||||
|
||||
and itype_list ty_list =
|
||||
List.fold_left (fun acc ty -> max acc (itype ty)) izero ty_list
|
||||
|
||||
(* saturate an initialization type. Every element must be initialized *)
|
||||
let rec initialized i =
|
||||
let i = irepr i in
|
||||
match i.i_desc with
|
||||
| Izero -> ()
|
||||
| Ivar -> i.i_desc <- Ilink(izero)
|
||||
| Imax(i1, i2) -> initialized i1; initialized i2
|
||||
| Ilink(i) -> initialized i
|
||||
| Ione -> raise Unify
|
||||
|
||||
(* build an initialization type from a type *)
|
||||
let rec skeleton i ty =
|
||||
match ty with
|
||||
| Tbase _ -> leaf i
|
||||
| Tprod(ty_list) -> product (List.map (skeleton i) ty_list)
|
||||
|
||||
(* sub-typing *)
|
||||
let rec less left_ty right_ty =
|
||||
if left_ty == right_ty then ()
|
||||
else
|
||||
match left_ty, right_ty with
|
||||
| Iproduct(l1), Iproduct(l2) -> List.iter2 less l1 l2
|
||||
| Ileaf(i1), Ileaf(i2) -> iless i1 i2
|
||||
| _ -> raise Unify
|
||||
|
||||
and iless left_i right_i =
|
||||
if left_i == right_i then ()
|
||||
else
|
||||
let left_i = irepr left_i in
|
||||
let right_i = irepr right_i in
|
||||
if left_i == right_i then ()
|
||||
else
|
||||
match left_i.i_desc, right_i.i_desc with
|
||||
| (Izero, _) | (_, Ione) -> ()
|
||||
| _, Izero -> initialized left_i
|
||||
| Imax(i1, i2), _ ->
|
||||
iless i1 right_i; iless i2 right_i
|
||||
| _, Ivar ->
|
||||
let left_i = occur_check right_i.i_index left_i in
|
||||
right_i.i_desc <- Ilink(left_i)
|
||||
| _, Imax(i1, i2) ->
|
||||
let i1 = occur_check left_i.i_index i1 in
|
||||
let i2 = occur_check left_i.i_index i2 in
|
||||
right_i.i_desc <- Ilink(imax left_i (imax i1 i2))
|
||||
| _ -> raise Unify
|
||||
|
||||
(* an inequation [a < t[a]] becomes [a = t[0]] *)
|
||||
and occur_check index i =
|
||||
match i.i_desc with
|
||||
| Izero | Ione -> i
|
||||
| Ivar -> if i.i_index = index then izero else i
|
||||
| Imax(i1, i2) ->
|
||||
max (occur_check index i1) (occur_check index i2)
|
||||
| Ilink(i) -> occur_check index i
|
||||
|
||||
(* computes the initialization type of a merge *)
|
||||
let merge opt_c c_i_list =
|
||||
let rec search c c_i_list =
|
||||
match c_i_list with
|
||||
| [] -> izero
|
||||
| (c0, i) :: c_i_list -> if c = c0 then i else search c c_i_list in
|
||||
match opt_c with
|
||||
| None -> List.fold_left (fun acc (_, i) -> max acc i) izero c_i_list
|
||||
| Some(c) -> search c c_i_list
|
||||
|
||||
module Printer = struct
|
||||
open Format
|
||||
|
||||
let rec print_list_r print po sep pf ff = function
|
||||
| [] -> ()
|
||||
| x :: l ->
|
||||
fprintf ff "@[%s%a" po print x;
|
||||
List.iter (fprintf ff "%s@]@ @[%a" sep print) l;
|
||||
fprintf ff "%s@]" pf
|
||||
|
||||
let rec fprint_init ff i = match i.i_desc with
|
||||
| Izero -> fprintf ff "0"
|
||||
| Ione -> fprintf ff "1"
|
||||
| Ivar -> fprintf ff "0"
|
||||
| Imax(i1, i2) -> fprintf ff "@[%a\\/%a@]" fprint_init i1 fprint_init i2
|
||||
| Ilink(i) -> fprint_init ff i
|
||||
|
||||
let rec fprint_typ ff = function
|
||||
| Ileaf(i) -> fprint_init ff i
|
||||
| Iproduct(ty_list) ->
|
||||
fprintf ff "@[%a@]" (print_list_r fprint_typ "("" *"")") ty_list
|
||||
|
||||
let output_typ oc ty =
|
||||
let ff = formatter_of_out_channel oc in
|
||||
fprintf ff "@[";
|
||||
fprint_typ ff ty;
|
||||
fprintf ff "@?@]"
|
||||
end
|
||||
|
||||
module Error = struct
|
||||
open Location
|
||||
|
||||
type error = | Eclash of typ * typ
|
||||
|
||||
exception Error of location * error
|
||||
|
||||
let error loc kind = raise (Error(loc, kind))
|
||||
|
||||
let message loc kind =
|
||||
begin match kind with
|
||||
| Eclash(left_ty, right_ty) ->
|
||||
Printf.eprintf "%aInitialization error: this expression has type \
|
||||
%a, \n\
|
||||
but is expected to have type %a\n"
|
||||
output_location loc
|
||||
Printer.output_typ left_ty
|
||||
Printer.output_typ right_ty
|
||||
end;
|
||||
raise Misc.Error
|
||||
end
|
||||
|
||||
let less_exp e actual_ty expected_ty =
|
||||
try
|
||||
less actual_ty expected_ty
|
||||
with | Unify -> Error.message e.e_loc (Error.Eclash(actual_ty, expected_ty))
|
||||
|
||||
let rec typing h e =
|
||||
match e.e_desc with
|
||||
| Econst(c) -> leaf izero
|
||||
| Evar(x) -> let { t_init = i } = Env.find x h in leaf i
|
||||
| Efby(None, e) ->
|
||||
expect h e (skeleton izero e.e_ty);
|
||||
leaf ione
|
||||
| Efby(Some _, e) ->
|
||||
expect h e (skeleton izero e.e_ty);
|
||||
leaf izero
|
||||
| Etuple(e_list) ->
|
||||
product (List.map (typing h) e_list)
|
||||
| Eop(_, e_list) ->
|
||||
let i = List.fold_left (fun acc e -> itype (typing h e)) izero e_list in
|
||||
skeleton i e.e_ty
|
||||
| Eapp(_, e_list) ->
|
||||
List.iter (fun e -> expect h e (skeleton izero e.e_ty)) e_list;
|
||||
skeleton izero e.e_ty
|
||||
| Eevery(_, e_list, n) ->
|
||||
List.iter (fun e -> expect h e (skeleton izero e.e_ty)) e_list;
|
||||
let { t_init = i } = Env.find n h in
|
||||
skeleton i e.e_ty
|
||||
| Ewhen(e, c, n) ->
|
||||
let { t_init = i1 } = Env.find n h in
|
||||
let i2 = itype (typing h e) in
|
||||
skeleton (max i1 i2) e.e_ty
|
||||
| Eifthenelse(e1, e2, e3) ->
|
||||
let i1 = itype (typing h e1) in
|
||||
let i2 = itype (typing h e2) in
|
||||
let i3 = itype (typing h e3) in
|
||||
let i = max i1 (max i2 i3) in
|
||||
skeleton i e.e_ty
|
||||
| Emerge(n, c_e_list) ->
|
||||
let { t_init = i; t_value = opt_c } = Env.find n h in
|
||||
let i =
|
||||
merge opt_c
|
||||
(List.map (fun (c, e) -> (c, itype (typing h e))) c_e_list) in
|
||||
skeleton i e.e_ty
|
||||
| Efield(e1,n) ->
|
||||
let i = itype (typing h e1) in
|
||||
skeleton i e.e_ty
|
||||
| Estruct(l) ->
|
||||
let i =
|
||||
List.fold_left
|
||||
(fun acc (_, e) -> max acc (itype (typing h e))) izero l in
|
||||
skeleton i e.e_ty
|
||||
|
||||
and expect h e expected_ty =
|
||||
let actual_ty = typing h e in
|
||||
less_exp e actual_ty expected_ty
|
||||
|
||||
let rec typing_pat h = function
|
||||
| Evarpat(x) -> let { t_init = i } = Env.find x h in leaf i
|
||||
| Etuplepat(pat_list) ->
|
||||
product (List.map (typing_pat h) pat_list)
|
||||
|
||||
let typing_eqs h eq_list =
|
||||
List.iter
|
||||
(fun { p_lhs = pat; p_rhs = e } ->
|
||||
let ty_pat = typing_pat h pat in
|
||||
expect h e ty_pat) eq_list
|
||||
|
||||
let build h eq_list =
|
||||
let rec build_pat h = function
|
||||
| Evarpat(x) -> Env.add x { t_init = new_var (); t_value = None } h
|
||||
| Etuplepat(pat_list) -> List.fold_left build_pat h pat_list in
|
||||
let build_equation h { p_lhs = pat; p_rhs = e } =
|
||||
match pat, e.e_desc with
|
||||
| Evarpat(x), Efby(Some(Cconstr c), _) ->
|
||||
(* we keep the initial value of state variables *)
|
||||
Env.add x { t_init = new_var (); t_value = Some(c) } h
|
||||
| _ -> build_pat h pat in
|
||||
List.fold_left build_equation h eq_list
|
||||
|
||||
let sbuild h dec =
|
||||
List.fold_left
|
||||
(fun h { v_name = n } -> Env.add n { t_init = izero; t_value = None } h)
|
||||
h dec
|
||||
|
||||
let typing_contract h contract =
|
||||
match contract with
|
||||
| None -> h
|
||||
| Some { c_local = l_list; c_eq = eq_list; c_assume = e_a;
|
||||
c_enforce = e_g; c_controllables = c_list } ->
|
||||
let h = sbuild h c_list in
|
||||
let h' = build h eq_list in
|
||||
typing_eqs h' eq_list;
|
||||
(* assumption *)
|
||||
expect h' e_a (skeleton izero e_a.e_ty);
|
||||
(* property *)
|
||||
expect h' e_g (skeleton izero e_g.e_ty);
|
||||
h
|
||||
|
||||
let typing_node { n_name = f; n_input = i_list; n_output = o_list;
|
||||
n_contract = contract;
|
||||
n_local = l_list; n_equs = eq_list } =
|
||||
let h = sbuild Env.empty i_list in
|
||||
let h = sbuild h o_list in
|
||||
let h = typing_contract h contract in
|
||||
|
||||
let h = build h eq_list in
|
||||
typing_eqs h eq_list
|
||||
|
||||
let program ({ p_nodes = p_node_list } as p) =
|
||||
List.iter typing_node p_node_list;
|
||||
p
|
||||
|
||||
|
261
minils/transformations/normalize.ml
Normal file
261
minils/transformations/normalize.ml
Normal file
|
@ -0,0 +1,261 @@
|
|||
(**************************************************************************)
|
||||
(* *)
|
||||
(* Heptagon *)
|
||||
(* *)
|
||||
(* Author : Marc Pouzet *)
|
||||
(* Organization : Demons, LRI, University of Paris-Sud, Orsay *)
|
||||
(* *)
|
||||
(**************************************************************************)
|
||||
(* $Id$ *)
|
||||
|
||||
open Misc
|
||||
open Names
|
||||
open Ident
|
||||
open Global
|
||||
open Minils
|
||||
|
||||
let ctrue = Name("true")
|
||||
and cfalse = Name("false")
|
||||
|
||||
let equation (d_list, eq_list) ({ e_ty = te; e_linearity = l; e_ck = ck } as e) =
|
||||
let n = Ident.fresh "_v" in
|
||||
let d_list = { v_name = n; v_copy_of = None;
|
||||
v_type = base_type te; v_linearity = l; v_clock = ck } :: d_list
|
||||
and eq_list = { p_lhs = Evarpat(n); p_rhs = e } :: eq_list in
|
||||
(d_list, eq_list), n
|
||||
|
||||
let intro context e =
|
||||
match e.e_desc with
|
||||
Evar(n) -> context, n
|
||||
| _ -> equation context e
|
||||
|
||||
(* distribution: [(e1,...,ek) when C(n) = (e1 when C(n),...,ek when C(n))] *)
|
||||
let rec whenc context e c n =
|
||||
let when_on_c c n e =
|
||||
{ e with e_desc = Ewhen(e, c, n); e_ck = Con(e.e_ck, c, n) } in
|
||||
|
||||
match e.e_desc with
|
||||
| Etuple(e_list) ->
|
||||
let context, e_list =
|
||||
List.fold_right
|
||||
(fun e (context, e_list) -> let context, e = whenc context e c n in
|
||||
(context, e :: e_list))
|
||||
e_list (context, []) in
|
||||
context, { e with e_desc = Etuple(e_list); e_ck = Con(e.e_ck, c, n) }
|
||||
(* | Emerge _ -> let context, x = equation context e in
|
||||
context, when_on_c c n { e with e_desc = Evar(x) } *)
|
||||
| _ -> context, when_on_c c n e
|
||||
|
||||
(* transforms [merge x (c1, (e11,...,e1n));...;(ck, (ek1,...,ekn))] into *)
|
||||
(* [merge x (c1, e11)...(ck, ek1),..., merge x (c1, e1n)...(ck, ekn)] *)
|
||||
let rec merge e x ci_a_list =
|
||||
let rec split ci_tas_list =
|
||||
match ci_tas_list with
|
||||
| [] | (_, _, []) :: _ -> [], []
|
||||
| (ci, b, a :: tas) :: ci_tas_list ->
|
||||
let ci_ta_list, ci_tas_list = split ci_tas_list in
|
||||
(ci, a) :: ci_ta_list, (ci, b, tas) :: ci_tas_list in
|
||||
let rec distribute ci_tas_list =
|
||||
match ci_tas_list with
|
||||
| [] | (_, _, []) :: _ -> []
|
||||
| (ci, b, (eo :: _)) :: _ ->
|
||||
let ci_ta_list, ci_tas_list = split ci_tas_list in
|
||||
let ci_tas_list = distribute ci_tas_list in
|
||||
(if b then
|
||||
{ eo with e_desc = Emerge(x, ci_ta_list);
|
||||
e_ck = e.e_ck; e_loc = e.e_loc }
|
||||
else
|
||||
merge e x ci_ta_list)
|
||||
:: ci_tas_list in
|
||||
let rec erasetuple ci_a_list =
|
||||
match ci_a_list with
|
||||
| [] -> []
|
||||
| (ci, { e_desc = Etuple(l) }) :: ci_a_list ->
|
||||
(ci, false, l) :: erasetuple ci_a_list
|
||||
| (ci, e) :: ci_a_list ->
|
||||
(ci, true, [e]) :: erasetuple ci_a_list in
|
||||
let ci_tas_list = erasetuple ci_a_list in
|
||||
let ci_tas_list = distribute ci_tas_list in
|
||||
match ci_tas_list with
|
||||
| [e] -> e
|
||||
| l -> { e with e_desc = Etuple(l) }
|
||||
|
||||
let ifthenelse context e1 e2 e3 =
|
||||
let context, n = intro context e1 in
|
||||
let context, e2 = whenc context e2 ctrue n in
|
||||
let context, e3 = whenc context e3 cfalse n in
|
||||
context, merge e1 n [ctrue, e2; cfalse, e3]
|
||||
|
||||
let const e c =
|
||||
let rec const = function
|
||||
| Cbase | Cvar { contents = Cindex _ } -> c
|
||||
| Con(ck_on, tag, x) ->
|
||||
Ewhen({ e with e_desc = const ck_on; e_ck = ck_on }, tag, x)
|
||||
| Cvar { contents = Clink ck } -> const ck in
|
||||
const e.e_ck
|
||||
|
||||
(* normal form for expressions and equations: *)
|
||||
(* - e ::= op(e,...,e) | x | C | e when C(x) *)
|
||||
(* - act ::= e | merge x (C1 -> act) ... (Cn -> act) | (act,...,act) *)
|
||||
(* - eq ::= [x = v fby e] | [pat = act ] | [pat = f(e1,...,en) every n *)
|
||||
(* - A-normal form: (e1,...,en) when c(x) = (e1 when c(x),...,en when c(x) *)
|
||||
type kind = VRefCond | VRef | Exp | Act | Any
|
||||
|
||||
let function_args_kind = if !no_mem_alloc then Exp else VRefCond
|
||||
let merge_kind = if !no_mem_alloc then Act else VRef
|
||||
|
||||
let rec constant e = match e.e_desc with
|
||||
| Econst _ | Econstvar _ -> true
|
||||
| Ewhen(e, _, _) -> constant e
|
||||
| Evar _ -> true
|
||||
| _ -> false
|
||||
|
||||
let add context expected_kind ({ e_desc = de; e_linearity = l } as e) =
|
||||
let up = match de, expected_kind with
|
||||
| (Evar _ | Efield _ ) , VRefCond -> false
|
||||
| Efby _, VRefCond -> true
|
||||
| _ , VRefCond -> not (Linearity.is_not_linear l)
|
||||
| (Evar _ | Efield _ ) , VRef -> false
|
||||
| _ , VRef -> true
|
||||
| ( Emerge _ | Etuple _
|
||||
| Eapp _ | Eevery _ | Efby _ | Eselect_dyn _
|
||||
| Eupdate _ | Econcat _ | Erepeat _ | Eiterator _
|
||||
| Eselect_slice _ ), Exp -> true
|
||||
| ( Eapp _ | Eevery _ | Efby _ ), Act -> true
|
||||
| _ -> false in
|
||||
if up then
|
||||
let context, n = equation context e in
|
||||
context, { e with e_desc = Evar(n) }
|
||||
else context, e
|
||||
|
||||
let rec translate kind context e =
|
||||
let context, e = match e.e_desc with
|
||||
| Emerge(n, tag_e_list) ->
|
||||
let context, ta_list =
|
||||
List.fold_right
|
||||
(fun (tag, e) (context, ta_list) ->
|
||||
let context, act = translate merge_kind context e in
|
||||
context, ((tag, act) :: ta_list))
|
||||
tag_e_list (context, []) in
|
||||
context, merge e n ta_list
|
||||
| Eifthenelse(e1, e2, e3) ->
|
||||
let context, e1 = translate Any context e1 in
|
||||
let context, e2 = translate Act context e2 in
|
||||
let context, e3 = translate Act context e3 in
|
||||
ifthenelse context e1 e2 e3
|
||||
| Etuple(e_list) ->
|
||||
let context, e_list = translate_list kind context e_list in
|
||||
context, { e with e_desc = Etuple(e_list) }
|
||||
| Ewhen(e1, c, n) ->
|
||||
let context, e1 = translate kind context e1 in
|
||||
whenc context e1 c n
|
||||
| Eop(op, params, e_list) ->
|
||||
let context, e_list = translate_list function_args_kind context e_list in
|
||||
context, { e with e_desc = Eop(op, params, e_list) }
|
||||
| Eapp(app, params, e_list) ->
|
||||
let context, e_list = translate_list function_args_kind context e_list in
|
||||
context, { e with e_desc = Eapp(app, params, e_list) }
|
||||
| Eevery(app, params, e_list, n) ->
|
||||
let context, e_list = translate_list function_args_kind context e_list in
|
||||
context, { e with e_desc = Eevery(app, params, e_list, n) }
|
||||
| Efby(v, e1) ->
|
||||
let context, e1 = translate Exp context e1 in
|
||||
let context, e1' =
|
||||
if constant e1 then context, e1
|
||||
else let context, n = equation context e1 in
|
||||
context, { e1 with e_desc = Evar(n) } in
|
||||
context, { e with e_desc = Efby(v, e1') }
|
||||
| Ereset_mem (_, _, _) -> context, e
|
||||
| Evar _ -> context, e
|
||||
| Econst(c) -> context, { e with e_desc = const e (Econst c) }
|
||||
| Econstvar x -> context, { e with e_desc = const e (Econstvar x) }
|
||||
| Efield(e', field) ->
|
||||
let context, e' = translate Exp context e' in
|
||||
context, { e with e_desc = Efield(e', field) }
|
||||
| Estruct(l) ->
|
||||
let context, l =
|
||||
List.fold_right
|
||||
(fun (field, e) (context, field_desc_list) ->
|
||||
let context, e = translate Exp context e in
|
||||
context, ((field, e) :: field_desc_list))
|
||||
l (context, []) in
|
||||
context, { e with e_desc = Estruct(l) }
|
||||
(*Array operators*)
|
||||
| Earray(e_list) ->
|
||||
let context, e_list = translate_list kind context e_list in
|
||||
context, { e with e_desc = Earray(e_list) }
|
||||
| Erepeat (n,e') ->
|
||||
let context, e' = translate VRef context e' in
|
||||
context, { e with e_desc = Erepeat(n, e') }
|
||||
| Eselect (idx,e') ->
|
||||
let context, e' = translate VRef context e' in
|
||||
context, { e with e_desc = Eselect(idx, e') }
|
||||
| Eselect_dyn (idx, bounds, e1, e2) ->
|
||||
let context, e1 = translate VRef context e1 in
|
||||
let context, idx = translate_list Exp context idx in
|
||||
let context, e2 = translate Exp context e2 in
|
||||
context, { e with e_desc = Eselect_dyn(idx, bounds, e1, e2) }
|
||||
| Eupdate (idx, e1, e2) ->
|
||||
let context, e1 = translate VRef context e1 in
|
||||
let context, e2 = translate Exp context e2 in
|
||||
context, { e with e_desc = Eupdate(idx, e1, e2) }
|
||||
| Eselect_slice (idx1, idx2, e') ->
|
||||
let context, e' = translate VRef context e' in
|
||||
context, { e with e_desc = Eselect_slice(idx1, idx2, e') }
|
||||
| Econcat (e1, e2) ->
|
||||
let context, e1 = translate VRef context e1 in
|
||||
let context, e2 = translate VRef context e2 in
|
||||
context, { e with e_desc = Econcat(e1, e2) }
|
||||
| Eiterator (it, f, params, n, e_list, reset) ->
|
||||
let context, e_list = translate_list function_args_kind context e_list in
|
||||
context, { e with e_desc = Eiterator(it, f, params, n, e_list, reset) }
|
||||
| Efield_update (f, e1, e2) ->
|
||||
let context, e1 = translate VRef context e1 in
|
||||
let context, e2 = translate Exp context e2 in
|
||||
context, { e with e_desc = Efield_update(f, e1, e2) }
|
||||
in add context kind e
|
||||
|
||||
and translate_list kind context e_list =
|
||||
match e_list with
|
||||
[] -> context, []
|
||||
| e :: e_list ->
|
||||
let context, e = translate kind context e in
|
||||
let context, e_list = translate_list kind context e_list in
|
||||
context, e :: e_list
|
||||
|
||||
let rec translate_eq context pat e =
|
||||
(* applies distribution rules *)
|
||||
(* [x = v fby e] should verifies that x is local *)
|
||||
(* [(p1,...,pn) = (e1,...,en)] into [p1 = e1;...;pn = en] *)
|
||||
let rec distribute ((d_list, eq_list) as context) pat e =
|
||||
match pat, e.e_desc with
|
||||
| Evarpat(x), Efby _ when not (vd_mem x d_list) ->
|
||||
let (d_list, eq_list), n = equation context e in
|
||||
d_list,
|
||||
{ p_lhs = pat; p_rhs = { e with e_desc = Evar(n) } } :: eq_list
|
||||
| Etuplepat(pat_list), Etuple(e_list) ->
|
||||
List.fold_left2 distribute context pat_list e_list
|
||||
| _ -> d_list, { p_lhs = pat; p_rhs = e } :: eq_list in
|
||||
|
||||
let context, e = translate Any context e in
|
||||
distribute context pat e
|
||||
|
||||
let translate_eq_list d_list eq_list =
|
||||
List.fold_left
|
||||
(fun context { p_lhs = pat; p_rhs = e } -> translate_eq context pat e)
|
||||
(d_list, []) eq_list
|
||||
|
||||
let translate_contract ({ c_eq = eq_list; c_local = d_list } as c) =
|
||||
let d_list,eq_list = translate_eq_list d_list eq_list in
|
||||
{ c with
|
||||
c_local = d_list;
|
||||
c_eq = eq_list }
|
||||
|
||||
let translate_node ({ n_contract = contract;
|
||||
n_local = d_list; n_equs = eq_list } as node) =
|
||||
let contract = optional translate_contract contract in
|
||||
let d_list, eq_list = translate_eq_list d_list eq_list in
|
||||
{ node with n_contract = contract; n_local = d_list; n_equs = eq_list }
|
||||
|
||||
let program ({ p_nodes = p_node_list } as p) =
|
||||
{ p with p_nodes = List.map translate_node p_node_list }
|
86
minils/transformations/schedule.ml
Normal file
86
minils/transformations/schedule.ml
Normal file
|
@ -0,0 +1,86 @@
|
|||
(**************************************************************************)
|
||||
(* *)
|
||||
(* Heptagon *)
|
||||
(* *)
|
||||
(* Author : Marc Pouzet *)
|
||||
(* Organization : Demons, LRI, University of Paris-Sud, Orsay *)
|
||||
(* *)
|
||||
(**************************************************************************)
|
||||
(* scheduling of equations *)
|
||||
|
||||
(* $Id$ *)
|
||||
|
||||
open Misc
|
||||
open Minils
|
||||
open Graph
|
||||
open Dep
|
||||
|
||||
(* possible overlapping between clocks *)
|
||||
let join ck1 ck2 =
|
||||
let n1 = Vars.head ck1
|
||||
and n2 = Vars.head ck2 in
|
||||
(* C1(x1) on ... on Cn(xn) with C'1(x'1) on ... on C'k(x'k) *)
|
||||
match n1, n2 with
|
||||
[], [] -> true
|
||||
| x1 ::_, x2 ::_ when x1 = x2 -> true
|
||||
| _ -> false
|
||||
|
||||
let join eq1 eq2 = join (Vars.clock eq1) (Vars.clock eq2)
|
||||
|
||||
(* possible overlapping between nodes *)
|
||||
(*let head e =
|
||||
match e with
|
||||
| Emerge(_, c_e_list) -> List.fold (fun acc e -> Vars.head (clock e) :: acc)
|
||||
| e -> [Vars.head (clock e)]
|
||||
|
||||
(* e1 define a pieces of control structures with *)
|
||||
(* paths on clock C1(x1) on ... on Cn(xn) ... *)
|
||||
(* e1 can be merged if *)
|
||||
let n1_list = head e1 in
|
||||
let n2_list = head e2 in
|
||||
*)
|
||||
|
||||
|
||||
(* clever scheduling *)
|
||||
let schedule eq_list =
|
||||
let rec recook = function
|
||||
| [] -> []
|
||||
| node :: node_list -> node >> (recook node_list)
|
||||
|
||||
and (>>) node node_list =
|
||||
try
|
||||
insert node node_list
|
||||
with
|
||||
Not_found -> node :: node_list
|
||||
|
||||
and insert node = function
|
||||
| [] -> raise Not_found
|
||||
| node1 :: node_list ->
|
||||
if linked node node1 then raise Not_found
|
||||
else
|
||||
try
|
||||
node1 :: (insert node node_list)
|
||||
with
|
||||
| Not_found ->
|
||||
if join (containt node) (containt node1)
|
||||
then node :: node1 :: node_list
|
||||
else raise Not_found in
|
||||
|
||||
let node_list, _ = DataFlowDep.build eq_list in
|
||||
let node_list = recook (topological node_list) in
|
||||
let node_list = List.rev node_list in
|
||||
let node_list = recook node_list in
|
||||
let node_list = List.rev node_list in
|
||||
List.map containt node_list
|
||||
|
||||
let schedule_contract ({ c_eq = eqs } as c) =
|
||||
let eqs = schedule eqs in
|
||||
{ c with c_eq = eqs }
|
||||
|
||||
let node ({ n_contract = contract; n_equs = eq_list } as node) =
|
||||
let contract = optional schedule_contract contract in
|
||||
let eq_list = schedule eq_list in
|
||||
{ node with n_equs = eq_list; n_contract = contract }
|
||||
|
||||
let program ({ p_nodes = p_node_list } as p) =
|
||||
{ p with p_nodes = List.map node p_node_list }
|
26
myocamlbuild.ml
Normal file
26
myocamlbuild.ml
Normal file
|
@ -0,0 +1,26 @@
|
|||
open Ocamlbuild_plugin
|
||||
open Ocamlbuild_plugin.Options
|
||||
|
||||
let sub_dirs = ["global"; "parsing"; "sigali"; "dataflow"; "sequential";
|
||||
"analysis"; "translation"; "main"; "simulation"]
|
||||
|
||||
let df = function
|
||||
| Before_options ->
|
||||
include_dirs := sub_dirs @ !include_dirs
|
||||
| After_rules ->
|
||||
(* Tell ocamlbuild about the camlp4 library. *)
|
||||
ocaml_lib ~extern:true ~dir:"+camlp4" "camlp4";
|
||||
|
||||
(* Add preproc.cmo to the ocaml pre-processor when use_preproc is set *)
|
||||
flag ["ocaml"; "pp"; "use_preproc"] (A "preproc.cmo");
|
||||
(* Running ocamldep on ocaml code that is tagged with use_preproc will
|
||||
require the cmo. Note that you only need this declaration when the
|
||||
syntax extension is part of the sources to be compiled with
|
||||
ocamlbuild. *)
|
||||
dep ["ocaml"; "ocamldep"; "use_preproc"] ["preproc.cmo"];
|
||||
|
||||
(* LablGTK use for graphical simulator *)
|
||||
ocaml_lib ~extern:true ~dir:"+lablgtk2" "lablgtk"
|
||||
| _ -> ()
|
||||
|
||||
let _ = dispatch df
|
80
utilities/dep.ml
Normal file
80
utilities/dep.ml
Normal file
|
@ -0,0 +1,80 @@
|
|||
(**************************************************************************)
|
||||
(* *)
|
||||
(* Heptagon *)
|
||||
(* *)
|
||||
(* Author : Marc Pouzet *)
|
||||
(* Organization : Demons, LRI, University of Paris-Sud, Orsay *)
|
||||
(* *)
|
||||
(**************************************************************************)
|
||||
(* dependences between equations *)
|
||||
(* $Id$ *)
|
||||
|
||||
open Graph
|
||||
open Ident
|
||||
|
||||
module type READ =
|
||||
sig
|
||||
type equation
|
||||
val read: equation -> ident list
|
||||
val def: ident list -> equation -> ident list
|
||||
val linear_read : equation -> ident list
|
||||
val antidep: equation -> bool
|
||||
val mem_reset : equation -> ident list
|
||||
end
|
||||
|
||||
module Make (Read:READ) =
|
||||
struct
|
||||
let build eqs =
|
||||
(* associate a graph node for each name declaration *)
|
||||
let rec nametograph g var_list is_antidep n_to_graph =
|
||||
let add_node env x =
|
||||
if Env.mem x env then
|
||||
let l = Env.find x env in
|
||||
Env.add x ((g, is_antidep)::l) env
|
||||
else
|
||||
Env.add x [(g, is_antidep)] env
|
||||
in
|
||||
List.fold_left add_node n_to_graph var_list in
|
||||
|
||||
let rec nametograph_env g var_list node_env =
|
||||
List.fold_left (fun env x -> Env.add x g env) node_env var_list in
|
||||
|
||||
let rec init_graph eqs g_list n_to_graph node_env =
|
||||
match eqs with
|
||||
| [] -> g_list, n_to_graph, node_env
|
||||
| eq :: eqs ->
|
||||
let g = make eq in
|
||||
let node_env = nametograph_env g (Read.def [] eq) node_env in
|
||||
let n_to_graph = nametograph g (Read.def [] eq) (Read.antidep eq) n_to_graph in
|
||||
let n_to_graph = nametograph g (Read.linear_read eq) true n_to_graph in
|
||||
let n_to_graph = nametograph g (Read.mem_reset eq) false n_to_graph in
|
||||
init_graph eqs (g :: g_list) n_to_graph node_env
|
||||
in
|
||||
|
||||
let rec make_graph g_list names_to_graph =
|
||||
let attach_one node (g, is_antidep) =
|
||||
if is_antidep then
|
||||
add_depends g node
|
||||
else
|
||||
add_depends node g
|
||||
in
|
||||
|
||||
let attach node n =
|
||||
try
|
||||
let l = Env.find n names_to_graph in
|
||||
List.iter (attach_one node) l
|
||||
with
|
||||
| Not_found -> () in
|
||||
|
||||
match g_list with
|
||||
| [] -> ()
|
||||
| node :: g_list ->
|
||||
let names = Read.read (containt node) in
|
||||
List.iter (attach node) names;
|
||||
make_graph g_list names_to_graph in
|
||||
|
||||
let g_list, names_to_graph, node_env = init_graph eqs [] Env.empty Env.empty in
|
||||
make_graph g_list names_to_graph;
|
||||
g_list, node_env
|
||||
end
|
||||
|
143
utilities/graph.ml
Normal file
143
utilities/graph.ml
Normal file
|
@ -0,0 +1,143 @@
|
|||
(**************************************************************************)
|
||||
(* *)
|
||||
(* Heptagon *)
|
||||
(* *)
|
||||
(* Author : Marc Pouzet *)
|
||||
(* Organization : Demons, LRI, University of Paris-Sud, Orsay *)
|
||||
(* *)
|
||||
(**************************************************************************)
|
||||
(* graph manipulation *)
|
||||
(* $Id$ *)
|
||||
type 'a graph =
|
||||
{ g_top: 'a node list;
|
||||
g_bot: 'a node list }
|
||||
|
||||
and 'a node =
|
||||
{ g_containt: 'a;
|
||||
g_tag: int;
|
||||
mutable g_visited: bool;
|
||||
mutable g_mark: int;
|
||||
mutable g_depends_on: 'a node list;
|
||||
mutable g_depends_by: 'a node list;
|
||||
}
|
||||
|
||||
exception Cycle of int (* returns the index of the node *)
|
||||
|
||||
let tag = ref 0
|
||||
let new_tag () = incr tag; !tag
|
||||
let containt g = g.g_containt
|
||||
let linked g1 g2 =
|
||||
(List.memq g2 g1.g_depends_on) or (List.memq g1 g2.g_depends_on)
|
||||
let make c =
|
||||
{ g_containt = c; g_tag = new_tag (); g_visited = false;
|
||||
g_mark = -1; g_depends_on = []; g_depends_by = [] }
|
||||
let add_depends node1 node2 =
|
||||
if not (node1.g_tag = node2.g_tag or linked node1 node2) then (
|
||||
node1.g_depends_on <- node2 :: node1.g_depends_on;
|
||||
node2.g_depends_by <- node1 :: node2.g_depends_by
|
||||
)
|
||||
|
||||
let remove_depends node1 node2 =
|
||||
if not (node1.g_tag = node2.g_tag) then (
|
||||
node1.g_depends_on <- List.filter (fun n -> n.g_tag <> node2.g_tag) node1.g_depends_on;
|
||||
node2.g_depends_by <- List.filter (fun n -> n.g_tag <> node1.g_tag) node2.g_depends_by
|
||||
)
|
||||
|
||||
let graph top_list bot_list = { g_top = top_list; g_bot = bot_list }
|
||||
|
||||
|
||||
let topological g_list =
|
||||
let rec sortrec g_list seq =
|
||||
match g_list with
|
||||
| [] -> seq
|
||||
| g :: g_list ->
|
||||
if g.g_visited then sortrec g_list seq
|
||||
else
|
||||
begin
|
||||
g.g_visited <- true;
|
||||
let seq = sortrec g.g_depends_on seq in
|
||||
sortrec g_list (g :: seq)
|
||||
end in
|
||||
let seq = sortrec g_list [] in
|
||||
List.iter
|
||||
(fun ({ g_visited = _ } as node) -> node.g_visited <- false) g_list;
|
||||
List.rev seq
|
||||
|
||||
(** Detection of cycles *)
|
||||
(* Mark nodes with:
|
||||
- -1 initially, for unvisited nodes
|
||||
- 0 for "opened" nodes, currently visited, while visiting its descendents
|
||||
- 1 for "closed" nodes, visited once, no circuits found from it.
|
||||
A circuit is found when a node marked with 0 is visited again.
|
||||
*)
|
||||
|
||||
let cycle g_list =
|
||||
(* store nodes in a stack *)
|
||||
let s = Stack.create () in
|
||||
(* flush the connected component *)
|
||||
let rec flush index =
|
||||
if Stack.is_empty s then []
|
||||
else let v = Stack.pop s in
|
||||
v.g_containt :: flush v.g_tag in
|
||||
|
||||
let rec visit g =
|
||||
match g.g_mark with
|
||||
| -1 ->
|
||||
(* Unvisited yet *)
|
||||
(* Open node *)
|
||||
Stack.push g s;
|
||||
g.g_mark <- 0;
|
||||
(* Visit descendents *)
|
||||
List.iter visit g.g_depends_on;
|
||||
(* Close node *)
|
||||
ignore (Stack.pop s);
|
||||
g.g_mark <- 1
|
||||
| 0 ->
|
||||
(* Visit an opened node (visited and not close) : circuit *)
|
||||
raise (Cycle g.g_tag)
|
||||
| 1 | _ ->
|
||||
(* Visit a closed node (no existing circuit) : pass *)
|
||||
() in
|
||||
try
|
||||
List.iter visit g_list; None
|
||||
with
|
||||
| Cycle(index) -> Some(flush index)
|
||||
|
||||
(** [accessible useful_nodes g_list] returns the list of
|
||||
accessible nodes starting from useful_nodes and belonging to
|
||||
g_list. *)
|
||||
let accessible useful_nodes g_list =
|
||||
let rec follow g =
|
||||
if not g.g_visited then
|
||||
begin
|
||||
g.g_visited <- true;
|
||||
List.iter follow g.g_depends_on
|
||||
end in
|
||||
let read acc g =
|
||||
if g.g_visited then begin g.g_visited <- false; g :: acc end else acc in
|
||||
List.iter follow useful_nodes;
|
||||
List.fold_left read [] g_list
|
||||
|
||||
(** [exists_path nodes n1 n2] returns whether there is a path
|
||||
from n1 to n2 in the graph. nodes is the list of all the nodes
|
||||
in the graph. *)
|
||||
let exists_path nodes n1 n2 =
|
||||
List.mem n2 (accessible [n1] nodes)
|
||||
|
||||
open Format
|
||||
|
||||
let print_node print g =
|
||||
printf "Node : @[<hov>";
|
||||
print_int g.g_tag;
|
||||
printf "@]";
|
||||
printf " Depends on :@\n";
|
||||
printf " @[<v>";
|
||||
List.iter
|
||||
(fun node ->
|
||||
printf "@[<hov 2>";
|
||||
print_int node.g_tag;
|
||||
printf "@]@ ")
|
||||
g.g_depends_on;
|
||||
printf "@]"
|
||||
|
||||
|
204
utilities/misc.ml
Normal file
204
utilities/misc.ml
Normal file
|
@ -0,0 +1,204 @@
|
|||
(**************************************************************************)
|
||||
(* *)
|
||||
(* Heptagon *)
|
||||
(* *)
|
||||
(* Author : Marc Pouzet *)
|
||||
(* Organization : Demons, LRI, University of Paris-Sud, Orsay *)
|
||||
(* *)
|
||||
(**************************************************************************)
|
||||
(* useful stuff *)
|
||||
(* $Id$ *)
|
||||
|
||||
(* version of the compiler *)
|
||||
let version = "0.4"
|
||||
let interface_format_version = "5"
|
||||
let date = "DATE"
|
||||
|
||||
(* standard module *)
|
||||
let pervasives_module = "Pervasives"
|
||||
let standard_lib = "STDLIB"
|
||||
let standard_lib = try Sys.getenv "HEPTLIB" with Not_found -> standard_lib
|
||||
|
||||
(* list of modules initially opened *)
|
||||
let default_used_modules = ref [pervasives_module]
|
||||
let set_no_pervasives () = default_used_modules := []
|
||||
|
||||
(* load paths *)
|
||||
let load_path = ref ([standard_lib])
|
||||
|
||||
let set_stdlib p =
|
||||
load_path := [p]
|
||||
and add_include d =
|
||||
load_path := d :: !load_path;;
|
||||
|
||||
(* where is the standard library *)
|
||||
let locate_stdlib () =
|
||||
let stdlib = try
|
||||
Sys.getenv "HEPTLIB"
|
||||
with
|
||||
Not_found -> standard_lib in
|
||||
Printf.printf "Standard library in %s\n" stdlib
|
||||
|
||||
let show_version () =
|
||||
Printf.printf "The Heptagon compiler, version %s (%s)\n"
|
||||
version date;
|
||||
locate_stdlib ()
|
||||
|
||||
(* other options of the compiler *)
|
||||
let verbose = ref false
|
||||
let print_types = ref false
|
||||
|
||||
let simulation = ref false
|
||||
let simulation_node : string option ref = ref None
|
||||
let set_simulation_node s =
|
||||
simulation := true;
|
||||
simulation_node := Some s
|
||||
|
||||
(* Target languages list for code generation *)
|
||||
let target_languages : string list ref = ref []
|
||||
|
||||
let add_target_language s =
|
||||
target_languages := s :: !target_languages
|
||||
|
||||
(* Optional path for generated files (C or Java) *)
|
||||
let target_path : string option ref = ref None
|
||||
|
||||
let set_target_path path =
|
||||
target_path := Some path
|
||||
|
||||
let full_type_info = ref false
|
||||
|
||||
let boolean = ref false
|
||||
|
||||
let deadcode = ref false
|
||||
|
||||
let init = ref true
|
||||
|
||||
let cse = ref false
|
||||
|
||||
let tomato = ref false
|
||||
|
||||
(* Backward compatibility *)
|
||||
let set_sigali () = add_target_language "z3z";;
|
||||
|
||||
let intermediate = ref false
|
||||
|
||||
let nodes_to_inline : string list ref = ref []
|
||||
|
||||
let nodes_to_display : string list ref = ref []
|
||||
|
||||
let node_to_flatten : string option ref = ref None
|
||||
|
||||
let no_mem_alloc = ref false
|
||||
|
||||
let use_interf_scheduler = ref false
|
||||
|
||||
let use_new_reset_encoding = ref false
|
||||
|
||||
let optional f = function
|
||||
| None -> None
|
||||
| Some x -> Some (f x)
|
||||
|
||||
let optunit f = function
|
||||
| None -> ()
|
||||
| Some x -> f x
|
||||
|
||||
(** [split_string s c] splits the string [s] in a list of sub-strings according
|
||||
to separator [c]. *)
|
||||
let rec split_string s c =
|
||||
try
|
||||
let id = String.index s c in
|
||||
let rest = String.sub s (id + 1) (String.length s - id - 1) in
|
||||
String.sub s 0 id :: split_string rest c
|
||||
with Not_found -> [s]
|
||||
|
||||
(* error during the whole process *)
|
||||
exception Error
|
||||
|
||||
(* creation of names. Ensure unicity for the whole compilation chain *)
|
||||
let symbol = ref 0
|
||||
|
||||
let gen_symbol () = incr symbol; "_"^(string_of_int !symbol)
|
||||
let reset_symbol () = symbol := (*!min_symbol*) 0
|
||||
|
||||
open Format
|
||||
open Unix
|
||||
|
||||
let print_header_info ff cbeg cend =
|
||||
let tm = Unix.localtime (Unix.time ()) in
|
||||
fprintf ff "%s --- Generated the %d/%d/%d at %d:%d --- %s@\n"
|
||||
cbeg tm.tm_mday (tm.tm_mon+1) (tm.tm_year + 1900) tm.tm_hour tm.tm_min cend;
|
||||
fprintf ff "%s --- heptagon compiler, version %s (compiled %s) --- %s@\n"
|
||||
cbeg version date cend;
|
||||
fprintf ff "%s --- Command line: %a--- %s@\n@\n"
|
||||
cbeg
|
||||
(fun ff a ->
|
||||
Array.iter (fun arg -> fprintf ff "%s " arg) a)
|
||||
Sys.argv
|
||||
cend
|
||||
|
||||
let unique l =
|
||||
let tbl = Hashtbl.create 10 in (* You could replace 10 with List.length l *)
|
||||
List.iter (fun i -> Hashtbl.replace tbl i ()) l;
|
||||
Hashtbl.fold (fun key data accu -> key :: accu) tbl []
|
||||
|
||||
type iterator_name =
|
||||
Imap
|
||||
| Ifold
|
||||
| Imapfold
|
||||
|
||||
let iterator_to_string i =
|
||||
match i with
|
||||
| Imap -> "map"
|
||||
| Ifold -> "fold"
|
||||
| Imapfold -> "mapfold"
|
||||
|
||||
let rec incomplete_map f l =
|
||||
match l with
|
||||
| [] -> []
|
||||
| [a] -> [a]
|
||||
| a::l -> (f a)::(incomplete_map f l)
|
||||
|
||||
let rec last_element l =
|
||||
match l with
|
||||
| [] -> assert false
|
||||
| [v] -> v
|
||||
| v::l -> last_element l
|
||||
|
||||
(** [split_last l] returns l without its last element and
|
||||
the last element of l. *)
|
||||
let rec split_last = function
|
||||
| [] -> assert false
|
||||
| [a] -> [], a
|
||||
| v::l ->
|
||||
let l, a = split_last l in
|
||||
v::l, a
|
||||
|
||||
let remove x l =
|
||||
List.filter (fun y -> x <> y) l
|
||||
|
||||
let is_empty = function
|
||||
| [] -> true
|
||||
| _ -> false
|
||||
|
||||
(** [repeat_list v n] returns a list with n times the value v. *)
|
||||
let repeat_list v n =
|
||||
let rec aux = function
|
||||
| 0 -> []
|
||||
| n -> v::(aux (n-1))
|
||||
in
|
||||
aux n
|
||||
|
||||
(** Same as List.mem_assoc but using the value instead of the key. *)
|
||||
let rec memd_assoc value = function
|
||||
| [] -> false
|
||||
| (k,d)::l -> (d = value) or (memd_assoc value l)
|
||||
|
||||
(** Same as List.assoc but searching for a data and returning the key. *)
|
||||
let rec assocd value = function
|
||||
| [] -> raise Not_found
|
||||
| (k,d)::l ->
|
||||
if d = value then
|
||||
k
|
||||
else
|
||||
assocd value l
|
158
utilities/misc.mli
Normal file
158
utilities/misc.mli
Normal file
|
@ -0,0 +1,158 @@
|
|||
(**************************************************************************)
|
||||
(* *)
|
||||
(* Heptagon *)
|
||||
(* *)
|
||||
(* Author : Marc Pouzet *)
|
||||
(* Organization : Demons, LRI, University of Paris-Sud, Orsay *)
|
||||
(* *)
|
||||
(**************************************************************************)
|
||||
|
||||
(* $Id$ *)
|
||||
|
||||
(* Version and date of compilation *)
|
||||
val version : string
|
||||
val interface_format_version: string
|
||||
val date : string
|
||||
|
||||
(* List of modules initially opened *)
|
||||
val default_used_modules : string list ref
|
||||
|
||||
(* Void the list of modules initially opened *)
|
||||
val set_no_pervasives : unit -> unit
|
||||
|
||||
(* Path list to libraries *)
|
||||
val load_path : string list ref
|
||||
|
||||
(* Set path to standard library *)
|
||||
val set_stdlib : string -> unit
|
||||
|
||||
(* Add path to libraries *)
|
||||
val add_include : string -> unit
|
||||
|
||||
(* Print the path to standard library *)
|
||||
val locate_stdlib : unit -> unit
|
||||
|
||||
(* Print the compiler version and its compilation date *)
|
||||
val show_version : unit -> unit
|
||||
|
||||
(* Verbose option *)
|
||||
val verbose : bool ref
|
||||
|
||||
(* Print types option *)
|
||||
val print_types : bool ref
|
||||
|
||||
(* Simulation mode *)
|
||||
val simulation : bool ref
|
||||
(* Simulated node *)
|
||||
val simulation_node : string option ref
|
||||
(* Set the simulation mode on *)
|
||||
val set_simulation_node : string -> unit
|
||||
|
||||
(* List of target languages *)
|
||||
val target_languages : string list ref
|
||||
(* Add target language to the list *)
|
||||
val add_target_language : string -> unit
|
||||
|
||||
(* Optional path for generated files (C or Java) *)
|
||||
val target_path : string option ref
|
||||
(* Set the optional target path *)
|
||||
val set_target_path : string -> unit
|
||||
|
||||
(* Print full type information when pretty-printing MiniLS code. *)
|
||||
val full_type_info : bool ref
|
||||
|
||||
(* Boolean transformation of enumerated types *)
|
||||
val boolean : bool ref
|
||||
|
||||
(* Deadcode removal *)
|
||||
val deadcode : bool ref
|
||||
|
||||
(* Initialization analysis (enabled by default) *)
|
||||
val init : bool ref
|
||||
|
||||
(* Common sub-expression elimination *)
|
||||
val cse : bool ref
|
||||
|
||||
(* Automata minimization *)
|
||||
val tomato : bool ref
|
||||
|
||||
(* Z/3Z back-end mode *)
|
||||
val set_sigali : unit -> unit
|
||||
|
||||
(* Intermediate-equations removal *)
|
||||
val intermediate : bool ref
|
||||
|
||||
(* Nodes to be inlined *)
|
||||
val nodes_to_inline : string list ref
|
||||
|
||||
(* Nodes which dependency graphics will be serialized to .dot file. *)
|
||||
val nodes_to_display : string list ref
|
||||
|
||||
(* Node to flatten *)
|
||||
val node_to_flatten : string option ref
|
||||
|
||||
(* Disable the memory allocation phase*)
|
||||
val no_mem_alloc : bool ref
|
||||
|
||||
(* Whether to use the interference aware scheduler*)
|
||||
val use_interf_scheduler : bool ref
|
||||
|
||||
(* Use the new encoding of resets using reset_mem. *)
|
||||
val use_new_reset_encoding : bool ref
|
||||
|
||||
(* Misc. functions *)
|
||||
val optional : ('a -> 'b) -> 'a option -> 'b option
|
||||
val optunit : ('a -> unit) -> 'a option -> unit
|
||||
val split_string : string -> char -> string list
|
||||
|
||||
(* Printing header informations (compiler version, generation date...) *)
|
||||
(* [print_header_info ff cbeg cend] prints header info, where [ff] is
|
||||
the formatter used, [cbeg] and [cend] the string of begin and end
|
||||
of commentaries in the target language *)
|
||||
val print_header_info : Format.formatter -> string -> string -> unit
|
||||
|
||||
(* Error during the whole process *)
|
||||
exception Error
|
||||
|
||||
(* Generation of unique names. Mandatory call of reset_symbol between
|
||||
set_min_symbol and gen_symbol *)
|
||||
(*val set_min_symbol : int -> unit*)
|
||||
val gen_symbol : unit -> string
|
||||
val reset_symbol : unit -> unit
|
||||
|
||||
type iterator_name =
|
||||
Imap
|
||||
| Ifold
|
||||
| Imapfold
|
||||
|
||||
val iterator_to_string : iterator_name -> string
|
||||
|
||||
(** [unique l] returns the [l] list without duplicates. O([length l]). *)
|
||||
val unique : 'a list -> 'a list
|
||||
|
||||
(** [incomplete_map f l] applies f to all the elements of
|
||||
l except the last element. *)
|
||||
val incomplete_map : ('a -> 'a) -> 'a list -> 'a list
|
||||
|
||||
(** [last_element l] returns the last element of the list l.*)
|
||||
val last_element : 'a list -> 'a
|
||||
|
||||
(** [split_last l] returns the list l without its last element
|
||||
and the last element of the list .*)
|
||||
val split_last : 'a list -> ('a list * 'a)
|
||||
|
||||
(** [remove x l] removes all occurrences of x from list l.*)
|
||||
val remove : 'a -> 'a list -> 'a list
|
||||
|
||||
(** [is_empty l] returns whether the list l is empty.*)
|
||||
val is_empty : 'a list -> bool
|
||||
|
||||
(** [repeat_list v n] returns a list with n times the value v. *)
|
||||
val repeat_list : 'a -> int -> 'a list
|
||||
|
||||
(** Same as List.mem_assoc but using the value instead of the key. *)
|
||||
val memd_assoc : 'b -> ('a * 'b) list -> bool
|
||||
|
||||
(** Same as List.assoc but searching for a data and returning the key. *)
|
||||
val assocd: 'b -> ('a * 'b) list -> 'a
|
||||
|
Loading…
Reference in a new issue