我最近在Haskell中一直在研究一种小型矢量控制语言,而且我一直坚持使用解析器。语言的语法基本如下:
1
,3.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
答案 0 :(得分:1)
你看过函数chainl
了吗?它可以用于构造语法中左递归产生的解析器。我相信它应该通过功能应用来解决你的问题。
我现在还没有安装ghc,因此无法测试您的代码。但是,我可以就如何解决问题提供一些通用的指示。
解决方案1:
使用chainl
的解决方案就像:
funApp = chainl1 expr (return App)
其中expr
是表达式解析器,App
是函数应用程序的构造。
解决方案2:
其他可能性是将many
与foldl
结合使用:
funApp = foldl1 App <$> many1 expr
这个想法是many1
将生成expr
和它们的解析结果列表
将使用App
按函数foldl1
合并。
希望他会帮助你。