数字和十六进制的 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.

有没有办法解决这个问题,或者我只是将 sizecrc 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 模式有点不优雅。 很酷,但要带行李。