2016-11-01 3 views
1

FParsecを使用してPow(3 + 2,2)などのプレフィックス関数を解析しようとしました。私は以下のように、サンプルファイルの電卓のチュートリアルを読んでいます。例はすべて単項接頭辞関数です。私は、FParsec.OperatorPrecedenceParserを使用して、複数の入力でプレフィックス関数をどのように実現できるのだろうかと思います。私は、実際のアプリケーション http://www.quanttec.com/fparsec/users-guide/tips-and-tricks.html#parsing-f-infix-operatorsFParsecを使用してPow()などのプレフィックス関数を複数のパラメータで解析する方法

のために後の文字列パーサを必要として、私は後の文字列パーサの例次の簡単なスクリプトを書いた1

http://www.quanttec.com/fparsec/reference/operatorprecedenceparser.html#members.PrefixOperator

let number = pfloat .>> ws 

let opp = new OperatorPrecedenceParser<float,unit,unit>() 
let expr = opp.ExpressionParser 
opp.TermParser <- number <|> between (str_ws "(") (str_ws ")") expr 


opp.AddOperator(InfixOperator("+", ws, 1, Associativity.Left, (+))) 
opp.AddOperator(InfixOperator("-", ws, 1, Associativity.Left, (-))) 
opp.AddOperator(InfixOperator("*", ws, 2, Associativity.Left, (*))) 
opp.AddOperator(InfixOperator("/", ws, 2, Associativity.Left, (/))) 
opp.AddOperator(InfixOperator("^", ws, 3, Associativity.Right, fun x y -> System.Math.Pow(x, y))) 
opp.AddOperator(PrefixOperator("-", ws, 4, true, fun x -> -x)) 

let ws1 = nextCharSatisfiesNot isLetter >>. ws 
opp.AddOperator(PrefixOperator("log", ws1, 4, true, System.Math.Log)) 
opp.AddOperator(PrefixOperator("exp", ws1, 4, true, System.Math.Exp)) 

更新abs(pow(1,2))は解析できるが、pow(abs(1) 、2)はできません。私はidentWithArgsの入力の一部としてプレフィックス関数を使用する方法について困惑しています。

#I @"..\packages\FParsec.1.0.2\lib\net40-client" 
#r "FParsecCS.dll" 
#r "FParsec.dll" 

open FParsec 

type PrefixFunc = POW 
type Expr = 
    | InfixOpExpr of string * Expr * Expr 
    | PrefixOpExpr of string * Expr 
    | PrefixFuncExpr of PrefixFunc * Expr list 
    | Number of int 

let ws = spaces 
let ws1 = spaces1 
let str s = pstring s 
let str_ws s = ws >>. str s .>> ws 
let strci s = pstringCI s 
let strci_ws s = ws >>. strci s .>> ws 
let strciret_ws s x = ws >>. strci s .>> ws >>% x 

let isSymbolicOperatorChar = isAnyOf "!%&*+-./<=>@^|~?" 
let remainingOpChars_ws = manySatisfy isSymbolicOperatorChar .>> ws 

let primitive = pint32 .>> ws |>> Number 
let argList = sepBy primitive (str_ws ",") 
let argListInParens = between (str_ws "(") (str_ws ")") argList 
let prefixFunc = strciret_ws "pow" POW 
let identWithArgs = 
    pipe2 prefixFunc argListInParens (fun funcId args -> PrefixFuncExpr(funcId, args)) 

let opp = new OperatorPrecedenceParser<Expr, string, unit>() 
opp.TermParser <- 
    primitive <|> 
    identWithArgs <|> 
    between (pstring "(") (pstring ")") opp.ExpressionParser 

// a helper function for adding infix operators to opp 
let addSymbolicInfixOperators prefix precedence associativity = 
    let op = InfixOperator(prefix, remainingOpChars_ws, 
          precedence, associativity,(), 
          fun remOpChars expr1 expr2 -> 
           InfixOpExpr(prefix + remOpChars, expr1, expr2)) 
    opp.AddOperator(op) 

// the operator definitions: 
addSymbolicInfixOperators "*" 10 Associativity.Left 
addSymbolicInfixOperators "**" 20 Associativity.Right 

opp.AddOperator(PrefixOperator("abs",remainingOpChars_ws,3,true,(),fun remOpChars expr -> PrefixOpExpr("abs", expr))) 
opp.AddOperator(PrefixOperator("log",remainingOpChars_ws,3,true,(),fun remOpChars expr -> PrefixOpExpr("log", expr))) 

run opp.ExpressionParser "abs(pow(1,2))" 
run opp.ExpressionParser "pow(abs(1),2)" 
+2

ここをクリックしてください:http://stackoverflow.com/questions/9197687/parsing-function-application-with-fparsec-using-operatorprecedenceparser(および関連する質問)。 – scrwtp

+2

要するに、単項演算子ではなく、 'TermParser'の一部として関数アプリケーションをモデル化する方が良い考えです。 – scrwtp

+0

なぜあなたは上記のアドバイスを受けたくないのですか? –

答えて

0

私は1年後に問題を再検討し始め、最終的に問題を認識しました。

私は、コードの先頭にOperatorPrecedenceParserを持って、次の

let opp = new OperatorPrecedenceParser<Expr, string, unit>() 
let argList = sepBy opp.ExpressionParser (str_ws ",") 

に次のコード

let argList = sepBy primitive (str_ws ",") 

を変更しました。そして、argListに直接入れることで、opp.ExpressionParserを再帰的に呼び出すことができます。

私はOperatorPrecedenceParserがcreateParserForwardedToRefと非常によく似ていることに気付きました。後で実装するまでパーサーを作成しません。 FParsecはこのように再帰性を実現しなければなりません。 JSONサンプルパーサーと同様です。

この変更後、abs(pow(1,2))とpow(abs(1)、2)の両方を解析できます。これがこれまでにこの問題を抱えている人たちを助けることを望みます。

関連する問題