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