Skip to content
Snippets Groups Projects
grammar_parser.ml 2.69 KiB
Newer Older
open Str
open List_utils
open Lexing
open Grammar_lexer
open Grammar_parser_yacc
open Grammar

let print_position outx lexbuf =
  let pos = lexbuf.lex_curr_p in
  Printf.fprintf outx "%s:%d:%d" pos.pos_fname
    pos.pos_lnum (pos.pos_cnum - pos.pos_bol + 1)

let parse_with_error lexbuf =
  try main token lexbuf with
  | Error ->
    Printf.fprintf stderr "%a: syntax error\n" print_position lexbuf;
    exit (-1)

let parse_grammar file : grammar * nonterm =
  let ic = open_in file in
  let lexbuf = Lexing.from_channel ic in
  lexbuf.Lexing.lex_curr_p <- {lexbuf.Lexing.lex_curr_p with pos_fname = file};
  let gram : grammar = parse_with_error lexbuf in
  let (undefined_strings, used_strings) : string list * string list =
    List.fold_left (fun (undef, used) rule ->
        List.fold_left
          (fun (undef, used) prod ->
             let undef =
               if not (List.mem prod (List.map fst gram.tokens) || List.mem prod gram.nonterms || List.mem prod undef)
               then prod::undef
               else undef in
             let used =
               if List.mem prod used then used else prod::used in
             (undef, used)
          )
          (undef, used) (rule.rule_prods)
      ) ([],[]) (gram.rules) in

  (* Error if undefined tokens or non-terminals are encountered *)
  if undefined_strings <> []
  then (Printf.printf "Undefined tokens or non-terminals: %a\n" print_list undefined_strings;
       failwith "Undefined tokens or non-terminals");

  match gram.axiom with
  | None -> failwith "No axiom was defined for the grammar.\n Aborting."
  | Some axiom ->

    (* Warn if some non terminals are never seen on the right hand side of a rule. *)
    let unused_nts = List.filter (fun nt -> not (List.mem nt used_strings) && Some nt <> gram.axiom) gram.nonterms in
    if unused_nts <> [] then Printf.printf "The following non-terminals are declared but never appear on the right hand-side of a rule:\n%a\n" print_list unused_nts;

    (* Warn if some tokens are never seen on the right hand side of a rule. *)
    let unused_toks = (List.filter_map (fun (t,_) -> if not (List.mem t used_strings) then Some t else None) gram.tokens) in
    if unused_toks <> [] then Printf.printf "The following tokens are declared but never appear on the right hand-side of a rule:\n%a\n" print_list unused_toks;

    let h : (nonterm , rule list) Hashtbl.t =
      Hashtbl.create (List.length gram.nonterms) in
    List.iter ( fun r ->
        match Hashtbl.find_opt h r.rule_nt with
        | None -> Hashtbl.add h r.rule_nt [r]
        | Some lp -> Hashtbl.replace h r.rule_nt (lp@[r]) ) (gram.rules);
    let rules = List.concat (List.map (fun n -> hashget_def h n []) gram.nonterms) in
    { gram with rules = rules }, axiom