出于好奇,我正在学习ANTLR,特别是4,我正在尝试创建一个简单的语法。我选择了NES (Nintentdo娱乐系统)游戏精灵文件,这是第一次尝试。比方说,这里是“侏罗纪公园”在互联网上找到的一个游戏精灵文件样本:
GZUXXKVS Infinite ammo on pick-up
PAVPAGZE More bullets picked up from small dinosaurs
PAVPAGZA Fewer bullets picked up from small dinosaurs
GZEULOVK Infinite lives--1st 2 Levels only
ATVGZOSA Immune to most attacks
VEXASASA + VEUAXASA 3-ball bolas picked up
NEXASASA + NEUAXASA Explosive multi-shots这是我正在研究的语法。
grammar NesGameGenie;
all: lines EOF;
lines: (anyLine? EOL+)* anyLine?;
anyLine: codeLine;
codeLine: code;
code: CODE (PLUS? CODE)*;
CODE: SHORT_CODE | LONG_CODE;
fragment SHORT_CODE: FF FF FF FF FF FF;
fragment LONG_CODE: FF FF FF FF FF FF FF FF;
fragment FF: [APZLGITYEOXUKSVN];
COMMENT: COMMENT_START NOEOL -> skip;
COMMENT_START: [#;];
EOL: '\r'? '\n';
PLUS: '+';
WS: [ \t]+ -> skip;
fragment NOEOL: ~[\r\n]*;它的篇幅短得可笑,而且很简单,但它仍然有两个问题,我可以看到:
line 1:16 token recognition error at: 'In'这样的识别错误,因为语法中没有提供描述规则。#符号添加到描述中可能会导致忽略行尾的其余部分。至少,AAAAAA Player #1 ammo只报告了Player和#1 ammo,但我认为一旦引入了描述规则,它就可以修复。我以前添加描述规则的尝试导致了许多不同的错误,我已经找到了一个非错误的解决方案,但仍然不是一个很好的解决方案:
...
codeLine: code description?;
...
description: PRINTABLE+;
...
PRINTABLE: [\u0020-\uFFFE];
...不幸的是,每个字符都被解析为一个PRINTABLE,而我正在寻找的是一个description规则,用于匹配行(或文件)的末尾(或文件),包括空格,但在左和右进行裁剪。如果我将+添加到PRINTABLE的末尾,则整个文档被视为无效。我猜想PRINTABLE可能在某种程度上安全地与description规则相关联,但是description: ('\u0020' .. '\uFFFE')+;捕获的更多。
应该如何声明description规则,让它捕获代码之后的行尾的所有字符,但只在左和右裁剪空白空间([ \t])?简单地说,我将有一个语法,它将解析为类似的内容(包括#字符,而不是将其解析为注释):
code=..., description="Infinite ammo on pick-up"
code=..., description="More bullets picked up from small dinosaurs"
code=..., description="Fewer bullets picked up from small dinosaurs"
code=..., description="Infinite lives--1st 2 Levels only"
code=..., description="Immune to most attacks"
code=..., description="3-ball bolas picked up"
code=..., description="Explosive multi-shots"还有一点,我用的是:
发布于 2016-10-20 17:11:01
其实很容易,只需使用lexer模式。一旦你击中了某些标记,就改变模式。
这里是词法语法,解析器基于这个语法很容易(文件名是NesGameGenieLexer.g4):
lexer grammar NesGameGenieLexer;
CODE: [A-Z]+;
WS : [ ]+ -> skip, mode(COMMENT_MODE);
mode COMMENT_MODE;
PLUS: '+' (' ')* -> mode(DEFAULT_MODE);
fragment ANY_CHAR: [a-zA-Z_/0-9=.\-\\ ];
COMMENT: ANY_CHAR+;
NEWLINE: [\r\n] -> skip, mode(DEFAULT_MODE);我认为+不可能在评论中。如果您使用ANTLRWorks lexer调试器,您可以看到所有令牌类型和令牌模式很好地突出显示。
下面是解析器语法(文件名为NesGameGenieParser.g4):
parser grammar NesGameGenieParser;
options {
tokenVocab=NesGameGenieLexer;
}
file: line+;
line : code comment
| code PLUS code comment;
code: CODE;
comment: COMMENT;在这里,我假设CODE只是PLUS之前的一组字符,但很明显,这很容易更改:)
发布于 2016-10-21 02:34:44
在整个不眠之夜中,我的睡眠时间大大减少,我似乎已经成功地编写了lexer和解析器语法。不需要解释太多,请参阅源代码中的注释,所以简单地说:
雷克萨斯:
lexer grammar NesGameGenieLexer;
COMMENT: [#;] ~[\r\n]+ [\r\n]+ -> skip;
CODE: (SHORT_CODE | LONG_CODE) -> mode(CODE_FOUND_MODE);
fragment SHORT_CODE: FF FF FF FF FF FF;
fragment LONG_CODE: FF FF FF FF FF FF FF FF;
fragment FF: [APZLGITYEOXUKSVN];
WS: [\t ]+ -> skip;
mode CODE_FOUND_MODE;
PLUS: [\t ]* '+' [\t ]* -> mode(DEFAULT_MODE);
// Skip inline whitespaces and switch to the description detection mode.
DESCRIPTION_LEFT_DELIMITER: [\t ]+ -> skip, mode(DESCRIPTION_FOUND_MODE);
NEW_LINE_IN_CODE_FOUND_MODE: [\r\n]+ -> skip, mode(DEFAULT_MODE);
mode DESCRIPTION_FOUND_MODE;
// Greedily grab all non-CRLF characters and ignore trailing spaces - this is a trimming operation equivalent, I guess.
DESCRIPTION: ~[\r\n]*~[\r\n\t ]+;
// But then terminate the line and switch to the code detection mode.
// This operation is probably required because the `DESCRIPTION: ... -> mode(CODE_FOUND_MODE)` seems not working
NEW_LINE_IN_DESCRIPTION_FOUND_MODE: [\r\n]+ -> skip, mode(DEFAULT_MODE);解析器:
parser grammar NesGameGenieParser;
options {
tokenVocab = NesGameGenieLexer;
}
file
: line+
;
line
: code description?
| code (PLUS code)* description?
;
code
: CODE
;
description
: DESCRIPTION
;它看起来比我想的要复杂得多,但它似乎完全符合我的要求。另外,我也不确定上面的语法是否写得很好,是否很地道。感谢@cantSleepNow给出了模式的想法。
https://stackoverflow.com/questions/40159157
复制相似问题