首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >OperatorPrecedenceParser抛出我没有的负优先级异常

OperatorPrecedenceParser抛出我没有的负优先级异常
EN

Stack Overflow用户
提问于 2017-05-11 23:25:30
回答 1查看 39关注 0票数 0

我正在为基于lambda演算的编程语言创建一个解析器。我添加了一个infix操作符和它们的优先级,但是解析器出现了一个关于负优先级的错误。我能够手工解析操作符,但似乎不能正确地获得优先级。所以我想我还是学习使用OperatorPrecedenceParser吧。

我将展示代码,因为我不知道为什么会崩溃,因为我没有任何负优先级。

语言AST

代码语言:javascript
复制
module MiniML
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"; 
      ","; 
      "::"
    ]

下面是解析器本身。这是我第一次使用解析器组合器(和解析),所以如果有什么严重的错误,我想知道。否则,只要知道它坠毁的原因就够了。

代码语言:javascript
复制
open MiniML
open FParsec

let ws = spaces

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

let keyword : Parser<string,unit> = ["false";"true";"let";"end";"in";"if";"then";"else";"lam"] |> List.map pstring |> choice

let fstId = asciiLetter <|> pchar '_'

let restId = fstId <|> digit <|> pchar '''

let betweenPar p = between (pchar '(' .>> ws) (pchar ')' .>> ws) p

let cstB = (stringReturn "true"  (B true)) <|> (stringReturn "false" (B false))

let cstI = puint32 |>> (int >> I)

let cstU = stringReturn "()" Unit

let cstN = stringReturn "[]" Nil

let expC : Parser<Exp,unit> = cstB <|> cstI <|> cstU <|> cstN  |>> C

let expIdStr = notFollowedByL keyword "Cannot use keyword as variable" >>. 
                    notFollowedByL operator "Cannot use operator as variable" >>. 
                        many1CharsTill2 fstId restId (notFollowedBy restId)

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

let exp, expRef = createParserForwardedToRef<Exp, unit>()

let expApp, expAppRef = createParserForwardedToRef<Exp, unit>()

let expLam : Parser<Exp,unit> = (pstring "lam" >>. ws >>. expIdStr .>> ws .>> pchar '.') .>> ws .>>. exp |>> Lam

let expLet = tuple3 (pstring "let" >>. ws >>. expIdStr .>> ws .>> pchar '=' .>> ws) (exp .>> ws .>> pstring "in" .>> ws) (exp .>> ws .>> pstring "end") |>> Let

let expIf = tuple3 (pstring "if" >>. ws >>. exp .>> ws) (pstring "then" >>. ws >>. exp .>> ws) (pstring "else" >>. ws >>. exp) |>> If

let closeEXP, closeEXPRef = createParserForwardedToRef<Exp, unit>()

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 )

do closeEXPRef := choice [expC ; expId ; expBang ; betweenPar exp ; expList]  .>> ws

do expAppRef := many1 closeEXP |>> (function (x::xs) -> List.fold (fun x y -> App(x,y)) x xs | [] -> failwith "Impossible")

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

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

do expRef := [expLam;expIf;expLet;expApp] |>  choice |> (fun p -> p .>>. opt (expOp operator) |>> binOp )

let mainExp = expr .>> eof
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-05-12 00:02:14

您的示例代码似乎不完整,因为不包括expOpbinOp。当我在没有最后两行的情况下运行您的代码时,OPP抛出一个带有“运算符优先级必须大于0”的消息的ArgumentOutOfRangeException。添加逗号运算符时。问题是您指定0作为逗号运算符的优先级。

当您使用IDE和Visual等完全集成的调试器时,这样的问题更容易诊断。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43927098

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档