我有以下ANTLR4语法来解释正则表达式。
// Regular Expression Grammar.
grammar RegExpr;
program : expr EOF # Root
;
expr : TERM # TermNode
| expr '?' # OptionalNode
| '(' expr ')' # OrdinaryNode
| expr expr # ConcatNode
| expr '|' expr # OrNode
;
ESC : '\\' . ;
TERM : ([a-zA-Z0-9,.*^+\-&'":><#![\]] | ESC)+ ;
WS : [ \t\r\n]+ -> skip ; // skip spaces, tabs, newlines
然而,当我尝试解析字符串文字'\\('在Java中,我得到了
第1:0行在输入'\('
时没有可行的选择
我想将带有'\\'前缀的任何字符视为终端。例如,'\\(','\\)','\\\\','\\ X'被视为终端。
最后,我想解析'\(a。(b | c)\)'为
'\(a。'(b | c)'\)'
表示'\(a.b \)'和'\(a.c \)'。然后我可以删除所有'\'以获得'(a.b)'和'(a.c)'。
任何人都可以请指出为什么上面的语法会在'\\('和'\(a。(b | c)\)'上出错?
谢谢!
答案 0 :(得分:0)
行。我不知何故可以用
修复语法fragment ESC : '\\' . ;
不确定这里究竟发生了什么。
答案 1 :(得分:0)
由于ESC
不是原始语法中的片段,并且在语法文件中高于TERM
,因此只要lexer匹配TERM
,它就优先于\.
而且不再是。
答案 2 :(得分:0)
原始问题已经有了答案(使用fragment
),但我认为仍然缺乏理解。所以这里有一个解释:
在ANTLR词法分析器中,规则按照语法中指定的顺序进行处理。因此,ANTLR将从第一个规则开始,并尝试它是否可以匹配当前输入字符序列。如果它可以创建令牌并且该过程重新开始。如果它不能查询下一个词法分析器规则。
在您的示例ESC
之前指定了TERM
。因此,ANTLR会尝试将输入与ESC
匹配,然后才会尝试将其与TERM
匹配。因此,输入\.
将始终匹配为单个ESC
令牌,只有以下字符(不再与ESC
匹配)才会与TERM
匹配。
通过将ESC
定义为片段,您告诉ANTLR ESC
本身并不是词法分析器规则。因此,不会要求它匹配字符inputStream。片段只是可重用的部分,可用于组合实际的词法分析器规则,因此语法中第一个声明(和参考)的词法分析器规则变为TERM
。
实际上,使用片段的唯一优势是,如果您有多个词法分析器规则,在某些时候它们都包含相同的序列(例如'\\' .
)。每次您可以将该序列预定义为片段时,不必编写该序列。所以基本上你可以把片段看作一种变量,它包含可以插入词法分析器规则的实际序列。
长话短说:问题已经解决,因为片段不会创建令牌而正常的词法分析器规则会出现。