#include "QueryParser.h" #include "Query.h" #include "htString.h" // // parse a query string // // Query * QueryParser::Parse(const String &query_string) { error = ""; Token().Set(query_string); Query *result = ParseExpression(); if(result && !Token().IsEnd()) { Expected("end of query"); delete result; result = 0; } return result; } // parse one word // return a fuzzy word query // Query * QueryParser::ParseWord() { Query *result = new FuzzyWordQuery(Token().Value()); Token().Next(); return result; } // // parse one word // return an exact query // Query * QueryParser::ParseExactWord() { Query *result = new ExactWordQuery(Token().Value()); Token().Next(); return result; } // "a" --> a // "a b" --> a next b // "a b c" --> (a next b) next c // ... // Query * QueryParser::ParsePhrase() { Query *result = 0; if(!Token().IsEnd() && !Token().IsQuote()) { result = ParseExactWord(); } while(result && !Token().IsEnd() && !Token().IsQuote()) { Query *next = ParseExactWord(); if(next) { result = new NextQuery(result, next); } else { delete result; result = 0; } } if(!result) { Expected("at least one word after \""); } return result; } void QueryParser::Expected(const String &what) { error << "Expected " << what; if(Token().IsEnd()) { error << " at the end"; } else { error << " instead of " << Token().Value(); } } // // expr == term { term } // Query * SimpleQueryParser::ParseExpression() { Query *result = 0; Query *term = ParseTerm(); if(term) { if(token.IsEnd()) { result = term; } else { result = MakeQuery(); while(term && !token.IsEnd()) { token.Next(); result->Add(term); term = ParseTerm(); } } } if(!term) { delete result; result = 0; } return result; } // // term == word | '"' phrase '"' // Query * SimpleQueryParser::ParseTerm() { Query *result = 0; if(token.IsWord()) { // don't advance token here! result = ParseWord(); } else if(token.IsQuote()) { token.Next(); result = ParsePhrase(); if(result) { if(token.IsQuote()) { token.Next(); } else { Expected("closing \""); delete result; result = 0; } } } else { Expected("a word or a quoted phrase"); } return result; } // // expr == andlist { 'or' andlist } // Query * BooleanQueryParser::ParseExpression() { Query *result = 0; Query *term = ParseAnd(); if(term) { if(token.IsOr()) { result = new OrQuery; while(term && token.IsOr()) { result->Add(term); token.Next(); term = ParseAnd(); } } else { result = term; } } if(!term && result) { delete result; } return result; } Query * GParser::ParseExpression() { List factors; Query *result = 0; String op; Query *factor = ParseFactor(); if(factor) { result = factor; } while(factor && (token.IsOr() || token.IsAnd() || token.IsNot() || token.IsNear())) { if(op != token.Value()) { Query *previous = result; result = MakeOperatorQuery(op); result->Add(previous); op = token.Value(); } token.Next(); factor = ParseFactor(); if(factor) { result->Add(factor); } } if(!factor && result) { delete result; result = 0; } return result; } OperatorQuery * GParser::MakeOperatorQuery(const String &op) const { OperatorQuery *result = 0; if(op == String("or")) { result = new OrQuery; } else if(op == String("and")) { result = new AndQuery; } else if(op == String("not")) { result = new NotQuery; } return result; } // // andlist = notlist { 'and' notlist } // Query * BooleanQueryParser::ParseAnd() { Query *result = 0; Query *not = ParseNot(); if(not) { if(token.IsAnd()) { result = new AndQuery(); while(not && token.IsAnd()) { result->Add(not); token.Next(); not = ParseNot(); } } else { result = not; } } if(!not && result) { delete result; result = 0; } return result; } // // notlist = nearlist { 'not' nearlist } // Query * BooleanQueryParser::ParseNot() { Query *result = 0; Query *near = ParseNear(); if(near) { if(token.IsNot()) { result = new NotQuery(); while(near && token.IsNot()) { result->Add(near); token.Next(); near = ParseNear(); } } else { result = near; } } if(!near && result) { delete result; result = 0; } return result; } // // near == factor { 'near' factor } // 'near' query is binary // Query * BooleanQueryParser::ParseNear() { Query *result = ParseFactor(); while(result && token.IsNear()) { token.Next(); int distance = 10; // config["default_near_distance"]; if(token.IsSlash()) { distance = 0; token.Next(); if(token.IsWord()) { distance = token.Value().as_integer(); token.Next(); } } if(distance > 0) { Query *right = ParseFactor(); if(right) { result = new NearQuery(result, right, distance); } else { delete result; result = 0; } } else { Expected("a distance > 0 for 'Near'"); delete result; result = 0; } } return result; } // // factor == word | '"' phrase '"' | '(' expression ')' // Query * BooleanQueryParser::ParseFactor() { Query *result = 0; if(token.IsWord()) { result = ParseWord(); } else if(token.IsQuote()) { token.Next(); result = ParsePhrase(); if(result) { if(token.IsQuote()) { token.Next(); } else { Expected("closing \""); delete result; result = 0; } } } else if(token.IsLeftParen()) { token.Next(); result = ParseExpression(); if(result) { if(token.IsRightParen()) { token.Next(); } else { Expected(")"); delete result; result = 0; } } } else { Expected("(, \", or a word"); } return result; }