16

我正在使用 ocamlyacc 和 ocamllex。我的语法中有一个错误产生,表示自定义异常。到目前为止,我可以让它报告错误位置:

| error { raise (Parse_failure (string_of_position (symbol_start_pos ()))) }

但是,我也想知道读取了哪个令牌。一定有办法——有人知道吗?

谢谢。

4

3 回答 3

22

调试ocamlyacc解析器的最佳方法是设置OCAMLRUNPARAM参数以包含字符p- 这将使解析器打印它经历的所有状态,以及它执行的每个 shift/reduce。

如果您使用的是 bash,则可以使用以下命令执行此操作:

$ export OCAMLRUNPARAM='p'
于 2010-07-29T07:02:30.240 回答
16

标记由词法分析器生成,因此您可以在发生错误时使用当前的词法分析器标记:

  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应该在词法分析器中更新以包含正确的位置。(来源

于 2009-12-21T09:05:52.633 回答
2

我认为,与 yacc 类似,标记存储在与语法规则中的符号相对应的变量中。在这里,由于只有一个符号(错误),您可以使用 $1printf等简单地输出。

编辑:回复评论。

为什么要使用错误终端?我正在阅读 ocamlyacc 教程,该教程说发生解析错误时会调用特殊的错误处理例程。像这样:

3.1.5。错误报告程序

当解析器函数检测到语法错误时,它会调用一个以parse_error字符串“语法错误”作为参数命名的函数。默认parse_error函数不执行任何操作并返回,从而启动错误恢复(请参阅错误恢复)。用户可以在语法文件的 header 部分定义一个自定义的 parse_error 函数,例如:

let parse_error s = (* Called by the parser function on error *)
  print_endline s;
  flush stdout

好吧,看起来你只得到那个函数的“语法错误”。敬请期待更多的信息。

于 2009-12-19T15:42:39.830 回答