如何在F#中解析时处理错误

时间:2011-03-09 10:47:07

标签: parsing f# error-handling fsyacc

我正在为我的F#Lexer和Parser使用fslex / fsyacc实用程序。如果输入文本的语法不正确,则必须知道它发生的位置。

可以在Lexer中确定不正确的lexeme(token),如果使用了错误的符号或单词,则抛出异常:

rule token = parse
          ...      
  | integer   { INT (Int32.Parse(lexeme lexbuf)) }
  | "*="      { failwith "Incorrect symbol" }
  | eof       { EOF }

这个问题更多地与Parser(fsyacc)有关 - 如果输入文本具有正确的令牌并且被Lexer成功标记,但在解析过程中发生错误(例如,错误的令牌顺序或规则中缺少令牌)

我知道如果捕获异常,这会给位置(行和列),解析失败的地方:

try
   Parser.start Lexer.token lexbuf
with e ->
   let pos = lexbuf.EndPos
   let line = pos.Line
   let column = pos.Column
   let message = e.Message  // "parse error"
    ... 

但是是否有可能(如果是 - 怎么做?)来确定解析失败的AST类

例如,我可以在parser.fsy文件中编写类似于以下的内容:

Expression1: 
   | INT         { Int $1 }
     ...
   | _           { failwith "Error with parsing in Expression1"}

1 个答案:

答案 0 :(得分:9)

只是跳过“_”会导致转移/减少冲突。对于一小组令牌,您可以列出所有令牌。对于更大的令牌集,它更成问题。

F#编译器通过定义早期规则的前缀来做类似的事情,并设置错误状态:

atomicPattern:
  ...
  | LPAREN parenPatternBody RPAREN 
      {  let m = (lhs(parseState)) in SynPat.Paren($2 m,m) } 
  | LPAREN parenPatternBody recover 
      { reportParseErrorAt (rhs parseState 1) (FSComp.SR.parsUnmatchedParen()); $2 (rhs2 parseState 1 2) }
  | LPAREN error RPAREN 
      { (* silent recovery *) SynPat.Wild (lhs(parseState)) }
  | LPAREN recover 
      {  reportParseErrorAt (rhs parseState 1) (FSComp.SR.parsUnmatchedParen()); SynPat.Wild (lhs(parseState))}  

recover: 
   | error { true }  
   | EOF { false }

您可以在the repository中看到整个文件。

有关ocamlyacc / fsyacc中错误处理的更多信息,请参阅OCaml manual(第III部分→Lexer和解析器生成器→错误处理)。