关于如何将OperatorPrecedenceParser与我的集成混淆

时间:2017-05-15 01:44:01

标签: fparsec

我为解析器留下的唯一一件事就是成功地使运算符优先级工作,我的解析器就完成了。但我不知道如何将它与我当前的解析器集成。

首先,这是语言表示:

module MiniML
(* Structures de donnees a exporter *) 
type Exp =
            | C of Cst 
            | Id of Id 
            | Lam of Id * Exp 
            | App of Exp * Exp 
            | Let of Id * Exp * Exp
            | Pair of Exp * Exp
            | If of Exp * Exp * Exp
and Cst  = I of int | B of bool | Unit | Nil
and Id   = string;;

let op = ["+"; 
          "-";
          "*"; 
          "/"; 
          "="; 
          "<"; 
          ">"; 
          "@"; 
          "and"; 
          "or"; 
          ","; 
          "::"
        ]

(* Fonction permettant de transformer une exp en string *) 
let rec exp2str e = match e with
                        | C (I i) -> string i
                        | C (B b) -> string b
                        | C Unit -> "()"
                        | C Nil -> "nil"
                        | Id x -> x
                        | Lam(x,e) -> "lam " + x + "." + (exp2str e)
                        | App(Id x,Id y) -> x + " " + y
                        | App(Id x,((C _) as e')) -> x + " " + (exp2str e')
                        | App(Id x,Pair(e1,e2)) when  List.contains x op -> (exp2str e1) + " " + x + " " + (exp2str e2)
                        | App(Id x,((Pair _) as e')) -> x + (exp2str e')
                        | App(Id x, e') -> x + " (" + (exp2str e') + ")"
                        | App(e, Id x) -> "(" + (exp2str e) + ") " + x
                        | App(e', ((C _) as e'')) -> "(" + (exp2str e') + ") " + (exp2str e'')
                        | App(e,e') -> "(" + (exp2str e) + ") (" + (exp2str e') + ")"
                        | Let(x,e,e') ->
                            "let " + x + " = " + (exp2str e) + " in " + (exp2str e') + " end"
                        (* entensions *)
                        | Pair(e1,e2) -> "(" + (exp2str e1) + "," + (exp2str e2) + ")"
                        | If(e,e1,e2) -> "if " + (exp2str e) + " then " + (exp2str e1) + " else " + (exp2str e2)

这是解析器代码的当前状态(为了完整起见,我已经离开了法语注释。):

module FPParse

open MiniML
open FParsec

(* Raccourcis pour spaces. ws veux dire whitespace *)
let ws = spaces

let operator : Parser<MiniML.Id,unit> = op |> List.map pstring |> choice

(* Liste des mots cles du langage *)
let keyword : Parser<string,unit> = ["false";"true";"let";"end";"in";"if";"then";"else";"lam"] |> List.map pstring |> choice

(* Parse la premiere lettre d'un identifiant *)
let fstId = asciiLetter <|> pchar '_'

(* Parse les lettres autres que la premiere d'un identifiant *)
let restId = fstId <|> digit <|> pchar '''

(* Genere un parseur pour des valeurs entre parenthese *)
let betweenPar p = between (pchar '(' .>> ws) (pchar ')' .>> ws) p

(* Parse une constante boolean *)
let cstB = (stringReturn "true"  (B true)) <|> (stringReturn "false" (B false))

(* Parse une valeur entiere *)
let cstI = puint32 |>> (int >> I)

(*
    Parse Unit
*)
let cstU = stringReturn "()" Unit

(*
    Parse Nil
*)
let cstN = stringReturn "[]" Nil

(* Parse une expression constante *)
let expC : Parser<Exp,unit> = cstB <|> cstI <|> cstU <|> cstN  |>> C

(* Parse un string d'identifiant avec un parseur qui lorsqu'il reussis indique la fin du parsing de l'identifiant *)
let expIdStr = notFollowedByL keyword "Cannot use keyword as variable" >>. 
                    notFollowedByL operator "Cannot use operator as variable" >>. 
                        many1CharsTill2 fstId restId (notFollowedBy restId)


(* Parse un identifiant *)
let expId  : Parser<Exp,unit> = expIdStr |>> (MiniML.Exp.Id)

(* Comme exp est recursif on doit le declarer avec une valeur indefinie pour l'utiliser *)
let exp, expRef = createParserForwardedToRef<Exp, unit>()

(* Comme expApp est recursif on doit le declarer avec une valeur indefinie pour l'utiliser *)
let expApp, expAppRef = createParserForwardedToRef<Exp, unit>()

(* 
    Parse une expression lambda de la forme: lam( )*expId( )*.( )*exp 
*)
let expLam : Parser<Exp,unit> = (pstring "lam" >>. ws >>. expIdStr .>> ws .>> pchar '.') .>> ws .>>. exp |>> Lam

(* 
    Parse une expression let de la forme: let( )*expId( )*=( )*exp( )*in( )*exp( )*end
*)
let expLet = tuple3 (pstring "let" >>. ws >>. expIdStr .>> ws .>> pchar '=' .>> ws) (exp .>> ws .>> pstring "in" .>> ws) (exp .>> ws .>> pstring "end") |>> Let

(* 
    Parse une expression if de la forme: if( )*exp( )*then( )*exp( )*else( )*exp
*)
let expIf = tuple3 (pstring "if" >>. ws >>. exp .>> ws) (pstring "then" >>. ws >>. exp .>> ws) (pstring "else" >>. ws >>. exp) |>> If

(*  Comme closeEXP est recursif on doit le declarer avec une valeur indefinie pour l'utiliser  *)
let closeEXP, closeEXPRef = createParserForwardedToRef<Exp, unit>()

(*
    Parse un operateur ! de la forme: !exp
*)
let expBang = (pstring "!" >>% MiniML.Id "!") .>>. closeEXP |>> App


let buildList (el,ef)  = 
    let rec go l = match l with 
                       | (e::es) -> App(MiniML.Id "cons", Pair(e,go es))
                       | [] -> C Nil
    go (el @ [ef])

let expList = between (pchar '[' .>> ws) (pchar ']') (many (exp .>>? (ws .>> pchar ';' .>> ws)) .>>. exp .>> ws 
                |>> buildList )

let opOpp : InfixOperator<Exp,unit,unit> list = 
        [
          InfixOperator("*", ws, 7, Associativity.Left, fun x y -> App(MiniML.Id "*",Pair(x,y))); 
          InfixOperator("/", ws, 7, Associativity.Left, fun x y -> App(MiniML.Id "/",Pair(x,y)));
          InfixOperator("+", ws, 6, Associativity.Left, fun x y -> App(MiniML.Id "+",Pair(x,y))); 
          InfixOperator("-", ws, 6, Associativity.Left, fun x y -> App(MiniML.Id "-",Pair(x,y)));
          InfixOperator("::", ws,5, Associativity.Right, fun x y -> App(MiniML.Id "cons",Pair(x,y)));
          InfixOperator("=", ws, 4, Associativity.Left, fun x y -> App(MiniML.Id "=",Pair(x,y)));  
          InfixOperator("<", ws, 4, Associativity.Left, fun x y -> App(MiniML.Id "<",Pair(x,y)));  
          InfixOperator(">", ws, 4, Associativity.Left, fun x y -> App(MiniML.Id ">",Pair(x,y)));  
          InfixOperator("and", ws, 3, Associativity.Right, fun x y -> App(MiniML.Id "and",Pair(x,y))); 
          InfixOperator("or", ws, 2, Associativity.Right, fun x y -> App(MiniML.Id "or",Pair(x,y))); 
          InfixOperator(",", ws,1, Associativity.None, fun x y -> Pair(x,y) )
        ]

let opp = new OperatorPrecedenceParser<Exp,unit,unit>()
let expOp = opp.ExpressionParser
let term = exp <|> betweenPar expOp
opp.TermParser <- term
List.iter (fun x -> opp.AddOperator(x)) opOpp

(*
    Parse une expression close de la forme: expC | expId |  (exp)( )* | [exp]
*)
do closeEXPRef := choice [expC ; expId ; expBang ; betweenPar exp ; expList]  .>> ws


(*
    Assigne le parseur d'application en lambda-calcul. Le parseur parse autant d'expression close que possible.
    Il est impossible que la liste soit vide, du a l'utilisation de many1 qui echoue et retourne s'il n'y a pas
    au moins une valeur.
*)
do expAppRef := many1 closeEXP |>> (function (x::xs) -> List.fold (fun x y -> App(x,y)) x xs | [] -> failwith "Impossible")

(*
    Assigne le parseur d'expression en lambda-calcul. L'ordre des expressions represente leur priorite
*)
do expRef := [expLam;expIf;expLet;expApp] |>  choice


(*
    Parse une expression lambda-calcul au complet. Le eof s'assure qu'il ne reste pas de caractere non parse
*)
let mainExp = expOp .>> eof


(*
    Prends un string et retourne un Exp. Peut leve un message d'erreur en exception si le parsing echoue
*)
let str2exp s = match run mainExp s with
                    | Success(result, _, _)   -> result
                    | Failure(errorMsg, _, _) -> failwith errorMsg

我尝试在expApp解析器之后将它添加到选择列表中,但它只是被忽略了。如果我把它放在closedExp中的expApp之前,它会抛出异常,因为我认为是无限递归。我真的不知道如何混合它。我不想只是给出解决方案,我想知道为什么。另外,FParsec是否有任何重要的大语言例子被解析?

0 个答案:

没有答案