أنتلر:أبسط طريقة للتعرف على التواريخ والأرقام؟

StackOverflow https://stackoverflow.com/questions/141875

  •  02-07-2019
  •  | 
  •  

سؤال

ما هي الطريقة الأبسط (الأقصر، وأقل عدد من القواعد، وبدون تحذيرات) لتحليل كل من التواريخ والأرقام الصحيحة في نفس القواعد؟مشكلتي هي أن قاعدة lexer التي تتطابق مع شهر صالح (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: ('<'|'>');
هل كانت مفيدة؟

المحلول

المشكلة هي أنه يبدو أنك تريد إجراء التدقيق النحوي والدلالي في المعجم و/أو المحلل اللغوي الخاص بك.إنه خطأ شائع، وهو أمر ممكن فقط في اللغات البسيطة جدًا.

ما عليك فعله حقًا هو القبول على نطاق أوسع في المعجم والمحلل، ثم إجراء اختبارات دلالية.إن مدى صرامة المفردات يعود إليك، ولكن لديك خياران أساسيان، اعتمادًا على ما إذا كنت بحاجة إلى قبول الأصفار التي تسبق أيامك من الشهر أم لا:1) كن متقبلاً حقًا لـ INTs الخاصة بك، 2) حدد DATENUM لقبول تلك الرموز المميزة التي تكون صالحة للأيام فقط، ولكنها ليست INTs صالحة.أوصي بالثاني لأنه سيكون هناك فحوصات دلالية أقل ضرورية لاحقًا في الكود (نظرًا لأن INTs سيكون من الممكن التحقق منها على مستوى بناء الجملة وستحتاج فقط إلى إجراء فحوصات دلالية في التواريخ الخاصة بك.النهج الأول:

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

النهج الثاني :

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 */)}

ومع ذلك، عند القيام بذلك، فإنك تقوم بتضمين تعليمات برمجية خاصة باللغة في قواعدك النحوية، ولن تكون قابلة للنقل عبر الأهداف.

نصائح أخرى

باستخدام 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];
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top