Вы можете сделать это, переопределив метод emit()
из лексера и отследив последний выпущенный токен. Затем в вашем правиле IDENTIFIER
вы проверяете, был ли последний токен FUNCTION
, и в этом случае вы устанавливаете другой $type
для указанного токена.
Демо:
grammar T;
tokens {
FUNCTION_IDENTIFIER;
}
@lexer::members {
private Token last = null;
@Override
public Token emit() {
last = super.emit();
return last;
}
}
parse
: (t=. {System.out.printf("\%-20s -> '\%s'\n", tokenNames[$t.type], $t.text);})* EOF
;
FUNCTION
: 'function'
;
IDENTIFIER
: ('a'..'z' | 'A'..'Z')+
{
if(last != null && last.getType() == FUNCTION) $type=FUNCTION_IDENTIFIER;
}
;
SPACE
: ' ' {skip();}
;
А если вы запустите этот класс:
import org.antlr.runtime.*;
public class Main {
public static void main(String[] args) throws Exception {
TLexer lexer = new TLexer(new ANTLRStringStream("a function b c"));
CommonTokenStream tokens = new CommonTokenStream(lexer);
TParser parser = new TParser(tokens);
parser.parse();
}
}
вы увидите:
bart@hades:~/Programming/ANTLR/Demos/T$ java -cp antlr-3.3.jar org.antlr.Tool T.g
bart@hades:~/Programming/ANTLR/Demos/T$ javac -cp antlr-3.3.jar *.java
bart@hades:~/Programming/ANTLR/Demos/T$ java -cp .:antlr-3.3.jar Main
IDENTIFIER -> 'a'
FUNCTION -> 'function'
FUNCTION_IDENTIFIER -> 'b'
IDENTIFIER -> 'c'
EDIT
Обратите внимание, что если у вас есть токены, записанные на канал HIDDEN
, вам нужно немного изменить содержимое emit()
. Примерно так (не проверено!):
@lexer::members {
private Token last = null;
@Override
public Token emit() {
Token temp = super.emit();
if(temp.getType() != HIDDEN) {
last = temp;
}
return temp;
}
}
РЕДАКТИРОВАТЬ II
это нарушит другие правила, которые у меня были? Предположим, у меня есть правило, которое принимает все токены IDENTIFIER, и я добавил этот контекстный токен. Будет ли правило, которое у меня ранее было, теперь игнорировать все FUNCTION_IDENTIFIERS, из-за чего мне пришлось бы явно отлавливать FUNCTION_IDENTIFIER и IDENTIFIER в этом правиле?
Да, любое правило, ссылающееся на IDENTIFIER
, будет не соответствовать токену FUNCTION_IDENTIFIER
. Если вы хотите этого, просто создайте производство (правило синтаксического анализатора) следующим образом:
identifier
: IDENTIFIER
| FUNCTION_IDENTIFIER
;
и замените все значения IDENTIFIER
в правилах синтаксического анализатора на identifier
.