1

私はANTLRが初めてで、それで遊んでいます。これは私が考えることができる最も単純な文法ですが、変数「id123」を解析するとまだ機能しません (NoViableAltException) が、「abc1」、「ab」、「c1d2f3」では機能します。

ANTLR 3.1.3 と ANTLRWorks 1.4 を使用しています。

options 
{
    language = 'CSharp2';
    output = AST;
}

assign  :   variable '=' value;
value   :   (variable|constant);
variable:   LETTER (LETTER|DIGIT)*;
constant:   (STRING|INTEGER);

DIGIT   :   '0'..'9';
NATURAL :   (DIGIT)+;   
INTEGER :   ('-')? NATURAL; 
REAL    :   (INTEGER '.' NATURAL);

LETTER  :   ('a'..'z'|'A'..'Z');

CR      :   '\r'        { $channel = HIDDEN; }; 
LF      :   '\n'        { $channel = HIDDEN; }; 
CRLF    :   CR LF       { $channel = HIDDEN; }; 
SPACE   :   (' '|'\t')  { $channel = HIDDEN; };

STRING  :   '"' (~'"')* '"';
4

1 に答える 1

2

ANTLR のレクサーは、可能な限り一致を試みます。2 つ (またはそれ以上) のルールが同じ数の文字に一致する場合は常に、最初に定義されたルールが「勝ち」ます。そのため、レクサーが 1 つの数字に出くわすたびに、DIGITトークンが作成されます。これは、前に定義されているためですNATURAL

DIGIT   :   '0'..'9';
NATURAL :   (DIGIT)+;   

しかし、入力に対して"id123"、レクサーは次の 3 つのトークンを生成しました。

LETTER          'i'
LETTER          'd'
NATURAL         '123'

lexer は貪欲に一致するため、3 つのトークンではなくNATURALaが作成されます。DIGIT

あなたがすべきことは、variable代わりにレクサールールを作成することです:

assign   :   VARIABLE '=' value;
value    :   (VARIABLE | constant);
constant :   (STRING | INTEGER | REAL);

VARIABLE :   LETTER (LETTER|DIGIT)*;
INTEGER  :   ('-')? NATURAL; 
REAL     :   (INTEGER '.' NATURAL);
SPACE    :   (' ' | '\t' | '\r' | '\n')  { $channel = HIDDEN; };
STRING   :   '"' (~'"')* '"';

fragment NATURAL :   (DIGIT)+;   
fragment DIGIT   :   '0'..'9';
fragment LETTER  :   ('a'..'z' | 'A'..'Z');

また、いくつかのレクサー ルールを作成したことにも注意してくださいfragment。これは、レクサーがNATURALDIGITまたはLETTERトークンを生成しないことを意味します。これらのfragmentルールは、他のレクサー ルールでのみ使用できます。つまり、レクサーはVARIABLEINTEGERREAL、およびSTRINGトークン* のみを生成します (したがって、パーサー ルールで使用できるのはこれらだけです!)。

*'='もちろん、トークン...

于 2012-05-24T07:05:16.337 に答える