2

在野牛中,添加就足够了

%verbose-error 

到文件以使解析器错误更加详细。有什么方法可以通过 ocamlyacc 获得类似的功能?

是类似问题的答案,但我无法从中得出任何结论。这就是我调用词法分析器和解析器函数的方式:

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 ();;
4

2 回答 2

11

我认为 ocamlyacc 中没有选项可以自动执行您想要的操作,因此让我尝试在下面提供一个完整的描述,说明可以采取哪些措施来处理语法错误并获得更多有用的消息。也许这不是你问的。

错误实际上必须在词法错误和解析错误中分开,这取决于错误发生在解析过程的哪个阶段。

  • mll文件Failure中,如果出现意外模式,将引发异常
  • mly文件中,这是一个Parsing.Parse_error将生成的异常

所以你有几个解决方案:

  • 让词法分析器和解析器代码引发它们的异常,并在调用它们的代码中捕获它们
  • 在其中任何一个中实施具体的错误案例
    • 词法分析器的全部规则(或一些更具体的模式,如有必要)
    • 使用error解析器规则中的特殊终端来捕获特定位置的错误

在任何情况下,您都必须创建函数来获取有关源中错误位置的信息。 Lexing并且Parsing两者都使用在location中定义的记录,Lexing其中包含以下字段:

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

词法分析器使用的lexbuf变量有两个类似的值来跟踪当前被词法分析的标记(并lexeme_start_p让您访问这些数据)。解析器有四个来跟踪即将被合成的当前符号(或非终结符),以及当前规则项,可以使用函数(and ,以及and )检索。lexeme_curr_pLexingParsingrhs_start_posrhs_end_possymbol_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 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启用解析引擎使用的状态机的显示消息:它跟踪自动机的所有内部状态变化。

于 2012-12-27T02:41:21.763 回答
-1

Parsing模块中(你可以在这里查看)有一个功能Parsing.set_trace可以做到这一点。您可以将其用作:Parsing.set_trace True启用。此外,您可以使用 -v 参数运行 ocamlyacc,它将输出一个 .output,列出所有状态和 trasitions。

于 2017-05-20T16:36:32.020 回答