私は十分に単純に見えるパーサーを持っています。他のすべてのサブパーサーが失敗したため、一般的な解析エラーに関する情報を提供するために、このサブパーサーを最後に追加しました-
/// 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
ここで、入力ストリーム内のすべてのexprを取得する必要があるときに、readExprsTillEndを実行します。
もう一度ありがとう、グスタボ!