2016-11-01 7 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)를 모두 구문 분석 할 수 있습니다. 희망이이 문제를 가진 다른 사람들을 도울 수 있기를 바랍니다.