open Parser (* * ABSTRACT SYNTAX TREE TYPES * * This type represents the "abstract syntax" or structure of * an expression. In other words, it's an AST. * E.g., if we type in "aaa{bbb}" * we want to get a Terms [AAA; Brace (Terms [ BBB ])] * back. *) type Term = | AAA | BBB | Brace of Expr and Expr = | Terms of Term list (* * GRAMMAR * * ::= * ::= + * ::= aaa * | bbb * | * ::= { } * * The purpose of is just to make the * 'start' of our grammar can be found. *) (* * PARSER * * Remember, we always have to define things before we use them. * So the _last_ thing we define is the top-most non-terminal. * * Note that we use `recparser` so that we can _use_ `pexpr` before * we _define_ `pexpr`. We have to do that because the grammar is * recusive. `recparser` returns a tuple that represents the two * halves of an ordinary definition: * - the declared name of the definition (e.g., `pexpr`), and * - the implementation (e.g., `pexprImpl`). *) let pexpr, pexprImpl = recparser() // * "forward declare" let brace = pbetween (pchar '{') (pchar '}') pexpr |>> Brace // * define let pterm: Parser = // * define the 3 cases of a (pstr "aaa" |>> (fun _ -> AAA)) // - if "aaa", run constructor for Term AAA <|> (pstr "bbb" |>> (fun _ -> BBB)) // - if "bbb", run constructor for Term BBB <|> brace // - otherwise, it's a pexprImpl := pmany1 pterm |>> Terms // * now we define 's implementation: // look for at least one ; // give the list of terms found to the Terms constructor. let grammar: Parser = pleft pexpr peof // * look for an followed by the end of the file. [] let main argv = let input = argv.[0] // * we read input from the command line let input' = prepare input // * wrap input with bookkeeping data structure match (grammar input') with // * run the grammar parser, and pattern match the output | Success(res,_) -> printfn "%A" res // - if it succeeded, print what we got | Failure(_,_) -> printfn "nope" // - otherwise inform the user that it didn't work out 0