我有一个看起来很简单的解析器。我将此子解析器添加到末尾以提供有关一般解析错误的信息,因为所有其他子解析器都失败了 -
/// 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。
再次感谢古斯塔沃!