簡體   English   中英

將語法生成翻譯成Parsec

[英]Translate grammar production to Parsec

我正在嘗試轉換以下語法生成

callExpr:
    primaryExpr
  | callExpr primaryExpr

到Haskell中的Parsec表達式。

顯然問題是它是左遞歸的,所以我試圖解析它的遞歸 - 上升風格。 我試圖實現的偽代碼是:

e = primaryExp
while(true) {
    e2 = primaryExp
    if(e2 failed) break;
    e = CallExpr(e, e2)
}

我試圖將其翻譯成Haskell是:

callExpr :: IParser Expr
callExpr = do
    e <- primaryExpr
    return $ callExpr' e
  where
    callExpr' e = do
        e2m <- optionMaybe primaryExpr
        e' <- maybe e (\e2 -> callExpr' (CallExpr e e2)) e2m
        return e'

其中primaryExpr類型為IParser Expr ,IParser的定義為

type IParser a = ParsecT String () (State SourcePos) a

但是這會給我以下類型錯誤:

Couldn't match type `ParsecT String () (State SourcePos) t0'
              with `Expr'
Expected type: ParsecT String () (State SourcePos) Expr
  Actual type: ParsecT
                 String
                 ()
                 (State SourcePos)
                 (ParsecT String () (State SourcePos) t0)
In a stmt of a 'do' block: return $ callExpr' e
In the expression:
  do { e <- primaryExpr;
       return $ callExpr' e }
In an equation for `callExpr':
    callExpr
      = do { e <- primaryExpr;
             return $ callExpr' e }
      where
          callExpr' e
            = do { e2m <- optionMaybe primaryExpr;
                   .... }

如何修復此類錯誤?

使用chainl1 chainl1 p op以左關聯方式解析由op -s分隔的一個或多個p -s。 op返回一個二元函數,用於將兩側的p -s結果合並為一個結果。

由於你的語法似乎沒有分隔符,你可以使用帶有只返回組合函數的op chainl1

callExpr :: IParser Expr
callExpr = chainl1 primaryExpr (return CallExpr)

至於你的callExpr實現,我可以發現兩個錯誤。

首先,你使用return $ callExpr' e ,但callExpr' e已經是一個callExpr' e值,所以只需callExpr' e就是正確的。

其次,在maybe e (\\e2 -> callExpr' (CallExpr e e2)) e2m ,默認的e應該是maybe e (\\e2 -> callExpr' (CallExpr e e2)) e2m (或者我們怎么能將它綁定到e' ?),所以應該return e

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM