Toy project: grammar rules in Haskell.
Example:
import Grammar
arithmeticGrammar =
let number = OneOrMore $ Disjunction $ map (Literal . show) [0 .. 9]
plus = Sequence [number, Literal "+", expr]
minus = Sequence [number, Literal "-", expr]
expr = Disjunction [plus, minus, number]
in Grammar { start = expr }
matches arithmeticGrammar "4" == True
matches arithmeticGrammar "1+2-32" == True
matches arithmeticGrammar "text" == False
See src/Grammar.hs for implementation. See test/Spec.hs for tests / example usage.
Note that this module does not return a parse tree; it returns only the boolean of whether the string can be generated by the grammar.
A more advanced example, with parenthetical expressions, optional whitespace, and scientific notation literals:
import Grammar
arithmeticGrammar =
let whitespace = ZeroOrMore $ Literal " "
number = Sequence
[ OneOrMore $ Disjunction $ map (Literal . show) [0 .. 9]
-- optional scientific notation
, Optional $ Sequence
[ Disjunction [Literal "e", Literal "E"]
, Optional $ Literal "-"
, OneOrMore $ Disjunction $ map (Literal . show) [0 .. 9]
]
]
term = Disjunction
[ Sequence [whitespace, number, whitespace]
, Sequence [whitespace, Literal "(", expr, Literal ")", whitespace]
]
expr = Disjunction
[ Sequence [term, Literal "+", expr]
, Sequence [term, Literal "-", expr]
, Sequence [term, Literal "*", expr]
, Sequence [term, Literal "/", expr]
, Sequence [term, Literal "^", expr]
, term
]
in Grammar { start = expr }
matches arithmeticGrammar "15 * (3e5 + 17)" == True
matches arithmeticGrammar "1 - 15 * (33e-5)" == True
matches arithmeticGrammar "(1 - (15 * (33e-5)))" == True
matches arithmeticGrammar "(32 ^ 5e5) + 2e7" == True