open Combinator (* * ::= (plus ) * | n ∈ ℕ * * ::= | * ::= (plus ) * ::= + * ::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 *) let DEBUG = false (* AST *) type Expr = | Number of int | Plus of Expr * Expr (* PARSER *) let expr,exprImpl = recparser() let pad p = pbetween pws0 p pws0 let num = pmany1 pdigit |>> stringify |>> int |>> Number "num" let plus_inner = pright (pstr "plus") (pseq (pad expr) (pad expr) (fun (l,r) -> Plus (l,r)) ) "plus_inner" let plus = pbetween (pchar '(') plus_inner (pchar ')') "plus" // observe the weird := // that's just because exprImpl was defined using recparser exprImpl := plus <|> num "expr" let grammar = pleft expr peof "grammar" let parse (input: string) : Expr option = // change DEBUG above to make the // parser print or not print let i = if DEBUG then debug input else prepare input match grammar i with | Success(ast,_) -> Some ast | Failure(_,_) -> None (* EVALUATOR *) let rec eval (e: Expr) : int = match e with | Number n -> n | Plus (lhs,rhs) -> // eval lhs + eval rhs let lres = eval lhs let rres = eval rhs lres + rres [] let main args = let input = args[0] let result = parse input match result with | Some ast -> let res = eval ast printfn "Result: %d" res | None -> printfn "Invalid pluslang program!" 0