Haskell 带分隔符的Parsec置换解析器
我想解析汇编程序。我有一个用于解析汇编地址的固定格式:Haskell 带分隔符的Parsec置换解析器,haskell,parsec,Haskell,Parsec,我想解析汇编程序。我有一个用于解析汇编地址的固定格式:[register+offset+label]我实现了寄存器、偏移量和标签的解析器。现在我想创建一个解析器来解析整个地址 我想要接受的组合: [register] [offset] [label] [register + offset] [register + label] [offset + label] [register + offset + label] [] [register offset] [register + ] ...
[register+offset+label]
我实现了寄存器、偏移量和标签的解析器。现在我想创建一个解析器来解析整个地址
我想要接受的组合:
[register]
[offset]
[label]
[register + offset]
[register + label]
[offset + label]
[register + offset + label]
[]
[register offset]
[register + ]
...
我不想接受的是:
[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 ...
choice$try(parseRegister>=\r->Address(只是r)Nothing Nothing)
尝试
但它是丑陋的,不能与更多类型的元素很好地匹配。所以我在寻找一种更清洁的解决方案。类似的:
parsePlus = many1 (char ' ') >> char '+' >> many1 (char ' ')
parseRegisterModified = parsePlus >> parseOffsetLabel
parseOffsetModified = parsePlus >> parseLabel
parseRegister' = do
Address r _ _ <- parseRegister
optionMaybe parseRegisterModified >>=
return $ maybe
(Address r Nothing Nothing)
(\Address _ o l -> Address r o l)
parseOffset' = do
Address _ o _ <- parseOffset
optionMaybe parseOffsetModified >>=
return $ maybe
(Address Nothing o Nothing)
(\Address _ _ l -> Address Nothing o l)
parseOffsetLabel = try parseOffset' <|> parseLabel
parseAddress =
try parseRegister'
<|> parseOffset'
<|> parseLabel
parsePlus=many1(字符“”)>>char'+'>>many1(字符“”)
parseRegisterModified=parsePlus>>parseOffsetLabel
parseOffsetModified=parsePlus>>parseLabel
解析寄存器'=do
地址r\uu>=
返回$maybe
(地址r Nothing Nothing)
(\Address\uo l->Address r o l)
parseOffset'=do
地址uo>=
返回$maybe
(无地址或无地址)
(\Address\uuul->Address Nothing o o l)
parseOffsetLabel=尝试parseOffset的parseLabel
解析地址=
尝试解析寄存器'
parseOffset'
解析标签
使用Monoids
和sepBy1
可以得到更优雅的解决方案
但它允许编写[寄存器+寄存器]
(在我们的例子中,将两者相加)
如果对表格重新排序,您会看到一系列选项:
[register + offset + label]
[register + offset ]
[register + label]
[register ]
[ offset + label]
[ offset ]
[ label]
可以编写的语法:
address = '[' (register ('+' offset-label)? | offset-label) ']'
offset-label = offset ('+' label)? | label
在应用程序风格中,它非常简单,通过将所有内容包装在构造函数中只会产生轻微的噪音:
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
]
我们可以稍微清理一下这些实现:
parseRegisterOffsetLabel = choice
[ (,)
<$> just parseRegister
<*> option (Nothing, Nothing) (plus parseOffsetLabel)
, (,) Nothing <$> parseOffsetLabel
]
parseOffsetLabel = choice
[ (,)
<$> just parseOffset
<*> option Nothing (plus (just parseLabel))
, (,) Nothing <$> just parseLabel
]
parseRegisterOffsetLabel=选项
[ (,)
只需解析寄存器
选项(无,无)(加上parseOffsetLabel)
,(,)无解析OffsetLabel
]
parseOffsetLabel=choice
[ (,)
只是解析偏移量
选项Nothing(加上(仅解析标签))
,(,)没什么,只是解析标签
]
然后考虑重复,为我们提供一个体面的最终解决方案:
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)
parseChain begin def rest=choice
[(,)刚刚开始选项def(加上rest)
没有什么可以休息
]
parseRegisterOffsetLabel=parseChain
parseRegister(无,无)parseOffsetLabel
parseOffsetLabel=parseChain
parseOffset Nothing(仅parseLabel)
我会让你处理
+
周围和[]
内部的空白,我一直在寻找类似的内容,并找到了
. 虽然我的案例可以独立于低级平台进行扩展
在你的情况下可能看起来像
operand = do
(r, o, l) <- runPermsSep (char '+') $ (,,)
<$> maybeAtom register
<*> maybeAtom offset
<*> maybeAtom label
-- backtrack on inappropriate combination
when (null $ catMaybes [r, o, l]) . fail $ "operand expected"
return (r, o, l)
操作数=do
(r、o、l)一个轻量级技巧是使用Applicative
样式和optionMaybe
。像这样试试$Address optionMaybe parseRegister optionMaybe parseOffset optionMaybe parseLabel
。这也适用于一元格式。但我的主要问题是我必须解析那些签名!这些是文本字符串。您可能想使用sebby
获取字符串列表,然后从中计算地址
值?谢谢。它似乎是正确的解析器,但它是一个重量级的解决方案。这很有趣,但允许[register+register]
是不可接受的。不错。我做了一些修改以适应我的问题。我所做的编辑:我在前面创建了一个tuple::Parser a->Parser b->Parser(a,b)
combinator并使用了它,因此不需要使用应用程序
和
。使用符号“+”
处理空白。偏移量(0偏移量)和寄存器(始终为0的$0寄存器)都有默认值,所以我使用它们而不是什么都不使用。@BoldizárNémeth:很高兴能提供帮助。我只能提供一个通用的解决方案,因为我不知道您的数据类型。
operand = do
(r, o, l) <- runPermsSep (char '+') $ (,,)
<$> maybeAtom register
<*> maybeAtom offset
<*> maybeAtom label
-- backtrack on inappropriate combination
when (null $ catMaybes [r, o, l]) . fail $ "operand expected"
return (r, o, l)