2009-04-26 4 views
5

Ich lehre mich, JavaCC in einem Hobby-Projekt zu verwenden, und habe eine einfache Grammatik, um einen Parser zu schreiben. Ein Teil des Parsers beinhaltet folgende Leistungen:Erklärung und Lösung für die JavaCC-Warnung "Regulärer Ausdruck: FOO kann niemals als: BAR" gefunden werden?

TOKEN : { < DIGIT : (["0"-"9"]) > } 
TOKEN : { < INTEGER : (<DIGIT>)+ > } 
TOKEN : { < INTEGER_PAIR : (<INTEGER>){2} > } 
TOKEN : { < FLOAT : (<NEGATE>)? <INTEGER> | (<NEGATE>)? <INTEGER> "." <INTEGER> | (<NEGATE>)? <INTEGER> "." | (<NEGATE>)? "." <INTEGER> > } 
TOKEN : { < FLOAT_PAIR : (<FLOAT>){2} > } 
TOKEN : { < NUMBER_PAIR : <FLOAT_PAIR> | <INTEGER_PAIR> > } 
TOKEN : { < NEGATE : "-" > } 

Wenn mit JavaCC Kompilieren erhalte ich die Ausgabe:

Warning: Regular Expression choice : FLOAT_PAIR can never be matched as : NUMBER_PAIR 

Warning: Regular Expression choice : INTEGER_PAIR can never be matched as : NUMBER_PAIR 

Ich bin sicher, dass dies ein einfaches Konzept, aber ich verstehe nicht, die Warnung zu sein ein Anfänger in Parser-Generierung und regulären Ausdrücken.

Was bedeutet diese Warnung (in As-Novice-as-you-can-bekommen Bedingungen)?

Antwort

4

Ich kenne JavaCC nicht, aber ich bin ein Compileringenieur.

Die FLOAT_PAIR Regel ist mehrdeutig. Betrachten Sie den folgenden Text:

0.0 

Diese FLOAT 0 von FLOAT .0 gefolgt werden könnte; oder es könnte FLOAT 0. gefolgt von FLOAT 0 sein; beide ergeben FLOAT_PAIR. Oder es könnte ein einzelner FLOAT 0.0 sein.

Noch wichtiger ist, verwenden Sie lexikalische Analyse mit Zusammensetzung in einer Weise, die wahrscheinlich nie funktionieren wird. Betrachten Sie diese Nummer:

12345 

Dies als INTEGER 12, INTEGER 345 in einem INTEGER_PAIR resultierenden analysiert werden konnte. Oder es könnte als INTEGER 123, INTEGER 45, andere INTEGER_PAIR geparst werden. Oder es könnte INTEGER 12345, ein weiteres Token sein. Das Problem besteht, weil Sie keinen Leerraum zwischen den lexikalischen Elementen der INTEGER_PAIR (oder FLOAT_PAIR) benötigen.

Sie sollten fast nie versuchen, Paare wie diese im Lexer zu behandeln. Stattdessen sollten Sie einfache Zahlen (INTEGER und FLOAT) als Token behandeln und Dinge wie Negation und Pairing im Parser behandeln, wo Leerräume behandelt und entfernt wurden.

(Zum Beispiel, wie werden Sie "----42" verarbeiten?Dies ist ein gültiger Ausdruck in den meisten Programmiersprachen, der mehrere Negationen korrekt berechnet, aber nicht von Ihrem Lexer behandelt wird.)

Beachten Sie auch, dass einstellige Ganzzahlen in Ihrem Lexer nicht als INTEGER übereinstimmen. sie werden als DIGIT herauskommen. Ich kenne jedoch nicht die korrekte Syntax für JavaCC, um das für Sie zu beheben. Was Sie wollen, ist DIGIT nicht als ein Token, sondern einfach etwas, das Sie in den Definitionen anderer Token verwenden können; alternativ betten Sie die Definition von DIGIT ([0-9]) direkt in Ihre Regeln ein, wo immer Sie DIGIT verwenden.

0

Ich habe JavaCC nicht verwendet, aber es ist möglich, dass NUMBER_PAIR mehrdeutig ist.

Ich denke, dass das Problem auf die Tatsache kommt, dass die gleiche genaue Sache als FLOAT_PAIR und INTEGER_PAIR zusammengebracht werden kann, da FLOAT einen INTEGER abgleichen kann.

Aber das ist nur eine Vermutung nie die Syntax JavaCC gesehen zu haben :)

+0

Ich bin mir nicht sicher, ich habe Float geändert, so dass es nicht Integer - {))? "." | ()? "." | ()? "." >}, und immer noch die Warnung erhalten. Ich bin davon überrascht, denn was du gesagt hast, schien vollkommen logisch zu sein :) – Grundlefleck

+0

Hmm ... Ich denke immer noch, dass es mehrdeutig ist, aber ehrlich gesagt, da ich JavaCC nicht ausprobiert habe, bin ich hier nicht wirklich nützlich ... Ich werde aufschieben und hoffe, dass jemand, der es weiß, antworten wird. – Uri

0

Es bedeutet wahrscheinlich, dass jeder für FLOAT_PAIR Sie nur FLOAT_PAIR Token erhalten, nie eine NUMBER_PAIR Token. Die Regel FLOAT_PAIR stimmt bereits mit allen Eingaben überein, und JavaCC versucht nicht, weitere Übereinstimmungsregeln zu finden. Das wäre meine Interpretation, aber ich kenne JavaCC nicht, also nehmen Sie es mit einem Körnchen Salz.

Vielleicht können Sie irgendwie angeben, dass NUMBER_PAIR die Hauptproduktion ist und Sie keine anderen Token als Ergebnisse erhalten möchten.

0

Dank Barry Kelly Antwort, die Lösung, die ich habe kommen mit ist:

SKIP : { < #TO_SKIP : " " | "\t" > } 
    TOKEN : { < #DIGIT : (["0"-"9"]) > } 
    TOKEN : { < #DIGITS : (<DIGIT>)+ > } 
    TOKEN : { < INTEGER : <DIGITS> > } 
    TOKEN : { < INTEGER_PAIR : (<INTEGER>) (<TO_SKIP>)+ (<INTEGER>) > } 
    TOKEN : { < FLOAT : (<NEGATE>)?<DIGITS>"."<DIGITS> | (<NEGATE>)?"."<DIGITS> > } 
    TOKEN : { < FLOAT_PAIR : (<FLOAT>) (<TO_SKIP>)+ (<FLOAT>) > } 
    TOKEN : { < #NUMBER : <FLOAT> | <INTEGER> > } 
    TOKEN : { < NUMBER_PAIR : (<NUMBER>) (<TO_SKIP>)+ (<NUMBER>) >} 
    TOKEN : { < NEGATE : "-" > } 

Ich hatte vergessen, den Raum vollständig umfassen, die die beiden Token zu trennen verwendet wird, habe ich auch verwendet, die '#' Symbol, das die Übereinstimmung der Token stoppt und nur bei der Definition anderer Token verwendet wird. Das Obige wird von JavaCC ohne Warnung oder Fehler kompiliert.

Wie jedoch von Barry erwähnt, gibt es Gründe dagegen.

Verwandte Themen