Правила ANTLR для выражения всех символов, кроме этих - PullRequest
1 голос
/ 18 сентября 2011

Вопрос новичка.Скажем, у меня есть правило лексера, просто перечисляющее все приемлемые символы:

ACCEPTED_SYMBOLS:   ('~' |'!' |'@' |'#' |'$' |'%' |'^' |'\-' |'\+' | '=' |
                  '\\'|':' |'\"'|'\''|'<' |'>' |',' |'.' |'?' | '/'  ) ;

Но иногда я хочу другое правило, которое принимает все символы, кроме, скажем, '='

 ACCEPTED_SYMBOLS_EXCEPT_EQUAL: ('~' |'!' |'@' |'#' |'$' |'%' |'^' |'\-' |'\+' | 
                      '\\'|':' |'\"'|'\''|'<' |'>' |',' |'.' |'?' | '/'  ) ;

В основномя просто повторяю список без '='.

Но это звучит как глупый способ определения токенов.Что, если я получил еще один ACCEPTED_SYMBOLS_EXCEPT_HASH / COLON / и т. Д.

Можно ли написать правило синтаксического анализатора, которое получает соответствующие символы на основе ACCEPTED_SYMBOLS?Семантический предикат звучит как выбор, но я новичок в ANTLR и не знаю, как его использовать.

1 Ответ

2 голосов
/ 18 сентября 2011

Допустим, внутри вашего a правила все ACCEPTED_SYMBOLS символы действительны, но внутри правила b = недействительно.

Вы можете сделать это, используя предикат , например:

a
  :  ACCEPTED_SYMBOLS
  ; 

b
  :  t=ACCEPTED_SYMBOLS {!$t.text.equals("=")}?
  ;

ACCEPTED_SYMBOLS
  :  '~'  | '!' | '@' | '#'  | '$' | '%' | '^' | '-' | '+' | '=' |
     '\\' | ':' | '"' | '\'' | '<' | '>' | ',' | '.' | '?' | '/' 
  ;

Обратите внимание, что в грамматике ANTLR необходимо экранировать только одинарные кавычки и обратную косую черту внутри буквенной строки.

Или без предиката:

a
  :  any
  ; 

b
  :  SYMBOLS
  ;

any
  :  SYMBOLS 
  |  EQ
  ;

SYMBOLS
  :  '~'  | '!' | '@' | '#'  | '$' | '%' | '^' | '-' | '+' |
     '\\' | ':' | '"' | '\'' | '<' | '>' | ',' | '.' | '?' | '/' 
  ;

EQ
  :  '='
  ;

EDIT

Обратите внимание, что вы не можете определить правила в следующем порядке:

ACCEPTED_SYMBOLS:   ('~' |'!' |'@' |'#' |'$' |'%' |'^' |'-' |'+' | '=' |
                  '\\'|':' |'"'|'\''|'<' |'>' |',' |'.' |'?' | '/'  ) ;

ACCEPTED_SYMBOLS_EXCEPT_EQUAL: ('~' |'!' |'@' |'#' |'$' |'%' |'^' |'-' |'+' | 
                      '\\'|':' |'"'|'\''|'<' |'>' |',' |'.' |'?' | '/'  ) ;

ANTLR выдаст ошибку, что токен ACCEPTED_SYMBOLS_EXCEPT_EQUAL никогда не может быть создан, поскольку предыдущие правила уже будут соответствовать всему, что ACCEPTED_SYMBOLS_EXCEPT_EQUAL может соответствовать.

И если вы измените правила:

ACCEPTED_SYMBOLS_EXCEPT_EQUAL: ('~' |'!' |'@' |'#' |'$' |'%' |'^' |'-' |'+' | 
                      '\\'|':' |'"'|'\''|'<' |'>' |',' |'.' |'?' | '/'  ) ;

ACCEPTED_SYMBOLS:   ('~' |'!' |'@' |'#' |'$' |'%' |'^' |'-' |'+' | '=' |
                  '\\'|':' |'"'|'\''|'<' |'>' |',' |'.' |'?' | '/'  ) ;

тогда правило ACCEPTED_SYMBOLS может совпадать только с '='. Все остальные персонажи будут маркированы как ACCEPTED_SYMBOLS_EXCEPT_EQUAL токены.

Вы должны понимать, что лексер работает независимо от парсера: он просто создает токены, следуя правилам лексера сверху вниз, пытаясь найти максимально возможное совпадение, и ему все равно, что парсер в это время пытается чтобы соответствовать.

...