ANTLR4 RegEx词法分析器模式

时间:2015-12-11 17:55:15

标签: regex antlr4

我正在为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 个答案:

答案 0 :(得分: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            )

正如您所看到的,()在字符类之外被标记化,因为它们位于字符内部。

答案 1 :(得分:2)

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