【问题标题】:Grab all blank lines by Antlr 4 lexer/parser通过 Antlr 4 词法分析器/解析器抓取所有空行
【发布时间】:2017-06-13 14:00:43
【问题描述】:

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

空白标记定义为:

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

?>

【问题讨论】:

    标签: antlr antlr4


    【解决方案1】:

    试试这样的:

    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()

    【讨论】:

    • 这种方法不起作用...EmptyLine 词法分析器规则永远没有机会匹配和触发
    • Whitespace 规则中删除 + 符号后,EmptyLine 被触发,但在每个空行匹配之后,生成错误

      行 3:0 无关输入 '\r\n' 期望 {、HtmlText、HtmlScriptOpen、HtmlStyleOpen、HtmlDtd、HtmlOpen、HtmlClose、'/>'、HtmlSlash、HtmlEquals、HtmlStartQuoteString、HtmlStartDoubleQuoteString、HtmlHex , HtmlDecimal, HtmlName, HtmlEndQuoteString, HtmlQuoteString, HtmlEndDoubleQuoteString, HtmlDo.....}

    • 如果你的语法中突然没有skipping 空白字符(或换行符),那么你的解析器确实会抱怨令牌流不是它所期望的成为。这是一个完全不同的问题。您的问题是如何区分空行和空格字符,我想我已经回答了。如果您有其他问题,我建议您创建一个新问题并提供足够的信息(您的确切语法)以便其他人能够提供帮助。
    • 没什么可讨论的:)我之前的评论对于这个问答来说已经足够了。
    【解决方案2】:

    这是您对 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];
    

    请注意,我没有有意为Whitespace 中的Linebreak 调用使用循环。

    【讨论】:

    • 没有。我正在通过词法分析器/解析器做很多事情..比如只打印多行/单行 cmets,计算一些特定的单词等。但唯一得到所有空行的事情仍然悬而未决!!!
    • 试过这段代码,但是 Whitespace 在 while 循环中没有被接收为令牌

      CommonTokenStream tokens = new CommonTokenStream(new AntlrPHPLexer(charStream)); Token prevToken , currToken = null; while (tokens.LA(1) != IntStream.EOF) { currToken = tokens.LT(1); tokens.consume(); if (prevToken != null &amp;&amp; currToken.getText().trim().equals("\n") &amp;&amp; "\n".equals(prevToken.getText())) ++counter; prevToken = currToken; }
    • 很抱歉......它不再工作......即使换行符也没有打印任何东西`换行符:'\r'? '\n' { System.out.println("换行符:" + getLine()); };`
    猜你喜欢
    • 1970-01-01
    • 2011-01-30
    • 1970-01-01
    • 2012-03-04
    • 1970-01-01
    • 2023-03-19
    • 1970-01-01
    • 2014-03-25
    • 1970-01-01
    相关资源
    最近更新 更多