From: phk Date: Mon, 13 Mar 2006 12:37:04 +0000 (+0000) Subject: Add first cut of VCL compiler to the tree. X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=69b28b66f6ec241198c94e169d3434b49fa61960;p=varnish 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... git-svn-id: svn+ssh://projects.linpro.no/svn/varnish/trunk@43 d4fa192b-c00b-0410-8231-f00ffab90ce4 --- diff --git a/varnish-cache/lib/Makefile.am b/varnish-cache/lib/Makefile.am index d7e87680..54952a21 100644 --- a/varnish-cache/lib/Makefile.am +++ b/varnish-cache/lib/Makefile.am @@ -2,4 +2,5 @@ SUBDIRS = \ libvarnish \ - libvarnishapi + libvarnishapi \ + libvcl diff --git a/varnish-cache/lib/libvcl/Makefile b/varnish-cache/lib/libvcl/Makefile new file mode 100644 index 00000000..9b97e0b4 --- /dev/null +++ b/varnish-cache/lib/libvcl/Makefile @@ -0,0 +1,20 @@ +PROG = vpc + +SRCS += vcl_compile.c +SRCS += vcl_fixed_token.c + +NO_MAN = yes + +WARNS ?= 5 + +LDADD += -lsbuf + +.include + + +test: ${PROG} + ./${PROG} ${.CURDIR}/sample.vcl + cc -Wall -c _.c + +flint: + flint flint.lnt -I/usr/include -I. ${SRCS} diff --git a/varnish-cache/lib/libvcl/sample.vcl b/varnish-cache/lib/libvcl/sample.vcl new file mode 100644 index 00000000..24bc4789 --- /dev/null +++ b/varnish-cache/lib/libvcl/sample.vcl @@ -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; + } +} diff --git a/varnish-cache/lib/libvcl/vcl_compile.c b/varnish-cache/lib/libvcl/vcl_compile.c new file mode 100644 index 00000000..ef1dc0e0 --- /dev/null +++ b/varnish-cache/lib/libvcl/vcl_compile.c @@ -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 +#include +#include +#include +#include +#include +#include +#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 + +#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); +} diff --git a/varnish-cache/lib/libvcl/vcl_fixed_token.c b/varnish-cache/lib/libvcl/vcl_fixed_token.c new file mode 100644 index 00000000..3b226b0f --- /dev/null +++ b/varnish-cache/lib/libvcl/vcl_fixed_token.c @@ -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 */, +}; diff --git a/varnish-cache/lib/libvcl/vcl_gen_fixed_token.tcl b/varnish-cache/lib/libvcl/vcl_gen_fixed_token.tcl new file mode 100755 index 00000000..8c13712b --- /dev/null +++ b/varnish-cache/lib/libvcl/vcl_gen_fixed_token.tcl @@ -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 diff --git a/varnish-cache/lib/libvcl/vcl_lang.h b/varnish-cache/lib/libvcl/vcl_lang.h new file mode 100644 index 00000000..318abde2 --- /dev/null +++ b/varnish-cache/lib/libvcl/vcl_lang.h @@ -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 *); + + diff --git a/varnish-cache/lib/libvcl/vcl_priv.h b/varnish-cache/lib/libvcl/vcl_priv.h new file mode 100644 index 00000000..b8875ecf --- /dev/null +++ b/varnish-cache/lib/libvcl/vcl_priv.h @@ -0,0 +1,12 @@ +/* + * Stuff shared between main.c and fixed_token.c + */ + +#include "vcl_token_defs.h" +#include + +#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]; diff --git a/varnish-cache/lib/libvcl/vcl_token_defs.h b/varnish-cache/lib/libvcl/vcl_token_defs.h new file mode 100644 index 00000000..29655dc9 --- /dev/null +++ b/varnish-cache/lib/libvcl/vcl_token_defs.h @@ -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