2

バイソンでは、追加するだけで十分です

%verbose-error 

ファイルに追加して、パーサー エラーをより詳細にします。ocamlyacc で同様の機能を得る方法はありますか?

これは同様の質問に対する答えですが、私はそれから何も作ることができませんでした. これは、レクサー関数とパーサー関数を呼び出す方法です。

let rec foo () =
    try
    let line = input_line stdin in
    (try
       let _ = (Parser.latexstatement lexer_token_safe (Lexing.from_string line)) in
         print_string ("SUCCESS\n")
     with
           LexerException s          -> print_string ("$L" ^ line ^ "\n")
         | Parsing.Parse_error       -> print_string ("$P" ^ line ^ "\n")
         | _                         -> print_string ("$S " ^ line ^ "\n"));
    flush stdout;
    foo ();
    with
    End_of_file -> ()
;;
foo ();;
4

2 に答える 2

11

ocamlyacc には、あなたが望むことを自動的に行うオプションがあるとは思わないので、構文エラーを処理し、より有用なメッセージを表示するために何ができるかについて、以下に詳しく説明します。多分それはあなたが尋ねたものではありません。

エラーは、エラーが発生した解析プロセスの段階に応じて、字句エラーと解析エラーに実際に分離する必要があります。

  • mllファイルでは、予期Failureしないパターンの場合に例外が発生します
  • mlyファイルでは、Parsing.Parse_error生成される例外です

したがって、いくつかの解決策があります。

  • レクサーとパーサーのコードで例外を発生させ、それらを呼び出すコードでそれらをキャッチします
  • それらのいずれかでエラーの特定のケースを実装します
    • レクサーのキャッチオールルール (または、必要に応じてより具体的なパターン)
    • パーサー ルールで特別なターミナルを使用してerror、特定の場所でエラーをキャッチする

いずれにせよ、ソース内のエラーの位置に関する情報を取得する関数を作成する必要があります。 どちらも、次のフィールドを持つで定義されたレコードをLexing使用します。ParsinglocationLexing

  • pos_fname : 現在処理されているファイルの名前
  • pos_lnum : ファイル内の行番号
  • pos_bol :ファイルの先頭から行頭までの文字数
  • pos_cnum : 現在位置の文字番号

lexer によって使用されるlexbuf変数には、lexed されている現在のトークンを追跡するための 2 つの値があります (lexeme_start_pこれらのデータにアクセスできるようlexeme_curr_pLexingします)。また、パーサーには、合成されようとしている現在のシンボル (または非終端記号) を追跡するための 4 つと、現在のルール項目があり、これらはParsing関数 ( rhs_start_posand とrhs_end_pos同様にsymbol_start_posand symbol_end_pos) で取得できます。

より詳細な例外を生成するためのいくつかの関数を次に示します。

exception LexErr of string
exception ParseErr of string

let error msg start finish  = 
    Printf.sprintf "(line %d: char %d..%d): %s" start.pos_lnum 
          (start.pos_cnum -start.pos_bol) (finish.pos_cnum - finish.pos_bol) msg

let lex_error lexbuf = 
    raise ( LexErr (error (lexeme lexbuf) (lexeme_start_p lexbuf) (lexeme_end_p lexbuf)))

let parse_error msg nterm =
    raise ( ParseErr (error msg (rhs_start_p nterm) (rhs_end_p nterm)))

およびいくつかの基本的な使用例:

パーサー: %token ERR

/* ... */

wsorword:
    WS                 { $1 }
  | WORD            { $1 }
  | error             { parse_error "wsorword" 1; ERR "" } /* a token needed for typecheck */
;

レクサー:

rule lexer = parse
(*  ... *)
(* catch all pattern *)
| _                      { lex_error lexbuf }

あとは、例外をキャッチして処理するようにトップ レベルの関数を変更するだけです。

最後に、デバッグの目的で、解析エンジンによって使用されるステート マシンの表示メッセージを有効にするset_trace機能が利用可能です。これは、オートマトンのすべての内部状態の変化をトレースします。Parsing

于 2012-12-27T02:41:21.763 に答える
-1

モジュール(ここでParsing確認できます)には、まさにそれを行う関数があります。次のように使用できます。また、-v 引数を指定して ocamlyacc を実行すると、.output が出力され、すべての状態と傾向が一覧表示されます。Parsing.set_traceParsing.set_trace True

于 2017-05-20T16:36:32.020 に答える