ocamlyacc には、あなたが望むことを自動的に行うオプションがあるとは思わないので、構文エラーを処理し、より有用なメッセージを表示するために何ができるかについて、以下に詳しく説明します。多分それはあなたが尋ねたものではありません。
エラーは、エラーが発生した解析プロセスの段階に応じて、字句エラーと解析エラーに実際に分離する必要があります。
mll
ファイルでは、予期Failure
しないパターンの場合に例外が発生します
mly
ファイルでは、Parsing.Parse_error
生成される例外です
したがって、いくつかの解決策があります。
- レクサーとパーサーのコードで例外を発生させ、それらを呼び出すコードでそれらをキャッチします
- それらのいずれかでエラーの特定のケースを実装します
- レクサーのキャッチオールルール (または、必要に応じてより具体的なパターン)
- パーサー ルールで特別なターミナルを使用して
error
、特定の場所でエラーをキャッチする
いずれにせよ、ソース内のエラーの位置に関する情報を取得する関数を作成する必要があります。
どちらも、次のフィールドを持つで定義されたレコードをLexing
使用します。Parsing
location
Lexing
- pos_fname : 現在処理されているファイルの名前
- pos_lnum : ファイル内の行番号
- pos_bol :ファイルの先頭から行頭までの文字数
- pos_cnum : 現在位置の文字番号
lexer によって使用されるlexbuf
変数には、lexed されている現在のトークンを追跡するための 2 つの値があります (lexeme_start_p
これらのデータにアクセスできるようlexeme_curr_p
にLexing
します)。また、パーサーには、合成されようとしている現在のシンボル (または非終端記号) を追跡するための 4 つと、現在のルール項目があり、これらはParsing
関数 ( rhs_start_pos
and とrhs_end_pos
同様にsymbol_start_pos
and 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