Bir alıştırma olarak, aşağıdaki GADT'yi kullanarak Haskell'de tanımlanan son derece basit bir dil için bir ayrıştırıcı uygulayacağım (projem için gerçek dilbilgisi birçok ifadeyi içerir, ancak bu özüt yeterlidir sorusuna) için: aşağıdaki gibiTemel İfade Ayrıştırıcısındaki Sol Özyineyi Kaldırma
data Expr a where
I :: Int -> Expr Int
Add :: [Expr Int] -> Expr Int
ayrıştırma fonksiyonları şunlardır: nedeniyle kullanıyorum 1+1
kadar basit bir şeyi ayrıştırmak girişiminde ifade dilbilgisi sol özyinelemeli yapısı nedeniyle
expr :: Parser (Expr Int)
expr = foldl1 mplus
[ lit
, add
]
lit :: Parser (Expr Int)
lit = I . read <$> some digit
add :: Parser (Expr Int)
add = do
i0 <- expr
is (== '+')
i1 <- expr
is <- many (is (== '+') *> expr)
pure (Add (i0:i1:is))
expr
ayrıştırıcı, ayrıştırıcı sonsuz bir döngüde sıkışmış olsun.
: gibi bir şey içine
S -> S a | b
:
S -> b T
T -> a T
Ama birlikte mücadele ediyorum Bunu çözümleyicime nasıl uygularım.
newtype Parser a = Parser
{ runParser :: String -> [(a, String)]
}
instance Functor Parser where
fmap f (Parser p) = Parser $ \s ->
fmap (\(a, r) -> (f a, r)) (p s)
instance Applicative Parser where
pure a = Parser $ \s -> [(a, s)]
(<*>) (Parser f) (Parser p) = Parser $ \s ->
concat $ fmap (\(f', r) -> fmap (\(a, r') -> (f' a, r')) (p r)) (f >
instance Alternative Parser where
empty = Parser $ \s -> []
(<|>) (Parser a) (Parser b) = Parser $ \s ->
case a s of
(r:rs) -> (r:rs)
[] -> case b s of
(r:rs) -> (r:rs)
[] -> []
instance Monad Parser where
return = pure
(>>=) (Parser a) f = Parser $ \s ->
concat $ fmap (\(r, rs) -> runParser (f r) rs) (a s)
instance MonadPlus Parser where
mzero = empty
mplus (Parser a) (Parser b) = Parser $ \s -> a s ++ b s
char = Parser $ \case (c:cs) -> [(c, cs)]; [] -> []
is p = char >>= \c -> if p c then pure c else empty
digit = is isDigit
Sen 'attoparsec' kullanarak yerine kendi ayrıştırma çerçeve haddeleme düşünebilirsiniz, https://en.m.wikipedia.org/wiki/Operator-precedence_parser – dfeuer
Ayrıca bakmak isteyebilirsiniz. – dfeuer
@dfeuer, ama daha sonra alıştırmanın amacını kaçırmış oluruz! Bu operatör önceliği, iyi bir çözüm gibi gözüküyor olsa da .. İdeal olarak bu özyineli soy ayrıştırıcısıyla çalışabiliriz. –