Antlr中$channel = HIDDEN


有时象注释这样的部分在编译时并不是完全放弃的,如java中在/**….*/的注释形式中可以添加说明最终生成程序的文档,在.NET中使用 /// 注释形式也有类似的功能。也就是说我们在编译代码时忽略这些注释,而在分析生成文档时又要用到这些注释。这样的话就不能使用skip();方法了,skip()方法是抛弃其内容。所以ANTLR中加入了channel属性用来指定当前匹配的内容是属于哪一个频道,分析过程中关心哪个频道就可以只接收哪个频道的内容。ANTLR中定义有两个频道常量DEFAULT_CHANNEL和HIDDEN_CHANNEL,一般情况下匹配的内容都中放到DEFAULT_CHANNEL中。我们可以指定让当前匹配的内容放到哪个频道中。

前面示例中的词法规则可以改成如下形式。

COMMENT :  '/*'  .*  '*/' {$channel=HIDDEN;} ;

LINE_COMMENT :'//'  ~ ('\n' | '\r') *  '\r'? '\n' {$channel=HIDDEN;} ;

WS : ( ' ' | '\t'| '\n' | '\r' ) +  {$channel=HIDDEN;};

COMMENT、LINE_COMMENT和WS词法规则后面加入{$channel=HIDDEN;},这样匹配的字符就会被存放到HIDDEN频道中。下面将这个修改后的文法编译运行,其结果和使用skip()方法时是一样的。这就是说存在于HIDDEN频道中的内容被语法分析器忽略了,因为在默认情况下ANTLR语法分析程序只分析DEFAULT_CHANNEL中的内容。

Channel这个概念是介于词法分析和语法分析之间的一个概念,将存放匹配的内容存放到各个频道中是在词法分析时进行的,而语法分析时可以有选择的读某一个频道中的内容。那么如何让语法分析程序处理示例中的注释内容呢?我们再次修改文法因为我们只关心注释所以把WS : ( ' ' | '\t' | '\n' | '\r' ) + {Skip();};改回成skip()方法因为空白我们是不关心的,下面给出全部的文法。

grammar TestHidden;

options {

  language=CSharp;

  output=AST;

}

a : b INT b;

 

b : (COMMENT |LINE_COMMENT)*;

 

INT : DIGIT+;

DIGIT : '0' ..'9';

COMMENT :  '/*'  .*  '*/' {$channel=HIDDEN;} ;

LINE_COMMENT :'//'  ~ ('\n' | '\r') *  '\r'? '\n' {$channel=HIDDEN;} ;

WS : ( ' ' | '\t'| '\n' | '\r' ) +  {Skip();} ;

下面是运行代码,运行代码中加入了tokenStream.SetTokenTypeChannel方法。

TestSkipLexer lex= new TestSkipLexer(new ANTLRFileStream("f1.txt"));

CommonTokenStreamtokenStream = new CommonTokenStream(lex);

TestSkipParserparser = new TestSkipParser(tokenStream);

tokenStream.SetTokenTypeChannel(TestSkipLexer.COMMENT,Token.DEFAULT_CHANNEL);

tokenStream.SetTokenTypeChannel(TestSkipLexer.LINE_COMMENT,Token.DEFAULT_CHANNEL);

TestSkipParser.a_return bReturn = parser.a();


SetTokenTypeChannel方法是将指定的频道中的符号加入到分析程序关心的范围内,第一个参数是词法符号,第二个参数是这个符号所处频道。两条SetTokenTypeChannel语句将DEFAULT_CHANNEL 频道中的COMMENT、LINE_COMMENT加入到语法分析程序 channelOverrideMap集合中,语法分析程序会分析 channelOverrideMap集中注册的类型,此示例运行后的语法树有四个子节点:

你可能感兴趣的:(java,.net,文档,output)