2

文字ストリームを解析するために LL(k) EBNF 文法を使用しています。3 種類のトークンが必要です。

CHARACTERS

  letter = 'A'..'Z' + 'a'..'z' .
  digit = "0123456789" .
  messageChar = '\u0020'..'\u007e' - ' ' - '(' - ')' .

TOKENS

  num = ['-'] digit { digit } [ '.' digit { digit } ] .
  ident = letter { letter | digit | '_' } .
  message = messageChar { messageChar } .

最初の 2 つのトークン宣言は、共通の文字を共有していないため問題ありません。

ただし、3 番目のmessage, は無効です。これは、一部の文字列が と の両方である可能性がnumありmessage( など"123")、他の文字列が と の両方である可能性があるidentためですmessage( など"Hello")。したがって、トークナイザーは正しく区別できません。

もう 1 つの例は、整数と実数の区別です。すべての実数に少なくとも 1 つの小数点以下の桁数が必要でない限り (つまり、1 は 1.0 としてエンコードする必要がありますが、これは私にとってはオプションではありません)、これら 2 つの数値の違いについて文法でサポートを得ることができません。種類。すべての値が実数として表現され、ポイントの後にチェックを行う必要がありました。それは問題ありませんが、最適ではありません。私の本当の問題はmessageトークンにあります。そのための回避策が見つかりません。

問題は、LL(k) EBNF 文法でこれを行うことができるかということです。CoCo/Rを使用してパーサーとスキャナーを生成しています。

LL(k) EBNF でそれができない場合、他にどのようなオプションを検討できますか?

編集これは、CoCo/R から取得した出力です。

ココ/R (2010 年 4 月 23 日)
トークンが二重でメッセージが区別できない
トークン ident とメッセージを区別できません
...
9 個のエラーが検出されました
4

3 に答える 3

3

これを試して:

CHARACTERS

    letter = 'A'..'Z' + 'a'..'z' .
    digit = "0123456789" .
    messageChar = '\u0020'..'\u007e' - ' ' - '(' - ')'  .

TOKENS

    double = ['-'] digit { digit } [ '.' digit { digit } ] .
    ident = letter { letter | digit | '_' } .
    message = messageChar { messageChar } CONTEXT (")") .

'\u0020'ああ、それは Unicode SPACE であり、後で " " で削除することを指摘しなければなりません- ' '。ああ、 CONTEXT (')')複数の文字の先読みが必要ない場合に使用できます。上記のすべてのトークンが')'.

FWIW:CONTEXT囲まれたシーケンスを消費しません。プロダクションでそれを消費する必要があります。

編集:

わかりました、これはうまくいくようです。本当に、私は今回それを意味します:)

CHARACTERS
    letter = 'A'..'Z' + 'a'..'z' .
    digit = "0123456789" .
//    messageChar = '\u0020'..'\u007e' - ' ' - '(' - ')'  .

TOKENS

    double = ['-'] digit { digit } [ '.' digit { digit } ] .
    ident = letter { letter | digit | '_' } .
//    message = letter { messageChar } CONTEXT (')') .

// MessageText<out string m> = message               (. m = t.val; .)
// .

HearExpr<out HeardMessage message> =
    (.
        TimeSpan time; 
        Angle direction = Angle.NaN; 
        string messageText = ""; 
    .)
    "(hear" 
    TimeSpan<out time>
        ( "self" | AngleInDegrees<out direction> )
//         MessageText<out messageText>
    {
        ANY (. messageText += t.val; .)
    }
    ')'
    (. 
        message = new HeardMessage(time, direction, new Message(messageText)); 
    .)
    .

ANY')' または空白に到達するまで文字を読み取ります。各値を連結するループに入れましたが、そうしたくないかもしれません。ただし、「ここ」ではなく「ここ」を見たときに「上」を返さないように、ループに入れたい場合があります。messageText の単純な長さチェック、またはリストへの t.val の追加やカウントのチェックなどのその他の有効性チェックを実行できます。本当に何でも。RegEx を使用してテストを実行し、チェックする必要のあるパターンに準拠していることを確認することもできます。

編集 (2011 年 4 月 8 日): Coco/R を整数と実数で使用する例

COMPILER Calculator
CHARACTERS
    digit       = "0123456789".

TOKENS
    intNumber    = ['-'] digit { digit } .
    realNumber   = ['-'] { digit } "." digit { digit } 
                         [("e" | "E") ["+" | "-"] digit {digit}] .

PRODUCTIONS
    Calculator  = { Expression "=" } .
    Expression  = Term { "+" Term | "-" Term }.
    Term        = Factor { "*" Factor | "/" Factor }.
    Factor      = intNumber | realNumber .

END Calculator.

編集 (2011 年 4 月 9 日)

Factor<out double value>
    (. value = 0.0; .)
= 
    ( 
        intNumber 
        (. value = Convert.ToDouble(t.val); .)
        | 
        realNumber 
        (. value = Convert.ToDouble(t.val); .)
    ) 
    | "(" Expression<out value> ")"         
.

また

Factor<out double value>
    (. value = 0.0; .)
=
    ( intNumber | realNumber ) 
    (. value = Convert.ToDouble(t.val); .)
    | "(" Expression<out value> ")"
.
于 2010-06-24T16:49:08.430 に答える
2

コンテキスト依存のトークン化を備えたPEGジェネレーターを調べることをお勧めします。

http://en.wikipedia.org/wiki/Parsing_expression_grammar

各トークンは明確である必要があるため、COCO/Rなどを使用してこれを回避する方法を考えることはできません。

メッセージが引用符で囲まれている場合、または他の曖昧さ回避方法があれば、問題はありません。PEGも選択肢(最初の一致)を注文しているので、私は本当にPEGがあなたの答えかもしれないと思います。

また、以下もご覧ください。

http://tinlizzie.org/ometa/

于 2010-06-21T06:22:42.950 に答える
1

タイトルにもかかわらず、これはすべてパーサーではなくスキャナーに関連しているようです。私は CoCo/R を使用したことがないので、直接コメントすることはできませんが、一般的な (lex/Flex などの) スキャナーでは、ルールは順番に考慮されるため、選択されたルール/パターンは最初に一致します。私が作成したほとんどのスキャナーには「.」が含まれています。(つまり、何かに一致する) を最後のパターンとして使用し、他のルールに一致しない入力がある場合にエラー メッセージを表示します。

于 2010-06-15T14:44:08.657 に答える