You could do that by overriding the emit()
method from the lexer and keep track of the last emitted token. Then inside your IDENTIFIER
rule, you check if the last token was a FUNCTION
, in which case you set a different $type
for said token.
A demo:
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();}
;
And if you run this class:
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();
}
}
you will see:
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
Note that if you have tokens written to the HIDDEN
channel, you'll need to change the contents of emit()
slightly. Something like this (untested!):
@lexer::members {
private Token last = null;
@Override
public Token emit() {
Token temp = super.emit();
if(temp.getType() != HIDDEN) {
last = temp;
}
return temp;
}
}
EDIT II
will this break other rules that I had? Suppose I had a rule that took all IDENTIFIER tokens and I added this contextual token. Would the rule I previously had now ignore all FUNCTION_IDENTIFIERS, causing me to have to explicitly catch both FUNCTION_IDENTIFIER and IDENTIFIER in that rule?
Yes, any rule referencing IDENTIFIER
will not match a FUNCTION_IDENTIFIER
token. If you want that, simply create a production (parser rule) like this:
identifier
: IDENTIFIER
| FUNCTION_IDENTIFIER
;
and replace all IDENTIFIER
usages in parser rules by identifier
instead.