我正在为libretro数据文件编写一个解析器。这是我第一次使用antlr语法和解析器,所以请原谅我缺乏最佳实践。
但是,antlr是多么的酷,真不敢相信让我走到这一步是那么简单:)
game (
name "10-Yard Fight (World, set 1)"
year "1983"
developer "Irem"
rom ( name 10yard.zip size 62708 crc 8f401426 md5 040dc0827e184b8da9b91499f96c1fce sha1 8b15a2e54e9fdded3d61205bac6535ccc7b41271 )
)我的语法是:
grammar Datafile;
game: GAME LP
gameBody+
RP;
gameBody: gameName
| year
| developer
| rom+
;
rom: ROM LP
size
| crc
| md5
| serial
| sha1
RP;
size: SIZE NUMBER;
crc: CRC HEX;
md5: MD5 HEX;
sha1: SHA1 HEX;
serial: SERIAL STRING;
gameName: NAME STRING;
year: YEAR STRING;
developer: DEVELOPER STRING;
//keywords
GAME: 'game';
ROM: 'rom';
NAME: 'name';
YEAR: 'year';
DEVELOPER: 'developer';
SIZE: 'size';
CRC: 'crc';
MD5: 'md5';
SHA1: 'sha1';
SERIAL: 'serial';
LP: '(';
RP: ')';
STRING : '"' ( '\\"' | . )*? '"';
WS : [ \t\r\n\u000C]+ -> skip;
NUMBER: DIGIT+ ([.,] DIGIT+)?;
HEX: [a-fA-F0-9]+;
fragment LETTER: [A-Za-z];
fragment DIGIT: [0-9];因此,我并不是非常严格地通过使用通用字符串规则来捕获年份/开发人员之类的内容,因为有时日期是数据集中的字符串,我会在解析器逻辑上处理它们。
但我遇到了十六进制值的问题。因为它们不像在某些语言中那样通过0x前缀进行转义。发生的情况是,如果我有一个crc 0001100,那么解析器会将其捕获为NUMBER而不是HEX。
有没有办法解决这个问题,或者我只是把size和crc sha1 md5都映射成十六进制,然后在解析器上处理解析逻辑?
我遇到的另一个问题是试图找出如何捕获文件名(rom -> name),它可以是任何有效的文件名,但我无法编写捕获它的规则。
希望任何人都能加入进来:)
发布于 2021-11-03 02:08:11
如果没有一些十六进制数字的特殊语法,Lexer将无法识别它们。你只知道一些东西应该被上下文解释为十六进制数字。解析器规则为您提供上下文。
所以:
hexNumber: HEX | NUMBER;
crc: CRC hexNumber;
md5: MD5 hexNumber;
sha1: SHA1 hexNumber;现在,您的解析树中将有一个HexNumberContext,并且您将知道如何解释它。
你也可以这样做:
crc: CRC ( HEX | NUMBER)您可以同时尝试这两种方法,并查看生成的解析树和上下文类,看看您更喜欢哪一种。
发布于 2021-11-17 19:02:53
我认为您可以使用LEXER模式强制将数字解析为十六进制数字。我对词法分析器模式不太满意,因为我还是一个ANTLR4新手,但我想到了这样的东西:
CRC : 'crc' ->pushMode(HexOnly);
MD5 : 'md5' ->pushMode(HexOnly);
SHA1: 'sha1' ->pushMode(HexOnly);
...
mode HexOnly;
HEX1: [a-fA-F0-9]+ ->popMode;
... any other HexOnly mode thing在示例中,我使用了HEX1,因为我发现当我拥有不可改变的模式时,我有一个令牌类型,它也在其他地方使用,并且由于我仍然在学习"ANTLR4“,所以我将以自己的方式来实现一个解决方案,直到我学到一个优雅的解决方案。
我发现到目前为止,Lexer模式还不够优雅。很酷,但带着行李来。
https://stackoverflow.com/questions/69818123
复制相似问题