open MiniImp open Lexing (* -------------------------------------------------------------------------- *) (* Command Arguments *) let () = Clap.description "Interpreter for MiniImp language."; 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 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 let () = ( 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) ) in let return_value = return_value |> LiveVariables.compute_live_variables |> LiveVariables.optimize_cfg |> LiveVariables.compute_cfg |> ReduceRegisters.reduceregisters registers |> RISC.convert in if not evalb then Printf.fprintf outch "%a\n" RISC.RISCAssembly.pp return_value else Printf.fprintf outch "%d\n" (RISCSemantics.reduce return_value) 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;