繁体   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