As Stephan pointed out in a comment you can split the operator parser into two separate parsers and put your own parser in the middle for space-separated expressions. The following code demonstrates this:
#I "../packages/FParsec.1.0.1/lib/net40-client"
#r "FParsec"
#r "FParsecCS"
open FParsec
open System.Numerics
type Expr =
| Int of BigInteger
| Add of Expr * Expr
| Mul of Expr * Expr
| Pow of Expr * Expr
let str s = pstring s >>. spaces
let pInt : Parser<_, unit> = many1Satisfy isDigit |>> BigInteger.Parse .>> spaces
let high = OperatorPrecedenceParser<Expr,unit,unit>()
let low = OperatorPrecedenceParser<Expr,unit,unit>()
let pHighExpr = high.ExpressionParser .>> spaces
let pLowExpr = low.ExpressionParser .>> spaces
high.TermParser <-
choice
[ pInt |>> Int
between (str "(") (str ")") pLowExpr ]
low.TermParser <-
many1 pHighExpr |>> (function [f] -> f | fs -> List.reduce (fun f g -> Mul(f, g)) fs) .>> spaces
low.AddOperator(InfixOperator("+", spaces, 10, Associativity.Left, fun f g -> Add(f, g)))
high.AddOperator(InfixOperator("^", spaces, 20, Associativity.Right, fun f g -> Pow(f, g)))
run (spaces >>. pLowExpr .>> eof) "1 2 + 3 4 ^ 5 6"
The output is:
Add (Mul (Int 1,Int 2),Mul (Mul (Int 3,Pow (Int 4,Int 5)),Int 6))
which represents 1 * 2 + 3 * 4^5 * 6
as expected.
" "
space string with an 'after-string-parser' that fails without consuming input if the space is not followed by an identifier. – Interbreed(x)(y) = x*y
? – PoleaxeOPP
s. I'll try it. Thanks! – PoleaxeOperatorPrecedenceParser
they are not disambiguated and trying to parse "/." fails with an error. – PoleaxenotFollowedByString "." >>. spaces
as the after-string-parser for this operator. – InterbreednextCharSatisfiesNot (function '.' | ':' -> true | _ -> false)
instead ofnotFollowedByString
. (The generated error message shouldn't matter when the after-string-parser fails without consuming input.) – Interbreed