Tengo un analizador sintáctico que parece bastante directo. He añadido este sub-programa de análisis hasta el final para dar información acerca de los errores generales de análisis ya que todos los demás sub-programas de análisis fallaron -Cómo resolver el error de FParsec "El combinador 'muchos' se aplicó a un analizador que tiene éxito sin consumir ..."
/// 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
Sin embargo, una vez que agrego ReadError como una opción, me sale el error FParsec temido sobre el flujo de consumo en tiempo de ejecución - The combinator 'many' was applied to a parser that succeeds without consuming input and without changing the parser state in any other way.
No entiendo por qué obtengo esto ya que uso el resto de la línea analizada para crear una estructura de error usado (aquí 'violación').
¿Alguien me puede ayudar a entender esto? ¿Voy a señalar los errores del analizador al usuario de forma incorrecta? Si no, ¿cómo podría solucionar esto?
¡Gracias por su ayuda!
* * Más detalles
Aquí hay algo más de código que puede ser relevante -
/// 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 }
lo sé. Tal vez el problema es que ya está al final de la transmisión una vez que intenta ejecutar el analizador readError. ¿Eso haría que restOfLine no consumiera datos, ni siquiera espacios en blanco?
* Conclusión *
Resulta que el enfoque de error de información con un analizador ReadError que está mal. El enfoque correcto es utilizar un programa de análisis 'hasta el final' como tal -
/// 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
Ahora sólo funcionan readExprsTillEnd cuando necesito para obtener todos los exprs en un flujo de entrada.
Gracias de nuevo, Gustavo!
Se puede publicar más código? Particularmente el cuerpo de la función makeViolation. – Gustavo
Hecho. Por cierto, Gustavo, soy un gran fan de tu blog. Espero que Don Syme esté mirando el trabajo que has hecho: obtener funtores, aplicativos y mónadas sin HK o TC es enorme. Me pregunto si también podemos obtener flechas de alguna forma;) –
Gracias Bryan por sus comentarios sobre mi trabajo con Typeclasses. También espero que las personas del equipo de F # puedan agregar más soporte para esta técnica, de lo contrario dependen del equipo de CLR para implementar el soporte real de Typeclasses en el nivel .NET. En cuanto a las flechas, ¿echó un vistazo a http://stackoverflow.com/questions/4034802/how-would-i-translate-a-haskell-type-class-into-f? Hay más información sobre Arrows en el proyecto en http://code.google.com/p/fsharp-typeclasses. – Gustavo