Antlr &引用;跳过“;更改解析器行为

Antlr &引用;跳过“;更改解析器行为,antlr,antlr4,Antlr,Antlr4,向规则中添加skip并不能达到我的预期效果。下面是一个语法,表示由逗号和空格分隔的一对标记。我制作了一个逗号标记为skip的版本,还有一个没有: grammar Commas; COMMA: ', '; COMMASKIP: ', ' -> skip; DATA: ~[, \n]+; withoutSkip: data COMMA data '\n'; withSkip: data COMMASKIP data '\n'

向规则中添加
skip
并不能达到我的预期效果。下面是一个语法,表示由逗号和空格分隔的一对标记。我制作了一个逗号标记为
skip
的版本,还有一个没有:

grammar Commas;

COMMA:          ', ';
COMMASKIP:      ', ' -> skip;
DATA:           ~[, \n]+;

withoutSkip:    data COMMA data '\n';
withSkip:       data COMMASKIP data '\n';
data:           DATA;
在不跳过
的情况下测试规则可以正常工作:

$ echo 'a, b' | grun Commas withoutSkip -tree
(withoutSkip (data a) ,  (data b) \n)
使用
skip
时出现错误:

$ echo 'a, b' | grun Commas withSkip -tree
line 1:1 mismatched input ', ' expecting COMMASKIP
(withSkip (data a) ,  b \n)
如果我注释掉
逗号
而不注释skip
规则,我会得到以下结果:

$ echo 'a, b' | grun Commas withSkip -tree
line 1:3 missing ', ' at 'b'
(withSkip (data a) <missing ', '> (data b) \n)

我做错了什么?

skip
导致lexer丢弃令牌。因此,
skip
ped lexer规则不能在解析器规则中使用

另外,如果两个或多个规则匹配相同的输入,则首先定义的规则将从语法中稍后定义的规则中“赢”,无论解析器是否尝试匹配语法中稍后定义的规则,第一个规则都将始终“赢”。在您的情况下,将永远不会创建规则
COMMASKIP
,因为
COMMA
匹配相同的输入

试着这样做:

(withSkip (data a) (data b) \n)
grammar X;

COMMA : ',';
SPACE : (' '|'\n') -> skip;
DATA  : ~[, \n]+;

data  : DATA (COMMA DATA)*;
public class MyListener extends XBaseListener {

    @Override
    public void enterData(XParser.DataContext ctx) {

        List dataList = ctx.DATA(); // not sure what type of list it returns...
        // do something with `dataList`
    }
}
语法逗号

COMMA : ',' -> skip;
SPACE : (' '|'\n') -> skip;
DATA  : ~[, \n]+;

data  : DATA+;
编辑
那么,在不将逗号包含在解析树中的情况下,如何指定逗号的位置呢?您的代码将与a、b匹配

不需要,因此如果逗号有效(即,
a,b
)无效,则不能从lexer中跳过它

我认为在antlr3中应该使用感叹号

在Antlr4中,您不能从解析创建AST。在新版本中,所有终端/规则都位于一个解析树中。您可以使用自定义访问者和/或侦听器迭代此树。如何做到这一点的演示可以在以下问答中找到:

在您的情况下,语法如下所示:

(withSkip (data a) (data b) \n)
grammar X;

COMMA : ',';
SPACE : (' '|'\n') -> skip;
DATA  : ~[, \n]+;

data  : DATA (COMMA DATA)*;
public class MyListener extends XBaseListener {

    @Override
    public void enterData(XParser.DataContext ctx) {

        List dataList = ctx.DATA(); // not sure what type of list it returns...
        // do something with `dataList`
    }
}
然后创建一个如下所示的侦听器:

(withSkip (data a) (data b) \n)
grammar X;

COMMA : ',';
SPACE : (' '|'\n') -> skip;
DATA  : ~[, \n]+;

data  : DATA (COMMA DATA)*;
public class MyListener extends XBaseListener {

    @Override
    public void enterData(XParser.DataContext ctx) {

        List dataList = ctx.DATA(); // not sure what type of list it returns...
        // do something with `dataList`
    }
}

如您所见,
逗号
没有被删除,但在
enterData(…)
中,您只使用
数据
标记。

那么,如何指定逗号的位置而不将其包含在解析树中?您的代码将匹配
a、b
。我认为在antlr3中应该使用感叹号。@DanLipsitt,检查我的编辑。