2017-05-11 2 views
0

ラムダ計算に基づいたプログラミング言語のパーサを作成しています。中置演算子とその優先順位を追加しますが、パーサーが負の優先順位に関するエラーでクラッシュします。私は手でオペレータの解析を行うことができますが、私は優先権を得ることができないようです。だから、私はOperatorPrecedenceParserを使うことを学ぶかもしれない。OperatorPrecedenceParserは、私が持っていない負の優先順位に関する例外をスローします。

負の優先順位がないため、なぜクラッシュするのかわからないため、コードを表示します。ここで

言語AST

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"; 
     ","; 
     "::" 
    ] 

は、パーサそのものです。パーサーコンビネータ(そして解析)で初めてのことですので、何かがひどく間違っていたら、私は知りたいと思います。それ以外の場合は、なぜそれが十分な音を鳴らすのか知っているだけです。

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 

答えて

0

あなたのサンプルコードはexpOpbinOpが含まれていないので、完全ではないようです。最後の2行を使わずにコードを実行すると、OPPはArgumentOutOfRangeExceptionに "演算子の優先順位は0より大きくなければならない"というメッセージをスローします。カンマ演算子が追加されたとき。問題は、カンマ演算子の優先順位として0を指定したことです。

このような問題は、Visual Studioなどの完全に統合されたデバッガでIDEを使用すると診断しやすくなります。

+0

expOpとbinOpでは重要ではありません。私はそれらを消すのを忘れた。彼らは私が作ろうとした手巻きの優先パーサのためのものです。私はメッセージに関して例外について知っていた。私は0が有効な優先順位だと思った。 docは言う:値は常により大きいゼロです。行方不明よりもありますか? – ZelteHonor

+0

はい、ドキュメント内のテキストが「より大きい」を欠いています。それを指摘してくれてありがとう!私はあなたがゼロが許容された値だと思うようになったのは不思議です。 「より大きい(ゼロ)」を「非負」と解釈しましたか? (私が0を許可したいと思っていたら、 "0以上"と書いていたでしょう) –

+0

私はそれをすばやく読みました。私はそれが間違っていることを正確には知らない。それは、私がよく書くような数学者に慣れているからかもしれません。厳密に0より大きい。 – ZelteHonor

関連する問題