我有我认为世界上最简单的语法,解析dir1 / dir2 / filename形式的文件系统路径(没有前导/)。我已经删除了一些细节,以获得一个展示问题的小样本。
compilationUnit : relativePath;
identifier: IdentifierStart IdentifierPart*;
relativePath : identifier (SLASH identifier)*;
SLASH : '/';
fragment IdentifierPart : 'a'..'z' | 'A'..'Z' | '_' | '0'..'9';
fragment IdentifierStart : 'a'..'z' | 'A'..'Z' | '_';
如果我提供类似foo / aa / bb的东西,我会得到一个MissingTokenException。它标识一个标识符,然后获取SLASH,并且我在标识符上挂起了一个MissingTokenException。必须是我缺少的基本东西,但是什么?
答案 0 :(得分:2)
如果将关键字fragment
放在词法分析器规则之前,则无法在解析器规则中使用此规则。 fragment
只能在其他词法规则中使用。这些规则永远不会成为令牌,它们只能用作其他令牌的一部分(其他词法规则)。
换句话说:从语法中删除这些fragment
个关键字:
// parser rules
compilationUnit : relativePath;
relativePath : identifier (SLASH identifier)*;
identifier : IdentifierStart (IdentifierStart | Digit)*;
// lexer rules
SLASH : '/';
IdentifierStart : 'a'..'z' | 'A'..'Z' | '_';
Digit : '0'..'9';
但是,也可以将相对路径制作为单个标记,在这种情况下,可以保留fragment
关键字,但必须将一些解析器规则放入词法分析器规则,如下所示:
// parser rule
compilationUnit : RelativePath;
// lexer rules
RelativePath : Identifier ('/' Identifier)*;
fragment Identifier : IdentifierStart IdentifierPart*;
fragment IdentifierPart : 'a'..'z' | 'A'..'Z' | '_' | '0'..'9';
fragment IdentifierStart : 'a'..'z' | 'A'..'Z' | '_';
但是,因为RelativePath匹配单个Identifier
,所以永远不会为解析器创建Identifier
标记。因此,Identifier
也应该是fragment
。所以也许这不是你想要的。