module CS334 open Combinator // Our AST definition type Expr = | Terms of Term list and Term = | AAA | BBB | Braces of Expr // 'recparser()' lets us separate the declaration of the // parser name 'expr' from its implementation 'exprImpl' // so that we can refer to 'expr' before we define it. // We need to do this because the grammar is co-recursive: // 'expr' eventually calls 'braces', but 'braces' also calls 'expr' let expr, exprImpl = recparser() let aaa = pstr "aaa" |>> (fun _ -> AAA) // parses 'aaa' and returns an AAA let bbb = pstr "bbb" |>> (fun _ -> BBB) // parses 'bbb' and returns a BBB let braces = pbetween (pchar '{') expr (pchar '}') |>> (fun e -> Braces e) // parses a brace expression and returns a Braces let term = aaa <|> bbb <|> braces // parses any Term exprImpl := pmany1 term |>> (fun ts -> Terms ts) // parses one or more terms; returns a Terms object let grammar = pleft expr peof // top-level parser: 'pleft ... peof' ensures that we parse the entire input let parse (input: string) : Expr option = let i = prepare input match grammar i with | Success(ast,_) -> Some ast // just return the AST on success | Failure(pos,rule) -> // on failure, print out the problem as a side-effect // and then return None printfn "Invalid expression" let msg = sprintf "Cannot parse input at position %d in rule '%s':" pos rule let diag = diagnosticMessage 20 pos input msg printf "%s" diag None