首页 文章

ANTLR4 RegEx词法分析器模式

提问于
浏览
1

我正在为XSD内的RegEx工作一个Regx解析器 . 我之前的问题在这里被描述:ANTLR4 parsing RegEx

我从那以后拆分了Lexer和Parser . 现在我在解析括号内的parantheses时遇到问题 . 它们应被视为括号内的字符和外部的分组标记 . 这是我的词法分析器语法:

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 : [ \t\r\n]+ -> skip ;

fragment DIGIT : [0-9] ;
fragment ALPHA : [a-zA-Z] ;

这是一个例子:

[0-9a-z()]+

我觉得我应该使用括号上的模式来改变ALPHA片段的行为 . 如果我复制片段,我会收到一条错误消息,说我无法进行两次声明 . 我已经阅读了关于这个的参考资料,但我仍然没有得到我应该做的事情 .

我该如何实施这些模式?

2 回答

  • 2

    你将不得不在解析器中处理它,而不是词法分析器 . 当词法分析器看到一个'(',它将返回令牌LBrace . 对于词法分析器,没有关于令牌在哪里的上下文 . 它只是将输入划分为令牌 . 你必须定义解析规则和处理解析树时,然后你可以确定是否在括号内的LBrace .

  • 3

    这里是一个快速演示如何使用ANTLR4的词法模式创建一个上下文敏感的词法分析器:

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

    生成词法分析器后,您可以使用以下类来测试它:

    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 %s\n", 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            )
    

    如您所见, () 在字符类之外被标记为不同,因为它们位于字符内部 .

相关问题