r544 - trunk/varnish-cache/lib/libvcl

phk at projects.linpro.no phk at projects.linpro.no
Fri Jul 21 20:12:59 CEST 2006


Author: phk
Date: 2006-07-21 20:12:56 +0200 (Fri, 21 Jul 2006)
New Revision: 544

Added:
   trunk/varnish-cache/lib/libvcl/vcc_compile.c
   trunk/varnish-cache/lib/libvcl/vcc_compile.h
   trunk/varnish-cache/lib/libvcl/vcc_fixed_token.c
   trunk/varnish-cache/lib/libvcl/vcc_gen_fixed_token.tcl
   trunk/varnish-cache/lib/libvcl/vcc_obj.c
   trunk/varnish-cache/lib/libvcl/vcc_priv.h
   trunk/varnish-cache/lib/libvcl/vcc_token.c
   trunk/varnish-cache/lib/libvcl/vcc_token_defs.h
Removed:
   trunk/varnish-cache/lib/libvcl/vcl_fixed_token.c
   trunk/varnish-cache/lib/libvcl/vcl_gen_fixed_token.tcl
   trunk/varnish-cache/lib/libvcl/vcl_priv.h
   trunk/varnish-cache/lib/libvcl/vcl_token_defs.h
Modified:
   trunk/varnish-cache/lib/libvcl/Makefile.am
Log:
Move things over to the correct "VCC" prefix.

Split some stuff into separate files while we're at it.



Modified: trunk/varnish-cache/lib/libvcl/Makefile.am
===================================================================
--- trunk/varnish-cache/lib/libvcl/Makefile.am	2006-07-21 16:25:24 UTC (rev 543)
+++ trunk/varnish-cache/lib/libvcl/Makefile.am	2006-07-21 18:12:56 UTC (rev 544)
@@ -5,8 +5,11 @@
 lib_LTLIBRARIES = libvcl.la
 
 libvcl_la_SOURCES = \
-	vcl_priv.h \
-	vcl_token_defs.h \
+	vcc_priv.h \
+	vcc_compile.h \
+	vcc_token_defs.h \
 	\
-	vcl_compile.c \
-	vcl_fixed_token.c
+	vcc_compile.c \
+	vcc_fixed_token.c \
+	vcc_obj.c \
+	vcc_token.c

Added: trunk/varnish-cache/lib/libvcl/vcc_compile.c
===================================================================
--- trunk/varnish-cache/lib/libvcl/vcc_compile.c	2006-07-21 16:25:24 UTC (rev 543)
+++ trunk/varnish-cache/lib/libvcl/vcc_compile.c	2006-07-21 18:12:56 UTC (rev 544)
@@ -0,0 +1,1529 @@
+/*
+ * $Id: vcl_compile.c 531 2006-07-20 22:08:43Z phk $
+ */
+
+/*
+ * 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 <printf.h>
+#include <stdarg.h>
+#include <sbuf.h>
+#include <stdlib.h>
+#include <string.h>
+#include <queue.h>
+#include <unistd.h>
+
+#include "vcc_priv.h"
+#include "vcc_compile.h"
+
+#include "libvcl.h"
+
+#define ERRCHK(tl)	do { if ((tl)->err) return; } while (0)
+
+/*--------------------------------------------------------------------*/
+
+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 ErrInternal(tl) vcc__ErrInternal(tl, __func__, __LINE__)
+
+#define Expect(a, b) vcc__Expect(a, b, __LINE__)
+#define ExpectErr(a, b) do { vcc__Expect(a, b, __LINE__); ERRCHK(a);} while (0)
+
+#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 sbufs, possibly indented
+ */
+
+static void
+Fh(struct tokenlist *tl, int indent, const char *fmt, ...)
+{
+	va_list ap;
+
+	if (indent)
+		sbuf_printf(tl->fh, "%*.*s", tl->indent, tl->indent, "");
+	va_start(ap, fmt);
+	sbuf_vprintf(tl->fh, fmt, ap);
+	va_end(ap);
+}
+
+static void
+Fc(struct tokenlist *tl, int indent, const char *fmt, ...)
+{
+	va_list ap;
+
+	if (indent)
+		sbuf_printf(tl->fc, "%*.*s", tl->indent, tl->indent, "");
+	va_start(ap, fmt);
+	sbuf_vprintf(tl->fc, fmt, ap);
+	va_end(ap);
+}
+
+/*--------------------------------------------------------------------*/
+
+static char *
+EncString(struct token *t)
+{
+	char *p, *q;
+	const char *r;
+	unsigned u;
+
+	assert(t->tok == CSTR);
+	p = malloc(t->e - t->b);
+	assert(p != NULL);
+	q = p;
+	for (r = t->b + 1; r < t->e - 1; ) {
+		if (*r != '\\') {
+			*q++ = *r++;
+			continue;
+		}
+		switch (r[1]) {
+		case 'n':	*q++ = '\n';	r += 2; break;
+		case 'r':	*q++ = '\r';	r += 2; break;
+		case 'v':	*q++ = '\v';	r += 2; break;
+		case 'f':	*q++ = '\f';	r += 2; break;
+		case 't':	*q++ = '\t';	r += 2; break;
+		case 'b':	*q++ = '\b';	r += 2; break;
+		case '0': case '1': case '2': case '3':
+		case '4': case '5': case '6': case '7':
+			u = r[1] - '0';
+			r += 2;
+			if (isdigit(r[0]) && (r[0] - '0') < 8) {
+				u <<= 3;
+				u |= r[0] - '0';
+				r++;
+				if (isdigit(r[0]) && (r[0] - '0') < 8) {
+					u <<= 3;
+					u |= r[0] - '0';
+					r++;
+				}
+			}
+			*q++ = u;
+			break;
+		default:
+			*q++ = r[1];	
+			r += 2;
+			break;
+		}
+	}
+	*q = '\0';
+	return (p);
+}
+
+
+/*--------------------------------------------------------------------
+ * Keep track of definitions and references
+ */
+
+static struct ref *
+FindRef(struct tokenlist *tl, struct token *t, enum ref_type type)
+{
+	struct ref *r;
+
+	TAILQ_FOREACH(r, &tl->refs, list) {
+		if (r->type != type)
+			continue;
+		if (vcc_Teq(r->name, t))
+			return (r);
+	}
+	r = calloc(sizeof *r, 1);
+	assert(r != NULL);
+	r->name = t;
+	r->type = type;
+	TAILQ_INSERT_TAIL(&tl->refs, r, list);
+	return (r);
+}
+
+static int
+FindRefStr(struct tokenlist *tl, const char *s, enum ref_type type)
+{
+	struct ref *r;
+
+	TAILQ_FOREACH(r, &tl->refs, list) {
+		if (r->type != type)
+			continue;
+		if (vcc_IdIs(r->name, s))
+			return (1);
+	}
+	return (0);
+}
+
+static void
+AddRef(struct tokenlist *tl, struct token *t, enum ref_type type)
+{
+
+	FindRef(tl, t, type)->refcnt++;
+}
+
+static void
+AddRefStr(struct tokenlist *tl, const char *s, enum ref_type type)
+{
+	struct token *t;
+
+	t = calloc(sizeof *t, 1);
+	t->b = s;
+	t->e = strchr(s, '\0');
+	t->tok = METHOD;
+	AddRef(tl, t, type);
+}
+
+static void
+AddDef(struct tokenlist *tl, struct token *t, enum ref_type type)
+{
+	struct ref *r;
+
+	r = FindRef(tl, t, type);
+	r->defcnt++;
+	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 {
+		sbuf_printf(tl->sb, "Unknown time unit ");
+		vcc_ErrToken(tl, tl->t);
+		sbuf_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 {
+		sbuf_printf(tl->sb, "Unknown size unit ");
+		vcc_ErrToken(tl, tl->t);
+		sbuf_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
+ */
+
+static 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 unsigned
+IpVal(struct tokenlist *tl)
+{
+	unsigned u, v;
+	struct token *t;
+
+	t = tl->t;
+	u = UintVal(tl);
+	if (u < 256) {
+		v = u << 24;
+		Expect(tl, '.');
+		vcc_NextToken(tl);
+		t = tl->t;
+		u = UintVal(tl);
+		if (u < 256) {
+			v |= u << 16;
+			Expect(tl, '.');
+			vcc_NextToken(tl);
+			t = tl->t;
+			u = UintVal(tl);
+			if (u < 256) {
+				v |= u << 8;
+				Expect(tl, '.');
+				vcc_NextToken(tl);
+				t = tl->t;
+				u = UintVal(tl);
+				if (u < 256) {
+					v |= u;
+					return (v);
+				}
+			}
+		}
+	}
+	sbuf_printf(tl->sb, "Illegal octet in IP number\n");
+	vcc_ErrWhere(tl, t);
+	return (0);
+}
+
+/*--------------------------------------------------------------------*/
+
+static struct var *
+HeaderVar(struct tokenlist *tl __unused, struct token *t, struct var *vh)
+{
+	char *p;
+	struct var *v;
+	int i;
+
+	v = calloc(sizeof *v, 1);
+	assert(v != NULL);
+	i = t->e - t->b;
+	p = malloc(i + 1);
+	assert(p != NULL);
+	memcpy(p, t->b, i);
+	p[i] = '\0';
+	v->name = p;
+	v->fmt = STRING;
+	asprintf(&p, "VRT_GetHdr(sp, \"\\%03o%s:\")",
+	    strlen(v->name + vh->len) + 1, v->name + vh->len);
+	assert(p != NULL);
+	v->rname = p;
+	return (v);
+}
+
+/*--------------------------------------------------------------------*/
+
+static struct var *
+FindVar(struct tokenlist *tl, struct token *t, struct var *vl)
+{
+	struct var *v;
+
+	for (v = vl; v->name != NULL; v++) {
+		if (v->fmt == HEADER  && t->e - t->b <= v->len)
+			continue;
+		if (v->fmt != HEADER  && t->e - t->b != v->len)
+			continue;
+		if (memcmp(t->b, v->name, v->len))
+			continue;
+		if (v->fmt != HEADER)
+			return (v);
+		return (HeaderVar(tl, t, v));
+	}
+	sbuf_printf(tl->sb, "Unknown variable ");
+	vcc_ErrToken(tl, t);
+	sbuf_cat(tl->sb, "\nAt: ");
+	vcc_ErrWhere(tl, t);
+	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
+Cond_Ip(struct var *vp, struct tokenlist *tl)
+{
+	unsigned u;
+
+	switch (tl->t->tok) {
+	case '~':
+		vcc_NextToken(tl);
+		ExpectErr(tl, ID);
+		AddRef(tl, tl->t, R_ACL);
+		Fc(tl, 1, "ip_match(%s, acl_%T)\n", vp->rname, tl->t);
+		vcc_NextToken(tl);
+		break;
+	case T_EQ:
+	case T_NEQ:
+		Fc(tl, 1, "%s %T ", vp->rname, tl->t);
+		vcc_NextToken(tl);
+		u = IpVal(tl);
+		Fc(tl, 0, "%uU /* %u.%u.%u.%u */\n", u,
+		    (u >> 24) & 0xff, (u >> 16) & 0xff,
+		    (u >> 8) & 0xff, (u) & 0xff);
+		break;
+	default:
+		sbuf_printf(tl->sb, "Illegal condition ");
+		vcc_ErrToken(tl, tl->t);
+		sbuf_printf(tl->sb, " on IP number variable\n");
+		sbuf_printf(tl->sb, "  only '==', '!=' and '~' are legal\n");
+		vcc_ErrWhere(tl, tl->t);
+		break;
+	}
+}
+
+static void
+Cond_String(struct var *vp, struct tokenlist *tl)
+{
+
+	switch (tl->t->tok) {
+	case '~':
+		Fc(tl, 1, "string_match(%s, ", vp->rname);
+		vcc_NextToken(tl);
+		ExpectErr(tl, CSTR);
+		Fc(tl, 0, "%T)\n", 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);
+		Fc(tl, 0, "%T)\n", tl->t);
+		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, "%T ", tl->t);
+		vcc_NextToken(tl);
+		switch(vp->fmt) {
+		case TIME:
+			TimeVal(tl);
+			break;
+		case INT:
+			ExpectErr(tl, CNUM);
+			Fc(tl, 0, "%T ", tl->t);
+			vcc_NextToken(tl);
+			break;
+		case SIZE:
+			SizeVal(tl);
+			break;
+		default:
+			sbuf_printf(tl->sb,
+			    "No conditions available for variable '%s'\n",
+			    vp->name);
+			vcc_ErrWhere(tl, tl->t);
+			return;
+		}
+		Fc(tl, 0, "\n");
+		break;
+	default:
+		sbuf_printf(tl->sb, "Illegal condition ");
+		vcc_ErrToken(tl, tl->t);
+		sbuf_printf(tl->sb, " on integer variable\n");
+		sbuf_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_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, Cond_Ip(vp, tl)); break;
+		case STRING:	L(tl, Cond_String(vp, tl)); break;
+		case TIME:	L(tl, Cond_Int(vp, tl)); break;
+		/* XXX backend == */
+		default:	
+			sbuf_printf(tl->sb,
+			    "Variable '%s'"
+			    " has no conditions that can be checked\n",
+			    vp->name);
+			vcc_ErrWhere(tl, tl->t);
+			return;
+		}
+	} else {
+		sbuf_printf(tl->sb,
+		    "Syntax error in condition, expected '(', '!' or"
+		    " variable name, found ");
+		vcc_ErrToken(tl, tl->t);
+		sbuf_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, u;
+	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) case T_##b: \
+		Fc(tl, 1, "VRT_done(sp, VCL_RET_%s);\n", #b); \
+		tl->curproc->returns |= VCL_RET_##b; \
+		tl->curproc->returnt[c] = 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, "%T);\n", tl->t);
+			vcc_NextToken(tl);
+		} else
+			Fc(tl, 0, "(const char *)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(\"%T\");\n", 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_%T(sp))\n", tl->t);
+		Fc(tl, 1, "\treturn (1);\n");
+		vcc_NextToken(tl);
+		return;
+	case T_REWRITE:
+		ExpectErr(tl, CSTR);
+		Fc(tl, 1, "VCL_rewrite(%T", tl->t);
+		vcc_NextToken(tl);
+		ExpectErr(tl, CSTR);
+		Fc(tl, 0, ", %T);\n", 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->rname);
+		vcc_NextToken(tl);
+		switch (vp->fmt) {
+		case INT:
+		case SIZE:
+		case RATE:
+		case TIME:
+		case FLOAT:
+			Fc(tl, 0, "%T ", tl->t);
+			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;
+		case IP:
+			if (tl->t->tok == '=') {
+				vcc_NextToken(tl);
+				u = IpVal(tl);
+				Fc(tl, 0, "= %uU; /* %u.%u.%u.%u */\n",
+				    u,
+				    (u >> 24) & 0xff,
+				    (u >> 16) & 0xff,
+				    (u >> 8) & 0xff,
+				    u & 0xff);
+				break;
+			}
+			sbuf_printf(tl->sb, "Illegal assignment operator ");
+			vcc_ErrToken(tl, tl->t);
+			sbuf_printf(tl->sb,
+			    " only '=' is legal for IP numbers\n");
+			vcc_ErrWhere(tl, tl->t);
+			return;
+		case BACKEND:
+			if (tl->t->tok == '=') {
+				vcc_NextToken(tl);
+				AddRef(tl, tl->t, R_BACKEND);
+				Fc(tl, 0, "= &VGC_backend_%T;\n", tl->t);
+				vcc_NextToken(tl);
+				break;
+			}
+			sbuf_printf(tl->sb, "Illegal assignment operator ");
+			vcc_ErrToken(tl, tl->t);
+			sbuf_printf(tl->sb,
+			    " only '=' is legal for backend\n");
+			vcc_ErrWhere(tl, tl->t);
+			return;
+		default:
+			sbuf_printf(tl->sb,
+			    "Assignments not possible for '%s'\n", vp->name);
+			vcc_ErrWhere(tl, tl->t);
+			return;
+		}
+		return;
+	default:
+		sbuf_printf(tl->sb, "Expected action, 'if' or '}'\n");
+		vcc_ErrWhere(tl, at);
+		return;
+	}
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+Acl(struct tokenlist *tl)
+{
+	unsigned u, m;
+
+	vcc_NextToken(tl);
+
+	ExpectErr(tl, ID);
+	AddDef(tl, tl->t, R_ACL);
+	Fh(tl, 0, "static struct vcl_acl acl_%T[];\n", tl->t);
+	Fc(tl, 1, "static struct vcl_acl acl_%T[] = {\n", tl->t);
+	vcc_NextToken(tl);
+
+	tl->indent += INDENT;
+
+	ExpectErr(tl, '{');
+	vcc_NextToken(tl);
+
+	while (tl->t->tok == CNUM) {
+		u = IpVal(tl);
+		if (tl->t->tok == '/') {
+			vcc_NextToken(tl);
+			ExpectErr(tl, CNUM);
+			m = UintVal(tl);
+		} else
+			m = 32;
+		ExpectErr(tl, ';');
+		vcc_NextToken(tl);
+		Fc(tl, 1, "{ %11uU, %3uU }, /* %u.%u.%u.%u/%u */\n",
+		    u, m,
+		    (u >> 24) & 0xff, (u >> 16) & 0xff,
+		    (u >> 8) & 0xff, (u) & 0xff, m);
+	}
+	ExpectErr(tl, '}');
+	Fc(tl, 1, "{ %11uU, %3uU }\n", 0, 0);
+
+	tl->indent -= INDENT;
+
+	Fc(tl, 1, "};\n\n");
+	vcc_NextToken(tl);
+}
+
+/*--------------------------------------------------------------------*/
+
+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:
+			sbuf_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)
+{
+	struct var *vp;
+	struct token *t_be = NULL;
+	struct token *t_host = NULL;
+	struct token *t_port = NULL;
+	char *host = NULL;
+	char *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_%T (VCL_conf.backend[%d])\n",
+	    tl->t, tl->nbackend);
+	Fc(tl, 0, "static void\n");
+	Fc(tl, 1, "VGC_init_backend_%T (void)\n", tl->t);
+	Fc(tl, 1, "{\n");
+	Fc(tl, 1, "\tstruct backend *backend = VGC_backend_%T;\n", tl->t);
+	Fc(tl, 1, "\tconst char *p;\n");
+	Fc(tl, 1, "\n");
+	Fc(tl, 1, "\tVRT_set_backend_name(backend, \"%T\");\n", 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, "\tp = %T;\n", tl->t);
+			Fc(tl, 1, "\t");
+			Fc(tl, 0, vp->lname, "p");
+			Fc(tl, 0, ";\n");
+			vcc_NextToken(tl);
+			break;
+		case PORTNAME:
+			ExpectErr(tl, CSTR);
+			t_port = tl->t;
+			Fc(tl, 1, "\tp = %T;\n", tl->t);
+			Fc(tl, 1, "\t");
+			Fc(tl, 0, vp->lname, "p");
+			Fc(tl, 0, ";\n");
+			vcc_NextToken(tl);
+			break;
+		default:
+			sbuf_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) {
+		sbuf_printf(tl->sb, "Backend '%T' has no hostname\n", t_be);
+		vcc_ErrWhere(tl, tl->t);
+		return;
+	}
+	host = EncString(t_host);
+	ep = CheckHostPort(host, "80");
+	if (ep != NULL) {
+		sbuf_printf(tl->sb, "Backend '%T': %s\n", t_be, ep);
+		vcc_ErrWhere(tl, t_host);
+		return;
+	}
+	if (t_port != NULL) {
+		port = EncString(t_port);
+		ep = CheckHostPort(host, port);
+		if (ep != NULL) {
+			sbuf_printf(tl->sb, "Backend '%T': %s\n", t_be, ep);
+			vcc_ErrWhere(tl, t_port);
+			return;
+		}
+	}
+	
+	vcc_NextToken(tl);
+	Fc(tl, 1, "}\n");
+	Fc(tl, 0, "\n");
+	tl->nbackend++;
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+Function(struct tokenlist *tl)
+{
+
+	vcc_NextToken(tl);
+	ExpectErr(tl, ID);
+	tl->curproc = AddProc(tl, tl->t, 1);
+	tl->curproc->exists++;
+	AddDef(tl, tl->t, R_FUNC);
+	Fh(tl, 0, "static int VGC_function_%T (struct sess *sp);\n", tl->t);
+	Fc(tl, 1, "static int\n");
+	Fc(tl, 1, "VGC_function_%T (struct sess *sp)\n", tl->t);
+	vcc_NextToken(tl);
+	L(tl, Compound(tl));
+	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:
+			Acl(tl);
+			break;
+		case T_SUB:
+			Function(tl);
+			break;
+		case T_BACKEND:
+			Backend(tl);
+			break;
+		case EOI:
+			break;
+		default:
+			sbuf_printf(tl->sb,
+			    "Expected 'acl', 'sub' or 'backend', found ");
+			vcc_ErrToken(tl, tl->t);
+			sbuf_printf(tl->sb, " at\n");
+			vcc_ErrWhere(tl, tl->t);
+			return;
+		}
+	}
+}
+
+/*--------------------------------------------------------------------
+ * Consistency check
+ */
+
+static struct proc *
+AddProc(struct tokenlist *tl, struct token *t, int def)
+{
+	struct proc *p;
+
+	TAILQ_FOREACH(p, &tl->procs, list) {
+		if (!vcc_Teq(p->name, t)) 
+			continue;
+		if (def)
+			p->name = t;
+		return (p);
+	}
+	p = calloc(sizeof *p, 1);
+	assert(p != NULL);
+	p->name = t;
+	TAILQ_INIT(&p->calls);
+	TAILQ_INSERT_TAIL(&tl->procs, p, list);
+	return (p);
+}
+
+static void
+AddCall(struct tokenlist *tl, struct token *t)
+{
+	struct proccall *pc;
+	struct proc *p;
+
+	p = AddProc(tl, t, 0);
+	TAILQ_FOREACH(pc, &tl->curproc->calls, list) {
+		if (pc->p == p)
+			return;
+	}
+	pc = calloc(sizeof *pc, 1);
+	assert(pc != NULL);
+	pc->p = p;
+	pc->t = t;
+	TAILQ_INSERT_TAIL(&tl->curproc->calls, pc, list);
+}
+
+static int
+Consist_Decend(struct tokenlist *tl, struct proc *p, unsigned returns)
+{
+	unsigned u;
+	struct proccall *pc;
+
+	if (!p->exists) {
+		sbuf_printf(tl->sb, "Function %T does not exist\n", p->name);
+		return (1);
+	}
+	if (p->active) {
+		sbuf_printf(tl->sb, "Function recurses on\n");
+		vcc_ErrWhere(tl, p->name);
+		return (1);
+	}
+	u = p->returns & ~returns;
+	if (u) {
+#define VCL_RET_MAC(a, b, c) \
+		if (u & VCL_RET_##b) { \
+			sbuf_printf(tl->sb, "Illegal return for method\n"); \
+			vcc_ErrWhere(tl, p->returnt[c]); \
+		} 
+#include "vcl_returns.h"
+#undef VCL_RET_MAC
+		sbuf_printf(tl->sb, "In function\n");
+		vcc_ErrWhere(tl, p->name);
+		return (1);
+	}
+	p->active = 1;
+	TAILQ_FOREACH(pc, &p->calls, list) {
+		if (Consist_Decend(tl, pc->p, returns)) {
+			sbuf_printf(tl->sb, "\nCalled from\n");
+			vcc_ErrWhere(tl, p->name);
+			sbuf_printf(tl->sb, "at\n");
+			vcc_ErrWhere(tl, pc->t);
+			return (1);
+		}
+	}
+	p->active = 0;
+	p->called++;
+	return (0);
+}
+
+static int
+Consistency(struct tokenlist *tl)
+{
+	struct proc *p;
+	struct method *m;
+
+	TAILQ_FOREACH(p, &tl->procs, list) {
+		for(m = method_tab; m->name != NULL; m++) {
+			if (vcc_IdIs(p->name, m->defname))
+				p->called = 1;
+			if (vcc_IdIs(p->name, m->name))
+				break;
+		}
+		if (m->name == NULL) 
+			continue;
+		if (Consist_Decend(tl, p, m->returns)) {
+			sbuf_printf(tl->sb,
+			    "\nwhich is a %s method\n", m->name);
+			return (1);
+		}
+	}
+	TAILQ_FOREACH(p, &tl->procs, list) {
+		if (p->called)
+			continue;
+		sbuf_printf(tl->sb, "Function unused\n");
+		vcc_ErrWhere(tl, p->name);
+		return (1);
+	}
+	return (0);
+}
+
+/*--------------------------------------------------------------------*/
+
+static int
+CheckRefs(struct tokenlist *tl)
+{
+	struct ref *r;
+	const char *type;
+	int nerr = 0;
+
+	TAILQ_FOREACH(r, &tl->refs, list) {
+		if (r->defcnt != 0 && r->refcnt != 0)
+			continue;
+		nerr++;
+
+		switch(r->type) {
+		case R_FUNC:
+			type = "function";
+			break;
+		case R_ACL:
+			type = "acl";
+			break;
+		case R_BACKEND:
+			type = "backend";
+			break;
+		default:
+			ErrInternal(tl);
+			sbuf_printf(tl->sb, "Ref ");
+			vcc_ErrToken(tl, r->name);
+			sbuf_printf(tl->sb, " has unknown type %d\n",
+			    r->type);
+			continue;
+		}
+		if (r->defcnt == 0 && r->name->tok == METHOD) {
+			sbuf_printf(tl->sb,
+			    "No definition for method %T\n", r->name);
+			continue;
+		}
+
+		if (r->defcnt == 0) {
+			sbuf_printf(tl->sb,
+			    "Undefined %s %T, first reference:\n",
+			    type, r->name);
+			vcc_ErrWhere(tl, r->name);
+			continue;
+		} 
+
+		sbuf_printf(tl->sb, "Unused %s %T, defined:\n", type, r->name);
+		vcc_ErrWhere(tl, r->name);
+	}
+	return (nerr);
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+LocTable(struct tokenlist *tl)
+{
+	struct token *t;
+	unsigned lin, pos;
+	const char *p;
+	
+	Fh(tl, 0, "#define VGC_NREFS %u\n", tl->cnt + 1);
+	Fh(tl, 0, "static struct vrt_ref VGC_ref[VGC_NREFS];\n");
+	Fc(tl, 0, "static struct vrt_ref VGC_ref[VGC_NREFS] = {\n");
+	lin = 1;
+	pos = 0;
+	p = tl->b;
+	TAILQ_FOREACH(t, &tl->tokens, list) {
+		if (t->cnt == 0)
+			continue;
+		for (;p < t->b; p++) {
+			if (*p == '\n') {
+				lin++;
+				pos = 0;
+			} else if (*p == '\t') {
+				pos &= ~7;
+				pos += 8;
+			} else
+				pos++;
+		
+		}
+		Fc(tl, 0, "  [%3u] = { %4u, %3u, 0, \"%T\" },\n",
+		    t->cnt, lin, pos + 1, t);
+	}
+	Fc(tl, 0, "};\n");
+}
+
+
+/*--------------------------------------------------------------------*/
+
+static void
+EmitInitFunc(struct tokenlist *tl)
+{
+	struct ref *r;
+
+	Fc(tl, 0, "\nstatic void\nVGC_Init(void)\n{\n\n");
+	Fc(tl, 0, "\tVRT_alloc_backends(&VCL_conf);\n");
+	
+	TAILQ_FOREACH(r, &tl->refs, list) {
+		switch(r->type) {
+		case R_FUNC:
+			break;
+		case R_ACL:
+			break;
+		case R_BACKEND:
+			Fc(tl, 0, "\tVGC_init_backend_%T();\n", r->name);
+			break;
+		}
+	}
+	Fc(tl, 0, "}\n");
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+EmitStruct(struct tokenlist *tl)
+{
+
+	Fc(tl, 0, "\nstruct VCL_conf VCL_conf = {\n");
+	Fc(tl, 0, "\t.magic = VCL_CONF_MAGIC,\n");
+	Fc(tl, 0, "\t.init_func = VGC_Init,\n");
+	Fc(tl, 0, "\t.nbackend = %d,\n", tl->nbackend);
+	Fc(tl, 0, "\t.ref = VGC_ref,\n");
+	Fc(tl, 0, "\t.nref = VGC_NREFS,\n");
+#define VCL_RET_MAC(l,u,b)
+#define VCL_MET_MAC(l,u,b) \
+	if (FindRefStr(tl, "vcl_" #l, R_FUNC)) { \
+		Fc(tl, 0, "\t." #l "_func = VGC_function_vcl_" #l ",\n"); \
+		AddRefStr(tl, "vcl_" #l, R_FUNC); \
+	} else { \
+		Fc(tl, 0, "\t." #l "_func = VGC_function_default_vcl_" #l ",\n"); \
+	} \
+	AddRefStr(tl, "default_vcl_" #l, R_FUNC);
+#include "vcl_returns.h"
+#undef VCL_MET_MAC
+#undef VCL_RET_MAC
+	Fc(tl, 0, "};\n");
+}
+
+/*--------------------------------------------------------------------*/
+
+char *
+VCC_Compile(struct sbuf *sb, const char *b, const char *e)
+{
+	struct tokenlist tokens;
+	struct ref *r;
+	struct token *t;
+	FILE *fo;
+	char *of = NULL;
+	char buf[BUFSIZ];
+
+	memset(&tokens, 0, sizeof tokens);
+	TAILQ_INIT(&tokens.tokens);
+	TAILQ_INIT(&tokens.refs);
+	TAILQ_INIT(&tokens.procs);
+	tokens.sb = sb;
+
+	tokens.fc = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND);
+	assert(tokens.fc != NULL);
+
+	tokens.fh = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND);
+	assert(tokens.fh != NULL);
+
+	Fh(&tokens, 0, "extern struct VCL_conf VCL_conf;\n");
+
+	tokens.b = b;
+	if (e == NULL)
+		e = strchr(b, '\0');
+	assert(e != NULL);
+	tokens.e = e;
+	vcc_Lexer(&tokens, b, e);
+	vcc_Lexer(&tokens, vcc_default_vcl_b, vcc_default_vcl_e);
+	vcc_AddToken(&tokens, EOI, e, e);
+	if (tokens.err)
+		goto done;
+	tokens.t = TAILQ_FIRST(&tokens.tokens);
+	Parse(&tokens);
+	if (tokens.err)
+		goto done;
+	Consistency(&tokens);
+	if (tokens.err)
+		goto done;
+	LocTable(&tokens);
+
+	EmitInitFunc(&tokens);
+
+	EmitStruct(&tokens);
+
+	if (CheckRefs(&tokens))
+		goto done;
+
+	of = strdup("/tmp/vcl.XXXXXXXX");
+	assert(of != NULL);
+	mktemp(of);
+
+	sprintf(buf, 
+	    "tee /tmp/_.c |"
+	    "cc -fpic -shared -Wl,-x -o %s -x c - ", of);
+
+	fo = popen(buf, "w");
+	assert(fo != NULL);
+
+	vcl_output_lang_h(fo);
+
+	sbuf_finish(tokens.fh);
+	fputs(sbuf_data(tokens.fh), fo);
+	sbuf_delete(tokens.fh);
+
+	sbuf_finish(tokens.fc);
+	fputs(sbuf_data(tokens.fc), fo);
+	sbuf_delete(tokens.fc);
+
+	pclose(fo);
+done:
+
+	/* Free References */
+	while (!TAILQ_EMPTY(&tokens.refs)) {
+		r = TAILQ_FIRST(&tokens.refs);
+		TAILQ_REMOVE(&tokens.refs, r, list);
+		free(r);
+	}
+
+	/* Free Tokens */
+	while (!TAILQ_EMPTY(&tokens.tokens)) {
+		t = TAILQ_FIRST(&tokens.tokens);
+		TAILQ_REMOVE(&tokens.tokens, t, list);
+		free(t);
+	}
+	return (of);
+}
+
+/*--------------------------------------------------------------------*/
+
+char *
+VCC_CompileFile(struct sbuf *sb, const char *fn)
+{
+	char *f, *r;
+	int fd, i;
+	struct stat st;
+
+	fd = open(fn, O_RDONLY);
+	if (fd < 0) {
+		sbuf_printf(sb, "Cannot open file '%s': %s",
+		    fn, strerror(errno));
+		return (NULL);
+	}
+	assert(0 == fstat(fd, &st));
+	f = malloc(st.st_size + 1);
+	assert(f != NULL);
+	i = read(fd, f, st.st_size); 
+	assert(i == st.st_size);
+	f[i] = '\0';
+	r = VCC_Compile(sb, f, NULL);
+	free(f);
+	return (r);
+}
+
+/*--------------------------------------------------------------------*/
+
+static int
+VCC_T_render(FILE *f, const struct printf_info *info __unused, const void *const *args)
+{
+	const struct token *t;
+
+	t = *((const struct token * const*) (args[0]));
+	return (fprintf(f, "%*.*s",
+	    t->e - t->b, t->e - t->b, t->b));
+}
+     
+static int
+VCC_T_arginfo(const struct printf_info *info __unused, size_t n, int *argtypes)
+{
+
+	if (n > 0)
+		argtypes[0] = PA_POINTER;
+	return 1;
+}
+     
+/*--------------------------------------------------------------------*/
+
+void
+VCC_InitCompile(const char *default_vcl)
+{
+	struct var *v;
+
+	vcc_default_vcl_b = default_vcl;
+	vcc_default_vcl_e = strchr(default_vcl, '\0');
+	assert(vcc_default_vcl_e != NULL);
+	
+	register_printf_function ('T', VCC_T_render, VCC_T_arginfo);
+	vcl_init_tnames();
+	for (v = vcc_vars; v->name != NULL; v++)
+		v->len = strlen(v->name);
+	for (v = vcc_be_vars; v->name != NULL; v++)
+		v->len = strlen(v->name);
+}

Added: trunk/varnish-cache/lib/libvcl/vcc_compile.h
===================================================================
--- trunk/varnish-cache/lib/libvcl/vcc_compile.h	2006-07-21 16:25:24 UTC (rev 543)
+++ trunk/varnish-cache/lib/libvcl/vcc_compile.h	2006-07-21 18:12:56 UTC (rev 544)
@@ -0,0 +1,120 @@
+/*
+ * $Id$
+ */
+
+#include "queue.h"
+#include "vcl_returns.h"
+
+#define INDENT		2
+
+struct token {
+	unsigned		tok;
+	const char		*b;
+	const char		*e;
+	TAILQ_ENTRY(token)	list;
+	unsigned		cnt;
+};
+
+struct tokenlist {
+	TAILQ_HEAD(, token)	tokens;
+	const char		*b;
+	const char		*e;
+	struct token		*t;
+	int			indent;
+	unsigned		cnt;
+	struct sbuf		*fc, *fh;
+	TAILQ_HEAD(, ref)	refs;
+	struct sbuf		*sb;
+	int			err;
+	int			nbackend;
+	TAILQ_HEAD(, proc)	procs;
+	struct proc		*curproc;
+};
+
+enum var_type {
+	BACKEND,
+	BOOL,
+	INT,
+	FLOAT,
+	SIZE,
+	RATE,
+	TIME,
+	STRING,
+	IP,
+	HOSTNAME,
+	PORTNAME,
+	HEADER
+};
+
+enum ref_type {
+	R_FUNC,
+	R_ACL,
+	R_BACKEND
+};
+
+struct ref {
+	enum ref_type		type;
+	struct token		*name;
+	unsigned		defcnt;
+	unsigned		refcnt;
+	TAILQ_ENTRY(ref)	list;
+};
+
+struct var {
+	const char		*name;
+	enum var_type		fmt;
+	int			len;
+	const char		*rname;
+	const char		*lname;
+};
+
+static struct method {
+	const char		*name;
+	const char		*defname;
+	unsigned		returns;
+} method_tab[] = {
+#define VCL_RET_MAC(a,b,c)
+#define VCL_MET_MAC(a,b,c)	{ "vcl_"#a, "default_vcl_"#a, c },
+#include "vcl_returns.h"
+#undef VCL_MET_MAC
+#undef VCL_RET_MAC
+	{ NULL, 0U }
+};
+
+struct proccall {
+	TAILQ_ENTRY(proccall)	list;
+	struct proc		*p;
+	struct token		*t;
+};
+
+struct proc {
+	TAILQ_ENTRY(proc)	list;
+	TAILQ_HEAD(,proccall)	calls;
+	struct token		*name;
+	unsigned		returns;
+	unsigned		exists;
+	unsigned		called;
+	unsigned		active;
+	struct token		*returnt[VCL_RET_MAX];
+};
+
+
+/*--------------------------------------------------------------------*/
+
+/* vcc_compile.c */
+extern const char *vcc_default_vcl_b, *vcc_default_vcl_e;
+
+/* vcc_obj.c */
+extern struct var vcc_be_vars[];
+extern struct var vcc_vars[];
+
+/* vcc_token.c */
+void vcc_ErrToken(struct tokenlist *tl, struct token *t);
+void vcc_ErrWhere(struct tokenlist *tl, struct token *t);
+void vcc__Expect(struct tokenlist *tl, unsigned tok, int line);
+int vcc_Teq(struct token *t1, struct token *t2);
+int vcc_IdIs(struct token *t, const char *p);
+void vcc_Lexer(struct tokenlist *tl, const char *b, const char *e);
+void vcc_NextToken(struct tokenlist *tl);
+void vcc__ErrInternal(struct tokenlist *tl, const char *func, unsigned line);
+void vcc_AddToken(struct tokenlist *tl, unsigned tok, const char *b, const char *e);

Copied: trunk/varnish-cache/lib/libvcl/vcc_fixed_token.c (from rev 480, trunk/varnish-cache/lib/libvcl/vcl_fixed_token.c)
===================================================================
--- trunk/varnish-cache/lib/libvcl/vcl_fixed_token.c	2006-07-14 13:54:41 UTC (rev 480)
+++ trunk/varnish-cache/lib/libvcl/vcc_fixed_token.c	2006-07-21 18:12:56 UTC (rev 544)
@@ -0,0 +1,518 @@
+/*
+ * $Id$
+ *
+ * NB:  This file is machine generated, DO NOT EDIT!
+ *
+ * Edit vcc_gen_fixed_token.tcl instead
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include "vcc_priv.h"
+
+unsigned
+vcl_fixed_token(const char *p, const char **q)
+{
+
+	switch (p[0]) {
+	case '!':
+		if (p[0] == '!' && p[1] == '=') {
+			*q = p + 2;
+			return (T_NEQ);
+		}
+		if (p[0] == '!') {
+			*q = p + 1;
+			return ('!');
+		}
+		return (0);
+	case '%':
+		if (p[0] == '%') {
+			*q = p + 1;
+			return ('%');
+		}
+		return (0);
+	case '&':
+		if (p[0] == '&' && p[1] == '&') {
+			*q = p + 2;
+			return (T_CAND);
+		}
+		if (p[0] == '&') {
+			*q = p + 1;
+			return ('&');
+		}
+		return (0);
+	case '(':
+		if (p[0] == '(') {
+			*q = p + 1;
+			return ('(');
+		}
+		return (0);
+	case ')':
+		if (p[0] == ')') {
+			*q = p + 1;
+			return (')');
+		}
+		return (0);
+	case '*':
+		if (p[0] == '*' && p[1] == '=') {
+			*q = p + 2;
+			return (T_MUL);
+		}
+		if (p[0] == '*') {
+			*q = p + 1;
+			return ('*');
+		}
+		return (0);
+	case '+':
+		if (p[0] == '+' && p[1] == '=') {
+			*q = p + 2;
+			return (T_INCR);
+		}
+		if (p[0] == '+' && p[1] == '+') {
+			*q = p + 2;
+			return (T_INC);
+		}
+		if (p[0] == '+') {
+			*q = p + 1;
+			return ('+');
+		}
+		return (0);
+	case ',':
+		if (p[0] == ',') {
+			*q = p + 1;
+			return (',');
+		}
+		return (0);
+	case '-':
+		if (p[0] == '-' && p[1] == '-') {
+			*q = p + 2;
+			return (T_DEC);
+		}
+		if (p[0] == '-') {
+			*q = p + 1;
+			return ('-');
+		}
+		return (0);
+	case '.':
+		if (p[0] == '.') {
+			*q = p + 1;
+			return ('.');
+		}
+		return (0);
+	case '/':
+		if (p[0] == '/' && p[1] == '=') {
+			*q = p + 2;
+			return (T_DECR);
+		}
+		if (p[0] == '/' && p[1] == '=') {
+			*q = p + 2;
+			return (T_DIV);
+		}
+		if (p[0] == '/') {
+			*q = p + 1;
+			return ('/');
+		}
+		return (0);
+	case ';':
+		if (p[0] == ';') {
+			*q = p + 1;
+			return (';');
+		}
+		return (0);
+	case '<':
+		if (p[0] == '<' && p[1] == '=') {
+			*q = p + 2;
+			return (T_LEQ);
+		}
+		if (p[0] == '<' && p[1] == '<') {
+			*q = p + 2;
+			return (T_SHL);
+		}
+		if (p[0] == '<') {
+			*q = p + 1;
+			return ('<');
+		}
+		return (0);
+	case '=':
+		if (p[0] == '=' && p[1] == '=') {
+			*q = p + 2;
+			return (T_EQ);
+		}
+		if (p[0] == '=') {
+			*q = p + 1;
+			return ('=');
+		}
+		return (0);
+	case '>':
+		if (p[0] == '>' && p[1] == '>') {
+			*q = p + 2;
+			return (T_SHR);
+		}
+		if (p[0] == '>' && p[1] == '=') {
+			*q = p + 2;
+			return (T_GEQ);
+		}
+		if (p[0] == '>') {
+			*q = p + 1;
+			return ('>');
+		}
+		return (0);
+	case 'a':
+		if (p[0] == 'a' && p[1] == 'c' && p[2] == 'l'
+		     && !isvar(p[3])) {
+			*q = p + 3;
+			return (T_ACL);
+		}
+		return (0);
+	case 'b':
+		if (p[0] == 'b' && p[1] == 'a' && p[2] == 'c' && 
+		    p[3] == 'k' && p[4] == 'e' && p[5] == 'n' && 
+		    p[6] == 'd' && !isvar(p[7])) {
+			*q = p + 7;
+			return (T_BACKEND);
+		}
+		return (0);
+	case 'c':
+		if (p[0] == 'c' && p[1] == 'a' && p[2] == 'l' && 
+		    p[3] == 'l' && !isvar(p[4])) {
+			*q = p + 4;
+			return (T_CALL);
+		}
+		return (0);
+	case 'd':
+		if (p[0] == 'd' && p[1] == 'i' && p[2] == 's' && 
+		    p[3] == 'c' && p[4] == 'a' && p[5] == 'r' && 
+		    p[6] == 'd' && !isvar(p[7])) {
+			*q = p + 7;
+			return (T_DISCARD);
+		}
+		if (p[0] == 'd' && p[1] == 'e' && p[2] == 'l' && 
+		    p[3] == 'i' && p[4] == 'v' && p[5] == 'e' && 
+		    p[6] == 'r' && !isvar(p[7])) {
+			*q = p + 7;
+			return (T_DELIVER);
+		}
+		return (0);
+	case 'e':
+		if (p[0] == 'e' && p[1] == 'r' && p[2] == 'r' && 
+		    p[3] == 'o' && p[4] == 'r' && !isvar(p[5])) {
+			*q = p + 5;
+			return (T_ERROR);
+		}
+		if (p[0] == 'e' && p[1] == 'l' && p[2] == 's' && 
+		    p[3] == 'i' && p[4] == 'f' && !isvar(p[5])) {
+			*q = p + 5;
+			return (T_ELSIF);
+		}
+		if (p[0] == 'e' && p[1] == 'l' && p[2] == 's' && 
+		    p[3] == 'e' && p[4] == 'i' && p[5] == 'f'
+		     && !isvar(p[6])) {
+			*q = p + 6;
+			return (T_ELSEIF);
+		}
+		if (p[0] == 'e' && p[1] == 'l' && p[2] == 's' && 
+		    p[3] == 'e' && !isvar(p[4])) {
+			*q = p + 4;
+			return (T_ELSE);
+		}
+		return (0);
+	case 'f':
+		if (p[0] == 'f' && p[1] == 'u' && p[2] == 'n' && 
+		    p[3] == 'c' && !isvar(p[4])) {
+			*q = p + 4;
+			return (T_FUNC);
+		}
+		if (p[0] == 'f' && p[1] == 'e' && p[2] == 't' && 
+		    p[3] == 'c' && p[4] == 'h' && !isvar(p[5])) {
+			*q = p + 5;
+			return (T_FETCH);
+		}
+		return (0);
+	case 'i':
+		if (p[0] == 'i' && p[1] == 'n' && p[2] == 's' && 
+		    p[3] == 'e' && p[4] == 'r' && p[5] == 't' && 
+		    p[6] == '_' && p[7] == 'p' && p[8] == 'a' && 
+		    p[9] == 's' && p[10] == 's' && !isvar(p[11])) {
+			*q = p + 11;
+			return (T_INSERT_PASS);
+		}
+		if (p[0] == 'i' && p[1] == 'n' && p[2] == 's' && 
+		    p[3] == 'e' && p[4] == 'r' && p[5] == 't'
+		     && !isvar(p[6])) {
+			*q = p + 6;
+			return (T_INSERT);
+		}
+		if (p[0] == 'i' && p[1] == 'f' && !isvar(p[2])) {
+			*q = p + 2;
+			return (T_IF);
+		}
+		return (0);
+	case 'l':
+		if (p[0] == 'l' && p[1] == 'o' && p[2] == 'o' && 
+		    p[3] == 'k' && p[4] == 'u' && p[5] == 'p'
+		     && !isvar(p[6])) {
+			*q = p + 6;
+			return (T_LOOKUP);
+		}
+		return (0);
+	case 'n':
+		if (p[0] == 'n' && p[1] == 'o' && p[2] == '_' && 
+		    p[3] == 'n' && p[4] == 'e' && p[5] == 'w' && 
+		    p[6] == '_' && p[7] == 'c' && p[8] == 'a' && 
+		    p[9] == 'c' && p[10] == 'h' && p[11] == 'e'
+		     && !isvar(p[12])) {
+			*q = p + 12;
+			return (T_NO_NEW_CACHE);
+		}
+		if (p[0] == 'n' && p[1] == 'o' && p[2] == '_' && 
+		    p[3] == 'c' && p[4] == 'a' && p[5] == 'c' && 
+		    p[6] == 'h' && p[7] == 'e' && !isvar(p[8])) {
+			*q = p + 8;
+			return (T_NO_CACHE);
+		}
+		return (0);
+	case 'p':
+		if (p[0] == 'p' && p[1] == 'r' && p[2] == 'o' && 
+		    p[3] == 'c' && !isvar(p[4])) {
+			*q = p + 4;
+			return (T_PROC);
+		}
+		if (p[0] == 'p' && p[1] == 'i' && p[2] == 'p' && 
+		    p[3] == 'e' && !isvar(p[4])) {
+			*q = p + 4;
+			return (T_PIPE);
+		}
+		if (p[0] == 'p' && p[1] == 'a' && p[2] == 's' && 
+		    p[3] == 's' && !isvar(p[4])) {
+			*q = p + 4;
+			return (T_PASS);
+		}
+		return (0);
+	case 'r':
+		if (p[0] == 'r' && p[1] == 'e' && p[2] == 'w' && 
+		    p[3] == 'r' && p[4] == 'i' && p[5] == 't' && 
+		    p[6] == 'e' && !isvar(p[7])) {
+			*q = p + 7;
+			return (T_REWRITE);
+		}
+		return (0);
+	case 's':
+		if (p[0] == 's' && p[1] == 'w' && p[2] == 'i' && 
+		    p[3] == 't' && p[4] == 'c' && p[5] == 'h' && 
+		    p[6] == '_' && p[7] == 'c' && p[8] == 'o' && 
+		    p[9] == 'n' && p[10] == 'f' && p[11] == 'i' && 
+		    p[12] == 'g' && !isvar(p[13])) {
+			*q = p + 13;
+			return (T_SWITCH_CONFIG);
+		}
+		if (p[0] == 's' && p[1] == 'u' && p[2] == 'b'
+		     && !isvar(p[3])) {
+			*q = p + 3;
+			return (T_SUB);
+		}
+		if (p[0] == 's' && p[1] == 'e' && p[2] == 't'
+		     && !isvar(p[3])) {
+			*q = p + 3;
+			return (T_SET);
+		}
+		return (0);
+	case '{':
+		if (p[0] == '{') {
+			*q = p + 1;
+			return ('{');
+		}
+		return (0);
+	case '|':
+		if (p[0] == '|' && p[1] == '|') {
+			*q = p + 2;
+			return (T_COR);
+		}
+		if (p[0] == '|') {
+			*q = p + 1;
+			return ('|');
+		}
+		return (0);
+	case '}':
+		if (p[0] == '}') {
+			*q = p + 1;
+			return ('}');
+		}
+		return (0);
+	case '~':
+		if (p[0] == '~') {
+			*q = p + 1;
+			return ('~');
+		}
+		return (0);
+	default:
+		return (0);
+	}
+}
+
+const char *vcl_tnames[256];
+
+void
+vcl_init_tnames(void)
+{
+	vcl_tnames['!'] = "'!'";
+	vcl_tnames['%'] = "'%'";
+	vcl_tnames['&'] = "'&'";
+	vcl_tnames['('] = "'('";
+	vcl_tnames[')'] = "')'";
+	vcl_tnames['*'] = "'*'";
+	vcl_tnames['+'] = "'+'";
+	vcl_tnames[','] = "','";
+	vcl_tnames['-'] = "'-'";
+	vcl_tnames['.'] = "'.'";
+	vcl_tnames['/'] = "'/'";
+	vcl_tnames['<'] = "'<'";
+	vcl_tnames['='] = "'='";
+	vcl_tnames['>'] = "'>'";
+	vcl_tnames['{'] = "'{'";
+	vcl_tnames['}'] = "'}'";
+	vcl_tnames['|'] = "'|'";
+	vcl_tnames['~'] = "'~'";
+	vcl_tnames[';'] = "';'";
+	vcl_tnames[CNUM] = "CNUM";
+	vcl_tnames[CSTR] = "CSTR";
+	vcl_tnames[EOI] = "EOI";
+	vcl_tnames[ID] = "ID";
+	vcl_tnames[METHOD] = "METHOD";
+	vcl_tnames[T_ACL] = "acl";
+	vcl_tnames[T_BACKEND] = "backend";
+	vcl_tnames[T_CALL] = "call";
+	vcl_tnames[T_CAND] = "&&";
+	vcl_tnames[T_COR] = "||";
+	vcl_tnames[T_DEC] = "--";
+	vcl_tnames[T_DECR] = "/=";
+	vcl_tnames[T_DELIVER] = "deliver";
+	vcl_tnames[T_DISCARD] = "discard";
+	vcl_tnames[T_DIV] = "/=";
+	vcl_tnames[T_ELSE] = "else";
+	vcl_tnames[T_ELSEIF] = "elseif";
+	vcl_tnames[T_ELSIF] = "elsif";
+	vcl_tnames[T_EQ] = "==";
+	vcl_tnames[T_ERROR] = "error";
+	vcl_tnames[T_FETCH] = "fetch";
+	vcl_tnames[T_FUNC] = "func";
+	vcl_tnames[T_GEQ] = ">=";
+	vcl_tnames[T_IF] = "if";
+	vcl_tnames[T_INC] = "++";
+	vcl_tnames[T_INCR] = "+=";
+	vcl_tnames[T_INSERT] = "insert";
+	vcl_tnames[T_INSERT_PASS] = "insert_pass";
+	vcl_tnames[T_LEQ] = "<=";
+	vcl_tnames[T_LOOKUP] = "lookup";
+	vcl_tnames[T_MUL] = "*=";
+	vcl_tnames[T_NEQ] = "!=";
+	vcl_tnames[T_NO_CACHE] = "no_cache";
+	vcl_tnames[T_NO_NEW_CACHE] = "no_new_cache";
+	vcl_tnames[T_PASS] = "pass";
+	vcl_tnames[T_PIPE] = "pipe";
+	vcl_tnames[T_PROC] = "proc";
+	vcl_tnames[T_REWRITE] = "rewrite";
+	vcl_tnames[T_SET] = "set";
+	vcl_tnames[T_SHL] = "<<";
+	vcl_tnames[T_SHR] = ">>";
+	vcl_tnames[T_SUB] = "sub";
+	vcl_tnames[T_SWITCH_CONFIG] = "switch_config";
+	vcl_tnames[VAR] = "VAR";
+}
+
+void
+vcl_output_lang_h(FILE *f)
+{
+	fputs("#define VCL_RET_ERROR  (1 << 0)\n", f);
+	fputs("#define VCL_RET_LOOKUP  (1 << 1)\n", f);
+	fputs("#define VCL_RET_PIPE  (1 << 2)\n", f);
+	fputs("#define VCL_RET_PASS  (1 << 3)\n", f);
+	fputs("#define VCL_RET_INSERT_PASS  (1 << 4)\n", f);
+	fputs("#define VCL_RET_FETCH  (1 << 5)\n", f);
+	fputs("#define VCL_RET_INSERT  (1 << 6)\n", f);
+	fputs("#define VCL_RET_DELIVER  (1 << 7)\n", f);
+	fputs("#define VCL_RET_DISCARD  (1 << 8)\n", f);
+	fputs("/*\n", f);
+	fputs(" * $Id$\n", f);
+	fputs(" *\n", f);
+	fputs(" * NB:  This file is machine generated, DO NOT EDIT!\n", f);
+	fputs(" *\n", f);
+	fputs(" * Edit vcc_gen_fixed_token.tcl instead\n", f);
+	fputs(" */\n", f);
+	fputs("\n", f);
+	fputs("struct sess;\n", f);
+	fputs("\n", f);
+	fputs("typedef void vcl_init_f(void);\n", f);
+	fputs("typedef int vcl_func_f(struct sess *sp);\n", f);
+	fputs("\n", f);
+	fputs("struct VCL_conf {\n", f);
+	fputs("	unsigned        magic;\n", f);
+	fputs("#define VCL_CONF_MAGIC  0x7406c509      /* from /dev/random */\n", f);
+	fputs("\n", f);
+	fputs("        struct backend  **backend;\n", f);
+	fputs("        unsigned        nbackend;\n", f);
+	fputs("        struct vrt_ref  *ref;\n", f);
+	fputs("        unsigned        nref;\n", f);
+	fputs("        unsigned        busy;\n", f);
+	fputs("\n", f);
+	fputs("        vcl_init_f      *init_func;\n", f);
+	fputs("\n", f);
+	fputs("	vcl_func_f	*recv_func;\n", f);
+	fputs("	vcl_func_f	*miss_func;\n", f);
+	fputs("	vcl_func_f	*hit_func;\n", f);
+	fputs("	vcl_func_f	*fetch_func;\n", f);
+	fputs("	vcl_func_f	*timeout_func;\n", f);
+	fputs("};\n", f);
+	fputs("/*\n", f);
+	fputs(" * $Id$ \n", f);
+	fputs(" *\n", f);
+	fputs(" * Runtime support for compiled VCL programs.\n", f);
+	fputs(" *\n", f);
+	fputs(" * XXX: When this file is changed, lib/libvcl/vcl_gen_fixed_token.tcl\n", f);
+	fputs(" * XXX: *MUST* be rerun.\n", f);
+	fputs(" */\n", f);
+	fputs("\n", f);
+	fputs("struct sess;\n", f);
+	fputs("struct backend;\n", f);
+	fputs("struct VCL_conf;\n", f);
+	fputs("\n", f);
+	fputs("struct vrt_ref {\n", f);
+	fputs("	unsigned	line;\n", f);
+	fputs("	unsigned	pos;\n", f);
+	fputs("	unsigned	count;\n", f);
+	fputs("	const char	*token;\n", f);
+	fputs("};\n", f);
+	fputs("\n", f);
+	fputs("struct vrt_acl {\n", f);
+	fputs("	unsigned	ip;\n", f);
+	fputs("	unsigned	mask;\n", f);
+	fputs("};\n", f);
+	fputs("\n", f);
+	fputs("void VRT_count(struct sess *, unsigned);\n", f);
+	fputs("void VRT_no_cache(struct sess *);\n", f);
+	fputs("void VRT_no_new_cache(struct sess *);\n", f);
+	fputs("#if 0\n", f);
+	fputs("int ip_match(unsigned, struct vcl_acl *);\n", f);
+	fputs("int string_match(const char *, const char *);\n", f);
+	fputs("#endif\n", f);
+	fputs("int VRT_rewrite(const char *, const char *);\n", f);
+	fputs("void VRT_error(struct sess *, unsigned, const char *);\n", f);
+	fputs("int VRT_switch_config(const char *);\n", f);
+	fputs("\n", f);
+	fputs("char *VRT_GetHdr(struct sess *, const char *);\n", f);
+	fputs("char *VRT_GetReq(struct sess *);\n", f);
+	fputs("void VRT_handling(struct sess *sp, unsigned hand);\n", f);
+	fputs("int VRT_obj_valid(struct sess *);\n", f);
+	fputs("int VRT_obj_cacheable(struct sess *);\n", f);
+	fputs("\n", f);
+	fputs("void VRT_set_backend_name(struct backend *, const char *);\n", f);
+	fputs("void VRT_set_backend_hostname(struct backend *, const char *);\n", f);
+	fputs("void VRT_set_backend_portname(struct backend *, const char *);\n", f);
+	fputs("\n", f);
+	fputs("void VRT_alloc_backends(struct VCL_conf *cp);\n", f);
+	fputs("\n", f);
+	fputs("#define VRT_done(sp, hand)			\\\n", f);
+	fputs("	do {					\\\n", f);
+	fputs("		VRT_handling(sp, hand);		\\\n", f);
+	fputs("		return (1);			\\\n", f);
+	fputs("	} while (0)\n", f);
+}

Copied: trunk/varnish-cache/lib/libvcl/vcc_gen_fixed_token.tcl (from rev 480, trunk/varnish-cache/lib/libvcl/vcl_gen_fixed_token.tcl)
===================================================================
--- trunk/varnish-cache/lib/libvcl/vcl_gen_fixed_token.tcl	2006-07-14 13:54:41 UTC (rev 480)
+++ trunk/varnish-cache/lib/libvcl/vcc_gen_fixed_token.tcl	2006-07-21 18:12:56 UTC (rev 544)
@@ -0,0 +1,319 @@
+#!/usr/local/bin/tclsh8.4
+#
+# Generate various .c and .h files for the VCL compiler and the interfaces
+# for it.
+
+# These are the metods which can be called in the VCL program. 
+# Second element is list of valid return actions.
+#
+set methods {
+	{recv		{error pass pipe lookup}}
+	{miss		{error pass pipe fetch}}
+	{hit		{error pass pipe deliver}}
+	{fetch		{error pass pipe insert insert_pass}}
+	{timeout	{fetch discard}}
+}
+
+# These are the return actions
+#
+set returns {
+	error
+	lookup
+	pipe
+	pass
+	insert_pass
+	fetch
+	insert
+	deliver
+	discard
+}
+
+# Language keywords
+#
+set keywords {
+	if else elseif elsif
+
+	func proc sub
+
+	acl
+
+	backend
+
+	call
+	no_cache
+	no_new_cache
+	set
+	rewrite
+	switch_config
+}
+
+# Non-word tokens
+#
+set magic {
+	{"++"	INC}
+	{"--"	DEC}
+	{"&&"	CAND}
+	{"||"	COR}
+	{"<="	LEQ}
+	{"=="	EQ}
+	{"!="	NEQ}
+	{">="	GEQ}
+	{">>"	SHR}
+	{"<<"	SHL}
+	{"+="	INCR}
+	{"/="	DECR}
+	{"*="	MUL}
+	{"/="	DIV}
+}
+
+# Single char tokens
+#
+set char {{}()*+-/%><=;!&.|~,}
+
+# Other token identifiers
+#
+set extras {ID VAR CNUM CSTR EOI METHOD}
+
+#----------------------------------------------------------------------
+# Boilerplate warning for all generated files.
+
+proc warns {fd} {
+
+	puts $fd "/*"
+	puts $fd { * $Id$}
+	puts $fd " *"
+	puts $fd " * NB:  This file is machine generated, DO NOT EDIT!"
+	puts $fd " *"
+	puts $fd " * Edit vcc_gen_fixed_token.tcl instead"
+	puts $fd " */"
+	puts $fd ""
+}
+
+#----------------------------------------------------------------------
+# Build the vcl.h #include file
+
+set fo [open ../../include/vcl.h w]
+warns $fo
+puts $fo {struct sess;
+
+typedef void vcl_init_f(void);
+typedef int vcl_func_f(struct sess *sp);
+}
+puts $fo "struct VCL_conf {"
+puts $fo {	unsigned        magic;
+#define VCL_CONF_MAGIC  0x7406c509      /* from /dev/random */
+
+        struct backend  **backend;
+        unsigned        nbackend;
+        struct vrt_ref  *ref;
+        unsigned        nref;
+        unsigned        busy;
+
+        vcl_init_f      *init_func;
+}
+foreach m $methods {
+	puts $fo "\tvcl_func_f\t*[lindex $m 0]_func;"
+}
+puts $fo "};"
+
+close $fo
+
+#----------------------------------------------------------------------
+# Build the vcl_returns.h #include file
+
+set for [open "../../include/vcl_returns.h" w]
+warns $for
+puts $for "#ifdef VCL_RET_MAC"
+set i 0
+foreach k $returns {
+	if {$k == "error"} {
+		puts $for "#ifdef VCL_RET_MAC_E"
+		puts $for "VCL_RET_MAC_E($k, [string toupper $k], $i)"
+		puts $for "#endif"
+	} else {
+		puts $for "VCL_RET_MAC($k, [string toupper $k], (1 << $i))"
+	}
+	incr i
+}
+puts $for "#else"
+set i 0
+foreach k $returns {
+	puts $for "#define VCL_RET_[string toupper $k]  (1 << $i)"
+	incr i
+}
+puts $for "#define VCL_RET_MAX $i"
+puts $for "#endif"
+puts $for ""
+puts $for "#ifdef VCL_MET_MAC"
+foreach m $methods {
+	puts -nonewline $for "VCL_MET_MAC([lindex $m 0]"
+	puts -nonewline $for ",[string toupper [lindex $m 0]]"
+	set l [lindex $m 1]
+	puts -nonewline $for ",(VCL_RET_[string toupper [lindex $l 0]]"
+	foreach r [lrange $l 1 end] {
+		puts -nonewline $for "|VCL_RET_[string toupper $r]"
+	}
+	puts -nonewline $for ")"
+	puts $for ")"
+}
+puts $for "#endif"
+close $for
+
+#----------------------------------------------------------------------
+# Build the compiler token table and recognizers
+
+set fo [open "vcc_fixed_token.c" w]
+warns $fo
+
+set foh [open "vcc_token_defs.h" w]
+warns $foh
+
+puts $fo "#include <stdio.h>"
+puts $fo "#include <ctype.h>"
+puts $fo "#include \"vcc_priv.h\""
+
+set tn 128
+puts $foh "#define LOW_TOKEN $tn"
+
+
+proc add_token {tok str alpha} {
+	global tokens tn fixed foh
+
+	lappend tokens [list $tok $str]
+	puts $foh "#define $tok $tn"
+	incr tn
+	lappend fixed [list $str $tok $alpha]
+}
+
+proc mk_token {tok str alpha} {
+	set tok T_[string toupper $tok]
+	add_token $tok $str $alpha
+}
+
+foreach k $keywords { mk_token $k $k 1 }
+foreach k $returns { mk_token $k $k 1 }
+foreach k $magic { mk_token [lindex $k 1] [lindex $k 0] 0 }
+foreach k $extras {
+	set t [string toupper $k]
+	lappend tokens [list $t $t]
+	puts $foh "#define [string toupper $k] $tn"
+	incr tn
+}
+for {set i 0} {$i < [string length $char]} {incr i} {
+	set t [string index $char $i]
+	lappend token2 [list '$t' T$t]
+	lappend fixed [list "$t" '$t' 0]
+}
+
+set tokens [lsort $tokens]
+set token2 [lsort $token2]
+
+# We want to output in ascii order: create sorted first char list
+foreach t $fixed {
+	set xx([string index [lindex $t 0] 0]) 1
+}
+set seq [lsort [array names xx]]
+
+set ll 0
+
+puts $fo {
+unsigned
+vcl_fixed_token(const char *p, const char **q)}
+puts $fo "{"
+puts $fo ""
+puts $fo "	switch (p\[0\]) {"
+
+foreach ch "$seq" {
+	# Now find all tokens starting with ch
+	set l ""
+	foreach t $fixed {
+		if {[string index [lindex $t 0] 0] == $ch} {
+			lappend l $t
+		}
+	}
+	# And do then in reverse order to match longest first
+	set l [lsort -index 0 -decreasing $l]
+	scan "$ch" "%c" cx
+	if {$cx != $ll} {
+		if {$ll} {
+			puts $fo "		return (0);"
+		}
+	
+		puts $fo "	case '$ch':"
+		set ll $cx
+	}
+	foreach tt $l {
+		set k [lindex $tt 0]
+		puts -nonewline $fo "		if ("
+		for {set i 0} {$i < [string length $k]} {incr i} {
+			if {$i > 0} {
+				puts -nonewline $fo " && "
+				if {![expr $i % 3]} {
+					puts -nonewline $fo "\n\t\t    "
+				}
+			}
+			puts -nonewline $fo "p\[$i\] == '[string index $k $i]'"
+		}
+		if {[lindex $tt 2]} {
+			if {![expr $i % 3]} {
+				puts -nonewline $fo "\n\t\t    "
+			}
+			puts -nonewline $fo " && !isvar(p\[$i\])"
+		}
+		puts $fo ") {"
+		puts $fo "			*q = p + [string length $k];"
+		puts $fo "			return ([lindex $tt 1]);"
+		puts $fo "		}"
+	}
+} 
+puts $fo "		return (0);"
+puts $fo "	default:"
+puts $fo "		return (0);"
+puts $fo "	}"
+puts $fo "}"
+
+puts $fo ""
+puts $fo "const char *vcl_tnames\[256\];\n"
+puts $fo "void"
+puts $fo "vcl_init_tnames(void)"
+puts $fo "{"
+foreach i $token2 {
+	puts $fo "\tvcl_tnames\[[lindex $i 0]\] = \"[lindex $i 0]\";"
+}
+foreach i $tokens {
+	puts $fo "\tvcl_tnames\[[lindex $i 0]\] = \"[lindex $i 1]\";"
+}
+puts $fo "}"
+
+#----------------------------------------------------------------------
+# Create the C-code which emits the boilerplate definitions for the
+# generated C code output
+
+proc copy_include {n} {
+	global fo
+
+	set fi [open $n]
+	while {[gets $fi a] >= 0} {
+		regsub -all {\\} $a {\\\\} a
+		puts $fo "\tfputs(\"$a\\n\", f);"
+	}
+	close $fi
+}
+
+puts $fo ""
+puts $fo "void"
+puts $fo "vcl_output_lang_h(FILE *f)"
+puts $fo "{"
+set i 0
+foreach k $returns {
+	puts $fo "\tfputs(\"#define VCL_RET_[string toupper $k]  (1 << $i)\\n\", f);"
+	incr i
+}
+
+copy_include ../../include/vcl.h
+copy_include ../../include/vrt.h
+
+puts $fo "}"
+
+close $foh
+close $fo

Added: trunk/varnish-cache/lib/libvcl/vcc_obj.c
===================================================================
--- trunk/varnish-cache/lib/libvcl/vcc_obj.c	2006-07-21 16:25:24 UTC (rev 543)
+++ trunk/varnish-cache/lib/libvcl/vcc_obj.c	2006-07-21 18:12:56 UTC (rev 544)
@@ -0,0 +1,1843 @@
+/*
+ * $Id$
+ */
+
+#include <stdio.h>
+
+#include "vcc_compile.h"
+
+struct var vcc_be_vars[] = {
+	{ "backend.host",
+		HOSTNAME, 0,  NULL, "VRT_set_backend_hostname(backend, %s)" },
+	{ "backend.port",
+		PORTNAME, 0,  NULL, "VRT_set_backend_portname(backend, %s)" },
+};
+
+
+struct var vcc_vars[] = {
+	{ "req.request",		STRING,	  0,  "VRT_GetReq(sp)"	     },
+	{ "obj.valid",			BOOL,	  0,  "VRT_obj_valid(sp)"     },
+	{ "obj.cacheable",		BOOL,	  0,  "VRT_obj_cacheable(sp)" },
+	{ "obj.backend",		BACKEND,  0,  "VRT_obj_backend(sp)"   },
+	{ "req.http.",			HEADER,	  0,  NULL },
+#if 0
+	{ "req.ttlfactor",		FLOAT, 0,   "req->ttlfactor" },
+	{ "req.url.host",		STRING, 0,  "req->url.host" },
+	{ "req.url.path",		STRING, 0,  "req->url.path" },
+	{ "req.useragent",		STRING, 0,  "req->useragent" },
+	{ "req.backend",		BACKEND, 0, "req->backend"   },
+	{ "client.ip",			IP, 0,	    "client->ip"     },
+	{ "backend.response_time",	TIME, 0,    "backend->responsetime" },
+	{ "backend.down",		BOOL, 0,    "backend->down"  },
+	{ "backend.timeout",		TIME, 0,    "backend->timeout" },
+	{ "backend.bandwidth",		RATE, 0,    "backend->bandwidth" },
+	{ "obj.exist",			BOOL, 0,    "obj->exists" },
+	{ "obj.ttl",			TIME, 0,    "obj->ttl" },
+	{ "obj.result",			INT, 0,     "obj->result" },
+	{ "obj.size",			SIZE, 0,    "obj->size" },
+	{ "obj.usage",			INT, 0,     "obj->usage" },
+#endif
+	{ NULL,				INT, 0,	    "NULL" }
+};
+
+
+#if 0
+
+#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 <printf.h>
+#include <stdarg.h>
+#include <sbuf.h>
+#include <stdlib.h>
+#include <string.h>
+#include <queue.h>
+#include <unistd.h>
+
+#include "vcl_priv.h"
+#include "vcl_returns.h"
+#include "vcl_compile.h"
+
+#include "libvcl.h"
+
+#define ERRCHK(tl)	do { if ((tl)->err) return; } while (0)
+
+#define INDENT		2
+
+/*--------------------------------------------------------------------
+ * Consistency check
+ */
+
+static struct method {
+	const char		*name;
+	const char		*defname;
+	unsigned		returns;
+} method_tab[] = {
+#define VCL_RET_MAC(a,b,c)
+#define VCL_MET_MAC(a,b,c)	{ "vcl_"#a, "default_vcl_"#a, c },
+#include "vcl_returns.h"
+#undef VCL_MET_MAC
+#undef VCL_RET_MAC
+	{ NULL, 0U }
+};
+
+struct proccall {
+	TAILQ_ENTRY(proccall)	list;
+	struct proc		*p;
+	struct token		*t;
+};
+
+struct proc {
+	TAILQ_ENTRY(proc)	list;
+	TAILQ_HEAD(,proccall)	calls;
+	struct token		*name;
+	unsigned		returns;
+	unsigned		exists;
+	unsigned		called;
+	unsigned		active;
+	struct token		*returnt[VCL_RET_MAX];
+};
+
+/*--------------------------------------------------------------------*/
+
+
+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);
+static const char *vcc_default_vcl_b, *vcc_default_vcl_e;
+
+/*--------------------------------------------------------------------*/
+
+static void
+ErrToken(struct tokenlist *tl, struct token *t)
+{
+
+	if (t->tok == EOI)
+		sbuf_printf(tl->sb, "end of input");
+	else
+		sbuf_printf(tl->sb, "'%T'", t);
+}
+
+static void
+_ErrInternal(struct tokenlist *tl, const char *func, unsigned line)
+{
+
+	sbuf_printf(tl->sb, "VCL compiler internal error at %s():%u\n",
+	    func, line);
+	tl->err = 1;
+}
+
+#define ErrInternal(tl) _ErrInternal(tl, __func__, __LINE__)
+
+static void
+ErrWhere(struct tokenlist *tl, struct token *t)
+{
+	unsigned lin, pos, x, y;
+	const char *p, *l, *f, *b, *e;
+	
+	lin = 1;
+	pos = 0;
+	if (t->tok == METHOD)
+		return;
+	if (t->b >= vcc_default_vcl_b && t->b < vcc_default_vcl_e) {
+		f = "Default VCL code (compiled in)";
+		b = vcc_default_vcl_b;
+		e = vcc_default_vcl_e;
+	} else {
+		f = "VCL code";
+		b = tl->b;
+		e = tl->e;
+	}
+	for (l = p = b; p < t->b; p++) {
+		if (*p == '\n') {
+			lin++;
+			pos = 0;
+			l = p + 1;
+		} else if (*p == '\t') {
+			pos &= ~7;
+			pos += 8;
+		} else
+			pos++;
+	}
+	sbuf_printf(tl->sb, "In %s Line %d Pos %d\n", f, lin, pos);
+	x = y = 0;
+	for (p = l; p < e && *p != '\n'; p++) {
+		if (*p == '\t') {
+			y &= ~7;
+			y += 8;
+			while (x < y) {
+				sbuf_bcat(tl->sb, " ", 1);
+				x++;
+			}
+		} else {
+			x++;
+			y++;
+			sbuf_bcat(tl->sb, p, 1);
+		}
+	}
+	sbuf_cat(tl->sb, "\n");
+	x = y = 0;
+	for (p = l; p < e && *p != '\n'; p++) {
+		if (p >= t->b && p < t->e) {
+			sbuf_bcat(tl->sb, "#", 1);
+			x++;
+			y++;
+			continue;
+		}
+		if (*p == '\t') {
+			y &= ~7;
+			y += 8;
+		} else
+			y++;
+		while (x < y) {
+			sbuf_bcat(tl->sb, "-", 1);
+			x++;
+		}
+	}
+	sbuf_cat(tl->sb, "\n");
+	tl->err = 1;
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+NextToken(struct tokenlist *tl)
+{
+	tl->t = TAILQ_NEXT(tl->t, list);
+	if (tl->t == NULL) {
+		sbuf_printf(tl->sb,
+		    "Ran out of input, something is missing or"
+		    " maybe unbalanced (...) or {...}\n");
+		tl->err = 1;
+		return;
+	}
+}
+
+static void
+_Expect(struct tokenlist *tl, unsigned tok, int line)
+{
+	if (tl->t->tok == tok)
+		return;
+	sbuf_printf(tl->sb, "Expected %s got ", vcl_tnames[tok]);
+	ErrToken(tl, tl->t);
+	sbuf_printf(tl->sb, "\n(program line %u), at\n", line);
+	ErrWhere(tl, tl->t);
+}
+
+#define Expect(a, b) _Expect(a, b, __LINE__)
+#define ExpectErr(a, b) do { _Expect(a, b, __LINE__); ERRCHK(a);} while (0)
+
+#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 sbufs, possibly indented
+ */
+
+static void
+Fh(struct tokenlist *tl, int indent, const char *fmt, ...)
+{
+	va_list ap;
+
+	if (indent)
+		sbuf_printf(tl->fh, "%*.*s", tl->indent, tl->indent, "");
+	va_start(ap, fmt);
+	sbuf_vprintf(tl->fh, fmt, ap);
+	va_end(ap);
+}
+
+static void
+Fc(struct tokenlist *tl, int indent, const char *fmt, ...)
+{
+	va_list ap;
+
+	if (indent)
+		sbuf_printf(tl->fc, "%*.*s", tl->indent, tl->indent, "");
+	va_start(ap, fmt);
+	sbuf_vprintf(tl->fc, fmt, ap);
+	va_end(ap);
+}
+
+/*--------------------------------------------------------------------
+ * Compare token to token
+ */
+
+static int
+Teq(struct token *t1, struct token *t2)
+{
+	if (t1->e - t1->b != t2->e - t2->b)
+		return (0);
+	return (!memcmp(t1->b, t2->b, t1->e - t1->b));
+}
+
+/*--------------------------------------------------------------------
+ * Compare ID token to string, return true of match
+ */
+
+static int
+IdIs(struct token *t, const char *p)
+{
+	const char *q;
+
+	assert(t->tok == ID);
+	for (q = t->b; q < t->e && *p != '\0'; p++, q++)
+		if (*q != *p)
+			return (0);
+	if (q != t->e || *p != '\0')
+		return (0);
+	return (1);
+}
+
+/*--------------------------------------------------------------------*/
+
+static char *
+EncString(struct token *t)
+{
+	char *p, *q;
+	const char *r;
+	unsigned u;
+
+	assert(t->tok == CSTR);
+	p = malloc(t->e - t->b);
+	assert(p != NULL);
+	q = p;
+	for (r = t->b + 1; r < t->e - 1; ) {
+		if (*r != '\\') {
+			*q++ = *r++;
+			continue;
+		}
+		switch (r[1]) {
+		case 'n':	*q++ = '\n';	r += 2; break;
+		case 'r':	*q++ = '\r';	r += 2; break;
+		case 'v':	*q++ = '\v';	r += 2; break;
+		case 'f':	*q++ = '\f';	r += 2; break;
+		case 't':	*q++ = '\t';	r += 2; break;
+		case 'b':	*q++ = '\b';	r += 2; break;
+		case '0': case '1': case '2': case '3':
+		case '4': case '5': case '6': case '7':
+			u = r[1] - '0';
+			r += 2;
+			if (isdigit(r[0]) && (r[0] - '0') < 8) {
+				u <<= 3;
+				u |= r[0] - '0';
+				r++;
+				if (isdigit(r[0]) && (r[0] - '0') < 8) {
+					u <<= 3;
+					u |= r[0] - '0';
+					r++;
+				}
+			}
+			*q++ = u;
+			break;
+		default:
+			*q++ = r[1];	
+			r += 2;
+			break;
+		}
+	}
+	*q = '\0';
+	return (p);
+}
+
+
+/*--------------------------------------------------------------------
+ * Keep track of definitions and references
+ */
+
+static struct ref *
+FindRef(struct tokenlist *tl, struct token *t, enum ref_type type)
+{
+	struct ref *r;
+
+	TAILQ_FOREACH(r, &tl->refs, list) {
+		if (r->type != type)
+			continue;
+		if (Teq(r->name, t))
+			return (r);
+	}
+	r = calloc(sizeof *r, 1);
+	assert(r != NULL);
+	r->name = t;
+	r->type = type;
+	TAILQ_INSERT_TAIL(&tl->refs, r, list);
+	return (r);
+}
+
+static int
+FindRefStr(struct tokenlist *tl, const char *s, enum ref_type type)
+{
+	struct ref *r;
+
+	TAILQ_FOREACH(r, &tl->refs, list) {
+		if (r->type != type)
+			continue;
+		if (IdIs(r->name, s))
+			return (1);
+	}
+	return (0);
+}
+
+static void
+AddRef(struct tokenlist *tl, struct token *t, enum ref_type type)
+{
+
+	FindRef(tl, t, type)->refcnt++;
+}
+
+static void
+AddRefStr(struct tokenlist *tl, const char *s, enum ref_type type)
+{
+	struct token *t;
+
+	t = calloc(sizeof *t, 1);
+	t->b = s;
+	t->e = strchr(s, '\0');
+	t->tok = METHOD;
+	AddRef(tl, t, type);
+}
+
+static void
+AddDef(struct tokenlist *tl, struct token *t, enum ref_type type)
+{
+	struct ref *r;
+
+	r = FindRef(tl, t, type);
+	r->defcnt++;
+	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 (IdIs(tl->t, "ms"))
+		sc = 1e-3;
+	else if (IdIs(tl->t, "s"))
+		sc = 1.0;
+	else if (IdIs(tl->t, "m"))
+		sc = 60.0;
+	else if (IdIs(tl->t, "h"))
+		sc = 60.0 * 60.0;
+	else if (IdIs(tl->t, "d"))
+		sc = 60.0 * 60.0 * 24.0;
+	else {
+		sbuf_printf(tl->sb, "Unknown time unit ");
+		ErrToken(tl, tl->t);
+		sbuf_printf(tl->sb, ".  Legal are 's', 'm', 'h' and 'd'\n");
+		ErrWhere(tl, tl->t);
+		return (1.0);
+	}
+	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 (IdIs(tl->t, "b"))
+		sc = 1.0;
+	else if (IdIs(tl->t, "kb"))
+		sc = 1024.0;
+	else if (IdIs(tl->t, "mb") || IdIs(tl->t, "Mb"))
+		sc = 1024.0 * 1024.0;
+	else if (IdIs(tl->t, "gb") || IdIs(tl->t, "Gb"))
+		sc = 1024.0 * 1024.0 * 1024.0;
+	else {
+		sbuf_printf(tl->sb, "Unknown size unit ");
+		ErrToken(tl, tl->t);
+		sbuf_printf(tl->sb, ".  Legal are 'kb', 'mb' and 'gb'\n");
+		ErrWhere(tl, tl->t);
+		return (1.0);
+	}
+	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, '/');
+	NextToken(tl);
+	sc /= TimeUnit(tl);
+	return (sc);
+}
+
+/*--------------------------------------------------------------------
+ * Recognize and convert { CNUM } to unsigned value
+ */
+
+static 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';
+	}
+	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';
+	}
+	NextToken(tl);
+	if (tl->t->tok != '.') 
+		return (d);
+	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;
+	}
+	NextToken(tl);
+	return (d);
+}
+
+/*--------------------------------------------------------------------*/
+
+static unsigned
+IpVal(struct tokenlist *tl)
+{
+	unsigned u, v;
+	struct token *t;
+
+	t = tl->t;
+	u = UintVal(tl);
+	if (u < 256) {
+		v = u << 24;
+		Expect(tl, '.');
+		NextToken(tl);
+		t = tl->t;
+		u = UintVal(tl);
+		if (u < 256) {
+			v |= u << 16;
+			Expect(tl, '.');
+			NextToken(tl);
+			t = tl->t;
+			u = UintVal(tl);
+			if (u < 256) {
+				v |= u << 8;
+				Expect(tl, '.');
+				NextToken(tl);
+				t = tl->t;
+				u = UintVal(tl);
+				if (u < 256) {
+					v |= u;
+					return (v);
+				}
+			}
+		}
+	}
+	sbuf_printf(tl->sb, "Illegal octet in IP number\n");
+	ErrWhere(tl, t);
+	return (0);
+}
+
+/*--------------------------------------------------------------------*/
+
+static struct var *
+HeaderVar(struct tokenlist *tl __unused, struct token *t, struct var *vh)
+{
+	char *p;
+	struct var *v;
+	int i;
+
+	v = calloc(sizeof *v, 1);
+	assert(v != NULL);
+	i = t->e - t->b;
+	p = malloc(i + 1);
+	assert(p != NULL);
+	memcpy(p, t->b, i);
+	p[i] = '\0';
+	v->name = p;
+	v->fmt = STRING;
+	asprintf(&p, "VRT_GetHdr(sp, \"\\%03o%s:\")",
+	    strlen(v->name + vh->len) + 1, v->name + vh->len);
+	assert(p != NULL);
+	v->rname = p;
+	return (v);
+}
+
+/*--------------------------------------------------------------------*/
+
+static struct var *
+FindVar(struct tokenlist *tl, struct token *t, struct var *vl)
+{
+	struct var *v;
+
+	for (v = vl; v->name != NULL; v++) {
+		if (v->fmt == HEADER  && t->e - t->b <= v->len)
+			continue;
+		if (v->fmt != HEADER  && t->e - t->b != v->len)
+			continue;
+		if (memcmp(t->b, v->name, v->len))
+			continue;
+		if (v->fmt != HEADER)
+			return (v);
+		return (HeaderVar(tl, t, v));
+	}
+	sbuf_printf(tl->sb, "Unknown variable ");
+	ErrToken(tl, t);
+	sbuf_cat(tl->sb, "\nAt: ");
+	ErrWhere(tl, t);
+	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
+Cond_Ip(struct var *vp, struct tokenlist *tl)
+{
+	unsigned u;
+
+	switch (tl->t->tok) {
+	case '~':
+		NextToken(tl);
+		ExpectErr(tl, ID);
+		AddRef(tl, tl->t, R_ACL);
+		Fc(tl, 1, "ip_match(%s, acl_%T)\n", vp->rname, tl->t);
+		NextToken(tl);
+		break;
+	case T_EQ:
+	case T_NEQ:
+		Fc(tl, 1, "%s %T ", vp->rname, tl->t);
+		NextToken(tl);
+		u = IpVal(tl);
+		Fc(tl, 0, "%uU /* %u.%u.%u.%u */\n", u,
+		    (u >> 24) & 0xff, (u >> 16) & 0xff,
+		    (u >> 8) & 0xff, (u) & 0xff);
+		break;
+	default:
+		sbuf_printf(tl->sb, "Illegal condition ");
+		ErrToken(tl, tl->t);
+		sbuf_printf(tl->sb, " on IP number variable\n");
+		sbuf_printf(tl->sb, "  only '==', '!=' and '~' are legal\n");
+		ErrWhere(tl, tl->t);
+		break;
+	}
+}
+
+static void
+Cond_String(struct var *vp, struct tokenlist *tl)
+{
+
+	switch (tl->t->tok) {
+	case '~':
+		Fc(tl, 1, "string_match(%s, ", vp->rname);
+		NextToken(tl);
+		ExpectErr(tl, CSTR);
+		Fc(tl, 0, "%T)\n", tl->t);
+		NextToken(tl);
+		break;
+	case T_EQ:
+	case T_NEQ:
+		Fc(tl, 1, "%sstrcmp(%s, ",
+		    tl->t->tok == T_EQ ? "!" : "", vp->rname);
+		NextToken(tl);
+		ExpectErr(tl, CSTR);
+		Fc(tl, 0, "%T)\n", tl->t);
+		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, "%T ", tl->t);
+		NextToken(tl);
+		switch(vp->fmt) {
+		case TIME:
+			TimeVal(tl);
+			break;
+		case INT:
+			ExpectErr(tl, CNUM);
+			Fc(tl, 0, "%T ", tl->t);
+			NextToken(tl);
+			break;
+		case SIZE:
+			SizeVal(tl);
+			break;
+		default:
+			sbuf_printf(tl->sb,
+			    "No conditions available for variable '%s'\n",
+			    vp->name);
+			ErrWhere(tl, tl->t);
+			return;
+		}
+		Fc(tl, 0, "\n");
+		break;
+	default:
+		sbuf_printf(tl->sb, "Illegal condition ");
+		ErrToken(tl, tl->t);
+		sbuf_printf(tl->sb, " on integer variable\n");
+		sbuf_printf(tl->sb,
+		    "  only '==', '!=', '<', '>', '<=' and '>=' are legal\n");
+		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_2(struct tokenlist *tl)
+{
+	struct var *vp;
+
+	C(tl, ",");
+	if (tl->t->tok == '!') {
+		Fc(tl, 1, "!(\n");
+		NextToken(tl);
+	} else {
+		Fc(tl, 1, "(\n");
+	}
+	if (tl->t->tok == '(') {
+		NextToken(tl);
+		Cond_0(tl);
+		ExpectErr(tl, ')');
+		NextToken(tl);
+	} else if (tl->t->tok == VAR) {
+		vp = FindVar(tl, tl->t, vars);
+		ERRCHK(tl);
+		assert(vp != NULL);
+		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, Cond_Ip(vp, tl)); break;
+		case STRING:	L(tl, Cond_String(vp, tl)); break;
+		case TIME:	L(tl, Cond_Int(vp, tl)); break;
+		/* XXX backend == */
+		default:	
+			sbuf_printf(tl->sb,
+			    "Variable '%s'"
+			    " has no conditions that can be checked\n",
+			    vp->name);
+			ErrWhere(tl, tl->t);
+			return;
+		}
+	} else {
+		sbuf_printf(tl->sb,
+		    "Syntax error in condition, expected '(', '!' or"
+		    " variable name, found ");
+		ErrToken(tl, tl->t);
+		sbuf_printf(tl->sb, "\n");
+		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) {
+		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) {
+		NextToken(tl);
+		Fc(tl, 1, ") || (\n");
+		L(tl, Cond_1(tl));
+	}
+	Fc(tl, 1, ")\n");
+}
+
+static void
+Conditional(struct tokenlist *tl)
+{
+
+	ExpectErr(tl, '(');
+	NextToken(tl);
+	Fc(tl, 1, "(\n");
+	L(tl, Cond_0(tl));
+	ERRCHK(tl);
+	Fc(tl, 1, ")\n");
+	ExpectErr(tl, ')');
+	NextToken(tl);
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+IfStmt(struct tokenlist *tl)
+{
+
+	ExpectErr(tl, T_IF);
+	Fc(tl, 1, "if \n");
+	NextToken(tl);
+	L(tl, Conditional(tl));
+	ERRCHK(tl);
+	L(tl, Compound(tl));
+	ERRCHK(tl);
+	while (1) {
+		switch (tl->t->tok) {
+		case T_ELSE:
+			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");
+			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, u;
+	struct var *vp;
+	struct token *at;
+
+	at = tl->t;
+	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) case T_##b: \
+		Fc(tl, 1, "VRT_done(sp, VCL_RET_%s);\n", #b); \
+		tl->curproc->returns |= VCL_RET_##b; \
+		tl->curproc->returnt[c] = 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, "%T);\n", tl->t);
+			NextToken(tl);
+		} else
+			Fc(tl, 0, "(const char *)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(\"%T\");\n", tl->t);
+		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_%T(sp))\n", tl->t);
+		Fc(tl, 1, "\treturn (1);\n");
+		NextToken(tl);
+		return;
+	case T_REWRITE:
+		ExpectErr(tl, CSTR);
+		Fc(tl, 1, "VCL_rewrite(%T", tl->t);
+		NextToken(tl);
+		ExpectErr(tl, CSTR);
+		Fc(tl, 0, ", %T);\n", tl->t);
+		NextToken(tl);
+		return;
+	case T_SET:
+		ExpectErr(tl, VAR);
+		vp = FindVar(tl, tl->t, vars);
+		ERRCHK(tl);
+		assert(vp != NULL);
+		Fc(tl, 1, "%s ", vp->rname);
+		NextToken(tl);
+		switch (vp->fmt) {
+		case INT:
+		case SIZE:
+		case RATE:
+		case TIME:
+		case FLOAT:
+			Fc(tl, 0, "%T ", tl->t);
+			a = tl->t->tok;
+			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;
+		case IP:
+			if (tl->t->tok == '=') {
+				NextToken(tl);
+				u = IpVal(tl);
+				Fc(tl, 0, "= %uU; /* %u.%u.%u.%u */\n",
+				    u,
+				    (u >> 24) & 0xff,
+				    (u >> 16) & 0xff,
+				    (u >> 8) & 0xff,
+				    u & 0xff);
+				break;
+			}
+			sbuf_printf(tl->sb, "Illegal assignment operator ");
+			ErrToken(tl, tl->t);
+			sbuf_printf(tl->sb,
+			    " only '=' is legal for IP numbers\n");
+			ErrWhere(tl, tl->t);
+			return;
+		case BACKEND:
+			if (tl->t->tok == '=') {
+				NextToken(tl);
+				AddRef(tl, tl->t, R_BACKEND);
+				Fc(tl, 0, "= &VGC_backend_%T;\n", tl->t);
+				NextToken(tl);
+				break;
+			}
+			sbuf_printf(tl->sb, "Illegal assignment operator ");
+			ErrToken(tl, tl->t);
+			sbuf_printf(tl->sb,
+			    " only '=' is legal for backend\n");
+			ErrWhere(tl, tl->t);
+			return;
+		default:
+			sbuf_printf(tl->sb,
+			    "Assignments not possible for '%s'\n", vp->name);
+			ErrWhere(tl, tl->t);
+			return;
+		}
+		return;
+	default:
+		sbuf_printf(tl->sb, "Expected action, 'if' or '}'\n");
+		ErrWhere(tl, at);
+		return;
+	}
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+Acl(struct tokenlist *tl)
+{
+	unsigned u, m;
+
+	NextToken(tl);
+
+	ExpectErr(tl, ID);
+	AddDef(tl, tl->t, R_ACL);
+	Fh(tl, 0, "static struct vcl_acl acl_%T[];\n", tl->t);
+	Fc(tl, 1, "static struct vcl_acl acl_%T[] = {\n", tl->t);
+	NextToken(tl);
+
+	tl->indent += INDENT;
+
+	ExpectErr(tl, '{');
+	NextToken(tl);
+
+	while (tl->t->tok == CNUM) {
+		u = IpVal(tl);
+		if (tl->t->tok == '/') {
+			NextToken(tl);
+			ExpectErr(tl, CNUM);
+			m = UintVal(tl);
+		} else
+			m = 32;
+		ExpectErr(tl, ';');
+		NextToken(tl);
+		Fc(tl, 1, "{ %11uU, %3uU }, /* %u.%u.%u.%u/%u */\n",
+		    u, m,
+		    (u >> 24) & 0xff, (u >> 16) & 0xff,
+		    (u >> 8) & 0xff, (u) & 0xff, m);
+	}
+	ExpectErr(tl, '}');
+	Fc(tl, 1, "{ %11uU, %3uU }\n", 0, 0);
+
+	tl->indent -= INDENT;
+
+	Fc(tl, 1, "};\n\n");
+	NextToken(tl);
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+Compound(struct tokenlist *tl)
+{
+
+	ExpectErr(tl, '{');
+	Fc(tl, 1, "{\n");
+	tl->indent += INDENT;
+	C(tl, ";");
+	NextToken(tl);
+	while (1) {
+		ERRCHK(tl);
+		switch (tl->t->tok) {
+		case '{':
+			Compound(tl);
+			break;
+		case T_IF:
+			IfStmt(tl);
+			break;
+		case '}':
+			NextToken(tl);
+			tl->indent -= INDENT;
+			Fc(tl, 1, "}\n");
+			return;
+		case EOI:
+			sbuf_printf(tl->sb,
+			    "End of input while in compound statement\n");
+			tl->err = 1;
+			return;
+		default:
+			Action(tl);
+			ERRCHK(tl);
+			ExpectErr(tl, ';');
+			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)
+{
+	struct var *vp;
+	struct token *t_be = NULL;
+	struct token *t_host = NULL;
+	struct token *t_port = NULL;
+	char *host = NULL;
+	char *port = NULL;
+	const char *ep;
+
+	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_%T (VCL_conf.backend[%d])\n",
+	    tl->t, tl->nbackend);
+	Fc(tl, 0, "static void\n");
+	Fc(tl, 1, "VGC_init_backend_%T (void)\n", tl->t);
+	Fc(tl, 1, "{\n");
+	Fc(tl, 1, "\tstruct backend *backend = VGC_backend_%T;\n", tl->t);
+	Fc(tl, 1, "\tconst char *p;\n");
+	Fc(tl, 1, "\n");
+	Fc(tl, 1, "\tVRT_set_backend_name(backend, \"%T\");\n", tl->t);
+	NextToken(tl);
+	ExpectErr(tl, '{');
+	NextToken(tl);
+	while (1) {
+		if (tl->t->tok == '}')
+			break;
+		ExpectErr(tl, T_SET);
+		NextToken(tl);
+		ExpectErr(tl, VAR);
+		vp = FindVar(tl, tl->t, be_vars);
+		ERRCHK(tl);
+		assert(vp != NULL);
+		NextToken(tl);
+		ExpectErr(tl, '=');
+		NextToken(tl);
+		switch (vp->fmt) {
+		case HOSTNAME:
+			ExpectErr(tl, CSTR);
+			t_host = tl->t;
+			Fc(tl, 1, "\tp = %T;\n", tl->t);
+			Fc(tl, 1, "\t");
+			Fc(tl, 0, vp->lname, "p");
+			Fc(tl, 0, ";\n");
+			NextToken(tl);
+			break;
+		case PORTNAME:
+			ExpectErr(tl, CSTR);
+			t_port = tl->t;
+			Fc(tl, 1, "\tp = %T;\n", tl->t);
+			Fc(tl, 1, "\t");
+			Fc(tl, 0, vp->lname, "p");
+			Fc(tl, 0, ";\n");
+			NextToken(tl);
+			break;
+		default:
+			sbuf_printf(tl->sb,
+			    "Assignments not possible for '%s'\n", vp->name);
+			ErrWhere(tl, tl->t);
+			return;
+		}
+		ExpectErr(tl, ';');
+		NextToken(tl);
+	}
+	ExpectErr(tl, '}');
+	if (t_host == NULL) {
+		sbuf_printf(tl->sb, "Backend '%T' has no hostname\n", t_be);
+		ErrWhere(tl, tl->t);
+		return;
+	}
+	host = EncString(t_host);
+	ep = CheckHostPort(host, "80");
+	if (ep != NULL) {
+		sbuf_printf(tl->sb, "Backend '%T': %s\n", t_be, ep);
+		ErrWhere(tl, t_host);
+		return;
+	}
+	if (t_port != NULL) {
+		port = EncString(t_port);
+		ep = CheckHostPort(host, port);
+		if (ep != NULL) {
+			sbuf_printf(tl->sb, "Backend '%T': %s\n", t_be, ep);
+			ErrWhere(tl, t_port);
+			return;
+		}
+	}
+	
+	NextToken(tl);
+	Fc(tl, 1, "}\n");
+	Fc(tl, 0, "\n");
+	tl->nbackend++;
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+Function(struct tokenlist *tl)
+{
+
+	NextToken(tl);
+	ExpectErr(tl, ID);
+	tl->curproc = AddProc(tl, tl->t, 1);
+	tl->curproc->exists++;
+	AddDef(tl, tl->t, R_FUNC);
+	Fh(tl, 0, "static int VGC_function_%T (struct sess *sp);\n", tl->t);
+	Fc(tl, 1, "static int\n");
+	Fc(tl, 1, "VGC_function_%T (struct sess *sp)\n", tl->t);
+	NextToken(tl);
+	L(tl, Compound(tl));
+	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:
+			Acl(tl);
+			break;
+		case T_SUB:
+			Function(tl);
+			break;
+		case T_BACKEND:
+			Backend(tl);
+			break;
+		case EOI:
+			break;
+		default:
+			sbuf_printf(tl->sb,
+			    "Expected 'acl', 'sub' or 'backend', found ");
+			ErrToken(tl, tl->t);
+			sbuf_printf(tl->sb, " at\n");
+			ErrWhere(tl, tl->t);
+			return;
+		}
+	}
+}
+
+/*--------------------------------------------------------------------
+ * Add a token to the token list.
+ */
+
+static void
+AddToken(struct tokenlist *tl, unsigned tok, const char *b, const char *e)
+{
+	struct token *t;
+
+	t = calloc(sizeof *t, 1);
+	assert(t != NULL);
+	t->tok = tok;
+	t->b = b;
+	t->e = e;
+	TAILQ_INSERT_TAIL(&tl->tokens, t, list);
+	tl->t = t;
+	if (0) {
+		fprintf(stderr, "[%s %*.*s] ",
+		    vcl_tnames[tok],
+		    e - b, e - b, b);
+		if (tok == EOI)
+			fprintf(stderr, "\n");
+	}
+}
+
+/*--------------------------------------------------------------------
+ * Lexical analysis and token generation
+ */
+
+static void
+Lexer(struct tokenlist *tl, const char *b, const char *e)
+{
+	const char *p, *q;
+	unsigned u;
+
+	for (p = b; p < e; ) {
+
+		/* Skip any whitespace */
+		if (isspace(*p)) {
+			p++;
+			continue;
+		}
+
+		/* Skip '#.*\n' comments */
+		if (*p == '#') {
+			while (p < e && *p != '\n')
+				p++;
+			continue;
+		}
+
+		/* Skip C-style comments */
+		if (*p == '/' && p[1] == '*') {
+			p += 2;
+			for (p += 2; p < e; p++) {
+				if (*p == '*' && p[1] == '/') {
+					p += 2;
+					break;
+				}
+			}
+			continue;
+		}
+
+		/* Match for the fixed tokens (see token.tcl) */
+		u = vcl_fixed_token(p, &q);
+		if (u != 0) {
+			AddToken(tl, u, p, q);
+			p = q;
+			continue;
+		}
+
+		/* Match strings, with \\ and \" escapes */
+		if (*p == '"') {
+			for (q = p + 1; q < e; q++) {
+				if (*q == '\\' && q[1] == '\\')
+					q++;
+				else if (*q == '\\' && q[1] == '"')
+					q++;
+				else if (*q == '"') {
+					q++;
+					break;
+				}
+			}
+			AddToken(tl, CSTR, p, q);
+			p = q;
+			continue;
+		}
+
+		/* Match Identifiers */
+		if (isident1(*p)) {
+			for (q = p; q < e; q++)
+				if (!isident(*q))
+					break;
+			if (isvar(*q)) {
+				for (; q < e; q++)
+					if (!isvar(*q))
+						break;
+				AddToken(tl, VAR, p, q);
+			} else {
+				AddToken(tl, ID, p, q);
+			}
+			p = q;
+			continue;
+		}
+
+		/* Match numbers { [0-9]+ } */
+		if (isdigit(*p)) {
+			for (q = p; q < e; q++)
+				if (!isdigit(*q))
+					break;
+			AddToken(tl, CNUM, p, q);
+			p = q;
+			continue;
+		}
+		AddToken(tl, EOI, p, p + 1);
+		sbuf_printf(tl->sb, "Syntax error at\n");
+		ErrWhere(tl, tl->t);
+		return;
+	}
+}
+
+/*--------------------------------------------------------------------
+ * Consistency check
+ */
+
+static struct proc *
+AddProc(struct tokenlist *tl, struct token *t, int def)
+{
+	struct proc *p;
+
+	TAILQ_FOREACH(p, &tl->procs, list) {
+		if (!Teq(p->name, t)) 
+			continue;
+		if (def)
+			p->name = t;
+		return (p);
+	}
+	p = calloc(sizeof *p, 1);
+	assert(p != NULL);
+	p->name = t;
+	TAILQ_INIT(&p->calls);
+	TAILQ_INSERT_TAIL(&tl->procs, p, list);
+	return (p);
+}
+
+static void
+AddCall(struct tokenlist *tl, struct token *t)
+{
+	struct proccall *pc;
+	struct proc *p;
+
+	p = AddProc(tl, t, 0);
+	TAILQ_FOREACH(pc, &tl->curproc->calls, list) {
+		if (pc->p == p)
+			return;
+	}
+	pc = calloc(sizeof *pc, 1);
+	assert(pc != NULL);
+	pc->p = p;
+	pc->t = t;
+	TAILQ_INSERT_TAIL(&tl->curproc->calls, pc, list);
+}
+
+static int
+Consist_Decend(struct tokenlist *tl, struct proc *p, unsigned returns)
+{
+	unsigned u;
+	struct proccall *pc;
+
+	if (!p->exists) {
+		sbuf_printf(tl->sb, "Function %T does not exist\n", p->name);
+		return (1);
+	}
+	if (p->active) {
+		sbuf_printf(tl->sb, "Function recurses on\n");
+		ErrWhere(tl, p->name);
+		return (1);
+	}
+	u = p->returns & ~returns;
+	if (u) {
+#define VCL_RET_MAC(a, b, c) \
+		if (u & VCL_RET_##b) { \
+			sbuf_printf(tl->sb, "Illegal return for method\n"); \
+			ErrWhere(tl, p->returnt[c]); \
+		} 
+#include "vcl_returns.h"
+#undef VCL_RET_MAC
+		sbuf_printf(tl->sb, "In function\n");
+		ErrWhere(tl, p->name);
+		return (1);
+	}
+	p->active = 1;
+	TAILQ_FOREACH(pc, &p->calls, list) {
+		if (Consist_Decend(tl, pc->p, returns)) {
+			sbuf_printf(tl->sb, "\nCalled from\n");
+			ErrWhere(tl, p->name);
+			sbuf_printf(tl->sb, "at\n");
+			ErrWhere(tl, pc->t);
+			return (1);
+		}
+	}
+	p->active = 0;
+	p->called++;
+	return (0);
+}
+
+static int
+Consistency(struct tokenlist *tl)
+{
+	struct proc *p;
+	struct method *m;
+
+	TAILQ_FOREACH(p, &tl->procs, list) {
+		for(m = method_tab; m->name != NULL; m++) {
+			if (IdIs(p->name, m->defname))
+				p->called = 1;
+			if (IdIs(p->name, m->name))
+				break;
+		}
+		if (m->name == NULL) 
+			continue;
+		if (Consist_Decend(tl, p, m->returns)) {
+			sbuf_printf(tl->sb,
+			    "\nwhich is a %s method\n", m->name);
+			return (1);
+		}
+	}
+	TAILQ_FOREACH(p, &tl->procs, list) {
+		if (p->called)
+			continue;
+		sbuf_printf(tl->sb, "Function unused\n");
+		ErrWhere(tl, p->name);
+		return (1);
+	}
+	return (0);
+}
+
+/*--------------------------------------------------------------------*/
+
+static int
+CheckRefs(struct tokenlist *tl)
+{
+	struct ref *r;
+	const char *type;
+	int nerr = 0;
+
+	TAILQ_FOREACH(r, &tl->refs, list) {
+		if (r->defcnt != 0 && r->refcnt != 0)
+			continue;
+		nerr++;
+
+		switch(r->type) {
+		case R_FUNC:
+			type = "function";
+			break;
+		case R_ACL:
+			type = "acl";
+			break;
+		case R_BACKEND:
+			type = "backend";
+			break;
+		default:
+			ErrInternal(tl);
+			sbuf_printf(tl->sb, "Ref ");
+			ErrToken(tl, r->name);
+			sbuf_printf(tl->sb, " has unknown type %d\n",
+			    r->type);
+			continue;
+		}
+		if (r->defcnt == 0 && r->name->tok == METHOD) {
+			sbuf_printf(tl->sb,
+			    "No definition for method %T\n", r->name);
+			continue;
+		}
+
+		if (r->defcnt == 0) {
+			sbuf_printf(tl->sb,
+			    "Undefined %s %T, first reference:\n",
+			    type, r->name);
+			ErrWhere(tl, r->name);
+			continue;
+		} 
+
+		sbuf_printf(tl->sb, "Unused %s %T, defined:\n", type, r->name);
+		ErrWhere(tl, r->name);
+	}
+	return (nerr);
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+LocTable(struct tokenlist *tl)
+{
+	struct token *t;
+	unsigned lin, pos;
+	const char *p;
+	
+	Fh(tl, 0, "#define VGC_NREFS %u\n", tl->cnt + 1);
+	Fh(tl, 0, "static struct vrt_ref VGC_ref[VGC_NREFS];\n");
+	Fc(tl, 0, "static struct vrt_ref VGC_ref[VGC_NREFS] = {\n");
+	lin = 1;
+	pos = 0;
+	p = tl->b;
+	TAILQ_FOREACH(t, &tl->tokens, list) {
+		if (t->cnt == 0)
+			continue;
+		for (;p < t->b; p++) {
+			if (*p == '\n') {
+				lin++;
+				pos = 0;
+			} else if (*p == '\t') {
+				pos &= ~7;
+				pos += 8;
+			} else
+				pos++;
+		
+		}
+		Fc(tl, 0, "  [%3u] = { %4u, %3u, 0, \"%T\" },\n",
+		    t->cnt, lin, pos + 1, t);
+	}
+	Fc(tl, 0, "};\n");
+}
+
+
+/*--------------------------------------------------------------------*/
+
+static void
+EmitInitFunc(struct tokenlist *tl)
+{
+	struct ref *r;
+
+	Fc(tl, 0, "\nstatic void\nVGC_Init(void)\n{\n\n");
+	Fc(tl, 0, "\tVRT_alloc_backends(&VCL_conf);\n");
+	
+	TAILQ_FOREACH(r, &tl->refs, list) {
+		switch(r->type) {
+		case R_FUNC:
+			break;
+		case R_ACL:
+			break;
+		case R_BACKEND:
+			Fc(tl, 0, "\tVGC_init_backend_%T();\n", r->name);
+			break;
+		}
+	}
+	Fc(tl, 0, "}\n");
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+EmitStruct(struct tokenlist *tl)
+{
+
+	Fc(tl, 0, "\nstruct VCL_conf VCL_conf = {\n");
+	Fc(tl, 0, "\t.magic = VCL_CONF_MAGIC,\n");
+	Fc(tl, 0, "\t.init_func = VGC_Init,\n");
+	Fc(tl, 0, "\t.nbackend = %d,\n", tl->nbackend);
+	Fc(tl, 0, "\t.ref = VGC_ref,\n");
+	Fc(tl, 0, "\t.nref = VGC_NREFS,\n");
+#define VCL_RET_MAC(l,u,b)
+#define VCL_MET_MAC(l,u,b) \
+	if (FindRefStr(tl, "vcl_" #l, R_FUNC)) { \
+		Fc(tl, 0, "\t." #l "_func = VGC_function_vcl_" #l ",\n"); \
+		AddRefStr(tl, "vcl_" #l, R_FUNC); \
+	} else { \
+		Fc(tl, 0, "\t." #l "_func = VGC_function_default_vcl_" #l ",\n"); \
+	} \
+	AddRefStr(tl, "default_vcl_" #l, R_FUNC);
+#include "vcl_returns.h"
+#undef VCL_MET_MAC
+#undef VCL_RET_MAC
+	Fc(tl, 0, "};\n");
+}
+
+/*--------------------------------------------------------------------*/
+
+char *
+VCC_Compile(struct sbuf *sb, const char *b, const char *e)
+{
+	struct tokenlist tokens;
+	struct ref *r;
+	struct token *t;
+	FILE *fo;
+	char *of = NULL;
+	char buf[BUFSIZ];
+
+	memset(&tokens, 0, sizeof tokens);
+	TAILQ_INIT(&tokens.tokens);
+	TAILQ_INIT(&tokens.refs);
+	TAILQ_INIT(&tokens.procs);
+	tokens.sb = sb;
+
+	tokens.fc = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND);
+	assert(tokens.fc != NULL);
+
+	tokens.fh = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND);
+	assert(tokens.fh != NULL);
+
+	Fh(&tokens, 0, "extern struct VCL_conf VCL_conf;\n");
+
+	tokens.b = b;
+	if (e == NULL)
+		e = strchr(b, '\0');
+	assert(e != NULL);
+	tokens.e = e;
+	Lexer(&tokens, b, e);
+	Lexer(&tokens, vcc_default_vcl_b, vcc_default_vcl_e);
+	AddToken(&tokens, EOI, e, e);
+	if (tokens.err)
+		goto done;
+	tokens.t = TAILQ_FIRST(&tokens.tokens);
+	Parse(&tokens);
+	if (tokens.err)
+		goto done;
+	Consistency(&tokens);
+	if (tokens.err)
+		goto done;
+	LocTable(&tokens);
+
+	EmitInitFunc(&tokens);
+
+	EmitStruct(&tokens);
+
+	if (CheckRefs(&tokens))
+		goto done;
+
+	of = strdup("/tmp/vcl.XXXXXXXX");
+	assert(of != NULL);
+	mktemp(of);
+
+	sprintf(buf, 
+	    "tee /tmp/_.c |"
+	    "cc -fpic -shared -Wl,-x -o %s -x c - ", of);
+
+	fo = popen(buf, "w");
+	assert(fo != NULL);
+
+	vcl_output_lang_h(fo);
+
+	sbuf_finish(tokens.fh);
+	fputs(sbuf_data(tokens.fh), fo);
+	sbuf_delete(tokens.fh);
+
+	sbuf_finish(tokens.fc);
+	fputs(sbuf_data(tokens.fc), fo);
+	sbuf_delete(tokens.fc);
+
+	pclose(fo);
+done:
+
+	/* Free References */
+	while (!TAILQ_EMPTY(&tokens.refs)) {
+		r = TAILQ_FIRST(&tokens.refs);
+		TAILQ_REMOVE(&tokens.refs, r, list);
+		free(r);
+	}
+
+	/* Free Tokens */
+	while (!TAILQ_EMPTY(&tokens.tokens)) {
+		t = TAILQ_FIRST(&tokens.tokens);
+		TAILQ_REMOVE(&tokens.tokens, t, list);
+		free(t);
+	}
+	return (of);
+}
+
+/*--------------------------------------------------------------------*/
+
+char *
+VCC_CompileFile(struct sbuf *sb, const char *fn)
+{
+	char *f, *r;
+	int fd, i;
+	struct stat st;
+
+	fd = open(fn, O_RDONLY);
+	if (fd < 0) {
+		sbuf_printf(sb, "Cannot open file '%s': %s",
+		    fn, strerror(errno));
+		return (NULL);
+	}
+	assert(0 == fstat(fd, &st));
+	f = malloc(st.st_size + 1);
+	assert(f != NULL);
+	i = read(fd, f, st.st_size); 
+	assert(i == st.st_size);
+	f[i] = '\0';
+	r = VCC_Compile(sb, f, NULL);
+	free(f);
+	return (r);
+}
+
+/*--------------------------------------------------------------------*/
+
+static int
+VCC_T_render(FILE *f, const struct printf_info *info __unused, const void *const *args)
+{
+	const struct token *t;
+
+	t = *((const struct token * const*) (args[0]));
+	return (fprintf(f, "%*.*s",
+	    t->e - t->b, t->e - t->b, t->b));
+}
+     
+static int
+VCC_T_arginfo(const struct printf_info *info __unused, size_t n, int *argtypes)
+{
+
+	if (n > 0)
+		argtypes[0] = PA_POINTER;
+	return 1;
+}
+     
+/*--------------------------------------------------------------------*/
+
+void
+VCC_InitCompile(const char *default_vcl)
+{
+	struct var *v;
+
+	vcc_default_vcl_b = default_vcl;
+	vcc_default_vcl_e = strchr(default_vcl, '\0');
+	assert(vcc_default_vcl_e != NULL);
+	
+	register_printf_function ('T', VCC_T_render, VCC_T_arginfo);
+	vcl_init_tnames();
+	for (v = vars; v->name != NULL; v++)
+		v->len = strlen(v->name);
+	for (v = be_vars; v->name != NULL; v++)
+		v->len = strlen(v->name);
+}
+
+#endif

Copied: trunk/varnish-cache/lib/libvcl/vcc_priv.h (from rev 480, trunk/varnish-cache/lib/libvcl/vcl_priv.h)
===================================================================
--- trunk/varnish-cache/lib/libvcl/vcl_priv.h	2006-07-14 13:54:41 UTC (rev 480)
+++ trunk/varnish-cache/lib/libvcl/vcc_priv.h	2006-07-21 18:12:56 UTC (rev 544)
@@ -0,0 +1,13 @@
+/*
+ * Stuff shared between main.c and fixed_token.c
+ */
+
+#include "vcc_token_defs.h"
+
+#define isident1(c) (isalpha(c))
+#define isident(c) (isalpha(c) || isdigit(c) || (c) == '_')
+#define isvar(c) (isident(c) || (c) == '.')
+unsigned vcl_fixed_token(const char *p, const char **q);
+extern const char *vcl_tnames[256];
+void vcl_init_tnames(void);
+void vcl_output_lang_h(FILE *f);

Added: trunk/varnish-cache/lib/libvcl/vcc_token.c
===================================================================
--- trunk/varnish-cache/lib/libvcl/vcc_token.c	2006-07-21 16:25:24 UTC (rev 543)
+++ trunk/varnish-cache/lib/libvcl/vcc_token.c	2006-07-21 18:12:56 UTC (rev 544)
@@ -0,0 +1,312 @@
+/*
+ * $Id$
+ */
+
+#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 <printf.h>
+#include <stdarg.h>
+#include <sbuf.h>
+#include <stdlib.h>
+#include <string.h>
+#include <queue.h>
+#include <unistd.h>
+
+#include "vcc_priv.h"
+#include "vcl_returns.h"
+#include "vcc_compile.h"
+
+#include "libvcl.h"
+
+#define ERRCHK(tl)	do { if ((tl)->err) return; } while (0)
+
+#define INDENT		2
+
+/*--------------------------------------------------------------------*/
+
+void
+vcc_ErrToken(struct tokenlist *tl, struct token *t)
+{
+
+	if (t->tok == EOI)
+		sbuf_printf(tl->sb, "end of input");
+	else
+		sbuf_printf(tl->sb, "'%T'", t);
+}
+
+void
+vcc__ErrInternal(struct tokenlist *tl, const char *func, unsigned line)
+{
+
+	sbuf_printf(tl->sb, "VCL compiler internal error at %s():%u\n",
+	    func, line);
+	tl->err = 1;
+}
+
+void
+vcc_ErrWhere(struct tokenlist *tl, struct token *t)
+{
+	unsigned lin, pos, x, y;
+	const char *p, *l, *f, *b, *e;
+	
+	lin = 1;
+	pos = 0;
+	if (t->tok == METHOD)
+		return;
+	if (t->b >= vcc_default_vcl_b && t->b < vcc_default_vcl_e) {
+		f = "Default VCL code (compiled in)";
+		b = vcc_default_vcl_b;
+		e = vcc_default_vcl_e;
+	} else {
+		f = "VCL code";
+		b = tl->b;
+		e = tl->e;
+	}
+	for (l = p = b; p < t->b; p++) {
+		if (*p == '\n') {
+			lin++;
+			pos = 0;
+			l = p + 1;
+		} else if (*p == '\t') {
+			pos &= ~7;
+			pos += 8;
+		} else
+			pos++;
+	}
+	sbuf_printf(tl->sb, "In %s Line %d Pos %d\n", f, lin, pos);
+	x = y = 0;
+	for (p = l; p < e && *p != '\n'; p++) {
+		if (*p == '\t') {
+			y &= ~7;
+			y += 8;
+			while (x < y) {
+				sbuf_bcat(tl->sb, " ", 1);
+				x++;
+			}
+		} else {
+			x++;
+			y++;
+			sbuf_bcat(tl->sb, p, 1);
+		}
+	}
+	sbuf_cat(tl->sb, "\n");
+	x = y = 0;
+	for (p = l; p < e && *p != '\n'; p++) {
+		if (p >= t->b && p < t->e) {
+			sbuf_bcat(tl->sb, "#", 1);
+			x++;
+			y++;
+			continue;
+		}
+		if (*p == '\t') {
+			y &= ~7;
+			y += 8;
+		} else
+			y++;
+		while (x < y) {
+			sbuf_bcat(tl->sb, "-", 1);
+			x++;
+		}
+	}
+	sbuf_cat(tl->sb, "\n");
+	tl->err = 1;
+}
+
+/*--------------------------------------------------------------------*/
+
+void
+vcc_NextToken(struct tokenlist *tl)
+{
+	tl->t = TAILQ_NEXT(tl->t, list);
+	if (tl->t == NULL) {
+		sbuf_printf(tl->sb,
+		    "Ran out of input, something is missing or"
+		    " maybe unbalanced (...) or {...}\n");
+		tl->err = 1;
+		return;
+	}
+}
+
+void
+vcc__Expect(struct tokenlist *tl, unsigned tok, int line)
+{
+	if (tl->t->tok == tok)
+		return;
+	sbuf_printf(tl->sb, "Expected %s got ", vcl_tnames[tok]);
+	vcc_ErrToken(tl, tl->t);
+	sbuf_printf(tl->sb, "\n(program line %u), at\n", line);
+	vcc_ErrWhere(tl, tl->t);
+}
+
+#define Expect(a, b) _Expect(a, b, __LINE__)
+#define ExpectErr(a, b) do { _Expect(a, b, __LINE__); ERRCHK(a);} while (0)
+
+#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)
+	
+
+/*--------------------------------------------------------------------
+ * Compare token to token
+ */
+
+int
+vcc_Teq(struct token *t1, struct token *t2)
+{
+	if (t1->e - t1->b != t2->e - t2->b)
+		return (0);
+	return (!memcmp(t1->b, t2->b, t1->e - t1->b));
+}
+
+/*--------------------------------------------------------------------
+ * Compare ID token to string, return true of match
+ */
+
+int
+vcc_IdIs(struct token *t, const char *p)
+{
+	const char *q;
+
+	assert(t->tok == ID);
+	for (q = t->b; q < t->e && *p != '\0'; p++, q++)
+		if (*q != *p)
+			return (0);
+	if (q != t->e || *p != '\0')
+		return (0);
+	return (1);
+}
+
+/*--------------------------------------------------------------------
+ * Add a token to the token list.
+ */
+
+void
+vcc_AddToken(struct tokenlist *tl, unsigned tok, const char *b, const char *e)
+{
+	struct token *t;
+
+	t = calloc(sizeof *t, 1);
+	assert(t != NULL);
+	t->tok = tok;
+	t->b = b;
+	t->e = e;
+	TAILQ_INSERT_TAIL(&tl->tokens, t, list);
+	tl->t = t;
+	if (0) {
+		fprintf(stderr, "[%s %*.*s] ",
+		    vcl_tnames[tok],
+		    e - b, e - b, b);
+		if (tok == EOI)
+			fprintf(stderr, "\n");
+	}
+}
+
+/*--------------------------------------------------------------------
+ * Lexical analysis and token generation
+ */
+
+void
+vcc_Lexer(struct tokenlist *tl, const char *b, const char *e)
+{
+	const char *p, *q;
+	unsigned u;
+
+	for (p = b; p < e; ) {
+
+		/* Skip any whitespace */
+		if (isspace(*p)) {
+			p++;
+			continue;
+		}
+
+		/* Skip '#.*\n' comments */
+		if (*p == '#') {
+			while (p < e && *p != '\n')
+				p++;
+			continue;
+		}
+
+		/* Skip C-style comments */
+		if (*p == '/' && p[1] == '*') {
+			p += 2;
+			for (p += 2; p < e; p++) {
+				if (*p == '*' && p[1] == '/') {
+					p += 2;
+					break;
+				}
+			}
+			continue;
+		}
+
+		/* Match for the fixed tokens (see token.tcl) */
+		u = vcl_fixed_token(p, &q);
+		if (u != 0) {
+			vcc_AddToken(tl, u, p, q);
+			p = q;
+			continue;
+		}
+
+		/* Match strings, with \\ and \" escapes */
+		if (*p == '"') {
+			for (q = p + 1; q < e; q++) {
+				if (*q == '\\' && q[1] == '\\')
+					q++;
+				else if (*q == '\\' && q[1] == '"')
+					q++;
+				else if (*q == '"') {
+					q++;
+					break;
+				}
+			}
+			vcc_AddToken(tl, CSTR, p, q);
+			p = q;
+			continue;
+		}
+
+		/* Match Identifiers */
+		if (isident1(*p)) {
+			for (q = p; q < e; q++)
+				if (!isident(*q))
+					break;
+			if (isvar(*q)) {
+				for (; q < e; q++)
+					if (!isvar(*q))
+						break;
+				vcc_AddToken(tl, VAR, p, q);
+			} else {
+				vcc_AddToken(tl, ID, p, q);
+			}
+			p = q;
+			continue;
+		}
+
+		/* Match numbers { [0-9]+ } */
+		if (isdigit(*p)) {
+			for (q = p; q < e; q++)
+				if (!isdigit(*q))
+					break;
+			vcc_AddToken(tl, CNUM, p, q);
+			p = q;
+			continue;
+		}
+		vcc_AddToken(tl, EOI, p, p + 1);
+		sbuf_printf(tl->sb, "Syntax error at\n");
+		vcc_ErrWhere(tl, tl->t);
+		return;
+	}
+}

Copied: trunk/varnish-cache/lib/libvcl/vcc_token_defs.h (from rev 480, trunk/varnish-cache/lib/libvcl/vcl_token_defs.h)
===================================================================
--- trunk/varnish-cache/lib/libvcl/vcl_token_defs.h	2006-07-14 13:54:41 UTC (rev 480)
+++ trunk/varnish-cache/lib/libvcl/vcc_token_defs.h	2006-07-21 18:12:56 UTC (rev 544)
@@ -0,0 +1,53 @@
+/*
+ * $Id$
+ *
+ * NB:  This file is machine generated, DO NOT EDIT!
+ *
+ * Edit vcc_gen_fixed_token.tcl instead
+ */
+
+#define LOW_TOKEN 128
+#define T_IF 128
+#define T_ELSE 129
+#define T_ELSEIF 130
+#define T_ELSIF 131
+#define T_FUNC 132
+#define T_PROC 133
+#define T_SUB 134
+#define T_ACL 135
+#define T_BACKEND 136
+#define T_CALL 137
+#define T_NO_CACHE 138
+#define T_NO_NEW_CACHE 139
+#define T_SET 140
+#define T_REWRITE 141
+#define T_SWITCH_CONFIG 142
+#define T_ERROR 143
+#define T_LOOKUP 144
+#define T_PIPE 145
+#define T_PASS 146
+#define T_INSERT_PASS 147
+#define T_FETCH 148
+#define T_INSERT 149
+#define T_DELIVER 150
+#define T_DISCARD 151
+#define T_INC 152
+#define T_DEC 153
+#define T_CAND 154
+#define T_COR 155
+#define T_LEQ 156
+#define T_EQ 157
+#define T_NEQ 158
+#define T_GEQ 159
+#define T_SHR 160
+#define T_SHL 161
+#define T_INCR 162
+#define T_DECR 163
+#define T_MUL 164
+#define T_DIV 165
+#define ID 166
+#define VAR 167
+#define CNUM 168
+#define CSTR 169
+#define EOI 170
+#define METHOD 171

Deleted: trunk/varnish-cache/lib/libvcl/vcl_fixed_token.c
===================================================================
--- trunk/varnish-cache/lib/libvcl/vcl_fixed_token.c	2006-07-21 16:25:24 UTC (rev 543)
+++ trunk/varnish-cache/lib/libvcl/vcl_fixed_token.c	2006-07-21 18:12:56 UTC (rev 544)
@@ -1,518 +0,0 @@
-/*
- * $Id$
- *
- * NB:  This file is machine generated, DO NOT EDIT!
- *
- * Edit vcl_gen_fixed_token.tcl instead
- */
-
-#include <stdio.h>
-#include <ctype.h>
-#include "vcl_priv.h"
-
-unsigned
-vcl_fixed_token(const char *p, const char **q)
-{
-
-	switch (p[0]) {
-	case '!':
-		if (p[0] == '!' && p[1] == '=') {
-			*q = p + 2;
-			return (T_NEQ);
-		}
-		if (p[0] == '!') {
-			*q = p + 1;
-			return ('!');
-		}
-		return (0);
-	case '%':
-		if (p[0] == '%') {
-			*q = p + 1;
-			return ('%');
-		}
-		return (0);
-	case '&':
-		if (p[0] == '&' && p[1] == '&') {
-			*q = p + 2;
-			return (T_CAND);
-		}
-		if (p[0] == '&') {
-			*q = p + 1;
-			return ('&');
-		}
-		return (0);
-	case '(':
-		if (p[0] == '(') {
-			*q = p + 1;
-			return ('(');
-		}
-		return (0);
-	case ')':
-		if (p[0] == ')') {
-			*q = p + 1;
-			return (')');
-		}
-		return (0);
-	case '*':
-		if (p[0] == '*' && p[1] == '=') {
-			*q = p + 2;
-			return (T_MUL);
-		}
-		if (p[0] == '*') {
-			*q = p + 1;
-			return ('*');
-		}
-		return (0);
-	case '+':
-		if (p[0] == '+' && p[1] == '=') {
-			*q = p + 2;
-			return (T_INCR);
-		}
-		if (p[0] == '+' && p[1] == '+') {
-			*q = p + 2;
-			return (T_INC);
-		}
-		if (p[0] == '+') {
-			*q = p + 1;
-			return ('+');
-		}
-		return (0);
-	case ',':
-		if (p[0] == ',') {
-			*q = p + 1;
-			return (',');
-		}
-		return (0);
-	case '-':
-		if (p[0] == '-' && p[1] == '-') {
-			*q = p + 2;
-			return (T_DEC);
-		}
-		if (p[0] == '-') {
-			*q = p + 1;
-			return ('-');
-		}
-		return (0);
-	case '.':
-		if (p[0] == '.') {
-			*q = p + 1;
-			return ('.');
-		}
-		return (0);
-	case '/':
-		if (p[0] == '/' && p[1] == '=') {
-			*q = p + 2;
-			return (T_DECR);
-		}
-		if (p[0] == '/' && p[1] == '=') {
-			*q = p + 2;
-			return (T_DIV);
-		}
-		if (p[0] == '/') {
-			*q = p + 1;
-			return ('/');
-		}
-		return (0);
-	case ';':
-		if (p[0] == ';') {
-			*q = p + 1;
-			return (';');
-		}
-		return (0);
-	case '<':
-		if (p[0] == '<' && p[1] == '=') {
-			*q = p + 2;
-			return (T_LEQ);
-		}
-		if (p[0] == '<' && p[1] == '<') {
-			*q = p + 2;
-			return (T_SHL);
-		}
-		if (p[0] == '<') {
-			*q = p + 1;
-			return ('<');
-		}
-		return (0);
-	case '=':
-		if (p[0] == '=' && p[1] == '=') {
-			*q = p + 2;
-			return (T_EQ);
-		}
-		if (p[0] == '=') {
-			*q = p + 1;
-			return ('=');
-		}
-		return (0);
-	case '>':
-		if (p[0] == '>' && p[1] == '>') {
-			*q = p + 2;
-			return (T_SHR);
-		}
-		if (p[0] == '>' && p[1] == '=') {
-			*q = p + 2;
-			return (T_GEQ);
-		}
-		if (p[0] == '>') {
-			*q = p + 1;
-			return ('>');
-		}
-		return (0);
-	case 'a':
-		if (p[0] == 'a' && p[1] == 'c' && p[2] == 'l'
-		     && !isvar(p[3])) {
-			*q = p + 3;
-			return (T_ACL);
-		}
-		return (0);
-	case 'b':
-		if (p[0] == 'b' && p[1] == 'a' && p[2] == 'c' && 
-		    p[3] == 'k' && p[4] == 'e' && p[5] == 'n' && 
-		    p[6] == 'd' && !isvar(p[7])) {
-			*q = p + 7;
-			return (T_BACKEND);
-		}
-		return (0);
-	case 'c':
-		if (p[0] == 'c' && p[1] == 'a' && p[2] == 'l' && 
-		    p[3] == 'l' && !isvar(p[4])) {
-			*q = p + 4;
-			return (T_CALL);
-		}
-		return (0);
-	case 'd':
-		if (p[0] == 'd' && p[1] == 'i' && p[2] == 's' && 
-		    p[3] == 'c' && p[4] == 'a' && p[5] == 'r' && 
-		    p[6] == 'd' && !isvar(p[7])) {
-			*q = p + 7;
-			return (T_DISCARD);
-		}
-		if (p[0] == 'd' && p[1] == 'e' && p[2] == 'l' && 
-		    p[3] == 'i' && p[4] == 'v' && p[5] == 'e' && 
-		    p[6] == 'r' && !isvar(p[7])) {
-			*q = p + 7;
-			return (T_DELIVER);
-		}
-		return (0);
-	case 'e':
-		if (p[0] == 'e' && p[1] == 'r' && p[2] == 'r' && 
-		    p[3] == 'o' && p[4] == 'r' && !isvar(p[5])) {
-			*q = p + 5;
-			return (T_ERROR);
-		}
-		if (p[0] == 'e' && p[1] == 'l' && p[2] == 's' && 
-		    p[3] == 'i' && p[4] == 'f' && !isvar(p[5])) {
-			*q = p + 5;
-			return (T_ELSIF);
-		}
-		if (p[0] == 'e' && p[1] == 'l' && p[2] == 's' && 
-		    p[3] == 'e' && p[4] == 'i' && p[5] == 'f'
-		     && !isvar(p[6])) {
-			*q = p + 6;
-			return (T_ELSEIF);
-		}
-		if (p[0] == 'e' && p[1] == 'l' && p[2] == 's' && 
-		    p[3] == 'e' && !isvar(p[4])) {
-			*q = p + 4;
-			return (T_ELSE);
-		}
-		return (0);
-	case 'f':
-		if (p[0] == 'f' && p[1] == 'u' && p[2] == 'n' && 
-		    p[3] == 'c' && !isvar(p[4])) {
-			*q = p + 4;
-			return (T_FUNC);
-		}
-		if (p[0] == 'f' && p[1] == 'e' && p[2] == 't' && 
-		    p[3] == 'c' && p[4] == 'h' && !isvar(p[5])) {
-			*q = p + 5;
-			return (T_FETCH);
-		}
-		return (0);
-	case 'i':
-		if (p[0] == 'i' && p[1] == 'n' && p[2] == 's' && 
-		    p[3] == 'e' && p[4] == 'r' && p[5] == 't' && 
-		    p[6] == '_' && p[7] == 'p' && p[8] == 'a' && 
-		    p[9] == 's' && p[10] == 's' && !isvar(p[11])) {
-			*q = p + 11;
-			return (T_INSERT_PASS);
-		}
-		if (p[0] == 'i' && p[1] == 'n' && p[2] == 's' && 
-		    p[3] == 'e' && p[4] == 'r' && p[5] == 't'
-		     && !isvar(p[6])) {
-			*q = p + 6;
-			return (T_INSERT);
-		}
-		if (p[0] == 'i' && p[1] == 'f' && !isvar(p[2])) {
-			*q = p + 2;
-			return (T_IF);
-		}
-		return (0);
-	case 'l':
-		if (p[0] == 'l' && p[1] == 'o' && p[2] == 'o' && 
-		    p[3] == 'k' && p[4] == 'u' && p[5] == 'p'
-		     && !isvar(p[6])) {
-			*q = p + 6;
-			return (T_LOOKUP);
-		}
-		return (0);
-	case 'n':
-		if (p[0] == 'n' && p[1] == 'o' && p[2] == '_' && 
-		    p[3] == 'n' && p[4] == 'e' && p[5] == 'w' && 
-		    p[6] == '_' && p[7] == 'c' && p[8] == 'a' && 
-		    p[9] == 'c' && p[10] == 'h' && p[11] == 'e'
-		     && !isvar(p[12])) {
-			*q = p + 12;
-			return (T_NO_NEW_CACHE);
-		}
-		if (p[0] == 'n' && p[1] == 'o' && p[2] == '_' && 
-		    p[3] == 'c' && p[4] == 'a' && p[5] == 'c' && 
-		    p[6] == 'h' && p[7] == 'e' && !isvar(p[8])) {
-			*q = p + 8;
-			return (T_NO_CACHE);
-		}
-		return (0);
-	case 'p':
-		if (p[0] == 'p' && p[1] == 'r' && p[2] == 'o' && 
-		    p[3] == 'c' && !isvar(p[4])) {
-			*q = p + 4;
-			return (T_PROC);
-		}
-		if (p[0] == 'p' && p[1] == 'i' && p[2] == 'p' && 
-		    p[3] == 'e' && !isvar(p[4])) {
-			*q = p + 4;
-			return (T_PIPE);
-		}
-		if (p[0] == 'p' && p[1] == 'a' && p[2] == 's' && 
-		    p[3] == 's' && !isvar(p[4])) {
-			*q = p + 4;
-			return (T_PASS);
-		}
-		return (0);
-	case 'r':
-		if (p[0] == 'r' && p[1] == 'e' && p[2] == 'w' && 
-		    p[3] == 'r' && p[4] == 'i' && p[5] == 't' && 
-		    p[6] == 'e' && !isvar(p[7])) {
-			*q = p + 7;
-			return (T_REWRITE);
-		}
-		return (0);
-	case 's':
-		if (p[0] == 's' && p[1] == 'w' && p[2] == 'i' && 
-		    p[3] == 't' && p[4] == 'c' && p[5] == 'h' && 
-		    p[6] == '_' && p[7] == 'c' && p[8] == 'o' && 
-		    p[9] == 'n' && p[10] == 'f' && p[11] == 'i' && 
-		    p[12] == 'g' && !isvar(p[13])) {
-			*q = p + 13;
-			return (T_SWITCH_CONFIG);
-		}
-		if (p[0] == 's' && p[1] == 'u' && p[2] == 'b'
-		     && !isvar(p[3])) {
-			*q = p + 3;
-			return (T_SUB);
-		}
-		if (p[0] == 's' && p[1] == 'e' && p[2] == 't'
-		     && !isvar(p[3])) {
-			*q = p + 3;
-			return (T_SET);
-		}
-		return (0);
-	case '{':
-		if (p[0] == '{') {
-			*q = p + 1;
-			return ('{');
-		}
-		return (0);
-	case '|':
-		if (p[0] == '|' && p[1] == '|') {
-			*q = p + 2;
-			return (T_COR);
-		}
-		if (p[0] == '|') {
-			*q = p + 1;
-			return ('|');
-		}
-		return (0);
-	case '}':
-		if (p[0] == '}') {
-			*q = p + 1;
-			return ('}');
-		}
-		return (0);
-	case '~':
-		if (p[0] == '~') {
-			*q = p + 1;
-			return ('~');
-		}
-		return (0);
-	default:
-		return (0);
-	}
-}
-
-const char *vcl_tnames[256];
-
-void
-vcl_init_tnames(void)
-{
-	vcl_tnames['!'] = "'!'";
-	vcl_tnames['%'] = "'%'";
-	vcl_tnames['&'] = "'&'";
-	vcl_tnames['('] = "'('";
-	vcl_tnames[')'] = "')'";
-	vcl_tnames['*'] = "'*'";
-	vcl_tnames['+'] = "'+'";
-	vcl_tnames[','] = "','";
-	vcl_tnames['-'] = "'-'";
-	vcl_tnames['.'] = "'.'";
-	vcl_tnames['/'] = "'/'";
-	vcl_tnames['<'] = "'<'";
-	vcl_tnames['='] = "'='";
-	vcl_tnames['>'] = "'>'";
-	vcl_tnames['{'] = "'{'";
-	vcl_tnames['}'] = "'}'";
-	vcl_tnames['|'] = "'|'";
-	vcl_tnames['~'] = "'~'";
-	vcl_tnames[';'] = "';'";
-	vcl_tnames[CNUM] = "CNUM";
-	vcl_tnames[CSTR] = "CSTR";
-	vcl_tnames[EOI] = "EOI";
-	vcl_tnames[ID] = "ID";
-	vcl_tnames[METHOD] = "METHOD";
-	vcl_tnames[T_ACL] = "acl";
-	vcl_tnames[T_BACKEND] = "backend";
-	vcl_tnames[T_CALL] = "call";
-	vcl_tnames[T_CAND] = "&&";
-	vcl_tnames[T_COR] = "||";
-	vcl_tnames[T_DEC] = "--";
-	vcl_tnames[T_DECR] = "/=";
-	vcl_tnames[T_DELIVER] = "deliver";
-	vcl_tnames[T_DISCARD] = "discard";
-	vcl_tnames[T_DIV] = "/=";
-	vcl_tnames[T_ELSE] = "else";
-	vcl_tnames[T_ELSEIF] = "elseif";
-	vcl_tnames[T_ELSIF] = "elsif";
-	vcl_tnames[T_EQ] = "==";
-	vcl_tnames[T_ERROR] = "error";
-	vcl_tnames[T_FETCH] = "fetch";
-	vcl_tnames[T_FUNC] = "func";
-	vcl_tnames[T_GEQ] = ">=";
-	vcl_tnames[T_IF] = "if";
-	vcl_tnames[T_INC] = "++";
-	vcl_tnames[T_INCR] = "+=";
-	vcl_tnames[T_INSERT] = "insert";
-	vcl_tnames[T_INSERT_PASS] = "insert_pass";
-	vcl_tnames[T_LEQ] = "<=";
-	vcl_tnames[T_LOOKUP] = "lookup";
-	vcl_tnames[T_MUL] = "*=";
-	vcl_tnames[T_NEQ] = "!=";
-	vcl_tnames[T_NO_CACHE] = "no_cache";
-	vcl_tnames[T_NO_NEW_CACHE] = "no_new_cache";
-	vcl_tnames[T_PASS] = "pass";
-	vcl_tnames[T_PIPE] = "pipe";
-	vcl_tnames[T_PROC] = "proc";
-	vcl_tnames[T_REWRITE] = "rewrite";
-	vcl_tnames[T_SET] = "set";
-	vcl_tnames[T_SHL] = "<<";
-	vcl_tnames[T_SHR] = ">>";
-	vcl_tnames[T_SUB] = "sub";
-	vcl_tnames[T_SWITCH_CONFIG] = "switch_config";
-	vcl_tnames[VAR] = "VAR";
-}
-
-void
-vcl_output_lang_h(FILE *f)
-{
-	fputs("#define VCL_RET_ERROR  (1 << 0)\n", f);
-	fputs("#define VCL_RET_LOOKUP  (1 << 1)\n", f);
-	fputs("#define VCL_RET_PIPE  (1 << 2)\n", f);
-	fputs("#define VCL_RET_PASS  (1 << 3)\n", f);
-	fputs("#define VCL_RET_INSERT_PASS  (1 << 4)\n", f);
-	fputs("#define VCL_RET_FETCH  (1 << 5)\n", f);
-	fputs("#define VCL_RET_INSERT  (1 << 6)\n", f);
-	fputs("#define VCL_RET_DELIVER  (1 << 7)\n", f);
-	fputs("#define VCL_RET_DISCARD  (1 << 8)\n", f);
-	fputs("/*\n", f);
-	fputs(" * $Id$\n", f);
-	fputs(" *\n", f);
-	fputs(" * NB:  This file is machine generated, DO NOT EDIT!\n", f);
-	fputs(" *\n", f);
-	fputs(" * Edit vcl_gen_fixed_token.tcl instead\n", f);
-	fputs(" */\n", f);
-	fputs("\n", f);
-	fputs("struct sess;\n", f);
-	fputs("\n", f);
-	fputs("typedef void vcl_init_f(void);\n", f);
-	fputs("typedef int vcl_func_f(struct sess *sp);\n", f);
-	fputs("\n", f);
-	fputs("struct VCL_conf {\n", f);
-	fputs("	unsigned        magic;\n", f);
-	fputs("#define VCL_CONF_MAGIC  0x7406c509      /* from /dev/random */\n", f);
-	fputs("\n", f);
-	fputs("        struct backend  **backend;\n", f);
-	fputs("        unsigned        nbackend;\n", f);
-	fputs("        struct vrt_ref  *ref;\n", f);
-	fputs("        unsigned        nref;\n", f);
-	fputs("        unsigned        busy;\n", f);
-	fputs("\n", f);
-	fputs("        vcl_init_f      *init_func;\n", f);
-	fputs("\n", f);
-	fputs("	vcl_func_f	*recv_func;\n", f);
-	fputs("	vcl_func_f	*miss_func;\n", f);
-	fputs("	vcl_func_f	*hit_func;\n", f);
-	fputs("	vcl_func_f	*fetch_func;\n", f);
-	fputs("	vcl_func_f	*timeout_func;\n", f);
-	fputs("};\n", f);
-	fputs("/*\n", f);
-	fputs(" * $Id$ \n", f);
-	fputs(" *\n", f);
-	fputs(" * Runtime support for compiled VCL programs.\n", f);
-	fputs(" *\n", f);
-	fputs(" * XXX: When this file is changed, lib/libvcl/vcl_gen_fixed_token.tcl\n", f);
-	fputs(" * XXX: *MUST* be rerun.\n", f);
-	fputs(" */\n", f);
-	fputs("\n", f);
-	fputs("struct sess;\n", f);
-	fputs("struct backend;\n", f);
-	fputs("struct VCL_conf;\n", f);
-	fputs("\n", f);
-	fputs("struct vrt_ref {\n", f);
-	fputs("	unsigned	line;\n", f);
-	fputs("	unsigned	pos;\n", f);
-	fputs("	unsigned	count;\n", f);
-	fputs("	const char	*token;\n", f);
-	fputs("};\n", f);
-	fputs("\n", f);
-	fputs("struct vrt_acl {\n", f);
-	fputs("	unsigned	ip;\n", f);
-	fputs("	unsigned	mask;\n", f);
-	fputs("};\n", f);
-	fputs("\n", f);
-	fputs("void VRT_count(struct sess *, unsigned);\n", f);
-	fputs("void VRT_no_cache(struct sess *);\n", f);
-	fputs("void VRT_no_new_cache(struct sess *);\n", f);
-	fputs("#if 0\n", f);
-	fputs("int ip_match(unsigned, struct vcl_acl *);\n", f);
-	fputs("int string_match(const char *, const char *);\n", f);
-	fputs("#endif\n", f);
-	fputs("int VRT_rewrite(const char *, const char *);\n", f);
-	fputs("void VRT_error(struct sess *, unsigned, const char *);\n", f);
-	fputs("int VRT_switch_config(const char *);\n", f);
-	fputs("\n", f);
-	fputs("char *VRT_GetHdr(struct sess *, const char *);\n", f);
-	fputs("char *VRT_GetReq(struct sess *);\n", f);
-	fputs("void VRT_handling(struct sess *sp, unsigned hand);\n", f);
-	fputs("int VRT_obj_valid(struct sess *);\n", f);
-	fputs("int VRT_obj_cacheable(struct sess *);\n", f);
-	fputs("\n", f);
-	fputs("void VRT_set_backend_name(struct backend *, const char *);\n", f);
-	fputs("void VRT_set_backend_hostname(struct backend *, const char *);\n", f);
-	fputs("void VRT_set_backend_portname(struct backend *, const char *);\n", f);
-	fputs("\n", f);
-	fputs("void VRT_alloc_backends(struct VCL_conf *cp);\n", f);
-	fputs("\n", f);
-	fputs("#define VRT_done(sp, hand)			\\\n", f);
-	fputs("	do {					\\\n", f);
-	fputs("		VRT_handling(sp, hand);		\\\n", f);
-	fputs("		return (1);			\\\n", f);
-	fputs("	} while (0)\n", f);
-}

Deleted: trunk/varnish-cache/lib/libvcl/vcl_gen_fixed_token.tcl
===================================================================
--- trunk/varnish-cache/lib/libvcl/vcl_gen_fixed_token.tcl	2006-07-21 16:25:24 UTC (rev 543)
+++ trunk/varnish-cache/lib/libvcl/vcl_gen_fixed_token.tcl	2006-07-21 18:12:56 UTC (rev 544)
@@ -1,319 +0,0 @@
-#!/usr/local/bin/tclsh8.4
-#
-# Generate various .c and .h files for the VCL compiler and the interfaces
-# for it.
-
-# These are the metods which can be called in the VCL program. 
-# Second element is list of valid return actions.
-#
-set methods {
-	{recv		{error pass pipe lookup}}
-	{miss		{error pass pipe fetch}}
-	{hit		{error pass pipe deliver}}
-	{fetch		{error pass pipe insert insert_pass}}
-	{timeout	{fetch discard}}
-}
-
-# These are the return actions
-#
-set returns {
-	error
-	lookup
-	pipe
-	pass
-	insert_pass
-	fetch
-	insert
-	deliver
-	discard
-}
-
-# Language keywords
-#
-set keywords {
-	if else elseif elsif
-
-	func proc sub
-
-	acl
-
-	backend
-
-	call
-	no_cache
-	no_new_cache
-	set
-	rewrite
-	switch_config
-}
-
-# Non-word tokens
-#
-set magic {
-	{"++"	INC}
-	{"--"	DEC}
-	{"&&"	CAND}
-	{"||"	COR}
-	{"<="	LEQ}
-	{"=="	EQ}
-	{"!="	NEQ}
-	{">="	GEQ}
-	{">>"	SHR}
-	{"<<"	SHL}
-	{"+="	INCR}
-	{"/="	DECR}
-	{"*="	MUL}
-	{"/="	DIV}
-}
-
-# Single char tokens
-#
-set char {{}()*+-/%><=;!&.|~,}
-
-# Other token identifiers
-#
-set extras {ID VAR CNUM CSTR EOI METHOD}
-
-#----------------------------------------------------------------------
-# Boilerplate warning for all generated files.
-
-proc warns {fd} {
-
-	puts $fd "/*"
-	puts $fd { * $Id$}
-	puts $fd " *"
-	puts $fd " * NB:  This file is machine generated, DO NOT EDIT!"
-	puts $fd " *"
-	puts $fd " * Edit vcl_gen_fixed_token.tcl instead"
-	puts $fd " */"
-	puts $fd ""
-}
-
-#----------------------------------------------------------------------
-# Build the vcl.h #include file
-
-set fo [open ../../include/vcl.h w]
-warns $fo
-puts $fo {struct sess;
-
-typedef void vcl_init_f(void);
-typedef int vcl_func_f(struct sess *sp);
-}
-puts $fo "struct VCL_conf {"
-puts $fo {	unsigned        magic;
-#define VCL_CONF_MAGIC  0x7406c509      /* from /dev/random */
-
-        struct backend  **backend;
-        unsigned        nbackend;
-        struct vrt_ref  *ref;
-        unsigned        nref;
-        unsigned        busy;
-
-        vcl_init_f      *init_func;
-}
-foreach m $methods {
-	puts $fo "\tvcl_func_f\t*[lindex $m 0]_func;"
-}
-puts $fo "};"
-
-close $fo
-
-#----------------------------------------------------------------------
-# Build the vcl_returns.h #include file
-
-set for [open "../../include/vcl_returns.h" w]
-warns $for
-puts $for "#ifdef VCL_RET_MAC"
-set i 0
-foreach k $returns {
-	if {$k == "error"} {
-		puts $for "#ifdef VCL_RET_MAC_E"
-		puts $for "VCL_RET_MAC_E($k, [string toupper $k], $i)"
-		puts $for "#endif"
-	} else {
-		puts $for "VCL_RET_MAC($k, [string toupper $k], (1 << $i))"
-	}
-	incr i
-}
-puts $for "#else"
-set i 0
-foreach k $returns {
-	puts $for "#define VCL_RET_[string toupper $k]  (1 << $i)"
-	incr i
-}
-puts $for "#define VCL_RET_MAX $i"
-puts $for "#endif"
-puts $for ""
-puts $for "#ifdef VCL_MET_MAC"
-foreach m $methods {
-	puts -nonewline $for "VCL_MET_MAC([lindex $m 0]"
-	puts -nonewline $for ",[string toupper [lindex $m 0]]"
-	set l [lindex $m 1]
-	puts -nonewline $for ",(VCL_RET_[string toupper [lindex $l 0]]"
-	foreach r [lrange $l 1 end] {
-		puts -nonewline $for "|VCL_RET_[string toupper $r]"
-	}
-	puts -nonewline $for ")"
-	puts $for ")"
-}
-puts $for "#endif"
-close $for
-
-#----------------------------------------------------------------------
-# Build the compiler token table and recognizers
-
-set fo [open "vcl_fixed_token.c" w]
-warns $fo
-
-set foh [open "vcl_token_defs.h" w]
-warns $foh
-
-puts $fo "#include <stdio.h>"
-puts $fo "#include <ctype.h>"
-puts $fo "#include \"vcl_priv.h\""
-
-set tn 128
-puts $foh "#define LOW_TOKEN $tn"
-
-
-proc add_token {tok str alpha} {
-	global tokens tn fixed foh
-
-	lappend tokens [list $tok $str]
-	puts $foh "#define $tok $tn"
-	incr tn
-	lappend fixed [list $str $tok $alpha]
-}
-
-proc mk_token {tok str alpha} {
-	set tok T_[string toupper $tok]
-	add_token $tok $str $alpha
-}
-
-foreach k $keywords { mk_token $k $k 1 }
-foreach k $returns { mk_token $k $k 1 }
-foreach k $magic { mk_token [lindex $k 1] [lindex $k 0] 0 }
-foreach k $extras {
-	set t [string toupper $k]
-	lappend tokens [list $t $t]
-	puts $foh "#define [string toupper $k] $tn"
-	incr tn
-}
-for {set i 0} {$i < [string length $char]} {incr i} {
-	set t [string index $char $i]
-	lappend token2 [list '$t' T$t]
-	lappend fixed [list "$t" '$t' 0]
-}
-
-set tokens [lsort $tokens]
-set token2 [lsort $token2]
-
-# We want to output in ascii order: create sorted first char list
-foreach t $fixed {
-	set xx([string index [lindex $t 0] 0]) 1
-}
-set seq [lsort [array names xx]]
-
-set ll 0
-
-puts $fo {
-unsigned
-vcl_fixed_token(const char *p, const char **q)}
-puts $fo "{"
-puts $fo ""
-puts $fo "	switch (p\[0\]) {"
-
-foreach ch "$seq" {
-	# Now find all tokens starting with ch
-	set l ""
-	foreach t $fixed {
-		if {[string index [lindex $t 0] 0] == $ch} {
-			lappend l $t
-		}
-	}
-	# And do then in reverse order to match longest first
-	set l [lsort -index 0 -decreasing $l]
-	scan "$ch" "%c" cx
-	if {$cx != $ll} {
-		if {$ll} {
-			puts $fo "		return (0);"
-		}
-	
-		puts $fo "	case '$ch':"
-		set ll $cx
-	}
-	foreach tt $l {
-		set k [lindex $tt 0]
-		puts -nonewline $fo "		if ("
-		for {set i 0} {$i < [string length $k]} {incr i} {
-			if {$i > 0} {
-				puts -nonewline $fo " && "
-				if {![expr $i % 3]} {
-					puts -nonewline $fo "\n\t\t    "
-				}
-			}
-			puts -nonewline $fo "p\[$i\] == '[string index $k $i]'"
-		}
-		if {[lindex $tt 2]} {
-			if {![expr $i % 3]} {
-				puts -nonewline $fo "\n\t\t    "
-			}
-			puts -nonewline $fo " && !isvar(p\[$i\])"
-		}
-		puts $fo ") {"
-		puts $fo "			*q = p + [string length $k];"
-		puts $fo "			return ([lindex $tt 1]);"
-		puts $fo "		}"
-	}
-} 
-puts $fo "		return (0);"
-puts $fo "	default:"
-puts $fo "		return (0);"
-puts $fo "	}"
-puts $fo "}"
-
-puts $fo ""
-puts $fo "const char *vcl_tnames\[256\];\n"
-puts $fo "void"
-puts $fo "vcl_init_tnames(void)"
-puts $fo "{"
-foreach i $token2 {
-	puts $fo "\tvcl_tnames\[[lindex $i 0]\] = \"[lindex $i 0]\";"
-}
-foreach i $tokens {
-	puts $fo "\tvcl_tnames\[[lindex $i 0]\] = \"[lindex $i 1]\";"
-}
-puts $fo "}"
-
-#----------------------------------------------------------------------
-# Create the C-code which emits the boilerplate definitions for the
-# generated C code output
-
-proc copy_include {n} {
-	global fo
-
-	set fi [open $n]
-	while {[gets $fi a] >= 0} {
-		regsub -all {\\} $a {\\\\} a
-		puts $fo "\tfputs(\"$a\\n\", f);"
-	}
-	close $fi
-}
-
-puts $fo ""
-puts $fo "void"
-puts $fo "vcl_output_lang_h(FILE *f)"
-puts $fo "{"
-set i 0
-foreach k $returns {
-	puts $fo "\tfputs(\"#define VCL_RET_[string toupper $k]  (1 << $i)\\n\", f);"
-	incr i
-}
-
-copy_include ../../include/vcl.h
-copy_include ../../include/vrt.h
-
-puts $fo "}"
-
-close $foh
-close $fo

Deleted: trunk/varnish-cache/lib/libvcl/vcl_priv.h
===================================================================
--- trunk/varnish-cache/lib/libvcl/vcl_priv.h	2006-07-21 16:25:24 UTC (rev 543)
+++ trunk/varnish-cache/lib/libvcl/vcl_priv.h	2006-07-21 18:12:56 UTC (rev 544)
@@ -1,13 +0,0 @@
-/*
- * Stuff shared between main.c and fixed_token.c
- */
-
-#include "vcl_token_defs.h"
-
-#define isident1(c) (isalpha(c))
-#define isident(c) (isalpha(c) || isdigit(c) || (c) == '_')
-#define isvar(c) (isident(c) || (c) == '.')
-unsigned vcl_fixed_token(const char *p, const char **q);
-extern const char *vcl_tnames[256];
-void vcl_init_tnames(void);
-void vcl_output_lang_h(FILE *f);

Deleted: trunk/varnish-cache/lib/libvcl/vcl_token_defs.h
===================================================================
--- trunk/varnish-cache/lib/libvcl/vcl_token_defs.h	2006-07-21 16:25:24 UTC (rev 543)
+++ trunk/varnish-cache/lib/libvcl/vcl_token_defs.h	2006-07-21 18:12:56 UTC (rev 544)
@@ -1,53 +0,0 @@
-/*
- * $Id$
- *
- * NB:  This file is machine generated, DO NOT EDIT!
- *
- * Edit vcl_gen_fixed_token.tcl instead
- */
-
-#define LOW_TOKEN 128
-#define T_IF 128
-#define T_ELSE 129
-#define T_ELSEIF 130
-#define T_ELSIF 131
-#define T_FUNC 132
-#define T_PROC 133
-#define T_SUB 134
-#define T_ACL 135
-#define T_BACKEND 136
-#define T_CALL 137
-#define T_NO_CACHE 138
-#define T_NO_NEW_CACHE 139
-#define T_SET 140
-#define T_REWRITE 141
-#define T_SWITCH_CONFIG 142
-#define T_ERROR 143
-#define T_LOOKUP 144
-#define T_PIPE 145
-#define T_PASS 146
-#define T_INSERT_PASS 147
-#define T_FETCH 148
-#define T_INSERT 149
-#define T_DELIVER 150
-#define T_DISCARD 151
-#define T_INC 152
-#define T_DEC 153
-#define T_CAND 154
-#define T_COR 155
-#define T_LEQ 156
-#define T_EQ 157
-#define T_NEQ 158
-#define T_GEQ 159
-#define T_SHR 160
-#define T_SHL 161
-#define T_INCR 162
-#define T_DECR 163
-#define T_MUL 164
-#define T_DIV 165
-#define ID 166
-#define VAR 167
-#define CNUM 168
-#define CSTR 169
-#define EOI 170
-#define METHOD 171




More information about the varnish-commit mailing list