Analyse if / else / if Anweisungen
Frage
Ich versuche, die Struktur einer einfachen If -Anweisung zu replizieren:
if (paren) { block } [else ({ block } | rec if (paren)) ]
Für IF (Paren) Block erstelle ich einen IFBLOCK -AST -Knoten. Andernfalls füllt es rekursiv einen IFelsblock -Knoten.
Ich habe einige alternative Konstruktionen ausprobiert
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
Anregungen?
Lösung
Haben Sie sich meinen GLSL-Parser angesehen (es ist eine C-ähnliche Sprache)?http://laurent.le-brun.eu/fsharp/glsl_parse.fs
Aus dem Code -Beispiel finden Sie hier der relevante Teil für die if
Aussage:
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
//...
]
Ich denke, Ihr Problem ist, dass Sie verwenden attempt
Anstatt von opt
. opt
Bedeutet die else
Teil ist optional (wenn es nicht da ist, bekommen Sie None
). attempt
ist ganz anders:
Der Parser
attempt p
Wendet den Parser anp
. Wennp
fällt nach dem Ändern des Parser -Zustands oder mit einem tödlichen Fehler, fehl.attempt p
wird in den ursprünglichen Parser -Status zurückverfolgen und einen nicht tödlichen Fehler melden.
Wenn der Parser in attempt
fällt aus, es gibt immer noch einen Fehler, aber der Eingang wird nicht verbraucht (es ist nützlich, wenn sie mit dem kombiniert werden <|>
oder choice
Betreiber).