parsing - FParsec only parses expr between parentheses -
i coding parser (for learning pourpuses).
i want parse constructions like
let myvar 40 plus 2
and
let myvar (40 plus 2)
with no problems... parser not "understand" former. sees 40
, thinks "well, it's literal numeric 40
".
when put parentheses, parser works great.
i having hard time understand why.
parser:
type value = | boolean of bool | numeric of float | string of string type arithmetic = sum | sub | mul | div | pow type logic = , | or | equal | notequal | greater | smaller type identifier = | identifier of string type expression = | literal of value | arithmetic of expression * arithmetic * expression | negative of expression | negation of expression | logic of expression * logic * expression | variable of identifier type statement = | assignment of identifier * expression | print of expression | read of identifier let private ws = spaces let private str s = pstring s .>> ws let private pnumeric = pfloat .>> ws |>> fun n -> literal (numeric n) let private pboolean = choice [ (stringreturn "true" (literal (boolean true))) (stringreturn "false" (literal (boolean false))) ] .>> ws let private pstringliteral = choice [ between (pstring "\"") (pstring "\"") (manychars (satisfy (fun c -> c <> '"'))) between (pstring "'") (pstring "'") (manychars (satisfy (fun c -> c <> '''))) ] |>> fun s -> literal (string s) let private pidentifier = many1satisfy2l isletter (fun c -> isletter c || isdigit c) "identifier" |>> fun s -> identifier s let private betweenparentheses p = between (str "(") (str ")") p let private pvalue = choice [ pnumeric pboolean ] let private prefixoperator (p: operatorprecedenceparser<_,_,_>) op prec map = p.addoperator(prefixoperator (op, ws, prec, true, map)) let private infixoperator (p: operatorprecedenceparser<_,_,_>) op prec map = p.addoperator(infixoperator (op, ws, prec, associativity.left, map)) let private oppnegation = new operatorprecedenceparser<_,_,_>() let private opplogic = new operatorprecedenceparser<_,_,_>() let private opparithmetic = new operatorprecedenceparser<_,_,_>() let private oppnegative = new operatorprecedenceparser<_,_,_>() prefixoperator oppnegation "not" 1 (fun x -> negation x) infixoperator opplogic "is" 1 (fun x y -> logic (x, equal, y)) infixoperator opplogic "isnt" 1 (fun x y -> logic (x, notequal, y)) infixoperator opplogic "and" 2 (fun x y -> logic (x, and, y)) infixoperator opplogic "or" 3 (fun x y -> logic (x, or, y)) prefixoperator oppnegative "-" 1 (fun x -> negative x) infixoperator opparithmetic ">" 1 (fun x y -> logic (x, greater, y)) infixoperator opparithmetic "<" 1 (fun x y -> logic (x, smaller, y)) infixoperator opparithmetic "is" 2 (fun x y -> logic (x, equal, y)) infixoperator opparithmetic "isnt" 2 (fun x y -> logic (x, notequal, y)) infixoperator opparithmetic "plus" 3 (fun x y -> arithmetic (x, sum, y)) infixoperator opparithmetic "minus" 3 (fun x y -> arithmetic (x, sub, y)) infixoperator opparithmetic "times" 4 (fun x y -> arithmetic (x, mul, y)) infixoperator opparithmetic "divided by" 4 (fun x y -> arithmetic (x, div, y)) infixoperator opparithmetic "power" 5 (fun x y -> arithmetic (x, pow, y)) let private negationexprparser = oppnegation.expressionparser let private logicexprparser = opplogic.expressionparser let private arithmeticexprparser = opparithmetic.expressionparser let private negativeexprparser = oppnegative.expressionparser oppnegation.termparser <- choice [ betweenparentheses negationexprparser pboolean ] opplogic.termparser <- choice [ betweenparentheses logicexprparser pboolean ] oppnegative.termparser <- choice [ betweenparentheses negativeexprparser pnumeric ] opparithmetic.termparser <- choice [ betweenparentheses arithmeticexprparser pnumeric ] let private pexpression = choice [ attempt <| pstringliteral attempt <| negationexprparser attempt <| logicexprparser attempt <| negativeexprparser attempt <| arithmeticexprparser attempt <| (pidentifier |>> fun id -> variable id) ] let private passignment = pipe2 (str "let" .>> ws >>. pidentifier) (ws >>. str "be" >>. ws >>. pexpression) (fun id exp -> assignment (id, exp)) let private pprint = str "print" >>. pexpression |>> fun exp -> print exp let private pread = str "read" >>. pidentifier |>> fun id -> read id let private pstatement = choice [ passignment pprint pread ] let private pline = skipmany (satisfy (fun c -> c = '\n' || c = ' ')) >>. pstatement .>> ws let private pcode = many pline let generateast code = match run pcode code | success (ast, _, _) -> sprintf "%a" ast | failure (msg, _, _) -> msg
usage:
[<entrypoint>] let main argv = printfn "%s\n" (generateast "let b 5 plus 7") // [assignment (identifier "b",literal (numeric 5.0))] printfn "%s\n" (generateast "let b (5 plus 7)") // [assignment // (identifier "b",arithmetic (literal (numeric 5.0),sum,literal (numeric 7.0)))] 0
take @ fparsec - tracing parser
if add recommended fparsec tracing function top of code
let (<!>) (p: parser<_,_>) label : parser<_,_> = fun stream -> printfn "%a: entering %s" stream.position label let reply = p stream printfn "%a: leaving %s (%a)" stream.position label reply.status reply
then modify parsers use trace function
let private pnumeric = (pfloat .>> ws |>> fun n -> literal (numeric n)) <!> "pnumeric" let private pboolean = (choice [ (stringreturn "true" (literal (boolean true))) (stringreturn "false" (literal (boolean false))) ] .>> ws) <!> "pboolean" let private pstringliteral = (choice [ between (pstring "\"") (pstring "\"") (manychars (satisfy (fun c -> c <> '"'))) between (pstring "'") (pstring "'") (manychars (satisfy (fun c -> c <> '''))) ] |>> fun s -> literal (string s)) <!> "pstringliteral" let private pidentifier = (many1satisfy2l isletter (fun c -> isletter c || isdigit c) "identifier" |>> fun s -> identifier s) <!> "pidentifier" let private betweenparentheses p = (between (str "(") (str ")") p) <!> "betweenparentheses" let private pvalue = (choice [ pnumeric pboolean ]) <!> "pvalue" let private negationexprparser = oppnegation.expressionparser <!> "negationexprparser" let private logicexprparser = opplogic.expressionparser <!> "logicexprparser" let private arithmeticexprparser = opparithmetic.expressionparser <!> "arithmeticexprparser" let private negativeexprparser = oppnegative.expressionparser <!> "negativeexprparser " let private pexpression = choice [ attempt <| pstringliteral attempt <| negationexprparser attempt <| logicexprparser attempt <| negativeexprparser attempt <| arithmeticexprparser attempt <| (pidentifier |>> fun id -> variable id) ] <!> "pexpression" let private passignment = pipe2 (str "let" .>> ws >>. pidentifier) (ws >>. str "be" >>. ws >>. pexpression) (fun id exp -> assignment (id, exp)) <!> "passignment" let private pprint = (str "print" >>. pexpression |>> fun exp -> print exp) <!> "pprint" let private pread = (str "read" >>. pidentifier |>> fun id -> read id) <!> "pread" let private pstatement = (choice [ passignment pprint pread ]) <!> "pstatement" let private pline = (skipmany (satisfy (fun c -> c = '\n' || c = ' ')) >>. pstatement .>> ws) <!> "pline" let private pcode = many pline <!> "pcode"
and run code get
(ln: 1, col: 1): entering pcode (ln: 1, col: 1): entering pline (ln: 1, col: 1): entering pstatement (ln: 1, col: 1): entering passignment (ln: 1, col: 5): entering pidentifier (ln: 1, col: 6): leaving pidentifier (ok) (ln: 1, col: 10): entering pexpression (ln: 1, col: 10): entering pstringliteral (ln: 1, col: 10): leaving pstringliteral (error) (ln: 1, col: 10): entering negationexprparser (ln: 1, col: 10): entering betweenparentheses (ln: 1, col: 10): leaving betweenparentheses (error) (ln: 1, col: 10): entering pboolean (ln: 1, col: 10): leaving pboolean (error) (ln: 1, col: 10): leaving negationexprparser (error) (ln: 1, col: 10): entering logicexprparser (ln: 1, col: 10): entering betweenparentheses (ln: 1, col: 10): leaving betweenparentheses (error) (ln: 1, col: 10): entering pboolean (ln: 1, col: 10): leaving pboolean (error) (ln: 1, col: 10): leaving logicexprparser (error) (ln: 1, col: 10): entering negativeexprparser (ln: 1, col: 10): entering betweenparentheses (ln: 1, col: 10): leaving betweenparentheses (error) (ln: 1, col: 10): entering pnumeric (ln: 1, col: 12): leaving pnumeric (ok) (ln: 1, col: 12): leaving negativeexprparser (ok) (ln: 1, col: 12): leaving pexpression (ok) (ln: 1, col: 12): leaving passignment (ok) (ln: 1, col: 12): leaving pstatement (ok) (ln: 1, col: 12): leaving pline (ok) (ln: 1, col: 12): entering pline (ln: 1, col: 12): entering pstatement (ln: 1, col: 12): entering passignment (ln: 1, col: 12): leaving passignment (error) (ln: 1, col: 12): entering pprint (ln: 1, col: 12): leaving pprint (error) (ln: 1, col: 12): entering pread (ln: 1, col: 12): leaving pread (error) (ln: 1, col: 12): leaving pstatement (error) (ln: 1, col: 12): leaving pline (error) (ln: 1, col: 12): leaving pcode (ok) [assignment (identifier "b",literal (numeric 5.0))] (ln: 1, col: 1): entering pcode (ln: 1, col: 1): entering pline (ln: 1, col: 1): entering pstatement (ln: 1, col: 1): entering passignment (ln: 1, col: 5): entering pidentifier (ln: 1, col: 6): leaving pidentifier (ok) (ln: 1, col: 10): entering pexpression (ln: 1, col: 10): entering pstringliteral (ln: 1, col: 10): leaving pstringliteral (error) (ln: 1, col: 10): entering negationexprparser (ln: 1, col: 10): entering betweenparentheses (ln: 1, col: 11): entering negationexprparser (ln: 1, col: 11): entering betweenparentheses (ln: 1, col: 11): leaving betweenparentheses (error) (ln: 1, col: 11): entering pboolean (ln: 1, col: 11): leaving pboolean (error) (ln: 1, col: 11): leaving negationexprparser (error) (ln: 1, col: 11): leaving betweenparentheses (error) (ln: 1, col: 11): leaving negationexprparser (error) (ln: 1, col: 10): entering logicexprparser (ln: 1, col: 10): entering betweenparentheses (ln: 1, col: 11): entering logicexprparser (ln: 1, col: 11): entering betweenparentheses (ln: 1, col: 11): leaving betweenparentheses (error) (ln: 1, col: 11): entering pboolean (ln: 1, col: 11): leaving pboolean (error) (ln: 1, col: 11): leaving logicexprparser (error) (ln: 1, col: 11): leaving betweenparentheses (error) (ln: 1, col: 11): leaving logicexprparser (error) (ln: 1, col: 10): entering negativeexprparser (ln: 1, col: 10): entering betweenparentheses (ln: 1, col: 11): entering negativeexprparser (ln: 1, col: 11): entering betweenparentheses (ln: 1, col: 11): leaving betweenparentheses (error) (ln: 1, col: 11): entering pnumeric (ln: 1, col: 13): leaving pnumeric (ok) (ln: 1, col: 13): leaving negativeexprparser (ok) (ln: 1, col: 13): leaving betweenparentheses (error) (ln: 1, col: 13): leaving negativeexprparser (error) (ln: 1, col: 10): entering arithmeticexprparser (ln: 1, col: 10): entering betweenparentheses (ln: 1, col: 11): entering arithmeticexprparser (ln: 1, col: 11): entering betweenparentheses (ln: 1, col: 11): leaving betweenparentheses (error) (ln: 1, col: 11): entering pnumeric (ln: 1, col: 13): leaving pnumeric (ok) (ln: 1, col: 18): entering betweenparentheses (ln: 1, col: 18): leaving betweenparentheses (error) (ln: 1, col: 18): entering pnumeric (ln: 1, col: 19): leaving pnumeric (ok) (ln: 1, col: 19): leaving arithmeticexprparser (ok) (ln: 1, col: 20): leaving betweenparentheses (ok) (ln: 1, col: 20): leaving arithmeticexprparser (ok) (ln: 1, col: 20): leaving pexpression (ok) (ln: 1, col: 20): leaving passignment (ok) (ln: 1, col: 20): leaving pstatement (ok) (ln: 1, col: 20): leaving pline (ok) (ln: 1, col: 20): entering pline (ln: 1, col: 20): entering pstatement (ln: 1, col: 20): entering passignment (ln: 1, col: 20): leaving passignment (error) (ln: 1, col: 20): entering pprint (ln: 1, col: 20): leaving pprint (error) (ln: 1, col: 20): entering pread (ln: 1, col: 20): leaving pread (error) (ln: 1, col: 20): leaving pstatement (error) (ln: 1, col: 20): leaving pline (error) (ln: 1, col: 20): leaving pcode (ok) [assignment (identifier "b",arithmetic (literal (numeric 5.0),sum,literal (numeric 7.0)))]
this should figure out problem, more importantly how solve future problems fparsec.