Моя грамматика дает неожиданный результат. Я не уверен, является ли это просто моей ошибкой или некоторыми проблемами с логикой обработки неоднозначных альтернатив ANTLR.
Вот моя грамматика:
grammar PPMacro;
options {
language=Java;
backtrack=true;
}
file: (inputLines)+ EOF;
inputLines
: ( preprocessorLineSet | oneNormalInputLine ) ;
oneNormalInputLine @after{System.out.print("["+$text+"]");}
: (any_token_except_crlf)* CRLF ;
preprocessorLineSet
: ifPart endifLine;
ifPart: ifLine inputLines* ;
ifLine @after{System.out.print("{"+$text+"}" );}
: '#' IF (any_token_except_crlf)* CRLF ;
endifLine @after{System.out.print("{"+$text+"}" );}
: '#' ENDIF (any_token_except_crlf)* CRLF ;
any_token_except_crlf: (ANY_ID | WS | '#'|IF|ENDIF);
// just matches everything
CRLF: '\r'? '\n' ;
WS: (' '|'\t'|'\f' )+;
Hash: '#' ;
IF : 'if' ;
ENDIF : 'endif' ;
ANY_ID: ( 'a'..'z'|'A'..'Z'|'0'..'9'| '_')+ ;
Объяснение
Он предназначен для разбора блока C ++ #if ... #endif
Я пытаюсь распознать вложенный блок #if #endif. Это делается моим препроцессором LineSet . Он содержит рекурсивное определение для поддержки вложенного блока. oneNormalInputLine предназначен для обработки чего-либо, кроме формы #if. Это правило соответствует правилу соответствия чему-либо и фактически соответствует строке #if. Но я намеренно поместил его после препроцессораLineSet в inputLines . Я ожидаю, что этот порядок может помешать совпадению строк #if или #endif. Причина использования правила перехвата заключается в том, что я хочу, чтобы правило принимало любой другой синтаксис c ++ и просто возвращало их в вывод.
Я мой тест, я просто распечатываю все. Строки, совпадающие с preprocessorLineSet , должны быть окружены {}, а строки, соответствующие oneNormalInputLine , должны быть окружены [].
Пример ввода :
#if s
s
#if a
s
s
#endif
#endif
и это
#if
abc
#endif
Соответствующие выходы:
[#if s
][s
][#if a
][s
][s
][#endif
][#endif
]
и это
[#if
][abc
][#endif
]
Проблема
Все выходные строки, включая #if #endif, окружены [], что означает, что они совпадают ТОЛЬКО с oneNormalInputLine ! Но я не ожидаю этого. preprocessorLineSet должен соответствовать строкам #if. Почему я получил этот результат?
Эта строка содержит неоднозначные альтернативы:
inputLines : ( preprocessorLineSet | oneNormalInputLine );
, поскольку оба могут соответствовать #if и #endif. Но я ожидаю, что следует использовать первую альтернативу, а не более позднюю. Также обратите внимание, что функция возврата включена.
EDIT
Причина, по которой мое правило oneNormalInputLine принимает все, заключается в том, что трудно выразить что-то, не имеющее определенного шаблона, поскольку шаблон #if может быть довольно сложным:
/***
comments
*/ # /***
comments
*/ if
является допустимым шаблоном. Написание правила, не имеющего этого шаблона, кажется трудным.