以 Go 为目标匹配 ANTLR4 中任何可打印的类字母字符

Match any printable letter-like characters in ANTLR4 with Go as target

这把我吓坏了,我就是找不到解决办法。我有一个搜索查询的语法,并且想匹配由可打印字母组成的查询中的任何搜索词,特殊字符“(”,“)”除外。引号中的字符串被单独处理并起作用。

这是一个有点工作的语法:

    /* ANTLR Grammar for Minidb Query Language */

grammar Mdb;

start
    : searchclause EOF
    ;

searchclause
    : table expr
    ;

expr
    : fieldsearch
    | searchop fieldsearch
    | unop expr
    | expr relop expr
    | lparen expr relop expr rparen
    ;

lparen
    : '('
    ;

rparen
    : ')'
    ;

unop
    : NOT
    ;

relop
    : AND
    | OR
    ;

searchop
    : NO
    | EVERY
    ;

fieldsearch
    : field EQ searchterm
    ;

field
    : ID
    ;

table
    : ID
    ;

searchterm
    : 
    | STRING
    | ID+
    | DIGIT+
    | DIGIT+ ID+ 
    ;

STRING
    : '"' ~('\n'|'"')* ('"' )
    ;

AND
    : 'and'
    ;

OR
    : 'or'
    ;

NOT
    : 'not'
    ;
NO
    : 'no'
    ;

EVERY
    : 'every'
    ;

EQ
    : '='
    ;

fragment VALID_ID_START
    : ('a' .. 'z') | ('A' .. 'Z') | '_'
    ;

fragment VALID_ID_CHAR
    : VALID_ID_START | ('0' .. '9')
    ;

ID
    : VALID_ID_START VALID_ID_CHAR*
    ;

DIGIT
    : ('0' .. '9')
    ;

/*
NOT_SPECIAL
    : ~(' ' | '\t' | '\n' | '\r' | '\'' | '"' | ';' | '.' | '=' | '(' | ')' )
    ; */

WS
   : [ \r\n\t] + -> skip
;

问题是搜索词太受限制了。它应该匹配注释掉的 NOT_SPECIAL 中的任何字符,即有效查询将是:

Person Name=%
Person Address=^%Street%%%$^&*@^

但是每当我尝试以任何方式将 NOT_SPECIAL 放入 searchterm 的定义中时,它都不起作用。我也尝试过将它按字面意思放入规则中(注释掉 NOT_SPECIAL)和许多其他内容,但它就是行不通。在我的大多数尝试中,语法只是抱怨“=”之后的无关输入,并表示它期待 EOF。但我也不能将 EOF 放入 NOT_SPECIAL.

有什么方法可以简单地解析规则字段搜索中“=”之后的每个文本,直到出现空格或“)”、“(”?

N.B。 STRING 规则工作正常,但不应要求用户每次都使用引号,因为这是一个命令行工具,需要对其进行转义。

目标语言是 Go。

你可以通过引入一个 lexical mode 来解决这个问题,每当你匹配一个 EQ 标记时你就会输入它。一旦进入该词法模式,您要么匹配 () 或空格(在这种情况下您会跳出词法模式),要么继续匹配您的 NOT_SPECIAL 字符。

通过使用词法模式,您必须在自己的文件中定义词法分析器和解析器规则。请务必使用 lexer grammar ...parser grammar ... 而不是您在组合 .g4 文件中使用的 grammar ...

快速演示:

lexer grammar MdbLexer;

STRING
 : '"' ~[\r\n"]* '"'
 ;

OPAR
 : '('
 ;

CPAR
 : ')'
 ;

AND
 : 'and'
 ;

OR
 : 'or'
 ;

NOT
 : 'not'
 ;

NO
 : 'no'
 ;

EVERY
 : 'every'
 ;

EQ
 : '=' -> pushMode(NOT_SPECIAL_MODE)
 ;

ID
 : VALID_ID_START VALID_ID_CHAR*
 ;

DIGIT
 : [0-9]
 ;

WS
 : [ \r\n\t]+ -> skip
 ;

fragment VALID_ID_START
 : [a-zA-Z_]
 ;

fragment VALID_ID_CHAR
 : [a-zA-Z_0-9]
 ;

mode NOT_SPECIAL_MODE;

  OPAR2
   : '(' -> type(OPAR), popMode
   ;

  CPAR2
   : ')' -> type(CPAR), popMode
   ;

  WS2
   : [ \t\r\n] -> skip, popMode
   ;

  NOT_SPECIAL
   : ~[ \t\r\n()]+
   ;

您的解析器语法将像这样开始:

parser grammar MdbParser;

options {
    tokenVocab=MdbLexer;
}

start
 : searchclause EOF
 ;

// your other parser rules

我的 Go 有点生疏,但是一个小 Java 测试:

String source = "Person Address=^%Street%%%$^&*@^()";

MdbLexer lexer = new MdbLexer(CharStreams.fromString(source));

CommonTokenStream tokens = new CommonTokenStream(lexer);
tokens.fill();

for (Token t : tokens.getTokens()) {
  System.out.printf("%-15s %s\n", MdbLexer.VOCABULARY.getSymbolicName(t.getType()), t.getText());
}

打印以下内容:

ID              Person
ID              Address
EQ              =
NOT_SPECIAL     ^%Street%%%$^&*@^
OPAR            (
CPAR            )
EOF             <EOF>