2010-11-19 10 views
2

ich bin neu in ANTLR und ich versuche, Abfragen zu analysieren die folgenden usingANTLR Rewrite-Abfragetext zu wiederholen Text mit früheren Knoten

grammar SearchEngineQuery; 

options { language = CSharp2; output = AST; } 

tokens { 
AndNode; 
} 

LPARENTHESIS : '('; 
RPARENTHESIS : ')'; 

AND : 'and'; 
OR  : 'or'; 
ANDNOT : 'andnot'; 
NOT : 'not'; 
NEAR : 'near'; 


fragment CHARACTER : ('a'..'z'|'0'..'9'|'-'); 
fragment QUOTE  : ('"'); 
fragment WILDCARD : ('*'|'?'); 
fragment SPACE  : (' '|'\n'|'\r'|'\t'|'\u000C'); 

WILD_STRING 
    : (CHARACTER)* 
    ( 
     ('?') 
     (CHARACTER)* 
    )+ 
    ; 
PREFIX_STRING 
    : (CHARACTER)+ 
    ( 
     ('*') 
    )+ 
    ; 
WS  : (SPACE) { $channel=HIDDEN; }; 
PHRASE : (QUOTE)(WORD)(WILDCARD)?((SPACE)+(WORD)(WILDCARD)?)*(QUOTE); 
WORD : (CHARACTER)+; 

startExpression : nearExpression; 
nearExpression  : andExpression (NEAR^ andExpression)*; 
andExpression 
    : (andnotExpression  -> andnotExpression) 
    (AND? a=andnotExpression -> ^(AndNode $andnotExpression $a))* 
    ; 

andnotExpression : orExpression (ANDNOT^ orExpression)*; 
orExpression  : notExpression (OR^ notExpression)* ; 
notExpression : (NOT^)? (phraseExpression | wildExpression | prefixExpression | atomicExpression); 
phraseExpression : (PHRASE^); 
wildExpression : (WILD_STRING^); 
prefixExpression : (PREFIX_STRING^); 
atomicExpression : WORD | LPARENTHESIS! andExpression RPARENTHESIS!; 

Dies scheint für allgemeine Fragen ok zu arbeiten. Allerdings muss der Fall von a near (b or c) als tatsächlich behandelt werden:

alt text

und a near (b or c and (d or e)) Bedürfnissen behandelt werden wie:

alt text

Ich bin nicht in der Lage zu bestimmen, wie dies zu tun. Jede Hilfe würde sehr geschätzt werden.

Dank

+0

Was ist mit 'a und (b oder c)'? Sollte dies auch in "(a und b) oder (a und c)" umgewandelt werden? Und 'eine Nähe (b oder c und (d oder e))'? –

+0

Das a und (b oder c) kann so gehandhabt werden, wie es ist. Es ist die nahe Option, die verarbeitet werden muss, indem die Abfrage aufgelöst wird. Wie für eine Nähe (b oder c und (d oder e)) sollte idealerweise auch gebrochen werden. Entschuldigung für die Verzögerung bei der Antwort. Ich bin neu im Stackexchange und habe immer nur den Wert der Antworten zu dieser Frage in meinem Profil betrachtet. Jetzt weiß ich es besser. – Puneet

+0

Noch eine Sache, Ihre Grammatik erlaubt 'ein nahes x nahes (b oder c)', ist das richtig? Wenn ja, welche AST sollte das produzieren? –

Antwort

0

Sie würden wahrscheinlich in der Lage sein, dies zu erreichen, indem ein Mehrfachdurchlauf Baum Umschreiben Grammatik. Die Regeln sollten ziemlich kurz sein.

etwas ähnliches wie dies für den OP Fall:

orCaseRight: a=. NEAR ^(OR x=. y=.) -> ^(OR ^(NEAR $a $x) ^(NEAR $a $y)); 
orCaseLeft: ^(OR x=. y=.) NEAR a=. -> ^(OR ^(NEAR $a $x) ^(NEAR $a $y)); 

in TopDown eine Aktion hinzufügen, die einen rewrite Flag setzt, sobald eine Regel abgestimmt, so dass Sie so lange diese Grammatik anwenden können, wie der rewrite-Flag gesetzt ist .

Ich benutze dies um mathematische Ausdrücke zu optimieren/vorberechnen und es funktioniert wie ein Zauber.

+0

Sorry, aber wie würde ich die Grammatik wiederholen? Kannst du das weiter erklären? – Puneet

+0

Dies würden Sie in Ihrem Parser Aufruf Code tun. In meinem sieht es in etwa so aus: '// Ausdrücke vereinfachen while (wahr) { CommonTreeNodeStream nodes = new CommonTreeNodeStream (downup); AusdruckEinfacher Ausdruck = Vereinfachter = neuer ExpressionSimplifying (Knoten); downup = (Baum) expressionSimplifying.downup (downup, false); if (! ExpressionSimplifying.did_rewrite) Pause; } ' – stryba

+0

Sorry für den Code Chaos, Rückkehr wird nicht gut in Kommentaren unterstützt. Grundsätzlich nenne ich den TreeRewriter mit dem Ergebnis des vorherigen Durchlaufs, solange der Rewriter noch etwas schreibt. – stryba