我的语法如下
Identifier
: [a-zA-Z0-9_.]+
| '`' Identifier '`'
;
当我匹配一个标识符时,例如“某人”,我想剥去反引号并产生一个不同的标记,即someone
当然,我可以遍历最终的令牌数组,但是在令牌解析期间是否可以这样做?
答案 0 :(得分:0)
如果我很好理解,给定输入(文件t.text
):
one `someone`
two `fred`
tree `henry`
您希望自动生成令牌,就像语法具有词法分析器规则一样:
SOMEONE : 'someone' ;
FRED : 'fred' ;
HENRY : 'henry' ;
ID : [a-zA-Z0-9_.]+ ;
但令牌由type
标识,即整数,而不是词法分析器的名称。您可以使用setType():
type
grammar Question;
/* Change `someone` to SOMEONE, `fred` to FRED, etc. */
@lexer::members { int next_number = 1001; }
question
@init {System.out.println("Question last update 1117");}
: expr+ EOF
;
expr
: ID BACKTICK_ID
;
ID : [a-zA-Z0-9_.]+ ;
BACKTICK_ID : '`' ID '`' { setType(next_number); next_number+=1; } ;
WS : [ \r\n\t] -> skip ;
执行:
$ grun Question question -tokens -diagnostics t.text
[@0,0:2='one',<ID>,1:0]
[@1,4:12='`someone`',<1001>,1:4]
[@2,14:16='two',<ID>,2:0]
[@3,18:23='`fred`',<1002>,2:4]
[@4,25:28='tree',<ID>,3:0]
[@5,30:36='`henry`',<1003>,3:5]
[@6,38:37='<EOF>',<EOF>,4:0]
Question last update 1117
line 1:4 mismatched input '`someone`' expecting BACKTICK_ID
line 2:4 mismatched input '`fred`' expecting BACKTICK_ID
line 3:5 mismatched input '`henry`' expecting BACKTICK_ID
基本类型来自词法分析器规则:
$ cat Question.tokens
ID=1
BACKTICK_ID=2
WS=3
另一个来自setType
。您可以编写表中找到的标记,而不是为每个标记增加一个数字,在创建新标记之前,访问该表以检查它是否已存在并避免重复标记接收不同的数字。
无论如何,你在解析器中无能为力,因为解析器规则需要知道type
数字。
如果您事先知道一组名称,可以在tokens
声明中列出:
grammar Question;
/* Change `someone` to SOMEONE, `fred` to FRED, etc. */
@lexer::header {
import java.util.*;
}
tokens { SOMEONE, FRED, HENRY }
@lexer::members {
Map<String,Integer> keywords = new HashMap<String,Integer>() {{
put("someone", QuestionParser.SOMEONE);
put("fred", QuestionParser.FRED);
put("henry", QuestionParser.HENRY);
}};
}
question
@init {System.out.println("Question last update 1746");}
: expr+ EOF
;
expr
: ID SOMEONE
| ID FRED
| ID HENRY
;
ID : [a-zA-Z0-9_.]+ ;
BACKTICK_ID : '`' ID '`'
{ String textb = getText();
String texta = textb.substring(1, textb.length() - 1);
System.out.println("text before=" + textb + ", text after="+ texta);
if ( keywords.containsKey(texta)) {
setType(keywords.get(texta)); // reset token type
setText(texta); // remove backticks
}
}
;
WS : [ \r\n\t] -> skip ;
执行:
$ grun Question question -tokens -diagnostics t.text
text before=`someone`, text after=someone
text before=`fred`, text after=fred
text before=`henry`, text after=henry
[@0,0:2='one',<ID>,1:0]
[@1,4:12='someone',<4>,1:4]
[@2,14:16='two',<ID>,2:0]
[@3,18:23='fred',<5>,2:4]
[@4,25:28='tree',<ID>,3:0]
[@5,30:36='henry',<6>,3:5]
[@6,38:37='<EOF>',<EOF>,4:0]
Question last update 1746
$ cat Question.tokens
ID=1
BACKTICK_ID=2
WS=3
SOMEONE=4
FRED=5
HENRY=6
正如您所看到的,不再有错误,因为expr
规则对识别良好的令牌感到满意。即使没有
SOMEONE : 'someone' ;
FRED : 'fred' ;
HENRY : 'henry' ;
仅ID
和BACKTICK_ID
,types
已在tokens
语句后面的场景中定义:
public static final int
ID=1, BACKTICK_ID=2, WS=3, SOMEONE=4, FRED=5, HENRY=6;
我担心如果你想要一个免费的名单,那是不可能的,因为解析器使用的是types
,而不是词法规则的名称:
public static class ExprContext extends ParserRuleContext {
public TerminalNode ID() { return getToken(QuestionParser.ID, 0); }
public TerminalNode SOMEONE() { return getToken(QuestionParser.SOMEONE, 0); }
public TerminalNode FRED() { return getToken(QuestionParser.FRED, 0); }
public TerminalNode HENRY() { return getToken(QuestionParser.HENRY, 0); }
...
public final ExprContext expr() throws RecognitionException {
try { ...
setState(17);
case 1:
enterOuterAlt(_localctx, 1);
{
setState(11);
match(ID);
setState(12);
match(SOMEONE);
}
break;
在
match(SOMEONE);
SOMEONE
是一个代表数字4的常量。
如果您没有已知名称列表,emit
将无法解决您的问题,因为它会创建一个最重要字段为_type
的令牌:
public Token emit() {
Token t = _factory.create(_tokenFactorySourcePair, _type, _text, _channel, _tokenStartCharIndex, getCharIndex()-1,
_tokenStartLine, _tokenStartCharPositionInLine);
emit(t);
return t;
}