数字和十六进制的 Antlr 规则
Antlr rule for numbers and hex
我正在为 libretro datfiles 编写解析器。这是我的第一个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];
所以我不是非常严格地通过使用通用字符串规则来捕获 year/developer 之类的东西,因为有时日期是数据集中的字符串,我将在解析器逻辑上处理它们。
但是我遇到了十六进制值的问题。因为它们不像某些语言那样通过 0x
前缀转义。发生的事情是,如果我有一个 crc 0001100
那么解析器将其捕获为 NUMBER
而不是 HEX
.
有没有办法解决这个问题,或者我只是将 size
和 crc sha1 md5
都映射为十六进制并处理解析器上的解析逻辑?
我遇到的另一个问题是试图弄清楚如何捕获文件名(rom -> 名称),它可以是任何有效的文件名,但我无法编写捕获它的规则。
希望任何人都可以插话:)
如果没有一些特殊的十六进制数语法,词法分析器将无法识别它们。你只知道某些东西应该被上下文解释为十六进制数。解析器规则为您提供上下文。
所以:
hexNumber: HEX | NUMBER;
crc: CRC hexNumber;
md5: MD5 hexNumber;
sha1: SHA1 hexNumber;
现在您的解析树中将有一个 HexNumberContext,并且知道如何解释它。
你也可以这样做:
crc: CRC ( HEX | NUMBER)
您可以尝试两者并查看生成的解析树和上下文 类 以了解您更喜欢哪个。
我在想您可以使用 LEXER 模式来强制将数字解析为十六进制数字。我对 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 模式有点不优雅。
很酷,但要带行李。
我正在为 libretro datfiles 编写解析器。这是我的第一个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];
所以我不是非常严格地通过使用通用字符串规则来捕获 year/developer 之类的东西,因为有时日期是数据集中的字符串,我将在解析器逻辑上处理它们。
但是我遇到了十六进制值的问题。因为它们不像某些语言那样通过 0x
前缀转义。发生的事情是,如果我有一个 crc 0001100
那么解析器将其捕获为 NUMBER
而不是 HEX
.
有没有办法解决这个问题,或者我只是将 size
和 crc sha1 md5
都映射为十六进制并处理解析器上的解析逻辑?
我遇到的另一个问题是试图弄清楚如何捕获文件名(rom -> 名称),它可以是任何有效的文件名,但我无法编写捕获它的规则。
希望任何人都可以插话:)
如果没有一些特殊的十六进制数语法,词法分析器将无法识别它们。你只知道某些东西应该被上下文解释为十六进制数。解析器规则为您提供上下文。
所以:
hexNumber: HEX | NUMBER;
crc: CRC hexNumber;
md5: MD5 hexNumber;
sha1: SHA1 hexNumber;
现在您的解析树中将有一个 HexNumberContext,并且知道如何解释它。
你也可以这样做:
crc: CRC ( HEX | NUMBER)
您可以尝试两者并查看生成的解析树和上下文 类 以了解您更喜欢哪个。
我在想您可以使用 LEXER 模式来强制将数字解析为十六进制数字。我对 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 模式有点不优雅。 很酷,但要带行李。