Gabriel
Gabriel

Reputation: 1942

FParsec parse expressions with parentheses

I'm coding my first parser. It's in F# and I'm using with FParsec.

My parser parses things like true and false, (true and false or true), true, (((true and false or true))) etc, which is correct.

But it doesn't parses when it's like (true and false) or true. It fails when there are parentheses in the middle of the text.

How can I solve it?

Sample code:

let private infixOperator (opp: OperatorPrecedenceParser<_,_,_>) op prec map =
    opp.AddOperator(InfixOperator (op, ws, prec, Associativity.Left, map))

let private oppLogic = new OperatorPrecedenceParser<_,_,_>()

infixOperator oppLogic "is" 1 (fun x y -> Comparison (x, Equal, y))
infixOperator oppLogic "isnt" 1 (fun x y -> Comparison (x, NotEqual, y))
infixOperator oppLogic "or" 2 (fun x y -> Logic (x, Or, y))
infixOperator oppLogic "and" 3 (fun x y -> Logic (x, And, y))

let private exprParserLogic = oppLogic.ExpressionParser

let private betweenParentheses p =
    between (str "(") (str ")") p

oppLogic.TermParser <- choice [
    betweenParentheses exprParserLogic
    pboolean
]

let pexpression =
    choice [
        attempt <| betweenParentheses exprParserLogic
        exprParserLogic
    ]

let private pline =
    ws
    >>. pexpression
    .>> eof

Upvotes: 2

Views: 383

Answers (1)

sepp2k
sepp2k

Reputation: 370455

What happens for an input like "(true and false) or true" is that pline applies, which pexpression tries to apply betweenParentheses exprParserLogic. This succeeds and parses "(true and false)". So since the parse was successful, it never tries the second option exprParserLogic and simply returns to pline. pline then applies eof, which fails because "or true" is still left in the input.

Since betweenParentheses exprParserLogic is already part of the operator parser's term parser, there's no reason for you to try to parse it in its own rule. You can just have pline invoke exprParserLogic and remove pexpression altogether (or define let pexpression = oppLogic.ExpressionParser and remove exprParserLogic). This will correctly parse "(true and false) or true".

Upvotes: 1

Related Questions