You can do this by issuing two tokens ( Int and Range tokens) when you see ".." inside the float rule. You need to override two methods in your lexer in order to accomplish this.
Demo with a small part of your Dee grammar:
grammar Dee; @lexer::members { java.util.Queue<Token> tokens = new java.util.LinkedList<Token>(); public void offer(int ttype, String ttext) { this.emit(new CommonToken(ttype, ttext)); } @Override public void emit(Token t) { state.token = t; tokens.offer(t); } @Override public Token nextToken() { super.nextToken(); return tokens.isEmpty() ? Token.EOF_TOKEN : tokens.poll(); } } parse : (t=. {System.out.printf("\%-15s '\%s'\n", tokenNames[$t.type], $t.text);})* EOF ; Range : '..' ; IntegerLiteral : Integer IntSuffix? ; FloatLiteral : Float ImaginarySuffix? ;
Test the grammar with the class:
import org.antlr.runtime.*; public class Main { public static void main(String[] args) throws Exception { DeeLexer lexer = new DeeLexer(new ANTLRStringStream("1..2 .. 33.33 ..21.0")); DeeParser parser = new DeeParser(new CommonTokenStream(lexer)); parser.parse(); } }
And when you run Main , the following output is issued:
IntegerLiteral '1' Range '..' IntegerLiteral '2' Range '..' FloatLiteral '33.33' Range '..' FloatLiteral '21.0'
EDIT
Yes, as you pointed out in the comments, the lexer rule can only issue one single token. But, as you yourself have tried, semantic predicates can actually be used to make the lexer look forward to char -stream, to make sure that there really is a ".." after the IntegerLiteral token, before trying to match the FloatLiteral .
The following grammar will create the same tokens as the first demo.
grammar Dee; parse : (t=. {System.out.printf("\%-15s '\%s'\n", tokenNames[$t.type], $t.text);})* EOF ; Range : '..' ; Number : (IntegerLiteral Range)=> IntegerLiteral {$type=IntegerLiteral;} | (FloatLiteral)=> FloatLiteral {$type=FloatLiteral;} | IntegerLiteral {$type=IntegerLiteral;} ;