我正在使用ANTLR4解析魔术卡(org.antlr:antlr4 4-运行时:4.0)。此最小化版本能够解析能力,如Enchant creature
、Enchant black creature
、.以及Protection from creatures
、Protection from legendary creatures
、.
现在我正在尝试启用Protection from black
,这给我带来了问题。
我有以下的lexer和解析器语法,以及一个测试类:
莱克瑟:
lexer grammar OracleLexer;
Black: 'black';
Creature: 'creature';
Creatures: 'creatures';
Enchant: 'enchant';
From: 'from';
Legendary: 'legendary';
Protection: 'protection';
WS: [ \t\f\r\n]+ -> skip;
解析器:
parser grammar OracleParser;
options {
tokenVocab = OracleLexer;
}
line:
keywordAbility EOF;
keywordAbility:
Enchant singularObject #Enchant |
Protection From pluralObject #Protection; // (A)
// Protection From (pluralObject | objectQuality) #Protection; // (B)
singularObject:
objectQuality? Creature;
pluralObject:
objectQuality? Creatures;
objectQuality:
cardtypeQuality+? |
supertypeQuality+ cardtypeQuality*? |
colorQuality+ supertypeQuality* cardtypeQuality*?;
colorQuality:
Black;
supertypeQuality:
Legendary;
cardtypeQuality:
Creature;
考试班:
import static java.util.Arrays.*;
import static java.util.Collections.*;
import java.util.List;
import org.antlr.v4.runtime.*;
public class OracleParserTest {
private static final List<String> ruleNames = unmodifiableList(asList(OracleParser.ruleNames));
public static void main(String[] args) throws Exception {
parse("Enchant creature");
parse("Enchant black creature");
parse("Protection from black");
parse("Protection from black creatures");
}
private static void parse(String ability) throws RecognitionException {
OracleLexer lexer = new OracleLexer(new ANTLRInputStream(ability.toLowerCase()));
lexer.removeErrorListeners();
lexer.addErrorListener(new BailErrorListener());
OracleParser parser = new OracleParser(new CommonTokenStream(lexer));
parser.removeErrorListeners();
parser.setErrorHandler(new BailErrorStrategy());
RuleContext ctx = parser.line();
System.out.println(ctx.toStringTree(ruleNames));
ctx.inspect(ruleNames);
}
}
在解析器中,有一个keywordAbility
规则,在该规则中,我将替代(A)
更改为(B)
,突然之间,我再也无法与Enchant black creature
匹配了。以下是文本形式的所有解析树,如果有帮助的话:
original strings
Enchant creature
Enchant black creature
Protection from black
Protection from black creatures
parse trees variant (A)
(line (keywordAbility enchant (singularObject creature)) <EOF>)
(line (keywordAbility enchant (singularObject (objectQuality (colorQuality black)) creature)) <EOF>)
does not parse - expected
(line (keywordAbility protection from (pluralObject (objectQuality (colorQuality black)) creatures)) <EOF>)
parse trees variant (B)
(line (keywordAbility enchant (singularObject creature)) <EOF>)
does not parse - problem!
(line (keywordAbility protection from (objectQuality (colorQuality black))) <EOF>)
(line (keywordAbility protection from (pluralObject (objectQuality (colorQuality black)) creatures)) <EOF>)
下面是Enchant black creature
的堆栈跟踪
Exception in thread "main" org.antlr.v4.runtime.misc.ParseCancellationException
at org.antlr.v4.runtime.BailErrorStrategy.recover(BailErrorStrategy.java:51)
at net.slightlymagic.laterna.oracle.grammar.OracleParser.objectQuality(OracleParser.java:462)
at net.slightlymagic.laterna.oracle.grammar.OracleParser.singularObject(OracleParser.java:235)
at net.slightlymagic.laterna.oracle.grammar.OracleParser.keywordAbility(OracleParser.java:161)
at net.slightlymagic.laterna.oracle.grammar.OracleParser.line(OracleParser.java:79)
at net.slightlymagic.laterna.oracle.grammar.OracleParserTest.parse(OracleParserTest.java:49)
at net.slightlymagic.laterna.oracle.grammar.OracleParserTest.main(OracleParserTest.java:35)
Caused by: org.antlr.v4.runtime.NoViableAltException
at org.antlr.v4.runtime.atn.ParserATNSimulator.noViableAlt(ParserATNSimulator.java:1532)
at org.antlr.v4.runtime.atn.ParserATNSimulator.execATNWithFullContext(ParserATNSimulator.java:816)
at org.antlr.v4.runtime.atn.ParserATNSimulator.execATN(ParserATNSimulator.java:701)
at org.antlr.v4.runtime.atn.ParserATNSimulator.predictATN(ParserATNSimulator.java:389)
at org.antlr.v4.runtime.atn.ParserATNSimulator.adaptivePredict(ParserATNSimulator.java:346)
at net.slightlymagic.laterna.oracle.grammar.OracleParser.objectQuality(OracleParser.java:440)
... 5 more
我如何获得语法来解析这种能力(同样如此),为什么它不能正常工作呢?
(我尝试删除BailErrorStrategy,这使它工作,但也导致90%的魔术能力解析为假阳性,并没有解释为什么这一能力以前起作用。BailErrorStrategy是否完全干扰回溯?)
发布于 2014-10-01 06:07:12
ANTLR 4不使用回溯(运行时库实际上不包含任何形式的此类功能代码)。
我无法在这条消息的末尾使用测试来重现这个结果。我的猜测是以下原因之一造成了这个问题:
BailErrorStrategy
添加到你的雷克萨斯。它从未打算以这种方式使用。相反,按照my other answer中的建议将语法错误完全推迟到解析器。测试用例:
@Test
public void testCardParsing() throws Exception {
String grammar =
"grammar Oracle;\n" +
"\n" +
"line @init{setErrorHandler(new BailErrorStrategy());} @after {System.out.println($ctx.toStringTree(this));} :\n" +
" keywordAbility EOF;\n" +
"\n" +
"keywordAbility:\n" +
" Enchant singularObject #Enchant |\n" +
"// Protection From pluralObject #Protection; // (A)\n" +
" Protection From (pluralObject | objectQuality) #Protection; // (B)\n" +
"\n" +
"singularObject:\n" +
" objectQuality? Creature;\n" +
"\n" +
"pluralObject:\n" +
" objectQuality? Creatures;\n" +
"\n" +
"objectQuality:\n" +
" cardtypeQuality+? |\n" +
" supertypeQuality+ cardtypeQuality*? |\n" +
" colorQuality+ supertypeQuality* cardtypeQuality*?;\n" +
"\n" +
"colorQuality:\n" +
" Black;\n" +
"\n" +
"supertypeQuality:\n" +
" Legendary;\n" +
"\n" +
"cardtypeQuality:\n" +
" Creature;\n" +
"\n" +
"Black: 'black';\n" +
"Creature: 'creature';\n" +
"Creatures: 'creatures';\n" +
"Enchant: 'enchant';\n" +
"From: 'from';\n" +
"Legendary: 'legendary';\n" +
"Protection: 'protection';\n" +
"\n" +
"WS: [ \\t\\f\\r\\n]+ -> skip;";
String input = "enchant creature";
String found = execParser("Oracle.g4", grammar, "OracleParser", "OracleLexer", "line", input, true);
assertEquals("(line (keywordAbility enchant (singularObject creature)) <EOF>)\n", found);
assertNull(stderrDuringParse);
input = "enchant black creature";
found = execParser("Oracle.g4", grammar, "OracleParser", "OracleLexer", "line", input, false);
assertEquals("(line (keywordAbility enchant (singularObject (objectQuality (colorQuality black)) creature)) <EOF>)\n", found);
assertNull(stderrDuringParse);
input = "protection from black";
found = execParser("Oracle.g4", grammar, "OracleParser", "OracleLexer", "line", input, false);
assertEquals("(line (keywordAbility protection from (objectQuality (colorQuality black))) <EOF>)\n", found);
assertNull(stderrDuringParse);
input = "protection from black creatures";
found = execParser("Oracle.g4", grammar, "OracleParser", "OracleLexer", "line", input, false);
assertEquals("(line (keywordAbility protection from (pluralObject (objectQuality (colorQuality black)) creatures)) <EOF>)\n", found);
assertNull(stderrDuringParse);
}
https://stackoverflow.com/questions/26142835
复制