Ich bin ein Parser (zum Erlernen von pourpuses).FParsec analysiert nur Ausdrücke zwischen Klammern
Ich möchte es Konstruktionen wie
let myVar be 40 plus 2
und
let myVar be (40 plus 2)
ohne Probleme analysieren ... aber mein Parser "verstehen" nicht die erste. Es sieht die 40
und denkt "gut, es ist ein Literal Numeric 40
".
Wenn ich Klammern setzen, funktioniert mein Parser großartig.
Ich habe es schwer zu verstehen, warum.
Parser:
type value =
| Boolean of bool
| Numeric of float
| String of string
type arithmetic = Sum | Sub | Mul | Div | Pow
type logic = And | 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 with
| Success (ast, _, _) -> sprintf "%A" ast
| Failure (msg, _, _) -> msg
Verbrauch:
[<EntryPoint>]
let main argv =
printfn "%s\n" (generateAST "let b be 5 plus 7")
// [Assignment (Identifier "b",Literal (Numeric 5.0))]
printfn "%s\n" (generateAST "let b be (5 plus 7)")
// [Assignment
// (Identifier "b",Arithmetic (Literal (Numeric 5.0),Sum,Literal (Numeric 7.0)))]
0
Sie könnten Kommentare zu einer anderen Frage von Interesse finden: [Fparsec rekursive Grammatik werfen StackOverflowException] (http://stackoverflow.com/q/37077358/1243762) –
Sie haben [this] (http: //www.fssnip .net/lf) in einem Kommentar. Die Zeilen 77-80 von Parsers Code implementieren etwas, das dem entspricht, was ich getan habe. Warum funktioniert mein Code nicht, wenn es praktisch dasselbe ist? – Gabriel
Wenn Sie solche Fragen posten, versuchen Sie bitte, das Beispiel so weit wie möglich zu reduzieren. Auf diese Weise könnten Sie das Problem selbst finden oder zumindest die Wahrscheinlichkeit erhöhen, dass jemand anderes sich die Zeit nimmt, Ihre Frage zu verstehen und zu beantworten. (Wenn Sie diesen speziellen Beispielcode reduzieren, werde ich versuchen, Ihnen zu helfen!) –