Domanda

Sto cercando di replicare la struttura di un'istruzione semplice if:

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

Per il blocco if (paren), creo un nodo AST ifblock. Altrimenti, riempie ricorsivamente un nodo IFELSEBLOCK.

Ho provato parecchi costruzioni alternative

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

Suggerimenti?

È stato utile?

Soluzione

Hai dato un'occhiata al mio parser GLSL (è un linguaggio simile a C)?http://laurent.le-brun.eu/fsharp/glsl_parse.fs

Dall'esempio del codice, ecco la parte pertinente per if dichiarazione:

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

Penso che il tuo problema sia che stai usando attempt invece di opt. opt significa il else la parte è facoltativa (se non è lì, ottieni None). attempt è abbastanza diverso:

Il parser attempt p applica il parser p. Se p fallisce dopo aver cambiato lo stato del parser o con un errore fatale, attempt p tornerà a fare un backtrack allo stato di parser originale e segnalerà un errore non fatale.

Quando il parser dentro attempt fallisce, c'è ancora un errore ma l'input non è consumato (è utile se combinato con il <|> o choice operatori).

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top