diff --git a/vcalyx/ocaml/lexer.mll b/vcalyx/ocaml/lexer.mll index 4fe67b4fdc..8c7ac23a0d 100644 --- a/vcalyx/ocaml/lexer.mll +++ b/vcalyx/ocaml/lexer.mll @@ -1,13 +1,17 @@ { open Parser - exception ParseError of string + exception SyntaxError of string } let id = ['a'-'z' 'A'-'Z' '_'] ['a'-'z' 'A'-'Z' '0'-'9' '_' '.']* +let whitespace = [' ' '\t']+ +let newline = '\r' | '\n' | "\r\n" rule tokens = parse (* i.e., 1'd1 *) -| ['0'-'9']+"'d"['0'-'9']+ as i { INT (int_of_string i) } +| ['0'-'9']+ as i { INT (int_of_string i) } +| whitespace { tokens lexbuf } +| newline { Lexing.new_line lexbuf; tokens lexbuf } | "(" { LPAREN } | ")" { RPAREN } | "components" { COMPONENTS } @@ -41,4 +45,4 @@ rule tokens = parse | "assignments" { ASSIGNMENTS } | eof { EOF } | id as x { ID x } -| _ { raise (ParseError (Printf.sprintf "At offset %d: unexpected character.\n" (Lexing.lexeme_start lexbuf))) } \ No newline at end of file +| _ { raise (SyntaxError (Printf.sprintf "At offset %d: unexpected character %s" (Lexing.lexeme_start lexbuf) (Lexing.lexeme lexbuf))) } \ No newline at end of file diff --git a/vcalyx/ocaml/parser.mly b/vcalyx/ocaml/parser.mly index 1d2de03eed..7a4304f254 100644 --- a/vcalyx/ocaml/parser.mly +++ b/vcalyx/ocaml/parser.mly @@ -17,13 +17,13 @@ %token DIRECTION %token ASSIGNMENTS -%start main +%start main %% main: | LPAREN; LPAREN; COMPONENTS; LPAREN; comps = list(component); RPAREN; RPAREN; LPAREN; ENTRYPOINT; entry = ID; RPAREN; RPAREN; EOF - { {ctx_comps = comps; ctx_entrypoint = entry} } + { Some {ctx_comps = comps; ctx_entrypoint = entry} } attrs_clause: | LPAREN; ATTRIBUTES; LPAREN; attrs = list(attribute); RPAREN; RPAREN diff --git a/vcalyx/ocaml/vcx.ml b/vcalyx/ocaml/vcx.ml index b84128b4d5..fc83099e49 100644 --- a/vcalyx/ocaml/vcx.ml +++ b/vcalyx/ocaml/vcx.ml @@ -1,5 +1,28 @@ open Core open Vcalyx +open Lexing + +(* from https://dev.realworldocaml.org/parsing-with-ocamllex-and-menhir.html *) +let print_position outx lexbuf = + let pos = lexbuf.lex_curr_p in + fprintf outx "%s:%d:%d" pos.pos_fname pos.pos_lnum + (pos.pos_cnum - pos.pos_bol + 1) + +let parse_with_error lexbuf = + try Parser.main Lexer.tokens lexbuf with + (* | SyntaxError msg -> + fprintf stderr "%a: %s\n" print_position lexbuf msg; + None *) + | Parser.Error -> + fprintf stderr "%a: syntax error\n" print_position lexbuf; + exit (-1) + +let rec parse_and_print source_str source_location = + match parse_with_error source_str with + | Some _ -> + Printf.printf "Successfully parsed %s.\n" source_location; + parse_and_print source_str source_location + | None -> () let vcx_parse : Command.t = let open Command.Let_syntax in @@ -9,14 +32,13 @@ let vcx_parse : Command.t = fun () -> let source_chan = In_channel.create source_location in let source_str = Lexing.from_channel source_chan in - source_str.lex_curr_p <- { source_str.lex_curr_p with pos_fname = source_location }; - In_channel.close source_chan; - match Parser.main Lexer.tokens source_str with - | _ -> Printf.printf "Successfully parsed %s.\n" source_location] + source_str.lex_curr_p <- + { source_str.lex_curr_p with pos_fname = source_location }; + parse_and_print source_str source_location; + In_channel.close source_chan] let vcx_cmd : Command.t = Command.group ~summary:"vcx: the vcalyx command-line interface" [ ("parse", vcx_parse) ] -(* ("json-test", json_test) *) let () = Command_unix.run ~version:"dev" vcx_cmd