1

JavaCC にコンテキスト (現在の親トークン) を認識させる必要があり、そのコンテキストに応じて、異なるトークンが発生することを期待します。

次の擬似コードを検討してください。

TOKEN <abc> { "abc*" } // recognizes "abc", "abcd", "abcde", ...
TOKEN <abcd> { "abcd*" } // recognizes "abcd", "abcde", "abcdef", ...

TOKEN <element1> { "element1" "[" expectOnly(<abc>) "]" }
TOKEN <element2> { "element2" "[" expectOnly(<abcd>) "]" }
...

したがって、生成されたパーサーが という名前のトークンの「内部」にある場合、それは として認識されます"element1"が、それが「内部」という名前のトークンの場合、 と同じ文字列を認識します。"abcdef"<abc>"element2"<abcd>

element1 [ abcdef ] // aha! it can only be <abc>
element2 [ abcdef ] // aha! it can only be <abcd>

私が間違っていなければ、XML ファイルのより複雑な DTD 定義と同様に動作します。

では、どの「コンテキスト」でどのトークンが有効/期待されるかをどのように指定できますか?

注:私の実際のケースでは、トークンの一種の「階層」を定義するだけでは十分ではない<abcd>ため、「abcdef」は常にand よりも最初に照合され<abc>ます。コンテキスト認識トークンが本当に必要です。

4

2 に答える 2

2

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」のようなプロダクション ルール (非ターミナル) 内に配置する必要があります。

于 2010-05-05T11:47:55.187 に答える
1

レクサー状態を使用する必要があります。あなたの例は次のようになります。

<DEFAULT> TOKEN: { <ELEMENT1: "element1">: IN_ELEMENT1 }
<DEFAULT> TOKEN: { <ELEMENT2: "element2">: IN_ELEMENT2 }
<IN_ELEMENT1> TOKEN: { <ABC: "abc" (...)* >: DEFAULT }
<IN_ELEMENT2> トークン: { <ABCD: "abcd" (...)*>: DEFAULT }

(...)*適切な JavaCC 構文ではないことに注意してください。

于 2011-02-08T17:05:27.580 に答える