5

同じ文法で有効な日付と数値の両方を解析する最も簡単な (最短で、ルールが最も少なく、警告がない) 方法は何ですか? 私の問題は、有効な月 (1 ~ 12) に一致するレクサー ルールが、1 ~ 12 のすべての出現に一致することです。したがって、数値を一致させたい場合は、次のような解析ルールが必要です。

number: (MONTH|INT);

日と年のレクサー規則を追加すると、さらに複雑になります。次のような日付の解析ルールが必要です。

date: month '/' day ( '/' year )? -> ^('DATE' year month day);

同じツリー構造になる限り、月、日、年が解析規則であるかレクサー規則であるかは気にしません。また、他の場所で数字を認識できる必要があります。たとえば、次のようになります。

foo: STRING OP number -> ^(OP STRING number);
STRING: ('a'..'z')+;
OP: ('<'|'>');
4

2 に答える 2

6

問題は、レクサーやパーサーで構文チェックと意味チェックの両方を実行したいように見えることです。これはよくある間違いであり、非常に単純な言語でのみ発生する可能性があります。

本当に必要なのは、レクサーとパーサーでより広く受け入れてから、セマンティック チェックを実行することです。レクシングをどの程度厳密にするかはあなた次第ですが、月の日の前にゼロを受け入れる必要があるかどうかに応じて、2 つの基本的なオプションがあります。1) INT を実際に受け入れる、2) DATENUM を定義して有効な日であり、有効な INT ではないトークンのみを受け入れます。コードの後半で必要なセマンティック チェックが少なくなるため、2 番目の方法をお勧めします (INT は構文レベルで検証可能になり、日付に対してセマンティック チェックのみを実行する必要があるためです。最初のアプローチ:

INT: '0'..'9'+;

2 番目のアプローチ:

DATENUM: '0' '1'..'9';
INT: '0' | SIGN? '1'..'9' '0'..'9'*;

レクサーでこれらのルールを使用して受け入れた後、日付フィールドは次のいずれかになります。

date: INT '/' INT ( '/' INT )?

また:

date: (INT | DATENUM) '/' (INT | DATENUM) ('/' (INT | DATENUM) )?

その後、日付が有効であることを確認するために、AST に対してセマンティック ランを実行します。

ただし、文法でセマンティック チェックを実行することに固執している場合、ANTLR はパーサーでセマンティック述語を許可するため、次のように値をチェックする日付フィールドを作成できます。

date: month=INT '/' day=INT ( year='/' INT )? { year==null ? (/* First check /*) : (/* Second check */)}

ただし、これを行うと、文法に言語固有のコードが埋め込まれ、ターゲット間で移植できなくなります。

于 2008-09-26T21:14:13.957 に答える
1

ANTLR4 を使用して、私が使用した単純な結合文法を次に示します。レクサーを使用して単純なトークンのみを照合し、パーサー ルールに日付と数値の解釈を任せます。

// parser rules

date 
    : INT SEPARATOR month SEPARATOR INT
    | INT SEPARATOR month SEPARATOR INT4
    | INT SEPARATOR INT SEPARATOR INT4;

month : JAN | FEB | MAR | APR | MAY | JUN | JUL | AUG | SEP | OCT | NOV | DEC ;

number : FLOAT | INT | INT4 ;

// lexer rules

FLOAT : DIGIT+ '.' DIGIT+ ;

INT4 : DIGIT DIGIT DIGIT DIGIT;
INT : DIGIT+;

JAN : [Jj][Aa][Nn] ;
FEB : [Ff][Ee][Bb] ;
MAR : [Mm][Aa][Rr] ;
APR : [Aa][Pp][Rr] ;
MAY : [Mm][Aa][Yy] ; 
JUN : [Jj][Uu][Nn] ;
JUL : [Jj][Uu][Ll] ;
AUG : [Aa][Uu][Gg] ;
SEP : [Ss][Ee][Pp] ; 
OCT : [Oo][Cc][Tt] ; 
NOV : [Nn][Oo][Vv] ;
DEC : [Dd][Ee][Cc] ;

SEPARATOR : [/\\\-] ;

fragment DIGIT : [0-9];
于 2015-07-29T21:32:59.543 に答える