处理antlr 3中的隐藏通道

时间:2010-11-17 10:21:02

标签: antlr hidden channel

我正在编写一种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

2 个答案:

答案 0 :(得分:0)

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

另外,请查看其他related stack overflow question

答案 1 :(得分:0)

我刚刚经历了一些旧的问题,并认为值得回应的是最佳解决方案。最后,翻译语言的最佳方法是使用StringTemplate。这需要为您重新缩进输出。在ANTLR示例包中有一个非常好的例子叫做'cminus',它展示了如何使用它。