0

私は次の文法を持っています:

cmds
    : cmd+
    ;

cmd
    : include_cmd  |  other_cmd
    ;

include_cmd
    : INCLUDE  DOUBLE_QUOTE  FILE_NAME  DOUBLE_QUOTE
    ;

other_cmd
    : CMD_NAME  ARG+
    ;


INCLUDE
    : '#include'
    ;

DOUBLE_QUOTE
    : '"'
    ;

CMD_NAME
    : ('a'..'z')*
    ;

ARG
    : ('a'..'z' | 'A'..'Z' | '0'..'9' | '_')+
    ;

FILE_NAME
    : ('a'..'z' | 'A'..'Z' | '0'..'9' | '_' | '.')+
    ;

したがって、CMD_NAME、ARG、および FILE_NAME の違いは大きくなく、CMD_NAME は小文字でなければならず、ARG には大文字と「_」を使用でき、FILE_NAME には「.」を使用できます。

しかし、これには問題があります。- #include "abc", 'abc' は FILE_NAME ではなく CMD_NAME として解釈されます。文法ファイルで CMD_NAME が FILE_NAME の前にあるため、解析エラーが発生します。

これに対処するために予測などの手法に頼る必要がありますか? ホスト プログラミング言語に依存する以外に、純粋な EBNF ソリューションはありますか?

ありがとう。

4

1 に答える 1

1

しかし、これには問題があります。ルールを - #include "abc", 'abc' は FILE_NAME ではなく CMD_NAME として解釈されます。文法ファイルで CMD_NAME が FILE_NAME の前にあるため、解析エラーが発生すると考えられます。

すべての有効な のセットは、すべての有効なCMD_NAMEのセットと交差しますFILE_NAME。入力abcは両方の資格があります。lexer は、最初に一致したルールであるため、(ご想像のとおり) 最初にリストされたルールと入力を照合します。

これに対処するには、[述語] などの手法に頼る必要がありますか? ホスト プログラミング言語に依存する以外に、純粋な EBNF ソリューションはありますか?

それは、文法で何を受け入れるかによって異なります。include_cmd次のように、ルールをより一般的なものに変更することを検討してください。

include_cmd : INCLUDE STRING;

STRING 
    : '"' ~('"'|'\r'|'\n')* '"' {String text = getText(); setText(text.substring(1, text.length() - 1));}
    ;

入力#include "abc"は token に変わり[INCLUDE : #include] [STRING : abc]ます。

ファイル名が有効かどうかを文法で判断する必要はないと思います。有効なファイル名は有効なファイルを意味するものではなく、文法は OS ファイルの命名規則 (有効な文字、パスなど) を理解する必要があります。 ) おそらく文法自体には関係ありません。FILE_NAME上記のルールのようなルールを削除しても問題ないと思います。

また、注目に値するのは、CMD_NAMEルールが長さゼロの入力に一致することです。a を本当に空にできない限り、に変更('a'..'z')*することを検討してください。('a'..'z')+CMD_NAME


で行ったのと同じ問題が発生することにも注意しARGてくださいFILE_NAME。これは の後にリストされているCMD_NAMEため、両方のルールに該当する入力は (abc再び) ヒットしCMD_NAMEます。これらのルールを、次のような従来のルールに分割することを検討してください。

other_cmd : ID (ID | NUMBER)+ SEMI;   //instead of CMD_NAME ARG+
ID        : ('a'..'z'|'A'..'Z'|'_')+; //instead of CMD_NAME, "id" part of ARG
NUMBER    : ('0'..'9')+;              //"number" part of ARG
SEMI      : ';';

SEMIコマンドの終了をマークするルールを追加しました。そうしないと、パーサーは、入力a b c dが 3 つの引数を持つ 1 つのコマンド ( a(b,c,d)) であるか、またはそれぞれ 1 つの引数を持つ 2 つのコマンド( ) であるかを認識できませんa(b), c(d)

于 2013-02-03T23:16:17.780 に答える