From: phk Date: Sat, 24 Mar 2007 21:01:43 +0000 (+0000) Subject: Split off the parsing from vcc_compile.c into vcc_parse.c X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f7a78edd1fe32955d25f70a8f3ce713a4042fc1f;p=varnish Split off the parsing from vcc_compile.c into vcc_parse.c git-svn-id: svn+ssh://projects.linpro.no/svn/varnish/trunk@1283 d4fa192b-c00b-0410-8231-f00ffab90ce4 --- diff --git a/varnish-cache/lib/libvcl/Makefile.am b/varnish-cache/lib/libvcl/Makefile.am index 52c77294..a8184b6a 100644 --- a/varnish-cache/lib/libvcl/Makefile.am +++ b/varnish-cache/lib/libvcl/Makefile.am @@ -11,6 +11,7 @@ libvcl_la_SOURCES = \ \ vcc_acl.c \ vcc_compile.c \ + vcc_parse.c \ vcc_fixed_token.c \ vcc_obj.c \ vcc_token.c diff --git a/varnish-cache/lib/libvcl/vcc_compile.c b/varnish-cache/lib/libvcl/vcc_compile.c index 180e984c..4d9c6b21 100644 --- a/varnish-cache/lib/libvcl/vcc_compile.c +++ b/varnish-cache/lib/libvcl/vcc_compile.c @@ -96,25 +96,8 @@ static struct method method_tab[] = { /*--------------------------------------------------------------------*/ -static void Compound(struct tokenlist *tl); -static void Cond_0(struct tokenlist *tl); -static struct proc *AddProc(struct tokenlist *tl, struct token *t, int def); -static void AddCall(struct tokenlist *tl, struct token *t); const char *vcc_default_vcl_b, *vcc_default_vcl_e; -/*--------------------------------------------------------------------*/ - -#define L(tl, foo) do { \ - tl->indent += INDENT; \ - foo; \ - tl->indent -= INDENT; \ -} while (0) - -#define C(tl, sep) do { \ - Fc(tl, 1, "VRT_count(sp, %u)%s\n", ++tl->cnt, sep); \ - tl->t->cnt = tl->cnt; \ -} while (0) - /*-------------------------------------------------------------------- * Printf output to the two vsbs, possibly indented */ @@ -206,22 +189,6 @@ EncToken(struct vsb *sb, struct token *t) EncString(sb, t->dec, NULL); } -/*--------------------------------------------------------------------*/ - -static int -IsMethod(struct token *t) -{ - struct method *m; - - for(m = method_tab; m->name != NULL; m++) { - if (vcc_IdIs(t, m->defname)) - return (2); - if (vcc_IdIs(t, m->name)) - return (1); - } - return (0); -} - /*-------------------------------------------------------------------- * Keep track of definitions and references */ @@ -290,131 +257,6 @@ AddDef(struct tokenlist *tl, struct token *t, enum ref_type type) r->name = t; } -/*-------------------------------------------------------------------- - * Recognize and convert units of time, return seconds. - */ - -static double -TimeUnit(struct tokenlist *tl) -{ - double sc = 1.0; - - assert(tl->t->tok == ID); - if (vcc_IdIs(tl->t, "ms")) - sc = 1e-3; - else if (vcc_IdIs(tl->t, "s")) - sc = 1.0; - else if (vcc_IdIs(tl->t, "m")) - sc = 60.0; - else if (vcc_IdIs(tl->t, "h")) - sc = 60.0 * 60.0; - else if (vcc_IdIs(tl->t, "d")) - sc = 60.0 * 60.0 * 24.0; - else { - vsb_printf(tl->sb, "Unknown time unit "); - vcc_ErrToken(tl, tl->t); - vsb_printf(tl->sb, ". Legal are 's', 'm', 'h' and 'd'\n"); - vcc_ErrWhere(tl, tl->t); - return (1.0); - } - vcc_NextToken(tl); - return (sc); -} - -/*-------------------------------------------------------------------- - * Recognize and convert units of size, return bytes. - */ - -static double -SizeUnit(struct tokenlist *tl) -{ - double sc = 1.0; - - assert(tl->t->tok == ID); - if (vcc_IdIs(tl->t, "b")) - sc = 1.0; - else if (vcc_IdIs(tl->t, "kb")) - sc = 1024.0; - else if (vcc_IdIs(tl->t, "mb") || vcc_IdIs(tl->t, "Mb")) - sc = 1024.0 * 1024.0; - else if (vcc_IdIs(tl->t, "gb") || vcc_IdIs(tl->t, "Gb")) - sc = 1024.0 * 1024.0 * 1024.0; - else { - vsb_printf(tl->sb, "Unknown size unit "); - vcc_ErrToken(tl, tl->t); - vsb_printf(tl->sb, ". Legal are 'kb', 'mb' and 'gb'\n"); - vcc_ErrWhere(tl, tl->t); - return (1.0); - } - vcc_NextToken(tl); - return (sc); -} - -/*-------------------------------------------------------------------- - * Recognize and convert units of rate as { space '/' time } - */ - -static double -RateUnit(struct tokenlist *tl) -{ - double sc = 1.0; - - assert(tl->t->tok == ID); - sc = SizeUnit(tl); - Expect(tl, '/'); - vcc_NextToken(tl); - sc /= TimeUnit(tl); - return (sc); -} - -/*-------------------------------------------------------------------- - * Recognize and convert { CNUM } to unsigned value - */ - -unsigned -UintVal(struct tokenlist *tl) -{ - unsigned d = 0; - const char *p; - - Expect(tl, CNUM); - for (p = tl->t->b; p < tl->t->e; p++) { - d *= 10; - d += *p - '0'; - } - vcc_NextToken(tl); - return (d); -} - -/*-------------------------------------------------------------------- - * Recognize and convert { CNUM [ '.' [ CNUM ] ] } to double value - */ - -static double -DoubleVal(struct tokenlist *tl) -{ - double d = 0.0, e = 0.1; - const char *p; - - Expect(tl, CNUM); - for (p = tl->t->b; p < tl->t->e; p++) { - d *= 10; - d += *p - '0'; - } - vcc_NextToken(tl); - if (tl->t->tok != '.') - return (d); - vcc_NextToken(tl); - if (tl->t->tok != CNUM) - return (d); - for (p = tl->t->b; p < tl->t->e; p++) { - d += (*p - '0') * e; - e *= 0.1; - } - vcc_NextToken(tl); - return (d); -} - /*--------------------------------------------------------------------*/ static struct var * @@ -448,7 +290,7 @@ HeaderVar(struct tokenlist *tl, struct token *t, struct var *vh) /*--------------------------------------------------------------------*/ -static struct var * +struct var * FindVar(struct tokenlist *tl, struct token *t, struct var *vl) { struct var *v; @@ -471,671 +313,11 @@ FindVar(struct tokenlist *tl, struct token *t, struct var *vl) return (NULL); } - -/*--------------------------------------------------------------------*/ - -static void -TimeVal(struct tokenlist *tl) -{ - double v, sc; - - v = DoubleVal(tl); - ExpectErr(tl, ID); - sc = TimeUnit(tl); - Fc(tl, 0, "(%g * %g)", v, sc); -} - -static void -SizeVal(struct tokenlist *tl) -{ - double v, sc; - - v = DoubleVal(tl); - ExpectErr(tl, ID); - sc = SizeUnit(tl); - Fc(tl, 0, "(%g * %g)", v, sc); -} - -static void -RateVal(struct tokenlist *tl) -{ - double v, sc; - - v = DoubleVal(tl); - ExpectErr(tl, ID); - sc = RateUnit(tl); - Fc(tl, 0, "(%g * %g)", v, sc); -} - -/*--------------------------------------------------------------------*/ - -static void -vcc_re(struct tokenlist *tl, const char *str, struct token *re) -{ - char buf[32]; - - assert(re->tok == CSTR); - if (VRT_re_test(tl->sb, re->dec)) { - vcc_ErrWhere(tl, re); - return; - } - sprintf(buf, "VGC_re_%u", tl->recnt++); - - Fc(tl, 1, "VRT_re_match(%s, %s)\n", str, buf); - Fh(tl, 0, "void *%s;\n", buf); - Fi(tl, 0, "\tVRT_re_init(&%s, ",buf); - EncToken(tl->fi, re); - Fi(tl, 0, ");\n"); - Ff(tl, 0, "\tVRT_re_fini(%s);\n", buf); -} - - -/*--------------------------------------------------------------------*/ - -static void -Cond_String(struct var *vp, struct tokenlist *tl) -{ - - switch (tl->t->tok) { - case '~': - vcc_NextToken(tl); - ExpectErr(tl, CSTR); - vcc_re(tl, vp->rname, tl->t); - vcc_NextToken(tl); - break; - case T_EQ: - case T_NEQ: - Fc(tl, 1, "%sstrcmp(%s, ", - tl->t->tok == T_EQ ? "!" : "", vp->rname); - vcc_NextToken(tl); - ExpectErr(tl, CSTR); - EncToken(tl->fc, tl->t); - Fc(tl, 0, ")\n"); - vcc_NextToken(tl); - break; - default: - Fc(tl, 1, "%s != (void*)0", vp->rname); - break; - } -} - -static void -Cond_Int(struct var *vp, struct tokenlist *tl) -{ - - Fc(tl, 1, "%s ", vp->rname); - switch (tl->t->tok) { - case T_EQ: - case T_NEQ: - case T_LEQ: - case T_GEQ: - case '>': - case '<': - Fc(tl, 0, "%.*s ", PF(tl->t)); - vcc_NextToken(tl); - switch(vp->fmt) { - case TIME: - TimeVal(tl); - break; - case INT: - ExpectErr(tl, CNUM); - Fc(tl, 0, "%.*s ", PF(tl->t)); - vcc_NextToken(tl); - break; - case SIZE: - SizeVal(tl); - break; - default: - vsb_printf(tl->sb, - "No conditions available for variable '%s'\n", - vp->name); - vcc_ErrWhere(tl, tl->t); - return; - } - Fc(tl, 0, "\n"); - break; - default: - vsb_printf(tl->sb, "Illegal condition "); - vcc_ErrToken(tl, tl->t); - vsb_printf(tl->sb, " on integer variable\n"); - vsb_printf(tl->sb, - " only '==', '!=', '<', '>', '<=' and '>=' are legal\n"); - vcc_ErrWhere(tl, tl->t); - break; - } -} - -static void -Cond_Bool(struct var *vp, struct tokenlist *tl) -{ - - Fc(tl, 1, "%s\n", vp->rname); -} - -static void -Cond_Backend(struct var *vp, struct tokenlist *tl) -{ - - Fc(tl, 1, "%s\n", vp->rname); -} - -static void -Cond_2(struct tokenlist *tl) -{ - struct var *vp; - - C(tl, ","); - if (tl->t->tok == '!') { - Fc(tl, 1, "!(\n"); - vcc_NextToken(tl); - } else { - Fc(tl, 1, "(\n"); - } - if (tl->t->tok == '(') { - vcc_NextToken(tl); - Cond_0(tl); - ExpectErr(tl, ')'); - vcc_NextToken(tl); - } else if (tl->t->tok == VAR) { - vp = FindVar(tl, tl->t, vcc_vars); - ERRCHK(tl); - assert(vp != NULL); - vcc_NextToken(tl); - switch (vp->fmt) { - case INT: L(tl, Cond_Int(vp, tl)); break; - case SIZE: L(tl, Cond_Int(vp, tl)); break; - case BOOL: L(tl, Cond_Bool(vp, tl)); break; - case IP: L(tl, vcc_Cond_Ip(vp, tl)); break; - case STRING: L(tl, Cond_String(vp, tl)); break; - case TIME: L(tl, Cond_Int(vp, tl)); break; - case BACKEND: L(tl, Cond_Backend(vp, tl)); break; - default: - vsb_printf(tl->sb, - "Variable '%s'" - " has no conditions that can be checked\n", - vp->name); - vcc_ErrWhere(tl, tl->t); - return; - } - } else { - vsb_printf(tl->sb, - "Syntax error in condition, expected '(', '!' or" - " variable name, found "); - vcc_ErrToken(tl, tl->t); - vsb_printf(tl->sb, "\n"); - vcc_ErrWhere(tl, tl->t); - return; - } - Fc(tl, 1, ")\n"); -} - -static void -Cond_1(struct tokenlist *tl) -{ - - Fc(tl, 1, "(\n"); - L(tl, Cond_2(tl)); - while (tl->t->tok == T_CAND) { - vcc_NextToken(tl); - Fc(tl, 1, ") && (\n"); - L(tl, Cond_2(tl)); - } - Fc(tl, 1, ")\n"); -} - -static void -Cond_0(struct tokenlist *tl) -{ - - Fc(tl, 1, "(\n"); - L(tl, Cond_1(tl)); - while (tl->t->tok == T_COR) { - vcc_NextToken(tl); - Fc(tl, 1, ") || (\n"); - L(tl, Cond_1(tl)); - } - Fc(tl, 1, ")\n"); -} - -static void -Conditional(struct tokenlist *tl) -{ - - ExpectErr(tl, '('); - vcc_NextToken(tl); - Fc(tl, 1, "(\n"); - L(tl, Cond_0(tl)); - ERRCHK(tl); - Fc(tl, 1, ")\n"); - ExpectErr(tl, ')'); - vcc_NextToken(tl); -} - -/*--------------------------------------------------------------------*/ - -static void -IfStmt(struct tokenlist *tl) -{ - - ExpectErr(tl, T_IF); - Fc(tl, 1, "if \n"); - vcc_NextToken(tl); - L(tl, Conditional(tl)); - ERRCHK(tl); - L(tl, Compound(tl)); - ERRCHK(tl); - while (1) { - switch (tl->t->tok) { - case T_ELSE: - vcc_NextToken(tl); - if (tl->t->tok != T_IF) { - Fc(tl, 1, "else \n"); - L(tl, Compound(tl)); - ERRCHK(tl); - return; - } - /* FALLTHROUGH */ - case T_ELSEIF: - case T_ELSIF: - Fc(tl, 1, "else if \n"); - vcc_NextToken(tl); - L(tl, Conditional(tl)); - ERRCHK(tl); - L(tl, Compound(tl)); - ERRCHK(tl); - break; - default: - C(tl, ";"); - return; - } - } -} - -/*--------------------------------------------------------------------*/ - -static void -Action(struct tokenlist *tl) -{ - unsigned a; - struct var *vp; - struct token *at; - - at = tl->t; - vcc_NextToken(tl); - switch (at->tok) { - case T_NO_NEW_CACHE: - Fc(tl, 1, "VCL_no_new_cache(sp);\n"); - return; - case T_NO_CACHE: - Fc(tl, 1, "VCL_no_cache(sp);\n"); - return; -#define VCL_RET_MAC(a,b,c,d) case T_##b: \ - Fc(tl, 1, "VRT_done(sp, VCL_RET_%s);\n", #b); \ - tl->curproc->returns |= VCL_RET_##b; \ - tl->curproc->returnt[d] = at; \ - return; -#include "vcl_returns.h" -#undef VCL_RET_MAC - case T_ERROR: - if (tl->t->tok == CNUM) - a = UintVal(tl); - else - a = 0; - Fc(tl, 1, "VRT_error(sp, %u", a); - if (tl->t->tok == CSTR) { - Fc(tl, 0, ", %.*s", PF(tl->t)); - vcc_NextToken(tl); - } else { - Fc(tl, 0, ", (const char *)0"); - } - Fc(tl, 0, ");\n"); - Fc(tl, 1, "VRT_done(sp, VCL_RET_ERROR);\n"); - return; - case T_SWITCH_CONFIG: - ExpectErr(tl, ID); - Fc(tl, 1, "VCL_switch_config(\"%.*s\");\n", PF(tl->t)); - vcc_NextToken(tl); - return; - case T_CALL: - ExpectErr(tl, ID); - AddCall(tl, tl->t); - AddRef(tl, tl->t, R_FUNC); - Fc(tl, 1, "if (VGC_function_%.*s(sp))\n", PF(tl->t)); - Fc(tl, 1, "\treturn (1);\n"); - vcc_NextToken(tl); - return; - case T_REWRITE: - ExpectErr(tl, CSTR); - Fc(tl, 1, "VCL_rewrite(%.*s", PF(tl->t)); - vcc_NextToken(tl); - ExpectErr(tl, CSTR); - Fc(tl, 0, ", %.*s);\n", PF(tl->t)); - vcc_NextToken(tl); - return; - case T_SET: - ExpectErr(tl, VAR); - vp = FindVar(tl, tl->t, vcc_vars); - ERRCHK(tl); - assert(vp != NULL); - Fc(tl, 1, "%s", vp->lname); - vcc_NextToken(tl); - switch (vp->fmt) { - case INT: - case SIZE: - case RATE: - case TIME: - case FLOAT: - if (tl->t->tok != '=') - Fc(tl, 0, "%s %c ", vp->rname, *tl->t->b); - a = tl->t->tok; - vcc_NextToken(tl); - if (a == T_MUL || a == T_DIV) - Fc(tl, 0, "%g", DoubleVal(tl)); - else if (vp->fmt == TIME) - TimeVal(tl); - else if (vp->fmt == SIZE) - SizeVal(tl); - else if (vp->fmt == RATE) - RateVal(tl); - else - Fc(tl, 0, "%g", DoubleVal(tl)); - Fc(tl, 0, ");\n"); - break; -#if 0 /* XXX: enable if we find a legit use */ - case IP: - if (tl->t->tok == '=') { - vcc_NextToken(tl); - u = vcc_IpVal(tl); - Fc(tl, 0, "= %uU; /* %u.%u.%u.%u */\n", - u, - (u >> 24) & 0xff, - (u >> 16) & 0xff, - (u >> 8) & 0xff, - u & 0xff); - break; - } - vsb_printf(tl->sb, "Illegal assignment operator "); - vcc_ErrToken(tl, tl->t); - vsb_printf(tl->sb, - " only '=' is legal for IP numbers\n"); - vcc_ErrWhere(tl, tl->t); - return; -#endif - case BACKEND: - if (tl->t->tok == '=') { - vcc_NextToken(tl); - AddRef(tl, tl->t, R_BACKEND); - Fc(tl, 0, "VGC_backend_%.*s", PF(tl->t)); - vcc_NextToken(tl); - Fc(tl, 0, ");\n"); - break; - } - vsb_printf(tl->sb, "Illegal assignment operator "); - vcc_ErrToken(tl, tl->t); - vsb_printf(tl->sb, - " only '=' is legal for backend\n"); - vcc_ErrWhere(tl, tl->t); - return; - default: - vsb_printf(tl->sb, - "Assignments not possible for '%s'\n", vp->name); - vcc_ErrWhere(tl, tl->t); - return; - } - return; - default: - vsb_printf(tl->sb, "Expected action, 'if' or '}'\n"); - vcc_ErrWhere(tl, at); - return; - } -} - -/*--------------------------------------------------------------------*/ - -static void -Compound(struct tokenlist *tl) -{ - - ExpectErr(tl, '{'); - Fc(tl, 1, "{\n"); - tl->indent += INDENT; - C(tl, ";"); - vcc_NextToken(tl); - while (1) { - ERRCHK(tl); - switch (tl->t->tok) { - case '{': - Compound(tl); - break; - case T_IF: - IfStmt(tl); - break; - case '}': - vcc_NextToken(tl); - tl->indent -= INDENT; - Fc(tl, 1, "}\n"); - return; - case EOI: - vsb_printf(tl->sb, - "End of input while in compound statement\n"); - tl->err = 1; - return; - default: - Action(tl); - ERRCHK(tl); - ExpectErr(tl, ';'); - vcc_NextToken(tl); - break; - } - } -} - -/*--------------------------------------------------------------------*/ - -static const char * -CheckHostPort(const char *host, const char *port) -{ - struct addrinfo *res, hint; - int error; - - memset(&hint, 0, sizeof hint); - hint.ai_family = PF_UNSPEC; - hint.ai_socktype = SOCK_STREAM; - error = getaddrinfo(host, port, &hint, &res); - if (error) - return (gai_strerror(error)); - freeaddrinfo(res); - return (NULL); -} - -static void -Backend(struct tokenlist *tl) -{ - unsigned a; - struct var *vp; - struct token *t_be = NULL; - struct token *t_host = NULL; - struct token *t_port = NULL; - const char *ep; - - vcc_NextToken(tl); - ExpectErr(tl, ID); - t_be = tl->t; - AddDef(tl, tl->t, R_BACKEND); - if (tl->nbackend == 0) - AddRef(tl, tl->t, R_BACKEND); - Fh(tl, 1, "#define VGC_backend_%.*s (VCL_conf.backend[%d])\n", - PF(tl->t), tl->nbackend); - Fc(tl, 0, "\n"); - Fc(tl, 0, "static void\n"); - Fc(tl, 1, "VGC_init_backend_%.*s (void)\n", PF(tl->t)); - Fc(tl, 1, "{\n"); - Fc(tl, 1, "\tstruct backend *backend = VGC_backend_%.*s;\n", PF(tl->t)); - Fc(tl, 1, "\n"); - Fc(tl, 1, "\tVRT_set_backend_name(backend, \"%.*s\");\n", PF(tl->t)); - vcc_NextToken(tl); - ExpectErr(tl, '{'); - vcc_NextToken(tl); - while (1) { - if (tl->t->tok == '}') - break; - ExpectErr(tl, T_SET); - vcc_NextToken(tl); - ExpectErr(tl, VAR); - vp = FindVar(tl, tl->t, vcc_be_vars); - ERRCHK(tl); - assert(vp != NULL); - vcc_NextToken(tl); - ExpectErr(tl, '='); - vcc_NextToken(tl); - switch (vp->fmt) { - case HOSTNAME: - ExpectErr(tl, CSTR); - t_host = tl->t; - Fc(tl, 1, "\t%s ", vp->lname); - EncToken(tl->fc, t_host); - Fc(tl, 0, ");\n"); - vcc_NextToken(tl); - break; - case PORTNAME: - ExpectErr(tl, CSTR); - t_port = tl->t; - Fc(tl, 1, "\t%s ", vp->lname); - EncToken(tl->fc, t_port); - Fc(tl, 0, ");\n"); - vcc_NextToken(tl); - break; -#if 0 - case INT: - case SIZE: - case RATE: - case FLOAT: -#endif - case TIME: - Fc(tl, 1, "\t%s ", vp->lname); - a = tl->t->tok; - if (a == T_MUL || a == T_DIV) - Fc(tl, 0, "%g", DoubleVal(tl)); - else if (vp->fmt == TIME) - TimeVal(tl); - else if (vp->fmt == SIZE) - SizeVal(tl); - else if (vp->fmt == RATE) - RateVal(tl); - else - Fc(tl, 0, "%g", DoubleVal(tl)); - Fc(tl, 0, ");\n"); - break; - default: - vsb_printf(tl->sb, - "Assignments not possible for '%s'\n", vp->name); - vcc_ErrWhere(tl, tl->t); - return; - } - ExpectErr(tl, ';'); - vcc_NextToken(tl); - } - ExpectErr(tl, '}'); - if (t_host == NULL) { - vsb_printf(tl->sb, "Backend '%.*s' has no hostname\n", - PF(t_be)); - vcc_ErrWhere(tl, tl->t); - return; - } - ep = CheckHostPort(t_host->dec, "80"); - if (ep != NULL) { - vsb_printf(tl->sb, "Backend '%.*s': %s\n", PF(t_be), ep); - vcc_ErrWhere(tl, t_host); - return; - } - if (t_port != NULL) { - ep = CheckHostPort(t_host->dec, t_port->dec); - if (ep != NULL) { - vsb_printf(tl->sb, - "Backend '%.*s': %s\n", PF(t_be), ep); - vcc_ErrWhere(tl, t_port); - return; - } - } - - vcc_NextToken(tl); - Fc(tl, 1, "}\n"); - Fc(tl, 0, "\n"); - Fi(tl, 0, "\tVGC_init_backend_%.*s();\n", PF(t_be)); - Ff(tl, 0, "\tVRT_fini_backend(VGC_backend_%.*s);\n", PF(t_be)); - tl->nbackend++; -} - -/*--------------------------------------------------------------------*/ - -static void -Function(struct tokenlist *tl) -{ - struct token *tn; - - vcc_NextToken(tl); - ExpectErr(tl, ID); - tl->curproc = AddProc(tl, tl->t, 1); - tl->curproc->exists++; - tn = tl->t; - AddDef(tl, tl->t, R_FUNC); - Fh(tl, 0, "static int VGC_function_%.*s (struct sess *sp);\n", - PF(tl->t)); - Fc(tl, 1, "static int\n"); - Fc(tl, 1, "VGC_function_%.*s (struct sess *sp)\n", PF(tl->t)); - vcc_NextToken(tl); - tl->indent += INDENT; - Fc(tl, 1, "{\n"); - L(tl, Compound(tl)); - if (IsMethod(tn) == 1) { - Fc(tl, 1, "VGC_function_default_%.*s(sp);\n", PF(tn)); - } - Fc(tl, 1, "}\n"); - tl->indent -= INDENT; - Fc(tl, 0, "\n"); -} - -/*-------------------------------------------------------------------- - * Top level of parser, recognize: - * Function definitions - * Backend definitions - * End of input - */ - -static void -Parse(struct tokenlist *tl) -{ - - while (tl->t->tok != EOI) { - ERRCHK(tl); - switch (tl->t->tok) { - case T_ACL: - vcc_Acl(tl); - break; - case T_SUB: - Function(tl); - break; - case T_BACKEND: - Backend(tl); - break; - case EOI: - break; - default: - vsb_printf(tl->sb, - "Expected 'acl', 'sub' or 'backend', found "); - vcc_ErrToken(tl, tl->t); - vsb_printf(tl->sb, " at\n"); - vcc_ErrWhere(tl, tl->t); - return; - } - } -} - /*-------------------------------------------------------------------- * Consistency check */ -static struct proc * +struct proc * AddProc(struct tokenlist *tl, struct token *t, int def) { struct proc *p; @@ -1155,7 +337,7 @@ AddProc(struct tokenlist *tl, struct token *t, int def) return (p); } -static void +void AddCall(struct tokenlist *tl, struct token *t) { struct proccall *pc; @@ -1545,18 +727,23 @@ vcc_CompileSource(struct vsb *sb, struct source *sp) tl->nsources = 0; + /* General C code */ tl->fc = vsb_new(NULL, NULL, 0, VSB_AUTOEXTEND); assert(tl->fc != NULL); + /* Forward decls (.h like) */ tl->fh = vsb_new(NULL, NULL, 0, VSB_AUTOEXTEND); assert(tl->fh != NULL); + /* Init C code */ tl->fi = vsb_new(NULL, NULL, 0, VSB_AUTOEXTEND); assert(tl->fi != NULL); + /* Finish C code */ tl->ff = vsb_new(NULL, NULL, 0, VSB_AUTOEXTEND); assert(tl->ff != NULL); + /* body code of methods */ #define VCL_MET_MAC(l,U,m) \ tl->fm_##l = vsb_new(NULL, NULL, 0, VSB_AUTOEXTEND); \ assert(tl->fm_##l != NULL); @@ -1586,7 +773,7 @@ vcc_CompileSource(struct vsb *sb, struct source *sp) goto done; tl->t = TAILQ_FIRST(&tl->tokens); - Parse(tl); + vcc_Parse(tl); if (tl->err) goto done; Consistency(tl); diff --git a/varnish-cache/lib/libvcl/vcc_compile.h b/varnish-cache/lib/libvcl/vcc_compile.h index bd4b507c..187dee6c 100644 --- a/varnish-cache/lib/libvcl/vcc_compile.h +++ b/varnish-cache/lib/libvcl/vcc_compile.h @@ -155,13 +155,17 @@ void AddDef(struct tokenlist *tl, struct token *t, enum ref_type type); void AddRef(struct tokenlist *tl, struct token *t, enum ref_type type); void EncToken(struct vsb *sb, struct token *t); void EncString(struct vsb *sb, const char *b, const char *e); - +struct var *FindVar(struct tokenlist *tl, struct token *t, struct var *vl); +void AddCall(struct tokenlist *tl, struct token *t); +struct proc *AddProc(struct tokenlist *tl, struct token *t, int def); /* vcc_obj.c */ extern struct var vcc_be_vars[]; extern struct var vcc_vars[]; extern const char *vrt_obj_h; +/* vcc_parse.c */ +void vcc_Parse(struct tokenlist *tl); /* vcc_token.c */ void vcc_ErrToken(struct tokenlist *tl, struct token *t); diff --git a/varnish-cache/lib/libvcl/vcc_parse.c b/varnish-cache/lib/libvcl/vcc_parse.c new file mode 100644 index 00000000..53f18b00 --- /dev/null +++ b/varnish-cache/lib/libvcl/vcc_parse.c @@ -0,0 +1,914 @@ +/*- + * Copyright (c) 2006 Verdens Gang AS + * Copyright (c) 2006 Linpro AS + * All rights reserved. + * + * Author: Poul-Henning Kamp + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id$ + */ + +/* + * XXX: + * generate interface structure + * + * XXX: + * Better error messages, throughout. + * >It also accured to me that we could link the errors to the error + * >documentation. + * > + * >Unreferenced function 'request_policy', first mention is + * > Line 8 Pos 4 + * > sub request_policy { + * > ----##############-- + * >Read more about this type of error: + * >http://varnish/doc/error.html#Unreferenced%20function + * > + * > + * > Unknown variable 'obj.bandwidth' + * > At: Line 88 Pos 12 + * > if (obj.bandwidth < 1 kb/h) { + * > ------------#############------------ + * >Read more about this type of error: + * >http://varnish/doc/error.html#Unknown%20variable + * + * XXX: + * Create proper tmp filenames for .h, .c and .o + * + * XXX: + * and all the rest... + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "compat/asprintf.h" +#include "vsb.h" + +#include "vcc_priv.h" +#include "vcc_compile.h" + +#include "vrt.h" +#include "libvcl.h" + +static struct method method_tab[] = { +#define VCL_RET_MAC(l,U,b,n) +#define VCL_MET_MAC(l,U,m) { "vcl_"#l, "default_vcl_"#l, m }, +#include "vcl_returns.h" +#undef VCL_MET_MAC +#undef VCL_RET_MAC + { NULL, 0U } +}; + +/*--------------------------------------------------------------------*/ + +static void Compound(struct tokenlist *tl); +static void Cond_0(struct tokenlist *tl); +const char *vcc_default_vcl_b, *vcc_default_vcl_e; + +/*--------------------------------------------------------------------*/ + +#define L(tl, foo) do { \ + tl->indent += INDENT; \ + foo; \ + tl->indent -= INDENT; \ +} while (0) + +#define C(tl, sep) do { \ + Fc(tl, 1, "VRT_count(sp, %u)%s\n", ++tl->cnt, sep); \ + tl->t->cnt = tl->cnt; \ +} while (0) + +/*--------------------------------------------------------------------*/ + +static int +IsMethod(struct token *t) +{ + struct method *m; + + for(m = method_tab; m->name != NULL; m++) { + if (vcc_IdIs(t, m->defname)) + return (2); + if (vcc_IdIs(t, m->name)) + return (1); + } + return (0); +} + +/*-------------------------------------------------------------------- + * Recognize and convert units of time, return seconds. + */ + +static double +TimeUnit(struct tokenlist *tl) +{ + double sc = 1.0; + + assert(tl->t->tok == ID); + if (vcc_IdIs(tl->t, "ms")) + sc = 1e-3; + else if (vcc_IdIs(tl->t, "s")) + sc = 1.0; + else if (vcc_IdIs(tl->t, "m")) + sc = 60.0; + else if (vcc_IdIs(tl->t, "h")) + sc = 60.0 * 60.0; + else if (vcc_IdIs(tl->t, "d")) + sc = 60.0 * 60.0 * 24.0; + else { + vsb_printf(tl->sb, "Unknown time unit "); + vcc_ErrToken(tl, tl->t); + vsb_printf(tl->sb, ". Legal are 's', 'm', 'h' and 'd'\n"); + vcc_ErrWhere(tl, tl->t); + return (1.0); + } + vcc_NextToken(tl); + return (sc); +} + +/*-------------------------------------------------------------------- + * Recognize and convert units of size, return bytes. + */ + +static double +SizeUnit(struct tokenlist *tl) +{ + double sc = 1.0; + + assert(tl->t->tok == ID); + if (vcc_IdIs(tl->t, "b")) + sc = 1.0; + else if (vcc_IdIs(tl->t, "kb")) + sc = 1024.0; + else if (vcc_IdIs(tl->t, "mb") || vcc_IdIs(tl->t, "Mb")) + sc = 1024.0 * 1024.0; + else if (vcc_IdIs(tl->t, "gb") || vcc_IdIs(tl->t, "Gb")) + sc = 1024.0 * 1024.0 * 1024.0; + else { + vsb_printf(tl->sb, "Unknown size unit "); + vcc_ErrToken(tl, tl->t); + vsb_printf(tl->sb, ". Legal are 'kb', 'mb' and 'gb'\n"); + vcc_ErrWhere(tl, tl->t); + return (1.0); + } + vcc_NextToken(tl); + return (sc); +} + +/*-------------------------------------------------------------------- + * Recognize and convert units of rate as { space '/' time } + */ + +static double +RateUnit(struct tokenlist *tl) +{ + double sc = 1.0; + + assert(tl->t->tok == ID); + sc = SizeUnit(tl); + Expect(tl, '/'); + vcc_NextToken(tl); + sc /= TimeUnit(tl); + return (sc); +} + +/*-------------------------------------------------------------------- + * Recognize and convert { CNUM } to unsigned value + */ + +unsigned +UintVal(struct tokenlist *tl) +{ + unsigned d = 0; + const char *p; + + Expect(tl, CNUM); + for (p = tl->t->b; p < tl->t->e; p++) { + d *= 10; + d += *p - '0'; + } + vcc_NextToken(tl); + return (d); +} + +/*-------------------------------------------------------------------- + * Recognize and convert { CNUM [ '.' [ CNUM ] ] } to double value + */ + +static double +DoubleVal(struct tokenlist *tl) +{ + double d = 0.0, e = 0.1; + const char *p; + + Expect(tl, CNUM); + for (p = tl->t->b; p < tl->t->e; p++) { + d *= 10; + d += *p - '0'; + } + vcc_NextToken(tl); + if (tl->t->tok != '.') + return (d); + vcc_NextToken(tl); + if (tl->t->tok != CNUM) + return (d); + for (p = tl->t->b; p < tl->t->e; p++) { + d += (*p - '0') * e; + e *= 0.1; + } + vcc_NextToken(tl); + return (d); +} + +/*--------------------------------------------------------------------*/ + +static void +TimeVal(struct tokenlist *tl) +{ + double v, sc; + + v = DoubleVal(tl); + ExpectErr(tl, ID); + sc = TimeUnit(tl); + Fc(tl, 0, "(%g * %g)", v, sc); +} + +static void +SizeVal(struct tokenlist *tl) +{ + double v, sc; + + v = DoubleVal(tl); + ExpectErr(tl, ID); + sc = SizeUnit(tl); + Fc(tl, 0, "(%g * %g)", v, sc); +} + +static void +RateVal(struct tokenlist *tl) +{ + double v, sc; + + v = DoubleVal(tl); + ExpectErr(tl, ID); + sc = RateUnit(tl); + Fc(tl, 0, "(%g * %g)", v, sc); +} + +/*--------------------------------------------------------------------*/ + +static void +vcc_re(struct tokenlist *tl, const char *str, struct token *re) +{ + char buf[32]; + + assert(re->tok == CSTR); + if (VRT_re_test(tl->sb, re->dec)) { + vcc_ErrWhere(tl, re); + return; + } + sprintf(buf, "VGC_re_%u", tl->recnt++); + + Fc(tl, 1, "VRT_re_match(%s, %s)\n", str, buf); + Fh(tl, 0, "void *%s;\n", buf); + Fi(tl, 0, "\tVRT_re_init(&%s, ",buf); + EncToken(tl->fi, re); + Fi(tl, 0, ");\n"); + Ff(tl, 0, "\tVRT_re_fini(%s);\n", buf); +} + + +/*--------------------------------------------------------------------*/ + +static void +Cond_String(struct var *vp, struct tokenlist *tl) +{ + + switch (tl->t->tok) { + case '~': + vcc_NextToken(tl); + ExpectErr(tl, CSTR); + vcc_re(tl, vp->rname, tl->t); + vcc_NextToken(tl); + break; + case T_EQ: + case T_NEQ: + Fc(tl, 1, "%sstrcmp(%s, ", + tl->t->tok == T_EQ ? "!" : "", vp->rname); + vcc_NextToken(tl); + ExpectErr(tl, CSTR); + EncToken(tl->fc, tl->t); + Fc(tl, 0, ")\n"); + vcc_NextToken(tl); + break; + default: + Fc(tl, 1, "%s != (void*)0", vp->rname); + break; + } +} + +static void +Cond_Int(struct var *vp, struct tokenlist *tl) +{ + + Fc(tl, 1, "%s ", vp->rname); + switch (tl->t->tok) { + case T_EQ: + case T_NEQ: + case T_LEQ: + case T_GEQ: + case '>': + case '<': + Fc(tl, 0, "%.*s ", PF(tl->t)); + vcc_NextToken(tl); + switch(vp->fmt) { + case TIME: + TimeVal(tl); + break; + case INT: + ExpectErr(tl, CNUM); + Fc(tl, 0, "%.*s ", PF(tl->t)); + vcc_NextToken(tl); + break; + case SIZE: + SizeVal(tl); + break; + default: + vsb_printf(tl->sb, + "No conditions available for variable '%s'\n", + vp->name); + vcc_ErrWhere(tl, tl->t); + return; + } + Fc(tl, 0, "\n"); + break; + default: + vsb_printf(tl->sb, "Illegal condition "); + vcc_ErrToken(tl, tl->t); + vsb_printf(tl->sb, " on integer variable\n"); + vsb_printf(tl->sb, + " only '==', '!=', '<', '>', '<=' and '>=' are legal\n"); + vcc_ErrWhere(tl, tl->t); + break; + } +} + +static void +Cond_Bool(struct var *vp, struct tokenlist *tl) +{ + + Fc(tl, 1, "%s\n", vp->rname); +} + +static void +Cond_Backend(struct var *vp, struct tokenlist *tl) +{ + + Fc(tl, 1, "%s\n", vp->rname); +} + +static void +Cond_2(struct tokenlist *tl) +{ + struct var *vp; + + C(tl, ","); + if (tl->t->tok == '!') { + Fc(tl, 1, "!(\n"); + vcc_NextToken(tl); + } else { + Fc(tl, 1, "(\n"); + } + if (tl->t->tok == '(') { + vcc_NextToken(tl); + Cond_0(tl); + ExpectErr(tl, ')'); + vcc_NextToken(tl); + } else if (tl->t->tok == VAR) { + vp = FindVar(tl, tl->t, vcc_vars); + ERRCHK(tl); + assert(vp != NULL); + vcc_NextToken(tl); + switch (vp->fmt) { + case INT: L(tl, Cond_Int(vp, tl)); break; + case SIZE: L(tl, Cond_Int(vp, tl)); break; + case BOOL: L(tl, Cond_Bool(vp, tl)); break; + case IP: L(tl, vcc_Cond_Ip(vp, tl)); break; + case STRING: L(tl, Cond_String(vp, tl)); break; + case TIME: L(tl, Cond_Int(vp, tl)); break; + case BACKEND: L(tl, Cond_Backend(vp, tl)); break; + default: + vsb_printf(tl->sb, + "Variable '%s'" + " has no conditions that can be checked\n", + vp->name); + vcc_ErrWhere(tl, tl->t); + return; + } + } else { + vsb_printf(tl->sb, + "Syntax error in condition, expected '(', '!' or" + " variable name, found "); + vcc_ErrToken(tl, tl->t); + vsb_printf(tl->sb, "\n"); + vcc_ErrWhere(tl, tl->t); + return; + } + Fc(tl, 1, ")\n"); +} + +static void +Cond_1(struct tokenlist *tl) +{ + + Fc(tl, 1, "(\n"); + L(tl, Cond_2(tl)); + while (tl->t->tok == T_CAND) { + vcc_NextToken(tl); + Fc(tl, 1, ") && (\n"); + L(tl, Cond_2(tl)); + } + Fc(tl, 1, ")\n"); +} + +static void +Cond_0(struct tokenlist *tl) +{ + + Fc(tl, 1, "(\n"); + L(tl, Cond_1(tl)); + while (tl->t->tok == T_COR) { + vcc_NextToken(tl); + Fc(tl, 1, ") || (\n"); + L(tl, Cond_1(tl)); + } + Fc(tl, 1, ")\n"); +} + +static void +Conditional(struct tokenlist *tl) +{ + + ExpectErr(tl, '('); + vcc_NextToken(tl); + Fc(tl, 1, "(\n"); + L(tl, Cond_0(tl)); + ERRCHK(tl); + Fc(tl, 1, ")\n"); + ExpectErr(tl, ')'); + vcc_NextToken(tl); +} + +/*--------------------------------------------------------------------*/ + +static void +IfStmt(struct tokenlist *tl) +{ + + ExpectErr(tl, T_IF); + Fc(tl, 1, "if \n"); + vcc_NextToken(tl); + L(tl, Conditional(tl)); + ERRCHK(tl); + L(tl, Compound(tl)); + ERRCHK(tl); + while (1) { + switch (tl->t->tok) { + case T_ELSE: + vcc_NextToken(tl); + if (tl->t->tok != T_IF) { + Fc(tl, 1, "else \n"); + L(tl, Compound(tl)); + ERRCHK(tl); + return; + } + /* FALLTHROUGH */ + case T_ELSEIF: + case T_ELSIF: + Fc(tl, 1, "else if \n"); + vcc_NextToken(tl); + L(tl, Conditional(tl)); + ERRCHK(tl); + L(tl, Compound(tl)); + ERRCHK(tl); + break; + default: + C(tl, ";"); + return; + } + } +} + +/*--------------------------------------------------------------------*/ + +static void +Action(struct tokenlist *tl) +{ + unsigned a; + struct var *vp; + struct token *at; + + at = tl->t; + vcc_NextToken(tl); + switch (at->tok) { + case T_NO_NEW_CACHE: + Fc(tl, 1, "VCL_no_new_cache(sp);\n"); + return; + case T_NO_CACHE: + Fc(tl, 1, "VCL_no_cache(sp);\n"); + return; +#define VCL_RET_MAC(a,b,c,d) case T_##b: \ + Fc(tl, 1, "VRT_done(sp, VCL_RET_%s);\n", #b); \ + tl->curproc->returns |= VCL_RET_##b; \ + tl->curproc->returnt[d] = at; \ + return; +#include "vcl_returns.h" +#undef VCL_RET_MAC + case T_ERROR: + if (tl->t->tok == CNUM) + a = UintVal(tl); + else + a = 0; + Fc(tl, 1, "VRT_error(sp, %u", a); + if (tl->t->tok == CSTR) { + Fc(tl, 0, ", %.*s", PF(tl->t)); + vcc_NextToken(tl); + } else { + Fc(tl, 0, ", (const char *)0"); + } + Fc(tl, 0, ");\n"); + Fc(tl, 1, "VRT_done(sp, VCL_RET_ERROR);\n"); + return; + case T_SWITCH_CONFIG: + ExpectErr(tl, ID); + Fc(tl, 1, "VCL_switch_config(\"%.*s\");\n", PF(tl->t)); + vcc_NextToken(tl); + return; + case T_CALL: + ExpectErr(tl, ID); + AddCall(tl, tl->t); + AddRef(tl, tl->t, R_FUNC); + Fc(tl, 1, "if (VGC_function_%.*s(sp))\n", PF(tl->t)); + Fc(tl, 1, "\treturn (1);\n"); + vcc_NextToken(tl); + return; + case T_REWRITE: + ExpectErr(tl, CSTR); + Fc(tl, 1, "VCL_rewrite(%.*s", PF(tl->t)); + vcc_NextToken(tl); + ExpectErr(tl, CSTR); + Fc(tl, 0, ", %.*s);\n", PF(tl->t)); + vcc_NextToken(tl); + return; + case T_SET: + ExpectErr(tl, VAR); + vp = FindVar(tl, tl->t, vcc_vars); + ERRCHK(tl); + assert(vp != NULL); + Fc(tl, 1, "%s", vp->lname); + vcc_NextToken(tl); + switch (vp->fmt) { + case INT: + case SIZE: + case RATE: + case TIME: + case FLOAT: + if (tl->t->tok != '=') + Fc(tl, 0, "%s %c ", vp->rname, *tl->t->b); + a = tl->t->tok; + vcc_NextToken(tl); + if (a == T_MUL || a == T_DIV) + Fc(tl, 0, "%g", DoubleVal(tl)); + else if (vp->fmt == TIME) + TimeVal(tl); + else if (vp->fmt == SIZE) + SizeVal(tl); + else if (vp->fmt == RATE) + RateVal(tl); + else + Fc(tl, 0, "%g", DoubleVal(tl)); + Fc(tl, 0, ");\n"); + break; +#if 0 /* XXX: enable if we find a legit use */ + case IP: + if (tl->t->tok == '=') { + vcc_NextToken(tl); + u = vcc_IpVal(tl); + Fc(tl, 0, "= %uU; /* %u.%u.%u.%u */\n", + u, + (u >> 24) & 0xff, + (u >> 16) & 0xff, + (u >> 8) & 0xff, + u & 0xff); + break; + } + vsb_printf(tl->sb, "Illegal assignment operator "); + vcc_ErrToken(tl, tl->t); + vsb_printf(tl->sb, + " only '=' is legal for IP numbers\n"); + vcc_ErrWhere(tl, tl->t); + return; +#endif + case BACKEND: + if (tl->t->tok == '=') { + vcc_NextToken(tl); + AddRef(tl, tl->t, R_BACKEND); + Fc(tl, 0, "VGC_backend_%.*s", PF(tl->t)); + vcc_NextToken(tl); + Fc(tl, 0, ");\n"); + break; + } + vsb_printf(tl->sb, "Illegal assignment operator "); + vcc_ErrToken(tl, tl->t); + vsb_printf(tl->sb, + " only '=' is legal for backend\n"); + vcc_ErrWhere(tl, tl->t); + return; + default: + vsb_printf(tl->sb, + "Assignments not possible for '%s'\n", vp->name); + vcc_ErrWhere(tl, tl->t); + return; + } + return; + default: + vsb_printf(tl->sb, "Expected action, 'if' or '}'\n"); + vcc_ErrWhere(tl, at); + return; + } +} + +/*--------------------------------------------------------------------*/ + +static void +Compound(struct tokenlist *tl) +{ + + ExpectErr(tl, '{'); + Fc(tl, 1, "{\n"); + tl->indent += INDENT; + C(tl, ";"); + vcc_NextToken(tl); + while (1) { + ERRCHK(tl); + switch (tl->t->tok) { + case '{': + Compound(tl); + break; + case T_IF: + IfStmt(tl); + break; + case '}': + vcc_NextToken(tl); + tl->indent -= INDENT; + Fc(tl, 1, "}\n"); + return; + case EOI: + vsb_printf(tl->sb, + "End of input while in compound statement\n"); + tl->err = 1; + return; + default: + Action(tl); + ERRCHK(tl); + ExpectErr(tl, ';'); + vcc_NextToken(tl); + break; + } + } +} + +/*--------------------------------------------------------------------*/ + +static const char * +CheckHostPort(const char *host, const char *port) +{ + struct addrinfo *res, hint; + int error; + + memset(&hint, 0, sizeof hint); + hint.ai_family = PF_UNSPEC; + hint.ai_socktype = SOCK_STREAM; + error = getaddrinfo(host, port, &hint, &res); + if (error) + return (gai_strerror(error)); + freeaddrinfo(res); + return (NULL); +} + +static void +Backend(struct tokenlist *tl) +{ + unsigned a; + struct var *vp; + struct token *t_be = NULL; + struct token *t_host = NULL; + struct token *t_port = NULL; + const char *ep; + + vcc_NextToken(tl); + ExpectErr(tl, ID); + t_be = tl->t; + AddDef(tl, tl->t, R_BACKEND); + if (tl->nbackend == 0) + AddRef(tl, tl->t, R_BACKEND); + Fh(tl, 1, "#define VGC_backend_%.*s (VCL_conf.backend[%d])\n", + PF(tl->t), tl->nbackend); + Fc(tl, 0, "\n"); + Fc(tl, 0, "static void\n"); + Fc(tl, 1, "VGC_init_backend_%.*s (void)\n", PF(tl->t)); + Fc(tl, 1, "{\n"); + Fc(tl, 1, "\tstruct backend *backend = VGC_backend_%.*s;\n", PF(tl->t)); + Fc(tl, 1, "\n"); + Fc(tl, 1, "\tVRT_set_backend_name(backend, \"%.*s\");\n", PF(tl->t)); + vcc_NextToken(tl); + ExpectErr(tl, '{'); + vcc_NextToken(tl); + while (1) { + if (tl->t->tok == '}') + break; + ExpectErr(tl, T_SET); + vcc_NextToken(tl); + ExpectErr(tl, VAR); + vp = FindVar(tl, tl->t, vcc_be_vars); + ERRCHK(tl); + assert(vp != NULL); + vcc_NextToken(tl); + ExpectErr(tl, '='); + vcc_NextToken(tl); + switch (vp->fmt) { + case HOSTNAME: + ExpectErr(tl, CSTR); + t_host = tl->t; + Fc(tl, 1, "\t%s ", vp->lname); + EncToken(tl->fc, t_host); + Fc(tl, 0, ");\n"); + vcc_NextToken(tl); + break; + case PORTNAME: + ExpectErr(tl, CSTR); + t_port = tl->t; + Fc(tl, 1, "\t%s ", vp->lname); + EncToken(tl->fc, t_port); + Fc(tl, 0, ");\n"); + vcc_NextToken(tl); + break; +#if 0 + case INT: + case SIZE: + case RATE: + case FLOAT: +#endif + case TIME: + Fc(tl, 1, "\t%s ", vp->lname); + a = tl->t->tok; + if (a == T_MUL || a == T_DIV) + Fc(tl, 0, "%g", DoubleVal(tl)); + else if (vp->fmt == TIME) + TimeVal(tl); + else if (vp->fmt == SIZE) + SizeVal(tl); + else if (vp->fmt == RATE) + RateVal(tl); + else + Fc(tl, 0, "%g", DoubleVal(tl)); + Fc(tl, 0, ");\n"); + break; + default: + vsb_printf(tl->sb, + "Assignments not possible for '%s'\n", vp->name); + vcc_ErrWhere(tl, tl->t); + return; + } + ExpectErr(tl, ';'); + vcc_NextToken(tl); + } + ExpectErr(tl, '}'); + if (t_host == NULL) { + vsb_printf(tl->sb, "Backend '%.*s' has no hostname\n", + PF(t_be)); + vcc_ErrWhere(tl, tl->t); + return; + } + ep = CheckHostPort(t_host->dec, "80"); + if (ep != NULL) { + vsb_printf(tl->sb, "Backend '%.*s': %s\n", PF(t_be), ep); + vcc_ErrWhere(tl, t_host); + return; + } + if (t_port != NULL) { + ep = CheckHostPort(t_host->dec, t_port->dec); + if (ep != NULL) { + vsb_printf(tl->sb, + "Backend '%.*s': %s\n", PF(t_be), ep); + vcc_ErrWhere(tl, t_port); + return; + } + } + + vcc_NextToken(tl); + Fc(tl, 1, "}\n"); + Fc(tl, 0, "\n"); + Fi(tl, 0, "\tVGC_init_backend_%.*s();\n", PF(t_be)); + Ff(tl, 0, "\tVRT_fini_backend(VGC_backend_%.*s);\n", PF(t_be)); + tl->nbackend++; +} + +/*--------------------------------------------------------------------*/ + +static void +Function(struct tokenlist *tl) +{ + struct token *tn; + + vcc_NextToken(tl); + ExpectErr(tl, ID); + tl->curproc = AddProc(tl, tl->t, 1); + tl->curproc->exists++; + tn = tl->t; + AddDef(tl, tl->t, R_FUNC); + Fh(tl, 0, "static int VGC_function_%.*s (struct sess *sp);\n", + PF(tl->t)); + Fc(tl, 1, "static int\n"); + Fc(tl, 1, "VGC_function_%.*s (struct sess *sp)\n", PF(tl->t)); + vcc_NextToken(tl); + tl->indent += INDENT; + Fc(tl, 1, "{\n"); + L(tl, Compound(tl)); + if (IsMethod(tn) == 1) { + Fc(tl, 1, "VGC_function_default_%.*s(sp);\n", PF(tn)); + } + Fc(tl, 1, "}\n"); + tl->indent -= INDENT; + Fc(tl, 0, "\n"); +} + +/*-------------------------------------------------------------------- + * Top level of parser, recognize: + * Function definitions + * Backend definitions + * End of input + */ + +void +vcc_Parse(struct tokenlist *tl) +{ + + while (tl->t->tok != EOI) { + ERRCHK(tl); + switch (tl->t->tok) { + case T_ACL: + vcc_Acl(tl); + break; + case T_SUB: + Function(tl); + break; + case T_BACKEND: + Backend(tl); + break; + case EOI: + break; + default: + vsb_printf(tl->sb, + "Expected 'acl', 'sub' or 'backend', found "); + vcc_ErrToken(tl, tl->t); + vsb_printf(tl->sb, " at\n"); + vcc_ErrWhere(tl, tl->t); + return; + } + } +}