парсинг операторов if / else / if - PullRequest
4 голосов
/ 14 июня 2011

Я пытаюсь воспроизвести структуру простого оператора if:

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

для блока if (paren), я создаю узел IfBlock AST.В противном случае он рекурсивно заполняет узел IfElseBlock.

Я пробовал довольно много альтернативных конструкций

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

Предложения?

1 Ответ

4 голосов
/ 14 июня 2011

Вы смотрели на мой парсер GLSL (это C-подобный язык)? http://laurent.le -brun.eu / FSharp / glsl_parse.fs

Из примера кода приведена соответствующая часть для оператора if:

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

Я думаю, что ваша проблема в том, что вы используете attempt вместо opt. opt означает, что часть else является необязательной (если ее там нет, вы получите None). attempt совсем другой:

Парсер attempt p применяет парсер p. Если p не удается после изменения состояние парсера или со смертельным исходом ошибка, attempt p вернется к исходное состояние синтаксического анализатора и сообщить нефатальная ошибка.

При сбое синтаксического анализатора в attempt по-прежнему возникает ошибка, но ввод не используется (полезно в сочетании с операторами <|> или choice).

...