2 Main program for the moogle/kupo language
3 Copyright (C) 2002,2001 Justin David Smith, Caltech
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 (*** Generic program options ***)
26 let output_file = ref None
(* Name of .ml file (None = stdout) *)
27 let output_ifile = ref None
(* Name of .mli file (None = no interface) *)
28 let output_file_ro = ref false (* If true, make output file read-only *)
29 let print_insts = ref false (* Print instruction/transform tables? *)
30 let print_rules = ref false (* Print rewrite rules? *)
31 let print_inline = ref false (* Print inlined Kupo code? *)
34 (* As input files are read, the kupo program we are building
35 is stored here, in a single AST prog data structure. *)
36 let main_prog = ref Moogle_prog_ast.new_prog
43 Parses a program that is read from the indicated input channel.
44 The program data structure for this file only is returned. *)
47 let () = Moogle_ast_lex.reset_pos
() in
48 let lexbuf = Lexing.from_channel inx
in
49 let prog = Moogle_ast_parse.prog Moogle_ast_lex.main
lexbuf in
52 Parsing.Parse_error
->
53 raise
(ASTException
(exp_pos
(!Moogle_state.current_pos
), ParseError
))
55 raise
(ASTException
(exp_pos
(!Moogle_state.current_pos
), SysError s
))
59 Compile the kupo file named into an AST program structure.
60 After compilation, the AST structure will be concatenated to
61 the end of the main_prog structure, defined above. *)
63 Moogle_state.current_file
:= file
;
67 raise
(ASTException
(exp_pos
(!Moogle_state.current_pos
), SysError s
))
70 let prog = parse_prog inx in
71 let () = close_in
inx in
72 main_prog := Moogle_prog_ast.prog_of_expr
!main_prog file
prog
76 raise
(ASTException
(exp_pos
(!Moogle_state.current_pos
), SysError s
))
77 | ASTException
(pos
, msg
) as e
->
83 Similar to above function, but this version catches moogle
84 error exceptions and prints the exception out, then exits
85 with an abnormal return code. *)
90 ASTException
(pos
, msg
) ->
95 (*** File Permission/Access Code ***)
98 (* get_file_permissions
99 Get the current permissions on a named file. *)
100 let get_file_permissions file
=
101 let stats = Unix.stat file
in
106 Clear all write bits (user, group, and world) on a named file.
107 This call only has an effect if the output_file_ro flag is true. *)
108 let clear_write_bits file
=
109 if !output_file_ro then begin
110 let perm = get_file_permissions file
in
111 let perm = perm land (lnot
0o222
) in
117 Set the user write bit on a named file, so it can be modified.
118 This call only has an effect if the output_file_ro flag is true. *)
119 let set_write_bit file
=
120 if !output_file_ro then begin
122 let perm = get_file_permissions file
in
123 let perm = perm land 0o200
in
126 (* If the file doesn't exist here, it's not a big deal. *)
127 Unix.Unix_error
(Unix.ENOENT
, _
, _
) ->
132 (* close_nonstdout_channel
133 Closes the indicated output channel, *if* it is not stdout. *)
134 let close_nonstdout_channel out
=
135 if out
<> stdout
then
139 (*** Parse Options ***)
143 Print version information about moogleize. *)
144 let version_info () =
145 Printf.printf
"Moogleize for MCC (Mojave Compiler)\n";
146 Printf.printf
"Using Kupo Language Specification version %s\n" Moogle_state.kupo_language_specification
;
150 (* Define the program's options *)
151 let usage = "usage: moogleize [options] [files...]"
155 ["-o", Mc_arg.String
(fun s
-> output_file := Some s
),
156 "name of .ml file to write to (default: stdout)";
157 "-oi", Mc_arg.String
(fun s
-> output_ifile := Some s
),
158 "name of .mli file to write to (default: no interface)";
159 "-insts", Mc_arg.Set
print_insts,
160 "print instruction tables";
161 "-rules", Mc_arg.Set
print_rules,
162 "print pattern-match rules";
163 "-inline", Mc_arg.Set
print_inline,
164 "print inlined Kupo code blocks";
165 "-version", Mc_arg.Unit
version_info,
166 "print version information"];
167 "Advanced options (use with caution)",
168 ["-max-star", Mc_arg.Int
(fun i
-> Moogle_state.rule_max_star
:= i
),
169 "set maximum number of instructions a * wildcard can match in an input pattern" ^
170 " (default: " ^
(string_of_int
!Moogle_state.rule_max_star
) ^
")";
171 "-long-match", Mc_arg.Set
Moogle_state.rule_wildcard_long
,
172 "wildcards match the longest possible instruction sequence (may weaken peephole optimizations)" ^
173 (if !Moogle_state.rule_wildcard_long
then " (default)" else "");
174 "-short-match", Mc_arg.Clear
Moogle_state.rule_wildcard_long
,
175 "wildcards match the shortest possible instruction sequence (recommended)" ^
176 (if not
!Moogle_state.rule_wildcard_long
then " (default)" else "");
177 "-no-mangle", Mc_arg.Clear
Moogle_state.mangle_position_info
,
178 "if specified, do not mangle position information in emitted ML files.";
179 "-rdonly", Mc_arg.Set
output_file_ro,
180 "if specified, the output ML file is set as a read-only file, preventing" ^
181 " accidental modifications to the generated file. If this is set, then" ^
182 " moogleize will be allowed to delete read-only output files as well."]]
185 (*** Compile the Program ***)
189 Take the main_prog expression (generated by the front-end compile above)
190 and attempt to produce a real ML file as output. Output is either sent
191 to stdout, or to a named file. The write bits on the file may be cleared
192 if the -rdonly flag was specified. *)
194 (* Get the main_prog. *)
195 Mc_arg.parse
spec compile usage;
197 (* Make sure at least one interesting option was specified *)
199 if not
(!print_insts || !print_rules || !print_inline) then
200 raise
(ASTException
(exp_pos
(!Moogle_state.current_pos
),
201 StringError
"Neither -insts, -rules, nor -inline were specified on the command-line"))
204 (* Compile the prog into an ML program *)
205 let mlp, mlpi
= Moogle_mlp_prog.mlp_of_prog_header
!main_prog in
208 Moogle_mlp_prog.mlp_of_prog_insts
mlp mlpi
!main_prog
214 Moogle_mlp_prog.mlp_of_prog_rules
mlp mlpi
!main_prog
219 if !print_inline then
220 Moogle_mlp_prog.mlp_of_prog_inline_kupo
mlp mlpi
!main_prog
225 (* Create the output channel for the final ML file. *)
228 match !output_file with
236 raise
(ASTException
(exp_pos
(!Moogle_state.current_pos
), SysError s
))
237 | Unix.Unix_error
(err
, fn
, _
) ->
238 raise
(ASTException
(exp_pos
(!Moogle_state.current_pos
), SysError
(sprintf
"%s: %s" fn
(Unix.error_message err
))))
240 let outf = formatter_of_out_channel
out in
241 let () = pp_set_margin
outf 128 in
242 let pos () = exp_pos
(!Moogle_state.current_pos
) in
245 Moogle_mlp_print.pp_print_program
outf mlp;
246 pp_print_newline
outf ();
247 close_nonstdout_channel out;
248 match !output_file with
250 clear_write_bits file
255 pp_print_newline
outf ();
256 close_nonstdout_channel out;
257 raise
(ASTException
(pos (), SysError s
))
258 | Unix.Unix_error
(err
, fn
, _
) ->
259 close_nonstdout_channel out;
260 raise
(ASTException
(pos (), SysError
(sprintf
"%s: %s" fn
(Unix.error_message err
))))
261 | ASTException
(pos, msg
) as e
->
262 close_nonstdout_channel out;
266 (* Now, attempt to emit the MLI file *)
268 match !output_ifile with
271 let () = set_write_bit file
in
272 let out = open_out file
in
273 let outf = formatter_of_out_channel
out in
274 let () = pp_set_margin
outf 128 in
276 Moogle_mlp_print.pp_print_interface
outf mlpi
;
277 pp_print_newline
outf ();
279 clear_write_bits file
282 pp_print_newline
outf ();
284 raise
(ASTException
(pos (), SysError s
))
285 | Unix.Unix_error
(err
, fn
, _
) ->
287 raise
(ASTException
(pos (), SysError
(sprintf
"%s: %s" fn
(Unix.error_message err
))))
288 | ASTException
(pos, msg
) as e
->
300 ASTException
(pos, msg
) ->
303 | Moogle_prog_exn.ProgException
(pos, msg
) ->
304 Moogle_prog_exn.print_exn
pos msg
;