2
votes

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
1

1 Answers

1
votes

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".