Antlr4 ANRLR4词法语义谓词问题

Antlr4 ANRLR4词法语义谓词问题,antlr4,Antlr4,我试图在lexer中使用语义谓词来预测一个标记,但不知何故,我无法正确地得到它。以下是我所拥有的: 词汇语法 lexer grammar TLLexer; DirStart : { getCharPositionInLine() == 0 }? '#dir' ; DirEnd : { getCharPositionInLine() == 0 }? '#end' ; Cont : 'contents' [ \t]* -> mode(CNT)

我试图在lexer中使用语义谓词来预测一个标记,但不知何故,我无法正确地得到它。以下是我所拥有的:

词汇语法

lexer grammar TLLexer;

DirStart
    : { getCharPositionInLine() == 0 }? '#dir'
    ;

DirEnd
    : { getCharPositionInLine() == 0 }? '#end'
    ;

Cont
    : 'contents' [ \t]* -> mode(CNT)
    ;

WS
    : [ \t]+ -> channel(HIDDEN)
    ;

NL
    : '\r'? '\n'
    ;

mode CNT;

CNT_DirEnd
    : '#end' [ \t]* '\n'?
      { System.out.println("--matched end--"); }
    ;

CNT_LastLine
    : ~ '\n'* '\n'
      { _input.LA(1) == CNT_DirEnd }? -> mode(DEFAULT_MODE)
    ;

CNT_Line
    : ~ '\n'* '\n'
    ;
parser grammar TLParser;

options { tokenVocab = TLLexer; }

dirs
    : ( dir
      | NL
      )*
    ;

dir
    : DirStart Cont 
      contents
      DirEnd
    ;

contents
    : CNT_Line* CNT_LastLine
    ;
语法分析器

lexer grammar TLLexer;

DirStart
    : { getCharPositionInLine() == 0 }? '#dir'
    ;

DirEnd
    : { getCharPositionInLine() == 0 }? '#end'
    ;

Cont
    : 'contents' [ \t]* -> mode(CNT)
    ;

WS
    : [ \t]+ -> channel(HIDDEN)
    ;

NL
    : '\r'? '\n'
    ;

mode CNT;

CNT_DirEnd
    : '#end' [ \t]* '\n'?
      { System.out.println("--matched end--"); }
    ;

CNT_LastLine
    : ~ '\n'* '\n'
      { _input.LA(1) == CNT_DirEnd }? -> mode(DEFAULT_MODE)
    ;

CNT_Line
    : ~ '\n'* '\n'
    ;
parser grammar TLParser;

options { tokenVocab = TLLexer; }

dirs
    : ( dir
      | NL
      )*
    ;

dir
    : DirStart Cont 
      contents
      DirEnd
    ;

contents
    : CNT_Line* CNT_LastLine
    ;
本质上,CNT模式中的stuff中的每一行都是自由形式的,但它从不以#end开头,后跟可选的空格。基本上,我希望在默认lexer模式下继续匹配#end标记

我的测试输入如下:

#dir contents
 ..line..
#end
如果我在grun中运行这个,我会得到以下结果

$ grun TL dirs test.txt 
--matched end--
line 3:0 extraneous input '#end\n' expecting {CNT_LastLine, CNT_Line}
很明显,CNT_DirEnd得到匹配,但不知何故谓词没有检测到它

我知道这个特殊任务不需要语义谓词,但这只是不起作用的部分。虽然实际的解析器可能是在不使用谓词的情况下编写的,但如果我简单地将#end标记的匹配移动到模式CNT中,则实际的解析器将不太干净

谢谢,

凯莎。

我想我已经明白了。成员\u input表示原始输入的字符,因此\u input.LA返回字符,而不是lexer令牌ID(这是正确的术语吗?)。无论如何,lexer返回给解析器的数字与_input.LA返回的值无关,因此谓词失败,除非由于某种奇怪的运气,\u input.LA(1)返回的字符值等于CNT\u DirEnd的lexer ID

我修改了lexer,如下所示,现在它可以工作了,尽管它没有我希望的那么优雅(也许有人知道更好的方法?)

lexer语法-TLLexer;
@lexer::成员{
私有静态最终字符串END_DIR=“#END”;
私有布尔值isatendir(){
StringBuilder sb=新的StringBuilder();
int n=1;
内部集成电路;
//读取字符直到EOF
而((ic=_input.LA(n++)!=-1){
字符c=(字符)ic;
//我们只对下一行感兴趣
如果(c=='\n')中断;
如果(c=='\r')继续;
sb.附加(c);
}
//这行是以#结尾开始的吗?
如果(sb.indexOf(END_DIR)!=0)返回false;
//#结尾后面只跟空格吗?
for(int i=END_DIR.length();i模式(默认_模式)
;
碳纳米管线
:~'\n'*'\n'
;

我想我找到了答案。成员\u input表示原始输入的字符,因此\u input.LA返回字符,而不是lexer令牌ID(这是正确的术语吗?)。无论如何,lexer返回给解析器的数字与_input.LA返回的值无关,因此谓词失败,除非由于某种奇怪的运气,\u input.LA(1)返回的字符值等于CNT\u DirEnd的lexer ID

我修改了lexer,如下所示,现在它可以工作了,尽管它没有我希望的那么优雅(也许有人知道更好的方法?)

lexer语法-TLLexer;
@lexer::成员{
私有静态最终字符串END_DIR=“#END”;
私有布尔值isatendir(){
StringBuilder sb=新的StringBuilder();
int n=1;
内部集成电路;
//读取字符直到EOF
而((ic=_input.LA(n++)!=-1){
字符c=(字符)ic;
//我们只对下一行感兴趣
如果(c=='\n')中断;
如果(c=='\r')继续;
sb.附加(c);
}
//这行是以#结尾开始的吗?
如果(sb.indexOf(END_DIR)!=0)返回false;
//#结尾后面只跟空格吗?
for(int i=END_DIR.length();i模式(默认_模式)
;
碳纳米管线
:~'\n'*'\n'
;

似乎定义的CNT_行与“…行…”不匹配@ThomasG它确实匹配,您可以通过-gui选项看到它,或者如果您将打印操作添加到CNT_行(然后grun打印它3次,因为它永远无法退出CNT模式)和CNT_LastLine(永远不会打印它)。似乎定义的CNT_行与“…行…”不匹配@ThomasG它确实匹配,您可以通过-gui选项看到它,或者如果您将打印操作添加到CNT_行(然后grun将其打印3次,因为它永远无法脱离CNT模式)和CNT_LastLine(从不打印)。