首先我知道这个语法没有意义,但它是为了测试ANTLR规则优先级行为而创建的
grammar test;
options
{
output=AST;
backtrack=true;
memoize=true;
}
rule_list_in_order :
(
first_rule
| second_rule
| any_left_over_tokens)+
;
first_rule
:
FIRST_TOKEN
;
second_rule:
FIRST_TOKEN NEW_LINE SECOND_TOKEN NEW_LINE;
any_left_over_tokens
:
NEW_LINE
| FIRST_TOKEN
| SECOND_TOKEN;
FIRST_TOKEN
: 'First token here'
;
SECOND_TOKEN
: 'Second token here';
NEW_LINE
: ('\r'?'\n') ;
WS : (' '|'\t'|'\u000C')
{$channel=HIDDEN;}
;
当我给这个语法输入'这里的第一个令牌\ n第二个令牌'时,它匹配second_rule。
我原以为它匹配第一个规则然后是any_left_over_tokens,因为first_rule出现在rule_order_list中作为起点的second_rule之前。谁能解释为什么会这样?
干杯
答案 0 :(得分:15)
首先,ANTLR的词法分析器将从上到下标记输入。因此,首先定义的令牌优先于其下面的令牌。如果规则具有重叠的标记,则匹配大多数字符的规则将优先(贪婪匹配)。
同样的原则在解析器规则中成立。首先定义的规则也将首先匹配。例如,在规则foo
中,将首先在a
之前尝试子规则b
:
foo
: a
| b
;
请注意,在您的情况下,2 nd 规则不匹配,但尝试这样做,并且因为没有尾随换行符而失败,从而产生错误:
line 0:-1 mismatched input '<EOF>' expecting NEW_LINE
所以,根本没有匹配。但 是奇怪的。因为您设置了backtrack=true
,所以至少应该回溯并匹配:
first_rule
(“这里的第一个令牌”) any_left_over_tokens
(“换行符”) any_left_over_tokens
(“此处为第二个令牌”) 如果首先不匹配first_rule
,甚至不尝试匹配second_rule
开头。
手动执行谓词(以及禁用选项{...} 部分中的backtrack
)时的快速演示如下所示:
grammar T;
options {
output=AST;
//backtrack=true;
memoize=true;
}
rule_list_in_order
: ( (first_rule)=> first_rule {System.out.println("first_rule=[" + $first_rule.text + "]");}
| (second_rule)=> second_rule {System.out.println("second_rule=[" + $second_rule.text + "]");}
| any_left_over_tokens {System.out.println("any_left_over_tokens=[" + $any_left_over_tokens.text + "]");}
)+
;
first_rule
: FIRST_TOKEN
;
second_rule
: FIRST_TOKEN NEW_LINE SECOND_TOKEN NEW_LINE
;
any_left_over_tokens
: NEW_LINE
| FIRST_TOKEN
| SECOND_TOKEN
;
FIRST_TOKEN : 'First token here';
SECOND_TOKEN : 'Second token here';
NEW_LINE : ('\r'?'\n');
WS : (' '|'\t'|'\u000C') {$channel=HIDDEN;};
可以在课堂上进行测试:
import org.antlr.runtime.*;
public class Main {
public static void main(String[] args) throws Exception {
String source = "First token here\nSecond token here";
ANTLRStringStream in = new ANTLRStringStream(source);
TLexer lexer = new TLexer(in);
CommonTokenStream tokens = new CommonTokenStream(lexer);
TParser parser = new TParser(tokens);
parser.rule_list_in_order();
}
}
产生预期的输出:
first_rule=[First token here]
any_left_over_tokens=[
]
any_left_over_tokens=[Second token here]
请注意,使用以下内容无关紧要:
rule_list_in_order
: ( (first_rule)=> first_rule
| (second_rule)=> second_rule
| any_left_over_tokens
)+
;
或
rule_list_in_order
: ( (second_rule)=> second_rule // <--+--- swapped
| (first_rule)=> first_rule // <-/
| any_left_over_tokens
)+
;
,两者都会产生预期的输出。
所以,我的猜测是你可能发现了一个错误。
Yout可以尝试使用ANTLR邮件列表,以防你想要一个明确的答案(Terence Parr经常在那里经常光顾)。
祝你好运!PS。我用ANTLR v3.2进行了测试