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 * SPDX-License-Identifier: BSD-2-Clause
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32 #include "config.h"
33
34 #include <string.h>
35
36 #include "vcc_compile.h"
37
38 /*--------------------------------------------------------------------*/
39
40 static void vcc_Compound(struct vcc *tl);
41
42 /*--------------------------------------------------------------------*/
43
44 #define L(tl, foo) do { \
45 tl->indent += INDENT; \
46 foo; \
47 tl->indent -= INDENT; \
48 } while (0)
49
50 #define C(tl, sep) do { \
51 Fb(tl, 1, "VPI_count(ctx, %u)%s\n", ++tl->cnt, sep); \
52 tl->t->cnt = tl->cnt; \
53 } while (0)
54
55 /*--------------------------------------------------------------------
56 * SYNTAX:
57 * Conditional:
58 * '(' Cond_0 ')'
59 */
60
61 static void
vcc_Conditional(struct vcc * tl)62 vcc_Conditional(struct vcc *tl)
63 {
64
65 SkipToken(tl, '(');
66 Fb(tl, 0, "(\n");
67 L(tl, vcc_Expr(tl, BOOL));
68 ERRCHK(tl);
69 Fb(tl, 1, ")\n");
70 SkipToken(tl, ')');
71 }
72
73 /*--------------------------------------------------------------------
74 * SYNTAX:
75 * IfStmt:
76 * 'if' Conditional Compound Branch1* Branch2
77 * Branch1:
78 * 'elseif' Conditional Compound
79 * Branch2:
80 * 'else' Compound
81 * null
82 */
83
v_matchproto_(sym_act_f)84 void v_matchproto_(sym_act_f)
85 vcc_Act_If(struct vcc *tl, struct token *t, struct symbol *sym)
86 {
87
88 (void)t;
89 (void)sym;
90 Fb(tl, 1, "if ");
91 vcc_Conditional(tl);
92 ERRCHK(tl);
93 L(tl, vcc_Compound(tl));
94 ERRCHK(tl);
95 while (tl->t->tok == ID) {
96 if (vcc_IdIs(tl->t, "else")) {
97 vcc_NextToken(tl);
98 if (tl->t->tok == '{') {
99 Fb(tl, 1, "else\n");
100 L(tl, vcc_Compound(tl));
101 ERRCHK(tl);
102 return;
103 }
104 if (tl->t->tok != ID || !vcc_IdIs(tl->t, "if")) {
105 VSB_printf(tl->sb,
106 "'else' must be followed by 'if' or '{'\n");
107 vcc_ErrWhere(tl, tl->t);
108 return;
109 }
110 Fb(tl, 1, "else if ");
111 vcc_NextToken(tl);
112 vcc_Conditional(tl);
113 ERRCHK(tl);
114 L(tl, vcc_Compound(tl));
115 ERRCHK(tl);
116 } else if (vcc_IdIs(tl->t, "elseif") ||
117 vcc_IdIs(tl->t, "elsif") ||
118 vcc_IdIs(tl->t, "elif")) {
119 Fb(tl, 1, "else if ");
120 vcc_NextToken(tl);
121 vcc_Conditional(tl);
122 ERRCHK(tl);
123 L(tl, vcc_Compound(tl));
124 ERRCHK(tl);
125 } else {
126 break;
127 }
128 }
129 C(tl, ";");
130 }
131
132 /*--------------------------------------------------------------------
133 * SYNTAX:
134 * Compound:
135 * '{' Stmt* '}'
136 *
137 * Stmt:
138 * Compound
139 * IfStmt
140 * CSRC
141 * Id(Action) (XXX)
142 */
143
144 static void
vcc_Compound(struct vcc * tl)145 vcc_Compound(struct vcc *tl)
146 {
147 struct symbol *sym;
148 struct token *t;
149
150 SkipToken(tl, '{');
151 Fb(tl, 1, "{\n");
152 tl->indent += INDENT;
153 C(tl, ";");
154 Fb(tl, 1, "END_;\n");
155 while (1) {
156 ERRCHK(tl);
157 t = tl->t;
158 switch (tl->t->tok) {
159 case '{':
160 vcc_Compound(tl);
161 break;
162 case '}':
163 vcc_NextToken(tl);
164 tl->indent -= INDENT;
165 Fb(tl, 1, "}\n");
166 return;
167 case CSRC:
168 if (tl->allow_inline_c) {
169 Fb(tl, 1, "%.*s\n",
170 (int) (tl->t->e - (tl->t->b + 2)),
171 tl->t->b + 1);
172 vcc_NextToken(tl);
173 } else {
174 VSB_printf(tl->sb,
175 "Inline-C not allowed\n");
176 vcc_ErrWhere(tl, tl->t);
177 }
178 break;
179 case EOI:
180 VSB_printf(tl->sb,
181 "End of input while in compound statement\n");
182 tl->err = 1;
183 return;
184 case ID:
185 sym = VCC_SymbolGet(tl, SYM_MAIN, SYM_NONE,
186 SYMTAB_PARTIAL, XREF_NONE);
187 if (sym == NULL) {
188 VSB_printf(tl->sb, "Symbol not found.\n");
189 vcc_ErrWhere(tl, tl->t);
190 return;
191 }
192 if (sym->action == NULL) {
193 VSB_printf(tl->sb,
194 "Symbol cannot be used here.\n");
195 vcc_ErrWhere(tl, tl->t);
196 return;
197 }
198 if (sym->action_mask != 0)
199 vcc_AddUses(tl, t, NULL, sym, XREF_ACTION);
200 sym->action(tl, t, sym);
201 break;
202 default:
203 /* We deliberately do not mention inline C */
204 VSB_printf(tl->sb,
205 "Expected an action, 'if', '{' or '}'\n");
206 vcc_ErrWhere(tl, tl->t);
207 return;
208 }
209 Fb(tl, 1, "END_;\n");
210 }
211 }
212
213 /*--------------------------------------------------------------------
214 * SYNTAX:
215 * Function:
216 * 'sub' ID(name) Compound
217 */
218
219 static void
vcc_ParseFunction(struct vcc * tl)220 vcc_ParseFunction(struct vcc *tl)
221 {
222 struct symbol *sym, *bsym;
223 struct token *t;
224 struct proc *p;
225
226 vcc_NextToken(tl);
227 vcc_ExpectVid(tl, "subroutine");
228 ERRCHK(tl);
229
230 t = tl->t;
231 sym = VCC_SymbolGet(tl, SYM_MAIN, SYM_SUB, SYMTAB_CREATE, XREF_DEF);
232 ERRCHK(tl);
233 AN(sym);
234
235 if (vcc_builtin != NULL) {
236 vcc_builtin->t = t;
237 bsym = VCC_SymbolGet(vcc_builtin, SYM_MAIN, SYM_SUB,
238 SYMTAB_NOERR, XREF_NONE);
239 AZ(vcc_builtin->err);
240 }
241 else
242 bsym = NULL;
243
244 p = sym->proc;
245 if (p == NULL) {
246 if (vcc_builtin != NULL && bsym == NULL &&
247 (t->b[0] == 'v'|| t->b[0] == 'V') &&
248 (t->b[1] == 'c'|| t->b[1] == 'C') &&
249 (t->b[2] == 'l'|| t->b[2] == 'L') &&
250 (t->b[3] == '_')) {
251 VSB_printf(tl->sb,"The names 'vcl_*'"
252 " are reserved for subroutines.\n");
253 vcc_ErrWhere(tl, t);
254 VSB_printf(tl->sb, "Valid vcl_* subroutines are:\n");
255 VTAILQ_FOREACH(p, &vcc_builtin->procs, list) {
256 t = p->name;
257 VSB_printf(tl->sb, "\t%.*s\n",
258 (int)pdiff(t->b, t->e), t->b);
259 }
260 return;
261 }
262 VCC_GlobalSymbol(sym, SUB, "VGC_function");
263 p = vcc_NewProc(tl, sym);
264 p->name = t;
265 VSB_printf(p->cname, "%s", sym->lname);
266 } else if (p->method == NULL && bsym == NULL) {
267 VSB_printf(tl->sb, "Subroutine '%s' redefined\n", sym->name);
268 vcc_ErrWhere(tl, t);
269 VSB_printf(tl->sb, "Previously defined here:\n");
270 vcc_ErrWhere(tl, p->name);
271 return;
272 } else {
273 /* Add to VCL sub */
274 if (p->name == NULL)
275 p->name = t;
276 }
277 CHECK_OBJ_NOTNULL(p, PROC_MAGIC);
278 tl->fb = p->body;
279 Fb(tl, 1, " /* ... from ");
280 vcc_Coord(tl, p->body, NULL);
281 Fb(tl, 0, " */\n");
282 tl->curproc = p;
283 tl->indent += INDENT;
284 Fb(tl, 1, "{\n");
285 L(tl, vcc_Compound(tl));
286 Fb(tl, 1, "}\n");
287 tl->indent -= INDENT;
288 tl->fb = NULL;
289 tl->curproc = NULL;
290 }
291
292 /*--------------------------------------------------------------------
293 */
294
295 static void
vcc_ParseVcl(struct vcc * tl)296 vcc_ParseVcl(struct vcc *tl)
297 {
298 struct token *tok0;
299 int syntax;
300
301 assert(vcc_IdIs(tl->t, "vcl"));
302 tok0 = tl->t;
303 vcc_NextToken(tl);
304
305 Expect(tl, FNUM);
306 if (tl->t->e - tl->t->b != 3 || tl->t->b[1] != '.') {
307 VSB_cat(tl->sb,
308 "Don't play silly buggers with VCL version numbers\n");
309 vcc_ErrWhere(tl, tl->t);
310 ERRCHK(tl);
311 }
312 syntax = (tl->t->b[0] - '0') * 10 + (tl->t->b[2] - '0');
313 vcc_NextToken(tl);
314
315 if (syntax < VCL_LOW || syntax > VCL_HIGH) {
316 VSB_printf(tl->sb, "VCL version %.1f not supported.\n",
317 .1 * syntax);
318 vcc_ErrWhere2(tl, tok0, tl->t);
319 ERRCHK(tl);
320 }
321
322 if (tl->t->tok != ';') {
323 /* Special handling, because next token might be 'vcl'
324 * in the built-in VCL, and that would give a very
325 * confusing error message
326 */
327 VSB_cat(tl->sb, "Expected 'vcl N.N;' found no semi-colon\n");
328 vcc_ErrWhere2(tl, tok0, tl->t);
329 ERRCHK(tl);
330 }
331 vcc_NextToken(tl);
332 if (tl->syntax == 0)
333 tl->syntax = syntax;
334 if (syntax > tl->syntax) {
335 VSB_printf(tl->sb,
336 "VCL version %.1f higher than"
337 " the top level version %.1f\n",
338 .1 * syntax, .1 * tl->syntax);
339 vcc_ErrWhere2(tl, tok0, tl->t);
340 ERRCHK(tl);
341 }
342 }
343
344 /*--------------------------------------------------------------------
345 * Top level of parser, recognize:
346 * Inline C-code
347 * ACL definitions
348 * Function definitions
349 * Backend definitions
350 * VMOD import directives
351 * VCL version declarations
352 * End of input
353 */
354
355 typedef void parse_f(struct vcc *tl);
356
357 static struct toplev {
358 const char *name;
359 parse_f *func;
360 unsigned vcllo;
361 unsigned vclhi;
362 } toplev[] = {
363 { "acl", vcc_ParseAcl, VCL_41, VCL_HIGH },
364 { "sub", vcc_ParseFunction, VCL_41, VCL_HIGH },
365 { "backend", vcc_ParseBackend, VCL_41, VCL_HIGH },
366 { "probe", vcc_ParseProbe, VCL_41, VCL_HIGH },
367 { "import", vcc_ParseImport, VCL_41, VCL_HIGH },
368 { "vcl", vcc_ParseVcl, VCL_41, VCL_HIGH },
369 { NULL, NULL }
370 };
371
372 void
vcc_Parse(struct vcc * tl)373 vcc_Parse(struct vcc *tl)
374 {
375 struct toplev *tp;
376
377 AZ(tl->indent);
378 if (tl->t->tok != ID || !vcc_IdIs(tl->t, "vcl")) {
379 VSB_cat(tl->sb,
380 "VCL version declaration missing\n"
381 "Update your VCL to Version 4 syntax, and add\n"
382 "\tvcl 4.1;\n"
383 "on the first line of the VCL files.\n"
384 );
385 vcc_ErrWhere(tl, tl->t);
386 ERRCHK(tl);
387 }
388 vcc_ParseVcl(tl);
389 ERRCHK(tl);
390 AN(tl->syntax);
391 while (tl->t->tok != EOI) {
392 ERRCHK(tl);
393 switch (tl->t->tok) {
394 case CSRC:
395 if (tl->allow_inline_c) {
396 Fc(tl, 0, "%.*s\n",
397 (int) (tl->t->e - (tl->t->b + 4)),
398 tl->t->b + 2);
399 vcc_NextToken(tl);
400 } else {
401 VSB_cat(tl->sb, "Inline-C not allowed\n");
402 vcc_ErrWhere(tl, tl->t);
403 }
404 break;
405 case EOI:
406 break;
407 case ID:
408 for (tp = toplev; tp->name != NULL; tp++) {
409 if (tp->func == NULL)
410 continue;
411 if (!vcc_IdIs(tl->t, tp->name))
412 continue;
413 tp->func(tl);
414 break;
415 }
416 if (tp->name != NULL)
417 break;
418 /* FALLTHROUGH */
419 default:
420 /* We deliberately do not mention inline-C */
421 VSB_cat(tl->sb, "Expected one of\n\t");
422 for (tp = toplev; tp->name != NULL; tp++) {
423 if (tp[1].name == NULL)
424 VSB_cat(tl->sb, " or ");
425 VSB_printf(tl->sb, "'%s'", tp->name);
426 if (tp[1].name != NULL)
427 VSB_cat(tl->sb, ", ");
428 }
429 VSB_cat(tl->sb, "\nFound: ");
430 vcc_ErrToken(tl, tl->t);
431 VSB_cat(tl->sb, " at\n");
432 vcc_ErrWhere(tl, tl->t);
433 return;
434 }
435 }
436 AZ(tl->indent);
437 }
438
439 void
vcc_Parse_Init(struct vcc * tl)440 vcc_Parse_Init(struct vcc *tl)
441 {
442 struct toplev *tp;
443
444 for (tp = toplev; tp->name != NULL; tp++)
445 AN(VCC_MkSym(tl, tp->name, SYM_MAIN, SYM_RESERVED,
446 tp->vcllo, tp->vclhi));
447 }
448