处理antlr 3中的隐藏通道
我正在写一个ANTR语法,用于将一种语言翻译成另一种语言,但是关于使用隐藏通道的文档非常稀少。我到处找不到一个例子。我唯一发现的是www.antlr.org上的FAQ,它告诉你如何访问隐藏频道,但不是如何最好地使用此功能。目标语言是Java 在我的语法文件中,我传递空格和注释,如下所示:处理antlr 3中的隐藏通道,antlr,hidden,channel,Antlr,Hidden,Channel,我正在写一个ANTR语法,用于将一种语言翻译成另一种语言,但是关于使用隐藏通道的文档非常稀少。我到处找不到一个例子。我唯一发现的是www.antlr.org上的FAQ,它告诉你如何访问隐藏频道,但不是如何最好地使用此功能。目标语言是Java 在我的语法文件中,我传递空格和注释,如下所示: // Send runs of space and tab characters to the hidden channel. WHITESPACE : (SPACE | TAB)
// 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();
}
}
肯定有更好的办法吗
编辑:这是输入语言的一个示例:
-- -----------------------------------------------------------------
--
--
-- 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
研究继承CommonTokenStream并将子类的一个实例提供给ANTLR。从您给出的代码示例中,我怀疑您可能有兴趣查看版本3中可用的过滤器和重写选项
另外,看看另一个。我刚刚讨论了我的一些老问题,认为用最有效的最终解决方案来回答是值得的。最后,翻译语言的最佳方法是使用StringTemplate。这将为您重新缩进输出。在ANTLR示例包中有一个非常好的例子叫做“cminus”,它展示了如何使用它。你能发布一个你正在翻译的语言的例子吗?还有这个翻译的最终结果ANTLR参考书展示了重写模式的例子-选项{rewrite=true;}-以及CommonTokenStream的子类TokenRewriteStream。我没有用过这些,但它们可能很有趣。顺便说一句,我是ANTLR的粉丝,你可能想看看介绍。@Bart:我不知道为什么语言的细节很重要。但输入语言是一种称为STL的定制语言,欧洲航天局使用该语言控制地面站设备。请参阅下面的代码。目标语言是Javascript,在Rhino引擎中运行一些定制。大部分语言转换已完成,但我希望保留注释。“大约有3000个这样的脚本。@安迪和格伦。谢谢你的信息。我将阅读一些关于重写和这个CommonTokenStream的文章。看来评论有限,所以我在原始问题中添加了示例。
-- -----------------------------------------------------------------
--
--
-- 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