OK、ここで先読みというテクニックが必要なようです。ここに非常に優れたチュートリアルがあります:
先読みチュートリアル
私の最初の試みは間違っていましたが、コンテキストを定義する個別のトークンに対して機能するため、ここに残します (誰かにとって役立つかもしれません;o))。
ある種のマークアップ言語が必要だとしましょう。「マークアップ」したいのは次のとおりです。
- 文字 (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> ...
これは、パーサーが予期したものを見つけられなかったためです。
それが役立つことを願っています。
乾杯!
PS: トークンはターミナル シンボルであるため、パーサーはトークン内に「存在」することはできません (間違っている場合は訂正してください)。したがって、すべてのコンテキストの側面は、私の例の「WordContext」のようなプロダクション ルール (非ターミナル) 内に配置する必要があります。