/*--------------------------------------------------------------------*/
-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
*/
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
*/
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 *
/*--------------------------------------------------------------------*/
-static struct var *
+struct var *
FindVar(struct tokenlist *tl, struct token *t, struct var *vl)
{
struct var *v;
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;
return (p);
}
-static void
+void
AddCall(struct tokenlist *tl, struct token *t)
{
struct proccall *pc;
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);
goto done;
tl->t = TAILQ_FIRST(&tl->tokens);
- Parse(tl);
+ vcc_Parse(tl);
if (tl->err)
goto done;
Consistency(tl);
--- /dev/null
+/*-
+ * 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;
+ }
+ }
+}