私は ocamlyacc と ocamllex を使用しています。カスタム例外を通知する文法のエラー生成があります。これまでのところ、エラーの位置を報告するように取得できます。
| error { raise (Parse_failure (string_of_position (symbol_start_pos ()))) }
しかし、どのトークンが読み取られたかも知りたいです。方法があるはずです---誰か知っていますか?
ありがとう。
ocamlyacc
パーサーをデバッグする最善の方法は、 OCAMLRUNPARAM
param に文字を含めるように設定p
することです。これにより、パーサーは通過するすべての状態を出力し、各シフト/リデュースが実行されます。
bash を使用している場合は、次のコマンドでこれを行うことができます。
$ export OCAMLRUNPARAM='p'
トークンはレクサーによって生成されるため、エラーが発生したときに現在のレクサー トークンを使用できます。
let parse_buf_exn lexbuf =
try
T.input T.rule lexbuf
with exn ->
begin
let curr = lexbuf.Lexing.lex_curr_p in
let line = curr.Lexing.pos_lnum in
let cnum = curr.Lexing.pos_cnum - curr.Lexing.pos_bol in
let tok = Lexing.lexeme lexbuf in
let tail = Sql_lexer.ruleTail "" lexbuf in
raise (Error (exn,(line,cnum,tok,tail)))
end
Lexing.lexeme lexbuf
必要なものです。他のパーツは必須ではありませんが便利です。
ruleTail
ユーザーがエラーの位置を簡単に特定できるように、残りのすべてのトークンを文字列に連結します。lexbuf.Lexing.lex_curr_p
正しい位置を含むようにレクサーで更新する必要があります。(ソース)
yacc と同様に、トークンは文法規則の記号に対応する変数に格納されると思います。printf
ここではシンボル(エラー)が 1 つあるので、 などを使用して $1 を単純に出力できる場合があります。
編集:コメントに応答します。
なぜエラー端末を使うのですか?解析エラーが発生したときに特別なエラー処理ルーチンが呼び出されるという ocamlyacc チュートリアルを読んでいます。そのようです:
3.1.5. エラー報告ルーチン
パーサー関数が構文エラーを検出する
parse_error
と、文字列 "syntax error" を引数として名前が付けられた関数を呼び出します。デフォルトparse_error
関数は何もせずに戻り、エラー回復を開始します (エラー回復を参照)。ユーザーは、次のように、文法ファイルのヘッダー セクションでカスタマイズされた parse_error 関数を定義できます。
let parse_error s = (* Called by the parser function on error *)
print_endline s;
flush stdout
ただし、その関数では「構文エラー」しか発生しないようです。詳細については、しばらくお待ちください。