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

时间:2017-06-13 14:00:43

标签: antlr antlr4

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

Whitespace标记定义为:

Whitespace:         [ \t\r\n]+ -> skip;

我将其更改为:

Whitespace: (
             ' ' 
             | '\t' 
             | '\r' '\n' { newline(); } 
             | '\n'       { newline(); }
            );

但它收集了几乎所有的行,因为每一行都以“ \ n ”结尾。任何专家建议都可以帮助我。

要测试的示例PHP:

<?php

//02-5002201-00001 5002201 - Machine hours test

	function test()
	{	
/*	Name:			Test.php

	Title:			Demo

	by:				XYZ
*/
		if (true && false)
		{		
			echo "aa";
		}

//TODO		
		echo <<<SEGDTA
		<link rel="stylesheet" type="text/css" href="ui.css"/>

		<script type="text/javascript" src="min.js"></script>
		SEGDTA;
	}

?>

2 个答案:

答案 0 :(得分:2)

尝试这样的事情:

lexer grammar DemoLexer;

EmptyLine
 : {super.getCharPositionInLine() == 0}? [ \t]* '\r'? '\n'
 ;

Whitespace
 : [ \t\r\n] -> skip
 ;

Other
 : .
 ;

如果我运行以下测试类:

import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.Token;

public class Main {

    public static void main(String[] args) {

        String source = "foo\n" +
                "\n" +
                "bar\n" +
                "    \n" +
                "   baz   \r\n" +
                " \t\t\n" +
                "\tend\n\n";

        DemoLexer lexer = new DemoLexer(CharStreams.fromString(source));

        for (Token t : lexer.getAllTokens()) {

            String name = lexer.getTokenNames()[t.getType()];
            String text = t.getText().replace("\r","\\r").replace("\n","\\n").replace("\t","\\t");

            System.out.printf("%-20s '%s'\n", name, text);
        }
    }
}

这将打印出来:

Other                'f'
Other                'o'
Other                'o'
EmptyLine            '\n'
Other                'b'
Other                'a'
Other                'r'
EmptyLine            '    \n'
Other                'b'
Other                'a'
Other                'z'
EmptyLine            ' \t\t\n'
Other                'e'
Other                'n'
Other                'd'
EmptyLine            '\n'

请参阅:http://www.antlr.org/api/Java/org/antlr/v4/runtime/TokenSource.html#getCharPositionInLine()

答案 1 :(得分:1)

这是您使用PHP代码进行的唯一处理吗?如果是这样,您可以直接加载文件并计算空条目。在这种情况下不需要解析器。

<强>更新

因为你有这个解析器,你可以使用令牌流并遍历所有令牌。每当您看到换行符检查上一个令牌时,如果这也是换行符(或者这是流中的第一个令牌),您会找到一个空行。您甚至可以隐藏您的空白,因为令牌流将为您提供所有通道上的所有令牌(除非您对其进行过滤)。

无论如何,计算空行是一个语义步骤,解析器(正在执行语法步骤)不适合这个。

更新2

这里的代码应该有效(基于你的尝试):

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

请注意,我没有在Linebreak Whitespace中使用循环。{/ p>