| | varnish-cache/lib/libvcc/vcc_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: Poul-Henning Kamp <phk@phk.freebsd.dk> |
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 |
|
#include "config.h" |
32 |
|
|
33 |
|
#include <string.h> |
34 |
|
|
35 |
|
#include "vcc_compile.h" |
36 |
|
|
37 |
|
/*--------------------------------------------------------------------*/ |
38 |
|
|
39 |
|
static void vcc_Compound(struct vcc *tl); |
40 |
|
|
41 |
|
/*--------------------------------------------------------------------*/ |
42 |
|
|
43 |
|
#define L(tl, foo) do { \ |
44 |
|
tl->indent += INDENT; \ |
45 |
|
foo; \ |
46 |
|
tl->indent -= INDENT; \ |
47 |
|
} while (0) |
48 |
|
|
49 |
|
#define C(tl, sep) do { \ |
50 |
|
Fb(tl, 1, "VPI_count(ctx, VGC_NREFS, %u)%s\n", ++tl->cnt, sep); \ |
51 |
|
Fb(tl, 1, "if (UNLIKELY(ctx->vpi->trace)) VPI_trace(ctx, %u)%s\n", \ |
52 |
|
tl->cnt, sep); \ |
53 |
|
tl->t->cnt = tl->cnt; \ |
54 |
|
} while (0) |
55 |
|
|
56 |
|
/*-------------------------------------------------------------------- |
57 |
|
* SYNTAX: |
58 |
|
* Conditional: |
59 |
|
* '(' Cond_0 ')' |
60 |
|
*/ |
61 |
|
|
62 |
|
static void |
63 |
1692240 |
vcc_Conditional(struct vcc *tl) |
64 |
|
{ |
65 |
|
|
66 |
1692240 |
SkipToken(tl, '('); |
67 |
1692240 |
Fb(tl, 0, "(\n"); |
68 |
1692240 |
L(tl, vcc_Expr(tl, BOOL)); |
69 |
1692240 |
ERRCHK(tl); |
70 |
1690960 |
Fb(tl, 1, ")\n"); |
71 |
1690960 |
SkipToken(tl, ')'); |
72 |
1692240 |
} |
73 |
|
|
74 |
|
/*-------------------------------------------------------------------- |
75 |
|
* SYNTAX: |
76 |
|
* IfStmt: |
77 |
|
* 'if' Conditional Compound Branch1* Branch2 |
78 |
|
* Branch1: |
79 |
|
* 'elseif' Conditional Compound |
80 |
|
* Branch2: |
81 |
|
* 'else' Compound |
82 |
|
* null |
83 |
|
*/ |
84 |
|
|
85 |
|
void v_matchproto_(sym_act_f) |
86 |
1687000 |
vcc_Act_If(struct vcc *tl, struct token *t, struct symbol *sym) |
87 |
|
{ |
88 |
|
|
89 |
1687000 |
(void)t; |
90 |
1687000 |
(void)sym; |
91 |
1687000 |
Fb(tl, 1, "if "); |
92 |
1687000 |
vcc_Conditional(tl); |
93 |
1687000 |
ERRCHK(tl); |
94 |
1685680 |
L(tl, vcc_Compound(tl)); |
95 |
1685680 |
ERRCHK(tl); |
96 |
1690920 |
while (tl->t->tok == ID) { |
97 |
572680 |
if (vcc_IdIs(tl->t, "else")) { |
98 |
116320 |
vcc_NextToken(tl); |
99 |
116320 |
if (tl->t->tok == '{') { |
100 |
113320 |
Fb(tl, 1, "else\n"); |
101 |
113320 |
L(tl, vcc_Compound(tl)); |
102 |
113320 |
ERRCHK(tl); |
103 |
113320 |
return; |
104 |
|
} |
105 |
3000 |
if (tl->t->tok != ID || !vcc_IdIs(tl->t, "if")) { |
106 |
0 |
VSB_printf(tl->sb, |
107 |
|
"'else' must be followed by 'if' or '{'\n"); |
108 |
0 |
vcc_ErrWhere(tl, tl->t); |
109 |
0 |
return; |
110 |
|
} |
111 |
3000 |
Fb(tl, 1, "else if "); |
112 |
3000 |
vcc_NextToken(tl); |
113 |
3000 |
vcc_Conditional(tl); |
114 |
3000 |
ERRCHK(tl); |
115 |
3000 |
L(tl, vcc_Compound(tl)); |
116 |
3000 |
ERRCHK(tl); |
117 |
913600 |
} else if (vcc_IdIs(tl->t, "elseif") || |
118 |
456280 |
vcc_IdIs(tl->t, "elsif") || |
119 |
454240 |
vcc_IdIs(tl->t, "elif")) { |
120 |
2240 |
Fb(tl, 1, "else if "); |
121 |
2240 |
vcc_NextToken(tl); |
122 |
2240 |
vcc_Conditional(tl); |
123 |
2240 |
ERRCHK(tl); |
124 |
2240 |
L(tl, vcc_Compound(tl)); |
125 |
2240 |
ERRCHK(tl); |
126 |
2240 |
} else { |
127 |
454120 |
break; |
128 |
|
} |
129 |
|
} |
130 |
1572360 |
C(tl, ";"); |
131 |
1687000 |
} |
132 |
|
|
133 |
|
/*-------------------------------------------------------------------- |
134 |
|
* SYNTAX: |
135 |
|
* Compound: |
136 |
|
* '{' Stmt* '}' |
137 |
|
* |
138 |
|
* Stmt: |
139 |
|
* Compound |
140 |
|
* IfStmt |
141 |
|
* CSRC |
142 |
|
* Id(Action) (XXX) |
143 |
|
*/ |
144 |
|
|
145 |
|
static void |
146 |
5849080 |
vcc_Compound(struct vcc *tl) |
147 |
|
{ |
148 |
|
struct symbol *sym; |
149 |
|
struct token *t; |
150 |
|
|
151 |
5849080 |
SkipToken(tl, '{'); |
152 |
5849080 |
Fb(tl, 1, "{\n"); |
153 |
5849080 |
tl->indent += INDENT; |
154 |
5849080 |
C(tl, ";"); |
155 |
5849080 |
Fb(tl, 1, "END_;\n"); |
156 |
14461160 |
while (1) { |
157 |
14461160 |
ERRCHK(tl); |
158 |
14456600 |
t = tl->t; |
159 |
14456600 |
switch (tl->t->tok) { |
160 |
|
case '{': |
161 |
80 |
vcc_Compound(tl); |
162 |
80 |
break; |
163 |
|
case '}': |
164 |
5844320 |
vcc_NextToken(tl); |
165 |
5844320 |
tl->indent -= INDENT; |
166 |
5844320 |
Fb(tl, 1, "}\n"); |
167 |
5844320 |
return; |
168 |
|
case CSRC: |
169 |
600 |
if (tl->allow_inline_c) { |
170 |
1120 |
Fb(tl, 1, "%.*s\n", |
171 |
560 |
(int) (tl->t->e - (tl->t->b + 2)), |
172 |
560 |
tl->t->b + 1); |
173 |
560 |
vcc_NextToken(tl); |
174 |
560 |
} else { |
175 |
40 |
VSB_printf(tl->sb, |
176 |
|
"Inline-C not allowed\n"); |
177 |
40 |
vcc_ErrWhere(tl, tl->t); |
178 |
|
} |
179 |
600 |
break; |
180 |
|
case EOI: |
181 |
0 |
VSB_printf(tl->sb, |
182 |
|
"End of input while in compound statement\n"); |
183 |
0 |
tl->err = 1; |
184 |
0 |
return; |
185 |
|
case ID: |
186 |
8611600 |
sym = VCC_SymbolGet(tl, SYM_MAIN, SYM_NONE, |
187 |
|
SYMTAB_PARTIAL, XREF_NONE); |
188 |
8611600 |
if (sym == NULL) { |
189 |
160 |
VSB_printf(tl->sb, "Symbol not found.\n"); |
190 |
160 |
vcc_ErrWhere(tl, tl->t); |
191 |
160 |
return; |
192 |
|
} |
193 |
8611440 |
if (sym->action == NULL) { |
194 |
40 |
VSB_printf(tl->sb, |
195 |
|
"Symbol cannot be used here.\n"); |
196 |
40 |
vcc_ErrWhere(tl, tl->t); |
197 |
40 |
return; |
198 |
|
} |
199 |
8611400 |
if (sym->action_mask != 0) |
200 |
340560 |
vcc_AddUses(tl, t, NULL, sym, XREF_ACTION); |
201 |
8611400 |
sym->action(tl, t, sym); |
202 |
8611400 |
break; |
203 |
|
default: |
204 |
|
/* We deliberately do not mention inline C */ |
205 |
0 |
VSB_printf(tl->sb, |
206 |
|
"Expected an action, 'if', '{' or '}'\n"); |
207 |
0 |
vcc_ErrWhere(tl, tl->t); |
208 |
0 |
return; |
209 |
|
} |
210 |
8612080 |
Fb(tl, 1, "END_;\n"); |
211 |
|
} |
212 |
5849080 |
} |
213 |
|
|
214 |
|
/*-------------------------------------------------------------------- |
215 |
|
* SYNTAX: |
216 |
|
* Function: |
217 |
|
* 'sub' ID(name) Compound |
218 |
|
*/ |
219 |
|
|
220 |
|
static void |
221 |
4044920 |
vcc_ParseFunction(struct vcc *tl) |
222 |
|
{ |
223 |
|
struct symbol *sym, *bsym; |
224 |
|
struct token *t; |
225 |
|
struct proc *p; |
226 |
|
|
227 |
4044920 |
vcc_NextToken(tl); |
228 |
4044920 |
vcc_ExpectVid(tl, "subroutine"); |
229 |
4044920 |
ERRCHK(tl); |
230 |
|
|
231 |
4044880 |
t = tl->t; |
232 |
4044880 |
sym = VCC_SymbolGet(tl, SYM_MAIN, SYM_SUB, SYMTAB_CREATE, XREF_DEF); |
233 |
4044880 |
ERRCHK(tl); |
234 |
4044840 |
AN(sym); |
235 |
|
|
236 |
4044840 |
if (vcc_builtin != NULL) { |
237 |
1887720 |
vcc_builtin->t = t; |
238 |
1887720 |
bsym = VCC_SymbolGet(vcc_builtin, SYM_MAIN, SYM_SUB, |
239 |
|
SYMTAB_NOERR, XREF_NONE); |
240 |
1887720 |
AZ(vcc_builtin->err); |
241 |
1887720 |
} |
242 |
|
else |
243 |
2157120 |
bsym = NULL; |
244 |
|
|
245 |
4044840 |
p = sym->proc; |
246 |
4044840 |
if (p == NULL) { |
247 |
2434520 |
if (vcc_builtin != NULL && bsym == NULL && |
248 |
3080 |
vcc_Has_vcl_prefix(t->b)) { |
249 |
40 |
VSB_printf(tl->sb,"The names 'vcl_*'" |
250 |
|
" are reserved for subroutines.\n"); |
251 |
40 |
vcc_ErrWhere(tl, t); |
252 |
40 |
VSB_printf(tl->sb, "Valid vcl_* subroutines are:\n"); |
253 |
1480 |
VTAILQ_FOREACH(p, &vcc_builtin->procs, list) { |
254 |
1440 |
t = p->name; |
255 |
2880 |
VSB_printf(tl->sb, "\t%.*s\n", |
256 |
1440 |
(int)pdiff(t->b, t->e), t->b); |
257 |
1440 |
} |
258 |
40 |
return; |
259 |
|
} |
260 |
2434480 |
VCC_GlobalSymbol(sym, SUB); |
261 |
2434480 |
p = vcc_NewProc(tl, sym); |
262 |
2434480 |
p->name = t; |
263 |
2434480 |
VSB_printf(p->cname, "%s", sym->lname); |
264 |
4044800 |
} else if (p->method == NULL && bsym == NULL) { |
265 |
40 |
VSB_printf(tl->sb, "Subroutine '%s' redefined\n", sym->name); |
266 |
40 |
vcc_ErrWhere(tl, t); |
267 |
40 |
VSB_printf(tl->sb, "Previously defined here:\n"); |
268 |
40 |
vcc_ErrWhere(tl, p->name); |
269 |
40 |
return; |
270 |
|
} else { |
271 |
|
/* Add to VCL sub */ |
272 |
1610280 |
if (p->name == NULL) |
273 |
1552160 |
p->name = t; |
274 |
|
} |
275 |
4044760 |
CHECK_OBJ_NOTNULL(p, PROC_MAGIC); |
276 |
4044760 |
tl->fb = p->body; |
277 |
4044760 |
Fb(tl, 1, " /* ... from "); |
278 |
4044760 |
vcc_Coord(tl, p->body, NULL); |
279 |
4044760 |
Fb(tl, 0, " */\n"); |
280 |
4044760 |
tl->curproc = p; |
281 |
4044760 |
tl->indent += INDENT; |
282 |
4044760 |
Fb(tl, 1, "{\n"); |
283 |
4044760 |
L(tl, vcc_Compound(tl)); |
284 |
4044760 |
Fb(tl, 1, "}\n"); |
285 |
4044760 |
tl->indent -= INDENT; |
286 |
4044760 |
tl->fb = NULL; |
287 |
4044760 |
tl->curproc = NULL; |
288 |
4044920 |
} |
289 |
|
|
290 |
|
/*-------------------------------------------------------------------- |
291 |
|
*/ |
292 |
|
|
293 |
|
static void |
294 |
169280 |
vcc_ParseVcl(struct vcc *tl) |
295 |
|
{ |
296 |
|
struct token *tok0; |
297 |
|
int syntax; |
298 |
|
|
299 |
169280 |
assert(vcc_IdIs(tl->t, "vcl")); |
300 |
169280 |
tok0 = tl->t; |
301 |
169280 |
vcc_NextToken(tl); |
302 |
|
|
303 |
169280 |
Expect(tl, FNUM); |
304 |
169280 |
if (tl->t->e - tl->t->b != 3 || tl->t->b[1] != '.') { |
305 |
120 |
VSB_cat(tl->sb, |
306 |
|
"Don't play silly buggers with VCL version numbers\n"); |
307 |
120 |
vcc_ErrWhere(tl, tl->t); |
308 |
120 |
ERRCHK(tl); |
309 |
0 |
} |
310 |
169160 |
syntax = (tl->t->b[0] - '0') * 10 + (tl->t->b[2] - '0'); |
311 |
169160 |
vcc_NextToken(tl); |
312 |
|
|
313 |
169160 |
if (syntax < VCL_LOW || syntax > VCL_HIGH) { |
314 |
160 |
VSB_printf(tl->sb, "VCL version %.1f not supported.\n", |
315 |
80 |
.1 * syntax); |
316 |
80 |
vcc_ErrWhere2(tl, tok0, tl->t); |
317 |
80 |
ERRCHK(tl); |
318 |
0 |
} |
319 |
|
|
320 |
169080 |
if (tl->t->tok != ';') { |
321 |
|
/* Special handling, because next token might be 'vcl' |
322 |
|
* in the built-in VCL, and that would give a very |
323 |
|
* confusing error message |
324 |
|
*/ |
325 |
40 |
VSB_cat(tl->sb, "Expected 'vcl N.N;' found no semi-colon\n"); |
326 |
40 |
vcc_ErrWhere2(tl, tok0, tl->t); |
327 |
40 |
ERRCHK(tl); |
328 |
0 |
} |
329 |
169040 |
vcc_NextToken(tl); |
330 |
169040 |
if (tl->syntax == 0) |
331 |
118320 |
tl->syntax = syntax; |
332 |
169040 |
if (syntax > tl->syntax) { |
333 |
0 |
VSB_printf(tl->sb, |
334 |
|
"VCL version %.1f higher than" |
335 |
|
" the top level version %.1f\n", |
336 |
0 |
.1 * syntax, .1 * tl->syntax); |
337 |
0 |
vcc_ErrWhere2(tl, tok0, tl->t); |
338 |
0 |
ERRCHK(tl); |
339 |
0 |
} |
340 |
169280 |
} |
341 |
|
|
342 |
|
/*-------------------------------------------------------------------- |
343 |
|
* Top level of parser, recognize: |
344 |
|
* Inline C-code |
345 |
|
* ACL definitions |
346 |
|
* Function definitions |
347 |
|
* Backend definitions |
348 |
|
* VMOD import directives |
349 |
|
* VCL version declarations |
350 |
|
* End of input |
351 |
|
*/ |
352 |
|
|
353 |
|
typedef void parse_f(struct vcc *tl); |
354 |
|
|
355 |
|
static struct toplev { |
356 |
|
const char *name; |
357 |
|
parse_f *func; |
358 |
|
unsigned vcllo; |
359 |
|
unsigned vclhi; |
360 |
|
} toplev[] = { |
361 |
|
{ "acl", vcc_ParseAcl, VCL_41, VCL_HIGH }, |
362 |
|
{ "sub", vcc_ParseFunction, VCL_41, VCL_HIGH }, |
363 |
|
{ "backend", vcc_ParseBackend, VCL_41, VCL_HIGH }, |
364 |
|
{ "probe", vcc_ParseProbe, VCL_41, VCL_HIGH }, |
365 |
|
{ "import", vcc_ParseImport, VCL_41, VCL_HIGH }, |
366 |
|
{ "vcl", vcc_ParseVcl, VCL_41, VCL_HIGH }, |
367 |
|
{ NULL, NULL } |
368 |
|
}; |
369 |
|
|
370 |
|
void |
371 |
118520 |
vcc_Parse(struct vcc *tl) |
372 |
|
{ |
373 |
|
struct toplev *tp; |
374 |
|
|
375 |
118520 |
AZ(tl->indent); |
376 |
118520 |
if (tl->t->tok != ID || !vcc_IdIs(tl->t, "vcl")) { |
377 |
40 |
VSB_cat(tl->sb, |
378 |
|
"VCL version declaration missing\n" |
379 |
|
"Update your VCL to Version 4 syntax, and add\n" |
380 |
|
"\tvcl 4.1;\n" |
381 |
|
"on the first line of the VCL files.\n" |
382 |
|
); |
383 |
40 |
vcc_ErrWhere(tl, tl->t); |
384 |
40 |
ERRCHK(tl); |
385 |
0 |
} |
386 |
118480 |
vcc_ParseVcl(tl); |
387 |
118480 |
ERRCHK(tl); |
388 |
118320 |
AN(tl->syntax); |
389 |
4305720 |
while (tl->t->tok != EOI) { |
390 |
4195200 |
ERRCHK(tl); |
391 |
4187480 |
switch (tl->t->tok) { |
392 |
|
case CSRC: |
393 |
360 |
if (tl->allow_inline_c) { |
394 |
640 |
Fc(tl, 0, "%.*s\n", |
395 |
320 |
(int) (tl->t->e - (tl->t->b + 4)), |
396 |
320 |
tl->t->b + 2); |
397 |
320 |
vcc_NextToken(tl); |
398 |
320 |
} else { |
399 |
40 |
VSB_cat(tl->sb, "Inline-C not allowed\n"); |
400 |
40 |
vcc_ErrWhere(tl, tl->t); |
401 |
|
} |
402 |
360 |
break; |
403 |
|
case EOI: |
404 |
0 |
break; |
405 |
|
case ID: |
406 |
8713680 |
for (tp = toplev; tp->name != NULL; tp++) { |
407 |
8713640 |
if (tp->func == NULL) |
408 |
0 |
continue; |
409 |
8713640 |
if (!vcc_IdIs(tl->t, tp->name)) |
410 |
4526600 |
continue; |
411 |
4187040 |
tp->func(tl); |
412 |
4187040 |
break; |
413 |
|
} |
414 |
4187080 |
if (tp->name != NULL) |
415 |
4187040 |
break; |
416 |
|
/* FALLTHROUGH */ |
417 |
|
default: |
418 |
|
/* We deliberately do not mention inline-C */ |
419 |
80 |
VSB_cat(tl->sb, "Expected one of\n\t"); |
420 |
560 |
for (tp = toplev; tp->name != NULL; tp++) { |
421 |
480 |
if (tp[1].name == NULL) |
422 |
80 |
VSB_cat(tl->sb, " or "); |
423 |
480 |
VSB_printf(tl->sb, "'%s'", tp->name); |
424 |
480 |
if (tp[1].name != NULL) |
425 |
400 |
VSB_cat(tl->sb, ", "); |
426 |
480 |
} |
427 |
80 |
VSB_cat(tl->sb, "\nFound: "); |
428 |
80 |
vcc_ErrToken(tl, tl->t); |
429 |
80 |
VSB_cat(tl->sb, " at\n"); |
430 |
80 |
vcc_ErrWhere(tl, tl->t); |
431 |
80 |
return; |
432 |
|
} |
433 |
|
} |
434 |
110520 |
AZ(tl->indent); |
435 |
118520 |
} |
436 |
|
|
437 |
|
void |
438 |
119800 |
vcc_Parse_Init(struct vcc *tl) |
439 |
|
{ |
440 |
|
struct toplev *tp; |
441 |
|
|
442 |
838600 |
for (tp = toplev; tp->name != NULL; tp++) |
443 |
718800 |
AN(VCC_MkSym(tl, tp->name, SYM_MAIN, SYM_RESERVED, |
444 |
|
tp->vcllo, tp->vclhi)); |
445 |
119800 |
} |