2010-01-31 4 views
5

У меня есть то, что я считаю простым вопросом ANTLR. У меня есть два типа токенов: ident и special_ident. Я хочу, чтобы мой special_ident соответствовал одной букве, за которой следовала одна цифра. Я хочу, чтобы общий ident соответствовал одной букве, необязательно сопровождаемой любым количеством букв или цифр. Мой (неправильно) грамматика ниже:Как мой лексер ANTLR может соответствовать токену из символов, которые являются подмножествами другого вида токена?

expr 
    : special_ident 
    | ident 
    ; 

special_ident : LETTER DIGIT; 
ident   : LETTER (LETTER | DIGIT)*; 

LETTER : 'A'..'Z'; 
DIGIT : '0'..'9'; 

Когда я пытаюсь проверить эту грамматику, я получаю это предупреждение:

Решение может соответствовать ввода, такие как «БУКВА ЦИФРА» с использованием нескольких альтернатив: 1, 2. в результате, альтернативные (s) 2 были отключены для этого входа

Я понимаю, что моя грамматика неоднозначна, и что ввод таких как A1 может соответствовать либо ident или special_ident. Я просто хочу, чтобы special_ident использовался в самых узких случаях.

Вот некоторые ввода пробы и то, что я хотел бы, чтобы соответствовать:

A  : ident 
A1  : special_ident 
A1A : ident 
A12 : ident 
AA1 : ident 

Как я могу сформировать свою грамматику так, что я правильно определить два моих типов идентификаторов?

ответ

2

Развивая мысли Карла, я думаю у вас есть четыре различных случая:

  1. AA (A | N) *
  2. (A | N) +

только оп 2 должно быть токеном special_ident, а остальные три должны быть идентичными. Все токены можно идентифицировать только по синтаксису. Вот быстрая грамматика, которую я смог протестировать в ANTLRWorks, и, похоже, она работала правильно для меня. Я думаю, что у Карла может быть одна ошибка при попытке проверить АА, но получение на 99% огромной выгоды, так что это лишь незначительная модификация его быстрой мысли.

prog 
    : (expr WS)+ EOF; 

expr 
    : special_ident {System.out.println("Found special_ident:" + $special_ident.text + "\n");} 
    | ident {System.out.println("Found ident:" + $ident.text + "\n");} 
    ; 

special_ident : LETTER DIGIT; 

ident   : LETTER 
    |LETTER DIGIT (LETTER|DIGIT)+ 
    |LETTER LETTER (LETTER|DIGIT)*; 

LETTER : 'A'..'Z'; 
DIGIT : '0'..'9'; 
WS 
    : (' '|'\t'|'\n'|'\r')+; 
+0

Спасибо ... Я думаю, что все это имеет смысл. последний вариант в 'ident' redundant? Разве «LETTER LETTER» не станет эквивалентным всем правилом? Кроме того, было бы эквивалентно для всего правила сказать «ПИСЬМО ПИСЬМА?| ПИСЬМО ЦИФРА (ПИСЬМО DIGIT) + '? –

+0

Есть несколько разных способов, которыми вы можете иметь правила (я думаю), я просто убедился, что LETTER DIGIT имеет другую букву или цифру после того, как отделил ее от правила special_ident. Опция LETTER LETTER не требует больше токенов. Вот почему у одного есть знак плюса, а у другого есть звездочка. – WayneH

3

Кажется, что у вас есть 3 случая:

  • A
  • AN
  • A(A|N)(A|N)+

Вы могли бы классифицировать средний как special_ident, а два других в качестве ident; Кажется, это должно сделать трюк.

Я немного ржавый с ANTLR, надеюсь, этого намека достаточно. Я могу попытаться выписать выражения для вас, но они могут быть неправильно:

long_ident : LETTER (LETTER | DIGIT) (LETTER | DIGIT)+ 
special_ident : LETTER DIGIT; 
ident   : LETTER | long_ident;