tl; dr :我正在努力寻找需要使用nom进行前瞻的文本解析器的文档或示例。
长版
我使用nom来解析6502程序集。我正在努力创建一个可以解析各种寻址模式的解析器。任何给定的操作码都具有以下格式:
XXX AM
其中XXX
是三字符助记符,AM
是操作数。操作数可以采用多种形式,称为"寻址模式。"我已经定义了操作数的枚举,寻址模式的枚举,以及包含这些值的OpCode
元组结构,这最终是解析时返回的结果。
寻址模式可以完全省略,在这种情况下寻址模式为Implied
,它的文字值可以是A
,这是Accumulator
寻址模式。
许多寻址模式都是指存储器位置,而这些寻址模式是我努力解析的。特别是,如果寻址模式以$00
的形式指定单个字节,则它是ZeroPage
寻址模式,而指定$0000
形式的两个字节的操作数是{ {1}}寻址模式。为了使问题复杂化,这些寻址模式的索引变体以Absolute
,$00,X
,$00,Y
等形式出现。
现有的文本解析器是否有一些很好的例子可以说明解析所有类似值($0000,X
)的值的正确方法,但它们是如何结束的? nom文档不是很全面,我发现的最好的例子是INI解析器,它没有做任何像我试图完成的那样复杂的事情。我也查看了syn源代码,但它使用了很多自定义宏,并且是一个非常复杂的野兽,这使得它很难学习。
答案 0 :(得分:2)
执行此操作的一种方法是使用alt!()
宏。
这个想法是有一个解析器,它按顺序尝试每个替代方案。因此,如果您已经分别为每种寻址模式分配了解析器,则可以将它们组合成任何解析器:
// The sub-parsers all return Operand too.
named!(parse_operand<&str, Operand>,
alt!(parse_absolute_indexed |
parse_absolute |
parse_zeropage_indexed |
parse_zeropage |
parse_implied));
一些注意事项:
parse_absolute
放在parse_absolute_indexed
之后,因为前者会与操作数的初始部分匹配并且返回得太早。alt_complete!()
而不是alt!()
。这样做的原因是,如果您尝试匹配ADD $00
,可能与ADD $0000
匹配的解析器必须假设如果有更多输入到达它仍然匹配,并且alt!()
将不会跳过到下一个案例。使用alt_complete!()
,或者在complete!()
中包装内部匹配器,就是说不完整匹配是不匹配的。如果解析器非常复杂,那么可能意味着要做一些额外的工作(按顺序尝试每个解析),而不是像例如古老的yacc
生成的解析器,但我不认为这是一个问题。