在野牛中,添加就足够了
%verbose-error
到文件以使解析器错误更详细。有什么方法可以通过 ocamlyacc 获得类似的功能吗?
Here是类似问题的答案,但我无法从中得出任何结论。这就是我调用词法分析器和解析器函数的方式:
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 ();;
最佳答案
我不认为 ocamlyacc 中有一个选项可以自动执行您想要的操作,因此让我尝试在下面提供一个完整的描述,说明可以执行哪些操作来处理语法错误并提供更多有用的消息。也许这不是你问的。
错误实际上必须分为词法错误和解析错误,这取决于错误发生在解析过程的哪个阶段。
- 在
mll
文件中,如果出现意外模式,将引发Failure
异常 - 在
mly
文件中,会产生一个Parsing.Parse_error
异常
所以你有几个解决方案:
- 让词法分析器和解析器代码引发它们的异常,并在调用它们的代码中捕获它们
- 在其中任何一个中实现错误的具体情况
- 词法分析器的捕获所有规则(或必要时一些更具体的模式)
- 在解析器规则中使用
error
特殊终端来捕获特定位置的错误
在任何情况下,您都必须创建函数来获取有关源代码中错误位置的信息。
Lexing
和 Parsing
都使用 location
记录,在 Lexing
中定义,具有以下字段:
- pos_fname : 当前处理的文件名
- pos_lnum : 文件中的行号
- pos_bol : 行首从文件开头的字符数
- pos_cnum : 当前位置的字符数
词法分析器使用的 lexbuf
变量有两个类似的值来跟踪当前被词法分析的标记(lexeme_start_p
和 lexeme_curr_p
在 Lexing
让您访问这些数据)。并且解析器有四个跟踪当前要合成的符号(或非终端),以及当前规则项,可以通过Parsing
函数检索(rhs_start_pos
和 rhs_end_pos
,以及 symbol_start_pos
和 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 错误
/* ... */
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 }
剩下要做的就是修改您的顶级函数以捕获异常并处理它们。
最后,为了调试目的,Parsing
中提供了一个set_trace
函数,它可以显示解析引擎使用的状态机消息:它跟踪所有自动机的内部状态变化。
关于ocaml - ocamlyacc 的详细错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14046392/