Commit a51ac5e0 authored by POTTIER Francois's avatar POTTIER Francois

Added [--interpret-error].

parent 59cbe66a
......@@ -65,32 +65,38 @@ let stream (toks : Terminal.t list) : unit -> Terminal.t * Lexing.position * Lex
(* --------------------------------------------------------------------------- *)
(* [interpret] interprets a sentence. *)
(* [start sentence] returns the start symbol that we should use to interpret
the sentence [sentence]. *)
(* If a start symbol was explicitly provided as part of the sentence, we use
it. Otherwise, we use the grammar's unique start symbol, if there is
one. *)
let start ((nto, _) : sentence) : Nonterminal.t =
match nto with
| Some nt ->
nt
| None ->
match ProductionMap.is_singleton Lr1.entry with
| None ->
Error.error []
"Because the grammar has multiple start symbols, each of the\n\
sentences provided on the standard input channel must be of the\n\
form: <start symbol>: <token>*"
| Some (prod, _) ->
match Production.classify prod with
| Some nt ->
nt
| None ->
assert false
let interpret ((nto, toks) : sentence) : unit =
(* --------------------------------------------------------------------------- *)
(* Check whether a start symbol was provided. If not, use the grammar's
unique start symbol, if there is one. *)
(* [interpret] interprets a sentence. *)
(* The code that finds the unique start symbol is not very pretty. *)
let interpret ((_, toks) as sentence) : unit =
let nt =
match nto, ProductionMap.is_singleton Lr1.entry with
| Some nt, _ ->
nt
| None, Some (prod, _) ->
begin match Production.classify prod with
| Some nt ->
nt
| None ->
assert false
end
| None, None ->
Error.error []
"Because the grammar has multiple start symbols, each of the\n\
sentences provided on the standard input channel must be of the\n\
form: <start symbol>: <token>*"
in
let nt = start sentence in
(* Run the reference interpreter. This can produce a concrete syntax tree
([Some cst]), fail with a parser error ([None]), or fail with a lexer error
......@@ -134,40 +140,84 @@ let interpret ((nto, toks) : sentence) : unit =
(* --------------------------------------------------------------------------- *)
(* If [--interpret] is set, interpret the sentences found on the standard
input channel, then stop, without generating a parser. *)
(* [interpret_error] interprets a sentence, expecting it to end in an error. *)
let succeed s =
Printf.printf
"OK %d\n# This sentence ends with a syntax error in state %d, as expected.\n%!"
s s;
exit 0
let fail msg =
Printf.printf "BAD\n# %s.\n%!" msg;
exit 1
let interpret_error ((_, toks) as sentence) =
let nt = start sentence in
let open ReferenceInterpreter in
match check_error_path nt toks with
| OInputReadPastEnd ->
fail "No syntax error occurred"
| OInputNotFullyConsumed ->
fail "A syntax error occurred before the last token was reached"
| OUnexpectedAccept ->
fail "No syntax error occurred; in fact, the input was accepted"
| OK state ->
succeed (Lr1.number state)
open Lexing
(* --------------------------------------------------------------------------- *)
let () =
if Settings.interpret then begin
(* [setup()] returns a function [read] which reads one sentence from the
standard input channel. *)
(* Read a series of sentences from the standard input channel. *)
let setup () : unit -> sentence option =
(* For more comfortable interaction, we interpret each sentence
as soon as it is read. *)
let open Lexing in
let lexbuf = from_channel stdin in
lexbuf.lex_curr_p <- { lexbuf.lex_curr_p with pos_fname = "(stdin)" };
let lexbuf =
from_channel stdin
in
lexbuf.lex_curr_p <- { lexbuf.lex_curr_p with pos_fname = "(stdin)" };
let read () =
try
SentenceParser.sentence SentenceLexer.lex lexbuf
with Parsing.Parse_error ->
Error.error (Positions.lexbuf lexbuf) "Ill-formed input sentence."
in
let read () =
try
SentenceParser.sentence SentenceLexer.lex lexbuf
with Parsing.Parse_error ->
Error.error (Positions.lexbuf lexbuf) "Ill-formed input sentence."
in
read
(* --------------------------------------------------------------------------- *)
(* If [--interpret] is set, interpret the sentences found on the standard
input channel, then stop, without generating a parser. *)
let rec loop () =
(* We read a series of sentences from the standard input channel. To allow
interactive use, we interpret each sentence as soon as it is read. *)
let () =
if Settings.interpret then
let read = setup() in
while true do
match read() with
| None ->
exit 0
exit 0
| Some sentence ->
interpret sentence;
loop()
in
loop()
interpret sentence
done
end
(* --------------------------------------------------------------------------- *)
(* If [--interpret-error] is set, interpret one sentence found on the standard
input channel, then stop, without generating a parser. *)
(* We read just one sentence, confirm that this sentence ends in an error, and
(if that is the case) display the number of the state that is reached. *)
let () =
if Settings.interpret_error then
let read = setup() in
match read() with
| None ->
exit 1 (* abnormal: no input *)
| Some sentence ->
interpret_error sentence (* never returns *)
......@@ -130,6 +130,9 @@ let interpret =
let interpret_show_cst =
ref false
let interpret_error =
ref false
let table =
ref false
......@@ -190,6 +193,7 @@ let options = Arg.align [
"--inspection", Arg.Set inspection, " Generate the inspection API (requires --table)";
"--interpret", Arg.Set interpret, " Interpret the sentences provided on stdin";
"--interpret-show-cst", Arg.Set interpret_show_cst, " Show a concrete syntax tree upon acceptance";
"--interpret-error", Arg.Set interpret_error, " Interpret one sentence that should end in an error";
"--lalr", Arg.Unit (fun () -> construction_mode := ModeLALR), " Construct an LALR(1) automaton";
"--list-errors", Arg.Set list_errors, " Produce a list of erroneous inputs";
"--log-automaton", Arg.Set_int logA, "<level> Log information about the automaton";
......@@ -377,6 +381,9 @@ let interpret =
let interpret_show_cst =
!interpret_show_cst
let interpret_error =
!interpret_error
let table =
!table
......
......@@ -128,6 +128,12 @@ val interpret : bool
val interpret_show_cst : bool
(* Whether Menhir should behave as an interpreter, in a special mode where
it checks one input sentence, expecting it to trigger an error at the
last token, and displays which state was reached. *)
val interpret_error : bool
(* Whether to use the table-based back-end ([true]) or the code-based
back-end ([false]). *)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment