如何获取从默认通道和隐藏通道读取的Antlr解析器规则

如何获取从默认通道和隐藏通道读取的Antlr解析器规则,antlr,antlr3,lexer,parser-generator,Antlr,Antlr3,Lexer,Parser Generator,我在隐藏通道中使用了正常的空格分隔,但是我有一个规则,我希望在后面的处理中包含任何空格,但是我发现的任何示例都需要一些非常奇怪的手动编码 没有一个简单的选项可以从多个通道读取,比如从一开始就把空白放在那里 这是空格lexer规则 WS : ( ' ' | '\t' | '\r' | '\n' ) {$channel=HIDDEN;} ; 这是我的规则,我想包括空格 raw : '{'? (~('{'))*; 基

我在隐藏通道中使用了正常的空格分隔,但是我有一个规则,我希望在后面的处理中包含任何空格,但是我发现的任何示例都需要一些非常奇怪的手动编码

没有一个简单的选项可以从多个通道读取,比如从一开始就把空白放在那里

这是空格lexer规则

WS  :   ( ' '
        | '\t'
        | '\r'
        | '\n'
        ) {$channel=HIDDEN;}
    ;
这是我的规则,我想包括空格

raw :   '{'? (~('{'))*;
基本上,它是一个“一网打尽”的规则,用于捕获与其他模式处理的其他规则不匹配的任何内容,因此我需要原始流

我希望有一个
{$channel==DEFAULT | |$channel==HIDDEN}
语法示例,但找不到任何语法示例


我的目标是C#,但如果需要,我可以重写Java示例。

AFAIK,这是不可能的。但是,您可以扩展
无缓冲的TokenStream
,以在解析期间更改
通道。您不能使用
CommonTokenStream
,因为它缓冲了可变数量的令牌(并且缓冲区中可能有位于错误通道上的令牌!)。请注意,您至少需要ANTLR 3.3:在以前的版本中,
未缓冲的TokenStream
尚未包括在内

假设您想要解析(并显示)小写或大写字母。大写字母放在
隐藏的
通道上,因此通过deafult,只解析小写字母。然而,当解析器偶然发现小写的
“q”
时,我们希望切换到
隐藏的
通道。一旦对
隐藏的
频道进行解析,我们希望
的“Q”
再次将我们带回
默认频道

因此,在解析源代码时,首先打印
“a”
“b”
“c”
,然后更改频道,然后打印
“c”
“D”
,然后再次更改频道,最后将
“e”
打印到控制台

下面是一个ANTLR语法,它可以做到这一点:

ChannelDemo.g 下面是自定义令牌流类:

ChangeableChannelTokenStream.java 还有一个小的主类来测试这一切:

主类 最后,生成一个lexer/parser(1),编译所有源文件(2)并运行主类(3):

1. 根据上述语法生成的解析器将在遇到
“*”
时启用从所有通道读取。因此,在解析“aAbB*cCdDeE”时:

将打印以下内容:

a b c C d D e E A. B C C D D E E
也许你应该考虑把空白当作你的Gracar的一部分。但是为什么要用这些不重要的信息把你的gramar搞得乱七八糟呢?嗯,因为这不是不重要的。这条新线在某些情况下有意义。当您需要IDE支持时,例如从visual studio语言服务器获得IDE支持时,您需要指定一个语言语法,而不需要低级别ANTLR定制的所有细节。

Antler 4
中,我使用的是一个简单的解决方案。我没有在
antlr3
中测试它。它是C#,但您可以轻松地将其转换为Java

  • 将parser1.g4更改为下一步:

    parser grammar Parser1;
    
    options { tokenVocab=Lexer1; }
    
    startRule
    @init { SetWhiteSpacesAcceptence(false); } 
        : (componentWithWhiteSpaces | componentWithoutWhiteSpaces)* EOF
    ;
    
    componentWithWhiteSpaces : { SetWhiteSpacesAcceptence(true); } 
                                component1 component2 component3 
                                { SetWhiteSpacesAcceptence(false); } 
    ;
    
    componentWithoutWhiteSpaces : component4 component5 component6 
    
    lexer grammar Lexer1;
    WS : [ \t\r\n] { if( this.IsWhiteSpacesAccepted() ) Skip(); };
    
  • 将lexer1.g4更改为下一步:

    parser grammar Parser1;
    
    options { tokenVocab=Lexer1; }
    
    startRule
    @init { SetWhiteSpacesAcceptence(false); } 
        : (componentWithWhiteSpaces | componentWithoutWhiteSpaces)* EOF
    ;
    
    componentWithWhiteSpaces : { SetWhiteSpacesAcceptence(true); } 
                                component1 component2 component3 
                                { SetWhiteSpacesAcceptence(false); } 
    ;
    
    componentWithoutWhiteSpaces : component4 component5 component6 
    
    lexer grammar Lexer1;
    WS : [ \t\r\n] { if( this.IsWhiteSpacesAccepted() ) Skip(); };
    
  • Parser1
    类扩展为下一个:

    class MyParser : Parser1
    {
        public void SetWhiteSpacesAcceptence(bool isAccept)
        {
            if (_input != null && _input.TokenSource != null)
            {
                if (_input.TokenSource is MyLexer)
                {
                    MyLexer lexer = _input.TokenSource as MyLexer;
                    if (lexer != null)
                        lexer.SetWhiteSpacesAcceptence(isAccept);
                }
            }
        }
    
        public bool IsWhiteSpacesAccepted()
        {
            if (_input != null && _input.TokenSource != null)
            {
                if (_input.TokenSource is MyLexer)
                {
                    MyLexer lexer = _input.TokenSource as MyLexer;
                    if (lexer != null)
                        return lexer.IsWhiteSpacesAccepted();
                }
            }
    
            return false;
        }
    }
    
    class MyLexer : Lexer1
    {
        private bool isWhiteSpacesAccepted;
    
        public void SetWhiteSpacesAcceptence(bool isAccept) { isWhiteSpacesAccepted = isAccept }
    
        public bool IsWhiteSpacesAccepted() { return isWhiteSpacesAccepted; }
    }
    
  • Lexer1
    类扩展为下一个:

    class MyParser : Parser1
    {
        public void SetWhiteSpacesAcceptence(bool isAccept)
        {
            if (_input != null && _input.TokenSource != null)
            {
                if (_input.TokenSource is MyLexer)
                {
                    MyLexer lexer = _input.TokenSource as MyLexer;
                    if (lexer != null)
                        lexer.SetWhiteSpacesAcceptence(isAccept);
                }
            }
        }
    
        public bool IsWhiteSpacesAccepted()
        {
            if (_input != null && _input.TokenSource != null)
            {
                if (_input.TokenSource is MyLexer)
                {
                    MyLexer lexer = _input.TokenSource as MyLexer;
                    if (lexer != null)
                        return lexer.IsWhiteSpacesAccepted();
                }
            }
    
            return false;
        }
    }
    
    class MyLexer : Lexer1
    {
        private bool isWhiteSpacesAccepted;
    
        public void SetWhiteSpacesAcceptence(bool isAccept) { isWhiteSpacesAccepted = isAccept }
    
        public bool IsWhiteSpacesAccepted() { return isWhiteSpacesAccepted; }
    }
    
  • 现在,
    Main
    功能如下:

    static void Main()
    {
        AntlrFileStream input = new AntlrFileStream("pathToInputFile");
        MyLexer lexer = new MyLexer(input);
        UnbufferedTokenStream tokens = new UnbufferedTokenStream(lexer);
        MyParser parser = new MyParser(tokens);
    
        parser.startRule();
    }
    

  • 我将尝试从任何通道读取解决方案,因为这正是我想要的:)在使用AntlrWorks进行开发时,是否可以在.g文件中包含该类,而不必在外部编译和运行?如何在C#中实现?在Antlr.Runtime或Antlr.Runtime中没有“UnbufferedTokenStream”。Misc@Tizz,我不知道,不幸的是,C#不是我的强项。@BartKiers和Java不是我的强项。嗯,这里有一些好的方面,我希望我能翻译,但进展不太顺利。谢谢你的回答,我自己使用C语言,但我放弃了Antler,转而使用手工编码的lexel/解析器,部分原因是Antler在一段时间内与C语言目标有太多问题,但也因为Antler在我们的“语言”中遇到了问题嵌入在原始文本中,如html或javascript。Antler(或者至少据我所知)最适合于更严格的语法。 a b c C d D e E
    parser grammar Parser1;
    
    options { tokenVocab=Lexer1; }
    
    startRule
    @init { SetWhiteSpacesAcceptence(false); } 
        : (componentWithWhiteSpaces | componentWithoutWhiteSpaces)* EOF
    ;
    
    componentWithWhiteSpaces : { SetWhiteSpacesAcceptence(true); } 
                                component1 component2 component3 
                                { SetWhiteSpacesAcceptence(false); } 
    ;
    
    componentWithoutWhiteSpaces : component4 component5 component6 
    
    lexer grammar Lexer1;
    WS : [ \t\r\n] { if( this.IsWhiteSpacesAccepted() ) Skip(); };
    
    class MyParser : Parser1
    {
        public void SetWhiteSpacesAcceptence(bool isAccept)
        {
            if (_input != null && _input.TokenSource != null)
            {
                if (_input.TokenSource is MyLexer)
                {
                    MyLexer lexer = _input.TokenSource as MyLexer;
                    if (lexer != null)
                        lexer.SetWhiteSpacesAcceptence(isAccept);
                }
            }
        }
    
        public bool IsWhiteSpacesAccepted()
        {
            if (_input != null && _input.TokenSource != null)
            {
                if (_input.TokenSource is MyLexer)
                {
                    MyLexer lexer = _input.TokenSource as MyLexer;
                    if (lexer != null)
                        return lexer.IsWhiteSpacesAccepted();
                }
            }
    
            return false;
        }
    }
    
    class MyLexer : Lexer1
    {
        private bool isWhiteSpacesAccepted;
    
        public void SetWhiteSpacesAcceptence(bool isAccept) { isWhiteSpacesAccepted = isAccept }
    
        public bool IsWhiteSpacesAccepted() { return isWhiteSpacesAccepted; }
    }
    
    static void Main()
    {
        AntlrFileStream input = new AntlrFileStream("pathToInputFile");
        MyLexer lexer = new MyLexer(input);
        UnbufferedTokenStream tokens = new UnbufferedTokenStream(lexer);
        MyParser parser = new MyParser(tokens);
    
        parser.startRule();
    }