Совпадение любых печатных буквенных символов в ANTLR4 с Go в качестве цели - PullRequest
0 голосов
/ 10 января 2019

Это меня бесит, я просто не могу найти решение. У меня есть грамматика для поисковых запросов, и я хотел бы соответствовать любому поисковому запросу в запросе, составленном из печатных букв, за исключением специальных символов "(", ")". Строки, заключенные в кавычки, обрабатываются отдельно и работают.

Вот несколько рабочая грамматика:

    /* 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
;

Проблема в том, что searchterm слишком ограничен. Он должен соответствовать любому символу в закомментированном NOT_SPECIAL, то есть, допустимые запросы будут:

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

Но всякий раз, когда я пытаюсь каким-либо образом вставить NOT_SPECIAL в определение searchterm, это не работает. Я пытался вставить это буквально в правило, тоже (комментируя NOT_SPECIAL) и многие другие вещи, но это просто не работает. В большинстве моих попыток грамматика просто жаловалась на посторонний ввод после «=» и говорила, что ожидает EOF. Но я также не могу поместить EOF в NOT_SPECIAL.

Можно ли как-то просто проанализировать каждый текст после "=" в правиле fieldsearch, пока не появится пробел или ")", "("?

N.B. Правило STRING работает нормально, но пользователь не обязан каждый раз использовать кавычки, потому что это инструмент командной строки, и его нужно будет экранировать.

Целевой язык - Go.

1 Ответ

0 голосов
/ 11 января 2019

Вы можете решить эту проблему, введя лексический режим , который вы будете вводить при совпадении с токеном EQ. Находясь в этом лексическом режиме, вы либо сопоставляете (, ) или пробел (в этом случае вы выходите из лексического режима), либо продолжаете сопоставлять свои NOT_SPECIAL символы.

Используя лексические режимы, вы должны определить свои правила лексера и парсера в их собственных файлах. Обязательно используйте lexer grammar ... и parser grammar ... вместо grammar ..., который вы используете в объединенном файле .g4.

Небольшая демонстрация:

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

My 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>
...