4 let mgen ~verbose ~fuzz path lofs input oc
=
5 let info ?
(level
= 1) fmt
=
6 if level
<= verbose
then
9 Printf.ifprintf stdout fmt
13 match Sexp.(run_parser ppats
) input
with
14 | `Error
(ps
, err
, loc
) ->
15 Printf.eprintf
"%s:%d:%d %s\n"
16 path
(lofs
+ ps
.Sexp.line
) ps
.Sexp.coln err
;
17 Printf.eprintf
"%s" loc
;
22 info "adding ac variants...%!";
25 (fun npats
(_
, _
, ps
) ->
26 npats
+ List.length ps
)
29 let varsmap = Hashtbl.create
10 in
31 List.concat_map
(fun (name
, vars
, patterns
) ->
32 (try assert (Hashtbl.find
varsmap name
= vars
)
33 with Not_found
-> ());
34 Hashtbl.replace
varsmap name vars
;
36 (fun pattern
-> {name
; vars
; pattern
})
37 (List.concat_map ac_equiv patterns
)
40 info " %d -> %d patterns\n"
41 nparsed (List.length
rules);
44 setify
(List.map
(fun r
-> r
.name
) rules) in
46 info "generating match tables...%!";
47 let sa, am
, sm
= generate_table
rules in
48 let numbr = make_numberer
sa am sm
in
49 info " %d states, %d rules\n"
50 (Array.length
sa) (StateMap.cardinal sm
);
51 if verbose
>= 2 then begin
52 info "-------------\nstates:\n";
53 Array.iteri
(fun i s
->
54 info " state %d: %s\n"
55 i
(show_pattern s
.seen
)) sa;
56 info "-------------\nstatemap:\n";
57 Test.print_sm stderr sm
;
58 info "-------------\n";
61 info "generating matchers...\n";
63 List.map
(fun rname
->
64 info "+ %s...%!" rname
;
65 let m = lr_matcher sm
sa rules rname
in
66 let vars = Hashtbl.find
varsmap rname
in
67 info " %d nodes\n" (Action.size
m);
68 info ~level
:2 " -------------\n";
69 info ~level
:2 " automaton:\n";
71 (Format.asprintf
" @[%a@]" Action.pp
m);
72 info ~level
:2 " ----------\n";
78 info ~level
:0 "fuzzing statemap...\n";
79 let tp = Fuzz.fuzz_numberer
rules numbr in
80 info ~level
:0 "testing %d patterns...\n"
82 Fuzz.test_matchers
tp numbr rules
85 info "emitting C...\n";
89 { pfx
= ""; static
= true; oc
= oc
} in
91 emit_matchers
cgopts matchers;
97 let buf = Bytes.create
bufsz in
98 let data = Buffer.create
bufsz in
101 read := input ic
buf 0 bufsz;
104 Buffer.add_subbytes
data buf 0 !read
109 let begin_re, eoc_re
, end_re
=
110 let re = Str.regexp
in
111 ( re "mgen generated code"
113 , re "end of generated code" )
115 let str_match regexp str
=
118 Str.search_forward regexp str
0
120 with Not_found
-> false
123 let rec go st lofs pfx
rules lines
=
129 | `Prefix
-> "could not find mgen section"
130 | `Rules
-> "mgen rules not terminated"
131 | `Skip
-> "mgen section not terminated"
137 let pfx = line :: pfx in
138 if str_match begin_re line
140 let lofs = List.length
pfx in
141 go `Rules
lofs pfx rules lines
142 else go `Prefix
0 pfx rules lines
144 let pfx = line :: pfx in
145 if str_match eoc_re
line
146 then go `Skip
lofs pfx rules lines
147 else go `Rules
lofs pfx (line :: rules) lines
149 if str_match end_re
line then
150 let join = String.concat
"\n" in
151 let pfx = join (List.rev
pfx) ^
"\n\n"
152 and rules = join (List.rev
rules)
153 and sfx
= join (line :: lines
)
154 in (lofs, pfx, rules, sfx
)
155 else go `Skip
lofs pfx rules lines
158 let lines = String.split_on_char '
\n' src
in
159 go `Prefix
0 [] [] lines
163 "mgen [--fuzz] [--verbose <N>] <file>" in
165 let fuzz_arg = ref false in
166 let verbose_arg = ref 0 in
167 let input_paths = ref [] in
169 let anon_fun filename
=
170 input_paths := filename
:: !input_paths in
173 [ ( "--fuzz", Arg.Set
fuzz_arg
174 , " Fuzz tables and matchers" )
175 ; ( "--verbose", Arg.Set_int
verbose_arg
176 , "<N> Set verbosity level" )
177 ; ( "--", Arg.Rest_all
(List.iter
anon_fun)
178 , " Stop argument parsing" ) ]
180 Arg.parse
speclist anon_fun usage_msg;
182 let input_paths = !input_paths in
183 let verbose = !verbose_arg in
184 let fuzz = !fuzz_arg in
185 let input_path, input
=
186 match input_paths with
187 | ["-"] -> ("-", read_all stdin
)
188 | [path
] -> (path
, read_all (open_in path
))
191 "%s: single input file expected\n"
193 Arg.usage
speclist usage_msg; exit
1
195 let mgen = mgen ~
verbose ~
fuzz in
197 if Str.last_chars
input_path 2 <> ".c"
198 then mgen input_path 0 input stdout
200 let tmp_path = input_path ^
".tmp" in
203 try Sys.remove
tmp_path with _ -> ())
205 let lofs, pfx, rules, sfx
= split_c input
in
206 let oc = open_out
tmp_path in
207 output_string
oc pfx;
208 mgen input_path lofs rules oc;
209 output_string
oc sfx
;
211 Sys.rename
tmp_path input_path;