gpt4 book ai didi

haskell - 带分隔符的秒差距置换解析器

转载 作者:行者123 更新时间:2023-12-04 02:49:28 24 4
gpt4 key购买 nike

我想解析汇编程序。我有一个解析程序集地址的固定格式:[register + offset + label ] 我为寄存器、偏移量和标签实现了解析器。现在我想创建一个解析整个地址的解析器。

我想接受的组合:

[register]
[offset]
[label]
[register + offset]
[register + label]
[offset + label]
[register + offset + label]

还有我不想接受的:

[]
[register offset]
[register + ]
...

当然,简单的解决方案是:

choice $ try (parseRegister >>= \r -> Address (Just r) Nothing Nothing)
<|> try ...

但它很丑陋,并且不能很好地适应更多类型的元素。所以我正在寻找更清洁的解决方案。

最佳答案

如果您重新排序您的表,您会看到它是一系列的选择:

[register + offset + label]
[register + offset ]
[register + label]
[register ]
[ offset + label]
[ offset ]
[ label]

可能编写的语法:

address      = '[' (register ('+' offset-label)? | offset-label) ']'
offset-label = offset ('+' label)? | label

这在 Applicative 风格中非常简单,通过将所有内容包装在构造函数中只会产生轻微的噪音:

parseAddress :: Parser Address
parseAddress = do
(register, (offset, label)) <- between (char '[') (char ']') parseRegisterOffsetLabel
return $ Address register offset label

parseRegisterOffsetLabel :: Parser (Maybe Register, (Maybe Offset, Maybe Label))
parseRegisterOffsetLabel = choice
[ (,)
<$> (Just <$> parseRegister)
<*> option (Nothing, Nothing) (char '+' *> parseOffsetLabel)
, (,) Nothing <$> parseOffsetLabel
]

parseOffsetLabel :: Parser (Maybe Offset, Maybe Label)
parseOffsetLabel = choice
[ (,)
<$> (Just <$> parseOffset)
<*> option Nothing (char '+' *> (Just <$> parseLabel))
, (,) Nothing . Just <$> parseLabel
]

如果我们添加几个实用函数:

plus :: Parser a -> Parser a
plus x = char '+' *> x

just :: Parser a -> Parser (Maybe a)
just = fmap Just

我们可以稍微清理一下这些实现:

parseRegisterOffsetLabel = choice
[ (,)
<$> just parseRegister
<*> option (Nothing, Nothing) (plus parseOffsetLabel)
, (,) Nothing <$> parseOffsetLabel
]

parseOffsetLabel = choice
[ (,)
<$> just parseOffset
<*> option Nothing (plus (just parseLabel))
, (,) Nothing <$> just parseLabel
]

然后排除重复,给我们一个像样的最终解决方案:

parseChain begin def rest = choice
[ (,) <$> just begin <*> option def (plus rest)
, (,) Nothing <$> rest
]

parseRegisterOffsetLabel = parseChain
parseRegister (Nothing, Nothing) parseOffsetLabel

parseOffsetLabel = parseChain
parseOffset Nothing (just parseLabel)

我会让你处理 + 周围和 [] 内部的空白。

关于haskell - 带分隔符的秒差距置换解析器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18081493/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com