【发布时间】:2012-07-10 14:47:26
【问题描述】:
当我通过这些规则获得令牌时
STRINGA : '"' (options {greedy=false;}: ESC | .)* '"';
STRINGB : '\'' (options {greedy=false;}: ESC | .)* '\'';
它最终会抓取'text' 而不仅仅是text。我自己可以轻松删除 ' 和 ',但想知道如何让 ANTLR 删除它?
【问题讨论】:
当我通过这些规则获得令牌时
STRINGA : '"' (options {greedy=false;}: ESC | .)* '"';
STRINGB : '\'' (options {greedy=false;}: ESC | .)* '\'';
它最终会抓取'text' 而不仅仅是text。我自己可以轻松删除 ' 和 ',但想知道如何让 ANTLR 删除它?
【问题讨论】:
您将需要一些自定义代码。此外,您不应该在规则中使用.(点):您应该明确定义您想要匹配的所有内容除了一个反斜杠(假设这是您的 ESQ 以)开头,可能是 quote 和 换行符。
这样的事情可以做到:
grammar T;
parse
: STRING EOF {System.out.println($STRING.text);}
;
STRING
: '"' (ESQ | ~('"' | '\\' | '\r' | '\n'))* '"'
{
String matched = getText();
StringBuilder builder = new StringBuilder();
for(int i = 1; i < matched.length() - 1; i++) {
char ch = matched.charAt(i);
if(ch == '\\') {
i++;
ch = matched.charAt(i);
switch(ch) {
case 'n': builder.append('\n'); break;
case 't': builder.append('\t'); break;
default: builder.append(ch); break;
}
}
else {
builder.append(ch);
}
}
setText(builder.toString());
}
;
fragment ESQ
: '\\' ('n' | 't' | '"' | '\\')
;
如果您现在解析输入 "tabs:'\t\t\t'\nquote:\"\nbackslash:\\",则会将以下内容打印到控制台:
标签:' ' 引用:” 反斜杠:\
为了保持语法简洁,您当然可以在自定义方法中移动代码:
grammar T;
@lexer::members {
private String fix(String str) {
...
}
}
parse
: STRING EOF {System.out.println($STRING.text);}
;
STRING
: '"' (ESQ | ~('"' | '\\' | '\r' | '\n'))* '"' {setText(fix(getText()));}
;
fragment ESQ
: '\\' ('n' | 't' | '"' | '\\')
;
【讨论】:
一种方法是将字符串内容定义为单独的类别,例如
STRINGA : '"' STRINGCONTENTS '"';
STRINGB : '\'' STRINGCONTENTS '\'';
然后捕获 STRINGCONTENTS 值。
【讨论】: