Parsing polynomials with F# and FParsec
Parsing polynomials with F# and FParsec
Parsing a polynomial expression is a simple but interesting example of parsing. We need to handle operator precedence and associativity, for example *
has a higher precedence than +
and the exponentiation is right associative x^y^z=x^(y^z)
while subtraction is left associative x-y-z=(x-y)-z
. Moreover a straighforward definition of the grammar is left recursive and a recursive descent parser does not allow to parse such grammar. We need to arrange our grammar in order to avoid the left recursion.
In this post we will build a console app that:
- Ask the user for a polynomial expression such as
x+1
or2*(x-y)^2
. - Ask the user for the value of all the variables that appear in the polynomial.
- Print the value of the polynomial for the provided variables values.
The solution is very concise and simple thanks to the power of F# and the parser combinator library FParsec. Using simple and small building block we will build a recursive descent parser for our polynomial grammar. Let's start with choosing a representation for the polynomials.
The AST
We use a discriminated union to define a type to represent a polynomial:
type Expression =
| Add of Expression * Expression // x+y or z+1
| Const of double // 1 or 10.5
| Negative of Expression // -x
| Pow of Expression * Expression // x^2
| Product of Expression * Expression // x*y
| Subtract of Expression * Expression // x-1 or x-y
| Variable of char // x or y
Note that the type is recursive since we want to represent complex polynomials such as x*(y+1)
which corresponds to Product(Variable(x),Add(Variable(y),Const(1)))
. We could define a type for Pow
to have a better distinction between the base and the exponent, in this example the distinction is purely positional: the first Expression
is the base, the second one is the exponent.