2011-03-09 52 views
9

我爲F#Lexer和Parser使用fslex/fsyacc實用程序。如果輸入文本的語法不正確,就必須知道它發生的地方。如何在F#中解析錯誤#

有可能確定在詞法不正確語義(令牌),並拋出一個異常,如果它使用了不正確的符號或文字:

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

問題是更多地涉及分析器(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"} 

回答

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和解析器生成器→錯誤處理)。

+0

謝謝你的回答 - 它給了很多。試圖在我的代碼中添加解決方案 – Vitaliy 2011-03-09 12:54:58

+0

這兩種解決方案(空白令牌和恢復示例的關鍵規則)都適用於我,因此再次感謝您。我正在接受答覆 – Vitaliy 2011-03-09 13:14:29