Обрабатывать скрытый канал в ANTLR 3
Вопрос
Я пишу грамматику Antrl для перевода одного языка в другое, но документация по использованию скрытого канала очень скудна. Я не могу найти пример в любом месте. Единственное, что я нашел, - это FAQ на 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
Решение
Посмотрите на наследование CommontedStream и кормление экземпляра вашего подкласса в ANTLR. Из примера кода, который вы даете, я подозреваю, что вам может быть заинтересован в том, чтобы посмотреть на фильтр и параметры перезаписи, доступные в версии 3.
Кроме того, посмотрите на это другое Связанный вопрос переполнения стека.
Другие советы
Я только что проходил через некоторые из моих старых вопросов и думал, что стоит ответить на окончательное решение, которое работало лучшее. В конце концов, лучший способ перевести язык должен был использовать StringTemplate. Это заботится о перезагрузке на вывод для вас. Существует очень хороший пример под названием «CMINUS» в примерной упаковке ANTLR, который показывает, как его использовать.