ANTLR4 RegEx lexer modes



我正在XSD中为RegEx开发Regx解析器。我之前的问题在这里描述:ANTLR4解析RegEx

自年以来,我已经拆分了Lexer和Parser。现在我在解析括号内的副题时遇到了一个问题。它们应该被视为括号内的字符,而被视为外部的分组标记。这是我的lexer语法:

lexer grammar RegExLexer;
Char    : ALPHA ;
Int     : DIGIT ;
LBrack  : '[' ;//-> pushMode(modeRange) ;
RBrack  : ']' ;//-> popMode ;
LBrace  : '(' ;
RBrace  : ')' ;
Semi    : ';' ;
Comma   : ',' ;
Asterisk: '*' ;
Plus    : '+' ;
Dot     : '.' ;
Dash    : '-' ;
Question: '?' ;
LCBrace : '{' ;
RCBrace : '}' ;
Pipe    : '|' ;
Esc     : '\' ;
WS : [ trn]+ -> skip ;
fragment DIGIT : [0-9] ;
fragment ALPHA : [a-zA-Z] ;

下面是一个例子:

[0-9a-z()]+

我觉得我应该使用括号上的模式来改变ALPHA片段的行为。如果我复制片段,我会得到一个错误,说我不能有两次声明。我已经阅读了关于这方面的参考资料,但我仍然不知道该怎么做。

如何实现这些模式?

以下是如何使用ANTLR4的词法模式创建上下文敏感lexer的快速演示:

lexer grammar RegexLexer;
START_CHAR_CLASS
 : '[' -> pushMode(CharClass)
 ;
START_GROUP
 : '('
 ;
END_GROUP
 : ')'
 ;
PLAIN_ATOM
 : ~[()[]]
 ;
mode CharClass;
END_CHAR_CLASS
 : ']' -> popMode
 ;
CHAR_CLASS_ATOM
 : ~[rn\]]
 | '\' .
 ;

生成lexer后,可以使用以下类对其进行测试:

import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.Token;
public class Main {
    public static void main(String[] args) {
        RegexLexer lexer = new RegexLexer(new ANTLRInputStream("([()\]])"));
        for (Token token : lexer.getAllTokens()) {
            System.out.printf("%-20s %sn", RegexLexer.VOCABULARY.getSymbolicName(token.getType()), token.getText());
        }
    }
}

如果你运行这个Main类,下面的操作将打印到你的控制台:

START_GROUP          (
START_CHAR_CLASS     [
CHAR_CLASS_ATOM      (
CHAR_CLASS_ATOM      )
CHAR_CLASS_ATOM      ]
END_CHAR_CLASS       ]
END_GROUP            )

正如您所看到的,()在字符类外部和在字符类内部的标记方式不同。

您必须在解析器中处理此问题,而不是在lexer中。当lexer看到一个"("时,它将返回令牌LBrace。对于lexer,没有关于在哪里看到令牌的上下文。它只是将输入划分为令牌。您必须定义解析规则,在处理解析树时,您可以确定括号内是否有LBrace

相关内容

  • 没有找到相关文章

最新更新