これが解決に向けたスタートです。レクサーを使用してテキストをトークンに分割します。ここでの秘訣は、ルールID
が呼び出しごとに複数のトークンを発行できることです。これは非標準のレクサー動作であるため、いくつかの注意点があります。
これはANTLR4では機能しないと確信しています。
このコードは、すべてのトークンがにキューイングされていることを前提としていtokenQueue
ます。
ルールID
はキーワードの繰り返しを妨げないため、intintint
トークンを生成しINT
INT
INT
ます。それが悪い場合は、文法でどちらがより理にかなっているかに応じて、レクサー側またはパーサー側のいずれかでそれを処理することをお勧めします。
キーワードが短いほど、このソリューションは脆弱になります。入力はキーワードで始まり、その後にキーワード以外の文字列が続くためinternal
、無効です。ID
int
文法は、私が消去していない警告を生成します。このコードを使用する場合は、それらを削除することをお勧めします。
文法は次のとおりです。
MultiToken.g
grammar MultiToken;
@lexer::members{
private java.util.LinkedList<Token> tokenQueue = new java.util.LinkedList<Token>();
@Override
public Token nextToken() {
Token t = super.nextToken();
if (tokenQueue.isEmpty()){
if (t.getType() == Token.EOF){
return t;
} else {
throw new IllegalStateException("All tokens must be queued!");
}
} else {
return tokenQueue.removeFirst();
}
}
public void emit(int ttype, int tokenIndex) {
//This is lifted from ANTLR's Lexer class,
//but modified to handle queueing and multiple tokens per rule.
Token t;
if (tokenIndex > 0){
CommonToken last = (CommonToken) tokenQueue.getLast();
t = new CommonToken(input, ttype, state.channel, last.getStopIndex() + 1, getCharIndex() - 1);
} else {
t = new CommonToken(input, ttype, state.channel, state.tokenStartCharIndex, getCharIndex() - 1);
}
t.setLine(state.tokenStartLine);
t.setText(state.text);
t.setCharPositionInLine(state.tokenStartCharPositionInLine);
emit(t);
}
@Override
public void emit(Token t){
super.emit(t);
tokenQueue.addLast(t);
}
}
doc : (INT | FLOAT | ID | NUMBER)* EOF;
fragment
INT : 'int';
fragment
FLOAT : 'float';
NUMBER : ('0'..'9')+;
ID
@init {
int index = 0;
boolean rawId = false;
boolean keyword = false;
}
: ({!rawId}? INT {emit(INT, index++); keyword = true;}
| {!rawId}? FLOAT {emit(FLOAT, index++); keyword = true;}
| {!keyword}? ('a'..'z')+ {emit(ID, index++); rawId = true;}
)+
;
WS : (' '|'\t'|'\f'|'\r'|'\n')+ {skip();};
テストケース1:混合キーワード
入力
intfloat a
int b
float c
intfloatintfloat d
出力(トークン)
[INT : int] [FLOAT : float] [ID : a]
[INT : int] [ID : b]
[FLOAT : float] [ID : c]
[INT : int] [FLOAT : float] [INT : int] [FLOAT : float] [ID : d]
テストケース2:キーワードを含むID
入力
aintfloat
bint
cfloat
dintfloatintfloat
出力(トークン)
[ID : aintfloat]
[ID : bint]
[ID : cfloat]
[ID : dintfloatintfloat]
テストケース3:不正なID#1
入力
internal
出力(トークンとレクサーエラー)
[INT : int] [ID : rnal]
line 1:3 rule ID failed predicate: {!keyword}?
テストケース4:不正なID#2
入力
floatation
出力(トークンとレクサーエラー)
[FLOAT : float] [ID : tion]
line 1:5 rule ID failed predicate: {!keyword}?
テストケース5:非IDルール
入力
int x
float 3 float 4 float 5
5 a 6 b 7 int 8 d
出力(トークン)
[INT : int] [ID : x]
[FLOAT : float] [NUMBER : 3] [FLOAT : float] [NUMBER : 4] [FLOAT : float] [NUMBER : 5]
[NUMBER : 5] [ID : a] [NUMBER : 6] [ID : b] [NUMBER : 7] [INT : int] [NUMBER : 8] [ID : d]