ocaml - ocamlyacc 的详细错误

标签 ocaml yacc

在野牛中,添加就足够了

%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 特殊终端来捕获特定位置的错误

在任何情况下,您都必须创建函数来获取有关源代码中错误位置的信息。 LexingParsing 都使用 location 记录,在 Lexing 中定义,具有以下字段:

  • pos_fname : 当前处理的文件名
  • pos_lnum : 文件中的行号
  • pos_bol : 行首从文件开头的字符数
  • pos_cnum : 当前位置的字符数

词法分析器使用的 lexbuf 变量有两个类似的值来跟踪当前被词法分析的标记(lexeme_start_plexeme_curr_pLexing 让您访问这些数据)。并且解析器有四个跟踪当前要合成的符号(或非终端),以及当前规则项,可以通过Parsing函数检索(rhs_start_posrhs_end_pos,以及 symbol_start_possymbol_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/

相关文章:

parsing - 将错误产生式添加到语法中的策略是什么?

c - Flex 中 '(' 标记之前的预期标识符或 '{'

php - 使用 LLVM API 将全局字符串存储在可变变量中

recursion - Ocaml 自引用

encoding - ocaml 将字符串 UTF8 转换为 CP1251

ocaml - 编译、GMP、Ocaml的错误信息

python-3.x - 使用解析器重新同步的 PLY.yacc 错误处理

c - 尝试通过更改语法来解决 Shift Reduce 冲突

string - 如何比较 Ocaml 中的字符串

c - GCC 和 Flex/Bison 没有效果警告的声明