Antlr 从lexer跳过WS时编写对空格敏感的解析器规则
我在处理空白方面遇到了一些问题。在以下语法摘录中,我设置了lexer,以便解析器跳过空白:Antlr 从lexer跳过WS时编写对空格敏感的解析器规则,antlr,grammar,antlr4,Antlr,Grammar,Antlr4,我在处理空白方面遇到了一些问题。在以下语法摘录中,我设置了lexer,以便解析器跳过空白: ENTITY_VAR : 'user' | 'resource' ; INT : DIGIT+ | '-' DIGIT+ ; ID : LETTER (LETTER | DIGIT | SPECIAL)* ; ENTITY_ID : '__' ENTITY_VAR ('_w_' ID)?; NEWLINE : '\r'? '\n'; WS : [ \t\r\n]+ ->
ENTITY_VAR
: 'user'
| 'resource'
;
INT : DIGIT+ | '-' DIGIT+ ;
ID : LETTER (LETTER | DIGIT | SPECIAL)* ;
ENTITY_ID : '__' ENTITY_VAR ('_w_' ID)?;
NEWLINE : '\r'? '\n';
WS : [ \t\r\n]+ -> skip; // skip spaces, tabs, newlines
fragment LETTER : [a-zA-Z];
fragment DIGIT : [0-9];
fragment SPECIAL : ('_' | '#' );
问题是,我想匹配形式为ENTITY\u ID
的变量名称,这样匹配的字符串就不会有任何空格。正如我在这里所做的那样,将其作为一个lexer规则编写就足够了,但问题是我想用一个解析器规则来代替它,因为我想从我的代码中直接访问这两个标记ENTITY\u VAR
和ID
,而不是将它们压缩成一个完整的标记ENTITY\u ID
有什么想法吗?
基本上,任何允许我直接访问
ENTITY\u VAR
和ID
的解决方案都适合我,不管是将ENTITY\u ID
作为lexer规则,还是将其移动到解析器。就我通过浏览文档了解到的情况来看,这样的解决方案似乎不可行
解析器规则似乎只在默认通道上工作,因此我不能将WS
发送到channel(HIDDEN)
,然后仅为单个解析器规则恢复它
另一方面,antlr的一位作者指出,自版本4以来,不可能分解任何令牌
尽管我一点也不喜欢它,但似乎最快的方法是从lexer解析它(如问题中的代码),然后从Java重新解析整个字符串
尽管如此,对我的结论的任何其他更好的选择或更正都是受欢迎的。正如您自己的答案所暗示的,在某种管道中连接两个解析器是一种合理而简单的设计/解决方案,我非常确信ANTLR能够帮助实现这一点 我不知道ANTLR人员在流/源解析方面做了多少工作。但是,采用两次传递策略应该足够有效,因为第一次传递仅仅是对一种常规语言进行词法分析,即在输入的大小上使用非常小的
c
,即O(c*N)
如果你想要一个单程,代价是<代码> o(k*n)(用一个大k),你可以考虑,其中有(我没有尝试过)。
有几种方法我可以想到(不是按一个特殊的顺序):实体\u ID
发出多个令牌。寻找灵感实体\u ID
标记,并将它们拆分为几个其他标记,然后将此流传递给解析器实体ID
部分(=>是错误)内(=>忽略错误)INVALID_ENTITY_ID : '__' WS+ ENTITY_VAR WS? ('_w_' WS? ID)?
| '__' WS? ENTITY_VAR WS+ ('_w_' WS? ID)?
| '__' WS? ENTITY_VAR WS? ('_w_' WS+ ID)
;
这将捕获无效的实体\u ID
s,因为它比将成为单个令牌的部分长如果在“无错误”的情况下,2不会改变解析,也就是说,没有代码会因为允许空白而有不同的解释。可能会有帮助吗?一旦你无意中发现了
“\uuuu”
,你就可以切换不跳过空格的模式了?谢谢你的建议。因此,如果我理解正确,我会编写一个解析器规则entityVar
,这样当匹配“\uuuuu”
时,它会切换到禁用WS
lexer规则的模式?Ops,我的意思是entityId
,而不是Var
lexer模式不依赖于解析器规则。每当lexer匹配“\uuuuu”
,它都会切换模式,不管是否有解析器规则实际使用“\uuuuuu”
标记。您能给出一些示例输入代码和您想要的吗?谢谢,但是我将用这个解决方案解析的字符串非常小,使用任何类型的库都肯定是一种过度使用。我对如何再次解析实体\u ID
不感兴趣,而是通过使用Antlr:)的单次传递来完全避免它。最后,我选择了选项3。其他的每一个选项都涉及到对语法进行太多复杂的修改,在这种情况下,这些修改根本不值得。通过从java代码中通过正则表达式再次解析它,我能够保持语法简单明了。