2025-01-11 20:32:11 +01:00
|
|
|
open MiniImp
|
|
|
|
|
open Lexing
|
|
|
|
|
|
|
|
|
|
(* -------------------------------------------------------------------------- *)
|
|
|
|
|
(* Command Arguments *)
|
|
|
|
|
|
|
|
|
|
let () =
|
2025-01-15 00:10:44 +01:00
|
|
|
Clap.description "Interpreter for MiniImp language to RISC code.";
|
2025-01-11 20:32:11 +01:00
|
|
|
|
|
|
|
|
let files = Clap.section ~description: "Files to consider." "FILES" in
|
|
|
|
|
let values = Clap.section ~description: "Input values." "VALUES" in
|
|
|
|
|
|
|
|
|
|
let input = Clap.mandatory_string
|
|
|
|
|
~description: "Input file."
|
|
|
|
|
~placeholder: "FILENAME"
|
|
|
|
|
~section: files
|
|
|
|
|
~long: "input"
|
|
|
|
|
~short: 'i'
|
|
|
|
|
()
|
|
|
|
|
in
|
|
|
|
|
|
|
|
|
|
let registers = Clap.default_int
|
|
|
|
|
~description: "Optional number of registers available."
|
|
|
|
|
~placeholder: "INT"
|
|
|
|
|
~section: values
|
|
|
|
|
~long: "registers"
|
|
|
|
|
~short: 'r'
|
|
|
|
|
4
|
|
|
|
|
in
|
|
|
|
|
|
|
|
|
|
let evalb = Clap.flag
|
|
|
|
|
~description: "Optional flag for evaluating the generated risc code."
|
|
|
|
|
~section: values
|
|
|
|
|
~set_long: "eval"
|
|
|
|
|
~set_short: 'e'
|
|
|
|
|
false
|
|
|
|
|
in
|
|
|
|
|
|
2025-01-15 00:10:44 +01:00
|
|
|
let checkundefined = Clap.flag
|
2025-01-26 21:47:05 +01:00
|
|
|
~description: "Optional flag for disabling the check for undefined \
|
|
|
|
|
variables."
|
2025-01-15 00:10:44 +01:00
|
|
|
~section: values
|
|
|
|
|
~unset_long: "undefined"
|
|
|
|
|
~unset_short: 'u'
|
|
|
|
|
true
|
|
|
|
|
in
|
|
|
|
|
|
|
|
|
|
let optimizereg = Clap.flag
|
2025-01-26 21:47:05 +01:00
|
|
|
~description: "Optional flag for disabling optimizing registers with \
|
|
|
|
|
liveness analysis."
|
2025-01-15 00:10:44 +01:00
|
|
|
~section: values
|
|
|
|
|
~unset_long: "liveness"
|
|
|
|
|
~unset_short: 'l'
|
|
|
|
|
true
|
|
|
|
|
in
|
|
|
|
|
|
2025-01-11 20:32:11 +01:00
|
|
|
let inputval = Clap.default_int
|
|
|
|
|
~description: "Optional input value to feed to the program. \
|
|
|
|
|
If not specified it is read from stdin."
|
|
|
|
|
~placeholder: "INT"
|
|
|
|
|
~section: values
|
|
|
|
|
~long: "value"
|
|
|
|
|
~short: 'v'
|
|
|
|
|
0
|
|
|
|
|
in
|
|
|
|
|
|
|
|
|
|
let output = Clap.optional_string
|
|
|
|
|
~description: "Output file. If not specified output is printed on stdout."
|
|
|
|
|
~placeholder: "FILENAME"
|
|
|
|
|
~section: files
|
|
|
|
|
~long: "output"
|
|
|
|
|
~long_synonyms: ["out"; "result"]
|
|
|
|
|
~short: 'o'
|
|
|
|
|
()
|
|
|
|
|
in
|
|
|
|
|
|
|
|
|
|
Clap.close ();
|
|
|
|
|
|
|
|
|
|
(* -------------------------------------------------------------------------- *)
|
|
|
|
|
(* Interpreter *)
|
|
|
|
|
|
|
|
|
|
let print_position outx lexbuf =
|
|
|
|
|
let pos = lexbuf.lex_curr_p in
|
|
|
|
|
Printf.fprintf outx "Encountered \"%s\" at %s:%d:%d"
|
|
|
|
|
(Lexing.lexeme lexbuf) pos.pos_fname
|
|
|
|
|
pos.pos_lnum (pos.pos_cnum - pos.pos_bol + 1)
|
|
|
|
|
in
|
|
|
|
|
|
|
|
|
|
let interpret_file inch (registers: int) outch =
|
|
|
|
|
let lexbuf = Lexing.from_channel inch in
|
|
|
|
|
let program =
|
|
|
|
|
try Parser.prg Lexer.read lexbuf with
|
|
|
|
|
| Lexer.LexingError msg ->
|
|
|
|
|
Printf.fprintf stderr "%a: %s\n" print_position lexbuf msg;
|
|
|
|
|
exit (-1)
|
|
|
|
|
| Parser.Error ->
|
|
|
|
|
Printf.fprintf stderr "%a: syntax error\n" print_position lexbuf;
|
|
|
|
|
exit (-1)
|
|
|
|
|
in
|
|
|
|
|
let return_value =
|
|
|
|
|
program |>
|
|
|
|
|
CfgImp.convert_io inputval |>
|
|
|
|
|
CfgRISC.convert
|
|
|
|
|
in
|
|
|
|
|
|
2025-01-15 00:10:44 +01:00
|
|
|
if checkundefined then (
|
2025-01-11 20:32:11 +01:00
|
|
|
match DefinedVariables.compute_defined_variables return_value |>
|
|
|
|
|
DefinedVariables.check_undefined_variables
|
|
|
|
|
with
|
|
|
|
|
| None -> ()
|
|
|
|
|
| Some l ->
|
|
|
|
|
Printf.printf "Error: undefined variables: %a\n"
|
|
|
|
|
DefinedVariables.Variable.pplist l;
|
|
|
|
|
exit (-1)
|
2025-01-15 00:10:44 +01:00
|
|
|
) else ();
|
|
|
|
|
|
|
|
|
|
let return_value =
|
|
|
|
|
if optimizereg then
|
|
|
|
|
return_value |>
|
|
|
|
|
LiveVariables.compute_live_variables |>
|
|
|
|
|
LiveVariables.optimize_cfg |>
|
|
|
|
|
LiveVariables.compute_cfg
|
|
|
|
|
else
|
|
|
|
|
return_value
|
|
|
|
|
in
|
2025-01-11 20:32:11 +01:00
|
|
|
|
|
|
|
|
let return_value =
|
|
|
|
|
return_value |>
|
|
|
|
|
ReduceRegisters.reduceregisters registers |>
|
|
|
|
|
RISC.convert
|
|
|
|
|
in
|
|
|
|
|
|
2025-01-26 21:47:05 +01:00
|
|
|
if evalb
|
|
|
|
|
then Printf.fprintf outch "%d\n" (RISCSemantics.reduce return_value)
|
|
|
|
|
else Printf.fprintf outch "%a\n" RISC.RISCAssembly.pp return_value
|
2025-01-11 20:32:11 +01:00
|
|
|
in
|
|
|
|
|
|
|
|
|
|
let inx = In_channel.open_text input in
|
|
|
|
|
let outx = match output with
|
|
|
|
|
None -> stdout
|
|
|
|
|
| Some f -> Out_channel.open_text f
|
|
|
|
|
in
|
|
|
|
|
|
|
|
|
|
interpret_file inx registers outx;
|
2025-01-17 00:46:51 +01:00
|
|
|
|
|
|
|
|
Out_channel.close outx
|