ANTLR语法匹配以#

时间:2017-07-30 09:26:57

标签: antlr antlr4

我正在尝试将下面的文本与ANTLR语法匹配:

enter image description here

ANTLR语法是:

grammar header;


start : commentBlock
        EOF;

commentBlock : CommentLine+;
CommentLine  : '#' AsciiChars+;
AsciiChars : [a-zA-Z];

fragment CR : '\r';
fragment LF : '\n';
EOL : CR?LF ->skip;

fragment Tab : '\t';
fragment Space : ' ';
TS : (Tab|Space)+ ->skip;

我得到的错误是:

line 1:0 token recognition error at: '# '
line 2:0 token recognition error at: '# '
line 3:0 token recognition error at: '# '
[@0,2:2='a',<AsciiChars>,1:2]
[@1,7:7='b',<AsciiChars>,2:2]
[@2,12:12='c',<AsciiChars>,3:2]
[@3,15:14='<EOF>',<EOF>,4:0]
line 1:2 mismatched input 'a' expecting CommentLine

我猜语法是合理的,但错误发生的原因是什么?

ADD 1

奇怪的是,在我将词法分析器规则CommentLine更改为解析器规则commentLine后,它可以正常运行:

grammar header;

start : commentBlock
        EOF;

commentBlock : commentLine+;
commentLine  : '#' AsciiChars+; // <=== here CommentLine -> commentLine
AsciiChars : [a-zA-Z];

fragment CR : '\r';
fragment LF : '\n';
EOL : CR?LF ->skip;

fragment Tab : '\t';
fragment Space : ' ';
TS : (Tab|Space)+ ->skip; 

但实际上我想丢弃所有评论行。如果它必须是解析器规则,我不能使用->skip丢弃它。

ADD 2

我想我现在可以解释一下。

要记住的重要事项是:

  • lexer阶段在解析器阶段之前发生。
  • 如果跳过的令牌T1被另一个词法分析器规则引用,例如令牌T2,则令牌T2中的令牌T1部分跳过。

让我用简洁的例子解释一下:

要匹配的文件:

#   abc

语法1:

grammar test;

t : T2;
p : t
    EOF;

Char : [a-z];

T2 : '#' T1+ Char+; // <<<< Here T2 reference the so-skipped T1.

fragment Tab : '\t';
fragment Space : ' ';
T1 : (Tab|Space)+ ->skip; //<<<<< T1 is to be skipped.

在语法1中,跳过T1,但不跳过T2中的T1部分。 T2将匹配词法分析阶段中的输入文本。 (即使我们在T1之后放置T2,T2仍将匹配。我认为ANTLR做了一些贪婪的匹配以匹配最长的令牌。)

语法2:

跳过的T1不会被另一个令牌规则引用,而是直接在解析器规则中引用。

grammar test;

t : '#' T1+ Char+; // <<<<<<<<<<<< HERE
p : t
    EOF;

Char : [a-z];

fragment Tab : '\t';
fragment Space : ' ';
T1 : (Tab|Space)+ ->skip; //<<<<< T1 is to be skipped.

这一次,没有T2规则来帮助空间在词法分析阶段生存,输入文件中的所有T1都将被跳过。所以在解析器阶段之后,匹配将失败并显示以下错误:

[@0,0:0='#',<'#'>,1:0]
[@1,4:4='a',<Char>,1:4]
[@2,5:5='b',<Char>,1:5]
[@3,6:6='c',<Char>,1:6]
[@4,7:6='<EOF>',<EOF>,1:7]
line 1:4 mismatched input 'a' expecting T1

因为所有T1在词法分析阶段已经被丢弃

ADD 3

回到我原来的问题,我犯的一个微妙错误是,我想在跳过TS后,其余字符可以重新分组到新令牌{{1没有空格。这是ANTLR的明显错误。

由于lexer phase all happens before parser phaseCommentLine是一个令牌规则,因此它没有空格,因此它不会匹配输入内容中的任何内容。

正如@macmoonshine所说,我必须将CommentLine添加到TS令牌中。

3 个答案:

答案 0 :(得分:1)

您的语法在评论中不包含空格,但您的评论确实如此。

编辑:您是否尝试commentLine : '#' TS AsciiChars;作为评论规则?

答案 1 :(得分:1)

也许你正在寻找:

grammar Header;

start : CommentLine+ EOF;

CommentLine  : '#' ' ' AsciiChars+;
AsciiChars : [a-zA-Z];

fragment CR : '\r';
fragment LF : '\n';
EOL : CR?LF ->skip;

fragment Tab : '\t';
fragment Space : ' ';
TS : (Tab|Space)+ ->skip; 

现在这个只使用词法分析器规则。

到IGNORE评论

grammar Header;

start : CommentLine+ EOF;

CommentLine  : '#' ' ' AsciiChars+ -> skip;
AsciiChars : [a-zA-Z];

fragment CR : '\r';
fragment LF : '\n';
EOL : CR?LF ->skip;

fragment Tab : '\t';
fragment Space : ' ';
TS : (Tab|Space)+ ->skip;

这将完全忽略通知,实际上会产生错误,因为规则'start需要CommentLine现在被丢弃。因此,如果您想要忽略并放弃评论,请使用类似第二条的内容,并且不要在解析器规则中提及CommentLine,只要让词法分析器剥离它们。或者,如果您想保留评论,可以使用前一个评论。

至REROUTE评论

最后一个想法是将评论重新路由到另一个频道:

grammar Header;

start : other EOF;
other: AsciiChars;
CommentLine  : '#' ' ' AsciiChars+ -> channel(2);
AsciiChars : [a-zA-Z]+;

fragment CR : '\r';
fragment LF : '\n';
EOL : CR?LF ->skip;

fragment Tab : '\t';
fragment Space : ' ';
TS : (Tab|Space)+ ->skip;

在这个语法中,注释仍然是有效的,但是路由到另一个通道以进行可能的处理。我又添加了另一条规则 start只是为了匹配:

# a
# b
something
# c

[@0,0:2='# a',<CommentLine>,channel=2,1:0]
[@1,5:7='# b',<CommentLine>,channel=2,2:0]
[@2,10:18='something',<AsciiChars>,3:0]
[@3,21:23='# c',<CommentLine>,channel=2,4:0]
[@4,26:25='<EOF>',<EOF>,5:0]

其中一个选项肯定会为你做;)

答案 2 :(得分:0)

试试这个:您的评论与'#'交换'//'的普通单行评论相同。如果您在哈希使用后需要空格:'# '。如果您要求散列位于第1列,请使用:[\n\r] '# ' ~[\n\r]。通过查看示例,这应涵盖所有可能的选项。

COMMENT_LINE
    : '#'  ~[\n\r]* ->( skip )
    ;