我有一個解析器,似乎足夠直接。我加入這個子解析器年底提供有關一般分析錯誤信息,因爲所有其他子解析器失敗 -如何解決FParsec錯誤「組合器'很多'被應用於成功解析器,而不消耗...」
/// Read the rest of a line as an error.
let readError =
parse {
let! restOfLineStr = restOfLine true
return makeViolation ("Read error on: " + restOfLineStr + ".") }
/// Read an expression.
do readExprRef :=
choice
[attempt readBoolean
attempt readCharacter
attempt readString
attempt readInt
attempt readError] // just now added this sub-parser, and get the issue
但是,一旦我添加readError作爲一個選擇,我得到流可怕FParsec錯誤在運行時消耗 - The combinator 'many' was applied to a parser that succeeds without consuming input and without changing the parser state in any other way.
我不明白爲什麼我得到這個,因爲我使用解析的行剩餘來創建一個使用的錯誤(這裏'違反')結構。
有人可以幫我理解嗎?我是否以錯誤的方式向用戶發送解析器錯誤?如果沒有,我該如何解決這個問題?
謝謝你的幫助!
*更多細節*
這裏的一些代碼,可能是相關的 -
/// The expression structure.
type Expr =
| Violation of Expr
| Boolean of bool
| Character of char
| String of string
| Int of int
/// Make a violation from a string.
let makeViolation str = Violation (String str)
/// Read whitespace character as a string.
let spaceAsStr = anyOf whitespaceChars |>> fun chr -> string chr
/// Read a line comment.
let lineComment = pchar lineCommentChar >>. restOfLine true
/// Read a multiline comment.
/// TODO: make multiline comments nest.
let multilineComment =
between
(pstring openMultilineCommentStr)
(pstring closeMultilineCommentStr)
(charsTillString closeMultilineCommentStr false System.Int32.MaxValue)
/// Read whitespace text.
let whitespace = lineComment <|> multilineComment <|> spaceAsStr
/// Skip any white space characters.
let skipWhitespace = skipMany whitespace
/// Skip at least one white space character.
let skipWhitespace1 = skipMany1 whitespace
/// Read a boolean.
let readBoolean =
parse {
do! skipWhitespace
let! booleanValue = readStr trueStr <|> readStr falseStr
return Boolean (booleanValue = trueStr) }
/// Read a character.
let readCharacter =
parse {
// TODO: enable reading of escaped chars
do! skipWhitespace
let! chr = between skipSingleQuote skipSingleQuote (manyChars (noneOf "\'"))
return Character chr.[0] }
/// Read a string.
let readString =
parse {
// TODO: enable reading of escaped chars
do! skipWhitespace
let! str = between skipDoubleQuote skipDoubleQuote (manyChars (noneOf "\""))
return String str }
/// Read an int.
let readInt =
parse {
do! skipWhitespace
let! value = pint32
let! _ = opt (skipString intSuffixStr)
do! notFollowedByLetterOrNameChar
do! notFollowedByDot
return Int value }
我不知道。可能問題在於,一旦它嘗試運行readError解析器,它就已經在流的末尾了。這將使restOfLine不消耗任何輸入,甚至沒有空白?
* *結論
事實證明,該方法錯誤與readError解析器報告是錯誤的。正確的做法是使用「直到結束」解析器像這樣 -
/// Read the end of input.
let readEndOfInput = skipWhitespace >>. eof
// Read multiple exprs.
let readExprs = many readExpr
// Read exprs until the end of the input.
let readExprsTillEnd = readExprs .>> readEndOfInput
現在我只是運行readExprsTillEnd當我需要得到所有的exprs輸入流。
再次感謝Gustavo!
你可以發佈更多的代碼?特別是makeViolation函數的主體。 – Gustavo 2011-12-17 09:17:30
完成。順便說一句,古斯塔沃,我是你博客的粉絲。我希望Don Syme正在研究你所做的工作 - 在沒有HK或TC的情況下獲得功能,應用程序和monad是巨大的!我想知道我們是否也能以某種形式從你那裏得到箭頭;) – 2011-12-17 14:38:35