0001: /* Generated By:JavaCC: Do not edit this line. QueryParser.java */
0002: package org.apache.lucene.queryParser;
0003:
0004: import java.util.Vector;
0005: import java.io.*;
0006: import java.text.*;
0007: import java.util.*;
0008: import org.apache.lucene.index.Term;
0009: import org.apache.lucene.analysis.*;
0010: import org.apache.lucene.document.*;
0011: import org.apache.lucene.search.*;
0012: import org.apache.lucene.util.Parameter;
0013:
0014: /**
0015: * This class is generated by JavaCC. The most important method is
0016: * {@link #parse(String)}.
0017: *
0018: * The syntax for query strings is as follows:
0019: * A Query is a series of clauses.
0020: * A clause may be prefixed by:
0021: * <ul>
0022: * <li> a plus (<code>+</code>) or a minus (<code>-</code>) sign, indicating
0023: * that the clause is required or prohibited respectively; or
0024: * <li> a term followed by a colon, indicating the field to be searched.
0025: * This enables one to construct queries which search multiple fields.
0026: * </ul>
0027: *
0028: * A clause may be either:
0029: * <ul>
0030: * <li> a term, indicating all the documents that contain this term; or
0031: * <li> a nested query, enclosed in parentheses. Note that this may be used
0032: * with a <code>+</code>/<code>-</code> prefix to require any of a set of
0033: * terms.
0034: * </ul>
0035: *
0036: * Thus, in BNF, the query grammar is:
0037: * <pre>
0038: * Query ::= ( Clause )*
0039: * Clause ::= ["+", "-"] [<TERM> ":"] ( <TERM> | "(" Query ")" )
0040: * </pre>
0041: *
0042: * <p>
0043: * Examples of appropriately formatted queries can be found in the <a
0044: * href="http://lucene.apache.org/java/docs/queryparsersyntax.html">query syntax
0045: * documentation</a>.
0046: * </p>
0047: *
0048: * <p>
0049: * In {@link RangeQuery}s, QueryParser tries to detect date values, e.g.
0050: * <tt>date:[6/1/2005 TO 6/4/2005]</tt> produces a range query that searches
0051: * for "date" fields between 2005-06-01 and 2005-06-04. Note that the format
0052: * of the accepted input depends on {@link #setLocale(Locale) the locale}.
0053: * By default a date is converted into a search term using the deprecated
0054: * {@link DateField} for compatibility reasons.
0055: * To use the new {@link DateTools} to convert dates, a
0056: * {@link org.apache.lucene.document.DateTools.Resolution} has to be set.
0057: * </p>
0058: * <p>
0059: * The date resolution that shall be used for RangeQueries can be set
0060: * using {@link #setDateResolution(DateTools.Resolution)}
0061: * or {@link #setDateResolution(String, DateTools.Resolution)}. The former
0062: * sets the default date resolution for all fields, whereas the latter can
0063: * be used to set field specific date resolutions. Field specific date
0064: * resolutions take, if set, precedence over the default date resolution.
0065: * </p>
0066: * <p>
0067: * If you use neither {@link DateField} nor {@link DateTools} in your
0068: * index, you can create your own
0069: * query parser that inherits QueryParser and overwrites
0070: * {@link #getRangeQuery(String, String, String, boolean)} to
0071: * use a different method for date conversion.
0072: * </p>
0073: *
0074: * <p>Note that QueryParser is <em>not</em> thread-safe.</p>
0075: *
0076: * @author Brian Goetz
0077: * @author Peter Halacsy
0078: * @author Tatu Saloranta
0079: */
0080: public class QueryParser implements QueryParserConstants {
0081:
0082: private static final int CONJ_NONE = 0;
0083: private static final int CONJ_AND = 1;
0084: private static final int CONJ_OR = 2;
0085:
0086: private static final int MOD_NONE = 0;
0087: private static final int MOD_NOT = 10;
0088: private static final int MOD_REQ = 11;
0089:
0090: // make it possible to call setDefaultOperator() without accessing
0091: // the nested class:
0092: /** Alternative form of QueryParser.Operator.AND */
0093: public static final Operator AND_OPERATOR = Operator.AND;
0094: /** Alternative form of QueryParser.Operator.OR */
0095: public static final Operator OR_OPERATOR = Operator.OR;
0096:
0097: /** The actual operator that parser uses to combine query terms */
0098: private Operator operator = OR_OPERATOR;
0099:
0100: boolean lowercaseExpandedTerms = true;
0101: boolean useOldRangeQuery = false;
0102: boolean allowLeadingWildcard = false;
0103: boolean enablePositionIncrements = false;
0104:
0105: Analyzer analyzer;
0106: String field;
0107: int phraseSlop = 0;
0108: float fuzzyMinSim = FuzzyQuery.defaultMinSimilarity;
0109: int fuzzyPrefixLength = FuzzyQuery.defaultPrefixLength;
0110: Locale locale = Locale.getDefault();
0111:
0112: // the default date resolution
0113: DateTools.Resolution dateResolution = null;
0114: // maps field names to date resolutions
0115: Map fieldToDateResolution = null;
0116:
0117: /** The default operator for parsing queries.
0118: * Use {@link QueryParser#setDefaultOperator} to change it.
0119: */
0120: static public final class Operator extends Parameter {
0121: private Operator(String name) {
0122: super (name);
0123: }
0124:
0125: static public final Operator OR = new Operator("OR");
0126: static public final Operator AND = new Operator("AND");
0127: }
0128:
0129: /** Constructs a query parser.
0130: * @param f the default field for query terms.
0131: * @param a used to find terms in the query text.
0132: */
0133: public QueryParser(String f, Analyzer a) {
0134: this (new FastCharStream(new StringReader("")));
0135: analyzer = a;
0136: field = f;
0137: }
0138:
0139: /** Parses a query string, returning a {@link org.apache.lucene.search.Query}.
0140: * @param query the query string to be parsed.
0141: * @throws ParseException if the parsing fails
0142: */
0143: public Query parse(String query) throws ParseException {
0144: ReInit(new FastCharStream(new StringReader(query)));
0145: try {
0146: // TopLevelQuery is a Query followed by the end-of-input (EOF)
0147: Query res = TopLevelQuery(field);
0148: return res != null ? res : new BooleanQuery();
0149: } catch (ParseException tme) {
0150: // rethrow to include the original query:
0151: throw new ParseException("Cannot parse '" + query + "': "
0152: + tme.getMessage());
0153: } catch (TokenMgrError tme) {
0154: throw new ParseException("Cannot parse '" + query + "': "
0155: + tme.getMessage());
0156: } catch (BooleanQuery.TooManyClauses tmc) {
0157: throw new ParseException("Cannot parse '" + query
0158: + "': too many boolean clauses");
0159: }
0160: }
0161:
0162: /**
0163: * @return Returns the analyzer.
0164: */
0165: public Analyzer getAnalyzer() {
0166: return analyzer;
0167: }
0168:
0169: /**
0170: * @return Returns the field.
0171: */
0172: public String getField() {
0173: return field;
0174: }
0175:
0176: /**
0177: * Get the minimal similarity for fuzzy queries.
0178: */
0179: public float getFuzzyMinSim() {
0180: return fuzzyMinSim;
0181: }
0182:
0183: /**
0184: * Set the minimum similarity for fuzzy queries.
0185: * Default is 0.5f.
0186: */
0187: public void setFuzzyMinSim(float fuzzyMinSim) {
0188: this .fuzzyMinSim = fuzzyMinSim;
0189: }
0190:
0191: /**
0192: * Get the prefix length for fuzzy queries.
0193: * @return Returns the fuzzyPrefixLength.
0194: */
0195: public int getFuzzyPrefixLength() {
0196: return fuzzyPrefixLength;
0197: }
0198:
0199: /**
0200: * Set the prefix length for fuzzy queries. Default is 0.
0201: * @param fuzzyPrefixLength The fuzzyPrefixLength to set.
0202: */
0203: public void setFuzzyPrefixLength(int fuzzyPrefixLength) {
0204: this .fuzzyPrefixLength = fuzzyPrefixLength;
0205: }
0206:
0207: /**
0208: * Sets the default slop for phrases. If zero, then exact phrase matches
0209: * are required. Default value is zero.
0210: */
0211: public void setPhraseSlop(int phraseSlop) {
0212: this .phraseSlop = phraseSlop;
0213: }
0214:
0215: /**
0216: * Gets the default slop for phrases.
0217: */
0218: public int getPhraseSlop() {
0219: return phraseSlop;
0220: }
0221:
0222: /**
0223: * Set to <code>true</code> to allow leading wildcard characters.
0224: * <p>
0225: * When set, <code>*</code> or <code>?</code> are allowed as
0226: * the first character of a PrefixQuery and WildcardQuery.
0227: * Note that this can produce very slow
0228: * queries on big indexes.
0229: * <p>
0230: * Default: false.
0231: */
0232: public void setAllowLeadingWildcard(boolean allowLeadingWildcard) {
0233: this .allowLeadingWildcard = allowLeadingWildcard;
0234: }
0235:
0236: /**
0237: * @see #setAllowLeadingWildcard(boolean)
0238: */
0239: public boolean getAllowLeadingWildcard() {
0240: return allowLeadingWildcard;
0241: }
0242:
0243: /**
0244: * Set to <code>true</code> to enable position increments in result query.
0245: * <p>
0246: * When set, result phrase and multi-phrase queries will
0247: * be aware of position increments.
0248: * Useful when e.g. a StopFilter increases the position increment of
0249: * the token that follows an omitted token.
0250: * <p>
0251: * Default: false.
0252: */
0253: public void setEnablePositionIncrements(boolean enable) {
0254: this .enablePositionIncrements = enable;
0255: }
0256:
0257: /**
0258: * @see #setEnablePositionIncrements(boolean)
0259: */
0260: public boolean getEnablePositionIncrements() {
0261: return enablePositionIncrements;
0262: }
0263:
0264: /**
0265: * Sets the boolean operator of the QueryParser.
0266: * In default mode (<code>OR_OPERATOR</code>) terms without any modifiers
0267: * are considered optional: for example <code>capital of Hungary</code> is equal to
0268: * <code>capital OR of OR Hungary</code>.<br/>
0269: * In <code>AND_OPERATOR</code> mode terms are considered to be in conjuction: the
0270: * above mentioned query is parsed as <code>capital AND of AND Hungary</code>
0271: */
0272: public void setDefaultOperator(Operator op) {
0273: this .operator = op;
0274: }
0275:
0276: /**
0277: * Gets implicit operator setting, which will be either AND_OPERATOR
0278: * or OR_OPERATOR.
0279: */
0280: public Operator getDefaultOperator() {
0281: return operator;
0282: }
0283:
0284: /**
0285: * Whether terms of wildcard, prefix, fuzzy and range queries are to be automatically
0286: * lower-cased or not. Default is <code>true</code>.
0287: */
0288: public void setLowercaseExpandedTerms(boolean lowercaseExpandedTerms) {
0289: this .lowercaseExpandedTerms = lowercaseExpandedTerms;
0290: }
0291:
0292: /**
0293: * @see #setLowercaseExpandedTerms(boolean)
0294: */
0295: public boolean getLowercaseExpandedTerms() {
0296: return lowercaseExpandedTerms;
0297: }
0298:
0299: /**
0300: * By default QueryParser uses new ConstantScoreRangeQuery in preference to RangeQuery
0301: * for range queries. This implementation is generally preferable because it
0302: * a) Runs faster b) Does not have the scarcity of range terms unduly influence score
0303: * c) avoids any "TooManyBooleanClauses" exception.
0304: * However, if your application really needs to use the old-fashioned RangeQuery and the above
0305: * points are not required then set this option to <code>true</code>
0306: * Default is <code>false</code>.
0307: */
0308: public void setUseOldRangeQuery(boolean useOldRangeQuery) {
0309: this .useOldRangeQuery = useOldRangeQuery;
0310: }
0311:
0312: /**
0313: * @see #setUseOldRangeQuery(boolean)
0314: */
0315: public boolean getUseOldRangeQuery() {
0316: return useOldRangeQuery;
0317: }
0318:
0319: /**
0320: * Set locale used by date range parsing.
0321: */
0322: public void setLocale(Locale locale) {
0323: this .locale = locale;
0324: }
0325:
0326: /**
0327: * Returns current locale, allowing access by subclasses.
0328: */
0329: public Locale getLocale() {
0330: return locale;
0331: }
0332:
0333: /**
0334: * Sets the default date resolution used by RangeQueries for fields for which no
0335: * specific date resolutions has been set. Field specific resolutions can be set
0336: * with {@link #setDateResolution(String, DateTools.Resolution)}.
0337: *
0338: * @param dateResolution the default date resolution to set
0339: */
0340: public void setDateResolution(DateTools.Resolution dateResolution) {
0341: this .dateResolution = dateResolution;
0342: }
0343:
0344: /**
0345: * Sets the date resolution used by RangeQueries for a specific field.
0346: *
0347: * @param fieldName field for which the date resolution is to be set
0348: * @param dateResolution date resolution to set
0349: */
0350: public void setDateResolution(String fieldName,
0351: DateTools.Resolution dateResolution) {
0352: if (fieldName == null) {
0353: throw new IllegalArgumentException("Field cannot be null.");
0354: }
0355:
0356: if (fieldToDateResolution == null) {
0357: // lazily initialize HashMap
0358: fieldToDateResolution = new HashMap();
0359: }
0360:
0361: fieldToDateResolution.put(fieldName, dateResolution);
0362: }
0363:
0364: /**
0365: * Returns the date resolution that is used by RangeQueries for the given field.
0366: * Returns null, if no default or field specific date resolution has been set
0367: * for the given field.
0368: *
0369: */
0370: public DateTools.Resolution getDateResolution(String fieldName) {
0371: if (fieldName == null) {
0372: throw new IllegalArgumentException("Field cannot be null.");
0373: }
0374:
0375: if (fieldToDateResolution == null) {
0376: // no field specific date resolutions set; return default date resolution instead
0377: return this .dateResolution;
0378: }
0379:
0380: DateTools.Resolution resolution = (DateTools.Resolution) fieldToDateResolution
0381: .get(fieldName);
0382: if (resolution == null) {
0383: // no date resolutions set for the given field; return default date resolution instead
0384: resolution = this .dateResolution;
0385: }
0386:
0387: return resolution;
0388: }
0389:
0390: protected void addClause(Vector clauses, int conj, int mods, Query q) {
0391: boolean required, prohibited;
0392:
0393: // If this term is introduced by AND, make the preceding term required,
0394: // unless it's already prohibited
0395: if (clauses.size() > 0 && conj == CONJ_AND) {
0396: BooleanClause c = (BooleanClause) clauses.elementAt(clauses
0397: .size() - 1);
0398: if (!c.isProhibited())
0399: c.setOccur(BooleanClause.Occur.MUST);
0400: }
0401:
0402: if (clauses.size() > 0 && operator == AND_OPERATOR
0403: && conj == CONJ_OR) {
0404: // If this term is introduced by OR, make the preceding term optional,
0405: // unless it's prohibited (that means we leave -a OR b but +a OR b-->a OR b)
0406: // notice if the input is a OR b, first term is parsed as required; without
0407: // this modification a OR b would parsed as +a OR b
0408: BooleanClause c = (BooleanClause) clauses.elementAt(clauses
0409: .size() - 1);
0410: if (!c.isProhibited())
0411: c.setOccur(BooleanClause.Occur.SHOULD);
0412: }
0413:
0414: // We might have been passed a null query; the term might have been
0415: // filtered away by the analyzer.
0416: if (q == null)
0417: return;
0418:
0419: if (operator == OR_OPERATOR) {
0420: // We set REQUIRED if we're introduced by AND or +; PROHIBITED if
0421: // introduced by NOT or -; make sure not to set both.
0422: prohibited = (mods == MOD_NOT);
0423: required = (mods == MOD_REQ);
0424: if (conj == CONJ_AND && !prohibited) {
0425: required = true;
0426: }
0427: } else {
0428: // We set PROHIBITED if we're introduced by NOT or -; We set REQUIRED
0429: // if not PROHIBITED and not introduced by OR
0430: prohibited = (mods == MOD_NOT);
0431: required = (!prohibited && conj != CONJ_OR);
0432: }
0433: if (required && !prohibited)
0434: clauses.addElement(new BooleanClause(q,
0435: BooleanClause.Occur.MUST));
0436: else if (!required && !prohibited)
0437: clauses.addElement(new BooleanClause(q,
0438: BooleanClause.Occur.SHOULD));
0439: else if (!required && prohibited)
0440: clauses.addElement(new BooleanClause(q,
0441: BooleanClause.Occur.MUST_NOT));
0442: else
0443: throw new RuntimeException(
0444: "Clause cannot be both required and prohibited");
0445: }
0446:
0447: /**
0448: * @exception ParseException throw in overridden method to disallow
0449: */
0450: protected Query getFieldQuery(String field, String queryText)
0451: throws ParseException {
0452: // Use the analyzer to get all the tokens, and then build a TermQuery,
0453: // PhraseQuery, or nothing based on the term count
0454:
0455: TokenStream source = analyzer.tokenStream(field,
0456: new StringReader(queryText));
0457: Vector v = new Vector();
0458: org.apache.lucene.analysis.Token t;
0459: int positionCount = 0;
0460: boolean severalTokensAtSamePosition = false;
0461:
0462: while (true) {
0463: try {
0464: t = source.next();
0465: } catch (IOException e) {
0466: t = null;
0467: }
0468: if (t == null)
0469: break;
0470: v.addElement(t);
0471: if (t.getPositionIncrement() != 0)
0472: positionCount += t.getPositionIncrement();
0473: else
0474: severalTokensAtSamePosition = true;
0475: }
0476: try {
0477: source.close();
0478: } catch (IOException e) {
0479: // ignore
0480: }
0481:
0482: if (v.size() == 0)
0483: return null;
0484: else if (v.size() == 1) {
0485: t = (org.apache.lucene.analysis.Token) v.elementAt(0);
0486: return new TermQuery(new Term(field, t.termText()));
0487: } else {
0488: if (severalTokensAtSamePosition) {
0489: if (positionCount == 1) {
0490: // no phrase query:
0491: BooleanQuery q = new BooleanQuery(true);
0492: for (int i = 0; i < v.size(); i++) {
0493: t = (org.apache.lucene.analysis.Token) v
0494: .elementAt(i);
0495: TermQuery currentQuery = new TermQuery(
0496: new Term(field, t.termText()));
0497: q.add(currentQuery, BooleanClause.Occur.SHOULD);
0498: }
0499: return q;
0500: } else {
0501: // phrase query:
0502: MultiPhraseQuery mpq = new MultiPhraseQuery();
0503: mpq.setSlop(phraseSlop);
0504: List multiTerms = new ArrayList();
0505: int position = -1;
0506: for (int i = 0; i < v.size(); i++) {
0507: t = (org.apache.lucene.analysis.Token) v
0508: .elementAt(i);
0509: if (t.getPositionIncrement() > 0
0510: && multiTerms.size() > 0) {
0511: if (enablePositionIncrements) {
0512: mpq
0513: .add((Term[]) multiTerms
0514: .toArray(new Term[0]),
0515: position);
0516: } else {
0517: mpq.add((Term[]) multiTerms
0518: .toArray(new Term[0]));
0519: }
0520: multiTerms.clear();
0521: }
0522: position += t.getPositionIncrement();
0523: multiTerms.add(new Term(field, t.termText()));
0524: }
0525: if (enablePositionIncrements) {
0526: mpq.add((Term[]) multiTerms
0527: .toArray(new Term[0]), position);
0528: } else {
0529: mpq.add((Term[]) multiTerms
0530: .toArray(new Term[0]));
0531: }
0532: return mpq;
0533: }
0534: } else {
0535: PhraseQuery pq = new PhraseQuery();
0536: pq.setSlop(phraseSlop);
0537: int position = -1;
0538: for (int i = 0; i < v.size(); i++) {
0539: t = (org.apache.lucene.analysis.Token) v
0540: .elementAt(i);
0541: if (enablePositionIncrements) {
0542: position += t.getPositionIncrement();
0543: pq.add(new Term(field, t.termText()), position);
0544: } else {
0545: pq.add(new Term(field, t.termText()));
0546: }
0547: }
0548: return pq;
0549: }
0550: }
0551: }
0552:
0553: /**
0554: * Base implementation delegates to {@link #getFieldQuery(String,String)}.
0555: * This method may be overridden, for example, to return
0556: * a SpanNearQuery instead of a PhraseQuery.
0557: *
0558: * @exception ParseException throw in overridden method to disallow
0559: */
0560: protected Query getFieldQuery(String field, String queryText,
0561: int slop) throws ParseException {
0562: Query query = getFieldQuery(field, queryText);
0563:
0564: if (query instanceof PhraseQuery) {
0565: ((PhraseQuery) query).setSlop(slop);
0566: }
0567: if (query instanceof MultiPhraseQuery) {
0568: ((MultiPhraseQuery) query).setSlop(slop);
0569: }
0570:
0571: return query;
0572: }
0573:
0574: /**
0575: * @exception ParseException throw in overridden method to disallow
0576: */
0577: protected Query getRangeQuery(String field, String part1,
0578: String part2, boolean inclusive) throws ParseException {
0579: if (lowercaseExpandedTerms) {
0580: part1 = part1.toLowerCase();
0581: part2 = part2.toLowerCase();
0582: }
0583: try {
0584: DateFormat df = DateFormat.getDateInstance(
0585: DateFormat.SHORT, locale);
0586: df.setLenient(true);
0587: Date d1 = df.parse(part1);
0588: Date d2 = df.parse(part2);
0589: if (inclusive) {
0590: // The user can only specify the date, not the time, so make sure
0591: // the time is set to the latest possible time of that date to really
0592: // include all documents:
0593: Calendar cal = Calendar.getInstance(locale);
0594: cal.setTime(d2);
0595: cal.set(Calendar.HOUR_OF_DAY, 23);
0596: cal.set(Calendar.MINUTE, 59);
0597: cal.set(Calendar.SECOND, 59);
0598: cal.set(Calendar.MILLISECOND, 999);
0599: d2 = cal.getTime();
0600: }
0601: DateTools.Resolution resolution = getDateResolution(field);
0602: if (resolution == null) {
0603: // no default or field specific date resolution has been set,
0604: // use deprecated DateField to maintain compatibilty with
0605: // pre-1.9 Lucene versions.
0606: part1 = DateField.dateToString(d1);
0607: part2 = DateField.dateToString(d2);
0608: } else {
0609: part1 = DateTools.dateToString(d1, resolution);
0610: part2 = DateTools.dateToString(d2, resolution);
0611: }
0612: } catch (Exception e) {
0613: }
0614:
0615: if (useOldRangeQuery) {
0616: return new RangeQuery(new Term(field, part1), new Term(
0617: field, part2), inclusive);
0618: } else {
0619: return new ConstantScoreRangeQuery(field, part1, part2,
0620: inclusive, inclusive);
0621: }
0622: }
0623:
0624: /**
0625: * Factory method for generating query, given a set of clauses.
0626: * By default creates a boolean query composed of clauses passed in.
0627: *
0628: * Can be overridden by extending classes, to modify query being
0629: * returned.
0630: *
0631: * @param clauses Vector that contains {@link BooleanClause} instances
0632: * to join.
0633: *
0634: * @return Resulting {@link Query} object.
0635: * @exception ParseException throw in overridden method to disallow
0636: */
0637: protected Query getBooleanQuery(Vector clauses)
0638: throws ParseException {
0639: return getBooleanQuery(clauses, false);
0640: }
0641:
0642: /**
0643: * Factory method for generating query, given a set of clauses.
0644: * By default creates a boolean query composed of clauses passed in.
0645: *
0646: * Can be overridden by extending classes, to modify query being
0647: * returned.
0648: *
0649: * @param clauses Vector that contains {@link BooleanClause} instances
0650: * to join.
0651: * @param disableCoord true if coord scoring should be disabled.
0652: *
0653: * @return Resulting {@link Query} object.
0654: * @exception ParseException throw in overridden method to disallow
0655: */
0656: protected Query getBooleanQuery(Vector clauses, boolean disableCoord)
0657: throws ParseException {
0658: if (clauses.size() == 0) {
0659: return null; // all clause words were filtered away by the analyzer.
0660: }
0661: BooleanQuery query = new BooleanQuery(disableCoord);
0662: for (int i = 0; i < clauses.size(); i++) {
0663: query.add((BooleanClause) clauses.elementAt(i));
0664: }
0665: return query;
0666: }
0667:
0668: /**
0669: * Factory method for generating a query. Called when parser
0670: * parses an input term token that contains one or more wildcard
0671: * characters (? and *), but is not a prefix term token (one
0672: * that has just a single * character at the end)
0673: *<p>
0674: * Depending on settings, prefix term may be lower-cased
0675: * automatically. It will not go through the default Analyzer,
0676: * however, since normal Analyzers are unlikely to work properly
0677: * with wildcard templates.
0678: *<p>
0679: * Can be overridden by extending classes, to provide custom handling for
0680: * wildcard queries, which may be necessary due to missing analyzer calls.
0681: *
0682: * @param field Name of the field query will use.
0683: * @param termStr Term token that contains one or more wild card
0684: * characters (? or *), but is not simple prefix term
0685: *
0686: * @return Resulting {@link Query} built for the term
0687: * @exception ParseException throw in overridden method to disallow
0688: */
0689: protected Query getWildcardQuery(String field, String termStr)
0690: throws ParseException {
0691: if ("*".equals(field)) {
0692: if ("*".equals(termStr))
0693: return new MatchAllDocsQuery();
0694: }
0695: if (!allowLeadingWildcard
0696: && (termStr.startsWith("*") || termStr.startsWith("?")))
0697: throw new ParseException(
0698: "'*' or '?' not allowed as first character in WildcardQuery");
0699: if (lowercaseExpandedTerms) {
0700: termStr = termStr.toLowerCase();
0701: }
0702: Term t = new Term(field, termStr);
0703: return new WildcardQuery(t);
0704: }
0705:
0706: /**
0707: * Factory method for generating a query (similar to
0708: * {@link #getWildcardQuery}). Called when parser parses an input term
0709: * token that uses prefix notation; that is, contains a single '*' wildcard
0710: * character as its last character. Since this is a special case
0711: * of generic wildcard term, and such a query can be optimized easily,
0712: * this usually results in a different query object.
0713: *<p>
0714: * Depending on settings, a prefix term may be lower-cased
0715: * automatically. It will not go through the default Analyzer,
0716: * however, since normal Analyzers are unlikely to work properly
0717: * with wildcard templates.
0718: *<p>
0719: * Can be overridden by extending classes, to provide custom handling for
0720: * wild card queries, which may be necessary due to missing analyzer calls.
0721: *
0722: * @param field Name of the field query will use.
0723: * @param termStr Term token to use for building term for the query
0724: * (<b>without</b> trailing '*' character!)
0725: *
0726: * @return Resulting {@link Query} built for the term
0727: * @exception ParseException throw in overridden method to disallow
0728: */
0729: protected Query getPrefixQuery(String field, String termStr)
0730: throws ParseException {
0731: if (!allowLeadingWildcard && termStr.startsWith("*"))
0732: throw new ParseException(
0733: "'*' not allowed as first character in PrefixQuery");
0734: if (lowercaseExpandedTerms) {
0735: termStr = termStr.toLowerCase();
0736: }
0737: Term t = new Term(field, termStr);
0738: return new PrefixQuery(t);
0739: }
0740:
0741: /**
0742: * Factory method for generating a query (similar to
0743: * {@link #getWildcardQuery}). Called when parser parses
0744: * an input term token that has the fuzzy suffix (~) appended.
0745: *
0746: * @param field Name of the field query will use.
0747: * @param termStr Term token to use for building term for the query
0748: *
0749: * @return Resulting {@link Query} built for the term
0750: * @exception ParseException throw in overridden method to disallow
0751: */
0752: protected Query getFuzzyQuery(String field, String termStr,
0753: float minSimilarity) throws ParseException {
0754: if (lowercaseExpandedTerms) {
0755: termStr = termStr.toLowerCase();
0756: }
0757: Term t = new Term(field, termStr);
0758: return new FuzzyQuery(t, minSimilarity, fuzzyPrefixLength);
0759: }
0760:
0761: /**
0762: * Returns a String where the escape char has been
0763: * removed, or kept only once if there was a double escape.
0764: *
0765: * Supports escaped unicode characters, e. g. translates
0766: * <code>A</code> to <code>A</code>.
0767: *
0768: */
0769: private String discardEscapeChar(String input)
0770: throws ParseException {
0771: // Create char array to hold unescaped char sequence
0772: char[] output = new char[input.length()];
0773:
0774: // The length of the output can be less than the input
0775: // due to discarded escape chars. This variable holds
0776: // the actual length of the output
0777: int length = 0;
0778:
0779: // We remember whether the last processed character was
0780: // an escape character
0781: boolean lastCharWasEscapeChar = false;
0782:
0783: // The multiplier the current unicode digit must be multiplied with.
0784: // E. g. the first digit must be multiplied with 16^3, the second with 16^2...
0785: int codePointMultiplier = 0;
0786:
0787: // Used to calculate the codepoint of the escaped unicode character
0788: int codePoint = 0;
0789:
0790: for (int i = 0; i < input.length(); i++) {
0791: char curChar = input.charAt(i);
0792: if (codePointMultiplier > 0) {
0793: codePoint += hexToInt(curChar) * codePointMultiplier;
0794: codePointMultiplier >>>= 4;
0795: if (codePointMultiplier == 0) {
0796: output[length++] = (char) codePoint;
0797: codePoint = 0;
0798: }
0799: } else if (lastCharWasEscapeChar) {
0800: if (curChar == 'u') {
0801: // found an escaped unicode character
0802: codePointMultiplier = 16 * 16 * 16;
0803: } else {
0804: // this character was escaped
0805: output[length] = curChar;
0806: length++;
0807: }
0808: lastCharWasEscapeChar = false;
0809: } else {
0810: if (curChar == '\\') {
0811: lastCharWasEscapeChar = true;
0812: } else {
0813: output[length] = curChar;
0814: length++;
0815: }
0816: }
0817: }
0818:
0819: if (codePointMultiplier > 0) {
0820: throw new ParseException(
0821: "Truncated unicode escape sequence.");
0822: }
0823:
0824: if (lastCharWasEscapeChar) {
0825: throw new ParseException(
0826: "Term can not end with escape character.");
0827: }
0828:
0829: return new String(output, 0, length);
0830: }
0831:
0832: /** Returns the numeric value of the hexadecimal character */
0833: private static final int hexToInt(char c) throws ParseException {
0834: if ('0' <= c && c <= '9') {
0835: return c - '0';
0836: } else if ('a' <= c && c <= 'f') {
0837: return c - 'a' + 10;
0838: } else if ('A' <= c && c <= 'F') {
0839: return c - 'A' + 10;
0840: } else {
0841: throw new ParseException(
0842: "None-hex character in unicode escape sequence: "
0843: + c);
0844: }
0845: }
0846:
0847: /**
0848: * Returns a String where those characters that QueryParser
0849: * expects to be escaped are escaped by a preceding <code>\</code>.
0850: */
0851: public static String escape(String s) {
0852: StringBuffer sb = new StringBuffer();
0853: for (int i = 0; i < s.length(); i++) {
0854: char c = s.charAt(i);
0855: // These characters are part of the query syntax and must be escaped
0856: if (c == '\\' || c == '+' || c == '-' || c == '!'
0857: || c == '(' || c == ')' || c == ':' || c == '^'
0858: || c == '[' || c == ']' || c == '\"' || c == '{'
0859: || c == '}' || c == '~' || c == '*' || c == '?'
0860: || c == '|' || c == '&') {
0861: sb.append('\\');
0862: }
0863: sb.append(c);
0864: }
0865: return sb.toString();
0866: }
0867:
0868: /**
0869: * Command line tool to test QueryParser, using {@link org.apache.lucene.analysis.SimpleAnalyzer}.
0870: * Usage:<br>
0871: * <code>java org.apache.lucene.queryParser.QueryParser <input></code>
0872: */
0873: public static void main(String[] args) throws Exception {
0874: if (args.length == 0) {
0875: System.out
0876: .println("Usage: java org.apache.lucene.queryParser.QueryParser <input>");
0877: System.exit(0);
0878: }
0879: QueryParser qp = new QueryParser("field",
0880: new org.apache.lucene.analysis.SimpleAnalyzer());
0881: Query q = qp.parse(args[0]);
0882: System.out.println(q.toString("field"));
0883: }
0884:
0885: // * Query ::= ( Clause )*
0886: // * Clause ::= ["+", "-"] [<TERM> ":"] ( <TERM> | "(" Query ")" )
0887: final public int Conjunction() throws ParseException {
0888: int ret = CONJ_NONE;
0889: switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
0890: case AND:
0891: case OR:
0892: switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
0893: case AND:
0894: jj_consume_token(AND);
0895: ret = CONJ_AND;
0896: break;
0897: case OR:
0898: jj_consume_token(OR);
0899: ret = CONJ_OR;
0900: break;
0901: default:
0902: jj_la1[0] = jj_gen;
0903: jj_consume_token(-1);
0904: throw new ParseException();
0905: }
0906: break;
0907: default:
0908: jj_la1[1] = jj_gen;
0909: ;
0910: }
0911: {
0912: if (true)
0913: return ret;
0914: }
0915: throw new Error("Missing return statement in function");
0916: }
0917:
0918: final public int Modifiers() throws ParseException {
0919: int ret = MOD_NONE;
0920: switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
0921: case NOT:
0922: case PLUS:
0923: case MINUS:
0924: switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
0925: case PLUS:
0926: jj_consume_token(PLUS);
0927: ret = MOD_REQ;
0928: break;
0929: case MINUS:
0930: jj_consume_token(MINUS);
0931: ret = MOD_NOT;
0932: break;
0933: case NOT:
0934: jj_consume_token(NOT);
0935: ret = MOD_NOT;
0936: break;
0937: default:
0938: jj_la1[2] = jj_gen;
0939: jj_consume_token(-1);
0940: throw new ParseException();
0941: }
0942: break;
0943: default:
0944: jj_la1[3] = jj_gen;
0945: ;
0946: }
0947: {
0948: if (true)
0949: return ret;
0950: }
0951: throw new Error("Missing return statement in function");
0952: }
0953:
0954: // This makes sure that there is no garbage after the query string
0955: final public Query TopLevelQuery(String field)
0956: throws ParseException {
0957: Query q;
0958: q = Query(field);
0959: jj_consume_token(0);
0960: {
0961: if (true)
0962: return q;
0963: }
0964: throw new Error("Missing return statement in function");
0965: }
0966:
0967: final public Query Query(String field) throws ParseException {
0968: Vector clauses = new Vector();
0969: Query q, firstQuery = null;
0970: int conj, mods;
0971: mods = Modifiers();
0972: q = Clause(field);
0973: addClause(clauses, CONJ_NONE, mods, q);
0974: if (mods == MOD_NONE)
0975: firstQuery = q;
0976: label_1: while (true) {
0977: switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
0978: case AND:
0979: case OR:
0980: case NOT:
0981: case PLUS:
0982: case MINUS:
0983: case LPAREN:
0984: case STAR:
0985: case QUOTED:
0986: case TERM:
0987: case PREFIXTERM:
0988: case WILDTERM:
0989: case RANGEIN_START:
0990: case RANGEEX_START:
0991: case NUMBER:
0992: ;
0993: break;
0994: default:
0995: jj_la1[4] = jj_gen;
0996: break label_1;
0997: }
0998: conj = Conjunction();
0999: mods = Modifiers();
1000: q = Clause(field);
1001: addClause(clauses, conj, mods, q);
1002: }
1003: if (clauses.size() == 1 && firstQuery != null) {
1004: if (true)
1005: return firstQuery;
1006: } else {
1007: {
1008: if (true)
1009: return getBooleanQuery(clauses);
1010: }
1011: }
1012: throw new Error("Missing return statement in function");
1013: }
1014:
1015: final public Query Clause(String field) throws ParseException {
1016: Query q;
1017: Token fieldToken = null, boost = null;
1018: if (jj_2_1(2)) {
1019: switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
1020: case TERM:
1021: fieldToken = jj_consume_token(TERM);
1022: jj_consume_token(COLON);
1023: field = discardEscapeChar(fieldToken.image);
1024: break;
1025: case STAR:
1026: jj_consume_token(STAR);
1027: jj_consume_token(COLON);
1028: field = "*";
1029: break;
1030: default:
1031: jj_la1[5] = jj_gen;
1032: jj_consume_token(-1);
1033: throw new ParseException();
1034: }
1035: } else {
1036: ;
1037: }
1038: switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
1039: case STAR:
1040: case QUOTED:
1041: case TERM:
1042: case PREFIXTERM:
1043: case WILDTERM:
1044: case RANGEIN_START:
1045: case RANGEEX_START:
1046: case NUMBER:
1047: q = Term(field);
1048: break;
1049: case LPAREN:
1050: jj_consume_token(LPAREN);
1051: q = Query(field);
1052: jj_consume_token(RPAREN);
1053: switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
1054: case CARAT:
1055: jj_consume_token(CARAT);
1056: boost = jj_consume_token(NUMBER);
1057: break;
1058: default:
1059: jj_la1[6] = jj_gen;
1060: ;
1061: }
1062: break;
1063: default:
1064: jj_la1[7] = jj_gen;
1065: jj_consume_token(-1);
1066: throw new ParseException();
1067: }
1068: if (boost != null) {
1069: float f = (float) 1.0;
1070: try {
1071: f = Float.valueOf(boost.image).floatValue();
1072: q.setBoost(f);
1073: } catch (Exception ignored) {
1074: }
1075: }
1076: {
1077: if (true)
1078: return q;
1079: }
1080: throw new Error("Missing return statement in function");
1081: }
1082:
1083: final public Query Term(String field) throws ParseException {
1084: Token term, boost = null, fuzzySlop = null, goop1, goop2;
1085: boolean prefix = false;
1086: boolean wildcard = false;
1087: boolean fuzzy = false;
1088: boolean rangein = false;
1089: Query q;
1090: switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
1091: case STAR:
1092: case TERM:
1093: case PREFIXTERM:
1094: case WILDTERM:
1095: case NUMBER:
1096: switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
1097: case TERM:
1098: term = jj_consume_token(TERM);
1099: break;
1100: case STAR:
1101: term = jj_consume_token(STAR);
1102: wildcard = true;
1103: break;
1104: case PREFIXTERM:
1105: term = jj_consume_token(PREFIXTERM);
1106: prefix = true;
1107: break;
1108: case WILDTERM:
1109: term = jj_consume_token(WILDTERM);
1110: wildcard = true;
1111: break;
1112: case NUMBER:
1113: term = jj_consume_token(NUMBER);
1114: break;
1115: default:
1116: jj_la1[8] = jj_gen;
1117: jj_consume_token(-1);
1118: throw new ParseException();
1119: }
1120: switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
1121: case FUZZY_SLOP:
1122: fuzzySlop = jj_consume_token(FUZZY_SLOP);
1123: fuzzy = true;
1124: break;
1125: default:
1126: jj_la1[9] = jj_gen;
1127: ;
1128: }
1129: switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
1130: case CARAT:
1131: jj_consume_token(CARAT);
1132: boost = jj_consume_token(NUMBER);
1133: switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
1134: case FUZZY_SLOP:
1135: fuzzySlop = jj_consume_token(FUZZY_SLOP);
1136: fuzzy = true;
1137: break;
1138: default:
1139: jj_la1[10] = jj_gen;
1140: ;
1141: }
1142: break;
1143: default:
1144: jj_la1[11] = jj_gen;
1145: ;
1146: }
1147: String termImage = discardEscapeChar(term.image);
1148: if (wildcard) {
1149: q = getWildcardQuery(field, termImage);
1150: } else if (prefix) {
1151: q = getPrefixQuery(field, discardEscapeChar(term.image
1152: .substring(0, term.image.length() - 1)));
1153: } else if (fuzzy) {
1154: float fms = fuzzyMinSim;
1155: try {
1156: fms = Float.valueOf(fuzzySlop.image.substring(1))
1157: .floatValue();
1158: } catch (Exception ignored) {
1159: }
1160: if (fms < 0.0f || fms > 1.0f) {
1161: {
1162: if (true)
1163: throw new ParseException(
1164: "Minimum similarity for a FuzzyQuery has to be between 0.0f and 1.0f !");
1165: }
1166: }
1167: q = getFuzzyQuery(field, termImage, fms);
1168: } else {
1169: q = getFieldQuery(field, termImage);
1170: }
1171: break;
1172: case RANGEIN_START:
1173: jj_consume_token(RANGEIN_START);
1174: switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
1175: case RANGEIN_GOOP:
1176: goop1 = jj_consume_token(RANGEIN_GOOP);
1177: break;
1178: case RANGEIN_QUOTED:
1179: goop1 = jj_consume_token(RANGEIN_QUOTED);
1180: break;
1181: default:
1182: jj_la1[12] = jj_gen;
1183: jj_consume_token(-1);
1184: throw new ParseException();
1185: }
1186: switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
1187: case RANGEIN_TO:
1188: jj_consume_token(RANGEIN_TO);
1189: break;
1190: default:
1191: jj_la1[13] = jj_gen;
1192: ;
1193: }
1194: switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
1195: case RANGEIN_GOOP:
1196: goop2 = jj_consume_token(RANGEIN_GOOP);
1197: break;
1198: case RANGEIN_QUOTED:
1199: goop2 = jj_consume_token(RANGEIN_QUOTED);
1200: break;
1201: default:
1202: jj_la1[14] = jj_gen;
1203: jj_consume_token(-1);
1204: throw new ParseException();
1205: }
1206: jj_consume_token(RANGEIN_END);
1207: switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
1208: case CARAT:
1209: jj_consume_token(CARAT);
1210: boost = jj_consume_token(NUMBER);
1211: break;
1212: default:
1213: jj_la1[15] = jj_gen;
1214: ;
1215: }
1216: if (goop1.kind == RANGEIN_QUOTED) {
1217: goop1.image = goop1.image.substring(1, goop1.image
1218: .length() - 1);
1219: }
1220: if (goop2.kind == RANGEIN_QUOTED) {
1221: goop2.image = goop2.image.substring(1, goop2.image
1222: .length() - 1);
1223: }
1224: q = getRangeQuery(field, discardEscapeChar(goop1.image),
1225: discardEscapeChar(goop2.image), true);
1226: break;
1227: case RANGEEX_START:
1228: jj_consume_token(RANGEEX_START);
1229: switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
1230: case RANGEEX_GOOP:
1231: goop1 = jj_consume_token(RANGEEX_GOOP);
1232: break;
1233: case RANGEEX_QUOTED:
1234: goop1 = jj_consume_token(RANGEEX_QUOTED);
1235: break;
1236: default:
1237: jj_la1[16] = jj_gen;
1238: jj_consume_token(-1);
1239: throw new ParseException();
1240: }
1241: switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
1242: case RANGEEX_TO:
1243: jj_consume_token(RANGEEX_TO);
1244: break;
1245: default:
1246: jj_la1[17] = jj_gen;
1247: ;
1248: }
1249: switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
1250: case RANGEEX_GOOP:
1251: goop2 = jj_consume_token(RANGEEX_GOOP);
1252: break;
1253: case RANGEEX_QUOTED:
1254: goop2 = jj_consume_token(RANGEEX_QUOTED);
1255: break;
1256: default:
1257: jj_la1[18] = jj_gen;
1258: jj_consume_token(-1);
1259: throw new ParseException();
1260: }
1261: jj_consume_token(RANGEEX_END);
1262: switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
1263: case CARAT:
1264: jj_consume_token(CARAT);
1265: boost = jj_consume_token(NUMBER);
1266: break;
1267: default:
1268: jj_la1[19] = jj_gen;
1269: ;
1270: }
1271: if (goop1.kind == RANGEEX_QUOTED) {
1272: goop1.image = goop1.image.substring(1, goop1.image
1273: .length() - 1);
1274: }
1275: if (goop2.kind == RANGEEX_QUOTED) {
1276: goop2.image = goop2.image.substring(1, goop2.image
1277: .length() - 1);
1278: }
1279:
1280: q = getRangeQuery(field, discardEscapeChar(goop1.image),
1281: discardEscapeChar(goop2.image), false);
1282: break;
1283: case QUOTED:
1284: term = jj_consume_token(QUOTED);
1285: switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
1286: case FUZZY_SLOP:
1287: fuzzySlop = jj_consume_token(FUZZY_SLOP);
1288: break;
1289: default:
1290: jj_la1[20] = jj_gen;
1291: ;
1292: }
1293: switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
1294: case CARAT:
1295: jj_consume_token(CARAT);
1296: boost = jj_consume_token(NUMBER);
1297: break;
1298: default:
1299: jj_la1[21] = jj_gen;
1300: ;
1301: }
1302: int s = phraseSlop;
1303:
1304: if (fuzzySlop != null) {
1305: try {
1306: s = Float.valueOf(fuzzySlop.image.substring(1))
1307: .intValue();
1308: } catch (Exception ignored) {
1309: }
1310: }
1311: q = getFieldQuery(field, discardEscapeChar(term.image
1312: .substring(1, term.image.length() - 1)), s);
1313: break;
1314: default:
1315: jj_la1[22] = jj_gen;
1316: jj_consume_token(-1);
1317: throw new ParseException();
1318: }
1319: if (boost != null) {
1320: float f = (float) 1.0;
1321: try {
1322: f = Float.valueOf(boost.image).floatValue();
1323: } catch (Exception ignored) {
1324: /* Should this be handled somehow? (defaults to "no boost", if
1325: * boost number is invalid)
1326: */
1327: }
1328:
1329: // avoid boosting null queries, such as those caused by stop words
1330: if (q != null) {
1331: q.setBoost(f);
1332: }
1333: }
1334: {
1335: if (true)
1336: return q;
1337: }
1338: throw new Error("Missing return statement in function");
1339: }
1340:
1341: final private boolean jj_2_1(int xla) {
1342: jj_la = xla;
1343: jj_lastpos = jj_scanpos = token;
1344: try {
1345: return !jj_3_1();
1346: } catch (LookaheadSuccess ls) {
1347: return true;
1348: } finally {
1349: jj_save(0, xla);
1350: }
1351: }
1352:
1353: final private boolean jj_3R_2() {
1354: if (jj_scan_token(TERM))
1355: return true;
1356: if (jj_scan_token(COLON))
1357: return true;
1358: return false;
1359: }
1360:
1361: final private boolean jj_3_1() {
1362: Token xsp;
1363: xsp = jj_scanpos;
1364: if (jj_3R_2()) {
1365: jj_scanpos = xsp;
1366: if (jj_3R_3())
1367: return true;
1368: }
1369: return false;
1370: }
1371:
1372: final private boolean jj_3R_3() {
1373: if (jj_scan_token(STAR))
1374: return true;
1375: if (jj_scan_token(COLON))
1376: return true;
1377: return false;
1378: }
1379:
1380: public QueryParserTokenManager token_source;
1381: public Token token, jj_nt;
1382: private int jj_ntk;
1383: private Token jj_scanpos, jj_lastpos;
1384: private int jj_la;
1385: public boolean lookingAhead = false;
1386: private boolean jj_semLA;
1387: private int jj_gen;
1388: final private int[] jj_la1 = new int[23];
1389: static private int[] jj_la1_0;
1390: static private int[] jj_la1_1;
1391: static {
1392: jj_la1_0();
1393: jj_la1_1();
1394: }
1395:
1396: private static void jj_la1_0() {
1397: jj_la1_0 = new int[] { 0x180, 0x180, 0xe00, 0xe00, 0x1f69f80,
1398: 0x48000, 0x10000, 0x1f69000, 0x1348000, 0x80000,
1399: 0x80000, 0x10000, 0x18000000, 0x2000000, 0x18000000,
1400: 0x10000, 0x80000000, 0x20000000, 0x80000000, 0x10000,
1401: 0x80000, 0x10000, 0x1f68000, };
1402: }
1403:
1404: private static void jj_la1_1() {
1405: jj_la1_1 = new int[] { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
1406: 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x1,
1407: 0x0, 0x0, 0x0, 0x0, };
1408: }
1409:
1410: final private JJCalls[] jj_2_rtns = new JJCalls[1];
1411: private boolean jj_rescan = false;
1412: private int jj_gc = 0;
1413:
1414: public QueryParser(CharStream stream) {
1415: token_source = new QueryParserTokenManager(stream);
1416: token = new Token();
1417: jj_ntk = -1;
1418: jj_gen = 0;
1419: for (int i = 0; i < 23; i++)
1420: jj_la1[i] = -1;
1421: for (int i = 0; i < jj_2_rtns.length; i++)
1422: jj_2_rtns[i] = new JJCalls();
1423: }
1424:
1425: public void ReInit(CharStream stream) {
1426: token_source.ReInit(stream);
1427: token = new Token();
1428: jj_ntk = -1;
1429: jj_gen = 0;
1430: for (int i = 0; i < 23; i++)
1431: jj_la1[i] = -1;
1432: for (int i = 0; i < jj_2_rtns.length; i++)
1433: jj_2_rtns[i] = new JJCalls();
1434: }
1435:
1436: public QueryParser(QueryParserTokenManager tm) {
1437: token_source = tm;
1438: token = new Token();
1439: jj_ntk = -1;
1440: jj_gen = 0;
1441: for (int i = 0; i < 23; i++)
1442: jj_la1[i] = -1;
1443: for (int i = 0; i < jj_2_rtns.length; i++)
1444: jj_2_rtns[i] = new JJCalls();
1445: }
1446:
1447: public void ReInit(QueryParserTokenManager tm) {
1448: token_source = tm;
1449: token = new Token();
1450: jj_ntk = -1;
1451: jj_gen = 0;
1452: for (int i = 0; i < 23; i++)
1453: jj_la1[i] = -1;
1454: for (int i = 0; i < jj_2_rtns.length; i++)
1455: jj_2_rtns[i] = new JJCalls();
1456: }
1457:
1458: final private Token jj_consume_token(int kind)
1459: throws ParseException {
1460: Token oldToken;
1461: if ((oldToken = token).next != null)
1462: token = token.next;
1463: else
1464: token = token.next = token_source.getNextToken();
1465: jj_ntk = -1;
1466: if (token.kind == kind) {
1467: jj_gen++;
1468: if (++jj_gc > 100) {
1469: jj_gc = 0;
1470: for (int i = 0; i < jj_2_rtns.length; i++) {
1471: JJCalls c = jj_2_rtns[i];
1472: while (c != null) {
1473: if (c.gen < jj_gen)
1474: c.first = null;
1475: c = c.next;
1476: }
1477: }
1478: }
1479: return token;
1480: }
1481: token = oldToken;
1482: jj_kind = kind;
1483: throw generateParseException();
1484: }
1485:
1486: static private final class LookaheadSuccess extends java.lang.Error {
1487: }
1488:
1489: final private LookaheadSuccess jj_ls = new LookaheadSuccess();
1490:
1491: final private boolean jj_scan_token(int kind) {
1492: if (jj_scanpos == jj_lastpos) {
1493: jj_la--;
1494: if (jj_scanpos.next == null) {
1495: jj_lastpos = jj_scanpos = jj_scanpos.next = token_source
1496: .getNextToken();
1497: } else {
1498: jj_lastpos = jj_scanpos = jj_scanpos.next;
1499: }
1500: } else {
1501: jj_scanpos = jj_scanpos.next;
1502: }
1503: if (jj_rescan) {
1504: int i = 0;
1505: Token tok = token;
1506: while (tok != null && tok != jj_scanpos) {
1507: i++;
1508: tok = tok.next;
1509: }
1510: if (tok != null)
1511: jj_add_error_token(kind, i);
1512: }
1513: if (jj_scanpos.kind != kind)
1514: return true;
1515: if (jj_la == 0 && jj_scanpos == jj_lastpos)
1516: throw jj_ls;
1517: return false;
1518: }
1519:
1520: final public Token getNextToken() {
1521: if (token.next != null)
1522: token = token.next;
1523: else
1524: token = token.next = token_source.getNextToken();
1525: jj_ntk = -1;
1526: jj_gen++;
1527: return token;
1528: }
1529:
1530: final public Token getToken(int index) {
1531: Token t = lookingAhead ? jj_scanpos : token;
1532: for (int i = 0; i < index; i++) {
1533: if (t.next != null)
1534: t = t.next;
1535: else
1536: t = t.next = token_source.getNextToken();
1537: }
1538: return t;
1539: }
1540:
1541: final private int jj_ntk() {
1542: if ((jj_nt = token.next) == null)
1543: return (jj_ntk = (token.next = token_source.getNextToken()).kind);
1544: else
1545: return (jj_ntk = jj_nt.kind);
1546: }
1547:
1548: private java.util.Vector jj_expentries = new java.util.Vector();
1549: private int[] jj_expentry;
1550: private int jj_kind = -1;
1551: private int[] jj_lasttokens = new int[100];
1552: private int jj_endpos;
1553:
1554: private void jj_add_error_token(int kind, int pos) {
1555: if (pos >= 100)
1556: return;
1557: if (pos == jj_endpos + 1) {
1558: jj_lasttokens[jj_endpos++] = kind;
1559: } else if (jj_endpos != 0) {
1560: jj_expentry = new int[jj_endpos];
1561: for (int i = 0; i < jj_endpos; i++) {
1562: jj_expentry[i] = jj_lasttokens[i];
1563: }
1564: boolean exists = false;
1565: for (java.util.Enumeration e = jj_expentries.elements(); e
1566: .hasMoreElements();) {
1567: int[] oldentry = (int[]) (e.nextElement());
1568: if (oldentry.length == jj_expentry.length) {
1569: exists = true;
1570: for (int i = 0; i < jj_expentry.length; i++) {
1571: if (oldentry[i] != jj_expentry[i]) {
1572: exists = false;
1573: break;
1574: }
1575: }
1576: if (exists)
1577: break;
1578: }
1579: }
1580: if (!exists)
1581: jj_expentries.addElement(jj_expentry);
1582: if (pos != 0)
1583: jj_lasttokens[(jj_endpos = pos) - 1] = kind;
1584: }
1585: }
1586:
1587: public ParseException generateParseException() {
1588: jj_expentries.removeAllElements();
1589: boolean[] la1tokens = new boolean[33];
1590: for (int i = 0; i < 33; i++) {
1591: la1tokens[i] = false;
1592: }
1593: if (jj_kind >= 0) {
1594: la1tokens[jj_kind] = true;
1595: jj_kind = -1;
1596: }
1597: for (int i = 0; i < 23; i++) {
1598: if (jj_la1[i] == jj_gen) {
1599: for (int j = 0; j < 32; j++) {
1600: if ((jj_la1_0[i] & (1 << j)) != 0) {
1601: la1tokens[j] = true;
1602: }
1603: if ((jj_la1_1[i] & (1 << j)) != 0) {
1604: la1tokens[32 + j] = true;
1605: }
1606: }
1607: }
1608: }
1609: for (int i = 0; i < 33; i++) {
1610: if (la1tokens[i]) {
1611: jj_expentry = new int[1];
1612: jj_expentry[0] = i;
1613: jj_expentries.addElement(jj_expentry);
1614: }
1615: }
1616: jj_endpos = 0;
1617: jj_rescan_token();
1618: jj_add_error_token(0, 0);
1619: int[][] exptokseq = new int[jj_expentries.size()][];
1620: for (int i = 0; i < jj_expentries.size(); i++) {
1621: exptokseq[i] = (int[]) jj_expentries.elementAt(i);
1622: }
1623: return new ParseException(token, exptokseq, tokenImage);
1624: }
1625:
1626: final public void enable_tracing() {
1627: }
1628:
1629: final public void disable_tracing() {
1630: }
1631:
1632: final private void jj_rescan_token() {
1633: jj_rescan = true;
1634: for (int i = 0; i < 1; i++) {
1635: JJCalls p = jj_2_rtns[i];
1636: do {
1637: if (p.gen > jj_gen) {
1638: jj_la = p.arg;
1639: jj_lastpos = jj_scanpos = p.first;
1640: switch (i) {
1641: case 0:
1642: jj_3_1();
1643: break;
1644: }
1645: }
1646: p = p.next;
1647: } while (p != null);
1648: }
1649: jj_rescan = false;
1650: }
1651:
1652: final private void jj_save(int index, int xla) {
1653: JJCalls p = jj_2_rtns[index];
1654: while (p.gen > jj_gen) {
1655: if (p.next == null) {
1656: p = p.next = new JJCalls();
1657: break;
1658: }
1659: p = p.next;
1660: }
1661: p.gen = jj_gen + xla - jj_la;
1662: p.first = token;
1663: p.arg = xla;
1664: }
1665:
1666: static final class JJCalls {
1667: int gen;
1668: Token first;
1669: int arg;
1670: JJCalls next;
1671: }
1672:
1673: }
|