我使用ANTLR4来解析用Yarn编写的文本冒险游戏对话文件,所以大部分都是自由格式的文本和大量的孤岛语法,而且大部分内容都很顺利但是我有一个问题排除Shortcut
模式中的某些文字(当呈现供玩家选择的选项时)。
基本上我需要编写规则来匹配除#
,换行符或<<
之外的任何内容。当它到达<<
时,它需要进入一种新模式来处理各种表达式,或者只是离开当前模式,以便<<
将被现有规则选中。
我的词法分析器的缩减版本(忽略表达式规则):
lexer grammar YarnLexer;
NEWLINE : ('\n') -> skip;
CMD : '<<' -> pushMode(Command);
SHORTCUT : '->' -> pushMode(Shortcut);
HASHTAG : '#' ;
LINE_GOBBLE : . -> more, pushMode(Line);
mode Line;
LINE : ~('\n'|'#')* -> popMode;
mode Shortcut ;
TEXT : CHAR+ -> popMode;
fragment CHAR : ~('#'|'\n'|'<');
mode Command ;
CMD_EXIT : '>>' -> popMode;
// RULES FOR OPERATORS/IDs/NUMBERS/KEYWORDS/etc
CMD_TEXT : ~('>')+ ;
解析器语法(再次忽略表达式的所有规则):
parser grammar YarnParser;
options { tokenVocab=YarnLexer; }
dialogue: statement+ EOF;
statement : line_statement | shortcut_statement | command_statement ;
hashtag : HASHTAG LINE ;
line_statement : LINE hashtag? ;
shortcut_statement : SHORTCUT TEXT command_statement? hashtag?;
command_statement : CMD expression CMD_EXIT;
expression : CMD_TEXT ;
我已经测试了命令模式,当它本身和内部的所有内容都正常工作时,但是当我尝试解析我的示例输入时:
Where should we go?
-> the park
-> the zoo
-> Peter's house <<if $metPeter == true >>
ok shall we take the bus?
-> :<
-> ok
<<set $daySpent = true>>
我的问题是这一行:
-> Peter's house <<if $metPeter == true >>
完全匹配为TEXT,并且CMD规则被更长的TEXT忽略了。
我的第一个想法是将<
添加到集合中,但之后我无法使用以下文字:
-> :<
应该是完全有效的。知道怎么做吗?
答案 0 :(得分:0)
将单个左尖括号添加到排除列表会创建一个易于处理的单角案例:
TEXT : CHAR+ ;
CMD : '<<' -> pushMode(Command);
LAB : '<' -> type(TEXT) ;
fragment CHAR : ~('\n' | '#' | '<') ;