vinyl-cache/lib/libvinylapi/vxp_parse.c
0
/*-
1
 * Copyright (c) 2006 Verdens Gang AS
2
 * Copyright (c) 2006-2015 Varnish Software AS
3
 * All rights reserved.
4
 *
5
 * Author: Martin Blix Grydeland <martin@varnish-software.com>
6
 *
7
 * SPDX-License-Identifier: BSD-2-Clause
8
 *
9
 * Redistribution and use in source and binary forms, with or without
10
 * modification, are permitted provided that the following conditions
11
 * are met:
12
 * 1. Redistributions of source code must retain the above copyright
13
 *    notice, this list of conditions and the following disclaimer.
14
 * 2. Redistributions in binary form must reproduce the above copyright
15
 *    notice, this list of conditions and the following disclaimer in the
16
 *    documentation and/or other materials provided with the distribution.
17
 *
18
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
22
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28
 * SUCH DAMAGE.
29
 *
30
 */
31
32
#include "config.h"
33
34
#include <ctype.h>
35
#include <math.h>
36
#include <stdio.h>
37
38
#include "vdef.h"
39
#include "vas.h"
40
#include "miniobj.h"
41
42
#include "vbm.h"
43
#include "vqueue.h"
44
#include "vre.h"
45
#include "vsb.h"
46
47
#include "vapi/vsl.h"
48
49
#include "vsl_api.h"
50
#include "vxp.h"
51
52
static void vxp_expr_or(struct vxp *vxp, struct vex **pvex);
53
54
static struct vex *
55 6279
vex_alloc(const struct vxp *vxp)
56
{
57
        struct vex *vex;
58
59 6279
        ALLOC_OBJ(vex, VEX_MAGIC);
60 6279
        AN(vex);
61 6279
        vex->options = vxp->vex_options;
62 6279
        return (vex);
63
}
64
65
static void
66 5817
vxp_expr_lhs(struct vxp *vxp, struct vex_lhs **plhs)
67
{
68
        char *p;
69
        int i;
70
71 5817
        AN(plhs);
72 5817
        AZ(*plhs);
73 5817
        ALLOC_OBJ(*plhs, VEX_LHS_MAGIC);
74 5817
        AN(*plhs);
75 5817
        (*plhs)->tags = vbit_new(SLT__MAX);
76 5817
        (*plhs)->level = -1;
77
78 5817
        if (vxp->t->tok == '{') {
79
                /* Transaction level limits */
80 147
                vxp_NextToken(vxp);
81 147
                if (vxp->t->tok != VAL) {
82 42
                        VSB_printf(vxp->sb, "Expected integer got '%.*s' ",
83 21
                            PF(vxp->t));
84 21
                        vxp_ErrWhere(vxp, vxp->t, -1);
85 21
                        return;
86
                }
87 126
                (*plhs)->level = (int)strtol(vxp->t->dec, &p, 0);
88 126
                if ((*plhs)->level < 0) {
89 21
                        VSB_cat(vxp->sb, "Expected positive integer ");
90 21
                        vxp_ErrWhere(vxp, vxp->t, -1);
91 21
                        return;
92
                }
93 105
                if (*p == '-') {
94 21
                        (*plhs)->level_pm = -1;
95 21
                        p++;
96 105
                } else if (*p == '+') {
97 21
                        (*plhs)->level_pm = 1;
98 21
                        p++;
99 21
                }
100 105
                if (*p) {
101 21
                        VSB_cat(vxp->sb, "Syntax error in level limit ");
102 21
                        vxp_ErrWhere(vxp, vxp->t, -1);
103 21
                        return;
104
                }
105 84
                vxp_NextToken(vxp);
106 84
                ExpectErr(vxp, '}');
107 84
                vxp_NextToken(vxp);
108 84
        }
109
110 5838
        while (1) {
111
                /* The tags this expression applies to */
112 5838
                if (vxp->t->tok == VXID) {
113 1197
                        (*plhs)->vxid++;
114 1197
                        i = 0;
115 5838
                } else if (vxp->t->tok != VAL) {
116 42
                        VSB_printf(vxp->sb, "Expected VSL tag name got '%.*s' ",
117 21
                            PF(vxp->t));
118 21
                        vxp_ErrWhere(vxp, vxp->t, -1);
119 21
                        return;
120
                } else {
121 4620
                        (*plhs)->taglist++;
122 9240
                        i = VSL_Glob2Tags(vxp->t->dec, -1, vsl_vbm_bitset,
123 4620
                            (*plhs)->tags);
124
                }
125 5817
                if (i == -1) {
126 42
                        VSB_cat(vxp->sb, "Tag name matches zero tags ");
127 42
                        vxp_ErrWhere(vxp, vxp->t, -1);
128 42
                        return;
129
                }
130 5775
                if (i == -2) {
131 21
                        VSB_cat(vxp->sb, "Tag name is ambiguous ");
132 21
                        vxp_ErrWhere(vxp, vxp->t, -1);
133 21
                        return;
134
                }
135 5754
                if (i == -3) {
136 21
                        VSB_cat(vxp->sb, "Syntax error in tag name ");
137 21
                        vxp_ErrWhere(vxp, vxp->t, -1);
138 21
                        return;
139
                }
140 5733
                assert(i > 0 || vxp->t->tok == VXID);
141 5733
                vxp_NextToken(vxp);
142 5733
                if (vxp->t->tok != ',')
143 5649
                        break;
144 84
                vxp_NextToken(vxp);
145
        }
146
147 5649
        if (vxp->t->tok == ':') {
148
                /* Record prefix */
149 1428
                vxp_NextToken(vxp);
150 1428
                if (vxp->t->tok != VAL) {
151 42
                        VSB_printf(vxp->sb, "Expected string got '%.*s' ",
152 21
                            PF(vxp->t));
153 21
                        vxp_ErrWhere(vxp, vxp->t, -1);
154 21
                        return;
155
                }
156 1407
                AN(vxp->t->dec);
157 1407
                (*plhs)->prefix = strdup(vxp->t->dec);
158 1407
                AN((*plhs)->prefix);
159 1407
                (*plhs)->prefixlen = vstrlen((*plhs)->prefix);
160 1407
                vxp_NextToken(vxp);
161 1407
        }
162
163 5628
        if (vxp->t->tok == '[') {
164
                /* LHS field [] */
165 252
                vxp_NextToken(vxp);
166 252
                if (vxp->t->tok != VAL) {
167 42
                        VSB_printf(vxp->sb, "Expected integer got '%.*s' ",
168 21
                            PF(vxp->t));
169 21
                        vxp_ErrWhere(vxp, vxp->t, -1);
170 21
                        return;
171
                }
172 231
                (*plhs)->field = (int)strtol(vxp->t->dec, &p, 0);
173 231
                if (*p || (*plhs)->field <= 0) {
174 21
                        VSB_cat(vxp->sb, "Expected positive integer ");
175 21
                        vxp_ErrWhere(vxp, vxp->t, -1);
176 21
                        return;
177
                }
178 210
                vxp_NextToken(vxp);
179 210
                ExpectErr(vxp, ']');
180 210
                vxp_NextToken(vxp);
181 210
        }
182
183 5586
        if ((*plhs)->vxid == 0)
184 4410
                return;
185
186 2289
        if ((*plhs)->vxid > 1 || (*plhs)->level >= 0 ||
187 1134
            (*plhs)->field > 0 || (*plhs)->prefixlen > 0 ||
188 1113
            (*plhs)->taglist > 0) {
189 84
                VSB_cat(vxp->sb, "Unexpected taglist selection for vxid ");
190 84
                vxp_ErrWhere(vxp, vxp->t, -1);
191 84
        }
192 5817
}
193
194
static void
195 2184
vxp_expr_num(struct vxp *vxp, struct vex_rhs **prhs, unsigned vxid)
196
{
197
        char *endptr;
198
199 2184
        AN(prhs);
200 2184
        AZ(*prhs);
201 2184
        if (vxp->t->tok != VAL) {
202 21
                VSB_printf(vxp->sb, "Expected number got '%.*s' ", PF(vxp->t));
203 21
                vxp_ErrWhere(vxp, vxp->t, -1);
204 21
                return;
205
        }
206 2163
        AN(vxp->t->dec);
207 2163
        ALLOC_OBJ(*prhs, VEX_RHS_MAGIC);
208 2163
        AN(*prhs);
209 2163
        endptr = NULL;
210 2163
        if (strchr(vxp->t->dec, '.')) {
211 252
                (*prhs)->type = VEX_FLOAT;
212 252
                (*prhs)->val_float = strtod(vxp->t->dec, &endptr);
213 252
        } else {
214 1911
                (*prhs)->type = VEX_INT;
215 1911
                (*prhs)->val_int = strtoll(vxp->t->dec, &endptr, 0);
216
        }
217 2163
        while (isspace(*endptr))
218 0
                endptr++;
219 2163
        if (*endptr != '\0') {
220 84
                VSB_printf(vxp->sb, "%s parse error ",
221 42
                    (*prhs)->type == VEX_FLOAT ? "Floating point" : "Integer");
222 42
                vxp_ErrWhere(vxp, vxp->t, -1);
223 42
                return;
224
        }
225 2121
        if (vxid && (*prhs)->type != VEX_INT) {
226 42
                VSB_printf(vxp->sb, "Expected integer got '%.*s' ",
227 21
                    PF(vxp->t));
228 21
                vxp_ErrWhere(vxp, vxp->t, 0);
229 21
                return;
230
        }
231 2100
        vxp_NextToken(vxp);
232 2184
}
233
234
static void
235 294
vxp_expr_str(struct vxp *vxp, struct vex_rhs **prhs)
236
{
237
238 294
        AN(prhs);
239 294
        AZ(*prhs);
240 294
        if (vxp->t->tok != VAL) {
241 21
                VSB_printf(vxp->sb, "Expected string got '%.*s' ", PF(vxp->t));
242 21
                vxp_ErrWhere(vxp, vxp->t, -1);
243 21
                return;
244
        }
245 273
        AN(vxp->t->dec);
246 273
        ALLOC_OBJ(*prhs, VEX_RHS_MAGIC);
247 273
        AN(*prhs);
248 273
        (*prhs)->type = VEX_STRING;
249 273
        (*prhs)->val_string = strdup(vxp->t->dec);
250 273
        AN((*prhs)->val_string);
251 273
        (*prhs)->val_stringlen = vstrlen((*prhs)->val_string);
252 273
        vxp_NextToken(vxp);
253 294
}
254
255
static void
256 2310
vxp_expr_regex(struct vxp *vxp, struct vex_rhs **prhs)
257
{
258
        int err, erroff;
259
260
        /* XXX: Caseless option */
261
262 2310
        AN(prhs);
263 2310
        AZ(*prhs);
264 2310
        if (vxp->t->tok != VAL) {
265 42
                VSB_printf(vxp->sb, "Expected regular expression got '%.*s' ",
266 21
                    PF(vxp->t));
267 21
                vxp_ErrWhere(vxp, vxp->t, -1);
268 21
                return;
269
        }
270 2289
        AN(vxp->t->dec);
271 2289
        ALLOC_OBJ(*prhs, VEX_RHS_MAGIC);
272 2289
        AN(*prhs);
273 2289
        (*prhs)->type = VEX_REGEX;
274 2289
        (*prhs)->val_string = strdup(vxp->t->dec);
275 2289
        (*prhs)->val_regex = VRE_compile(vxp->t->dec, vxp->vre_options,
276
            &err, &erroff, 1);
277 2289
        if ((*prhs)->val_regex == NULL) {
278 21
                VSB_cat(vxp->sb, "Regular expression error: ");
279 21
                AZ(VRE_error(vxp->sb, err));
280 21
                VSB_putc(vxp->sb, ' ');
281 21
                vxp_ErrWhere(vxp, vxp->t, erroff);
282 21
                return;
283
        }
284 2268
        vxp_NextToken(vxp);
285 2310
}
286
287
static void
288 1092
vxp_vxid_cmp(struct vxp *vxp)
289
{
290
291 1092
        switch (vxp->t->tok) {
292
        /* Valid operators */
293
        case T_EQ:              /* == */
294
        case '<':               /* < */
295
        case '>':               /* > */
296
        case T_GEQ:             /* >= */
297
        case T_LEQ:             /* <= */
298
        case T_NEQ:             /* != */
299 1008
                break;
300
301
        /* Error */
302
        default:
303 168
                VSB_printf(vxp->sb, "Expected vxid operator got '%.*s' ",
304 84
                    PF(vxp->t));
305 84
                vxp_ErrWhere(vxp, vxp->t, -1);
306 84
        }
307 1092
}
308
309
/*
310
 * SYNTAX:
311
 *   expr_cmp:
312
 *     lhs
313
 *     lhs <operator> num|str|regex
314
 */
315
316
static void
317 5817
vxp_expr_cmp(struct vxp *vxp, struct vex **pvex)
318
{
319
320 5817
        AN(pvex);
321 5817
        AZ(*pvex);
322 5817
        *pvex = vex_alloc(vxp);
323 5817
        AN(*pvex);
324 5817
        vxp_expr_lhs(vxp, &(*pvex)->lhs);
325 5817
        ERRCHK(vxp);
326
327 5502
        if ((*pvex)->lhs->vxid) {
328 1092
                vxp_vxid_cmp(vxp);
329 1092
                ERRCHK(vxp);
330 1008
        }
331
332
        /* Test operator */
333 5418
        switch (vxp->t->tok) {
334
335
        /* Single lhs expressions don't take any more tokens */
336
        case EOI:
337
        case T_AND:
338
        case T_OR:
339
        case ')':
340 609
                (*pvex)->tok = T_TRUE;
341 609
                return;
342
343
        /* Valid operators */
344
        case T_EQ:              /* == */
345
        case '<':               /* < */
346
        case '>':               /* > */
347
        case T_GEQ:             /* >= */
348
        case T_LEQ:             /* <= */
349
        case T_NEQ:             /* != */
350
        case T_SEQ:             /* eq */
351
        case T_SNEQ:            /* ne */
352
        case '~':               /* ~ */
353
        case T_NOMATCH:         /* !~ */
354 4788
                (*pvex)->tok = vxp->t->tok;
355 4788
                break;
356
357
        /* Error */
358
        default:
359 42
                VSB_printf(vxp->sb, "Expected operator got '%.*s' ",
360 21
                    PF(vxp->t));
361 21
                vxp_ErrWhere(vxp, vxp->t, -1);
362 21
                return;
363
        }
364 4788
        vxp_NextToken(vxp);
365 4788
        ERRCHK(vxp);
366
367
        /* Value */
368 4788
        switch ((*pvex)->tok) {
369
        case '\0':
370 0
                WRONG("Missing token");
371 0
                break;
372
        case T_EQ:              /* == */
373
        case '<':               /* < */
374
        case '>':               /* > */
375
        case T_GEQ:             /* >= */
376
        case T_LEQ:             /* <= */
377
        case T_NEQ:             /* != */
378 2184
                vxp_expr_num(vxp, &(*pvex)->rhs, (*pvex)->lhs->vxid);
379 2184
                break;
380
        case T_SEQ:             /* eq */
381
        case T_SNEQ:            /* ne */
382 294
                vxp_expr_str(vxp, &(*pvex)->rhs);
383 294
                break;
384
        case '~':               /* ~ */
385
        case T_NOMATCH:         /* !~ */
386 2310
                vxp_expr_regex(vxp, &(*pvex)->rhs);
387 2310
                break;
388
        default:
389 0
                INCOMPL();
390 0
        }
391 5817
}
392
393
/*
394
 * SYNTAX:
395
 *   expr_group:
396
 *     '(' expr_or ')'
397
 *     expr_not
398
 */
399
400
static void
401 5922
vxp_expr_group(struct vxp *vxp, struct vex **pvex)
402
{
403
404 5922
        AN(pvex);
405 5922
        AZ(*pvex);
406
407 5922
        if (vxp->t->tok == '(') {
408 105
                SkipToken(vxp, '(');
409 105
                vxp_expr_or(vxp, pvex);
410 105
                ERRCHK(vxp);
411 105
                SkipToken(vxp, ')');
412 105
                return;
413
        }
414
415 5817
        vxp_expr_cmp(vxp, pvex);
416 5922
}
417
418
/*
419
 * SYNTAX:
420
 *   expr_not:
421
 *     'not' expr_group
422
 *     expr_group
423
 */
424
425
static void
426 5922
vxp_expr_not(struct vxp *vxp, struct vex **pvex)
427
{
428
429 5922
        AN(pvex);
430 5922
        AZ(*pvex);
431
432 5922
        if (vxp->t->tok == T_NOT) {
433 21
                *pvex = vex_alloc(vxp);
434 21
                AN(*pvex);
435 21
                (*pvex)->tok = vxp->t->tok;
436 21
                vxp_NextToken(vxp);
437 21
                vxp_expr_group(vxp, &(*pvex)->a);
438 21
                return;
439
        }
440
441 5901
        vxp_expr_group(vxp, pvex);
442 5922
}
443
444
/*
445
 * SYNTAX:
446
 *   expr_and:
447
 *     expr_not { 'and' expr_not }*
448
 */
449
450
static void
451 5754
vxp_expr_and(struct vxp *vxp, struct vex **pvex)
452
{
453
        struct vex *a;
454
455 5754
        AN(pvex);
456 5754
        AZ(*pvex);
457 5754
        vxp_expr_not(vxp, pvex);
458 5754
        ERRCHK(vxp);
459 5355
        while (vxp->t->tok == T_AND) {
460 168
                a = *pvex;
461 168
                *pvex = vex_alloc(vxp);
462 168
                AN(*pvex);
463 168
                (*pvex)->tok = vxp->t->tok;
464 168
                (*pvex)->a = a;
465 168
                vxp_NextToken(vxp);
466 168
                ERRCHK(vxp);
467 168
                vxp_expr_not(vxp, &(*pvex)->b);
468 168
                ERRCHK(vxp);
469
        }
470 5754
}
471
472
/*
473
 * SYNTAX:
474
 *   expr_or:
475
 *     expr_and { 'or' expr_and }*
476
 */
477
478
static void
479 5607
vxp_expr_or(struct vxp *vxp, struct vex **pvex)
480
{
481
        struct vex *a;
482
483 5607
        AN(pvex);
484 5607
        AZ(*pvex);
485 5607
        vxp_expr_and(vxp, pvex);
486 5607
        ERRCHK(vxp);
487 5187
        while (vxp->t->tok == T_OR) {
488 147
                a = *pvex;
489 147
                *pvex = vex_alloc(vxp);
490 147
                AN(*pvex);
491 147
                (*pvex)->tok = vxp->t->tok;
492 147
                (*pvex)->a = a;
493 147
                vxp_NextToken(vxp);
494 147
                ERRCHK(vxp);
495 147
                vxp_expr_and(vxp, &(*pvex)->b);
496 147
                ERRCHK(vxp);
497
        }
498 5607
}
499
500
/*
501
 * SYNTAX:
502
 *   expr:
503
 *     expr_or EOI { 'or' expr_or EOI }?
504
 */
505
506
static void
507 5628
vxp_expr(struct vxp *vxp, struct vex **pvex)
508
{
509 5628
        struct vex *a = NULL, *or;
510
511 5628
        if (*pvex == NULL) {
512 5502
                vxp_expr_or(vxp, pvex);
513 5502
                ERRCHK(vxp);
514 4935
                ExpectErr(vxp, EOI);
515 4935
                return;
516
        }
517
518 126
        vxp_expr(vxp, &a);
519 126
        ERRCHK(vxp);
520
521 126
        or = vex_alloc(vxp);
522 126
        AN(or);
523 126
        or->tok = T_OR;
524 126
        or->b = *pvex;
525 126
        or->a = a;
526 126
        *pvex = or;
527 5628
}
528
529
/*
530
 * Build a struct vex tree from the token list in vxp
531
 */
532
533
struct vex *
534 5418
vxp_Parse(struct vxp *vxp)
535
{
536 5418
        struct vex *vex = NULL;
537
538 5418
        AZ(vxp->err);
539 5418
        vxp->t = VTAILQ_FIRST(&vxp->tokens);
540
541 10353
        while (vxp->t != NULL) {
542
                /* Ignore empty queries */
543 6153
                while (vxp->t != NULL && vxp->t->tok == EOI)
544 504
                        vxp->t = VTAILQ_NEXT(vxp->t, list);
545
546 5649
                if (vxp->t == NULL)
547 147
                        break;
548
549 5502
                vxp_expr(vxp, &vex);
550
551 5502
                if (vxp->err) {
552 567
                        if (vex)
553 567
                                vex_Free(&vex);
554 567
                        AZ(vex);
555 567
                        return (NULL);
556
                }
557
558 4935
                vxp->t = VTAILQ_NEXT(vxp->t, list);
559
        }
560
561 4851
        return (vex);
562 5418
}
563
564
/*
565
 * Free a struct vex tree
566
 */
567
568
void
569 6279
vex_Free(struct vex **pvex)
570
{
571
        struct vex *vex;
572
        struct vex_lhs *lhs;
573
        struct vex_rhs *rhs;
574
575 6279
        TAKE_OBJ_NOTNULL(vex, pvex, VEX_MAGIC);
576
577 6279
        if (vex->lhs) {
578 5817
                CAST_OBJ_NOTNULL(lhs, vex->lhs, VEX_LHS_MAGIC);
579 5817
                if (lhs->tags)
580 5817
                        vbit_destroy(lhs->tags);
581 5817
                if (lhs->prefix)
582 1407
                        free(lhs->prefix);
583 5817
                FREE_OBJ(lhs);
584 5817
        }
585 6279
        if (vex->rhs) {
586 4725
                CAST_OBJ_NOTNULL(rhs, vex->rhs, VEX_RHS_MAGIC);
587 4725
                if (rhs->val_string)
588 2562
                        free(rhs->val_string);
589 4725
                if (rhs->val_regex)
590 2268
                        VRE_free(&rhs->val_regex);
591 4725
                FREE_OBJ(rhs);
592 4725
        }
593 6279
        if (vex->a) {
594 462
                vex_Free(&vex->a);
595 462
                AZ(vex->a);
596 462
        }
597 6279
        if (vex->b) {
598 441
                vex_Free(&vex->b);
599 441
                AZ(vex->b);
600 441
        }
601 6279
        FREE_OBJ(vex);
602 6279
}
603
604
#ifdef VXP_DEBUG
605
606
static void
607 63
vex_print_rhs(const struct vex_rhs *rhs)
608
{
609
610 63
        CHECK_OBJ_NOTNULL(rhs, VEX_RHS_MAGIC);
611 63
        fprintf(stderr, "rhs=");
612 63
        switch (rhs->type) {
613
        case VEX_INT:
614 42
                fprintf(stderr, "INT(%jd)", (intmax_t)rhs->val_int);
615 42
                break;
616
        case VEX_FLOAT:
617 0
                fprintf(stderr, "FLOAT(%f)", rhs->val_float);
618 0
                break;
619
        case VEX_STRING:
620 0
                AN(rhs->val_string);
621 0
                fprintf(stderr, "STRING(%s)", rhs->val_string);
622 0
                break;
623
        case VEX_REGEX:
624 21
                AN(rhs->val_string);
625 21
                AN(rhs->val_regex);
626 21
                fprintf(stderr, "REGEX(%s)", rhs->val_string);
627 21
                break;
628
        default:
629 0
                WRONG("rhs type");
630 0
                break;
631
        }
632 63
}
633
634
static void
635 84
vex_print_tags(const struct vbitmap *vbm)
636
{
637
        int i;
638 84
        int first = 1;
639
640 21588
        for (i = 0; i < SLT__MAX; i++) {
641 21504
                if (VSL_tags[i] == NULL)
642 13608
                        continue;
643 7896
                if (!vbit_test(vbm, i))
644 7728
                        continue;
645 168
                if (first)
646 84
                        first = 0;
647
                else
648 84
                        fprintf(stderr, ",");
649 168
                fprintf(stderr, "%s", VSL_tags[i]);
650 168
        }
651 84
}
652
653
static void
654 126
vex_print(const struct vex *vex, int indent)
655
{
656 126
        CHECK_OBJ_NOTNULL(vex, VEX_MAGIC);
657
658 126
        fprintf(stderr, "%*s%s", indent, "", vxp_tnames[vex->tok]);
659 126
        if (vex->lhs != NULL) {
660 84
                CHECK_OBJ(vex->lhs, VEX_LHS_MAGIC);
661 84
                AN(vex->lhs->tags);
662 84
                fprintf(stderr, " lhs=");
663 84
                if (vex->lhs->level >= 0)
664 0
                        fprintf(stderr, "{%d%s}", vex->lhs->level,
665 0
                            vex->lhs->level_pm < 0 ? "-" :
666 0
                            vex->lhs->level_pm > 0 ? "+" : "");
667 84
                fprintf(stderr, "(");
668 84
                vex_print_tags(vex->lhs->tags);
669 84
                fprintf(stderr, ")");
670 84
                if (vex->lhs->prefix) {
671 42
                        assert(vex->lhs->prefixlen == vstrlen(vex->lhs->prefix));
672 42
                        fprintf(stderr, ":%s", vex->lhs->prefix);
673 42
                }
674 84
                if (vex->lhs->field > 0)
675 21
                        fprintf(stderr, "[%d]", vex->lhs->field);
676 84
        }
677 126
        if (vex->rhs != NULL) {
678 63
                fprintf(stderr, " ");
679 63
                vex_print_rhs(vex->rhs);
680 63
        }
681 126
        fprintf(stderr, "\n");
682 126
        if (vex->a != NULL)
683 42
                vex_print(vex->a, indent + 2);
684 126
        if (vex->b != NULL)
685 42
                vex_print(vex->b, indent + 2);
686 126
}
687
688
void
689 42
vex_PrintTree(const struct vex *vex)
690
{
691
692 42
        CHECK_OBJ_NOTNULL(vex, VEX_MAGIC);
693 42
        fprintf(stderr, "VEX tree:\n");
694 42
        vex_print(vex, 2);
695 42
}
696
697
#endif /* VXP_DEBUG */