Vit*_*liy 9 error-handling f# parsing fsyacc
我正在为f#Lexer和Parser使用fslex/fsyacc实用程序.如果输入文本的语法不正确,则必须知道它发生的位置.
可以在Lexer中确定不正确的词位(标记),如果使用了错误的符号或单词则抛出异常:
rule token = parse
...
| integer { INT (Int32.Parse(lexeme lexbuf)) }
| "*=" { failwith "Incorrect symbol" }
| eof { EOF }
Run Code Online (Sandbox Code Playgroud)
这个问题更多地与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"
...
Run Code Online (Sandbox Code Playgroud)
但是有可能(如果是 - 如何做?)也确定AST类,解析失败.
例如,是否可以在我的parser.fsy文件中编写类似于以下内容的内容:
Expression1:
| INT { Int $1 }
...
| _ { failwith "Error with parsing in Expression1"}
Run Code Online (Sandbox Code Playgroud)
只是跳过"_"应该导致转移/减少冲突.对于一小组令牌,您可以列出所有令牌.对于更大的令牌集,它更成问题.
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 }
Run Code Online (Sandbox Code Playgroud)
您可以在存储库中查看整个文件.
有关ocamlyacc/fsyacc中错误处理的更多信息,请参见OCaml手册(第III部分→Lexer和解析器生成器→错误处理).