Правило вашего парсера:
oneToHundred
: ('1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9')
| ('1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9')('0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9')
| '100'
;
неявно создает следующие токены за кулисами:
D_1_9 : ('1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9');
D_0_9 : ('0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9');
D_100 : '100';
(не с этими именами правил, но содержимое, которому они соответствуют , создано )
Таким образом, если ваш лексер получит входные данные "11"
, будут созданы два токена D_1_9
и альтернатива 2 nd из правила oneToHundred
не сможет быть сопоставлена (эта альтернатива нужны два жетона: D_1_9 D_0_9
).
Вы должны понимать, что лексер работает независимо от парсера. Неважно, какой токен синтаксический анализатор «запрашивает» у лексера: у лексера есть свои собственные приоритеты, в результате чего '1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9'
никогда не будет соответствовать правилу D_0_9
(потому что он приходит после правило D_1_9
.
EDIT
Давайте назовем ваш ввод, 11;2102;34%;P11o
, четырьмя единицами, состоящими из atoms
(где atom
- буква или цифра), возможно, оканчивающихся на '%'
:
unit
: atoms '%'?
;
Если оно заканчивается '%'
, вы просто используете правило перезаписи для создания дерева с PERCENT
в качестве корня, в противном случае просто создайте дерево с SYMBOL
в качестве корня:
unit
: (atoms -> ^(/* SYMBOL */)) ('%' -> ^( /* PERCENT */))?
;
Рабочая демоверсия:
grammar T;
options {
output=AST;
ASTLabelType=CommonTree;
}
tokens {
ROOT;
SYMBOL;
PERCENT;
NUMBER;
}
parse
: unit (';' unit)* EOF -> ^(ROOT unit+)
;
unit
: (atoms -> ^(SYMBOL atoms))
('%' -> ^(PERCENT {new CommonTree(new CommonToken(NUMBER, $atoms.text))}))?
;
atoms
: atom+
;
atom
: Letter
| Digit
;
Digit : '0'..'9';
Letter : 'a'..'z' | 'A'..'Z';
Вы можете протестировать анализатор, используя следующий класс:
import org.antlr.runtime.*;
import org.antlr.runtime.tree.*;
import org.antlr.stringtemplate.*;
public class Main {
public static void main(String[] args) throws Exception {
TLexer lexer = new TLexer(new ANTLRStringStream("11;2102;34%;P11o"));
TParser parser = new TParser(new CommonTokenStream(lexer));
CommonTree tree = (CommonTree)parser.parse().getTree();
DOTTreeGenerator gen = new DOTTreeGenerator();
StringTemplate st = gen.toDOT(tree);
System.out.println(st);
}
}
, который будет выдавать DOT-вывод, соответствующий следующему AST:
![enter image description here](https://i.stack.imgur.com/UQSaw.png)
На изображении выше все листья имеют тип Letter
или Digit
, кроме "34"
, тип которого NUMBER
.