首页 文章

ANTLR语法匹配以#开头的注释行

提问于
浏览
0

我试图将下面的文本与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

奇怪的是,在我将 lexer 规则 CommentLine 更改为 parser 规则 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阶段在解析器阶段之前发生 .

  • 如果 skipped 令牌T1被另一个词法分析器规则引用,比如令牌T2,则跳过令牌T1部分 within 令牌T2将被 not .

让我用一个简洁的例子来解释它:

要匹配的文件:

#   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.

这次, no T2 rule to help the spaces to survive the lexer phase ,将跳过输入文件中的所有T1 . 所以 when in the parser phase afterwards ,匹配将失败并显示以下错误:

[@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都已 discarded in lexer phase .

ADD 3

回到我原来的问题,我犯的一个微妙的错误是,我想在 TS 被跳过之后,其余的字符可以 re-grouped 进入新的令牌 CommentLine ,它没有空格 . 这是ANTLR的明显错误 .

因为lexer phase all happens before parser phaseCommentLine 是一个标记规则,它没有空格,因此它不会匹配输入内容中的任何内容 .

就像@macmoonshine说的那样,我必须将 TS 添加到 CommentLine 令牌中 .

3 回答

  • 1

    试试这个:看来你的评论与 '//' 交换 '//' 的普通单行评论相同 . 如果在使用哈希后需要空格: '# ' . 如果您要求散列位于第1列,请使用: [\n\r] '# ' ~[\n\r] . 从这个例子来看,这应该涵盖所有潜在的选择 .

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

    你的语法在评论中不包含空格,但你的评论却有 .

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

  • 0

    也许你正在寻找:

    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 现在被丢弃 . 因此,如果您想要 ignore and discard 注释,请使用类似于第二个的注释,并且不要在解析器规则中提及 CommentLine ,只需让词法分析器剥离它们 . 或者,如果要保留注释,可以使用上一个注释 .

    至REROUTE评论

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

    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;
    

    在这个语法中,注释仍然是有效的,但是路由到另一个通道以进行可能的处理 . 我在_383052中添加了另一条规则,所以有一些东西要匹配:

    # 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]
    

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

相关问题