2015-03-28 27 views
5

Sto provando a scrivere un parser per il linguaggio Mathematica in F # utilizzando FParsec.Analizzare "x y z" con la precedenza di moltiplicare

Ne ho scritto uno per un MiniML che supporta la sintassi f x y = (f(x))(y) con precedenza elevata per l'applicazione di funzione. Ora ho bisogno di usare la stessa sintassi per dire f*x*y e, quindi, avere la stessa precedenza di moltiplicare. In particolare, x y + 2 = x*y + 2 mentre x y^2 = x * y^2.

Come può essere realizzato?

+2

Non ho provato questo, ma penso che si potrebbe implementare questo con [OperatorPrecedenceParser] (http://www.quanttec.com/fparsec/reference/operatorprecedenceparser.html) facendo sì che il normale parser degli spazi non accetti spazi bianchi tra identificatori e aggiunta di un operatore infisso per la stringa di spazio "" "' con un 'parser after-string' che non riesce a consumare input se lo spazio non è seguito da un identificatore. –

+0

Ma questo non analizzerebbe '(x) (y) = x * y'? –

+2

Forse potresti analizzare il secondo termine in paren usando un "(" operatore postfisso che analizza il termine e il paren di chiusura con il parser after-string-Un approccio più pulito, senza gli hackish "" e "(" operatori, sarebbe per analizzare i termini giustapposti come una sequenza di termini. Per gestire correttamente la precedenza, probabilmente avrai bisogno di un'istanza OPP separata per tutti i termini (di primo livello) in una sequenza diversa dalla prima. Questo altro OPP includerebbe solo gli operatori che avere una precedenza più alta della moltiplicazione (e nessun prefisso +/-) –

risposta

6

Come Stephan ha sottolineato in un commento, è possibile dividere il parser dell'operatore in due parser separati e inserire il proprio parser nel mezzo per le espressioni separate dallo spazio. Il codice di seguito illustra questo:

#I "../packages/FParsec.1.0.1/lib/net40-client" 
#r "FParsec" 
#r "FParsecCS" 

open FParsec 
open System.Numerics 

type Expr = 
    | Int of BigInteger 
    | Add of Expr * Expr 
    | Mul of Expr * Expr 
    | Pow of Expr * Expr 

let str s = pstring s >>. spaces 
let pInt : Parser<_, unit> = many1Satisfy isDigit |>> BigInteger.Parse .>> spaces 
let high = OperatorPrecedenceParser<Expr,unit,unit>() 
let low = OperatorPrecedenceParser<Expr,unit,unit>() 
let pHighExpr = high.ExpressionParser .>> spaces 
let pLowExpr = low.ExpressionParser .>> spaces 

high.TermParser <- 
    choice 
    [ pInt |>> Int 
     between (str "(") (str ")") pLowExpr ] 

low.TermParser <- 
    many1 pHighExpr |>> (function [f] -> f | fs -> List.reduce (fun f g -> Mul(f, g)) fs) .>> spaces 

low.AddOperator(InfixOperator("+", spaces, 10, Associativity.Left, fun f g -> Add(f, g))) 
high.AddOperator(InfixOperator("^", spaces, 20, Associativity.Right, fun f g -> Pow(f, g))) 

run (spaces >>. pLowExpr .>> eof) "1 2 + 3 4^5 6" 

il risultato è:

Add (Mul (Int 1,Int 2),Mul (Mul (Int 3,Pow (Int 4,Int 5)),Int 6)) 

che rappresenta 1 * 2 + 3 * 4^5 * 6 come previsto.

Problemi correlati