문제

I'm trying to replicate the structure of a simple if statement:

if (paren) { block } [else ({ block } | rec if (paren)) ]

for if (paren) block, I create a IfBlock AST node. Otherwise, it recursively fills a IfElseBlock node.

I've tried quite a few alternate constructions

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

Suggestions?

도움이 되었습니까?

해결책

Have you had a look at my GLSL parser (it's a C-like language)? http://laurent.le-brun.eu/fsharp/glsl_parse.fs

From the code example, here is the relevant part for the if statement:

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
  //...
  ]

I think your problem is that you're using attempt instead of opt. opt means the else part is optional (if it's not there, you get None). attempt is quite different:

The parser attempt p applies the parser p. If p fails after changing the parser state or with a fatal error, attempt p will backtrack to the original parser state and report a non‐fatal error.

When the parser in attempt fails, there's still an error but the input is not consumed (it's useful when combined with the <|> or choice operators).

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top