~ubuntu-branches/ubuntu/wily/recoll/wily

« back to all changes in this revision

Viewing changes to query/wasaparse.y

  • Committer: Package Import Robot
  • Author(s): Kartik Mistry
  • Date: 2015-08-03 14:16:32 UTC
  • mfrom: (33.1.1 sid)
  • Revision ID: package-import@ubuntu.com-20150803141632-w5a1cr8ub2rkyvfe
Tags: 1.21.0-1
* New upstream release.
* debian/control:
  + Build-depend on python3-dev, python-dev, not python3-all-dev and
    python-all-dev. Thanks to Steve Langasek for patch. (Closes: #793636)
  + Added Build-depends on bison.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
%{
 
2
#define YYDEBUG 1
 
3
 
 
4
#include <stdio.h>
 
5
 
 
6
#include <iostream>
 
7
#include <string>
 
8
 
 
9
#include "searchdata.h"
 
10
#include "wasaparserdriver.h"
 
11
#include "wasaparse.tab.h"
 
12
 
 
13
using namespace std;
 
14
 
 
15
int yylex(yy::parser::semantic_type *, yy::parser::location_type *, 
 
16
                  WasaParserDriver *);
 
17
void yyerror(char const *);
 
18
static void qualify(Rcl::SearchDataClauseDist *, const string &);
 
19
 
 
20
static void addSubQuery(WasaParserDriver *d,
 
21
                        Rcl::SearchData *sd, Rcl::SearchData *sq)
 
22
{
 
23
    sd->addClause(new Rcl::SearchDataClauseSub(RefCntr<Rcl::SearchData>(sq)));
 
24
}
 
25
 
 
26
%}
 
27
 
 
28
%skeleton "lalr1.cc"
 
29
%defines
 
30
%locations
 
31
%error-verbose
 
32
 
 
33
%parse-param {WasaParserDriver* d}
 
34
%lex-param {WasaParserDriver* d}
 
35
 
 
36
%union {
 
37
    std::string *str;
 
38
    Rcl::SearchDataClauseSimple *cl;
 
39
    Rcl::SearchData *sd;
 
40
}
 
41
%destructor {delete $$;} <str>
 
42
 
 
43
%type <cl> qualquote
 
44
%type <cl> fieldexpr
 
45
%type <cl> term
 
46
%type <sd> query
 
47
%type <str> complexfieldname
 
48
 
 
49
 /* Non operator tokens need precedence because of the possibility of
 
50
    concatenation which needs to have lower prec than OR */
 
51
%left <str> WORD
 
52
%left <str> QUOTED
 
53
%left <str> QUALIFIERS
 
54
%left AND UCONCAT '(' '-'
 
55
%left OR
 
56
 
 
57
%token EQUALS CONTAINS SMALLEREQ SMALLER GREATEREQ GREATER
 
58
 
 
59
%%
 
60
 
 
61
topquery: query
 
62
{
 
63
    d->m_result = $1;
 
64
}
 
65
 
 
66
query: 
 
67
query query %prec UCONCAT
 
68
{
 
69
    //cerr << "q: query query" << endl;
 
70
    Rcl::SearchData *sd = new Rcl::SearchData(Rcl::SCLT_AND, d->m_stemlang);
 
71
    addSubQuery(d, sd, $1);
 
72
    addSubQuery(d, sd, $2);
 
73
    $$ = sd;
 
74
}
 
75
| query AND query
 
76
{
 
77
    //cerr << "q: query AND query" << endl;
 
78
    Rcl::SearchData *sd = new Rcl::SearchData(Rcl::SCLT_AND, d->m_stemlang);
 
79
    addSubQuery(d, sd, $1);
 
80
    addSubQuery(d, sd, $3);
 
81
    $$ = sd;
 
82
}
 
83
| query OR query
 
84
{
 
85
    //cerr << "q: query OR query" << endl;
 
86
    Rcl::SearchData *top = new Rcl::SearchData(Rcl::SCLT_AND, d->m_stemlang);
 
87
    Rcl::SearchData *sd = new Rcl::SearchData(Rcl::SCLT_OR, d->m_stemlang);
 
88
    addSubQuery(d, sd, $1);
 
89
    addSubQuery(d, sd, $3);
 
90
    addSubQuery(d, top, sd);
 
91
    $$ = top;
 
92
}
 
93
| '(' query ')' 
 
94
{
 
95
    //cerr << "q: ( query )" << endl;
 
96
    $$ = $2;
 
97
}
 
98
|
 
99
fieldexpr %prec UCONCAT
 
100
{
 
101
    //cerr << "q: fieldexpr" << endl;
 
102
    Rcl::SearchData *sd = new Rcl::SearchData(Rcl::SCLT_AND, d->m_stemlang);
 
103
    d->addClause(sd, $1);
 
104
    $$ = sd;
 
105
}
 
106
;
 
107
 
 
108
fieldexpr: term 
 
109
{
 
110
    // cerr << "fe: simple fieldexpr: " << $1->gettext() << endl;
 
111
    $$ = $1;
 
112
}
 
113
| complexfieldname EQUALS term 
 
114
{
 
115
    // cerr << "fe: " << *$1 << " = " << $3->gettext() << endl;
 
116
    $3->setfield(*$1);
 
117
    $3->setrel(Rcl::SearchDataClause::REL_EQUALS);
 
118
    $$ = $3;
 
119
    delete $1;
 
120
}
 
121
| complexfieldname CONTAINS term 
 
122
{
 
123
    // cerr << "fe: " << *$1 << " : " << $3->gettext() << endl;
 
124
    $3->setfield(*$1);
 
125
    $3->setrel(Rcl::SearchDataClause::REL_CONTAINS);
 
126
    $$ = $3;
 
127
    delete $1;
 
128
}
 
129
| complexfieldname SMALLER term 
 
130
{
 
131
    // cerr << "fe: " << *$1 << " < " << $3->gettext() << endl;
 
132
    $3->setfield(*$1);
 
133
    $3->setrel(Rcl::SearchDataClause::REL_LT);
 
134
    $$ = $3;
 
135
    delete $1;
 
136
}
 
137
| complexfieldname SMALLEREQ term 
 
138
{
 
139
    // cerr << "fe: " << *$1 << " <= " << $3->gettext() << endl;
 
140
    $3->setfield(*$1);
 
141
    $3->setrel(Rcl::SearchDataClause::REL_LTE);
 
142
    $$ = $3;
 
143
    delete $1;
 
144
}
 
145
| complexfieldname GREATER term 
 
146
{
 
147
    // cerr << "fe: "  << *$1 << " > " << $3->gettext() << endl;
 
148
    $3->setfield(*$1);
 
149
    $3->setrel(Rcl::SearchDataClause::REL_GT);
 
150
    $$ = $3;
 
151
    delete $1;
 
152
}
 
153
| complexfieldname GREATEREQ term 
 
154
{
 
155
    // cerr << "fe: " << *$1 << " >= " << $3->gettext() << endl;
 
156
    $3->setfield(*$1);
 
157
    $3->setrel(Rcl::SearchDataClause::REL_GTE);
 
158
    $$ = $3;
 
159
    delete $1;
 
160
}
 
161
| '-' fieldexpr 
 
162
{
 
163
    // cerr << "fe: - fieldexpr[" << $2->gettext() << "]" << endl;
 
164
    $2->setexclude(true);
 
165
    $$ = $2;
 
166
}
 
167
;
 
168
 
 
169
/* Deal with field names like dc:title */
 
170
complexfieldname: 
 
171
WORD
 
172
{
 
173
    // cerr << "cfn: WORD" << endl;
 
174
    $$ = $1;
 
175
}
 
176
|
 
177
complexfieldname CONTAINS WORD
 
178
{
 
179
    // cerr << "cfn: complexfieldname ':' WORD" << endl;
 
180
    $$ = new string(*$1 + string(":") + *$3);
 
181
    delete $1;
 
182
    delete $3;
 
183
}
 
184
 
 
185
term: 
 
186
WORD
 
187
{
 
188
    //cerr << "term[" << *$1 << "]" << endl;
 
189
    $$ = new Rcl::SearchDataClauseSimple(Rcl::SCLT_AND, *$1);
 
190
    delete $1;
 
191
}
 
192
| qualquote 
 
193
{
 
194
    $$ = $1;
 
195
}
 
196
 
 
197
qualquote: 
 
198
QUOTED
 
199
{
 
200
    // cerr << "QUOTED[" << *$1 << "]" << endl;
 
201
    $$ = new Rcl::SearchDataClauseDist(Rcl::SCLT_PHRASE, *$1, 0);
 
202
    delete $1;
 
203
}
 
204
| QUOTED QUALIFIERS 
 
205
{
 
206
    // cerr << "QUOTED[" << *$1 << "] QUALIFIERS[" << *$2 << "]" << endl;
 
207
    Rcl::SearchDataClauseDist *cl = 
 
208
        new Rcl::SearchDataClauseDist(Rcl::SCLT_PHRASE, *$1, 0);
 
209
    qualify(cl, *$2);
 
210
    $$ = cl;
 
211
    delete $1;
 
212
    delete $2;
 
213
}
 
214
 
 
215
 
 
216
%%
 
217
 
 
218
#include <ctype.h>
 
219
 
 
220
// Look for int at index, skip and return new index found? value.
 
221
static unsigned int qualGetInt(const string& q, unsigned int cur, int *pval)
 
222
{
 
223
    unsigned int ncur = cur;
 
224
    if (cur < q.size() - 1) {
 
225
        char *endptr;
 
226
        int val = strtol(&q[cur + 1], &endptr, 10);
 
227
        if (endptr != &q[cur + 1]) {
 
228
            ncur += endptr - &q[cur + 1];
 
229
            *pval = val;
 
230
        }
 
231
    }
 
232
    return ncur;
 
233
}
 
234
 
 
235
static void qualify(Rcl::SearchDataClauseDist *cl, const string& quals)
 
236
{
 
237
    // cerr << "qualify(" << cl << ", " << quals << ")" << endl;
 
238
    for (unsigned int i = 0; i < quals.length(); i++) {
 
239
        //fprintf(stderr, "qual char %c\n", quals[i]);
 
240
        switch (quals[i]) {
 
241
        case 'b': 
 
242
            cl->setWeight(10.0);
 
243
            break;
 
244
        case 'c': break;
 
245
        case 'C': 
 
246
            cl->addModifier(Rcl::SearchDataClause::SDCM_CASESENS);
 
247
            break;
 
248
        case 'd': break;
 
249
        case 'D':  
 
250
            cl->addModifier(Rcl::SearchDataClause::SDCM_DIACSENS);
 
251
            break;
 
252
        case 'e': 
 
253
            cl->addModifier(Rcl::SearchDataClause::SDCM_CASESENS);
 
254
            cl->addModifier(Rcl::SearchDataClause::SDCM_DIACSENS);
 
255
            cl->addModifier(Rcl::SearchDataClause::SDCM_NOSTEMMING);
 
256
            break;
 
257
        case 'l': 
 
258
            cl->addModifier(Rcl::SearchDataClause::SDCM_NOSTEMMING);
 
259
            break;
 
260
        case 'L': break;
 
261
        case 'o':  
 
262
        {
 
263
            int slack = 10;
 
264
            i = qualGetInt(quals, i, &slack);
 
265
            cl->setslack(slack);
 
266
            //cerr << "set slack " << cl->getslack() << " done" << endl;
 
267
        }
 
268
        break;
 
269
        case 'p': 
 
270
            cl->setTp(Rcl::SCLT_NEAR);
 
271
            if (cl->getslack() == 0) {
 
272
                cl->setslack(10);
 
273
                //cerr << "set slack " << cl->getslack() << " done" << endl;
 
274
            }
 
275
            break;
 
276
        case '.':case '0':case '1':case '2':case '3':case '4':
 
277
        case '5':case '6':case '7':case '8':case '9':
 
278
        {
 
279
            int n = 0;
 
280
            float factor = 1.0;
 
281
            if (sscanf(&(quals[i]), "%f %n", &factor, &n)) {
 
282
                if (factor != 1.0) {
 
283
                    cl->setWeight(factor);
 
284
                }
 
285
            }
 
286
            if (n > 0)
 
287
                i += n - 1;
 
288
        }
 
289
        default:
 
290
            break;
 
291
        }
 
292
    }
 
293
}
 
294
 
 
295
 
 
296
// specialstartchars are special only at the beginning of a token
 
297
// (e.g. doctor-who is a term, not 2 terms separated by '-')
 
298
static const string specialstartchars("-");
 
299
// specialinchars are special everywhere except inside a quoted string
 
300
static const string specialinchars(":=<>()");
 
301
 
 
302
// Called with the first dquote already read
 
303
static int parseString(WasaParserDriver *d, yy::parser::semantic_type *yylval)
 
304
{
 
305
    string* value = new string();
 
306
    d->qualifiers().clear();
 
307
    int c;
 
308
    while ((c = d->GETCHAR())) {
 
309
        switch (c) {
 
310
        case '\\':
 
311
            /* Escape: get next char */
 
312
            c = d->GETCHAR();
 
313
            if (c == 0) {
 
314
                value->push_back(c);
 
315
                goto out;
 
316
            }
 
317
            value->push_back(c);
 
318
            break;
 
319
        case '"':
 
320
            /* End of string. Look for qualifiers */
 
321
            while ((c = d->GETCHAR()) && !isspace(c))
 
322
                d->qualifiers().push_back(c);
 
323
            goto out;
 
324
        default:
 
325
            value->push_back(c);
 
326
        }
 
327
    }
 
328
out:
 
329
    //cerr << "GOT QUOTED ["<<value<<"] quals [" << d->qualifiers() << "]" << endl;
 
330
    yylval->str = value;
 
331
    return yy::parser::token::QUOTED;
 
332
}
 
333
 
 
334
 
 
335
int yylex(yy::parser::semantic_type *yylval, yy::parser::location_type *, 
 
336
                  WasaParserDriver *d)
 
337
{
 
338
    if (!d->qualifiers().empty()) {
 
339
        yylval->str = new string();
 
340
        yylval->str->swap(d->qualifiers());
 
341
        return yy::parser::token::QUALIFIERS;
 
342
    }
 
343
 
 
344
    int c;
 
345
 
 
346
    /* Skip white space.  */
 
347
    while ((c = d->GETCHAR()) && isspace(c))
 
348
        continue;
 
349
 
 
350
    if (c == 0)
 
351
        return 0;
 
352
 
 
353
    if (specialstartchars.find_first_of(c) != string::npos) {
 
354
        //cerr << "yylex: return " << c << endl;
 
355
        return c;
 
356
    }
 
357
 
 
358
    // field-term relations
 
359
    switch (c) {
 
360
    case '=': return yy::parser::token::EQUALS;
 
361
    case ':': return yy::parser::token::CONTAINS;
 
362
    case '<': {
 
363
        int c1 = d->GETCHAR();
 
364
        if (c1 == '=') {
 
365
            return yy::parser::token::SMALLEREQ;
 
366
        } else {
 
367
            d->UNGETCHAR(c1);
 
368
            return yy::parser::token::SMALLER;
 
369
        }
 
370
    }
 
371
    case '>': {
 
372
        int c1 = d->GETCHAR();
 
373
        if (c1 == '=') {
 
374
            return yy::parser::token::GREATEREQ;
 
375
        } else {
 
376
            d->UNGETCHAR(c1);
 
377
            return yy::parser::token::GREATER;
 
378
        }
 
379
    }
 
380
    case '(': case ')':
 
381
        return c;
 
382
    }
 
383
        
 
384
    if (c == '"')
 
385
        return parseString(d, yylval);
 
386
 
 
387
    d->UNGETCHAR(c);
 
388
 
 
389
    // Other chars start a term or field name or reserved word
 
390
    string* word = new string();
 
391
    while ((c = d->GETCHAR())) {
 
392
        if (isspace(c)) {
 
393
            //cerr << "Word broken by whitespace" << endl;
 
394
            break;
 
395
        } else if (specialinchars.find_first_of(c) != string::npos) {
 
396
            //cerr << "Word broken by special char" << endl;
 
397
            d->UNGETCHAR(c);
 
398
            break;
 
399
        } else if (c == 0) {
 
400
            //cerr << "Word broken by EOF" << endl;
 
401
            break;
 
402
        } else {
 
403
            word->push_back(c);
 
404
        }
 
405
    }
 
406
    
 
407
    if (!word->compare("AND") || !word->compare("&&")) {
 
408
        delete word;
 
409
        return yy::parser::token::AND;
 
410
    } else if (!word->compare("OR") || !word->compare("||")) {
 
411
        delete word;
 
412
        return yy::parser::token::OR;
 
413
    }
 
414
 
 
415
//    cerr << "Got word [" << word << "]" << endl;
 
416
    yylval->str = word;
 
417
    return yy::parser::token::WORD;
 
418
}