]> err.no Git - varnish/commitdiff
Split off the parsing from vcc_compile.c into vcc_parse.c
authorphk <phk@d4fa192b-c00b-0410-8231-f00ffab90ce4>
Sat, 24 Mar 2007 21:01:43 +0000 (21:01 +0000)
committerphk <phk@d4fa192b-c00b-0410-8231-f00ffab90ce4>
Sat, 24 Mar 2007 21:01:43 +0000 (21:01 +0000)
git-svn-id: svn+ssh://projects.linpro.no/svn/varnish/trunk@1283 d4fa192b-c00b-0410-8231-f00ffab90ce4

varnish-cache/lib/libvcl/Makefile.am
varnish-cache/lib/libvcl/vcc_compile.c
varnish-cache/lib/libvcl/vcc_compile.h
varnish-cache/lib/libvcl/vcc_parse.c [new file with mode: 0644]

index 52c772946859ad1b52f79011368592469da14cf3..a8184b6a518fd0d754dd155953dfcffecf6b1bd6 100644 (file)
@@ -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
index 180e984c85e35720b06dfb2ba7ff136251f62bff..4d9c6b217c2c179f954dd40ef7b153dd7537842f 100644 (file)
@@ -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);
index bd4b507c8cfeb90da9d44ef3de8451b472647b7d..187dee6c03c39259b238c184d60f460b2ac0cb03 100644 (file)
@@ -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 (file)
index 0000000..53f18b0
--- /dev/null
@@ -0,0 +1,914 @@
+/*-
+ * Copyright (c) 2006 Verdens Gang AS
+ * Copyright (c) 2006 Linpro AS
+ * All rights reserved.
+ *
+ * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
+ *
+ * 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 <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <queue.h>
+#include <unistd.h>
+
+#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;
+               }
+       }
+}