varnish-cache/lib/libvcc/vcc_parse.c
1
/*-
2
 * Copyright (c) 2006 Verdens Gang AS
3
 * Copyright (c) 2006-2015 Varnish Software AS
4
 * All rights reserved.
5
 *
6
 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
21
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
 * SUCH DAMAGE.
28
 */
29
30
#include "config.h"
31
32
#include <string.h>
33
34
#include "vcc_compile.h"
35
36
/*--------------------------------------------------------------------*/
37
38
static void vcc_Compound(struct vcc *tl);
39
40
/*--------------------------------------------------------------------*/
41
42
#define L(tl, foo)      do {    \
43
        tl->indent += INDENT;   \
44
        foo;                    \
45
        tl->indent -= INDENT;   \
46
} while (0)
47
48
#define C(tl, sep)      do {                                    \
49
        Fb(tl, 1, "VRT_count(ctx, %u)%s\n", ++tl->cnt, sep);    \
50
        tl->t->cnt = tl->cnt;                                   \
51
} while (0)
52
53
/*--------------------------------------------------------------------
54
 * SYNTAX:
55
 *    Conditional:
56
 *      '(' Cond_0 ')'
57
 */
58
59
static void
60 8182
vcc_Conditional(struct vcc *tl)
61
{
62
63 8182
        SkipToken(tl, '(');
64 8182
        Fb(tl, 0, "(\n");
65 8182
        L(tl, vcc_Expr(tl, BOOL));
66 8182
        ERRCHK(tl);
67 8165
        Fb(tl, 1, ")\n");
68 8165
        SkipToken(tl, ')');
69
}
70
71
/*--------------------------------------------------------------------
72
 * SYNTAX:
73
 *    IfStmt:
74
 *      'if' Conditional  Compound Branch1* Branch2
75
 *    Branch1:
76
 *      'elseif' Conditional Compound
77
 *    Branch2:
78
 *      'else' Compound
79
 *      null
80
 */
81
82
static void
83 7340
vcc_IfStmt(struct vcc *tl)
84
{
85
86 7340
        SkipToken(tl, ID);
87 7340
        Fb(tl, 1, "if ");
88 7340
        vcc_Conditional(tl);
89 7340
        ERRCHK(tl);
90 7323
        L(tl, vcc_Compound(tl));
91 7323
        ERRCHK(tl);
92 15488
        while (tl->t->tok == ID) {
93 7957
                if (vcc_IdIs(tl->t, "else")) {
94 1598
                        vcc_NextToken(tl);
95 1598
                        if (tl->t->tok == '{') {
96 807
                                Fb(tl, 1, "else\n");
97 807
                                L(tl, vcc_Compound(tl));
98 807
                                ERRCHK(tl);
99 807
                                return;
100
                        }
101 791
                        if (tl->t->tok != ID || !vcc_IdIs(tl->t, "if")) {
102 0
                                VSB_printf(tl->sb,
103
                                    "'else' must be followed by 'if' or '{'\n");
104 0
                                vcc_ErrWhere(tl, tl->t);
105 0
                                return;
106
                        }
107 791
                        Fb(tl, 1, "else if ");
108 791
                        vcc_NextToken(tl);
109 791
                        vcc_Conditional(tl);
110 791
                        ERRCHK(tl);
111 791
                        L(tl, vcc_Compound(tl));
112 791
                        ERRCHK(tl);
113 12716
                } else if (vcc_IdIs(tl->t, "elseif") ||
114 12667
                     vcc_IdIs(tl->t, "elsif") ||
115 6310
                     vcc_IdIs(tl->t, "elif")) {
116 51
                        Fb(tl, 1, "else if ");
117 51
                        vcc_NextToken(tl);
118 51
                        vcc_Conditional(tl);
119 51
                        ERRCHK(tl);
120 51
                        L(tl, vcc_Compound(tl));
121 51
                        ERRCHK(tl);
122
                } else {
123
                        break;
124
                }
125
        }
126 6516
        C(tl, ";");
127
}
128
129
/*--------------------------------------------------------------------
130
 * SYNTAX:
131
 *    Compound:
132
 *      '{' Stmt* '}'
133
 *
134
 *    Stmt:
135
 *      Compound
136
 *      IfStmt
137
 *      CSRC
138
 *      Id(Action) (XXX)
139
 */
140
141
static void
142 20701
vcc_Compound(struct vcc *tl)
143
{
144
        int i;
145
146 20701
        SkipToken(tl, '{');
147 20701
        Fb(tl, 1, "{\n");
148 20701
        tl->indent += INDENT;
149 20701
        C(tl, ";");
150
        while (1) {
151 55899
                ERRCHK(tl);
152 55880
                switch (tl->t->tok) {
153
                case '{':
154 2
                        vcc_Compound(tl);
155 2
                        break;
156
                case '}':
157 20623
                        vcc_NextToken(tl);
158 20623
                        tl->indent -= INDENT;
159 20623
                        Fb(tl, 1, "}\n");
160 20623
                        return;
161
                case CSRC:
162 6
                        if (tl->allow_inline_c) {
163 10
                                Fb(tl, 1, "%.*s\n",
164 5
                                    (int) (tl->t->e - (tl->t->b + 2)),
165 5
                                    tl->t->b + 1);
166 5
                                vcc_NextToken(tl);
167
                        } else {
168 1
                                VSB_printf(tl->sb,
169
                                    "Inline-C not allowed\n");
170 1
                                vcc_ErrWhere(tl, tl->t);
171
                        }
172 6
                        break;
173
                case EOI:
174 0
                        VSB_printf(tl->sb,
175
                            "End of input while in compound statement\n");
176 0
                        tl->err = 1;
177 0
                        return;
178
                case ID:
179 35249
                        if (vcc_IdIs(tl->t, "if")) {
180 7340
                                vcc_IfStmt(tl);
181 7340
                                break;
182
                        } else {
183 27909
                                i = vcc_ParseAction(tl);
184 27909
                                ERRCHK(tl);
185 27856
                                if (i) {
186 27851
                                        SkipToken(tl, ';');
187 27850
                                        break;
188
                                }
189
                        }
190
                        /* FALLTHROUGH */
191
                default:
192
                        /* We deliberately do not mention inline C */
193 5
                        VSB_printf(tl->sb,
194
                            "Expected an action, 'if', '{' or '}'\n");
195 5
                        vcc_ErrWhere(tl, tl->t);
196 5
                        return;
197
                }
198 35198
                Fb(tl, 1, "if (*ctx->handling) return;\n");
199 35198
        }
200
}
201
202
/*--------------------------------------------------------------------
203
 * SYNTAX:
204
 *    Function:
205
 *      'sub' ID(name) Compound
206
 */
207
208
static void
209 11730
vcc_ParseFunction(struct vcc *tl)
210
{
211
        struct symbol *sym;
212
        struct proc *p;
213
214 11730
        vcc_NextToken(tl);
215 11730
        vcc_ExpectVid(tl, "function");
216 11730
        ERRCHK(tl);
217
218 11729
        sym = vcc_AddDef(tl, tl->t, SYM_SUB);
219 11729
        AN(sym);
220 11729
        p = sym->proc;
221 11729
        if (p == NULL) {
222 19
                if ((tl->t->b[0] == 'v'|| tl->t->b[0] == 'V') &&
223 2
                    (tl->t->b[1] == 'c'|| tl->t->b[1] == 'C') &&
224 1
                    (tl->t->b[2] == 'l'|| tl->t->b[2] == 'L')) {
225 1
                        VSB_printf(tl->sb,
226
                            "VCL sub's named 'vcl*' are reserved names.\n");
227 1
                        vcc_ErrWhere(tl, tl->t);
228 1
                        VSB_printf(tl->sb, "Valid vcl_* methods are:\n");
229 15
                        VTAILQ_FOREACH(p, &tl->procs, list) {
230 14
                                if (p->method != NULL)
231 14
                                        VSB_printf(tl->sb, "\t%s\n",
232 14
                                            p->method->name);
233
                        }
234 1
                        return;
235
                }
236 17
                VCC_GlobalSymbol(sym, SUB, "VGC_function");
237 17
                p = vcc_NewProc(tl, sym);
238 17
                p->name = tl->t;
239 17
                VSB_printf(p->cname, "%s", sym->rname);
240 11711
        } else if (p->method == NULL) {
241 1
                VSB_printf(tl->sb, "Function '%s' redefined\n", sym->name);
242 1
                vcc_ErrWhere(tl, tl->t);
243 1
                VSB_printf(tl->sb, "Previously defined here:\n");
244 1
                vcc_ErrWhere(tl, p->name);
245 1
                return;
246
        } else {
247
                /* Add to VCL sub */
248 11710
                AN(p->method);
249 11710
                if (p->name == NULL) {
250 10856
                        (void)vcc_AddDef(tl, tl->t, SYM_SUB);
251 10856
                        (void)vcc_AddRef(tl, tl->t, SYM_SUB);
252 10856
                        p->name = tl->t;
253
                }
254
        }
255 11727
        CHECK_OBJ_NOTNULL(p, PROC_MAGIC);
256 11727
        tl->fb = p->body;
257 11727
        Fb(tl, 1, "  /* ... from ");
258 11727
        vcc_Coord(tl, p->body, NULL);
259 11727
        Fb(tl, 0, " */\n");
260 11727
        tl->curproc = p;
261 11727
        vcc_NextToken(tl);
262 11727
        tl->indent += INDENT;
263 11727
        Fb(tl, 1, "{\n");
264 11727
        L(tl, vcc_Compound(tl));
265 11727
        Fb(tl, 1, "}\n");
266 11727
        tl->indent -= INDENT;
267 11727
        tl->fb = NULL;
268 11727
        tl->curproc = NULL;
269
}
270
271
/*--------------------------------------------------------------------
272
 */
273
274
static void
275 1666
vcc_ParseVcl(struct vcc *tl)
276
{
277
        struct token *tok;
278
279 1666
        assert(vcc_IdIs(tl->t, "vcl"));
280 1666
        vcc_NextToken(tl);
281 1666
        tok = tl->t;
282 1666
        tok->src->syntax = vcc_DoubleVal(tl);
283 1666
        ERRCHK(tl);
284 1666
        if (tl->t->e - tok->b > 4) {
285 1
                VSB_printf(tl->sb,
286
                    "Don't play silly buggers with VCL version numbers\n");
287 1
                vcc_ErrWhere2(tl, tok, tl->t);
288 1
                ERRCHK(tl);
289
        }
290 1665
        if (tl->syntax != 0.0 && tok->src->syntax > tl->syntax) {
291 2
                VSB_printf(tl->sb,
292
                    "VCL version %.1f higher than"
293
                    " the top level version %.1f\n",
294 2
                    tok->src->syntax, tl->syntax);
295 1
                vcc_ErrWhere2(tl, tok, tl->t);
296 1
                ERRCHK(tl);
297
        }
298 1664
        ExpectErr(tl, ';');
299 1664
        vcc_NextToken(tl);
300
}
301
302
/*--------------------------------------------------------------------
303
 * Top level of parser, recognize:
304
 *      Inline C-code
305
 *      ACL definitions
306
 *      Function definitions
307
 *      Backend definitions
308
 *      VMOD import directives
309
 *      VCL version declarations
310
 *      End of input
311
 */
312
313
typedef void parse_f(struct vcc *tl);
314
315
static struct toplev {
316
        const char      *name;
317
        parse_f         *func;
318
} toplev[] = {
319
        { "acl",                vcc_ParseAcl },
320
        { "sub",                vcc_ParseFunction },
321
        { "backend",            vcc_ParseBackend },
322
        { "probe",              vcc_ParseProbe },
323
        { "import",             vcc_ParseImport },
324
        { "vcl",                vcc_ParseVcl },
325
        { NULL, NULL }
326
};
327
328
void
329 894
vcc_Parse(struct vcc *tl)
330
{
331
        struct toplev *tp;
332
        struct token *tok;
333
334 894
        AZ(tl->indent);
335 894
        if (tl->t->tok != ID || !vcc_IdIs(tl->t, "vcl")) {
336 2
                VSB_printf(tl->sb,
337
                    "VCL version declaration missing\n"
338
                    "Update your VCL to Version 4 syntax, and add\n"
339
                    "\tvcl 4.0;\n"
340
                    "on the first line of the VCL files.\n"
341
                );
342 2
                vcc_ErrWhere(tl, tl->t);
343 2
                ERRCHK(tl);
344
        }
345 892
        tok = tl->t;
346 892
        vcc_ParseVcl(tl);
347 892
        if (tok->src->syntax != 4.0) {
348 1
                VSB_printf(tl->sb, "VCL version %.1f not supported.\n",
349 1
                    tok->src->syntax);
350 1
                vcc_ErrWhere2(tl, tok, tl->t);
351 1
                ERRCHK(tl);
352
        }
353 891
        tl->syntax = tl->t->src->syntax;
354 891
        ERRCHK(tl);
355 15515
        while (tl->t->tok != EOI) {
356 13854
                ERRCHK(tl);
357 13735
                switch (tl->t->tok) {
358
                case CSRC:
359 7
                        if (tl->allow_inline_c) {
360 12
                                Fc(tl, 0, "%.*s\n",
361 6
                                    (int) (tl->t->e - (tl->t->b + 4)),
362 6
                                    tl->t->b + 2);
363 6
                                vcc_NextToken(tl);
364
                        } else {
365 1
                                VSB_printf(tl->sb,
366
                                    "Inline-C not allowed\n");
367 1
                                vcc_ErrWhere(tl, tl->t);
368
                        }
369 7
                        break;
370
                case EOI:
371 0
                        break;
372
                case ID:
373 64492
                        for (tp = toplev; tp->name != NULL; tp++) {
374 32245
                                if (!vcc_IdIs(tl->t, tp->name))
375 18519
                                        continue;
376 13726
                                tp->func(tl);
377 13726
                                break;
378
                        }
379 13727
                        if (tp->name != NULL)
380 13726
                                break;
381
                        /* FALLTHROUGH */
382
                default:
383
                        /* We deliberately do not mention inline-C */
384 2
                        VSB_printf(tl->sb, "Expected one of\n\t");
385 14
                        for (tp = toplev; tp->name != NULL; tp++) {
386 12
                                if (tp[1].name == NULL)
387 2
                                        VSB_printf(tl->sb, " or ");
388 12
                                VSB_printf(tl->sb, "'%s'", tp->name);
389 12
                                if (tp[1].name != NULL)
390 10
                                        VSB_printf(tl->sb, ", ");
391
                        }
392 2
                        VSB_printf(tl->sb, "\nFound: ");
393 2
                        vcc_ErrToken(tl, tl->t);
394 2
                        VSB_printf(tl->sb, " at\n");
395 2
                        vcc_ErrWhere(tl, tl->t);
396 2
                        return;
397
                }
398
        }
399 770
        AZ(tl->indent);
400
}