如何使ANTLR4语法支持转义字符?

时间:2018-01-09 05:13:39

标签: java parsing antlr antlr4

我有以下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)\)'上出错?

谢谢!

3 个答案:

答案 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
实际上,使用片段的唯一优势是,如果您有多个词法分析器规则,在某些时候它们都包含相同的序列(例如'\\' .)。每次您可以将该序列预定义为片段时,不必编写该序列。所以基本上你可以把片段看作一种变量,它包含可以插入词法分析器规则的实际序列。

长话短说:问题已经解决,因为片段不会创建令牌而正常的词法分析器规则会出现。