analizaciones si / else / if declaraciones
Pregunta
Estoy tratando de replicar la estructura de una instrucción SIMPLE IF:
if (paren) { block } [else ({ block } | rec if (paren)) ]
Para el bloque if (paren), creo un nodo ASTBLOCK AST. De lo contrario, llena recursivamente un nodo ifelseblock.
He probado bastantes construcciones alternativas
let parse_if =
suffixparen .>>. suffixblock |>> IfBlock
//>>? attempt (str "else" >>. ifParser) |>> IfElseBlock
//<|> preturn IfBlock
// .>>? attempt (str "else" >>. ifParser) |>> IfElseBlock
// suffixparen .>>. suffixblock |>> IfBlock
// <|> ifParser |>> IfElseBlock
let inlineIf = str_ws "if" >>. parse_if
do ifParserR := inlineIf
¿Sugerencias?
Solución
¿Has echado un vistazo a mi analizador GLSL (es un lenguaje similar a C)?http://laurent.le-brun.eu/fsharp/glsl_parse.fs
Del ejemplo del código, aquí está la parte relevante para el if
declaración:
let statement, stmtRef = createParserForwardedToRef()
let ifStatement =
pipe3 (keyword "if" >>. parenExp) statement (opt (keyword "else" >>. statement))
(fun cond stmt1 stmt2 -> Ast.If(cond, stmt1, stmt2))
stmtRef := choice [
simpleStatement
block
ifStatement
forLoop
//...
]
Creo que tu problema es que estás usando attempt
en vez de opt
. opt
significa el else
parte es opcional (si no está allí, obtienes None
). attempt
es bastante diferente:
El analizador
attempt p
aplica el analizadorp
. Sip
falla después de cambiar el estado del analizador o con un error fatal,attempt p
retrocederá en el estado de analizador original e informará un error no fatal.
Cuando el analizador attempt
falla, todavía hay un error, pero la entrada no se consume (es útil cuando se combina con el <|>
o choice
operadores).