【问题标题】:I am trying to parse a simple expression but it has an infinite loop我正在尝试解析一个简单的表达式,但它有一个无限循环
【发布时间】:2016-05-09 17:49:36
【问题描述】:

我想解析这样的语言

foo = (bar, bar1 = (bar2 = bar4), bar5)

我写了一个简单的解析器

module SimpleParser where
import Text.Parsec.String (Parser)
import Text.Parsec.Language (emptyDef)
import Text.Parsec
import qualified Text.Parsec.Token as Tok
import Text.Parsec.Char
import Prelude

lexer :: Tok.TokenParser ()
lexer = Tok.makeTokenParser style
  where
    style = emptyDef {
              Tok.identLetter    = alphaNum
             }

parens :: Parser a -> Parser a
parens = Tok.parens lexer

commaSep :: Parser a -> Parser [a]
commaSep = Tok.commaSep lexer

identifier :: Parser String
identifier = Tok.identifier lexer

reservedOp :: String -> Parser ()
reservedOp = Tok.reservedOp lexer

data Expr = Ident String | Label String Expr | ExprList [Expr] deriving (Eq, Ord, Show)

parseExpr :: String -> Either ParseError Expr
parseExpr s = parse expr "" s

expr :: Parser Expr
expr = parens expr
      <|> try exprList
      <|> ident
ident :: Parser Expr
ident = do
  var <- identifier
  return $ Ident var

exprLabel :: Parser Expr
exprLabel = do
  var <- identifier
  reservedOp "="
  body <- expr
  return $ Label var body

exprList :: Parser Expr
exprList = do
  list <- commaSep (try exprLabel <|> expr)
  return $ ExprList list

但即使使用以下简单输入,它也有一个无限循环:

test = parseExpr "foo = bar"

有人可以解释为什么它不起作用以及如何解决它吗?

【问题讨论】:

  • 这种讨厌的行为通常与语法上的左递归有关。我没有足够的时间检查,但我相信使用chainlchainr 会有所帮助。稍后,我会检查您的代码并尝试修复。

标签: parsing haskell text-parsing parsec


【解决方案1】:

问题是,在您的代码中,exprList 如果尝试 解析一个标识符,即parse exprList "" "foo" 进入 一个无限循环。这是因为它试图将其解析为列表 标签或表达式,表达式可以是列表。一次 它不是exprLabel 它试图查看它是否可以是expr 等等 它再次调用exprList

要修复它,您需要确保 expr 检查两者是否存在 exprLabelidentifier 在尝试 exprList 之前。请注意,如果 以上所有失败它仍然会进入一个循环。这是因为它不知道这是否只是列表的开始(或列表列表的列表......)。

要解决此问题,您可以让expr 仅在匹配parens 时调用exprList,并使用exprList 作为起始Parser

expr :: Parser Expr
expr = parens (exprList)
      <|> try exprLabel
      <|> ident

exprList :: Parser Expr
exprList = do
  list <- commaSep expr
  return $ ExprList list

它的工作原理是这样的:

>parse exprList  "" "(foo=bar),foo=bar"
  Right (ExprList [ExprList [Label "foo" (Ident "bar")],Label "foo" (Ident "bar")])

【讨论】:

  • Note that if all the above fails it will still infinitely.有什么办法可以防止吗?
  • @ais ,抱歉,我忘了删除 exprList 作为 expr 的选项。它现在不应该循环。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-22
  • 2013-10-22
  • 2021-09-17
  • 2019-07-03
  • 2021-10-05
相关资源
最近更新 更多