front.ml 4.41 KB
Newer Older
1
(* The front-end. This module performs a series of toplevel side effects. *)
2

3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
(* ------------------------------------------------------------------------- *)

(* Reading a grammar from a file. *)

let load_partial_grammar filename =
  let validExt = if Settings.coq then ".vy" else ".mly" in
  if not (Filename.check_suffix filename validExt) then
    Error.error [] (Printf.sprintf
      "argument file names should end in %s. \"%s\" is not accepted."
      validExt filename);
  Error.set_filename filename;
  try

    let contents = IO.read_whole_file filename in
    Error.file_contents := Some contents;
    let lexbuf = Lexing.from_string contents in
    lexbuf.Lexing.lex_curr_p <-
	{ 
	  Lexing.pos_fname = filename; 
	  Lexing.pos_lnum  = 1;
	  Lexing.pos_bol   = 0; 
	  Lexing.pos_cnum  = 0
	};
    let grammar =
      { (Parser.grammar Lexer.main lexbuf) with ConcreteSyntax.pg_filename = filename }
    in
    Error.file_contents := None;
    grammar

  with Sys_error msg ->
    Error.error [] msg

(* ------------------------------------------------------------------------- *)

(* Read all of the grammar files that are named on the command line. *)

let partial_grammars = 
  List.map load_partial_grammar Settings.filenames

let () =
  Time.tick "Lexing and parsing"

(* ------------------------------------------------------------------------- *)

(* If several grammar files were specified, merge them. *)

let parameterized_grammar = 
  PartialGrammar.join_partial_grammars partial_grammars

(* ------------------------------------------------------------------------- *)

(* Expand away all applications of parameterized nonterminal symbols, so as to
   obtain a grammar without parameterized nonterminal symbols. *)

let grammar = 
  ParameterizedGrammar.expand parameterized_grammar

let () =
  Time.tick "Joining and expanding"

(* ------------------------------------------------------------------------- *)
64

65 66 67 68
(* If [--only-tokens] was specified on the command line, produce
   the definition of the [token] type and stop. *)

let () =
69
  TokenType.produce_tokentypes grammar
70

71 72
(* ------------------------------------------------------------------------- *)

73 74 75 76 77 78 79 80
(* Perform reachability analysis. *)

let grammar =
  Reachability.trim grammar

let () =
  Time.tick "Trimming"

81 82
(* ------------------------------------------------------------------------- *)

83 84
(* If [--depend] or [--raw-depend] was specified on the command line,
   perform dependency analysis and stop. *)
85 86 87 88 89 90 91 92 93

let () =
  match Settings.depend with
  | Settings.OMRaw
  | Settings.OMPostprocess ->
      Infer.depend grammar (* never returns *)
  | Settings.OMNone ->
      ()

94 95 96 97 98 99
(* The purpose of [--depend] and [--raw-depend] is to support [--infer].
   Indeed, [--infer] is implemented by producing a mock [.ml] file (which
   contains just the semantic actions) and invoking [ocamlc]. This requires
   certain [.cmi] files to exist. So, [--depend] is a way for us to announce
   which [.cmi] files we need. It is implemented by producing the mock [.ml]
   file and running [ocamldep] on it. *)
100

101 102
(* ------------------------------------------------------------------------- *)

POTTIER Francois's avatar
POTTIER Francois committed
103 104
(* If [--infer] was specified on the command line, perform type inference.
   The OCaml type of every nonterminal is then known. *)
105 106 107 108 109 110 111 112 113

let grammar =
  if Settings.infer then
    let grammar = Infer.infer grammar in
    Time.tick "Inferring types for nonterminals";
    grammar
  else
    grammar

114 115
(* ------------------------------------------------------------------------- *)

116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
(* If [--no-inline] was specified on the command line, skip the
   inlining of non terminal definitions marked with %inline. *)

let grammar =
  if Settings.inline then begin
    let grammar, inlined = 
      NonTerminalDefinitionInlining.inline grammar
    in
    if not Settings.infer && inlined && not Settings.coq then
      Error.warning []
	"you are using the standard library and/or the %inline keyword. We\n\
	 recommend switching on --infer in order to avoid obscure type error messages.";
    Time.tick "Inlining";
    grammar
  end
  else 
    grammar

134 135
(* ------------------------------------------------------------------------- *)

136 137 138 139 140 141 142 143 144 145 146
(* If [--only-preprocess] or [--only-preprocess-drop] was specified on the
   command line, print the grammar and stop. Otherwise, continue. *)

let () =
  match Settings.preprocess_mode with
  | Settings.PMOnlyPreprocess mode ->
      UnparameterizedPrinter.print mode stdout grammar;
      exit 0
  | Settings.PMNormal ->
      ()