ОК, похоже, вам нужна техника, которая называется lookahead. Вот очень хороший урок:
Учебник Lookahead
Тогда моя первая попытка была неправильной, но поскольку она работает для отдельных токенов, определяющих контекст, я оставлю это здесь (может быть, это кому-нибудь пригодится; о)).
Допустим, мы хотим иметь какой-то язык разметки. Все, что мы хотим "разметить":
- Выражения, состоящие из букв (abc ... zABC ... Z) и пробелов -> слова
- Выражения, состоящие из чисел (0-9) -> чисел
Мы хотим заключить слова в теги и цифры в теги. Так что, если я правильно понял, это то, что вы хотите сделать: если вы находитесь в контексте слова (между тегами слова), компилятор должен ожидать буквы и пробелы, в контексте чисел он ожидает числа.
Я создал файл WordNumber.jj, который определяет грамматику и анализатор, который будет сгенерирован:
options
{
LOOKAHEAD= 1;
CHOICE_AMBIGUITY_CHECK = 2;
OTHER_AMBIGUITY_CHECK = 1;
STATIC = true;
DEBUG_PARSER = false;
DEBUG_LOOKAHEAD = false;
DEBUG_TOKEN_MANAGER = false;
ERROR_REPORTING = true;
JAVA_UNICODE_ESCAPE = false;
UNICODE_INPUT = false;
IGNORE_CASE = false;
USER_TOKEN_MANAGER = false;
USER_CHAR_STREAM = false;
BUILD_PARSER = true;
BUILD_TOKEN_MANAGER = true;
SANITY_CHECK = true;
FORCE_LA_CHECK = false;
}
PARSER_BEGIN(WordNumberParser)
/** Model-tree Parser */
public class WordNumberParser
{
/** Main entry point. */
public static void main(String args []) throws ParseException
{
WordNumberParser parser = new WordNumberParser(System.in);
parser.Input();
}
}
PARSER_END(WordNumberParser)
SKIP :
{
" "
| "\n"
| "\r"
| "\r\n"
| "\t"
}
TOKEN :
{
< WORD_TOKEN : (["a"-"z"] | ["A"-"Z"] | " " | "." | ",")+ > |
< NUMBER_TOKEN : (["0"-"9"])+ >
}
/** Root production. */
void Input() :
{}
{
( WordContext() | NumberContext() )* < EOF >
}
/** WordContext production. */
void WordContext() :
{}
{
"<WORDS>" (< WORD_TOKEN >)+ "</WORDS>"
}
/** NumberContext production. */
void NumberContext() :
{}
{
"<NUMBER>" (< NUMBER_TOKEN >)+ "</NUMBER>"
}
Вы можете проверить это с помощью такого файла:
<WORDS>This is a sentence. As you can see the parser accepts it.</WORDS>
<WORDS>The answer to life, universe and everything is</WORDS><NUMBER>42</NUMBER>
<NUMBER>This sentence will make the parser sad. Do not make the parser sad.</NUMBER>
Последняя строка заставит парсер выдать исключение, подобное этому:
Exception in thread "main" ParseException: Encountered " <WORD_TOKEN> "This sentence will make the parser sad. Do not make the parser sad. "" at line 3, column 9.
Was expecting:
<NUMBER_TOKEN> ...
Это потому, что парсер не нашел того, что ожидал.
Надеюсь, это поможет.
Ура!
P.S .: Парсер не может быть "внутри" токена, так как токен является символом терминала (поправьте меня, если я ошибаюсь), который не может быть заменен правилами производства в дальнейшем. Таким образом, все аспекты контекста должны быть помещены в производственное правило (не терминальное), такое как «WordContext» в моем примере.