Frage

Was sind die einfachste (kürzesten, wenigsten Regeln und keine Warnungen) Art und Weise sowohl gültige Daten und Zahlen in der gleichen Grammatik zu analysieren? Mein Problem ist, dass ein Lexer Regel ein gültiger Monat (1-12) jedes Auftreten von 1-12 übereinstimmen übereinstimmen. Also, wenn ich will nur eine Nummer übereinstimmen, ich brauche eine Parsing-Regel wie:

number: (MONTH|INT);

Es wird nur noch komplexer, wenn ich Lexer Regeln für Tag und Jahr hinzuzufügen. Ich möchte ein Parse-Regel für das Datum wie folgt aus:

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

ist mir egal, wenn Monat, Tag und Jahr Parse oder Lexer Regeln sind, nur so lange, wie ich mit dem gleichen Baumstruktur enden. Ich muß auch in der Lage sein, Zahlen an anderer Stelle zu erkennen, z.

foo: STRING OP number -> ^(OP STRING number);
STRING: ('a'..'z')+;
OP: ('<'|'>');
War es hilfreich?

Lösung

Das Problem ist, dass Sie scheinen zu wollen, sowohl syntaktische und semantische Prüfung in Ihrem Lexer und / oder Ihrem Parser auszuführen. Es ist ein weit verbreiteter Irrtum, und etwas, das nur in sehr einfachen Sprachen ist.

Was Sie wirklich brauchen, zu tun ist im Großen und Ganzen im Lexer und Parser, zu akzeptieren und dann semantische Prüfungen durchführen. Wie streng die Sie in Ihrem lexing sind, ist bis zu Ihnen, aber Sie haben zwei grundlegende Optionen, je nachdem, ob Sie brauchen Nullen zu akzeptieren Ihre Tage des Monats vor: 1) wirklich Seien Sie für Ihre INTs akzeptieren, 2) definieren DATENUM zu nur die Token akzeptieren, die gültigen Tage sind, noch nicht gültig INTs. Ich empfehle die zweite, weil es weniger semantische Prüfungen notwendig später im Code (da INTs wird dann auf der Syntax Ebene überprüfbar sein und Sie müssen nur semantische Prüfungen auf Ihren Daten führen Der erste Ansatz:.

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

Der zweite Ansatz:

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

Nach der Lexer mit diesen Regeln zu akzeptieren, Ihr Datumsfeld würde entweder:

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

oder:

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

Danach würde man einen semantischen Lauf über Ihren AST durchführt, um sicherzustellen, dass Ihre Reisedaten gültig sind.

Wenn Sie tot Satz sind auf semantische Prüfungen in Ihrer Grammatik durchgeführt wird, ermöglicht jedoch ANTLR semantische Prädikate im Parser, so könnten Sie ein Datumsfeld machen, die die Werte wie folgt überprüft:

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

Wenn Sie das tun, aber Sie werden das Einbetten sprachspezifischen Code in Ihrer Grammatik, und es wird nicht tragbar über Ziele sein.

Andere Tipps

ANTLR4 verwenden, hier ist eine einfache kombinierte Grammatik, die ich verwenden. Es nutzt die Lexer nur einfache Token übereinstimmen, die Parser Regeln verlassen Daten vs Zahlen zu interpretieren.

// 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];
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top