diff --git a/Cimp.ml b/Cimp.ml index 503bc62cf4e4022858891ef599ffb680c51b736a..6271819f91890b1624415ef417bec16e293bf3ba 100644 --- a/Cimp.ml +++ b/Cimp.ml @@ -2,12 +2,7 @@ (* for the full license governing this code. *) (* local files *) -open Common -open Options -open Error -open Cmd -open Dump -open Env +open Common (* extracted code (/extract) *) module Compile = Compiler__Compile_com @@ -18,72 +13,70 @@ module State = State__State module Imp = Imp__Imp let () = - - cmd; (* parse command line options and put into opt *) - p_stderr (string_of_opt opt); - - let inBuff = - try Some (open_in opt.infile) - with _ -> None - in - + Cmd.cmd; (* parse command line options and put into opt *) + p_stderr (Options.string_of_opt Options.opt); try - match inBuff with - | None -> raise (CompilerError("File open error :" ^ opt.infile)) - | Some inBuffer -> - let lexbuf = Lexing.from_channel inBuffer in - lexbuf.lex_curr_p <- { lexbuf.lex_curr_p with pos_fname = opt.infile }; - try - let p = Parser.prog Lexer.lex lexbuf in - (* p_stdout ("Decl:" ^ nl ^ T_Dump.of_prog p); *) - - let com = T_Check.tc_prog inBuffer p in - - if opt.d_ast then - p_stderr ("Raw AST:" ^ nl ^ Dump.of_com com ^ nl); - if opt.d_past then - p_stderr ("Pretty AST:" ^ nl ^ Dump.pretty_of_com 0 com ^ nl); - - let code = Compile.compile_program com in - if opt.d_code then - p_stderr ("Raw Code : \n" ^ of_code false code ^ nl); - if opt.d_pcode then - p_stderr ("Pretty Code : \n" ^ of_code true code ^ nl); - - let st_0 = State.const (Z.of_int 0) in (* assume all variables 0 *) - - (* imp_ex execution *) - if opt.imp_ex then ( - try - p_stdout ("Execute : imp_ex" ); - let st_end = Imp_Ex.ceval_ex st_0 com in - p_stdout ("ceval_ex" ^ nl ^ Env.to_string st_end ^ nl); - with - | _ -> p_stdout "ceval : Exited with an error\n"; - ); - - (* vm_ex execution *) - if opt.vm_ex then ( - try - let _ = Vm_Ex.instr_iter_ex code (VMS (Z.of_int 0, [], st_0)) in - () - with - | Vm_Ex.Err -> p_stderr ("execution error") - | Vm_Ex.Halt (VMS (pos, stack, st_halt)) -> - p_stdout ("execution halted"); - p_stdout ("instr_iter_ex" ^ nl ^ Env.to_string st_halt ^ nl); - () - ); - - p_stdout ("Done!"); + let inBuffer = open_in Options.opt.infile in + let lexbuf = Lexing.from_channel inBuffer in + lexbuf.lex_curr_p <- { lexbuf.lex_curr_p with pos_fname = Options.opt.infile }; + try + let p = Parser.prog Lexer.lex lexbuf in + (* (* Comment out to get a Dump of the T_Imp with (some) span information *) + + p_stdout ("Decl:" ^ nl ^ T_Dump.of_prog p); + *) + + let com = T_Check.tc_prog inBuffer p in + + if Options.opt.d_ast then + p_stderr ("Raw AST:" ^ nl ^ Dump.of_com com ^ nl); + if Options.opt.d_past then + p_stderr ("Pretty AST:" ^ nl ^ Dump.pretty_of_com 0 com ^ nl); + + let code = Compile.compile_program com in + if Options.opt.d_code then + p_stderr ("Raw Code : \n" ^ Dump.of_code false code ^ nl); + if Options.opt.d_pcode then + p_stderr ("Pretty Code : \n" ^ Dump.of_code true code ^ nl); + + let st_0 = State.const (Z.of_int 0) in (* assume all variables 0 *) + + (* imp_ex execution *) + if Options.opt.imp_ex then ( + try + p_stdout ("Execute : imp_ex" ); + let st_end = Imp_Ex.ceval_ex st_0 com in + p_stdout ("ceval_ex" ^ nl ^ Env.to_string st_end ^ nl); + with + | _ -> p_stdout "ceval : Exited with an error\n"; + ); + + (* vm_ex execution *) + if Options.opt.vm_ex then ( + try + let _ = Vm_Ex.instr_iter_ex code (VMS (Z.of_int 0, [], st_0)) in + () + with + | Vm_Ex.Err -> p_stderr ("execution error") + | Vm_Ex.Halt (VMS (pos, stack, st_halt)) -> + p_stdout ("execution halted"); + p_stdout ("instr_iter_ex" ^ nl ^ Env.to_string st_halt ^ nl); + () + ); + + p_stdout ("Done!"); + + with + | Lexer.SyntaxError msg -> + raise (CompilerError ("Syntax error. " ^ msg ^ Error.parse_err_msg inBuffer lexbuf)); + | Parser.Error -> + raise (CompilerError ("Parser error." ^ Error.parse_err_msg inBuffer lexbuf)); - with - | Lexer.SyntaxError msg -> raise (CompilerError ("Syntax error. " ^ msg ^ parse_err_msg lexbuf)); - | Parser.Error -> - raise (CompilerError ("Parser error." ^ parse_err_msg lexbuf)); - (* raise (CompilerError ("Parser error.")); *) with | CompilerError msg -> p_stderr msg; + exit (-1); | Failure msg -> p_stderr ("Failure (internal error): " ^ msg); + exit (-1); + | Sys_error msg -> p_stderr("File open error :" ^ Options.opt.infile ^ msg); exit (-1);; diff --git a/Error.ml b/Error.ml index d48c0d55d476114bcaeebc81170c67325b4d2827..a5057c0f1ed43ea33f4301af070b1e56636a940d 100644 --- a/Error.ml +++ b/Error.ml @@ -20,14 +20,27 @@ let ci = { let next_line lexbuf = Lexing.new_line lexbuf -let parse_err_msg lexbuf = - let pos = lexbuf.lex_curr_p in - let index = pos.pos_cnum - pos.pos_bol -1 in - " File " ^ pos.pos_fname ^ - " : Line " ^ string_of_int pos.pos_lnum ^ - " : Position " ^ string_of_int index ^ nl ^ - submatch (Bytes.to_string lexbuf.lex_buffer) pos.pos_bol '\n' ^ nl ^ - (String.make index ' ' ) ^ "^" ^ nl +let parse_err_msg ch lexbuf = + try + let pos = lexbuf.lex_curr_p in + let index = pos.pos_cnum - pos.pos_bol -1 in + let info = + " File " ^ pos.pos_fname ^ + " : Line " ^ string_of_int pos.pos_lnum ^ + " : Position " ^ string_of_int index ^ nl in + let _ = seek_in ch pos.pos_bol in + let line = input_line ch in (* might raise End_of_file *) + info ^ line ^ nl ^ + (String.make index ' ' ) ^ "^" ^ nl + with + End_of_file -> + let pos = lexbuf.lex_curr_p in + let index = pos.pos_cnum - pos.pos_bol -1 in + + " File " ^ pos.pos_fname ^ + " : Line " ^ string_of_int pos.pos_lnum ^ + " : Position " ^ string_of_int index ^ nl ^ + " Error at EOF" ^ nl let set_info lexbuf = let pos = lexbuf.lex_curr_p in diff --git a/README.md b/README.md index 9a7415653e79b893ba3d9c1164da7092bf329111..149099a5d0c309ef9dfc9785b93555025a4cea68 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,31 @@ # Cimp, compiler harness for D7011E, Compiler Construction +This (new) version includes span information in the 'T_Imp.ml' AST, along with a simle type checker. + +## Todo: + +The examples are not updated, you need to add type information, e.g. + +``` +(* tc_1.imp passes type checking *) +a : SINT; (* types must be declared *) +b : UINT32; +a := a + 1; +b := b +u 1 +``` + +and +``` +(* tc_2.imp fails type checking *) +a : SINT; (* types must be declared *) +b : UINT32; +a := a + 1; +b := a +u 1 + +Type error: Expected UINT32 got SINT in:<105..106> a +in command: <100..111> b := a +u 1 +``` + ## Requirements: Dependencies: @@ -117,6 +143,9 @@ Files: ├── Lexer.mll Lexer rules ├── Options.ml Command line options (used by Cmd) ├── Parser.mly Parser rules +├── T_Check.ml Type checker +├── T_Dump.ml Printing of T_AST (the input language AST) +├── T_Imp.ml The input language AST ├── README.md This file ├── _build Build directory for OCaml ├── examples Some examples diff --git a/T_Check.ml b/T_Check.ml index 566f79541a1f6c9963ea278dc9faf4f344848f00..c3832e7f5e935854a218e6383c30c504115c0753 100644 --- a/T_Check.ml +++ b/T_Check.ml @@ -10,28 +10,34 @@ open State__State module Imp = Imp__Imp +(* converting a span to a string *) let of_span inb (start, stop) = let _ = seek_in inb start in let s = really_input_string inb (stop - start) in "<" ^ string_of_int start ^ ".." ^ string_of_int stop ^ "> " ^ s +(* report a duplicate definition *) let unique_id chan (id1, (t1, s1)) (id2, (t2, s2)) = if id1 = id2 then raise (CompilerError("Dupclicate variable definition: " ^ of_span chan s1 ^ " already declared at " ^ of_span chan s2)) else () +(* build a type environment in acc *) let rec idt_acc ch sp acc = function - | Dseq (d1, d2) -> (idt_acc_span ch (idt_acc_span ch acc d1) d2) - | Ddecl (id, t) -> List.iter (unique_id ch (id, (t, sp))) acc; + | Dseq (d1, d2) -> + idt_acc_span ch (idt_acc_span ch acc d1) d2 + | Ddecl (id, t) -> + (* check that the identifier is not yet declared *) + List.iter (unique_id ch (id, (t, sp))) acc; + (* add the identifier to acc *) (id, (t, sp)) :: acc - and idt_acc_span c acc (d, s) = idt_acc c s acc d let of_idt ch (id, (t,s)) = of_id id ^ ":" ^ of_types t ^ of_span ch s - +(* unify t2 to be compatible to the expected type t1 *) let tc_unify ch t1 t2 s2 : types = match t1, t2 with | Tsint, Tsint -> Tsint @@ -43,6 +49,7 @@ let tc_unify ch t1 t2 s2 : types = "Type error: Expected " ^ of_types t1 ^ " got " ^ of_types t2 ^ " in:" ^ of_span ch s2)) +(* unify types t1 and t2 *) let tc_unify2 ch t1 s1 t2 s2 : types = match t1, t2 with | Tsint, Tsint -> Tsint @@ -54,6 +61,7 @@ let tc_unify2 ch t1 s1 t2 s2 : types = "Type error: " ^ of_types t1 ^ " in:" ^ of_span ch s1 ^ " does not match " ^ of_types t2 ^ " in:" ^ of_span ch s2)) +(* lookup of identifier id in the type environment itl *) let get_id_type itl (id : id) : types * span = try List.assoc id itl diff --git a/imp_programs/tc_1.imp b/imp_programs/tc_1.imp new file mode 100644 index 0000000000000000000000000000000000000000..6240197afa74ad1220851ae1f29c04896e335f8d --- /dev/null +++ b/imp_programs/tc_1.imp @@ -0,0 +1,5 @@ +(* tc_1.imp passes type checking *) +a : SINT; (* types must be declared *) +b : UINT32; +a := a + 1; +b := b +u 1 \ No newline at end of file diff --git a/imp_programs/tc_2.imp b/imp_programs/tc_2.imp new file mode 100644 index 0000000000000000000000000000000000000000..0a9dcc7baf91613b3764e5d5c5e816321dbae789 --- /dev/null +++ b/imp_programs/tc_2.imp @@ -0,0 +1,5 @@ +(* tc_2.imp fails type checking *) +a : SINT; (* types must be declared *) +b : UINT32; +a := a + 1; +b := a +u 1 \ No newline at end of file