【发布时间】:2018-01-05 23:45:16
【问题描述】:
我正在尝试将以下文本与 ANTLR 语法匹配:
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
我猜语法是合理的,但是为什么会出现错误?
加 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 来丢弃它。
添加 2
我想我现在可以解释了。
要记住的关键事项是:
- 词法分析器阶段发生在解析器阶段之前。
- 如果 跳过 标记 T1 被另一个词法分析器规则引用,例如标记 T2,则标记 T1 部分 在标记 T2 将不跳过。
让我用一个简洁的例子来解释它:
要匹配的文档:
# 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 将在词法分析器阶段匹配输入文本。 (即使我们将 T2 放在 T1 之后,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 都已经在词法分析阶段被丢弃。
添加 3
回到我最初的问题,我犯的一个微妙的错误是,我认为在跳过TS之后,剩余的字符可以重新分组到新的标记CommentLine中,这没有空格。这对 ANTLR 来说是完全错误的。
因为lexer phase all happens before parser phase,CommentLine是一个token规则,里面没有空格,所以不会匹配输入内容中的任何内容。
正如@macmoonshine 所说,我必须将TS 添加到CommentLine 令牌中。
【问题讨论】:
-
请务必查看我在下面建议的许多选项。
-
那里肯定有一个“接受”——我还能提供什么帮助来获得接受;)