处理antlr 3中的隐藏通道

发布于 2024-10-02 17:37:08 字数 3070 浏览 8 评论 0 原文

我正在编写一个 ANTRL 语法,用于将一种语言翻译成另一种语言,但是有关使用 HIDDEN 通道的文档非常缺乏。我在任何地方都找不到例子。我唯一找到的是 www.antlr.org 上的常见问题解答,它告诉您如何访问隐藏通道,但不告诉您如何最好地使用此功能。目标语言是Java。

在我的语法文件中,我像这样传递空格和注释:

// Send runs of space and tab characters to the hidden channel.        
WHITESPACE 
    :   (SPACE | TAB)+ { $channel = HIDDEN; }
    ;

// Single-line comments begin with --
SINGLE_COMMENT 
    :    ('--' COMMENT_CHARS NEWLINE) {
            $channel=HIDDEN;
        }
    ;

fragment COMMENT_CHARS 
    :   ~('\r' | '\n')*
    ;

// Treat runs of newline characters as a single NEWLINE token.
NEWLINE 
    :   ('\r'? '\n')+ { $channel = HIDDEN; }
    ;

在我的成员部分中,我定义了一种将隐藏通道令牌写入输出 StringStream 的方法...

@members {

private int savedIndex = 0;

void ProcessHiddenChannel(TokenStream input) {      
    List<Token> tokens = ((CommonTokenStream)input).getTokens(savedIndex, input.index());
    for(Token token: tokens) {
        if(token.getChannel() == token.HIDDEN_CHANNEL) {
            output.append(token.getText());

        }
    }
    savedIndex = input.index();
}
}

现在要使用它,我必须在每个令牌之后调用该方法在我的语法中。

myParserRule
        :       MYTOKEN1 { ProcessHiddenChannel(input); }
                MYTOKEN2 { ProcessHiddenChannel(input); }
        ;

当然一定有更好的方法吗?

编辑:这是输入语言的示例:

-- -----------------------------------------------------------------
--
--
--  Name                Description
--  ==================================
--  IFM1/183         Freq Spectrum Inversion
--                     
-- -----------------------------------------------------------------

PROCEDURE IFM1/183

TITLE "Freq Spectrum Inversion";

HELP
      Freq Spectrum Inversion

ENDHELP;

PRIVILEGE CTRL;

WINDOW MANDATORY;

INPUT

   $Input : @NO_YES
   DEFAULT select %YES when /IFMS1/183.VALUE = %NO;
                  %NO otherwise
           endselect
   PROMPT "Spec Inv";

   $Forced_Cmd : BOOLEAN
   Default FALSE
   Prompt  "Forced Commanding";

DEFINE
   &RetCode   : @PSTATUS := %OK;
   &msg       : STRING;
   &Input     : BOOLEAN;

REQUIRE AVAILABLE(/IFMS1)
        MSG "IFMS1 not available";

REQUIRE /IFMS1/001.VALUE = %MON_AND_CTRL
        MSG "IFMS1 not in control mode";

BEGIN  -- Procedure Body --

    &msg := "IFMS1/183 -> " + toString($Input) + " : "; 

-- pre-check

   IF /IFMS1/183.VALUE = $Input
      AND $Forced_Cmd = FALSE THEN
      EXIT (%OK, MSG &msg + "already set");
   ENDIF;

-- command

   IF $Input =  %YES THEN &Input:= TRUE;
    ELSE  &Input:= FALSE;
   ENDIF;

   SET &RetCode := SEND IFMS1.FREQPLAN
        ( $FreqSpecInv := &Input);
   IF &RetCode <> %OK THEN
      EXIT (&RetCode, MSG &msg + "command failed");
   ENDIF;

-- verify

   SET &RetCode := VERIFY /IFMS1/183.VALUE = $Input TIMEOUT '10';
   IF &RetCode <> %OK THEN
      EXIT (&RetCode, MSG &msg + "verification failed");
   ELSE
      EXIT (&RetCode, MSG &msg + "verified");
   ENDIF;

END

I am writing an ANTRL grammar for translating one language to another but the documentation on using the HIDDEN channel is very scarce. I cannot find an example anywhere. The only thing I have found is the FAQ on www.antlr.org which tells you how to access the hidden channel but not how best to use this functionality. The target language is Java.

In my grammar file, I pass whitespace and comments through like so:

// Send runs of space and tab characters to the hidden channel.        
WHITESPACE 
    :   (SPACE | TAB)+ { $channel = HIDDEN; }
    ;

// Single-line comments begin with --
SINGLE_COMMENT 
    :    ('--' COMMENT_CHARS NEWLINE) {
            $channel=HIDDEN;
        }
    ;

fragment COMMENT_CHARS 
    :   ~('\r' | '\n')*
    ;

// Treat runs of newline characters as a single NEWLINE token.
NEWLINE 
    :   ('\r'? '\n')+ { $channel = HIDDEN; }
    ;

In my members section I have defined a method for writing hidden channel tokens to my output StringStream...

@members {

private int savedIndex = 0;

void ProcessHiddenChannel(TokenStream input) {      
    List<Token> tokens = ((CommonTokenStream)input).getTokens(savedIndex, input.index());
    for(Token token: tokens) {
        if(token.getChannel() == token.HIDDEN_CHANNEL) {
            output.append(token.getText());

        }
    }
    savedIndex = input.index();
}
}

Now to use this, I have to call the method after every single token in my grammar.

myParserRule
        :       MYTOKEN1 { ProcessHiddenChannel(input); }
                MYTOKEN2 { ProcessHiddenChannel(input); }
        ;

Surely there must be a better way?

EDIT: This is an example of the input language:

-- -----------------------------------------------------------------
--
--
--  Name                Description
--  ==================================
--  IFM1/183         Freq Spectrum Inversion
--                     
-- -----------------------------------------------------------------

PROCEDURE IFM1/183

TITLE "Freq Spectrum Inversion";

HELP
      Freq Spectrum Inversion

ENDHELP;

PRIVILEGE CTRL;

WINDOW MANDATORY;

INPUT

   $Input : @NO_YES
   DEFAULT select %YES when /IFMS1/183.VALUE = %NO;
                  %NO otherwise
           endselect
   PROMPT "Spec Inv";

   $Forced_Cmd : BOOLEAN
   Default FALSE
   Prompt  "Forced Commanding";

DEFINE
   &RetCode   : @PSTATUS := %OK;
   &msg       : STRING;
   &Input     : BOOLEAN;

REQUIRE AVAILABLE(/IFMS1)
        MSG "IFMS1 not available";

REQUIRE /IFMS1/001.VALUE = %MON_AND_CTRL
        MSG "IFMS1 not in control mode";

BEGIN  -- Procedure Body --

    &msg := "IFMS1/183 -> " + toString($Input) + " : "; 

-- pre-check

   IF /IFMS1/183.VALUE = $Input
      AND $Forced_Cmd = FALSE THEN
      EXIT (%OK, MSG &msg + "already set");
   ENDIF;

-- command

   IF $Input =  %YES THEN &Input:= TRUE;
    ELSE  &Input:= FALSE;
   ENDIF;

   SET &RetCode := SEND IFMS1.FREQPLAN
        ( $FreqSpecInv := &Input);
   IF &RetCode <> %OK THEN
      EXIT (&RetCode, MSG &msg + "command failed");
   ENDIF;

-- verify

   SET &RetCode := VERIFY /IFMS1/183.VALUE = $Input TIMEOUT '10';
   IF &RetCode <> %OK THEN
      EXIT (&RetCode, MSG &msg + "verification failed");
   ELSE
      EXIT (&RetCode, MSG &msg + "verified");
   ENDIF;

END

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

天生の放荡 2024-10-09 17:37:08

研究继承 CommonTokenStream 并将子类的实例输入 ANTLR。从您提供的代码示例中,我怀疑您可能有兴趣查看版本 3 中可用的过滤器和重写选项。

另外,请查看其他 相关堆栈溢出问题

Look into inheriting CommonTokenStream and feeding an instance of your subclass into ANTLR. From the code example that you give, I suspect that you might be interested in taking a look at the filter and the rewrite options available in version 3.

Also, take a look at this other related stack overflow question.

如痴如狂 2024-10-09 17:37:08

我刚刚解决了一些旧问题,并认为值得以最有效的最终解决方案进行回应。最后,翻译语言的最佳方法是使用 StringTemplate。这会为您重新缩进输出。 ANTLR 示例包中有一个非常好的示例,名为“cminus”,它展示了如何使用它。

I have just been going through some of my old questions and thought it was worth responding with the final solution that worked the best. In the end, the best way to translate a language was to use StringTemplate. This takes care of re-indenting the output for you. There is a very good example called 'cminus' in the ANTLR example pack that shows how to use it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文