通过Antlr 4 lexer/parser获取所有空行

通过Antlr 4 lexer/parser获取所有空行,antlr,antlr4,Antlr,Antlr4,试图通过Antlr 4 lexer/parser获取给定PHP文件的所有空行(仅行号)。我使用的语法可以在GitHub上找到 空白标记定义为: Whitespace: [ \t\r\n]+ -> skip; 我将此更改为: Whitespace: ( ' ' | '\t' | '\r' '\n' { newline(); } | '\n' { newl

试图通过Antlr 4 lexer/parser获取给定PHP文件的所有空行(仅行号)。我使用的语法可以在GitHub上找到

空白标记定义为:

Whitespace:         [ \t\r\n]+ -> skip;
我将此更改为:

Whitespace: (
             ' ' 
             | '\t' 
             | '\r' '\n' { newline(); } 
             | '\n'       { newline(); }
            );
但是它收集了几乎所有的行,因为每一行都以“\n”结尾。任何专家的建议都能给我一个线索

要测试的PHP示例:
试试这样的方法:

lexer语法DemoLexer;
空位线
:{super.getCharPositionInLine()==0}?[\t]*'\r'?'\不
;
空白
:[\t\r\n]->跳过
;
其他
: .
;
如果我运行以下测试类:

import org.antlr.v4.runtime.CharStreams;
导入org.antlr.v4.runtime.Token;
公共班机{
公共静态void main(字符串[]args){
String source=“foo\n”+
“\n”+
“栏\n”+
“\n”+
“baz\r\n”+
“\t\t\n”+
“\t\n\n”;
DemoLexer lexer=新的DemoLexer(CharStreams.fromString(source));
for(Token t:lexer.getAllTokens()){
字符串名称=lexer.getTokenNames()[t.getType()];
字符串text=t.getText().replace(“\r”,“\\r”).replace(“\n”,“\\n”).replace(“\t”,“\\t”);
System.out.printf(“%-20s'%s'\n”,名称,文本);
}
}
}
这将被打印出来:

其他“f”
其他“o”
其他“o”
空行'\n'
其他“b”
其他“a”
其他“r”
空行'\n'
其他“b”
其他“a”
其他“z”
空行'\t\t\n'
其他“e”
其他'n'
其他'd'
空行'\n'

请参阅:

请尝试以下方法:

lexer语法DemoLexer;
空位线
:{super.getCharPositionInLine()==0}?[\t]*'\r'?'\不
;
空白
:[\t\r\n]->跳过
;
其他
: .
;
如果我运行以下测试类:

import org.antlr.v4.runtime.CharStreams;
导入org.antlr.v4.runtime.Token;
公共班机{
公共静态void main(字符串[]args){
String source=“foo\n”+
“\n”+
“栏\n”+
“\n”+
“baz\r\n”+
“\t\t\n”+
“\t\n\n”;
DemoLexer lexer=新的DemoLexer(CharStreams.fromString(source));
for(Token t:lexer.getAllTokens()){
字符串名称=lexer.getTokenNames()[t.getType()];
字符串text=t.getText().replace(“\r”,“\\r”).replace(“\n”,“\\n”).replace(“\t”,“\\t”);
System.out.printf(“%-20s'%s'\n”,名称,文本);
}
}
}
这将被打印出来:

其他“f”
其他“o”
其他“o”
空行'\n'
其他“b”
其他“a”
其他“r”
空行'\n'
其他“b”
其他“a”
其他“z”
空行'\t\t\n'
其他“e”
其他'n'
其他'd'
空行'\n'

请参阅:

这是您对PHP代码所做的唯一处理吗?如果是这样,您可以简单地逐行加载文件并计算空条目。在这种情况下不需要解析器

更新

既然您已经有了解析器,那么您可以使用令牌流并遍历所有令牌。每当看到换行符时,请检查上一个标记,如果这也是换行符(或这是流中的第一个标记),则会发现一个空行。您甚至可以隐藏空白,因为令牌流将为您提供所有通道上的所有令牌(除非您对其进行过滤)

不管怎么说,计算空行数是一个语义步骤,而解析器(正在执行语法步骤)不是进行此操作的正确位置

更新2

以下是应该可以工作的代码(基于您的尝试):


请注意,我无意中在
空白中对
换行符
调用使用循环。

这是您对PHP代码所做的唯一处理吗?如果是这样,您可以简单地逐行加载文件并计算空条目。在这种情况下不需要解析器

更新

既然您已经有了解析器,那么您可以使用令牌流并遍历所有令牌。每当看到换行符时,请检查上一个标记,如果这也是换行符(或这是流中的第一个标记),则会发现一个空行。您甚至可以隐藏空白,因为令牌流将为您提供所有通道上的所有令牌(除非您对其进行过滤)

不管怎么说,计算空行数是一个语义步骤,而解析器(正在执行语法步骤)不是进行此操作的正确位置

更新2

以下是应该可以工作的代码(基于您的尝试):


请注意,我并不是有意为
换行符
调用
空格
而使用循环。

不是。我正在用lexer/parser做很多事情。比如只打印多行/单行注释,计算一些特定的单词等。但唯一得到所有空行的事情仍然是挂起的!!!已尝试此代码,但在while循环中未将空白作为令牌接收

CommonTokenStream令牌=新的CommonTokenStream(新的AntlrPHPLexer(charStream));Token prevToken,currToken=null;while(tokens.LA(1)!=IntStream.EOF){currToken=tokens.LT(1);tokens.consume();if(prevToken!=null&&currToken.getText().trim().equals(“\n”)&&“\n”.equals(prevToken.getText())++counter;prevToken=currToken;

很抱歉,它不再工作了……即使换行符也不打印任何东西`Linebreak:'\r'?'\n'{System.out.println(“Linebreak:+getLine());}`不,我在做很多事情
CommonTokenStream tokenStream = new CommonTokenStream(new AntlrPHPLexer(charStream));

tokenStream.fill(); // Load all tokens.
int counter = 0;
List<Token> tokens = tokenStream.getTokens();
for (int i = 0; i < tokens.size(); ++i) {
  if (tokens.get(i).getType() == AntlrPHPLexer.Linebreak) {
    if (i == 0 || (tokens.get(i - 1).getType() == AntlrPHPLexer.Linebreak))
      ++counter;
  }
}
Whitespace: ([ \t]+ | Linebreak) -> skip;
Linebreak: [\r\n];