小语言解析陷入循环

时间:2016-03-13 19:09:19

标签: parsing haskell parsec

我最近在Haskell中一直在研究一种小型矢量控制语言,而且我一直坚持使用解析器。语言的语法基本如下:

  • 所有数字都是浮点数。可接受的语法为13.7-8.等。
  • 矢量以逗号分隔并括在括号中
  • 变量是单个字符或用大括号括起来的多个字符(即[1, 7, -3.2][x,y]
  • 功能应用程序是左关联的,由两个相邻的表达式表示(即f[1,2,3]{reduce}+0[9,3-7]
  • 忽略空格

在BNF(如果有错误,我道歉;我不经常使用BNF):

<expr> ::= <parens> | <app> | <var> | <num> | <vect>
<subexpr> ::= <parens> | <var> | <num> | <vect>

<parens> ::= "(" <spaces> <expr> <spaces> ")"
<app> ::= <expr> <spaces> <subexpr>
<var> ::= "{" <varchars> "}" | <varchar>
<num> ::= ...
<vect> ::= "[" <spaces> <commasep> <spaces> "]"

<spaces> ::= <spaces> " " | ""
<varchar> ::= "A" | "B" | ... | "a" | "b" | ... | "!" | "@" | ...
<varchars> ::= <varchars> <varchar> | <varchar>
<commasep> ::= <commasep> <spaces> "," <spaces> <expr> | <expr>

在我尝试添加函数应用程序之前一切正常,然后解析器陷入无限循环,即使输入字符串只是一个数字。我假设它与funcApp解析器的第一行有关,但我不确定如何修复它。任何帮助表示赞赏。

(为简单起见,我已经排除了评估者并简化了'Expression.hs',但是'Parse.hs'和Expression数据类型非常相似)

Parse.hs:

module Parse
       (
       ) where

import Data.Functor
import Control.Applicative
import qualified Data.Vector as Vec
import Text.Parsec hiding (many, optional, (<|>))

import Expression (Expression)
import qualified Expression as Expr

expr :: Parsec [Char] u Expression
expr = try (funcApp <* eof) <|>
       (subexpr <* eof)

subexpr = try var  <|>
          try numLit <|>
          vectLit


numLit = do
  s <- option 1 (char '-' *> return (-1))
  a <- some digit
  b <- option "0" (char '.' *> many digit)
  let x = sum $ zipWith (*) [10**x | x <- [0,1..]]
          $ map (read . (:[])) $ reverse a
  let y = sum $ zipWith (*) [10**x | x <- [-1,-2..]]
          $ map (read . (:[])) b
  return $ Expr.Number $ s * (x + y)

vectLit = do
  char '[' ; spaces
  xs <- expr `sepBy` (spaces *> char ',' <* spaces)
  spaces ; char ']'
  return $ Expr.Vector $ Vec.fromList xs

var = fmap Expr.Variable $
      ((:[]) <$> oneOf cs) <|> (char '{' *> many (oneOf cs) <* char '}')
  where cs = ['A'..'Z'] ++ ['a'..'z'] ++ "!@#$%^&*_+~-=,./<>?|;:"

funcApp = do
  a <- expr
  spaces
  b <- subexpr
  return $ Expr.FunctionApplication a b

Expression.hs

module Expression
       (
         Expression(..)
       ) where

data Expression = Number               Float
                | Vector               (Vector Expression)
                | PrimitiveFunction    (Expression -> Expression)
                | Function             Expression Expression
                | Variable             String
                | FunctionApplication  Expression Expression
                | Error                String

1 个答案:

答案 0 :(得分:1)

你看过函数chainl了吗?它可以用于构造语法中左递归产生的解析器。我相信它应该通过功能应用来解决你的问题。

我现在还没有安装ghc,因此无法测试您的代码。但是,我可以就如何解决问题提供一些通用的指示。

解决方案1:

使用chainl的解决方案就像:

funApp = chainl1 expr (return App) 

其中expr是表达式解析器,App是函数应用程序的构造。

解决方案2:

其他可能性是将manyfoldl结合使用:

funApp = foldl1 App <$> many1 expr 

这个想法是many1将生成expr和它们的解析结果列表 将使用App按函数foldl1合并。

希望他会帮助你。

相关问题