From 9c89c64716fcc9993ab58236e5e8e830bb0277ff Mon Sep 17 00:00:00 2001 From: Bastien Rousseau Date: Fri, 11 Aug 2023 00:25:01 +0200 Subject: [PATCH] Unify the command line interface under one parser (interactive and interpreter) --- Makefile | 2 +- README.md | 10 +++---- lib/cli_parser.ml | 20 ++++++++++---- lib/interpreter_ui.ml | 16 +++++++++++ src/dune | 10 +++---- src/interactive.ml | 42 ----------------------------- src/interpreter.ml | 63 ++++++++++++++++++++++++------------------- 7 files changed, 78 insertions(+), 85 deletions(-) create mode 100644 lib/interpreter_ui.ml delete mode 100644 src/interactive.ml diff --git a/Makefile b/Makefile index 22b445c..4237058 100644 --- a/Makefile +++ b/Makefile @@ -11,4 +11,4 @@ test: dune test install: - @test -s interactive || ln -s ./_build/default/src/interactive.exe interactive + @test -s interpreter || ln -s ./_build/default/src/interpreter.exe interpreter diff --git a/README.md b/README.md index 272dade..bdb7fdb 100644 --- a/README.md +++ b/README.md @@ -13,15 +13,15 @@ eval $(opam env --set-switch) make ``` -Finally, the command `make install` creates a symbolic link to the interactive interpreter in this repository. +Finally, the command `make install` creates a symbolic link to the interpreter in this repository. ## Usage -Executable: `./interactive ` -Assembly examples in `./tests` (for the syntax) +Executable: `./interpreter ` +Assembly examples in `./tests/test_files` (for the syntax) The default version of the interpreter uses a version of Cerise with seals, uninitialized and directed capabilities. -For a version of Cerise without these features, use `./interactive --version vanilla`. +For a version of Cerise without these features, use `./interpreter --version vanilla`. -For more information about the options, `./interactive --help`. +For more information about the options, `./interpreter --help`. Press `SPACE` to take a step, and `ESC` to exit. diff --git a/lib/cli_parser.ml b/lib/cli_parser.ml index 7e90084..f177ebf 100644 --- a/lib/cli_parser.ml +++ b/lib/cli_parser.ml @@ -1,10 +1,16 @@ -(* TODO only one cli command, with a -I flag for --interactive*) (* TODO test of the CLI *) -(* TODO reuse the parser for the interpreter *) -let parse_argument_interactive addr_max = + +type cli_mode = Interactive_mode | Interpreter_mode + +(** Initialize the Cerise version and returns + (mode, program_filename, register_filename, size_mem) *) +let parse_arguments addr_max : + (cli_mode * string * string * Z.t) + = let usage_msg = - "interactive [--version version] [--locality locality] [--sealing | --no-sealing] [--stack | --no-stack] [--uperms | --no-uperms] [--mem-size size] " + "interpreter [-I] [--interactive] [--version version] [--locality locality] [--sealing | --no-sealing] [--stack | --no-stack] [--uperms | --no-uperms] [--mem-size size] " in + let interactive_option = ref false in let version_option = ref "default" in let stack_option = ref false in let no_stack_option = ref false in @@ -20,6 +26,8 @@ let parse_argument_interactive addr_max = let anon_fun filename = input_files := filename :: !input_files in let speclist = [ + ("--interactive", Arg.Set interactive_option, "Interactive mode of the interpreter"); + ("-I", Arg.Set interactive_option, "Interactive mode of the interpreter"); ("--version", Arg.Set_string version_option, "Version Cerise: default, vanilla, ucerise, mcerise, seal_cerise, custom"); ("--sealing", Arg.Set sealing_option, "Enable the seals"); ("--no-sealing", Arg.Set no_sealing_option, "Disable the seals"); @@ -33,6 +41,8 @@ let parse_argument_interactive addr_max = ] in Arg.parse speclist anon_fun usage_msg; + let mode = if !interactive_option then Interactive_mode else Interpreter_mode in + (* Construct the configuration *) let _ = match !version_option with @@ -95,4 +105,4 @@ let parse_argument_interactive addr_max = else s) in - (filename_prog, !regfile_name_option, size_mem) + (mode, filename_prog, !regfile_name_option, size_mem) diff --git a/lib/interpreter_ui.ml b/lib/interpreter_ui.ml new file mode 100644 index 0000000..cac2dfe --- /dev/null +++ b/lib/interpreter_ui.ml @@ -0,0 +1,16 @@ +let print_exec_state (m : Machine.mchn) = + print_endline @@ Pretty_printer.string_of_exec_state (fst m) + +let print_reg_state (m : Machine.mchn) = + let open Pretty_printer in + let rs = (snd m).reg in + print_endline "+-----------------------"; + Machine.RegMap.iter (fun r w -> + print_endline @@ string_of_reg_word r w) rs; + print_endline "+-----------------------" + +let interpreter (m_init : Machine.mchn) = + let m_final = Machine.run m_init in + print_reg_state m_final; + Printf.printf "Final execution state: %s\n" + (Pretty_printer.string_of_exec_state (fst m_final)) diff --git a/src/dune b/src/dune index 087729b..9cbcb86 100644 --- a/src/dune +++ b/src/dune @@ -1,13 +1,13 @@ (executable (name interpreter) (modules interpreter) - (libraries libinterp)) - -(executable - (name interactive) - (modules interactive) (libraries libinterp notty notty.unix containers)) +; (executable +; (name interactive) +; (modules interactive) +; (libraries libinterp notty notty.unix containers)) + (executable (name awkward_ucaps) (modules awkward_ucaps) diff --git a/src/interactive.ml b/src/interactive.ml deleted file mode 100644 index 9cfb156..0000000 --- a/src/interactive.ml +++ /dev/null @@ -1,42 +0,0 @@ -open Libinterp - -(* main loop *) -let () = - let addr_max = (Int32.to_int Int32.max_int)/4096 in - let (filename_prog, regfile_name, size_mem) = - Cli_parser.parse_argument_interactive addr_max - in - - let module Cfg = struct let addr_max : Z.t = size_mem end in - let module Ui = Interactive_ui.MkUi (Cfg) in - - let prog_panel_start = ref Z.zero in - let stk_panel_start = - ref Z.(if !Parameters.flags.stack then ((Cfg.addr_max)/ ~$2) else ~$0) - in - - let prog = - match Program.parse_prog filename_prog with - | Ok prog -> prog - | Error msg -> - Printf.eprintf "Program parse error: %s\n" msg; - exit 1 - in - - let regfile = - let init_regfile = (Machine.init_reg_state Cfg.addr_max) in - if regfile_name = "" - then init_regfile - else - (match Program.parse_regfile regfile_name Cfg.addr_max !stk_panel_start with - | Ok regs -> - (Machine.RegMap.fold - (fun r w rf -> Machine.RegMap.add r w rf) regs) init_regfile - | Error msg -> - Printf.eprintf "Regfile parse error: %s\n" msg; - exit 1) - in - - let m_init = Program.init_machine prog (Some Cfg.addr_max) regfile in - - Ui.render_loop ~show_stack:(!Parameters.flags.stack) prog_panel_start stk_panel_start m_init diff --git a/src/interpreter.ml b/src/interpreter.ml index 84bc960..cef4c6f 100644 --- a/src/interpreter.ml +++ b/src/interpreter.ml @@ -1,38 +1,47 @@ open Libinterp -let print_exec_state (m : Machine.mchn) = - print_endline @@ Pretty_printer.string_of_exec_state (fst m) - -let print_reg_state (m : Machine.mchn) = - let open Pretty_printer in - let rs = (snd m).reg in - print_endline "+-----------------------"; - Machine.RegMap.iter (fun r w -> - print_endline @@ string_of_reg_word r w) rs; - print_endline "+-----------------------" - let () = - (* very basic commandline argument parsing (to be improved) *) - let filename = - match Sys.argv |> Array.to_list |> List.tl with - | [filename] -> filename - | _ -> - Printf.eprintf "usage: %s \n" Sys.argv.(0); - exit 1 + let addr_max = (Int32.to_int Int32.max_int)/4096 in + let (mode, filename_prog, regfile_name, size_mem) = + Cli_parser.parse_arguments addr_max in + + (* Parse initial memory (program) *) let prog = - match Program.parse_prog filename with + match Program.parse_prog filename_prog with | Ok prog -> prog | Error msg -> - Printf.eprintf "Parse error: %s\n" msg; + Printf.eprintf "Program parse error: %s\n" msg; exit 1 in - let addr_max = Z.of_int ((Int32.to_int Int32.max_int)/4096) in - let init_regfile = Machine.init_reg_state addr_max in + let stk_addr = + Z.(if !Parameters.flags.stack then (size_mem/ ~$2) else ~$0) + in + + (* Parse initial register file *) + let regfile = + let init_regfile = (Machine.init_reg_state size_mem) in + if regfile_name = "" + then init_regfile + else + (match Program.parse_regfile regfile_name size_mem stk_addr with + | Ok regs -> + (Machine.RegMap.fold + (fun r w rf -> Machine.RegMap.add r w rf) regs) init_regfile + | Error msg -> + Printf.eprintf "Regfile parse error: %s\n" msg; + exit 1) + in + let m_init = Program.init_machine prog (Some size_mem) regfile in + + match mode with + | Cli_parser.Interactive_mode -> + let module Cfg = struct let addr_max : Z.t = size_mem end in + let module Ui = Interactive_ui.MkUi (Cfg) in + let prog_panel_start = ref Z.zero in + let stk_panel_start = ref stk_addr in + Ui.render_loop ~show_stack:(!Parameters.flags.stack) prog_panel_start stk_panel_start m_init - let m_init = Program.init_machine prog (Some addr_max) init_regfile in - let m_final = Machine.run m_init in - print_reg_state m_final; - Printf.printf "Final execution state: %s\n" - (Pretty_printer.string_of_exec_state (fst m_final)) + | Cli_parser.Interpreter_mode -> + Interpreter_ui.interpreter m_init