r43 - in trunk/varnish-cache/lib: . libvcl

phk at projects.linpro.no phk at projects.linpro.no
Mon Mar 13 13:37:05 CET 2006


Author: phk
Date: 2006-03-13 13:37:04 +0100 (Mon, 13 Mar 2006)
New Revision: 43

Added:
   trunk/varnish-cache/lib/libvcl/
   trunk/varnish-cache/lib/libvcl/Makefile
   trunk/varnish-cache/lib/libvcl/sample.vcl
   trunk/varnish-cache/lib/libvcl/vcl_compile.c
   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_lang.h
   trunk/varnish-cache/lib/libvcl/vcl_priv.h
   trunk/varnish-cache/lib/libvcl/vcl_token_defs.h
Modified:
   trunk/varnish-cache/lib/Makefile.am
Log:
Add first cut of VCL compiler to the tree.

The Makefile is a temporary shim until I get the auto* stuff working.

The sample.vcl is a small mock-up to test the compiler.

Some of the .h files needs to move other places in the fullness of time.

But other than that...



Modified: trunk/varnish-cache/lib/Makefile.am
===================================================================
--- trunk/varnish-cache/lib/Makefile.am	2006-03-02 10:32:59 UTC (rev 42)
+++ trunk/varnish-cache/lib/Makefile.am	2006-03-13 12:37:04 UTC (rev 43)
@@ -2,4 +2,5 @@
 
 SUBDIRS = \
 	libvarnish \
-	libvarnishapi
+	libvarnishapi \
+	libvcl

Added: trunk/varnish-cache/lib/libvcl/Makefile
===================================================================
--- trunk/varnish-cache/lib/libvcl/Makefile	2006-03-02 10:32:59 UTC (rev 42)
+++ trunk/varnish-cache/lib/libvcl/Makefile	2006-03-13 12:37:04 UTC (rev 43)
@@ -0,0 +1,20 @@
+PROG	=	vpc
+
+SRCS	+=	vcl_compile.c
+SRCS	+=	vcl_fixed_token.c
+
+NO_MAN	=	yes
+
+WARNS	?=	5
+
+LDADD	+=	-lsbuf
+
+.include <bsd.prog.mk>
+
+
+test:	${PROG}
+	./${PROG} ${.CURDIR}/sample.vcl
+	cc -Wall -c _.c
+
+flint:	
+	flint flint.lnt -I/usr/include -I. ${SRCS}

Added: trunk/varnish-cache/lib/libvcl/sample.vcl
===================================================================
--- trunk/varnish-cache/lib/libvcl/sample.vcl	2006-03-02 10:32:59 UTC (rev 42)
+++ trunk/varnish-cache/lib/libvcl/sample.vcl	2006-03-13 12:37:04 UTC (rev 43)
@@ -0,0 +1,109 @@
+
+acl rfc1918 {
+	10.0.0.0/8;
+	172.16.0.0/12;
+	192.168.0.0/16;
+}
+
+sub request_policy {
+
+	if (client.ip == 10.1.2.3) {
+		no_cache;
+		finish;
+	}
+
+	if (client.ip ~ rfc1918) {
+		no_cache;
+		finish;
+	}
+
+	if (req.url.host ~ "cnn.no$") {
+		rewrite "cnn.no$" "vg.no";
+	}
+
+	if (req.url.path ~ "cgi-bin") {
+		no_cache;
+	}
+
+	if (req.useragent ~ "spider") {
+		no_new_cache;
+	}
+
+# comment
+
+	if (backend.response_time <= 0.8s) {
+		set req.ttlfactor = 1.5;
+	} elseif (backend.response_time > 1.5s) {
+		set req.ttlfactor = 2.0;
+	} elseif (backend.response_time > 2.5m) {
+		set req.ttlfactor = 5.0;
+	}
+
+	/*
+	 * the program contains no references to
+	 * maxage, s-maxage and expires, so the
+	 * default handling (RFC2616) applies
+	 */
+}
+
+backend vg {
+	set backend.ip = 10.0.0.100;
+	set backend.timeout = 4s;
+	set backend.bandwidth = 2000Mb/s;
+}
+
+backend chat {
+	set backend.ip = 10.0.0.4;
+	set backend.timeout = 4s;
+	set backend.bandwidth = 2000Mb/s;
+}
+
+sub bail {
+	error 404 "Bailing out";
+	finish;
+}
+
+sub fetch_policy {
+
+	if (!req.url.host ~ "/vg.no$/") {
+		set req.backend = vg;
+	} else {
+		/* XXX: specify 404 page url ? */
+		error 404;
+	}
+
+	if (backend.response_time > 2.0s) {
+		if (req.url.path ~ "/landbrugspriser/") {
+			call bail;
+		}
+	}
+	fetch;
+	if (backend.down) {
+		if (obj.exist) {
+			set obj.ttl += 10m;
+			finish;
+		}
+		switch_config ohhshit;
+	}
+	if (obj.result == 404) {
+		error 300 "http://www.vg.no";
+	}
+	if (obj.result != 200) {
+		finish;
+	}
+	if (obj.size > 256kb) {
+		no_cache;
+	} else if (obj.size > 32kb && obj.ttl < 2m) {
+		set obj.ttl = 5m;
+	}
+	if (backend.response_time > 2.0s) {
+		set obj.ttl *= 2.0;
+	}
+}
+
+sub prefetch_policy {
+
+	if (obj.usage < 10 && obj.ttl < 5m) {
+		fetch;
+	}
+}

Added: trunk/varnish-cache/lib/libvcl/vcl_compile.c
===================================================================
--- trunk/varnish-cache/lib/libvcl/vcl_compile.c	2006-03-02 10:32:59 UTC (rev 42)
+++ trunk/varnish-cache/lib/libvcl/vcl_compile.c	2006-03-13 12:37:04 UTC (rev 43)
@@ -0,0 +1,1383 @@
+/*
+ * $Id$
+ */
+
+/*
+ * XXX:
+ *	generate interface structure
+ *
+ * XXX:
+ *	Better error messages, throughout.
+ *	>It also accured to me that we could link the errors to the error 
+ *	>documentation.
+ *	>
+ *	>Unreferenced  function 'request_policy', first mention is
+ *	>         Line 8 Pos 4
+ *	>         sub request_policy {
+ *	>         ----##############--
+ *	>Read more about this type of error:
+ *	>http://varnish/doc/error.html#Unreferenced%20function
+ *	>
+ *	>
+ *	>         Unknown variable 'obj.bandwidth'
+ *	>         At: Line 88 Pos 12
+ *	>                 if (obj.bandwidth < 1 kb/h) {
+ *	>         ------------#############------------
+ *	>Read more about this type of error:
+ *	>http://varnish/doc/error.html#Unknown%20variable
+ * 
+ * XXX:
+ *	Create proper tmp filenames for .h, .c and .o
+ *
+ * XXX:
+ *	and all the rest...
+ */
+
+#include <assert.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/sbuf.h>
+#include <sys/queue.h>
+#include "vcl_priv.h"
+
+#define ERRCHK(tl)	do { if ((tl)->err) return; } while (0)
+
+#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;
+	FILE			*fc, *fh;
+	TAILQ_HEAD(, ref)	refs;
+	struct sbuf		*sb;
+	int			err;
+};
+
+enum var_type {
+	BACKEND,
+	BOOL,
+	INT,
+	FLOAT,
+	SIZE,
+	RATE,
+	TIME,
+	STRING,
+	IP
+};
+
+struct var {
+	const char		*name;
+	enum var_type		fmt;
+	int			len;
+	const char		*cname;
+	
+};
+
+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;
+};
+
+
+static struct var vars[] = {
+	{ "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.ip",			IP, 0,      "backend->ip"    },
+	{ "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" },
+	{ NULL,				INT, 0,	    "NULL" }
+};
+
+static void Compound(struct tokenlist *tl);
+static void Cond_0(struct tokenlist *tl);
+
+/*--------------------------------------------------------------------*/
+
+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, "'%*.*s'", t->e - t->b, t->e - t->b, t->b);
+}
+
+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;
+	
+	lin = 1;
+	pos = 0;
+	for (l = p = tl->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, "Line %d Pos %d\n", lin, pos);
+	x = y = 0;
+	for (p = l; p < tl->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 < tl->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 ", 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 I(tl)	do { 		\
+	fprintf(tl->fc, "/* %-11s */ ", __func__); \
+	fprintf(tl->fc, "%*.*s", tl->indent, tl->indent, ""); \
+} while (0)
+
+#define L(tl, foo)	do {	\
+	tl->indent += INDENT;	\
+	foo;			\
+	tl->indent -= INDENT;	\
+} while (0)
+
+#define C(tl, sep)	do {				\
+	I(tl);						\
+	fprintf(tl->fc, "VCL_count(%u)%s\n", ++tl->cnt, sep);	\
+	tl->t->cnt = tl->cnt; 				\
+} while (0)
+	
+/*--------------------------------------------------------------------
+ * 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);
+}
+
+/*--------------------------------------------------------------------
+ * 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 (r->name->e - r->name->b != t->e - t->b)
+			continue;
+		if (memcmp(t->b, r->name->b, t->e - t->b))
+			continue;
+		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 void
+AddRef(struct tokenlist *tl, struct token *t, enum ref_type type)
+{
+
+	FindRef(tl, t, type)->refcnt++;
+}
+
+static void
+AddDef(struct tokenlist *tl, struct token *t, enum ref_type type)
+{
+
+	FindRef(tl, t, type)->defcnt++;
+}
+
+/*--------------------------------------------------------------------
+ * 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 += digittoint(*p);
+	}
+	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 += digittoint(*p);
+	}
+	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 += digittoint(*p) * 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 *
+FindVar(struct tokenlist *tl, struct token *t)
+{
+	struct var *v;
+
+	for (v = vars; v->name != NULL; v++) {
+		if (t->e - t->b != v->len)
+			continue;
+		if (!memcmp(t->b, v->name, v->len))
+			return (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);
+	fprintf(tl->fc, "(%g * %g)", v, sc);
+}
+
+static void
+SizeVal(struct tokenlist *tl)
+{
+	double v, sc;
+
+	v = DoubleVal(tl);
+	ExpectErr(tl, ID);
+	sc = SizeUnit(tl);
+	fprintf(tl->fc, "(%g * %g)", v, sc);
+}
+
+static void
+RateVal(struct tokenlist *tl)
+{
+	double v, sc;
+
+	v = DoubleVal(tl);
+	ExpectErr(tl, ID);
+	sc = RateUnit(tl);
+	fprintf(tl->fc, "(%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);
+		I(tl);
+		AddRef(tl, tl->t, R_ACL);
+		fprintf(tl->fc, "ip_match(%s, acl_%*.*s)\n",
+		    vp->cname,
+		    tl->t->e - tl->t->b,
+		    tl->t->e - tl->t->b, tl->t->b);
+		NextToken(tl);
+		break;
+	case T_EQ:
+	case T_NEQ:
+		I(tl);
+		fprintf(tl->fc, "%s %*.*s ",
+		    vp->cname,
+		    tl->t->e - tl->t->b,
+		    tl->t->e - tl->t->b, tl->t->b);
+		NextToken(tl);
+		u = IpVal(tl);
+		fprintf(tl->fc, "%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 __unused, struct tokenlist *tl)
+{
+
+	switch (tl->t->tok) {
+	case '~':
+		I(tl); fprintf(tl->fc, "string_match(%s, ", vp->cname);
+		NextToken(tl);
+		ExpectErr(tl, CSTR);
+		fprintf(tl->fc, "%*.*s)\n",
+			tl->t->e - tl->t->b,
+			tl->t->e - tl->t->b, tl->t->b);
+		NextToken(tl);
+		break;
+	default:
+		sbuf_printf(tl->sb, "Illegal condition ");
+		ErrToken(tl, tl->t);
+		sbuf_printf(tl->sb, " on string variable\n");
+		sbuf_printf(tl->sb, "  only '~' is legal\n");
+		ErrWhere(tl, tl->t);
+		break;
+	}
+}
+
+static void
+Cond_Int(struct var *vp, struct tokenlist *tl)
+{
+
+	I(tl);
+	fprintf(tl->fc, "%s ", vp->cname);
+	switch (tl->t->tok) {
+	case T_EQ:
+	case T_NEQ:
+	case T_LEQ:
+	case T_GEQ:
+	case '>':
+	case '<':
+		fprintf(tl->fc, "%*.*s ", 
+			tl->t->e - tl->t->b,
+			tl->t->e - tl->t->b, tl->t->b);
+		NextToken(tl);
+		switch(vp->fmt) {
+		case TIME:
+			TimeVal(tl);
+			break;
+		case INT:
+			ExpectErr(tl, CNUM);
+			fprintf(tl->fc, "%*.*s ", 
+				tl->t->e - tl->t->b,
+				tl->t->e - tl->t->b, tl->t->b);
+			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;
+		}
+		fprintf(tl->fc, "\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)
+{
+
+	I(tl);
+	fprintf(tl->fc, "%s\n", vp->cname);
+}
+
+static void
+Cond_2(struct tokenlist *tl)
+{
+	struct var *vp;
+
+	C(tl, ",");
+	I(tl);
+	if (tl->t->tok == '!') {
+		fprintf(tl->fc, "!");
+		NextToken(tl);
+	}
+	fprintf(tl->fc, "(\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);
+		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;
+	}
+	I(tl);
+	fprintf(tl->fc, ")\n");
+}
+
+static void
+Cond_1(struct tokenlist *tl)
+{
+
+	I(tl); fprintf(tl->fc, "(\n");
+	L(tl, Cond_2(tl));
+	while (tl->t->tok == T_CAND) {
+		NextToken(tl);
+		I(tl); fprintf(tl->fc, ") && (\n");
+		L(tl, Cond_2(tl));
+	}
+	I(tl); fprintf(tl->fc, ")\n");
+}
+
+static void
+Cond_0(struct tokenlist *tl)
+{
+
+	I(tl); fprintf(tl->fc, "(\n");
+	L(tl, Cond_1(tl));
+	while (tl->t->tok == T_COR) {
+		NextToken(tl);
+		I(tl); fprintf(tl->fc, ") || (\n");
+		L(tl, Cond_1(tl));
+	}
+	I(tl); fprintf(tl->fc, ")\n");
+}
+
+static void
+Conditional(struct tokenlist *tl)
+{
+
+	ExpectErr(tl, '(');
+	NextToken(tl);
+	I(tl); fprintf(tl->fc, "(\n");
+	L(tl, Cond_0(tl));
+	ERRCHK(tl);
+	I(tl); fprintf(tl->fc, ")\n");
+	ExpectErr(tl, ')');
+	NextToken(tl);
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+IfStmt(struct tokenlist *tl)
+{
+
+	ExpectErr(tl, T_IF);
+	I(tl); fprintf(tl->fc, "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) {
+				I(tl); fprintf(tl->fc, "else \n");
+				L(tl, Compound(tl));
+				ERRCHK(tl);
+				return;
+			}
+			/* FALLTHROUGH */
+		case T_ELSEIF:
+		case T_ELSIF:
+			I(tl); fprintf(tl->fc, "else if \n");
+			NextToken(tl);
+			L(tl, Conditional(tl));
+			ERRCHK(tl);
+			L(tl, Compound(tl));
+			ERRCHK(tl);
+			break;
+		default:
+			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:
+		I(tl);
+		fprintf(tl->fc, "VCL_no_new_cache();\n");
+		return;
+	case T_NO_CACHE:
+		I(tl);
+		fprintf(tl->fc, "VCL_no_cache();\n");
+		return;
+	case T_FINISH:
+		I(tl);
+		fprintf(tl->fc, "return;\n");
+		return;
+	case T_FETCH:
+		I(tl);
+		fprintf(tl->fc, "VCL_fetch();\n");
+		return;
+	case T_ERROR:
+		a = UintVal(tl);
+		I(tl);
+		fprintf(tl->fc, "VCL_error(%u, ", a);
+		if (tl->t->tok == CSTR) {
+			fprintf(tl->fc, "%*.*s);\n",
+			    tl->t->e - tl->t->b,
+			    tl->t->e - tl->t->b, tl->t->b);
+			NextToken(tl);
+		} else
+			fprintf(tl->fc, "(const char *)0);\n");
+		return;
+	case T_SWITCH_CONFIG:
+		ExpectErr(tl, ID);
+		I(tl);
+		fprintf(tl->fc, "VCL_switch_config(\"%*.*s\");\n",
+		    tl->t->e - tl->t->b,
+		    tl->t->e - tl->t->b, tl->t->b);
+		NextToken(tl);
+		return;
+	case T_CALL:
+		ExpectErr(tl, ID);
+		AddRef(tl, tl->t, R_FUNC);
+		I(tl);
+		fprintf(tl->fc, "VCL_function_%*.*s(VCL_PASS_ARGS);\n",
+		    tl->t->e - tl->t->b,
+		    tl->t->e - tl->t->b, tl->t->b);
+		/* XXX: check if function finished request */
+		NextToken(tl);
+		return;
+	case T_REWRITE:
+		ExpectErr(tl, CSTR);
+		I(tl);
+		fprintf(tl->fc, "VCL_rewrite(%*.*s",
+		    tl->t->e - tl->t->b,
+		    tl->t->e - tl->t->b, tl->t->b);
+		NextToken(tl);
+		ExpectErr(tl, CSTR);
+		fprintf(tl->fc, ", %*.*s);\n",
+		    tl->t->e - tl->t->b,
+		    tl->t->e - tl->t->b, tl->t->b);
+		NextToken(tl);
+		return;
+	case T_SET:
+		ExpectErr(tl, VAR);
+		vp = FindVar(tl, tl->t);
+		ERRCHK(tl);
+		assert(vp != NULL);
+		I(tl);
+		fprintf(tl->fc, "%s ", vp->cname);
+		NextToken(tl);
+		switch (vp->fmt) {
+		case INT:
+		case SIZE:
+		case RATE:
+		case TIME:
+		case FLOAT:
+			fprintf(tl->fc, "%*.*s ",
+			    tl->t->e - tl->t->b,
+			    tl->t->e - tl->t->b, tl->t->b);
+			a = tl->t->tok;
+			NextToken(tl);
+			if (a == T_MUL || a == T_DIV)
+				fprintf(tl->fc, "%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 
+				fprintf(tl->fc, "%g", DoubleVal(tl));
+			fprintf(tl->fc, ";\n");
+			break;
+		case IP:
+			if (tl->t->tok == '=') {
+				NextToken(tl);
+				u = IpVal(tl);
+				fprintf(tl->fc, "= %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);
+				fprintf(tl->fc, "= &VCL_backend_%*.*s;\n",
+				    tl->t->e - tl->t->b,
+				    tl->t->e - tl->t->b, tl->t->b);
+				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);
+	fprintf(tl->fh, "static struct vcl_acl acl_%*.*s[];\n",
+	    tl->t->e - tl->t->b,
+	    tl->t->e - tl->t->b, tl->t->b);
+	I(tl);
+	fprintf(tl->fc, "static struct vcl_acl acl_%*.*s[] = {\n",
+	    tl->t->e - tl->t->b,
+	    tl->t->e - tl->t->b, tl->t->b);
+	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);
+		I(tl);
+		fprintf(tl->fc, "{ %11uU, %3uU }, /* %u.%u.%u.%u/%u */\n",
+		    u, m,
+		    (u >> 24) & 0xff, (u >> 16) & 0xff,
+		    (u >> 8) & 0xff, (u) & 0xff, m);
+	}
+	ExpectErr(tl, '}');
+	I(tl);
+	fprintf(tl->fc, "{ %11uU, %3uU }\n", 0, 0);
+
+	tl->indent -= INDENT;
+
+	I(tl);
+	fprintf(tl->fc, "};\n\n");
+	NextToken(tl);
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+Compound(struct tokenlist *tl)
+{
+
+	ExpectErr(tl, '{');
+	I(tl); fprintf(tl->fc, "{\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;
+			I(tl); fprintf(tl->fc, "}\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 void
+Backend(struct tokenlist *tl)
+{
+
+	NextToken(tl);
+	ExpectErr(tl, ID);
+	AddDef(tl, tl->t, R_BACKEND);
+	I(tl);
+	fprintf(tl->fh, "static struct backend VCL_backend_%*.*s;\n",
+	    tl->t->e - tl->t->b,
+	    tl->t->e - tl->t->b, tl->t->b);
+	fprintf(tl->fc, "static struct backend VCL_backend_%*.*s;\n",
+	    tl->t->e - tl->t->b,
+	    tl->t->e - tl->t->b, tl->t->b);
+	fprintf(tl->fc, "static void\n");
+	I(tl);
+	fprintf(tl->fc, "VCL_init_backend_%*.*s (struct backend *backend)\n",
+	    tl->t->e - tl->t->b,
+	    tl->t->e - tl->t->b, tl->t->b);
+	NextToken(tl);
+	L(tl, Compound(tl));
+	fprintf(tl->fc, "\n");
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+Function(struct tokenlist *tl)
+{
+
+	NextToken(tl);
+	ExpectErr(tl, ID);
+	AddDef(tl, tl->t, R_FUNC);
+	fprintf(tl->fh, "static void VCL_function_%*.*s (VCL_FARGS);\n",
+	    tl->t->e - tl->t->b,
+	    tl->t->e - tl->t->b, tl->t->b);
+	I(tl);
+	fprintf(tl->fc, "static void\n");
+	I(tl);
+	fprintf(tl->fc, "VCL_function_%*.*s (VCL_FARGS)\n",
+	    tl->t->e - tl->t->b,
+	    tl->t->e - tl->t->b, tl->t->b);
+	NextToken(tl);
+	L(tl, Compound(tl));
+	fprintf(tl->fc, "\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;
+}
+
+/*--------------------------------------------------------------------
+ * 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 = 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;
+	}
+	/* Add End Of Input token */
+	AddToken(tl, EOI, p, p);
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+CheckRefs(struct tokenlist *tl)
+{
+	struct ref *r;
+	const char *bug;
+
+	TAILQ_FOREACH(r, &tl->refs, list) {
+		if (r->defcnt == 0)
+			bug = "Undefined ";
+		else if (r->refcnt == 0)
+			bug = "Unreferenced ";
+		else
+			continue;
+		switch(r->type) {
+		case R_FUNC:
+			sbuf_printf(tl->sb, "%s function ", bug);
+			break;
+		case R_ACL:
+			sbuf_printf(tl->sb, "%s acl ", bug);
+			break;
+		case R_BACKEND:
+			sbuf_printf(tl->sb, "%s backend ", bug);
+			break;
+		default:
+			ErrInternal(tl);
+			sbuf_printf(tl->sb, "Ref ");
+			ErrToken(tl, r->name);
+			sbuf_printf(tl->sb, " has unknown type %d\n",
+			    r->type);
+			return;
+		}
+		ErrToken(tl, r->name);
+		sbuf_cat(tl->sb, ", first mention is\n");
+		ErrWhere(tl, r->name);
+		return;
+	}
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+LocTable(struct tokenlist *tl)
+{
+	struct token *t;
+	unsigned lin, pos;
+	const char *p;
+	
+	fprintf(tl->fh, "static struct vcl_ref VCL_ref[%u];\n", tl->cnt + 1);
+	fprintf(tl->fc, "static struct vcl_ref VCL_ref[%u] = {\n", tl->cnt + 1);
+	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++;
+		
+		}
+		fprintf(tl->fc,
+		    "%*.*s[%3u] = { %4u, %3u, 0, \"%*.*s\" },\n",
+		    INDENT, INDENT, "",
+		    t->cnt, lin, pos + 1,
+		    t->e - t->b,
+		    t->e - t->b, t->b);
+	}
+	fprintf(tl->fc, "};\n");
+}
+
+
+/*--------------------------------------------------------------------*/
+
+static void
+Compile(struct sbuf *sb, const char *b, const char *e)
+{
+	struct tokenlist	tokens;
+
+	memset(&tokens, 0, sizeof tokens);
+	TAILQ_INIT(&tokens.tokens);
+	TAILQ_INIT(&tokens.refs);
+	tokens.sb = sb;
+
+	tokens.fc = fopen("_.c", "w");
+	assert(tokens.fc != NULL);
+
+	tokens.fh = fopen("_.h", "w");
+	assert(tokens.fh != NULL);
+
+	fprintf(tokens.fc, "#include \"vcl_lang.h\"\n");
+	fprintf(tokens.fc, "#include \"_.h\"\n");
+	tokens.b = b;
+	tokens.e = e;
+	Lexer(&tokens, b, e);
+	ERRCHK(&tokens);
+	tokens.t = TAILQ_FIRST(&tokens.tokens);
+	Parse(&tokens);
+	ERRCHK(&tokens);
+	CheckRefs(&tokens);
+	ERRCHK(&tokens);
+	LocTable(&tokens);
+}
+
+/*--------------------------------------------------------------------*/
+
+#include <err.h>
+
+#define MYSPACE	(128 * 1024)
+
+int
+main(int argc, char **argv)
+{
+	char *p;
+	size_t z;
+	FILE *fi;
+	struct sbuf *sb;
+
+	setbuf(stdout, NULL);
+	{
+	struct var *v;
+
+	for (v = vars; v->name != NULL; v++) {
+		v->len = strlen(v->name);
+	}
+	}
+	if (argc != 2)
+		err(1, "Usage: %s file", argv[0]);
+	fi = fopen(argv[1], "r");
+	if (fi == NULL)
+		err(1, "Cannot open %s", argv[1]);
+	p = malloc(MYSPACE);
+	assert(p != NULL);
+
+	z = fread(p, 1, MYSPACE - 1, fi);
+	if (z == 0)
+		err(1, "Nothing read from %s", argv[1]);
+	p[z] = '\0';
+	sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND);
+	Compile(sb, p, p + z);
+	sbuf_finish(sb);
+	if (sbuf_len(sb))
+		printf("<%s>\n", sbuf_data(sb));
+	return (0);
+}

Added: trunk/varnish-cache/lib/libvcl/vcl_fixed_token.c
===================================================================
--- trunk/varnish-cache/lib/libvcl/vcl_fixed_token.c	2006-03-02 10:32:59 UTC (rev 42)
+++ trunk/varnish-cache/lib/libvcl/vcl_fixed_token.c	2006-03-13 12:37:04 UTC (rev 43)
@@ -0,0 +1,365 @@
+/*
+ * NB:  This file is machine generated, DO NOT EDIT!
+ * instead, edit the Tcl script vcl_gen_fixed_token.tcl and run it by hand
+ */
+
+#include "vcl_priv.h"
+
+unsigned
+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 '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] == 'i' && p[2] == 'n' && 
+		    p[3] == 'i' && p[4] == 's' && p[5] == 'h'
+		     && !isvar(p[6])) {
+			*q = p + 6;
+			return (T_FINISH);
+		}
+		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] == 'f' && !isvar(p[2])) {
+			*q = p + 2;
+			return (T_IF);
+		}
+		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);
+		}
+		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 *tnames[256] = {
+	['!'] = "'!'" /* t2 '!' T! */,
+	['%'] = "'%'" /* t2 '%' T% */,
+	['&'] = "'&'" /* t2 '&' T& */,
+	['('] = "'('" /* t2 '(' T( */,
+	[')'] = "')'" /* t2 ')' T) */,
+	['*'] = "'*'" /* t2 '*' T* */,
+	['+'] = "'+'" /* t2 '+' T+ */,
+	[','] = "','" /* t2 ',' T, */,
+	['-'] = "'-'" /* t2 '-' T- */,
+	['.'] = "'.'" /* t2 '.' T. */,
+	['/'] = "'/'" /* t2 '/' T/ */,
+	['<'] = "'<'" /* t2 '<' T< */,
+	['='] = "'='" /* t2 '=' T= */,
+	['>'] = "'>'" /* t2 '>' T> */,
+	['{'] = "'{'" /* t2 '\{' T\{ */,
+	['}'] = "'}'" /* t2 '\}' T\} */,
+	['|'] = "'|'" /* t2 '|' T| */,
+	['~'] = "'~'" /* t2 '~' T~ */,
+	[';'] = "';'" /* t2 {';'} {T;} */,
+	[CNUM] = "CNUM" /* t CNUM CNUM */,
+	[CSTR] = "CSTR" /* t CSTR CSTR */,
+	[EOI] = "EOI" /* t EOI EOI */,
+	[ID] = "ID" /* t ID ID */,
+	[T_ACL] = "acl" /* t T_ACL acl */,
+	[T_BACKEND] = "backend" /* t T_BACKEND backend */,
+	[T_CALL] = "call" /* t T_CALL call */,
+	[T_CAND] = "&&" /* t T_CAND && */,
+	[T_COR] = "||" /* t T_COR || */,
+	[T_DEC] = "--" /* t T_DEC -- */,
+	[T_DECR] = "/=" /* t T_DECR /= */,
+	[T_DIV] = "/=" /* t T_DIV /= */,
+	[T_ELSE] = "else" /* t T_ELSE else */,
+	[T_ELSEIF] = "elseif" /* t T_ELSEIF elseif */,
+	[T_ELSIF] = "elsif" /* t T_ELSIF elsif */,
+	[T_EQ] = "==" /* t T_EQ == */,
+	[T_ERROR] = "error" /* t T_ERROR error */,
+	[T_FETCH] = "fetch" /* t T_FETCH fetch */,
+	[T_FINISH] = "finish" /* t T_FINISH finish */,
+	[T_FUNC] = "func" /* t T_FUNC func */,
+	[T_GEQ] = ">=" /* t T_GEQ >= */,
+	[T_IF] = "if" /* t T_IF if */,
+	[T_INC] = "++" /* t T_INC ++ */,
+	[T_INCR] = "+=" /* t T_INCR += */,
+	[T_LEQ] = "<=" /* t T_LEQ <= */,
+	[T_MUL] = "*=" /* t T_MUL *= */,
+	[T_NEQ] = "!=" /* t T_NEQ != */,
+	[T_NO_CACHE] = "no_cache" /* t T_NO_CACHE no_cache */,
+	[T_NO_NEW_CACHE] = "no_new_cache" /* t T_NO_NEW_CACHE no_new_cache */,
+	[T_PROC] = "proc" /* t T_PROC proc */,
+	[T_REWRITE] = "rewrite" /* t T_REWRITE rewrite */,
+	[T_SET] = "set" /* t T_SET set */,
+	[T_SHL] = "<<" /* t T_SHL << */,
+	[T_SHR] = ">>" /* t T_SHR >> */,
+	[T_SUB] = "sub" /* t T_SUB sub */,
+	[T_SWITCH_CONFIG] = "switch_config" /* t T_SWITCH_CONFIG switch_config */,
+	[VAR] = "VAR" /* t VAR VAR */,
+};

Added: trunk/varnish-cache/lib/libvcl/vcl_gen_fixed_token.tcl
===================================================================
--- trunk/varnish-cache/lib/libvcl/vcl_gen_fixed_token.tcl	2006-03-02 10:32:59 UTC (rev 42)
+++ trunk/varnish-cache/lib/libvcl/vcl_gen_fixed_token.tcl	2006-03-13 12:37:04 UTC (rev 43)
@@ -0,0 +1,171 @@
+#!/usr/local/bin/tclsh8.4
+#
+# Generate a C source file to recognize a set of tokens for the
+# Varnish 
+
+set keywords {
+	if else elseif elsif
+
+	func proc sub
+
+	acl
+
+	backend
+
+	error
+	fetch
+	call
+	no_cache
+	no_new_cache
+	set
+	rewrite
+	finish
+	switch_config
+}
+
+set magic {
+	{"++"	INC}
+	{"--"	DEC}
+	{"&&"	CAND}
+	{"||"	COR}
+	{"<="	LEQ}
+	{"=="	EQ}
+	{"!="	NEQ}
+	{">="	GEQ}
+	{">>"	SHR}
+	{"<<"	SHL}
+	{"+="	INCR}
+	{"/="	DECR}
+	{"*="	MUL}
+	{"/="	DIV}
+}
+
+set char {{}()*+-/%><=;!&.|~,}
+
+set extras {ID VAR CNUM CSTR EOI}
+
+set fo [open "vcl_fixed_token.c" w]
+
+puts $fo {/*
+ * NB:  This file is machine generated, DO NOT EDIT!
+ * instead, edit the Tcl script vcl_gen_fixed_token.tcl and run it by hand
+ */
+}
+
+set foh [open "vcl_token_defs.h" w]
+puts $foh {/*
+ * NB:  This file is machine generated, DO NOT EDIT!
+ * instead, edit the Tcl script vcl_gen_fixed_token.tcl and run it by hand
+ */
+}
+
+puts $fo "#include \"vcl_priv.h\""
+
+set tn 128
+puts $foh "#define LOW_TOKEN $tn"
+
+foreach k $keywords {
+	set t T_[string toupper $k]
+	lappend tokens [list $t $k]
+	puts $foh "#define $t $tn"
+	incr tn
+	lappend fixed [list $k $t 1]
+}
+foreach k $magic {
+	set t T_[string toupper [lindex $k 1]]
+	lappend tokens [list $t [lindex $k 0]]
+	puts $foh "#define $t $tn"
+	incr tn
+	lappend fixed [list [lindex $k 0] $t 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
+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 *tnames\[256\] = {"
+foreach i $token2 {
+	puts $fo "\t\[[lindex $i 0]\] = \"[lindex $i 0]\" /* t2 $i */,"
+}
+foreach i $tokens {
+	puts $fo "\t\[[lindex $i 0]\] = \"[lindex $i 1]\" /* t $i */,"
+}
+puts $fo "};"
+
+close $foh
+close $fo


Property changes on: trunk/varnish-cache/lib/libvcl/vcl_gen_fixed_token.tcl
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/varnish-cache/lib/libvcl/vcl_lang.h
===================================================================
--- trunk/varnish-cache/lib/libvcl/vcl_lang.h	2006-03-02 10:32:59 UTC (rev 42)
+++ trunk/varnish-cache/lib/libvcl/vcl_lang.h	2006-03-13 12:37:04 UTC (rev 43)
@@ -0,0 +1,62 @@
+/*
+ * Stuff necessary to compile a VCL programs C code
+ */
+
+
+struct vcl_ref {
+	unsigned	line;
+	unsigned	pos;
+	unsigned	count;
+	const char	*token;
+};
+
+struct vcl_acl {
+	unsigned	ip;
+	unsigned	mask;
+};
+
+struct client {
+	unsigned	ip;
+};
+
+struct req {
+	char		*req;
+	char		*useragent;
+	struct {
+		char		*path;
+		char		*host;
+	}		url;
+	double		ttlfactor;
+	struct backend	*backend;
+};
+
+struct backend {
+	unsigned	ip;
+	double		responsetime;
+	double		timeout;
+	double		bandwidth;
+	int		down;
+};
+
+struct obj {
+	int		exists;
+	double		ttl;
+	unsigned	result;
+	unsigned	size;
+	unsigned	usage;
+};
+
+#define VCL_FARGS	struct client *client, struct obj *obj, struct req *req, struct backend *backend
+#define VCL_PASS_ARGS	client, obj, req, backend
+
+void VCL_count(unsigned);
+void VCL_no_cache();
+void VCL_no_new_cache();
+int ip_match(unsigned, struct vcl_acl *);
+int string_match(const char *, const char *);
+int VCL_rewrite(const char *, const char *);
+int VCL_error(unsigned, const char *);
+int VCL_fetch(void);
+int VCL_switch_config(const char *);
+
+

Added: trunk/varnish-cache/lib/libvcl/vcl_priv.h
===================================================================
--- trunk/varnish-cache/lib/libvcl/vcl_priv.h	2006-03-02 10:32:59 UTC (rev 42)
+++ trunk/varnish-cache/lib/libvcl/vcl_priv.h	2006-03-13 12:37:04 UTC (rev 43)
@@ -0,0 +1,12 @@
+/*
+ * Stuff shared between main.c and fixed_token.c
+ */
+
+#include "vcl_token_defs.h"
+#include <ctype.h>
+
+#define isident1(c) (isalpha(c))
+#define isident(c) (isalpha(c) || isdigit(c) || (c) == '_')
+#define isvar(c) (isident(c) || (c) == '.')
+unsigned fixed_token(const char *p, const char **q);
+extern const char *tnames[256];

Added: trunk/varnish-cache/lib/libvcl/vcl_token_defs.h
===================================================================
--- trunk/varnish-cache/lib/libvcl/vcl_token_defs.h	2006-03-02 10:32:59 UTC (rev 42)
+++ trunk/varnish-cache/lib/libvcl/vcl_token_defs.h	2006-03-13 12:37:04 UTC (rev 43)
@@ -0,0 +1,43 @@
+/*
+ * NB:  This file is machine generated, DO NOT EDIT!
+ * instead, edit the Tcl script vcl_gen_fixed_token.tcl and run it by hand
+ */
+
+#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_ERROR 137
+#define T_FETCH 138
+#define T_CALL 139
+#define T_NO_CACHE 140
+#define T_NO_NEW_CACHE 141
+#define T_SET 142
+#define T_REWRITE 143
+#define T_FINISH 144
+#define T_SWITCH_CONFIG 145
+#define T_INC 146
+#define T_DEC 147
+#define T_CAND 148
+#define T_COR 149
+#define T_LEQ 150
+#define T_EQ 151
+#define T_NEQ 152
+#define T_GEQ 153
+#define T_SHR 154
+#define T_SHL 155
+#define T_INCR 156
+#define T_DECR 157
+#define T_MUL 158
+#define T_DIV 159
+#define ID 160
+#define VAR 161
+#define CNUM 162
+#define CSTR 163
+#define EOI 164




More information about the varnish-commit mailing list