2015-03-28 5 views
5

Я пытаюсь написать парсер для языка Mathematica в F #, используя FParsec.Разбор «x y z» с приоритетом умножения

Я написал один для MiniML, который поддерживает синтаксис f x y = (f(x))(y) с высоким приоритетом для приложения-функции. Теперь мне нужно использовать один и тот же синтаксис для обозначения f*x*y и, следовательно, иметь такой же приоритет, как умножение. В частности, x y + 2 = x*y + 2 тогда как x y^2 = x * y^2.

Как это можно сделать?

+2

Я не пробовал это, но я думаю, что вы можете реализовать это с помощью [OperatorPrecedenceParser] (http://www.quanttec.com/fparsec/reference/operatorprecedenceparser.html), сделав ваш обычный синтаксический анализатор пробелов не принятым пробелом между идентификаторами и добавлением оператора инфикса для '' '' пробельной строки с «послепорядком-парсером», которая терпит неудачу, не потребляя вход, если пробелу не соответствует идентификатор. –

+0

Но это не будет анализировать '(x) (y) = x * y'? –

+2

Возможно, вы могли бы проанализировать второй термин в parens, используя «(« постфиксный оператор, который анализирует термин и заключительный параграф с помощью парсера после строки ». Более чистый подход без хакерских« »и« («операторов» был бы для синтаксического анализа совпадающих терминов в качестве последовательности терминов. Чтобы правильно обрабатывать приоритет, вам, вероятно, понадобится отдельный экземпляр OPP для всех (верхнего уровня) терминов в последовательности, отличной от первой. Этот другой OPP будет включать только операторов, которые имеют более высокий приоритет, чем умножение (и без префикса +/-). –

ответ

6

Как указал Стефан в комментарии, вы можете разделить оператор-синтаксический анализатор на два отдельных синтаксических анализатора и поместить свой собственный синтаксический анализатор в середине для пространственно разделенных выражений. Следующий код демонстрирует это:

#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" 

выход:

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

1 * 2 + 3 * 4^5 * 6, который представляет, как ожидалось.