ocamlyacc的详细错误 [英] verbose error with ocamlyacc

查看:67
本文介绍了ocamlyacc的详细错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在野牛中,添加就足够了

In bison, it is sufficient to add

%verbose-error 

添加到文件中,以使解析器错误更加冗长.是否可以通过ocamlyacc获得类似功能?

to the file to make the parser errors more verbose. Is there any way to gain similar functionality with ocamlyacc?

此处是类似问题的答案,但我无法从中做出任何贡献.这就是我调用词法分析器和解析器函数的方式:

Here is the answer for a similar question, but I could not make anything out of it. This is how I call the lexer and parser functions:

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中没有一个选项可以自动执行您想要的操作,因此让我尝试在下面提供对可以完成操作的完整描述处理语法错误并获得更多有用的消息.也许这不是您要的.

I don't think that there's an option in ocamlyacc to do what you want automatically, so let me try to provide below a through description of what could be done to handle syntactic errors and have more useful messages. Maybe it is not what you asked.

根据错误发生在解析过程的哪个阶段,实际上必须将错误分为词法错误和解析错误.

Errors must actually be separated in lexical and parse errors, depending on which stage of the parsing process the error happens in.

  • mll文件中,如果出现意外模式,将引发Failure异常
  • mly文件中,这是将生成的Parsing.Parse_error异常
  • In mll files, a Failure exception will be raised in case of unexpected patterns
  • in mly files, it's a Parsing.Parse_error exception which will be generated

因此,您有几种解决方案:

So you have several solutions:

  • 让词法分析器和解析器代码引发它们的异常,并在调用它们的代码中捕获它们
  • 在其中任何一个中执行错误的特定情况
    • 捕获词法分析器的所有规则(或如有必要,提供一些更具体的模式)
    • 使用解析器规则中的error特殊终端在特定位置捕获错误
    • let the lexer and parser code raise their exceptions, and catch them in the code calling them
    • implement the specific cases of errors in the either of them with
      • a catch all rule for the lexer (or some more specific patterns if necessary)
      • using the error special terminal in the parser rules to catch errors in specific places

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

      In any case, you will have to make functions to get information about the position of the error in the source. Lexing and Parsing both use a location record, defined in Lexing, with the following fields:

      • pos_fname:当前正在处理的文件的名称
      • pos_lnum:文件中的行号
      • pos_bol:文件开头的字符编号 在行的开头
      • pos_cnum:当前位置的字符号
      • pos_fname : the name of the file currently processed
      • pos_lnum : the line number in the file
      • pos_bol : the character number from the start of the file at the beginning of the line
      • pos_cnum : the character number at the current position

      词法分析器使用的lexbuf变量具有两个值,类似于用于跟踪当前词法化的令牌(Lexing中的lexeme_start_plexeme_curr_p允许您访问这些数据).解析器有四个用于跟踪将要合成的当前符号(或非终结符)以及当前规则项,可以使用Parsing函数(rhs_start_posrhs_end_pos以及symbol_end_pos).

      The lexbuf variable used by the lexer has two values like that to track the current token being lexed (lexeme_start_p and lexeme_curr_p in Lexing let you access these data). And the parser has four to track the current symbol (or non-terminal) about to be synthetized, and the current rule items, which can be retrieved with Parsing functions (rhs_start_pos and rhs_end_pos, as well as symbol_start_pos and symbol_end_pos).

      这里有一些函数可以生成更详细的异常:

      Here's a few functions to generate more detailed exceptions:

      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

      parser: %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 }
      

      剩下要做的就是修改顶级函数以捕获异常并对其进行处理.

      All that would be left to do is to modify your top level function to catch the exceptions and process them.

      最后,出于调试目的,Parsing中提供了一个set_trace函数,该函数启用了解析引擎使用的状态机的显示消息:它跟踪自动机的所有内部状态变化.

      Finally, for debugging purposes, there is a set_trace function available in Parsing which enable the display messages of the state machine used by the parsing engine: it traces all the internal state changes of the automaton.

      这篇关于ocamlyacc的详细错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆