r544 - trunk/varnish-cache/lib/libvcl
phk at projects.linpro.no
phk at projects.linpro.no
Fri Jul 21 20:12:59 CEST 2006
Author: phk
Date: 2006-07-21 20:12:56 +0200 (Fri, 21 Jul 2006)
New Revision: 544
Added:
trunk/varnish-cache/lib/libvcl/vcc_compile.c
trunk/varnish-cache/lib/libvcl/vcc_compile.h
trunk/varnish-cache/lib/libvcl/vcc_fixed_token.c
trunk/varnish-cache/lib/libvcl/vcc_gen_fixed_token.tcl
trunk/varnish-cache/lib/libvcl/vcc_obj.c
trunk/varnish-cache/lib/libvcl/vcc_priv.h
trunk/varnish-cache/lib/libvcl/vcc_token.c
trunk/varnish-cache/lib/libvcl/vcc_token_defs.h
Removed:
trunk/varnish-cache/lib/libvcl/vcl_fixed_token.c
trunk/varnish-cache/lib/libvcl/vcl_gen_fixed_token.tcl
trunk/varnish-cache/lib/libvcl/vcl_priv.h
trunk/varnish-cache/lib/libvcl/vcl_token_defs.h
Modified:
trunk/varnish-cache/lib/libvcl/Makefile.am
Log:
Move things over to the correct "VCC" prefix.
Split some stuff into separate files while we're at it.
Modified: trunk/varnish-cache/lib/libvcl/Makefile.am
===================================================================
--- trunk/varnish-cache/lib/libvcl/Makefile.am 2006-07-21 16:25:24 UTC (rev 543)
+++ trunk/varnish-cache/lib/libvcl/Makefile.am 2006-07-21 18:12:56 UTC (rev 544)
@@ -5,8 +5,11 @@
lib_LTLIBRARIES = libvcl.la
libvcl_la_SOURCES = \
- vcl_priv.h \
- vcl_token_defs.h \
+ vcc_priv.h \
+ vcc_compile.h \
+ vcc_token_defs.h \
\
- vcl_compile.c \
- vcl_fixed_token.c
+ vcc_compile.c \
+ vcc_fixed_token.c \
+ vcc_obj.c \
+ vcc_token.c
Added: trunk/varnish-cache/lib/libvcl/vcc_compile.c
===================================================================
--- trunk/varnish-cache/lib/libvcl/vcc_compile.c 2006-07-21 16:25:24 UTC (rev 543)
+++ trunk/varnish-cache/lib/libvcl/vcc_compile.c 2006-07-21 18:12:56 UTC (rev 544)
@@ -0,0 +1,1529 @@
+/*
+ * $Id: vcl_compile.c 531 2006-07-20 22:08:43Z phk $
+ */
+
+/*
+ * XXX:
+ * generate interface structure
+ *
+ * XXX:
+ * Better error messages, throughout.
+ * >It also accured to me that we could link the errors to the error
+ * >documentation.
+ * >
+ * >Unreferenced function 'request_policy', first mention is
+ * > Line 8 Pos 4
+ * > sub request_policy {
+ * > ----##############--
+ * >Read more about this type of error:
+ * >http://varnish/doc/error.html#Unreferenced%20function
+ * >
+ * >
+ * > Unknown variable 'obj.bandwidth'
+ * > At: Line 88 Pos 12
+ * > if (obj.bandwidth < 1 kb/h) {
+ * > ------------#############------------
+ * >Read more about this type of error:
+ * >http://varnish/doc/error.html#Unknown%20variable
+ *
+ * XXX:
+ * Create proper tmp filenames for .h, .c and .o
+ *
+ * XXX:
+ * and all the rest...
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <printf.h>
+#include <stdarg.h>
+#include <sbuf.h>
+#include <stdlib.h>
+#include <string.h>
+#include <queue.h>
+#include <unistd.h>
+
+#include "vcc_priv.h"
+#include "vcc_compile.h"
+
+#include "libvcl.h"
+
+#define ERRCHK(tl) do { if ((tl)->err) return; } while (0)
+
+/*--------------------------------------------------------------------*/
+
+static void Compound(struct tokenlist *tl);
+static void Cond_0(struct tokenlist *tl);
+static struct proc *AddProc(struct tokenlist *tl, struct token *t, int def);
+static void AddCall(struct tokenlist *tl, struct token *t);
+const char *vcc_default_vcl_b, *vcc_default_vcl_e;
+
+/*--------------------------------------------------------------------*/
+
+#define ErrInternal(tl) vcc__ErrInternal(tl, __func__, __LINE__)
+
+#define Expect(a, b) vcc__Expect(a, b, __LINE__)
+#define ExpectErr(a, b) do { vcc__Expect(a, b, __LINE__); ERRCHK(a);} while (0)
+
+#define L(tl, foo) do { \
+ tl->indent += INDENT; \
+ foo; \
+ tl->indent -= INDENT; \
+} while (0)
+
+#define C(tl, sep) do { \
+ Fc(tl, 1, "VRT_count(sp, %u)%s\n", ++tl->cnt, sep); \
+ tl->t->cnt = tl->cnt; \
+} while (0)
+
+/*--------------------------------------------------------------------
+ * Printf output to the two sbufs, possibly indented
+ */
+
+static void
+Fh(struct tokenlist *tl, int indent, const char *fmt, ...)
+{
+ va_list ap;
+
+ if (indent)
+ sbuf_printf(tl->fh, "%*.*s", tl->indent, tl->indent, "");
+ va_start(ap, fmt);
+ sbuf_vprintf(tl->fh, fmt, ap);
+ va_end(ap);
+}
+
+static void
+Fc(struct tokenlist *tl, int indent, const char *fmt, ...)
+{
+ va_list ap;
+
+ if (indent)
+ sbuf_printf(tl->fc, "%*.*s", tl->indent, tl->indent, "");
+ va_start(ap, fmt);
+ sbuf_vprintf(tl->fc, fmt, ap);
+ va_end(ap);
+}
+
+/*--------------------------------------------------------------------*/
+
+static char *
+EncString(struct token *t)
+{
+ char *p, *q;
+ const char *r;
+ unsigned u;
+
+ assert(t->tok == CSTR);
+ p = malloc(t->e - t->b);
+ assert(p != NULL);
+ q = p;
+ for (r = t->b + 1; r < t->e - 1; ) {
+ if (*r != '\\') {
+ *q++ = *r++;
+ continue;
+ }
+ switch (r[1]) {
+ case 'n': *q++ = '\n'; r += 2; break;
+ case 'r': *q++ = '\r'; r += 2; break;
+ case 'v': *q++ = '\v'; r += 2; break;
+ case 'f': *q++ = '\f'; r += 2; break;
+ case 't': *q++ = '\t'; r += 2; break;
+ case 'b': *q++ = '\b'; r += 2; break;
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ u = r[1] - '0';
+ r += 2;
+ if (isdigit(r[0]) && (r[0] - '0') < 8) {
+ u <<= 3;
+ u |= r[0] - '0';
+ r++;
+ if (isdigit(r[0]) && (r[0] - '0') < 8) {
+ u <<= 3;
+ u |= r[0] - '0';
+ r++;
+ }
+ }
+ *q++ = u;
+ break;
+ default:
+ *q++ = r[1];
+ r += 2;
+ break;
+ }
+ }
+ *q = '\0';
+ return (p);
+}
+
+
+/*--------------------------------------------------------------------
+ * Keep track of definitions and references
+ */
+
+static struct ref *
+FindRef(struct tokenlist *tl, struct token *t, enum ref_type type)
+{
+ struct ref *r;
+
+ TAILQ_FOREACH(r, &tl->refs, list) {
+ if (r->type != type)
+ continue;
+ if (vcc_Teq(r->name, t))
+ return (r);
+ }
+ r = calloc(sizeof *r, 1);
+ assert(r != NULL);
+ r->name = t;
+ r->type = type;
+ TAILQ_INSERT_TAIL(&tl->refs, r, list);
+ return (r);
+}
+
+static int
+FindRefStr(struct tokenlist *tl, const char *s, enum ref_type type)
+{
+ struct ref *r;
+
+ TAILQ_FOREACH(r, &tl->refs, list) {
+ if (r->type != type)
+ continue;
+ if (vcc_IdIs(r->name, s))
+ return (1);
+ }
+ return (0);
+}
+
+static void
+AddRef(struct tokenlist *tl, struct token *t, enum ref_type type)
+{
+
+ FindRef(tl, t, type)->refcnt++;
+}
+
+static void
+AddRefStr(struct tokenlist *tl, const char *s, enum ref_type type)
+{
+ struct token *t;
+
+ t = calloc(sizeof *t, 1);
+ t->b = s;
+ t->e = strchr(s, '\0');
+ t->tok = METHOD;
+ AddRef(tl, t, type);
+}
+
+static void
+AddDef(struct tokenlist *tl, struct token *t, enum ref_type type)
+{
+ struct ref *r;
+
+ r = FindRef(tl, t, type);
+ r->defcnt++;
+ r->name = t;
+}
+
+/*--------------------------------------------------------------------
+ * Recognize and convert units of time, return seconds.
+ */
+
+static double
+TimeUnit(struct tokenlist *tl)
+{
+ double sc = 1.0;
+
+ assert(tl->t->tok == ID);
+ if (vcc_IdIs(tl->t, "ms"))
+ sc = 1e-3;
+ else if (vcc_IdIs(tl->t, "s"))
+ sc = 1.0;
+ else if (vcc_IdIs(tl->t, "m"))
+ sc = 60.0;
+ else if (vcc_IdIs(tl->t, "h"))
+ sc = 60.0 * 60.0;
+ else if (vcc_IdIs(tl->t, "d"))
+ sc = 60.0 * 60.0 * 24.0;
+ else {
+ sbuf_printf(tl->sb, "Unknown time unit ");
+ vcc_ErrToken(tl, tl->t);
+ sbuf_printf(tl->sb, ". Legal are 's', 'm', 'h' and 'd'\n");
+ vcc_ErrWhere(tl, tl->t);
+ return (1.0);
+ }
+ vcc_NextToken(tl);
+ return (sc);
+}
+
+/*--------------------------------------------------------------------
+ * Recognize and convert units of size, return bytes.
+ */
+
+static double
+SizeUnit(struct tokenlist *tl)
+{
+ double sc = 1.0;
+
+ assert(tl->t->tok == ID);
+ if (vcc_IdIs(tl->t, "b"))
+ sc = 1.0;
+ else if (vcc_IdIs(tl->t, "kb"))
+ sc = 1024.0;
+ else if (vcc_IdIs(tl->t, "mb") || vcc_IdIs(tl->t, "Mb"))
+ sc = 1024.0 * 1024.0;
+ else if (vcc_IdIs(tl->t, "gb") || vcc_IdIs(tl->t, "Gb"))
+ sc = 1024.0 * 1024.0 * 1024.0;
+ else {
+ sbuf_printf(tl->sb, "Unknown size unit ");
+ vcc_ErrToken(tl, tl->t);
+ sbuf_printf(tl->sb, ". Legal are 'kb', 'mb' and 'gb'\n");
+ vcc_ErrWhere(tl, tl->t);
+ return (1.0);
+ }
+ vcc_NextToken(tl);
+ return (sc);
+}
+
+/*--------------------------------------------------------------------
+ * Recognize and convert units of rate as { space '/' time }
+ */
+
+static double
+RateUnit(struct tokenlist *tl)
+{
+ double sc = 1.0;
+
+ assert(tl->t->tok == ID);
+ sc = SizeUnit(tl);
+ Expect(tl, '/');
+ vcc_NextToken(tl);
+ sc /= TimeUnit(tl);
+ return (sc);
+}
+
+/*--------------------------------------------------------------------
+ * Recognize and convert { CNUM } to unsigned value
+ */
+
+static unsigned
+UintVal(struct tokenlist *tl)
+{
+ unsigned d = 0;
+ const char *p;
+
+ Expect(tl, CNUM);
+ for (p = tl->t->b; p < tl->t->e; p++) {
+ d *= 10;
+ d += *p - '0';
+ }
+ vcc_NextToken(tl);
+ return (d);
+}
+
+/*--------------------------------------------------------------------
+ * Recognize and convert { CNUM [ '.' [ CNUM ] ] } to double value
+ */
+
+static double
+DoubleVal(struct tokenlist *tl)
+{
+ double d = 0.0, e = 0.1;
+ const char *p;
+
+ Expect(tl, CNUM);
+ for (p = tl->t->b; p < tl->t->e; p++) {
+ d *= 10;
+ d += *p - '0';
+ }
+ vcc_NextToken(tl);
+ if (tl->t->tok != '.')
+ return (d);
+ vcc_NextToken(tl);
+ if (tl->t->tok != CNUM)
+ return (d);
+ for (p = tl->t->b; p < tl->t->e; p++) {
+ d += (*p - '0') * e;
+ e *= 0.1;
+ }
+ vcc_NextToken(tl);
+ return (d);
+}
+
+/*--------------------------------------------------------------------*/
+
+static unsigned
+IpVal(struct tokenlist *tl)
+{
+ unsigned u, v;
+ struct token *t;
+
+ t = tl->t;
+ u = UintVal(tl);
+ if (u < 256) {
+ v = u << 24;
+ Expect(tl, '.');
+ vcc_NextToken(tl);
+ t = tl->t;
+ u = UintVal(tl);
+ if (u < 256) {
+ v |= u << 16;
+ Expect(tl, '.');
+ vcc_NextToken(tl);
+ t = tl->t;
+ u = UintVal(tl);
+ if (u < 256) {
+ v |= u << 8;
+ Expect(tl, '.');
+ vcc_NextToken(tl);
+ t = tl->t;
+ u = UintVal(tl);
+ if (u < 256) {
+ v |= u;
+ return (v);
+ }
+ }
+ }
+ }
+ sbuf_printf(tl->sb, "Illegal octet in IP number\n");
+ vcc_ErrWhere(tl, t);
+ return (0);
+}
+
+/*--------------------------------------------------------------------*/
+
+static struct var *
+HeaderVar(struct tokenlist *tl __unused, struct token *t, struct var *vh)
+{
+ char *p;
+ struct var *v;
+ int i;
+
+ v = calloc(sizeof *v, 1);
+ assert(v != NULL);
+ i = t->e - t->b;
+ p = malloc(i + 1);
+ assert(p != NULL);
+ memcpy(p, t->b, i);
+ p[i] = '\0';
+ v->name = p;
+ v->fmt = STRING;
+ asprintf(&p, "VRT_GetHdr(sp, \"\\%03o%s:\")",
+ strlen(v->name + vh->len) + 1, v->name + vh->len);
+ assert(p != NULL);
+ v->rname = p;
+ return (v);
+}
+
+/*--------------------------------------------------------------------*/
+
+static struct var *
+FindVar(struct tokenlist *tl, struct token *t, struct var *vl)
+{
+ struct var *v;
+
+ for (v = vl; v->name != NULL; v++) {
+ if (v->fmt == HEADER && t->e - t->b <= v->len)
+ continue;
+ if (v->fmt != HEADER && t->e - t->b != v->len)
+ continue;
+ if (memcmp(t->b, v->name, v->len))
+ continue;
+ if (v->fmt != HEADER)
+ return (v);
+ return (HeaderVar(tl, t, v));
+ }
+ sbuf_printf(tl->sb, "Unknown variable ");
+ vcc_ErrToken(tl, t);
+ sbuf_cat(tl->sb, "\nAt: ");
+ vcc_ErrWhere(tl, t);
+ return (NULL);
+}
+
+
+/*--------------------------------------------------------------------*/
+
+static void
+TimeVal(struct tokenlist *tl)
+{
+ double v, sc;
+
+ v = DoubleVal(tl);
+ ExpectErr(tl, ID);
+ sc = TimeUnit(tl);
+ Fc(tl, 0, "(%g * %g)", v, sc);
+}
+
+static void
+SizeVal(struct tokenlist *tl)
+{
+ double v, sc;
+
+ v = DoubleVal(tl);
+ ExpectErr(tl, ID);
+ sc = SizeUnit(tl);
+ Fc(tl, 0, "(%g * %g)", v, sc);
+}
+
+static void
+RateVal(struct tokenlist *tl)
+{
+ double v, sc;
+
+ v = DoubleVal(tl);
+ ExpectErr(tl, ID);
+ sc = RateUnit(tl);
+ Fc(tl, 0, "(%g * %g)", v, sc);
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+Cond_Ip(struct var *vp, struct tokenlist *tl)
+{
+ unsigned u;
+
+ switch (tl->t->tok) {
+ case '~':
+ vcc_NextToken(tl);
+ ExpectErr(tl, ID);
+ AddRef(tl, tl->t, R_ACL);
+ Fc(tl, 1, "ip_match(%s, acl_%T)\n", vp->rname, tl->t);
+ vcc_NextToken(tl);
+ break;
+ case T_EQ:
+ case T_NEQ:
+ Fc(tl, 1, "%s %T ", vp->rname, tl->t);
+ vcc_NextToken(tl);
+ u = IpVal(tl);
+ Fc(tl, 0, "%uU /* %u.%u.%u.%u */\n", u,
+ (u >> 24) & 0xff, (u >> 16) & 0xff,
+ (u >> 8) & 0xff, (u) & 0xff);
+ break;
+ default:
+ sbuf_printf(tl->sb, "Illegal condition ");
+ vcc_ErrToken(tl, tl->t);
+ sbuf_printf(tl->sb, " on IP number variable\n");
+ sbuf_printf(tl->sb, " only '==', '!=' and '~' are legal\n");
+ vcc_ErrWhere(tl, tl->t);
+ break;
+ }
+}
+
+static void
+Cond_String(struct var *vp, struct tokenlist *tl)
+{
+
+ switch (tl->t->tok) {
+ case '~':
+ Fc(tl, 1, "string_match(%s, ", vp->rname);
+ vcc_NextToken(tl);
+ ExpectErr(tl, CSTR);
+ Fc(tl, 0, "%T)\n", tl->t);
+ vcc_NextToken(tl);
+ break;
+ case T_EQ:
+ case T_NEQ:
+ Fc(tl, 1, "%sstrcmp(%s, ",
+ tl->t->tok == T_EQ ? "!" : "", vp->rname);
+ vcc_NextToken(tl);
+ ExpectErr(tl, CSTR);
+ Fc(tl, 0, "%T)\n", tl->t);
+ vcc_NextToken(tl);
+ break;
+ default:
+ Fc(tl, 1, "%s != (void*)0", vp->rname);
+ break;
+ }
+}
+
+static void
+Cond_Int(struct var *vp, struct tokenlist *tl)
+{
+
+ Fc(tl, 1, "%s ", vp->rname);
+ switch (tl->t->tok) {
+ case T_EQ:
+ case T_NEQ:
+ case T_LEQ:
+ case T_GEQ:
+ case '>':
+ case '<':
+ Fc(tl, 0, "%T ", tl->t);
+ vcc_NextToken(tl);
+ switch(vp->fmt) {
+ case TIME:
+ TimeVal(tl);
+ break;
+ case INT:
+ ExpectErr(tl, CNUM);
+ Fc(tl, 0, "%T ", tl->t);
+ vcc_NextToken(tl);
+ break;
+ case SIZE:
+ SizeVal(tl);
+ break;
+ default:
+ sbuf_printf(tl->sb,
+ "No conditions available for variable '%s'\n",
+ vp->name);
+ vcc_ErrWhere(tl, tl->t);
+ return;
+ }
+ Fc(tl, 0, "\n");
+ break;
+ default:
+ sbuf_printf(tl->sb, "Illegal condition ");
+ vcc_ErrToken(tl, tl->t);
+ sbuf_printf(tl->sb, " on integer variable\n");
+ sbuf_printf(tl->sb,
+ " only '==', '!=', '<', '>', '<=' and '>=' are legal\n");
+ vcc_ErrWhere(tl, tl->t);
+ break;
+ }
+}
+
+static void
+Cond_Bool(struct var *vp, struct tokenlist *tl)
+{
+
+ Fc(tl, 1, "%s\n", vp->rname);
+}
+
+static void
+Cond_2(struct tokenlist *tl)
+{
+ struct var *vp;
+
+ C(tl, ",");
+ if (tl->t->tok == '!') {
+ Fc(tl, 1, "!(\n");
+ vcc_NextToken(tl);
+ } else {
+ Fc(tl, 1, "(\n");
+ }
+ if (tl->t->tok == '(') {
+ vcc_NextToken(tl);
+ Cond_0(tl);
+ ExpectErr(tl, ')');
+ vcc_NextToken(tl);
+ } else if (tl->t->tok == VAR) {
+ vp = FindVar(tl, tl->t, vcc_vars);
+ ERRCHK(tl);
+ assert(vp != NULL);
+ vcc_NextToken(tl);
+ switch (vp->fmt) {
+ case INT: L(tl, Cond_Int(vp, tl)); break;
+ case SIZE: L(tl, Cond_Int(vp, tl)); break;
+ case BOOL: L(tl, Cond_Bool(vp, tl)); break;
+ case IP: L(tl, Cond_Ip(vp, tl)); break;
+ case STRING: L(tl, Cond_String(vp, tl)); break;
+ case TIME: L(tl, Cond_Int(vp, tl)); break;
+ /* XXX backend == */
+ default:
+ sbuf_printf(tl->sb,
+ "Variable '%s'"
+ " has no conditions that can be checked\n",
+ vp->name);
+ vcc_ErrWhere(tl, tl->t);
+ return;
+ }
+ } else {
+ sbuf_printf(tl->sb,
+ "Syntax error in condition, expected '(', '!' or"
+ " variable name, found ");
+ vcc_ErrToken(tl, tl->t);
+ sbuf_printf(tl->sb, "\n");
+ vcc_ErrWhere(tl, tl->t);
+ return;
+ }
+ Fc(tl, 1, ")\n");
+}
+
+static void
+Cond_1(struct tokenlist *tl)
+{
+
+ Fc(tl, 1, "(\n");
+ L(tl, Cond_2(tl));
+ while (tl->t->tok == T_CAND) {
+ vcc_NextToken(tl);
+ Fc(tl, 1, ") && (\n");
+ L(tl, Cond_2(tl));
+ }
+ Fc(tl, 1, ")\n");
+}
+
+static void
+Cond_0(struct tokenlist *tl)
+{
+
+ Fc(tl, 1, "(\n");
+ L(tl, Cond_1(tl));
+ while (tl->t->tok == T_COR) {
+ vcc_NextToken(tl);
+ Fc(tl, 1, ") || (\n");
+ L(tl, Cond_1(tl));
+ }
+ Fc(tl, 1, ")\n");
+}
+
+static void
+Conditional(struct tokenlist *tl)
+{
+
+ ExpectErr(tl, '(');
+ vcc_NextToken(tl);
+ Fc(tl, 1, "(\n");
+ L(tl, Cond_0(tl));
+ ERRCHK(tl);
+ Fc(tl, 1, ")\n");
+ ExpectErr(tl, ')');
+ vcc_NextToken(tl);
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+IfStmt(struct tokenlist *tl)
+{
+
+ ExpectErr(tl, T_IF);
+ Fc(tl, 1, "if \n");
+ vcc_NextToken(tl);
+ L(tl, Conditional(tl));
+ ERRCHK(tl);
+ L(tl, Compound(tl));
+ ERRCHK(tl);
+ while (1) {
+ switch (tl->t->tok) {
+ case T_ELSE:
+ vcc_NextToken(tl);
+ if (tl->t->tok != T_IF) {
+ Fc(tl, 1, "else \n");
+ L(tl, Compound(tl));
+ ERRCHK(tl);
+ return;
+ }
+ /* FALLTHROUGH */
+ case T_ELSEIF:
+ case T_ELSIF:
+ Fc(tl, 1, "else if \n");
+ vcc_NextToken(tl);
+ L(tl, Conditional(tl));
+ ERRCHK(tl);
+ L(tl, Compound(tl));
+ ERRCHK(tl);
+ break;
+ default:
+ C(tl, ";");
+ return;
+ }
+ }
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+Action(struct tokenlist *tl)
+{
+ unsigned a, u;
+ struct var *vp;
+ struct token *at;
+
+ at = tl->t;
+ vcc_NextToken(tl);
+ switch (at->tok) {
+ case T_NO_NEW_CACHE:
+ Fc(tl, 1, "VCL_no_new_cache(sp);\n");
+ return;
+ case T_NO_CACHE:
+ Fc(tl, 1, "VCL_no_cache(sp);\n");
+ return;
+#define VCL_RET_MAC(a,b,c) case T_##b: \
+ Fc(tl, 1, "VRT_done(sp, VCL_RET_%s);\n", #b); \
+ tl->curproc->returns |= VCL_RET_##b; \
+ tl->curproc->returnt[c] = at; \
+ return;
+#include "vcl_returns.h"
+#undef VCL_RET_MAC
+ case T_ERROR:
+ if (tl->t->tok == CNUM)
+ a = UintVal(tl);
+ else
+ a = 0;
+ Fc(tl, 1, "VRT_error(sp, %u, ", a);
+ if (tl->t->tok == CSTR) {
+ Fc(tl, 0, "%T);\n", tl->t);
+ vcc_NextToken(tl);
+ } else
+ Fc(tl, 0, "(const char *)0);\n");
+ Fc(tl, 1, "VRT_done(sp, VCL_RET_ERROR);\n");
+ return;
+ case T_SWITCH_CONFIG:
+ ExpectErr(tl, ID);
+ Fc(tl, 1, "VCL_switch_config(\"%T\");\n", tl->t);
+ vcc_NextToken(tl);
+ return;
+ case T_CALL:
+ ExpectErr(tl, ID);
+ AddCall(tl, tl->t);
+ AddRef(tl, tl->t, R_FUNC);
+ Fc(tl, 1, "if (VGC_function_%T(sp))\n", tl->t);
+ Fc(tl, 1, "\treturn (1);\n");
+ vcc_NextToken(tl);
+ return;
+ case T_REWRITE:
+ ExpectErr(tl, CSTR);
+ Fc(tl, 1, "VCL_rewrite(%T", tl->t);
+ vcc_NextToken(tl);
+ ExpectErr(tl, CSTR);
+ Fc(tl, 0, ", %T);\n", tl->t);
+ vcc_NextToken(tl);
+ return;
+ case T_SET:
+ ExpectErr(tl, VAR);
+ vp = FindVar(tl, tl->t, vcc_vars);
+ ERRCHK(tl);
+ assert(vp != NULL);
+ Fc(tl, 1, "%s ", vp->rname);
+ vcc_NextToken(tl);
+ switch (vp->fmt) {
+ case INT:
+ case SIZE:
+ case RATE:
+ case TIME:
+ case FLOAT:
+ Fc(tl, 0, "%T ", tl->t);
+ a = tl->t->tok;
+ vcc_NextToken(tl);
+ if (a == T_MUL || a == T_DIV)
+ Fc(tl, 0, "%g", DoubleVal(tl));
+ else if (vp->fmt == TIME)
+ TimeVal(tl);
+ else if (vp->fmt == SIZE)
+ SizeVal(tl);
+ else if (vp->fmt == RATE)
+ RateVal(tl);
+ else
+ Fc(tl, 0, "%g", DoubleVal(tl));
+ Fc(tl, 0, ";\n");
+ break;
+ case IP:
+ if (tl->t->tok == '=') {
+ vcc_NextToken(tl);
+ u = IpVal(tl);
+ Fc(tl, 0, "= %uU; /* %u.%u.%u.%u */\n",
+ u,
+ (u >> 24) & 0xff,
+ (u >> 16) & 0xff,
+ (u >> 8) & 0xff,
+ u & 0xff);
+ break;
+ }
+ sbuf_printf(tl->sb, "Illegal assignment operator ");
+ vcc_ErrToken(tl, tl->t);
+ sbuf_printf(tl->sb,
+ " only '=' is legal for IP numbers\n");
+ vcc_ErrWhere(tl, tl->t);
+ return;
+ case BACKEND:
+ if (tl->t->tok == '=') {
+ vcc_NextToken(tl);
+ AddRef(tl, tl->t, R_BACKEND);
+ Fc(tl, 0, "= &VGC_backend_%T;\n", tl->t);
+ vcc_NextToken(tl);
+ break;
+ }
+ sbuf_printf(tl->sb, "Illegal assignment operator ");
+ vcc_ErrToken(tl, tl->t);
+ sbuf_printf(tl->sb,
+ " only '=' is legal for backend\n");
+ vcc_ErrWhere(tl, tl->t);
+ return;
+ default:
+ sbuf_printf(tl->sb,
+ "Assignments not possible for '%s'\n", vp->name);
+ vcc_ErrWhere(tl, tl->t);
+ return;
+ }
+ return;
+ default:
+ sbuf_printf(tl->sb, "Expected action, 'if' or '}'\n");
+ vcc_ErrWhere(tl, at);
+ return;
+ }
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+Acl(struct tokenlist *tl)
+{
+ unsigned u, m;
+
+ vcc_NextToken(tl);
+
+ ExpectErr(tl, ID);
+ AddDef(tl, tl->t, R_ACL);
+ Fh(tl, 0, "static struct vcl_acl acl_%T[];\n", tl->t);
+ Fc(tl, 1, "static struct vcl_acl acl_%T[] = {\n", tl->t);
+ vcc_NextToken(tl);
+
+ tl->indent += INDENT;
+
+ ExpectErr(tl, '{');
+ vcc_NextToken(tl);
+
+ while (tl->t->tok == CNUM) {
+ u = IpVal(tl);
+ if (tl->t->tok == '/') {
+ vcc_NextToken(tl);
+ ExpectErr(tl, CNUM);
+ m = UintVal(tl);
+ } else
+ m = 32;
+ ExpectErr(tl, ';');
+ vcc_NextToken(tl);
+ Fc(tl, 1, "{ %11uU, %3uU }, /* %u.%u.%u.%u/%u */\n",
+ u, m,
+ (u >> 24) & 0xff, (u >> 16) & 0xff,
+ (u >> 8) & 0xff, (u) & 0xff, m);
+ }
+ ExpectErr(tl, '}');
+ Fc(tl, 1, "{ %11uU, %3uU }\n", 0, 0);
+
+ tl->indent -= INDENT;
+
+ Fc(tl, 1, "};\n\n");
+ vcc_NextToken(tl);
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+Compound(struct tokenlist *tl)
+{
+
+ ExpectErr(tl, '{');
+ Fc(tl, 1, "{\n");
+ tl->indent += INDENT;
+ C(tl, ";");
+ vcc_NextToken(tl);
+ while (1) {
+ ERRCHK(tl);
+ switch (tl->t->tok) {
+ case '{':
+ Compound(tl);
+ break;
+ case T_IF:
+ IfStmt(tl);
+ break;
+ case '}':
+ vcc_NextToken(tl);
+ tl->indent -= INDENT;
+ Fc(tl, 1, "}\n");
+ return;
+ case EOI:
+ sbuf_printf(tl->sb,
+ "End of input while in compound statement\n");
+ tl->err = 1;
+ return;
+ default:
+ Action(tl);
+ ERRCHK(tl);
+ ExpectErr(tl, ';');
+ vcc_NextToken(tl);
+ break;
+ }
+ }
+}
+
+/*--------------------------------------------------------------------*/
+
+static const char *
+CheckHostPort(const char *host, const char *port)
+{
+ struct addrinfo *res, hint;
+ int error;
+
+ memset(&hint, 0, sizeof hint);
+ hint.ai_family = PF_UNSPEC;
+ hint.ai_socktype = SOCK_STREAM;
+ error = getaddrinfo(host, port, &hint, &res);
+ if (error)
+ return (gai_strerror(error));
+ freeaddrinfo(res);
+ return (NULL);
+}
+
+static void
+Backend(struct tokenlist *tl)
+{
+ struct var *vp;
+ struct token *t_be = NULL;
+ struct token *t_host = NULL;
+ struct token *t_port = NULL;
+ char *host = NULL;
+ char *port = NULL;
+ const char *ep;
+
+ vcc_NextToken(tl);
+ ExpectErr(tl, ID);
+ t_be = tl->t;
+ AddDef(tl, tl->t, R_BACKEND);
+ if (tl->nbackend == 0)
+ AddRef(tl, tl->t, R_BACKEND);
+ Fh(tl, 1, "#define VGC_backend_%T (VCL_conf.backend[%d])\n",
+ tl->t, tl->nbackend);
+ Fc(tl, 0, "static void\n");
+ Fc(tl, 1, "VGC_init_backend_%T (void)\n", tl->t);
+ Fc(tl, 1, "{\n");
+ Fc(tl, 1, "\tstruct backend *backend = VGC_backend_%T;\n", tl->t);
+ Fc(tl, 1, "\tconst char *p;\n");
+ Fc(tl, 1, "\n");
+ Fc(tl, 1, "\tVRT_set_backend_name(backend, \"%T\");\n", tl->t);
+ vcc_NextToken(tl);
+ ExpectErr(tl, '{');
+ vcc_NextToken(tl);
+ while (1) {
+ if (tl->t->tok == '}')
+ break;
+ ExpectErr(tl, T_SET);
+ vcc_NextToken(tl);
+ ExpectErr(tl, VAR);
+ vp = FindVar(tl, tl->t, vcc_be_vars);
+ ERRCHK(tl);
+ assert(vp != NULL);
+ vcc_NextToken(tl);
+ ExpectErr(tl, '=');
+ vcc_NextToken(tl);
+ switch (vp->fmt) {
+ case HOSTNAME:
+ ExpectErr(tl, CSTR);
+ t_host = tl->t;
+ Fc(tl, 1, "\tp = %T;\n", tl->t);
+ Fc(tl, 1, "\t");
+ Fc(tl, 0, vp->lname, "p");
+ Fc(tl, 0, ";\n");
+ vcc_NextToken(tl);
+ break;
+ case PORTNAME:
+ ExpectErr(tl, CSTR);
+ t_port = tl->t;
+ Fc(tl, 1, "\tp = %T;\n", tl->t);
+ Fc(tl, 1, "\t");
+ Fc(tl, 0, vp->lname, "p");
+ Fc(tl, 0, ";\n");
+ vcc_NextToken(tl);
+ break;
+ default:
+ sbuf_printf(tl->sb,
+ "Assignments not possible for '%s'\n", vp->name);
+ vcc_ErrWhere(tl, tl->t);
+ return;
+ }
+ ExpectErr(tl, ';');
+ vcc_NextToken(tl);
+ }
+ ExpectErr(tl, '}');
+ if (t_host == NULL) {
+ sbuf_printf(tl->sb, "Backend '%T' has no hostname\n", t_be);
+ vcc_ErrWhere(tl, tl->t);
+ return;
+ }
+ host = EncString(t_host);
+ ep = CheckHostPort(host, "80");
+ if (ep != NULL) {
+ sbuf_printf(tl->sb, "Backend '%T': %s\n", t_be, ep);
+ vcc_ErrWhere(tl, t_host);
+ return;
+ }
+ if (t_port != NULL) {
+ port = EncString(t_port);
+ ep = CheckHostPort(host, port);
+ if (ep != NULL) {
+ sbuf_printf(tl->sb, "Backend '%T': %s\n", t_be, ep);
+ vcc_ErrWhere(tl, t_port);
+ return;
+ }
+ }
+
+ vcc_NextToken(tl);
+ Fc(tl, 1, "}\n");
+ Fc(tl, 0, "\n");
+ tl->nbackend++;
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+Function(struct tokenlist *tl)
+{
+
+ vcc_NextToken(tl);
+ ExpectErr(tl, ID);
+ tl->curproc = AddProc(tl, tl->t, 1);
+ tl->curproc->exists++;
+ AddDef(tl, tl->t, R_FUNC);
+ Fh(tl, 0, "static int VGC_function_%T (struct sess *sp);\n", tl->t);
+ Fc(tl, 1, "static int\n");
+ Fc(tl, 1, "VGC_function_%T (struct sess *sp)\n", tl->t);
+ vcc_NextToken(tl);
+ L(tl, Compound(tl));
+ Fc(tl, 0, "\n");
+}
+
+/*--------------------------------------------------------------------
+ * Top level of parser, recognize:
+ * Function definitions
+ * Backend definitions
+ * End of input
+ */
+
+static void
+Parse(struct tokenlist *tl)
+{
+
+ while (tl->t->tok != EOI) {
+ ERRCHK(tl);
+ switch (tl->t->tok) {
+ case T_ACL:
+ Acl(tl);
+ break;
+ case T_SUB:
+ Function(tl);
+ break;
+ case T_BACKEND:
+ Backend(tl);
+ break;
+ case EOI:
+ break;
+ default:
+ sbuf_printf(tl->sb,
+ "Expected 'acl', 'sub' or 'backend', found ");
+ vcc_ErrToken(tl, tl->t);
+ sbuf_printf(tl->sb, " at\n");
+ vcc_ErrWhere(tl, tl->t);
+ return;
+ }
+ }
+}
+
+/*--------------------------------------------------------------------
+ * Consistency check
+ */
+
+static struct proc *
+AddProc(struct tokenlist *tl, struct token *t, int def)
+{
+ struct proc *p;
+
+ TAILQ_FOREACH(p, &tl->procs, list) {
+ if (!vcc_Teq(p->name, t))
+ continue;
+ if (def)
+ p->name = t;
+ return (p);
+ }
+ p = calloc(sizeof *p, 1);
+ assert(p != NULL);
+ p->name = t;
+ TAILQ_INIT(&p->calls);
+ TAILQ_INSERT_TAIL(&tl->procs, p, list);
+ return (p);
+}
+
+static void
+AddCall(struct tokenlist *tl, struct token *t)
+{
+ struct proccall *pc;
+ struct proc *p;
+
+ p = AddProc(tl, t, 0);
+ TAILQ_FOREACH(pc, &tl->curproc->calls, list) {
+ if (pc->p == p)
+ return;
+ }
+ pc = calloc(sizeof *pc, 1);
+ assert(pc != NULL);
+ pc->p = p;
+ pc->t = t;
+ TAILQ_INSERT_TAIL(&tl->curproc->calls, pc, list);
+}
+
+static int
+Consist_Decend(struct tokenlist *tl, struct proc *p, unsigned returns)
+{
+ unsigned u;
+ struct proccall *pc;
+
+ if (!p->exists) {
+ sbuf_printf(tl->sb, "Function %T does not exist\n", p->name);
+ return (1);
+ }
+ if (p->active) {
+ sbuf_printf(tl->sb, "Function recurses on\n");
+ vcc_ErrWhere(tl, p->name);
+ return (1);
+ }
+ u = p->returns & ~returns;
+ if (u) {
+#define VCL_RET_MAC(a, b, c) \
+ if (u & VCL_RET_##b) { \
+ sbuf_printf(tl->sb, "Illegal return for method\n"); \
+ vcc_ErrWhere(tl, p->returnt[c]); \
+ }
+#include "vcl_returns.h"
+#undef VCL_RET_MAC
+ sbuf_printf(tl->sb, "In function\n");
+ vcc_ErrWhere(tl, p->name);
+ return (1);
+ }
+ p->active = 1;
+ TAILQ_FOREACH(pc, &p->calls, list) {
+ if (Consist_Decend(tl, pc->p, returns)) {
+ sbuf_printf(tl->sb, "\nCalled from\n");
+ vcc_ErrWhere(tl, p->name);
+ sbuf_printf(tl->sb, "at\n");
+ vcc_ErrWhere(tl, pc->t);
+ return (1);
+ }
+ }
+ p->active = 0;
+ p->called++;
+ return (0);
+}
+
+static int
+Consistency(struct tokenlist *tl)
+{
+ struct proc *p;
+ struct method *m;
+
+ TAILQ_FOREACH(p, &tl->procs, list) {
+ for(m = method_tab; m->name != NULL; m++) {
+ if (vcc_IdIs(p->name, m->defname))
+ p->called = 1;
+ if (vcc_IdIs(p->name, m->name))
+ break;
+ }
+ if (m->name == NULL)
+ continue;
+ if (Consist_Decend(tl, p, m->returns)) {
+ sbuf_printf(tl->sb,
+ "\nwhich is a %s method\n", m->name);
+ return (1);
+ }
+ }
+ TAILQ_FOREACH(p, &tl->procs, list) {
+ if (p->called)
+ continue;
+ sbuf_printf(tl->sb, "Function unused\n");
+ vcc_ErrWhere(tl, p->name);
+ return (1);
+ }
+ return (0);
+}
+
+/*--------------------------------------------------------------------*/
+
+static int
+CheckRefs(struct tokenlist *tl)
+{
+ struct ref *r;
+ const char *type;
+ int nerr = 0;
+
+ TAILQ_FOREACH(r, &tl->refs, list) {
+ if (r->defcnt != 0 && r->refcnt != 0)
+ continue;
+ nerr++;
+
+ switch(r->type) {
+ case R_FUNC:
+ type = "function";
+ break;
+ case R_ACL:
+ type = "acl";
+ break;
+ case R_BACKEND:
+ type = "backend";
+ break;
+ default:
+ ErrInternal(tl);
+ sbuf_printf(tl->sb, "Ref ");
+ vcc_ErrToken(tl, r->name);
+ sbuf_printf(tl->sb, " has unknown type %d\n",
+ r->type);
+ continue;
+ }
+ if (r->defcnt == 0 && r->name->tok == METHOD) {
+ sbuf_printf(tl->sb,
+ "No definition for method %T\n", r->name);
+ continue;
+ }
+
+ if (r->defcnt == 0) {
+ sbuf_printf(tl->sb,
+ "Undefined %s %T, first reference:\n",
+ type, r->name);
+ vcc_ErrWhere(tl, r->name);
+ continue;
+ }
+
+ sbuf_printf(tl->sb, "Unused %s %T, defined:\n", type, r->name);
+ vcc_ErrWhere(tl, r->name);
+ }
+ return (nerr);
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+LocTable(struct tokenlist *tl)
+{
+ struct token *t;
+ unsigned lin, pos;
+ const char *p;
+
+ Fh(tl, 0, "#define VGC_NREFS %u\n", tl->cnt + 1);
+ Fh(tl, 0, "static struct vrt_ref VGC_ref[VGC_NREFS];\n");
+ Fc(tl, 0, "static struct vrt_ref VGC_ref[VGC_NREFS] = {\n");
+ lin = 1;
+ pos = 0;
+ p = tl->b;
+ TAILQ_FOREACH(t, &tl->tokens, list) {
+ if (t->cnt == 0)
+ continue;
+ for (;p < t->b; p++) {
+ if (*p == '\n') {
+ lin++;
+ pos = 0;
+ } else if (*p == '\t') {
+ pos &= ~7;
+ pos += 8;
+ } else
+ pos++;
+
+ }
+ Fc(tl, 0, " [%3u] = { %4u, %3u, 0, \"%T\" },\n",
+ t->cnt, lin, pos + 1, t);
+ }
+ Fc(tl, 0, "};\n");
+}
+
+
+/*--------------------------------------------------------------------*/
+
+static void
+EmitInitFunc(struct tokenlist *tl)
+{
+ struct ref *r;
+
+ Fc(tl, 0, "\nstatic void\nVGC_Init(void)\n{\n\n");
+ Fc(tl, 0, "\tVRT_alloc_backends(&VCL_conf);\n");
+
+ TAILQ_FOREACH(r, &tl->refs, list) {
+ switch(r->type) {
+ case R_FUNC:
+ break;
+ case R_ACL:
+ break;
+ case R_BACKEND:
+ Fc(tl, 0, "\tVGC_init_backend_%T();\n", r->name);
+ break;
+ }
+ }
+ Fc(tl, 0, "}\n");
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+EmitStruct(struct tokenlist *tl)
+{
+
+ Fc(tl, 0, "\nstruct VCL_conf VCL_conf = {\n");
+ Fc(tl, 0, "\t.magic = VCL_CONF_MAGIC,\n");
+ Fc(tl, 0, "\t.init_func = VGC_Init,\n");
+ Fc(tl, 0, "\t.nbackend = %d,\n", tl->nbackend);
+ Fc(tl, 0, "\t.ref = VGC_ref,\n");
+ Fc(tl, 0, "\t.nref = VGC_NREFS,\n");
+#define VCL_RET_MAC(l,u,b)
+#define VCL_MET_MAC(l,u,b) \
+ if (FindRefStr(tl, "vcl_" #l, R_FUNC)) { \
+ Fc(tl, 0, "\t." #l "_func = VGC_function_vcl_" #l ",\n"); \
+ AddRefStr(tl, "vcl_" #l, R_FUNC); \
+ } else { \
+ Fc(tl, 0, "\t." #l "_func = VGC_function_default_vcl_" #l ",\n"); \
+ } \
+ AddRefStr(tl, "default_vcl_" #l, R_FUNC);
+#include "vcl_returns.h"
+#undef VCL_MET_MAC
+#undef VCL_RET_MAC
+ Fc(tl, 0, "};\n");
+}
+
+/*--------------------------------------------------------------------*/
+
+char *
+VCC_Compile(struct sbuf *sb, const char *b, const char *e)
+{
+ struct tokenlist tokens;
+ struct ref *r;
+ struct token *t;
+ FILE *fo;
+ char *of = NULL;
+ char buf[BUFSIZ];
+
+ memset(&tokens, 0, sizeof tokens);
+ TAILQ_INIT(&tokens.tokens);
+ TAILQ_INIT(&tokens.refs);
+ TAILQ_INIT(&tokens.procs);
+ tokens.sb = sb;
+
+ tokens.fc = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND);
+ assert(tokens.fc != NULL);
+
+ tokens.fh = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND);
+ assert(tokens.fh != NULL);
+
+ Fh(&tokens, 0, "extern struct VCL_conf VCL_conf;\n");
+
+ tokens.b = b;
+ if (e == NULL)
+ e = strchr(b, '\0');
+ assert(e != NULL);
+ tokens.e = e;
+ vcc_Lexer(&tokens, b, e);
+ vcc_Lexer(&tokens, vcc_default_vcl_b, vcc_default_vcl_e);
+ vcc_AddToken(&tokens, EOI, e, e);
+ if (tokens.err)
+ goto done;
+ tokens.t = TAILQ_FIRST(&tokens.tokens);
+ Parse(&tokens);
+ if (tokens.err)
+ goto done;
+ Consistency(&tokens);
+ if (tokens.err)
+ goto done;
+ LocTable(&tokens);
+
+ EmitInitFunc(&tokens);
+
+ EmitStruct(&tokens);
+
+ if (CheckRefs(&tokens))
+ goto done;
+
+ of = strdup("/tmp/vcl.XXXXXXXX");
+ assert(of != NULL);
+ mktemp(of);
+
+ sprintf(buf,
+ "tee /tmp/_.c |"
+ "cc -fpic -shared -Wl,-x -o %s -x c - ", of);
+
+ fo = popen(buf, "w");
+ assert(fo != NULL);
+
+ vcl_output_lang_h(fo);
+
+ sbuf_finish(tokens.fh);
+ fputs(sbuf_data(tokens.fh), fo);
+ sbuf_delete(tokens.fh);
+
+ sbuf_finish(tokens.fc);
+ fputs(sbuf_data(tokens.fc), fo);
+ sbuf_delete(tokens.fc);
+
+ pclose(fo);
+done:
+
+ /* Free References */
+ while (!TAILQ_EMPTY(&tokens.refs)) {
+ r = TAILQ_FIRST(&tokens.refs);
+ TAILQ_REMOVE(&tokens.refs, r, list);
+ free(r);
+ }
+
+ /* Free Tokens */
+ while (!TAILQ_EMPTY(&tokens.tokens)) {
+ t = TAILQ_FIRST(&tokens.tokens);
+ TAILQ_REMOVE(&tokens.tokens, t, list);
+ free(t);
+ }
+ return (of);
+}
+
+/*--------------------------------------------------------------------*/
+
+char *
+VCC_CompileFile(struct sbuf *sb, const char *fn)
+{
+ char *f, *r;
+ int fd, i;
+ struct stat st;
+
+ fd = open(fn, O_RDONLY);
+ if (fd < 0) {
+ sbuf_printf(sb, "Cannot open file '%s': %s",
+ fn, strerror(errno));
+ return (NULL);
+ }
+ assert(0 == fstat(fd, &st));
+ f = malloc(st.st_size + 1);
+ assert(f != NULL);
+ i = read(fd, f, st.st_size);
+ assert(i == st.st_size);
+ f[i] = '\0';
+ r = VCC_Compile(sb, f, NULL);
+ free(f);
+ return (r);
+}
+
+/*--------------------------------------------------------------------*/
+
+static int
+VCC_T_render(FILE *f, const struct printf_info *info __unused, const void *const *args)
+{
+ const struct token *t;
+
+ t = *((const struct token * const*) (args[0]));
+ return (fprintf(f, "%*.*s",
+ t->e - t->b, t->e - t->b, t->b));
+}
+
+static int
+VCC_T_arginfo(const struct printf_info *info __unused, size_t n, int *argtypes)
+{
+
+ if (n > 0)
+ argtypes[0] = PA_POINTER;
+ return 1;
+}
+
+/*--------------------------------------------------------------------*/
+
+void
+VCC_InitCompile(const char *default_vcl)
+{
+ struct var *v;
+
+ vcc_default_vcl_b = default_vcl;
+ vcc_default_vcl_e = strchr(default_vcl, '\0');
+ assert(vcc_default_vcl_e != NULL);
+
+ register_printf_function ('T', VCC_T_render, VCC_T_arginfo);
+ vcl_init_tnames();
+ for (v = vcc_vars; v->name != NULL; v++)
+ v->len = strlen(v->name);
+ for (v = vcc_be_vars; v->name != NULL; v++)
+ v->len = strlen(v->name);
+}
Added: trunk/varnish-cache/lib/libvcl/vcc_compile.h
===================================================================
--- trunk/varnish-cache/lib/libvcl/vcc_compile.h 2006-07-21 16:25:24 UTC (rev 543)
+++ trunk/varnish-cache/lib/libvcl/vcc_compile.h 2006-07-21 18:12:56 UTC (rev 544)
@@ -0,0 +1,120 @@
+/*
+ * $Id$
+ */
+
+#include "queue.h"
+#include "vcl_returns.h"
+
+#define INDENT 2
+
+struct token {
+ unsigned tok;
+ const char *b;
+ const char *e;
+ TAILQ_ENTRY(token) list;
+ unsigned cnt;
+};
+
+struct tokenlist {
+ TAILQ_HEAD(, token) tokens;
+ const char *b;
+ const char *e;
+ struct token *t;
+ int indent;
+ unsigned cnt;
+ struct sbuf *fc, *fh;
+ TAILQ_HEAD(, ref) refs;
+ struct sbuf *sb;
+ int err;
+ int nbackend;
+ TAILQ_HEAD(, proc) procs;
+ struct proc *curproc;
+};
+
+enum var_type {
+ BACKEND,
+ BOOL,
+ INT,
+ FLOAT,
+ SIZE,
+ RATE,
+ TIME,
+ STRING,
+ IP,
+ HOSTNAME,
+ PORTNAME,
+ HEADER
+};
+
+enum ref_type {
+ R_FUNC,
+ R_ACL,
+ R_BACKEND
+};
+
+struct ref {
+ enum ref_type type;
+ struct token *name;
+ unsigned defcnt;
+ unsigned refcnt;
+ TAILQ_ENTRY(ref) list;
+};
+
+struct var {
+ const char *name;
+ enum var_type fmt;
+ int len;
+ const char *rname;
+ const char *lname;
+};
+
+static struct method {
+ const char *name;
+ const char *defname;
+ unsigned returns;
+} method_tab[] = {
+#define VCL_RET_MAC(a,b,c)
+#define VCL_MET_MAC(a,b,c) { "vcl_"#a, "default_vcl_"#a, c },
+#include "vcl_returns.h"
+#undef VCL_MET_MAC
+#undef VCL_RET_MAC
+ { NULL, 0U }
+};
+
+struct proccall {
+ TAILQ_ENTRY(proccall) list;
+ struct proc *p;
+ struct token *t;
+};
+
+struct proc {
+ TAILQ_ENTRY(proc) list;
+ TAILQ_HEAD(,proccall) calls;
+ struct token *name;
+ unsigned returns;
+ unsigned exists;
+ unsigned called;
+ unsigned active;
+ struct token *returnt[VCL_RET_MAX];
+};
+
+
+/*--------------------------------------------------------------------*/
+
+/* vcc_compile.c */
+extern const char *vcc_default_vcl_b, *vcc_default_vcl_e;
+
+/* vcc_obj.c */
+extern struct var vcc_be_vars[];
+extern struct var vcc_vars[];
+
+/* vcc_token.c */
+void vcc_ErrToken(struct tokenlist *tl, struct token *t);
+void vcc_ErrWhere(struct tokenlist *tl, struct token *t);
+void vcc__Expect(struct tokenlist *tl, unsigned tok, int line);
+int vcc_Teq(struct token *t1, struct token *t2);
+int vcc_IdIs(struct token *t, const char *p);
+void vcc_Lexer(struct tokenlist *tl, const char *b, const char *e);
+void vcc_NextToken(struct tokenlist *tl);
+void vcc__ErrInternal(struct tokenlist *tl, const char *func, unsigned line);
+void vcc_AddToken(struct tokenlist *tl, unsigned tok, const char *b, const char *e);
Copied: trunk/varnish-cache/lib/libvcl/vcc_fixed_token.c (from rev 480, trunk/varnish-cache/lib/libvcl/vcl_fixed_token.c)
===================================================================
--- trunk/varnish-cache/lib/libvcl/vcl_fixed_token.c 2006-07-14 13:54:41 UTC (rev 480)
+++ trunk/varnish-cache/lib/libvcl/vcc_fixed_token.c 2006-07-21 18:12:56 UTC (rev 544)
@@ -0,0 +1,518 @@
+/*
+ * $Id$
+ *
+ * NB: This file is machine generated, DO NOT EDIT!
+ *
+ * Edit vcc_gen_fixed_token.tcl instead
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include "vcc_priv.h"
+
+unsigned
+vcl_fixed_token(const char *p, const char **q)
+{
+
+ switch (p[0]) {
+ case '!':
+ if (p[0] == '!' && p[1] == '=') {
+ *q = p + 2;
+ return (T_NEQ);
+ }
+ if (p[0] == '!') {
+ *q = p + 1;
+ return ('!');
+ }
+ return (0);
+ case '%':
+ if (p[0] == '%') {
+ *q = p + 1;
+ return ('%');
+ }
+ return (0);
+ case '&':
+ if (p[0] == '&' && p[1] == '&') {
+ *q = p + 2;
+ return (T_CAND);
+ }
+ if (p[0] == '&') {
+ *q = p + 1;
+ return ('&');
+ }
+ return (0);
+ case '(':
+ if (p[0] == '(') {
+ *q = p + 1;
+ return ('(');
+ }
+ return (0);
+ case ')':
+ if (p[0] == ')') {
+ *q = p + 1;
+ return (')');
+ }
+ return (0);
+ case '*':
+ if (p[0] == '*' && p[1] == '=') {
+ *q = p + 2;
+ return (T_MUL);
+ }
+ if (p[0] == '*') {
+ *q = p + 1;
+ return ('*');
+ }
+ return (0);
+ case '+':
+ if (p[0] == '+' && p[1] == '=') {
+ *q = p + 2;
+ return (T_INCR);
+ }
+ if (p[0] == '+' && p[1] == '+') {
+ *q = p + 2;
+ return (T_INC);
+ }
+ if (p[0] == '+') {
+ *q = p + 1;
+ return ('+');
+ }
+ return (0);
+ case ',':
+ if (p[0] == ',') {
+ *q = p + 1;
+ return (',');
+ }
+ return (0);
+ case '-':
+ if (p[0] == '-' && p[1] == '-') {
+ *q = p + 2;
+ return (T_DEC);
+ }
+ if (p[0] == '-') {
+ *q = p + 1;
+ return ('-');
+ }
+ return (0);
+ case '.':
+ if (p[0] == '.') {
+ *q = p + 1;
+ return ('.');
+ }
+ return (0);
+ case '/':
+ if (p[0] == '/' && p[1] == '=') {
+ *q = p + 2;
+ return (T_DECR);
+ }
+ if (p[0] == '/' && p[1] == '=') {
+ *q = p + 2;
+ return (T_DIV);
+ }
+ if (p[0] == '/') {
+ *q = p + 1;
+ return ('/');
+ }
+ return (0);
+ case ';':
+ if (p[0] == ';') {
+ *q = p + 1;
+ return (';');
+ }
+ return (0);
+ case '<':
+ if (p[0] == '<' && p[1] == '=') {
+ *q = p + 2;
+ return (T_LEQ);
+ }
+ if (p[0] == '<' && p[1] == '<') {
+ *q = p + 2;
+ return (T_SHL);
+ }
+ if (p[0] == '<') {
+ *q = p + 1;
+ return ('<');
+ }
+ return (0);
+ case '=':
+ if (p[0] == '=' && p[1] == '=') {
+ *q = p + 2;
+ return (T_EQ);
+ }
+ if (p[0] == '=') {
+ *q = p + 1;
+ return ('=');
+ }
+ return (0);
+ case '>':
+ if (p[0] == '>' && p[1] == '>') {
+ *q = p + 2;
+ return (T_SHR);
+ }
+ if (p[0] == '>' && p[1] == '=') {
+ *q = p + 2;
+ return (T_GEQ);
+ }
+ if (p[0] == '>') {
+ *q = p + 1;
+ return ('>');
+ }
+ return (0);
+ case 'a':
+ if (p[0] == 'a' && p[1] == 'c' && p[2] == 'l'
+ && !isvar(p[3])) {
+ *q = p + 3;
+ return (T_ACL);
+ }
+ return (0);
+ case 'b':
+ if (p[0] == 'b' && p[1] == 'a' && p[2] == 'c' &&
+ p[3] == 'k' && p[4] == 'e' && p[5] == 'n' &&
+ p[6] == 'd' && !isvar(p[7])) {
+ *q = p + 7;
+ return (T_BACKEND);
+ }
+ return (0);
+ case 'c':
+ if (p[0] == 'c' && p[1] == 'a' && p[2] == 'l' &&
+ p[3] == 'l' && !isvar(p[4])) {
+ *q = p + 4;
+ return (T_CALL);
+ }
+ return (0);
+ case 'd':
+ if (p[0] == 'd' && p[1] == 'i' && p[2] == 's' &&
+ p[3] == 'c' && p[4] == 'a' && p[5] == 'r' &&
+ p[6] == 'd' && !isvar(p[7])) {
+ *q = p + 7;
+ return (T_DISCARD);
+ }
+ if (p[0] == 'd' && p[1] == 'e' && p[2] == 'l' &&
+ p[3] == 'i' && p[4] == 'v' && p[5] == 'e' &&
+ p[6] == 'r' && !isvar(p[7])) {
+ *q = p + 7;
+ return (T_DELIVER);
+ }
+ return (0);
+ case 'e':
+ if (p[0] == 'e' && p[1] == 'r' && p[2] == 'r' &&
+ p[3] == 'o' && p[4] == 'r' && !isvar(p[5])) {
+ *q = p + 5;
+ return (T_ERROR);
+ }
+ if (p[0] == 'e' && p[1] == 'l' && p[2] == 's' &&
+ p[3] == 'i' && p[4] == 'f' && !isvar(p[5])) {
+ *q = p + 5;
+ return (T_ELSIF);
+ }
+ if (p[0] == 'e' && p[1] == 'l' && p[2] == 's' &&
+ p[3] == 'e' && p[4] == 'i' && p[5] == 'f'
+ && !isvar(p[6])) {
+ *q = p + 6;
+ return (T_ELSEIF);
+ }
+ if (p[0] == 'e' && p[1] == 'l' && p[2] == 's' &&
+ p[3] == 'e' && !isvar(p[4])) {
+ *q = p + 4;
+ return (T_ELSE);
+ }
+ return (0);
+ case 'f':
+ if (p[0] == 'f' && p[1] == 'u' && p[2] == 'n' &&
+ p[3] == 'c' && !isvar(p[4])) {
+ *q = p + 4;
+ return (T_FUNC);
+ }
+ if (p[0] == 'f' && p[1] == 'e' && p[2] == 't' &&
+ p[3] == 'c' && p[4] == 'h' && !isvar(p[5])) {
+ *q = p + 5;
+ return (T_FETCH);
+ }
+ return (0);
+ case 'i':
+ if (p[0] == 'i' && p[1] == 'n' && p[2] == 's' &&
+ p[3] == 'e' && p[4] == 'r' && p[5] == 't' &&
+ p[6] == '_' && p[7] == 'p' && p[8] == 'a' &&
+ p[9] == 's' && p[10] == 's' && !isvar(p[11])) {
+ *q = p + 11;
+ return (T_INSERT_PASS);
+ }
+ if (p[0] == 'i' && p[1] == 'n' && p[2] == 's' &&
+ p[3] == 'e' && p[4] == 'r' && p[5] == 't'
+ && !isvar(p[6])) {
+ *q = p + 6;
+ return (T_INSERT);
+ }
+ if (p[0] == 'i' && p[1] == 'f' && !isvar(p[2])) {
+ *q = p + 2;
+ return (T_IF);
+ }
+ return (0);
+ case 'l':
+ if (p[0] == 'l' && p[1] == 'o' && p[2] == 'o' &&
+ p[3] == 'k' && p[4] == 'u' && p[5] == 'p'
+ && !isvar(p[6])) {
+ *q = p + 6;
+ return (T_LOOKUP);
+ }
+ return (0);
+ case 'n':
+ if (p[0] == 'n' && p[1] == 'o' && p[2] == '_' &&
+ p[3] == 'n' && p[4] == 'e' && p[5] == 'w' &&
+ p[6] == '_' && p[7] == 'c' && p[8] == 'a' &&
+ p[9] == 'c' && p[10] == 'h' && p[11] == 'e'
+ && !isvar(p[12])) {
+ *q = p + 12;
+ return (T_NO_NEW_CACHE);
+ }
+ if (p[0] == 'n' && p[1] == 'o' && p[2] == '_' &&
+ p[3] == 'c' && p[4] == 'a' && p[5] == 'c' &&
+ p[6] == 'h' && p[7] == 'e' && !isvar(p[8])) {
+ *q = p + 8;
+ return (T_NO_CACHE);
+ }
+ return (0);
+ case 'p':
+ if (p[0] == 'p' && p[1] == 'r' && p[2] == 'o' &&
+ p[3] == 'c' && !isvar(p[4])) {
+ *q = p + 4;
+ return (T_PROC);
+ }
+ if (p[0] == 'p' && p[1] == 'i' && p[2] == 'p' &&
+ p[3] == 'e' && !isvar(p[4])) {
+ *q = p + 4;
+ return (T_PIPE);
+ }
+ if (p[0] == 'p' && p[1] == 'a' && p[2] == 's' &&
+ p[3] == 's' && !isvar(p[4])) {
+ *q = p + 4;
+ return (T_PASS);
+ }
+ return (0);
+ case 'r':
+ if (p[0] == 'r' && p[1] == 'e' && p[2] == 'w' &&
+ p[3] == 'r' && p[4] == 'i' && p[5] == 't' &&
+ p[6] == 'e' && !isvar(p[7])) {
+ *q = p + 7;
+ return (T_REWRITE);
+ }
+ return (0);
+ case 's':
+ if (p[0] == 's' && p[1] == 'w' && p[2] == 'i' &&
+ p[3] == 't' && p[4] == 'c' && p[5] == 'h' &&
+ p[6] == '_' && p[7] == 'c' && p[8] == 'o' &&
+ p[9] == 'n' && p[10] == 'f' && p[11] == 'i' &&
+ p[12] == 'g' && !isvar(p[13])) {
+ *q = p + 13;
+ return (T_SWITCH_CONFIG);
+ }
+ if (p[0] == 's' && p[1] == 'u' && p[2] == 'b'
+ && !isvar(p[3])) {
+ *q = p + 3;
+ return (T_SUB);
+ }
+ if (p[0] == 's' && p[1] == 'e' && p[2] == 't'
+ && !isvar(p[3])) {
+ *q = p + 3;
+ return (T_SET);
+ }
+ return (0);
+ case '{':
+ if (p[0] == '{') {
+ *q = p + 1;
+ return ('{');
+ }
+ return (0);
+ case '|':
+ if (p[0] == '|' && p[1] == '|') {
+ *q = p + 2;
+ return (T_COR);
+ }
+ if (p[0] == '|') {
+ *q = p + 1;
+ return ('|');
+ }
+ return (0);
+ case '}':
+ if (p[0] == '}') {
+ *q = p + 1;
+ return ('}');
+ }
+ return (0);
+ case '~':
+ if (p[0] == '~') {
+ *q = p + 1;
+ return ('~');
+ }
+ return (0);
+ default:
+ return (0);
+ }
+}
+
+const char *vcl_tnames[256];
+
+void
+vcl_init_tnames(void)
+{
+ vcl_tnames['!'] = "'!'";
+ vcl_tnames['%'] = "'%'";
+ vcl_tnames['&'] = "'&'";
+ vcl_tnames['('] = "'('";
+ vcl_tnames[')'] = "')'";
+ vcl_tnames['*'] = "'*'";
+ vcl_tnames['+'] = "'+'";
+ vcl_tnames[','] = "','";
+ vcl_tnames['-'] = "'-'";
+ vcl_tnames['.'] = "'.'";
+ vcl_tnames['/'] = "'/'";
+ vcl_tnames['<'] = "'<'";
+ vcl_tnames['='] = "'='";
+ vcl_tnames['>'] = "'>'";
+ vcl_tnames['{'] = "'{'";
+ vcl_tnames['}'] = "'}'";
+ vcl_tnames['|'] = "'|'";
+ vcl_tnames['~'] = "'~'";
+ vcl_tnames[';'] = "';'";
+ vcl_tnames[CNUM] = "CNUM";
+ vcl_tnames[CSTR] = "CSTR";
+ vcl_tnames[EOI] = "EOI";
+ vcl_tnames[ID] = "ID";
+ vcl_tnames[METHOD] = "METHOD";
+ vcl_tnames[T_ACL] = "acl";
+ vcl_tnames[T_BACKEND] = "backend";
+ vcl_tnames[T_CALL] = "call";
+ vcl_tnames[T_CAND] = "&&";
+ vcl_tnames[T_COR] = "||";
+ vcl_tnames[T_DEC] = "--";
+ vcl_tnames[T_DECR] = "/=";
+ vcl_tnames[T_DELIVER] = "deliver";
+ vcl_tnames[T_DISCARD] = "discard";
+ vcl_tnames[T_DIV] = "/=";
+ vcl_tnames[T_ELSE] = "else";
+ vcl_tnames[T_ELSEIF] = "elseif";
+ vcl_tnames[T_ELSIF] = "elsif";
+ vcl_tnames[T_EQ] = "==";
+ vcl_tnames[T_ERROR] = "error";
+ vcl_tnames[T_FETCH] = "fetch";
+ vcl_tnames[T_FUNC] = "func";
+ vcl_tnames[T_GEQ] = ">=";
+ vcl_tnames[T_IF] = "if";
+ vcl_tnames[T_INC] = "++";
+ vcl_tnames[T_INCR] = "+=";
+ vcl_tnames[T_INSERT] = "insert";
+ vcl_tnames[T_INSERT_PASS] = "insert_pass";
+ vcl_tnames[T_LEQ] = "<=";
+ vcl_tnames[T_LOOKUP] = "lookup";
+ vcl_tnames[T_MUL] = "*=";
+ vcl_tnames[T_NEQ] = "!=";
+ vcl_tnames[T_NO_CACHE] = "no_cache";
+ vcl_tnames[T_NO_NEW_CACHE] = "no_new_cache";
+ vcl_tnames[T_PASS] = "pass";
+ vcl_tnames[T_PIPE] = "pipe";
+ vcl_tnames[T_PROC] = "proc";
+ vcl_tnames[T_REWRITE] = "rewrite";
+ vcl_tnames[T_SET] = "set";
+ vcl_tnames[T_SHL] = "<<";
+ vcl_tnames[T_SHR] = ">>";
+ vcl_tnames[T_SUB] = "sub";
+ vcl_tnames[T_SWITCH_CONFIG] = "switch_config";
+ vcl_tnames[VAR] = "VAR";
+}
+
+void
+vcl_output_lang_h(FILE *f)
+{
+ fputs("#define VCL_RET_ERROR (1 << 0)\n", f);
+ fputs("#define VCL_RET_LOOKUP (1 << 1)\n", f);
+ fputs("#define VCL_RET_PIPE (1 << 2)\n", f);
+ fputs("#define VCL_RET_PASS (1 << 3)\n", f);
+ fputs("#define VCL_RET_INSERT_PASS (1 << 4)\n", f);
+ fputs("#define VCL_RET_FETCH (1 << 5)\n", f);
+ fputs("#define VCL_RET_INSERT (1 << 6)\n", f);
+ fputs("#define VCL_RET_DELIVER (1 << 7)\n", f);
+ fputs("#define VCL_RET_DISCARD (1 << 8)\n", f);
+ fputs("/*\n", f);
+ fputs(" * $Id$\n", f);
+ fputs(" *\n", f);
+ fputs(" * NB: This file is machine generated, DO NOT EDIT!\n", f);
+ fputs(" *\n", f);
+ fputs(" * Edit vcc_gen_fixed_token.tcl instead\n", f);
+ fputs(" */\n", f);
+ fputs("\n", f);
+ fputs("struct sess;\n", f);
+ fputs("\n", f);
+ fputs("typedef void vcl_init_f(void);\n", f);
+ fputs("typedef int vcl_func_f(struct sess *sp);\n", f);
+ fputs("\n", f);
+ fputs("struct VCL_conf {\n", f);
+ fputs(" unsigned magic;\n", f);
+ fputs("#define VCL_CONF_MAGIC 0x7406c509 /* from /dev/random */\n", f);
+ fputs("\n", f);
+ fputs(" struct backend **backend;\n", f);
+ fputs(" unsigned nbackend;\n", f);
+ fputs(" struct vrt_ref *ref;\n", f);
+ fputs(" unsigned nref;\n", f);
+ fputs(" unsigned busy;\n", f);
+ fputs("\n", f);
+ fputs(" vcl_init_f *init_func;\n", f);
+ fputs("\n", f);
+ fputs(" vcl_func_f *recv_func;\n", f);
+ fputs(" vcl_func_f *miss_func;\n", f);
+ fputs(" vcl_func_f *hit_func;\n", f);
+ fputs(" vcl_func_f *fetch_func;\n", f);
+ fputs(" vcl_func_f *timeout_func;\n", f);
+ fputs("};\n", f);
+ fputs("/*\n", f);
+ fputs(" * $Id$ \n", f);
+ fputs(" *\n", f);
+ fputs(" * Runtime support for compiled VCL programs.\n", f);
+ fputs(" *\n", f);
+ fputs(" * XXX: When this file is changed, lib/libvcl/vcl_gen_fixed_token.tcl\n", f);
+ fputs(" * XXX: *MUST* be rerun.\n", f);
+ fputs(" */\n", f);
+ fputs("\n", f);
+ fputs("struct sess;\n", f);
+ fputs("struct backend;\n", f);
+ fputs("struct VCL_conf;\n", f);
+ fputs("\n", f);
+ fputs("struct vrt_ref {\n", f);
+ fputs(" unsigned line;\n", f);
+ fputs(" unsigned pos;\n", f);
+ fputs(" unsigned count;\n", f);
+ fputs(" const char *token;\n", f);
+ fputs("};\n", f);
+ fputs("\n", f);
+ fputs("struct vrt_acl {\n", f);
+ fputs(" unsigned ip;\n", f);
+ fputs(" unsigned mask;\n", f);
+ fputs("};\n", f);
+ fputs("\n", f);
+ fputs("void VRT_count(struct sess *, unsigned);\n", f);
+ fputs("void VRT_no_cache(struct sess *);\n", f);
+ fputs("void VRT_no_new_cache(struct sess *);\n", f);
+ fputs("#if 0\n", f);
+ fputs("int ip_match(unsigned, struct vcl_acl *);\n", f);
+ fputs("int string_match(const char *, const char *);\n", f);
+ fputs("#endif\n", f);
+ fputs("int VRT_rewrite(const char *, const char *);\n", f);
+ fputs("void VRT_error(struct sess *, unsigned, const char *);\n", f);
+ fputs("int VRT_switch_config(const char *);\n", f);
+ fputs("\n", f);
+ fputs("char *VRT_GetHdr(struct sess *, const char *);\n", f);
+ fputs("char *VRT_GetReq(struct sess *);\n", f);
+ fputs("void VRT_handling(struct sess *sp, unsigned hand);\n", f);
+ fputs("int VRT_obj_valid(struct sess *);\n", f);
+ fputs("int VRT_obj_cacheable(struct sess *);\n", f);
+ fputs("\n", f);
+ fputs("void VRT_set_backend_name(struct backend *, const char *);\n", f);
+ fputs("void VRT_set_backend_hostname(struct backend *, const char *);\n", f);
+ fputs("void VRT_set_backend_portname(struct backend *, const char *);\n", f);
+ fputs("\n", f);
+ fputs("void VRT_alloc_backends(struct VCL_conf *cp);\n", f);
+ fputs("\n", f);
+ fputs("#define VRT_done(sp, hand) \\\n", f);
+ fputs(" do { \\\n", f);
+ fputs(" VRT_handling(sp, hand); \\\n", f);
+ fputs(" return (1); \\\n", f);
+ fputs(" } while (0)\n", f);
+}
Copied: trunk/varnish-cache/lib/libvcl/vcc_gen_fixed_token.tcl (from rev 480, trunk/varnish-cache/lib/libvcl/vcl_gen_fixed_token.tcl)
===================================================================
--- trunk/varnish-cache/lib/libvcl/vcl_gen_fixed_token.tcl 2006-07-14 13:54:41 UTC (rev 480)
+++ trunk/varnish-cache/lib/libvcl/vcc_gen_fixed_token.tcl 2006-07-21 18:12:56 UTC (rev 544)
@@ -0,0 +1,319 @@
+#!/usr/local/bin/tclsh8.4
+#
+# Generate various .c and .h files for the VCL compiler and the interfaces
+# for it.
+
+# These are the metods which can be called in the VCL program.
+# Second element is list of valid return actions.
+#
+set methods {
+ {recv {error pass pipe lookup}}
+ {miss {error pass pipe fetch}}
+ {hit {error pass pipe deliver}}
+ {fetch {error pass pipe insert insert_pass}}
+ {timeout {fetch discard}}
+}
+
+# These are the return actions
+#
+set returns {
+ error
+ lookup
+ pipe
+ pass
+ insert_pass
+ fetch
+ insert
+ deliver
+ discard
+}
+
+# Language keywords
+#
+set keywords {
+ if else elseif elsif
+
+ func proc sub
+
+ acl
+
+ backend
+
+ call
+ no_cache
+ no_new_cache
+ set
+ rewrite
+ switch_config
+}
+
+# Non-word tokens
+#
+set magic {
+ {"++" INC}
+ {"--" DEC}
+ {"&&" CAND}
+ {"||" COR}
+ {"<=" LEQ}
+ {"==" EQ}
+ {"!=" NEQ}
+ {">=" GEQ}
+ {">>" SHR}
+ {"<<" SHL}
+ {"+=" INCR}
+ {"/=" DECR}
+ {"*=" MUL}
+ {"/=" DIV}
+}
+
+# Single char tokens
+#
+set char {{}()*+-/%><=;!&.|~,}
+
+# Other token identifiers
+#
+set extras {ID VAR CNUM CSTR EOI METHOD}
+
+#----------------------------------------------------------------------
+# Boilerplate warning for all generated files.
+
+proc warns {fd} {
+
+ puts $fd "/*"
+ puts $fd { * $Id$}
+ puts $fd " *"
+ puts $fd " * NB: This file is machine generated, DO NOT EDIT!"
+ puts $fd " *"
+ puts $fd " * Edit vcc_gen_fixed_token.tcl instead"
+ puts $fd " */"
+ puts $fd ""
+}
+
+#----------------------------------------------------------------------
+# Build the vcl.h #include file
+
+set fo [open ../../include/vcl.h w]
+warns $fo
+puts $fo {struct sess;
+
+typedef void vcl_init_f(void);
+typedef int vcl_func_f(struct sess *sp);
+}
+puts $fo "struct VCL_conf {"
+puts $fo { unsigned magic;
+#define VCL_CONF_MAGIC 0x7406c509 /* from /dev/random */
+
+ struct backend **backend;
+ unsigned nbackend;
+ struct vrt_ref *ref;
+ unsigned nref;
+ unsigned busy;
+
+ vcl_init_f *init_func;
+}
+foreach m $methods {
+ puts $fo "\tvcl_func_f\t*[lindex $m 0]_func;"
+}
+puts $fo "};"
+
+close $fo
+
+#----------------------------------------------------------------------
+# Build the vcl_returns.h #include file
+
+set for [open "../../include/vcl_returns.h" w]
+warns $for
+puts $for "#ifdef VCL_RET_MAC"
+set i 0
+foreach k $returns {
+ if {$k == "error"} {
+ puts $for "#ifdef VCL_RET_MAC_E"
+ puts $for "VCL_RET_MAC_E($k, [string toupper $k], $i)"
+ puts $for "#endif"
+ } else {
+ puts $for "VCL_RET_MAC($k, [string toupper $k], (1 << $i))"
+ }
+ incr i
+}
+puts $for "#else"
+set i 0
+foreach k $returns {
+ puts $for "#define VCL_RET_[string toupper $k] (1 << $i)"
+ incr i
+}
+puts $for "#define VCL_RET_MAX $i"
+puts $for "#endif"
+puts $for ""
+puts $for "#ifdef VCL_MET_MAC"
+foreach m $methods {
+ puts -nonewline $for "VCL_MET_MAC([lindex $m 0]"
+ puts -nonewline $for ",[string toupper [lindex $m 0]]"
+ set l [lindex $m 1]
+ puts -nonewline $for ",(VCL_RET_[string toupper [lindex $l 0]]"
+ foreach r [lrange $l 1 end] {
+ puts -nonewline $for "|VCL_RET_[string toupper $r]"
+ }
+ puts -nonewline $for ")"
+ puts $for ")"
+}
+puts $for "#endif"
+close $for
+
+#----------------------------------------------------------------------
+# Build the compiler token table and recognizers
+
+set fo [open "vcc_fixed_token.c" w]
+warns $fo
+
+set foh [open "vcc_token_defs.h" w]
+warns $foh
+
+puts $fo "#include <stdio.h>"
+puts $fo "#include <ctype.h>"
+puts $fo "#include \"vcc_priv.h\""
+
+set tn 128
+puts $foh "#define LOW_TOKEN $tn"
+
+
+proc add_token {tok str alpha} {
+ global tokens tn fixed foh
+
+ lappend tokens [list $tok $str]
+ puts $foh "#define $tok $tn"
+ incr tn
+ lappend fixed [list $str $tok $alpha]
+}
+
+proc mk_token {tok str alpha} {
+ set tok T_[string toupper $tok]
+ add_token $tok $str $alpha
+}
+
+foreach k $keywords { mk_token $k $k 1 }
+foreach k $returns { mk_token $k $k 1 }
+foreach k $magic { mk_token [lindex $k 1] [lindex $k 0] 0 }
+foreach k $extras {
+ set t [string toupper $k]
+ lappend tokens [list $t $t]
+ puts $foh "#define [string toupper $k] $tn"
+ incr tn
+}
+for {set i 0} {$i < [string length $char]} {incr i} {
+ set t [string index $char $i]
+ lappend token2 [list '$t' T$t]
+ lappend fixed [list "$t" '$t' 0]
+}
+
+set tokens [lsort $tokens]
+set token2 [lsort $token2]
+
+# We want to output in ascii order: create sorted first char list
+foreach t $fixed {
+ set xx([string index [lindex $t 0] 0]) 1
+}
+set seq [lsort [array names xx]]
+
+set ll 0
+
+puts $fo {
+unsigned
+vcl_fixed_token(const char *p, const char **q)}
+puts $fo "{"
+puts $fo ""
+puts $fo " switch (p\[0\]) {"
+
+foreach ch "$seq" {
+ # Now find all tokens starting with ch
+ set l ""
+ foreach t $fixed {
+ if {[string index [lindex $t 0] 0] == $ch} {
+ lappend l $t
+ }
+ }
+ # And do then in reverse order to match longest first
+ set l [lsort -index 0 -decreasing $l]
+ scan "$ch" "%c" cx
+ if {$cx != $ll} {
+ if {$ll} {
+ puts $fo " return (0);"
+ }
+
+ puts $fo " case '$ch':"
+ set ll $cx
+ }
+ foreach tt $l {
+ set k [lindex $tt 0]
+ puts -nonewline $fo " if ("
+ for {set i 0} {$i < [string length $k]} {incr i} {
+ if {$i > 0} {
+ puts -nonewline $fo " && "
+ if {![expr $i % 3]} {
+ puts -nonewline $fo "\n\t\t "
+ }
+ }
+ puts -nonewline $fo "p\[$i\] == '[string index $k $i]'"
+ }
+ if {[lindex $tt 2]} {
+ if {![expr $i % 3]} {
+ puts -nonewline $fo "\n\t\t "
+ }
+ puts -nonewline $fo " && !isvar(p\[$i\])"
+ }
+ puts $fo ") {"
+ puts $fo " *q = p + [string length $k];"
+ puts $fo " return ([lindex $tt 1]);"
+ puts $fo " }"
+ }
+}
+puts $fo " return (0);"
+puts $fo " default:"
+puts $fo " return (0);"
+puts $fo " }"
+puts $fo "}"
+
+puts $fo ""
+puts $fo "const char *vcl_tnames\[256\];\n"
+puts $fo "void"
+puts $fo "vcl_init_tnames(void)"
+puts $fo "{"
+foreach i $token2 {
+ puts $fo "\tvcl_tnames\[[lindex $i 0]\] = \"[lindex $i 0]\";"
+}
+foreach i $tokens {
+ puts $fo "\tvcl_tnames\[[lindex $i 0]\] = \"[lindex $i 1]\";"
+}
+puts $fo "}"
+
+#----------------------------------------------------------------------
+# Create the C-code which emits the boilerplate definitions for the
+# generated C code output
+
+proc copy_include {n} {
+ global fo
+
+ set fi [open $n]
+ while {[gets $fi a] >= 0} {
+ regsub -all {\\} $a {\\\\} a
+ puts $fo "\tfputs(\"$a\\n\", f);"
+ }
+ close $fi
+}
+
+puts $fo ""
+puts $fo "void"
+puts $fo "vcl_output_lang_h(FILE *f)"
+puts $fo "{"
+set i 0
+foreach k $returns {
+ puts $fo "\tfputs(\"#define VCL_RET_[string toupper $k] (1 << $i)\\n\", f);"
+ incr i
+}
+
+copy_include ../../include/vcl.h
+copy_include ../../include/vrt.h
+
+puts $fo "}"
+
+close $foh
+close $fo
Added: trunk/varnish-cache/lib/libvcl/vcc_obj.c
===================================================================
--- trunk/varnish-cache/lib/libvcl/vcc_obj.c 2006-07-21 16:25:24 UTC (rev 543)
+++ trunk/varnish-cache/lib/libvcl/vcc_obj.c 2006-07-21 18:12:56 UTC (rev 544)
@@ -0,0 +1,1843 @@
+/*
+ * $Id$
+ */
+
+#include <stdio.h>
+
+#include "vcc_compile.h"
+
+struct var vcc_be_vars[] = {
+ { "backend.host",
+ HOSTNAME, 0, NULL, "VRT_set_backend_hostname(backend, %s)" },
+ { "backend.port",
+ PORTNAME, 0, NULL, "VRT_set_backend_portname(backend, %s)" },
+};
+
+
+struct var vcc_vars[] = {
+ { "req.request", STRING, 0, "VRT_GetReq(sp)" },
+ { "obj.valid", BOOL, 0, "VRT_obj_valid(sp)" },
+ { "obj.cacheable", BOOL, 0, "VRT_obj_cacheable(sp)" },
+ { "obj.backend", BACKEND, 0, "VRT_obj_backend(sp)" },
+ { "req.http.", HEADER, 0, NULL },
+#if 0
+ { "req.ttlfactor", FLOAT, 0, "req->ttlfactor" },
+ { "req.url.host", STRING, 0, "req->url.host" },
+ { "req.url.path", STRING, 0, "req->url.path" },
+ { "req.useragent", STRING, 0, "req->useragent" },
+ { "req.backend", BACKEND, 0, "req->backend" },
+ { "client.ip", IP, 0, "client->ip" },
+ { "backend.response_time", TIME, 0, "backend->responsetime" },
+ { "backend.down", BOOL, 0, "backend->down" },
+ { "backend.timeout", TIME, 0, "backend->timeout" },
+ { "backend.bandwidth", RATE, 0, "backend->bandwidth" },
+ { "obj.exist", BOOL, 0, "obj->exists" },
+ { "obj.ttl", TIME, 0, "obj->ttl" },
+ { "obj.result", INT, 0, "obj->result" },
+ { "obj.size", SIZE, 0, "obj->size" },
+ { "obj.usage", INT, 0, "obj->usage" },
+#endif
+ { NULL, INT, 0, "NULL" }
+};
+
+
+#if 0
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <printf.h>
+#include <stdarg.h>
+#include <sbuf.h>
+#include <stdlib.h>
+#include <string.h>
+#include <queue.h>
+#include <unistd.h>
+
+#include "vcl_priv.h"
+#include "vcl_returns.h"
+#include "vcl_compile.h"
+
+#include "libvcl.h"
+
+#define ERRCHK(tl) do { if ((tl)->err) return; } while (0)
+
+#define INDENT 2
+
+/*--------------------------------------------------------------------
+ * Consistency check
+ */
+
+static struct method {
+ const char *name;
+ const char *defname;
+ unsigned returns;
+} method_tab[] = {
+#define VCL_RET_MAC(a,b,c)
+#define VCL_MET_MAC(a,b,c) { "vcl_"#a, "default_vcl_"#a, c },
+#include "vcl_returns.h"
+#undef VCL_MET_MAC
+#undef VCL_RET_MAC
+ { NULL, 0U }
+};
+
+struct proccall {
+ TAILQ_ENTRY(proccall) list;
+ struct proc *p;
+ struct token *t;
+};
+
+struct proc {
+ TAILQ_ENTRY(proc) list;
+ TAILQ_HEAD(,proccall) calls;
+ struct token *name;
+ unsigned returns;
+ unsigned exists;
+ unsigned called;
+ unsigned active;
+ struct token *returnt[VCL_RET_MAX];
+};
+
+/*--------------------------------------------------------------------*/
+
+
+static void Compound(struct tokenlist *tl);
+static void Cond_0(struct tokenlist *tl);
+static struct proc *AddProc(struct tokenlist *tl, struct token *t, int def);
+static void AddCall(struct tokenlist *tl, struct token *t);
+static const char *vcc_default_vcl_b, *vcc_default_vcl_e;
+
+/*--------------------------------------------------------------------*/
+
+static void
+ErrToken(struct tokenlist *tl, struct token *t)
+{
+
+ if (t->tok == EOI)
+ sbuf_printf(tl->sb, "end of input");
+ else
+ sbuf_printf(tl->sb, "'%T'", t);
+}
+
+static void
+_ErrInternal(struct tokenlist *tl, const char *func, unsigned line)
+{
+
+ sbuf_printf(tl->sb, "VCL compiler internal error at %s():%u\n",
+ func, line);
+ tl->err = 1;
+}
+
+#define ErrInternal(tl) _ErrInternal(tl, __func__, __LINE__)
+
+static void
+ErrWhere(struct tokenlist *tl, struct token *t)
+{
+ unsigned lin, pos, x, y;
+ const char *p, *l, *f, *b, *e;
+
+ lin = 1;
+ pos = 0;
+ if (t->tok == METHOD)
+ return;
+ if (t->b >= vcc_default_vcl_b && t->b < vcc_default_vcl_e) {
+ f = "Default VCL code (compiled in)";
+ b = vcc_default_vcl_b;
+ e = vcc_default_vcl_e;
+ } else {
+ f = "VCL code";
+ b = tl->b;
+ e = tl->e;
+ }
+ for (l = p = b; p < t->b; p++) {
+ if (*p == '\n') {
+ lin++;
+ pos = 0;
+ l = p + 1;
+ } else if (*p == '\t') {
+ pos &= ~7;
+ pos += 8;
+ } else
+ pos++;
+ }
+ sbuf_printf(tl->sb, "In %s Line %d Pos %d\n", f, lin, pos);
+ x = y = 0;
+ for (p = l; p < e && *p != '\n'; p++) {
+ if (*p == '\t') {
+ y &= ~7;
+ y += 8;
+ while (x < y) {
+ sbuf_bcat(tl->sb, " ", 1);
+ x++;
+ }
+ } else {
+ x++;
+ y++;
+ sbuf_bcat(tl->sb, p, 1);
+ }
+ }
+ sbuf_cat(tl->sb, "\n");
+ x = y = 0;
+ for (p = l; p < e && *p != '\n'; p++) {
+ if (p >= t->b && p < t->e) {
+ sbuf_bcat(tl->sb, "#", 1);
+ x++;
+ y++;
+ continue;
+ }
+ if (*p == '\t') {
+ y &= ~7;
+ y += 8;
+ } else
+ y++;
+ while (x < y) {
+ sbuf_bcat(tl->sb, "-", 1);
+ x++;
+ }
+ }
+ sbuf_cat(tl->sb, "\n");
+ tl->err = 1;
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+NextToken(struct tokenlist *tl)
+{
+ tl->t = TAILQ_NEXT(tl->t, list);
+ if (tl->t == NULL) {
+ sbuf_printf(tl->sb,
+ "Ran out of input, something is missing or"
+ " maybe unbalanced (...) or {...}\n");
+ tl->err = 1;
+ return;
+ }
+}
+
+static void
+_Expect(struct tokenlist *tl, unsigned tok, int line)
+{
+ if (tl->t->tok == tok)
+ return;
+ sbuf_printf(tl->sb, "Expected %s got ", vcl_tnames[tok]);
+ ErrToken(tl, tl->t);
+ sbuf_printf(tl->sb, "\n(program line %u), at\n", line);
+ ErrWhere(tl, tl->t);
+}
+
+#define Expect(a, b) _Expect(a, b, __LINE__)
+#define ExpectErr(a, b) do { _Expect(a, b, __LINE__); ERRCHK(a);} while (0)
+
+#define L(tl, foo) do { \
+ tl->indent += INDENT; \
+ foo; \
+ tl->indent -= INDENT; \
+} while (0)
+
+#define C(tl, sep) do { \
+ Fc(tl, 1, "VRT_count(sp, %u)%s\n", ++tl->cnt, sep); \
+ tl->t->cnt = tl->cnt; \
+} while (0)
+
+/*--------------------------------------------------------------------
+ * Printf output to the two sbufs, possibly indented
+ */
+
+static void
+Fh(struct tokenlist *tl, int indent, const char *fmt, ...)
+{
+ va_list ap;
+
+ if (indent)
+ sbuf_printf(tl->fh, "%*.*s", tl->indent, tl->indent, "");
+ va_start(ap, fmt);
+ sbuf_vprintf(tl->fh, fmt, ap);
+ va_end(ap);
+}
+
+static void
+Fc(struct tokenlist *tl, int indent, const char *fmt, ...)
+{
+ va_list ap;
+
+ if (indent)
+ sbuf_printf(tl->fc, "%*.*s", tl->indent, tl->indent, "");
+ va_start(ap, fmt);
+ sbuf_vprintf(tl->fc, fmt, ap);
+ va_end(ap);
+}
+
+/*--------------------------------------------------------------------
+ * Compare token to token
+ */
+
+static int
+Teq(struct token *t1, struct token *t2)
+{
+ if (t1->e - t1->b != t2->e - t2->b)
+ return (0);
+ return (!memcmp(t1->b, t2->b, t1->e - t1->b));
+}
+
+/*--------------------------------------------------------------------
+ * Compare ID token to string, return true of match
+ */
+
+static int
+IdIs(struct token *t, const char *p)
+{
+ const char *q;
+
+ assert(t->tok == ID);
+ for (q = t->b; q < t->e && *p != '\0'; p++, q++)
+ if (*q != *p)
+ return (0);
+ if (q != t->e || *p != '\0')
+ return (0);
+ return (1);
+}
+
+/*--------------------------------------------------------------------*/
+
+static char *
+EncString(struct token *t)
+{
+ char *p, *q;
+ const char *r;
+ unsigned u;
+
+ assert(t->tok == CSTR);
+ p = malloc(t->e - t->b);
+ assert(p != NULL);
+ q = p;
+ for (r = t->b + 1; r < t->e - 1; ) {
+ if (*r != '\\') {
+ *q++ = *r++;
+ continue;
+ }
+ switch (r[1]) {
+ case 'n': *q++ = '\n'; r += 2; break;
+ case 'r': *q++ = '\r'; r += 2; break;
+ case 'v': *q++ = '\v'; r += 2; break;
+ case 'f': *q++ = '\f'; r += 2; break;
+ case 't': *q++ = '\t'; r += 2; break;
+ case 'b': *q++ = '\b'; r += 2; break;
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ u = r[1] - '0';
+ r += 2;
+ if (isdigit(r[0]) && (r[0] - '0') < 8) {
+ u <<= 3;
+ u |= r[0] - '0';
+ r++;
+ if (isdigit(r[0]) && (r[0] - '0') < 8) {
+ u <<= 3;
+ u |= r[0] - '0';
+ r++;
+ }
+ }
+ *q++ = u;
+ break;
+ default:
+ *q++ = r[1];
+ r += 2;
+ break;
+ }
+ }
+ *q = '\0';
+ return (p);
+}
+
+
+/*--------------------------------------------------------------------
+ * Keep track of definitions and references
+ */
+
+static struct ref *
+FindRef(struct tokenlist *tl, struct token *t, enum ref_type type)
+{
+ struct ref *r;
+
+ TAILQ_FOREACH(r, &tl->refs, list) {
+ if (r->type != type)
+ continue;
+ if (Teq(r->name, t))
+ return (r);
+ }
+ r = calloc(sizeof *r, 1);
+ assert(r != NULL);
+ r->name = t;
+ r->type = type;
+ TAILQ_INSERT_TAIL(&tl->refs, r, list);
+ return (r);
+}
+
+static int
+FindRefStr(struct tokenlist *tl, const char *s, enum ref_type type)
+{
+ struct ref *r;
+
+ TAILQ_FOREACH(r, &tl->refs, list) {
+ if (r->type != type)
+ continue;
+ if (IdIs(r->name, s))
+ return (1);
+ }
+ return (0);
+}
+
+static void
+AddRef(struct tokenlist *tl, struct token *t, enum ref_type type)
+{
+
+ FindRef(tl, t, type)->refcnt++;
+}
+
+static void
+AddRefStr(struct tokenlist *tl, const char *s, enum ref_type type)
+{
+ struct token *t;
+
+ t = calloc(sizeof *t, 1);
+ t->b = s;
+ t->e = strchr(s, '\0');
+ t->tok = METHOD;
+ AddRef(tl, t, type);
+}
+
+static void
+AddDef(struct tokenlist *tl, struct token *t, enum ref_type type)
+{
+ struct ref *r;
+
+ r = FindRef(tl, t, type);
+ r->defcnt++;
+ r->name = t;
+}
+
+/*--------------------------------------------------------------------
+ * Recognize and convert units of time, return seconds.
+ */
+
+static double
+TimeUnit(struct tokenlist *tl)
+{
+ double sc = 1.0;
+
+ assert(tl->t->tok == ID);
+ if (IdIs(tl->t, "ms"))
+ sc = 1e-3;
+ else if (IdIs(tl->t, "s"))
+ sc = 1.0;
+ else if (IdIs(tl->t, "m"))
+ sc = 60.0;
+ else if (IdIs(tl->t, "h"))
+ sc = 60.0 * 60.0;
+ else if (IdIs(tl->t, "d"))
+ sc = 60.0 * 60.0 * 24.0;
+ else {
+ sbuf_printf(tl->sb, "Unknown time unit ");
+ ErrToken(tl, tl->t);
+ sbuf_printf(tl->sb, ". Legal are 's', 'm', 'h' and 'd'\n");
+ ErrWhere(tl, tl->t);
+ return (1.0);
+ }
+ NextToken(tl);
+ return (sc);
+}
+
+/*--------------------------------------------------------------------
+ * Recognize and convert units of size, return bytes.
+ */
+
+static double
+SizeUnit(struct tokenlist *tl)
+{
+ double sc = 1.0;
+
+ assert(tl->t->tok == ID);
+ if (IdIs(tl->t, "b"))
+ sc = 1.0;
+ else if (IdIs(tl->t, "kb"))
+ sc = 1024.0;
+ else if (IdIs(tl->t, "mb") || IdIs(tl->t, "Mb"))
+ sc = 1024.0 * 1024.0;
+ else if (IdIs(tl->t, "gb") || IdIs(tl->t, "Gb"))
+ sc = 1024.0 * 1024.0 * 1024.0;
+ else {
+ sbuf_printf(tl->sb, "Unknown size unit ");
+ ErrToken(tl, tl->t);
+ sbuf_printf(tl->sb, ". Legal are 'kb', 'mb' and 'gb'\n");
+ ErrWhere(tl, tl->t);
+ return (1.0);
+ }
+ NextToken(tl);
+ return (sc);
+}
+
+/*--------------------------------------------------------------------
+ * Recognize and convert units of rate as { space '/' time }
+ */
+
+static double
+RateUnit(struct tokenlist *tl)
+{
+ double sc = 1.0;
+
+ assert(tl->t->tok == ID);
+ sc = SizeUnit(tl);
+ Expect(tl, '/');
+ NextToken(tl);
+ sc /= TimeUnit(tl);
+ return (sc);
+}
+
+/*--------------------------------------------------------------------
+ * Recognize and convert { CNUM } to unsigned value
+ */
+
+static unsigned
+UintVal(struct tokenlist *tl)
+{
+ unsigned d = 0;
+ const char *p;
+
+ Expect(tl, CNUM);
+ for (p = tl->t->b; p < tl->t->e; p++) {
+ d *= 10;
+ d += *p - '0';
+ }
+ NextToken(tl);
+ return (d);
+}
+
+/*--------------------------------------------------------------------
+ * Recognize and convert { CNUM [ '.' [ CNUM ] ] } to double value
+ */
+
+static double
+DoubleVal(struct tokenlist *tl)
+{
+ double d = 0.0, e = 0.1;
+ const char *p;
+
+ Expect(tl, CNUM);
+ for (p = tl->t->b; p < tl->t->e; p++) {
+ d *= 10;
+ d += *p - '0';
+ }
+ NextToken(tl);
+ if (tl->t->tok != '.')
+ return (d);
+ NextToken(tl);
+ if (tl->t->tok != CNUM)
+ return (d);
+ for (p = tl->t->b; p < tl->t->e; p++) {
+ d += (*p - '0') * e;
+ e *= 0.1;
+ }
+ NextToken(tl);
+ return (d);
+}
+
+/*--------------------------------------------------------------------*/
+
+static unsigned
+IpVal(struct tokenlist *tl)
+{
+ unsigned u, v;
+ struct token *t;
+
+ t = tl->t;
+ u = UintVal(tl);
+ if (u < 256) {
+ v = u << 24;
+ Expect(tl, '.');
+ NextToken(tl);
+ t = tl->t;
+ u = UintVal(tl);
+ if (u < 256) {
+ v |= u << 16;
+ Expect(tl, '.');
+ NextToken(tl);
+ t = tl->t;
+ u = UintVal(tl);
+ if (u < 256) {
+ v |= u << 8;
+ Expect(tl, '.');
+ NextToken(tl);
+ t = tl->t;
+ u = UintVal(tl);
+ if (u < 256) {
+ v |= u;
+ return (v);
+ }
+ }
+ }
+ }
+ sbuf_printf(tl->sb, "Illegal octet in IP number\n");
+ ErrWhere(tl, t);
+ return (0);
+}
+
+/*--------------------------------------------------------------------*/
+
+static struct var *
+HeaderVar(struct tokenlist *tl __unused, struct token *t, struct var *vh)
+{
+ char *p;
+ struct var *v;
+ int i;
+
+ v = calloc(sizeof *v, 1);
+ assert(v != NULL);
+ i = t->e - t->b;
+ p = malloc(i + 1);
+ assert(p != NULL);
+ memcpy(p, t->b, i);
+ p[i] = '\0';
+ v->name = p;
+ v->fmt = STRING;
+ asprintf(&p, "VRT_GetHdr(sp, \"\\%03o%s:\")",
+ strlen(v->name + vh->len) + 1, v->name + vh->len);
+ assert(p != NULL);
+ v->rname = p;
+ return (v);
+}
+
+/*--------------------------------------------------------------------*/
+
+static struct var *
+FindVar(struct tokenlist *tl, struct token *t, struct var *vl)
+{
+ struct var *v;
+
+ for (v = vl; v->name != NULL; v++) {
+ if (v->fmt == HEADER && t->e - t->b <= v->len)
+ continue;
+ if (v->fmt != HEADER && t->e - t->b != v->len)
+ continue;
+ if (memcmp(t->b, v->name, v->len))
+ continue;
+ if (v->fmt != HEADER)
+ return (v);
+ return (HeaderVar(tl, t, v));
+ }
+ sbuf_printf(tl->sb, "Unknown variable ");
+ ErrToken(tl, t);
+ sbuf_cat(tl->sb, "\nAt: ");
+ ErrWhere(tl, t);
+ return (NULL);
+}
+
+
+/*--------------------------------------------------------------------*/
+
+static void
+TimeVal(struct tokenlist *tl)
+{
+ double v, sc;
+
+ v = DoubleVal(tl);
+ ExpectErr(tl, ID);
+ sc = TimeUnit(tl);
+ Fc(tl, 0, "(%g * %g)", v, sc);
+}
+
+static void
+SizeVal(struct tokenlist *tl)
+{
+ double v, sc;
+
+ v = DoubleVal(tl);
+ ExpectErr(tl, ID);
+ sc = SizeUnit(tl);
+ Fc(tl, 0, "(%g * %g)", v, sc);
+}
+
+static void
+RateVal(struct tokenlist *tl)
+{
+ double v, sc;
+
+ v = DoubleVal(tl);
+ ExpectErr(tl, ID);
+ sc = RateUnit(tl);
+ Fc(tl, 0, "(%g * %g)", v, sc);
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+Cond_Ip(struct var *vp, struct tokenlist *tl)
+{
+ unsigned u;
+
+ switch (tl->t->tok) {
+ case '~':
+ NextToken(tl);
+ ExpectErr(tl, ID);
+ AddRef(tl, tl->t, R_ACL);
+ Fc(tl, 1, "ip_match(%s, acl_%T)\n", vp->rname, tl->t);
+ NextToken(tl);
+ break;
+ case T_EQ:
+ case T_NEQ:
+ Fc(tl, 1, "%s %T ", vp->rname, tl->t);
+ NextToken(tl);
+ u = IpVal(tl);
+ Fc(tl, 0, "%uU /* %u.%u.%u.%u */\n", u,
+ (u >> 24) & 0xff, (u >> 16) & 0xff,
+ (u >> 8) & 0xff, (u) & 0xff);
+ break;
+ default:
+ sbuf_printf(tl->sb, "Illegal condition ");
+ ErrToken(tl, tl->t);
+ sbuf_printf(tl->sb, " on IP number variable\n");
+ sbuf_printf(tl->sb, " only '==', '!=' and '~' are legal\n");
+ ErrWhere(tl, tl->t);
+ break;
+ }
+}
+
+static void
+Cond_String(struct var *vp, struct tokenlist *tl)
+{
+
+ switch (tl->t->tok) {
+ case '~':
+ Fc(tl, 1, "string_match(%s, ", vp->rname);
+ NextToken(tl);
+ ExpectErr(tl, CSTR);
+ Fc(tl, 0, "%T)\n", tl->t);
+ NextToken(tl);
+ break;
+ case T_EQ:
+ case T_NEQ:
+ Fc(tl, 1, "%sstrcmp(%s, ",
+ tl->t->tok == T_EQ ? "!" : "", vp->rname);
+ NextToken(tl);
+ ExpectErr(tl, CSTR);
+ Fc(tl, 0, "%T)\n", tl->t);
+ NextToken(tl);
+ break;
+ default:
+ Fc(tl, 1, "%s != (void*)0", vp->rname);
+ break;
+ }
+}
+
+static void
+Cond_Int(struct var *vp, struct tokenlist *tl)
+{
+
+ Fc(tl, 1, "%s ", vp->rname);
+ switch (tl->t->tok) {
+ case T_EQ:
+ case T_NEQ:
+ case T_LEQ:
+ case T_GEQ:
+ case '>':
+ case '<':
+ Fc(tl, 0, "%T ", tl->t);
+ NextToken(tl);
+ switch(vp->fmt) {
+ case TIME:
+ TimeVal(tl);
+ break;
+ case INT:
+ ExpectErr(tl, CNUM);
+ Fc(tl, 0, "%T ", tl->t);
+ NextToken(tl);
+ break;
+ case SIZE:
+ SizeVal(tl);
+ break;
+ default:
+ sbuf_printf(tl->sb,
+ "No conditions available for variable '%s'\n",
+ vp->name);
+ ErrWhere(tl, tl->t);
+ return;
+ }
+ Fc(tl, 0, "\n");
+ break;
+ default:
+ sbuf_printf(tl->sb, "Illegal condition ");
+ ErrToken(tl, tl->t);
+ sbuf_printf(tl->sb, " on integer variable\n");
+ sbuf_printf(tl->sb,
+ " only '==', '!=', '<', '>', '<=' and '>=' are legal\n");
+ ErrWhere(tl, tl->t);
+ break;
+ }
+}
+
+static void
+Cond_Bool(struct var *vp, struct tokenlist *tl)
+{
+
+ Fc(tl, 1, "%s\n", vp->rname);
+}
+
+static void
+Cond_2(struct tokenlist *tl)
+{
+ struct var *vp;
+
+ C(tl, ",");
+ if (tl->t->tok == '!') {
+ Fc(tl, 1, "!(\n");
+ NextToken(tl);
+ } else {
+ Fc(tl, 1, "(\n");
+ }
+ if (tl->t->tok == '(') {
+ NextToken(tl);
+ Cond_0(tl);
+ ExpectErr(tl, ')');
+ NextToken(tl);
+ } else if (tl->t->tok == VAR) {
+ vp = FindVar(tl, tl->t, vars);
+ ERRCHK(tl);
+ assert(vp != NULL);
+ NextToken(tl);
+ switch (vp->fmt) {
+ case INT: L(tl, Cond_Int(vp, tl)); break;
+ case SIZE: L(tl, Cond_Int(vp, tl)); break;
+ case BOOL: L(tl, Cond_Bool(vp, tl)); break;
+ case IP: L(tl, Cond_Ip(vp, tl)); break;
+ case STRING: L(tl, Cond_String(vp, tl)); break;
+ case TIME: L(tl, Cond_Int(vp, tl)); break;
+ /* XXX backend == */
+ default:
+ sbuf_printf(tl->sb,
+ "Variable '%s'"
+ " has no conditions that can be checked\n",
+ vp->name);
+ ErrWhere(tl, tl->t);
+ return;
+ }
+ } else {
+ sbuf_printf(tl->sb,
+ "Syntax error in condition, expected '(', '!' or"
+ " variable name, found ");
+ ErrToken(tl, tl->t);
+ sbuf_printf(tl->sb, "\n");
+ ErrWhere(tl, tl->t);
+ return;
+ }
+ Fc(tl, 1, ")\n");
+}
+
+static void
+Cond_1(struct tokenlist *tl)
+{
+
+ Fc(tl, 1, "(\n");
+ L(tl, Cond_2(tl));
+ while (tl->t->tok == T_CAND) {
+ NextToken(tl);
+ Fc(tl, 1, ") && (\n");
+ L(tl, Cond_2(tl));
+ }
+ Fc(tl, 1, ")\n");
+}
+
+static void
+Cond_0(struct tokenlist *tl)
+{
+
+ Fc(tl, 1, "(\n");
+ L(tl, Cond_1(tl));
+ while (tl->t->tok == T_COR) {
+ NextToken(tl);
+ Fc(tl, 1, ") || (\n");
+ L(tl, Cond_1(tl));
+ }
+ Fc(tl, 1, ")\n");
+}
+
+static void
+Conditional(struct tokenlist *tl)
+{
+
+ ExpectErr(tl, '(');
+ NextToken(tl);
+ Fc(tl, 1, "(\n");
+ L(tl, Cond_0(tl));
+ ERRCHK(tl);
+ Fc(tl, 1, ")\n");
+ ExpectErr(tl, ')');
+ NextToken(tl);
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+IfStmt(struct tokenlist *tl)
+{
+
+ ExpectErr(tl, T_IF);
+ Fc(tl, 1, "if \n");
+ NextToken(tl);
+ L(tl, Conditional(tl));
+ ERRCHK(tl);
+ L(tl, Compound(tl));
+ ERRCHK(tl);
+ while (1) {
+ switch (tl->t->tok) {
+ case T_ELSE:
+ NextToken(tl);
+ if (tl->t->tok != T_IF) {
+ Fc(tl, 1, "else \n");
+ L(tl, Compound(tl));
+ ERRCHK(tl);
+ return;
+ }
+ /* FALLTHROUGH */
+ case T_ELSEIF:
+ case T_ELSIF:
+ Fc(tl, 1, "else if \n");
+ NextToken(tl);
+ L(tl, Conditional(tl));
+ ERRCHK(tl);
+ L(tl, Compound(tl));
+ ERRCHK(tl);
+ break;
+ default:
+ C(tl, ";");
+ return;
+ }
+ }
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+Action(struct tokenlist *tl)
+{
+ unsigned a, u;
+ struct var *vp;
+ struct token *at;
+
+ at = tl->t;
+ NextToken(tl);
+ switch (at->tok) {
+ case T_NO_NEW_CACHE:
+ Fc(tl, 1, "VCL_no_new_cache(sp);\n");
+ return;
+ case T_NO_CACHE:
+ Fc(tl, 1, "VCL_no_cache(sp);\n");
+ return;
+#define VCL_RET_MAC(a,b,c) case T_##b: \
+ Fc(tl, 1, "VRT_done(sp, VCL_RET_%s);\n", #b); \
+ tl->curproc->returns |= VCL_RET_##b; \
+ tl->curproc->returnt[c] = at; \
+ return;
+#include "vcl_returns.h"
+#undef VCL_RET_MAC
+ case T_ERROR:
+ if (tl->t->tok == CNUM)
+ a = UintVal(tl);
+ else
+ a = 0;
+ Fc(tl, 1, "VRT_error(sp, %u, ", a);
+ if (tl->t->tok == CSTR) {
+ Fc(tl, 0, "%T);\n", tl->t);
+ NextToken(tl);
+ } else
+ Fc(tl, 0, "(const char *)0);\n");
+ Fc(tl, 1, "VRT_done(sp, VCL_RET_ERROR);\n");
+ return;
+ case T_SWITCH_CONFIG:
+ ExpectErr(tl, ID);
+ Fc(tl, 1, "VCL_switch_config(\"%T\");\n", tl->t);
+ NextToken(tl);
+ return;
+ case T_CALL:
+ ExpectErr(tl, ID);
+ AddCall(tl, tl->t);
+ AddRef(tl, tl->t, R_FUNC);
+ Fc(tl, 1, "if (VGC_function_%T(sp))\n", tl->t);
+ Fc(tl, 1, "\treturn (1);\n");
+ NextToken(tl);
+ return;
+ case T_REWRITE:
+ ExpectErr(tl, CSTR);
+ Fc(tl, 1, "VCL_rewrite(%T", tl->t);
+ NextToken(tl);
+ ExpectErr(tl, CSTR);
+ Fc(tl, 0, ", %T);\n", tl->t);
+ NextToken(tl);
+ return;
+ case T_SET:
+ ExpectErr(tl, VAR);
+ vp = FindVar(tl, tl->t, vars);
+ ERRCHK(tl);
+ assert(vp != NULL);
+ Fc(tl, 1, "%s ", vp->rname);
+ NextToken(tl);
+ switch (vp->fmt) {
+ case INT:
+ case SIZE:
+ case RATE:
+ case TIME:
+ case FLOAT:
+ Fc(tl, 0, "%T ", tl->t);
+ a = tl->t->tok;
+ NextToken(tl);
+ if (a == T_MUL || a == T_DIV)
+ Fc(tl, 0, "%g", DoubleVal(tl));
+ else if (vp->fmt == TIME)
+ TimeVal(tl);
+ else if (vp->fmt == SIZE)
+ SizeVal(tl);
+ else if (vp->fmt == RATE)
+ RateVal(tl);
+ else
+ Fc(tl, 0, "%g", DoubleVal(tl));
+ Fc(tl, 0, ";\n");
+ break;
+ case IP:
+ if (tl->t->tok == '=') {
+ NextToken(tl);
+ u = IpVal(tl);
+ Fc(tl, 0, "= %uU; /* %u.%u.%u.%u */\n",
+ u,
+ (u >> 24) & 0xff,
+ (u >> 16) & 0xff,
+ (u >> 8) & 0xff,
+ u & 0xff);
+ break;
+ }
+ sbuf_printf(tl->sb, "Illegal assignment operator ");
+ ErrToken(tl, tl->t);
+ sbuf_printf(tl->sb,
+ " only '=' is legal for IP numbers\n");
+ ErrWhere(tl, tl->t);
+ return;
+ case BACKEND:
+ if (tl->t->tok == '=') {
+ NextToken(tl);
+ AddRef(tl, tl->t, R_BACKEND);
+ Fc(tl, 0, "= &VGC_backend_%T;\n", tl->t);
+ NextToken(tl);
+ break;
+ }
+ sbuf_printf(tl->sb, "Illegal assignment operator ");
+ ErrToken(tl, tl->t);
+ sbuf_printf(tl->sb,
+ " only '=' is legal for backend\n");
+ ErrWhere(tl, tl->t);
+ return;
+ default:
+ sbuf_printf(tl->sb,
+ "Assignments not possible for '%s'\n", vp->name);
+ ErrWhere(tl, tl->t);
+ return;
+ }
+ return;
+ default:
+ sbuf_printf(tl->sb, "Expected action, 'if' or '}'\n");
+ ErrWhere(tl, at);
+ return;
+ }
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+Acl(struct tokenlist *tl)
+{
+ unsigned u, m;
+
+ NextToken(tl);
+
+ ExpectErr(tl, ID);
+ AddDef(tl, tl->t, R_ACL);
+ Fh(tl, 0, "static struct vcl_acl acl_%T[];\n", tl->t);
+ Fc(tl, 1, "static struct vcl_acl acl_%T[] = {\n", tl->t);
+ NextToken(tl);
+
+ tl->indent += INDENT;
+
+ ExpectErr(tl, '{');
+ NextToken(tl);
+
+ while (tl->t->tok == CNUM) {
+ u = IpVal(tl);
+ if (tl->t->tok == '/') {
+ NextToken(tl);
+ ExpectErr(tl, CNUM);
+ m = UintVal(tl);
+ } else
+ m = 32;
+ ExpectErr(tl, ';');
+ NextToken(tl);
+ Fc(tl, 1, "{ %11uU, %3uU }, /* %u.%u.%u.%u/%u */\n",
+ u, m,
+ (u >> 24) & 0xff, (u >> 16) & 0xff,
+ (u >> 8) & 0xff, (u) & 0xff, m);
+ }
+ ExpectErr(tl, '}');
+ Fc(tl, 1, "{ %11uU, %3uU }\n", 0, 0);
+
+ tl->indent -= INDENT;
+
+ Fc(tl, 1, "};\n\n");
+ NextToken(tl);
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+Compound(struct tokenlist *tl)
+{
+
+ ExpectErr(tl, '{');
+ Fc(tl, 1, "{\n");
+ tl->indent += INDENT;
+ C(tl, ";");
+ NextToken(tl);
+ while (1) {
+ ERRCHK(tl);
+ switch (tl->t->tok) {
+ case '{':
+ Compound(tl);
+ break;
+ case T_IF:
+ IfStmt(tl);
+ break;
+ case '}':
+ NextToken(tl);
+ tl->indent -= INDENT;
+ Fc(tl, 1, "}\n");
+ return;
+ case EOI:
+ sbuf_printf(tl->sb,
+ "End of input while in compound statement\n");
+ tl->err = 1;
+ return;
+ default:
+ Action(tl);
+ ERRCHK(tl);
+ ExpectErr(tl, ';');
+ NextToken(tl);
+ break;
+ }
+ }
+}
+
+/*--------------------------------------------------------------------*/
+
+static const char *
+CheckHostPort(const char *host, const char *port)
+{
+ struct addrinfo *res, hint;
+ int error;
+
+ memset(&hint, 0, sizeof hint);
+ hint.ai_family = PF_UNSPEC;
+ hint.ai_socktype = SOCK_STREAM;
+ error = getaddrinfo(host, port, &hint, &res);
+ if (error)
+ return (gai_strerror(error));
+ freeaddrinfo(res);
+ return (NULL);
+}
+
+static void
+Backend(struct tokenlist *tl)
+{
+ struct var *vp;
+ struct token *t_be = NULL;
+ struct token *t_host = NULL;
+ struct token *t_port = NULL;
+ char *host = NULL;
+ char *port = NULL;
+ const char *ep;
+
+ NextToken(tl);
+ ExpectErr(tl, ID);
+ t_be = tl->t;
+ AddDef(tl, tl->t, R_BACKEND);
+ if (tl->nbackend == 0)
+ AddRef(tl, tl->t, R_BACKEND);
+ Fh(tl, 1, "#define VGC_backend_%T (VCL_conf.backend[%d])\n",
+ tl->t, tl->nbackend);
+ Fc(tl, 0, "static void\n");
+ Fc(tl, 1, "VGC_init_backend_%T (void)\n", tl->t);
+ Fc(tl, 1, "{\n");
+ Fc(tl, 1, "\tstruct backend *backend = VGC_backend_%T;\n", tl->t);
+ Fc(tl, 1, "\tconst char *p;\n");
+ Fc(tl, 1, "\n");
+ Fc(tl, 1, "\tVRT_set_backend_name(backend, \"%T\");\n", tl->t);
+ NextToken(tl);
+ ExpectErr(tl, '{');
+ NextToken(tl);
+ while (1) {
+ if (tl->t->tok == '}')
+ break;
+ ExpectErr(tl, T_SET);
+ NextToken(tl);
+ ExpectErr(tl, VAR);
+ vp = FindVar(tl, tl->t, be_vars);
+ ERRCHK(tl);
+ assert(vp != NULL);
+ NextToken(tl);
+ ExpectErr(tl, '=');
+ NextToken(tl);
+ switch (vp->fmt) {
+ case HOSTNAME:
+ ExpectErr(tl, CSTR);
+ t_host = tl->t;
+ Fc(tl, 1, "\tp = %T;\n", tl->t);
+ Fc(tl, 1, "\t");
+ Fc(tl, 0, vp->lname, "p");
+ Fc(tl, 0, ";\n");
+ NextToken(tl);
+ break;
+ case PORTNAME:
+ ExpectErr(tl, CSTR);
+ t_port = tl->t;
+ Fc(tl, 1, "\tp = %T;\n", tl->t);
+ Fc(tl, 1, "\t");
+ Fc(tl, 0, vp->lname, "p");
+ Fc(tl, 0, ";\n");
+ NextToken(tl);
+ break;
+ default:
+ sbuf_printf(tl->sb,
+ "Assignments not possible for '%s'\n", vp->name);
+ ErrWhere(tl, tl->t);
+ return;
+ }
+ ExpectErr(tl, ';');
+ NextToken(tl);
+ }
+ ExpectErr(tl, '}');
+ if (t_host == NULL) {
+ sbuf_printf(tl->sb, "Backend '%T' has no hostname\n", t_be);
+ ErrWhere(tl, tl->t);
+ return;
+ }
+ host = EncString(t_host);
+ ep = CheckHostPort(host, "80");
+ if (ep != NULL) {
+ sbuf_printf(tl->sb, "Backend '%T': %s\n", t_be, ep);
+ ErrWhere(tl, t_host);
+ return;
+ }
+ if (t_port != NULL) {
+ port = EncString(t_port);
+ ep = CheckHostPort(host, port);
+ if (ep != NULL) {
+ sbuf_printf(tl->sb, "Backend '%T': %s\n", t_be, ep);
+ ErrWhere(tl, t_port);
+ return;
+ }
+ }
+
+ NextToken(tl);
+ Fc(tl, 1, "}\n");
+ Fc(tl, 0, "\n");
+ tl->nbackend++;
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+Function(struct tokenlist *tl)
+{
+
+ NextToken(tl);
+ ExpectErr(tl, ID);
+ tl->curproc = AddProc(tl, tl->t, 1);
+ tl->curproc->exists++;
+ AddDef(tl, tl->t, R_FUNC);
+ Fh(tl, 0, "static int VGC_function_%T (struct sess *sp);\n", tl->t);
+ Fc(tl, 1, "static int\n");
+ Fc(tl, 1, "VGC_function_%T (struct sess *sp)\n", tl->t);
+ NextToken(tl);
+ L(tl, Compound(tl));
+ Fc(tl, 0, "\n");
+}
+
+/*--------------------------------------------------------------------
+ * Top level of parser, recognize:
+ * Function definitions
+ * Backend definitions
+ * End of input
+ */
+
+static void
+Parse(struct tokenlist *tl)
+{
+
+ while (tl->t->tok != EOI) {
+ ERRCHK(tl);
+ switch (tl->t->tok) {
+ case T_ACL:
+ Acl(tl);
+ break;
+ case T_SUB:
+ Function(tl);
+ break;
+ case T_BACKEND:
+ Backend(tl);
+ break;
+ case EOI:
+ break;
+ default:
+ sbuf_printf(tl->sb,
+ "Expected 'acl', 'sub' or 'backend', found ");
+ ErrToken(tl, tl->t);
+ sbuf_printf(tl->sb, " at\n");
+ ErrWhere(tl, tl->t);
+ return;
+ }
+ }
+}
+
+/*--------------------------------------------------------------------
+ * Add a token to the token list.
+ */
+
+static void
+AddToken(struct tokenlist *tl, unsigned tok, const char *b, const char *e)
+{
+ struct token *t;
+
+ t = calloc(sizeof *t, 1);
+ assert(t != NULL);
+ t->tok = tok;
+ t->b = b;
+ t->e = e;
+ TAILQ_INSERT_TAIL(&tl->tokens, t, list);
+ tl->t = t;
+ if (0) {
+ fprintf(stderr, "[%s %*.*s] ",
+ vcl_tnames[tok],
+ e - b, e - b, b);
+ if (tok == EOI)
+ fprintf(stderr, "\n");
+ }
+}
+
+/*--------------------------------------------------------------------
+ * Lexical analysis and token generation
+ */
+
+static void
+Lexer(struct tokenlist *tl, const char *b, const char *e)
+{
+ const char *p, *q;
+ unsigned u;
+
+ for (p = b; p < e; ) {
+
+ /* Skip any whitespace */
+ if (isspace(*p)) {
+ p++;
+ continue;
+ }
+
+ /* Skip '#.*\n' comments */
+ if (*p == '#') {
+ while (p < e && *p != '\n')
+ p++;
+ continue;
+ }
+
+ /* Skip C-style comments */
+ if (*p == '/' && p[1] == '*') {
+ p += 2;
+ for (p += 2; p < e; p++) {
+ if (*p == '*' && p[1] == '/') {
+ p += 2;
+ break;
+ }
+ }
+ continue;
+ }
+
+ /* Match for the fixed tokens (see token.tcl) */
+ u = vcl_fixed_token(p, &q);
+ if (u != 0) {
+ AddToken(tl, u, p, q);
+ p = q;
+ continue;
+ }
+
+ /* Match strings, with \\ and \" escapes */
+ if (*p == '"') {
+ for (q = p + 1; q < e; q++) {
+ if (*q == '\\' && q[1] == '\\')
+ q++;
+ else if (*q == '\\' && q[1] == '"')
+ q++;
+ else if (*q == '"') {
+ q++;
+ break;
+ }
+ }
+ AddToken(tl, CSTR, p, q);
+ p = q;
+ continue;
+ }
+
+ /* Match Identifiers */
+ if (isident1(*p)) {
+ for (q = p; q < e; q++)
+ if (!isident(*q))
+ break;
+ if (isvar(*q)) {
+ for (; q < e; q++)
+ if (!isvar(*q))
+ break;
+ AddToken(tl, VAR, p, q);
+ } else {
+ AddToken(tl, ID, p, q);
+ }
+ p = q;
+ continue;
+ }
+
+ /* Match numbers { [0-9]+ } */
+ if (isdigit(*p)) {
+ for (q = p; q < e; q++)
+ if (!isdigit(*q))
+ break;
+ AddToken(tl, CNUM, p, q);
+ p = q;
+ continue;
+ }
+ AddToken(tl, EOI, p, p + 1);
+ sbuf_printf(tl->sb, "Syntax error at\n");
+ ErrWhere(tl, tl->t);
+ return;
+ }
+}
+
+/*--------------------------------------------------------------------
+ * Consistency check
+ */
+
+static struct proc *
+AddProc(struct tokenlist *tl, struct token *t, int def)
+{
+ struct proc *p;
+
+ TAILQ_FOREACH(p, &tl->procs, list) {
+ if (!Teq(p->name, t))
+ continue;
+ if (def)
+ p->name = t;
+ return (p);
+ }
+ p = calloc(sizeof *p, 1);
+ assert(p != NULL);
+ p->name = t;
+ TAILQ_INIT(&p->calls);
+ TAILQ_INSERT_TAIL(&tl->procs, p, list);
+ return (p);
+}
+
+static void
+AddCall(struct tokenlist *tl, struct token *t)
+{
+ struct proccall *pc;
+ struct proc *p;
+
+ p = AddProc(tl, t, 0);
+ TAILQ_FOREACH(pc, &tl->curproc->calls, list) {
+ if (pc->p == p)
+ return;
+ }
+ pc = calloc(sizeof *pc, 1);
+ assert(pc != NULL);
+ pc->p = p;
+ pc->t = t;
+ TAILQ_INSERT_TAIL(&tl->curproc->calls, pc, list);
+}
+
+static int
+Consist_Decend(struct tokenlist *tl, struct proc *p, unsigned returns)
+{
+ unsigned u;
+ struct proccall *pc;
+
+ if (!p->exists) {
+ sbuf_printf(tl->sb, "Function %T does not exist\n", p->name);
+ return (1);
+ }
+ if (p->active) {
+ sbuf_printf(tl->sb, "Function recurses on\n");
+ ErrWhere(tl, p->name);
+ return (1);
+ }
+ u = p->returns & ~returns;
+ if (u) {
+#define VCL_RET_MAC(a, b, c) \
+ if (u & VCL_RET_##b) { \
+ sbuf_printf(tl->sb, "Illegal return for method\n"); \
+ ErrWhere(tl, p->returnt[c]); \
+ }
+#include "vcl_returns.h"
+#undef VCL_RET_MAC
+ sbuf_printf(tl->sb, "In function\n");
+ ErrWhere(tl, p->name);
+ return (1);
+ }
+ p->active = 1;
+ TAILQ_FOREACH(pc, &p->calls, list) {
+ if (Consist_Decend(tl, pc->p, returns)) {
+ sbuf_printf(tl->sb, "\nCalled from\n");
+ ErrWhere(tl, p->name);
+ sbuf_printf(tl->sb, "at\n");
+ ErrWhere(tl, pc->t);
+ return (1);
+ }
+ }
+ p->active = 0;
+ p->called++;
+ return (0);
+}
+
+static int
+Consistency(struct tokenlist *tl)
+{
+ struct proc *p;
+ struct method *m;
+
+ TAILQ_FOREACH(p, &tl->procs, list) {
+ for(m = method_tab; m->name != NULL; m++) {
+ if (IdIs(p->name, m->defname))
+ p->called = 1;
+ if (IdIs(p->name, m->name))
+ break;
+ }
+ if (m->name == NULL)
+ continue;
+ if (Consist_Decend(tl, p, m->returns)) {
+ sbuf_printf(tl->sb,
+ "\nwhich is a %s method\n", m->name);
+ return (1);
+ }
+ }
+ TAILQ_FOREACH(p, &tl->procs, list) {
+ if (p->called)
+ continue;
+ sbuf_printf(tl->sb, "Function unused\n");
+ ErrWhere(tl, p->name);
+ return (1);
+ }
+ return (0);
+}
+
+/*--------------------------------------------------------------------*/
+
+static int
+CheckRefs(struct tokenlist *tl)
+{
+ struct ref *r;
+ const char *type;
+ int nerr = 0;
+
+ TAILQ_FOREACH(r, &tl->refs, list) {
+ if (r->defcnt != 0 && r->refcnt != 0)
+ continue;
+ nerr++;
+
+ switch(r->type) {
+ case R_FUNC:
+ type = "function";
+ break;
+ case R_ACL:
+ type = "acl";
+ break;
+ case R_BACKEND:
+ type = "backend";
+ break;
+ default:
+ ErrInternal(tl);
+ sbuf_printf(tl->sb, "Ref ");
+ ErrToken(tl, r->name);
+ sbuf_printf(tl->sb, " has unknown type %d\n",
+ r->type);
+ continue;
+ }
+ if (r->defcnt == 0 && r->name->tok == METHOD) {
+ sbuf_printf(tl->sb,
+ "No definition for method %T\n", r->name);
+ continue;
+ }
+
+ if (r->defcnt == 0) {
+ sbuf_printf(tl->sb,
+ "Undefined %s %T, first reference:\n",
+ type, r->name);
+ ErrWhere(tl, r->name);
+ continue;
+ }
+
+ sbuf_printf(tl->sb, "Unused %s %T, defined:\n", type, r->name);
+ ErrWhere(tl, r->name);
+ }
+ return (nerr);
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+LocTable(struct tokenlist *tl)
+{
+ struct token *t;
+ unsigned lin, pos;
+ const char *p;
+
+ Fh(tl, 0, "#define VGC_NREFS %u\n", tl->cnt + 1);
+ Fh(tl, 0, "static struct vrt_ref VGC_ref[VGC_NREFS];\n");
+ Fc(tl, 0, "static struct vrt_ref VGC_ref[VGC_NREFS] = {\n");
+ lin = 1;
+ pos = 0;
+ p = tl->b;
+ TAILQ_FOREACH(t, &tl->tokens, list) {
+ if (t->cnt == 0)
+ continue;
+ for (;p < t->b; p++) {
+ if (*p == '\n') {
+ lin++;
+ pos = 0;
+ } else if (*p == '\t') {
+ pos &= ~7;
+ pos += 8;
+ } else
+ pos++;
+
+ }
+ Fc(tl, 0, " [%3u] = { %4u, %3u, 0, \"%T\" },\n",
+ t->cnt, lin, pos + 1, t);
+ }
+ Fc(tl, 0, "};\n");
+}
+
+
+/*--------------------------------------------------------------------*/
+
+static void
+EmitInitFunc(struct tokenlist *tl)
+{
+ struct ref *r;
+
+ Fc(tl, 0, "\nstatic void\nVGC_Init(void)\n{\n\n");
+ Fc(tl, 0, "\tVRT_alloc_backends(&VCL_conf);\n");
+
+ TAILQ_FOREACH(r, &tl->refs, list) {
+ switch(r->type) {
+ case R_FUNC:
+ break;
+ case R_ACL:
+ break;
+ case R_BACKEND:
+ Fc(tl, 0, "\tVGC_init_backend_%T();\n", r->name);
+ break;
+ }
+ }
+ Fc(tl, 0, "}\n");
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+EmitStruct(struct tokenlist *tl)
+{
+
+ Fc(tl, 0, "\nstruct VCL_conf VCL_conf = {\n");
+ Fc(tl, 0, "\t.magic = VCL_CONF_MAGIC,\n");
+ Fc(tl, 0, "\t.init_func = VGC_Init,\n");
+ Fc(tl, 0, "\t.nbackend = %d,\n", tl->nbackend);
+ Fc(tl, 0, "\t.ref = VGC_ref,\n");
+ Fc(tl, 0, "\t.nref = VGC_NREFS,\n");
+#define VCL_RET_MAC(l,u,b)
+#define VCL_MET_MAC(l,u,b) \
+ if (FindRefStr(tl, "vcl_" #l, R_FUNC)) { \
+ Fc(tl, 0, "\t." #l "_func = VGC_function_vcl_" #l ",\n"); \
+ AddRefStr(tl, "vcl_" #l, R_FUNC); \
+ } else { \
+ Fc(tl, 0, "\t." #l "_func = VGC_function_default_vcl_" #l ",\n"); \
+ } \
+ AddRefStr(tl, "default_vcl_" #l, R_FUNC);
+#include "vcl_returns.h"
+#undef VCL_MET_MAC
+#undef VCL_RET_MAC
+ Fc(tl, 0, "};\n");
+}
+
+/*--------------------------------------------------------------------*/
+
+char *
+VCC_Compile(struct sbuf *sb, const char *b, const char *e)
+{
+ struct tokenlist tokens;
+ struct ref *r;
+ struct token *t;
+ FILE *fo;
+ char *of = NULL;
+ char buf[BUFSIZ];
+
+ memset(&tokens, 0, sizeof tokens);
+ TAILQ_INIT(&tokens.tokens);
+ TAILQ_INIT(&tokens.refs);
+ TAILQ_INIT(&tokens.procs);
+ tokens.sb = sb;
+
+ tokens.fc = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND);
+ assert(tokens.fc != NULL);
+
+ tokens.fh = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND);
+ assert(tokens.fh != NULL);
+
+ Fh(&tokens, 0, "extern struct VCL_conf VCL_conf;\n");
+
+ tokens.b = b;
+ if (e == NULL)
+ e = strchr(b, '\0');
+ assert(e != NULL);
+ tokens.e = e;
+ Lexer(&tokens, b, e);
+ Lexer(&tokens, vcc_default_vcl_b, vcc_default_vcl_e);
+ AddToken(&tokens, EOI, e, e);
+ if (tokens.err)
+ goto done;
+ tokens.t = TAILQ_FIRST(&tokens.tokens);
+ Parse(&tokens);
+ if (tokens.err)
+ goto done;
+ Consistency(&tokens);
+ if (tokens.err)
+ goto done;
+ LocTable(&tokens);
+
+ EmitInitFunc(&tokens);
+
+ EmitStruct(&tokens);
+
+ if (CheckRefs(&tokens))
+ goto done;
+
+ of = strdup("/tmp/vcl.XXXXXXXX");
+ assert(of != NULL);
+ mktemp(of);
+
+ sprintf(buf,
+ "tee /tmp/_.c |"
+ "cc -fpic -shared -Wl,-x -o %s -x c - ", of);
+
+ fo = popen(buf, "w");
+ assert(fo != NULL);
+
+ vcl_output_lang_h(fo);
+
+ sbuf_finish(tokens.fh);
+ fputs(sbuf_data(tokens.fh), fo);
+ sbuf_delete(tokens.fh);
+
+ sbuf_finish(tokens.fc);
+ fputs(sbuf_data(tokens.fc), fo);
+ sbuf_delete(tokens.fc);
+
+ pclose(fo);
+done:
+
+ /* Free References */
+ while (!TAILQ_EMPTY(&tokens.refs)) {
+ r = TAILQ_FIRST(&tokens.refs);
+ TAILQ_REMOVE(&tokens.refs, r, list);
+ free(r);
+ }
+
+ /* Free Tokens */
+ while (!TAILQ_EMPTY(&tokens.tokens)) {
+ t = TAILQ_FIRST(&tokens.tokens);
+ TAILQ_REMOVE(&tokens.tokens, t, list);
+ free(t);
+ }
+ return (of);
+}
+
+/*--------------------------------------------------------------------*/
+
+char *
+VCC_CompileFile(struct sbuf *sb, const char *fn)
+{
+ char *f, *r;
+ int fd, i;
+ struct stat st;
+
+ fd = open(fn, O_RDONLY);
+ if (fd < 0) {
+ sbuf_printf(sb, "Cannot open file '%s': %s",
+ fn, strerror(errno));
+ return (NULL);
+ }
+ assert(0 == fstat(fd, &st));
+ f = malloc(st.st_size + 1);
+ assert(f != NULL);
+ i = read(fd, f, st.st_size);
+ assert(i == st.st_size);
+ f[i] = '\0';
+ r = VCC_Compile(sb, f, NULL);
+ free(f);
+ return (r);
+}
+
+/*--------------------------------------------------------------------*/
+
+static int
+VCC_T_render(FILE *f, const struct printf_info *info __unused, const void *const *args)
+{
+ const struct token *t;
+
+ t = *((const struct token * const*) (args[0]));
+ return (fprintf(f, "%*.*s",
+ t->e - t->b, t->e - t->b, t->b));
+}
+
+static int
+VCC_T_arginfo(const struct printf_info *info __unused, size_t n, int *argtypes)
+{
+
+ if (n > 0)
+ argtypes[0] = PA_POINTER;
+ return 1;
+}
+
+/*--------------------------------------------------------------------*/
+
+void
+VCC_InitCompile(const char *default_vcl)
+{
+ struct var *v;
+
+ vcc_default_vcl_b = default_vcl;
+ vcc_default_vcl_e = strchr(default_vcl, '\0');
+ assert(vcc_default_vcl_e != NULL);
+
+ register_printf_function ('T', VCC_T_render, VCC_T_arginfo);
+ vcl_init_tnames();
+ for (v = vars; v->name != NULL; v++)
+ v->len = strlen(v->name);
+ for (v = be_vars; v->name != NULL; v++)
+ v->len = strlen(v->name);
+}
+
+#endif
Copied: trunk/varnish-cache/lib/libvcl/vcc_priv.h (from rev 480, trunk/varnish-cache/lib/libvcl/vcl_priv.h)
===================================================================
--- trunk/varnish-cache/lib/libvcl/vcl_priv.h 2006-07-14 13:54:41 UTC (rev 480)
+++ trunk/varnish-cache/lib/libvcl/vcc_priv.h 2006-07-21 18:12:56 UTC (rev 544)
@@ -0,0 +1,13 @@
+/*
+ * Stuff shared between main.c and fixed_token.c
+ */
+
+#include "vcc_token_defs.h"
+
+#define isident1(c) (isalpha(c))
+#define isident(c) (isalpha(c) || isdigit(c) || (c) == '_')
+#define isvar(c) (isident(c) || (c) == '.')
+unsigned vcl_fixed_token(const char *p, const char **q);
+extern const char *vcl_tnames[256];
+void vcl_init_tnames(void);
+void vcl_output_lang_h(FILE *f);
Added: trunk/varnish-cache/lib/libvcl/vcc_token.c
===================================================================
--- trunk/varnish-cache/lib/libvcl/vcc_token.c 2006-07-21 16:25:24 UTC (rev 543)
+++ trunk/varnish-cache/lib/libvcl/vcc_token.c 2006-07-21 18:12:56 UTC (rev 544)
@@ -0,0 +1,312 @@
+/*
+ * $Id$
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <printf.h>
+#include <stdarg.h>
+#include <sbuf.h>
+#include <stdlib.h>
+#include <string.h>
+#include <queue.h>
+#include <unistd.h>
+
+#include "vcc_priv.h"
+#include "vcl_returns.h"
+#include "vcc_compile.h"
+
+#include "libvcl.h"
+
+#define ERRCHK(tl) do { if ((tl)->err) return; } while (0)
+
+#define INDENT 2
+
+/*--------------------------------------------------------------------*/
+
+void
+vcc_ErrToken(struct tokenlist *tl, struct token *t)
+{
+
+ if (t->tok == EOI)
+ sbuf_printf(tl->sb, "end of input");
+ else
+ sbuf_printf(tl->sb, "'%T'", t);
+}
+
+void
+vcc__ErrInternal(struct tokenlist *tl, const char *func, unsigned line)
+{
+
+ sbuf_printf(tl->sb, "VCL compiler internal error at %s():%u\n",
+ func, line);
+ tl->err = 1;
+}
+
+void
+vcc_ErrWhere(struct tokenlist *tl, struct token *t)
+{
+ unsigned lin, pos, x, y;
+ const char *p, *l, *f, *b, *e;
+
+ lin = 1;
+ pos = 0;
+ if (t->tok == METHOD)
+ return;
+ if (t->b >= vcc_default_vcl_b && t->b < vcc_default_vcl_e) {
+ f = "Default VCL code (compiled in)";
+ b = vcc_default_vcl_b;
+ e = vcc_default_vcl_e;
+ } else {
+ f = "VCL code";
+ b = tl->b;
+ e = tl->e;
+ }
+ for (l = p = b; p < t->b; p++) {
+ if (*p == '\n') {
+ lin++;
+ pos = 0;
+ l = p + 1;
+ } else if (*p == '\t') {
+ pos &= ~7;
+ pos += 8;
+ } else
+ pos++;
+ }
+ sbuf_printf(tl->sb, "In %s Line %d Pos %d\n", f, lin, pos);
+ x = y = 0;
+ for (p = l; p < e && *p != '\n'; p++) {
+ if (*p == '\t') {
+ y &= ~7;
+ y += 8;
+ while (x < y) {
+ sbuf_bcat(tl->sb, " ", 1);
+ x++;
+ }
+ } else {
+ x++;
+ y++;
+ sbuf_bcat(tl->sb, p, 1);
+ }
+ }
+ sbuf_cat(tl->sb, "\n");
+ x = y = 0;
+ for (p = l; p < e && *p != '\n'; p++) {
+ if (p >= t->b && p < t->e) {
+ sbuf_bcat(tl->sb, "#", 1);
+ x++;
+ y++;
+ continue;
+ }
+ if (*p == '\t') {
+ y &= ~7;
+ y += 8;
+ } else
+ y++;
+ while (x < y) {
+ sbuf_bcat(tl->sb, "-", 1);
+ x++;
+ }
+ }
+ sbuf_cat(tl->sb, "\n");
+ tl->err = 1;
+}
+
+/*--------------------------------------------------------------------*/
+
+void
+vcc_NextToken(struct tokenlist *tl)
+{
+ tl->t = TAILQ_NEXT(tl->t, list);
+ if (tl->t == NULL) {
+ sbuf_printf(tl->sb,
+ "Ran out of input, something is missing or"
+ " maybe unbalanced (...) or {...}\n");
+ tl->err = 1;
+ return;
+ }
+}
+
+void
+vcc__Expect(struct tokenlist *tl, unsigned tok, int line)
+{
+ if (tl->t->tok == tok)
+ return;
+ sbuf_printf(tl->sb, "Expected %s got ", vcl_tnames[tok]);
+ vcc_ErrToken(tl, tl->t);
+ sbuf_printf(tl->sb, "\n(program line %u), at\n", line);
+ vcc_ErrWhere(tl, tl->t);
+}
+
+#define Expect(a, b) _Expect(a, b, __LINE__)
+#define ExpectErr(a, b) do { _Expect(a, b, __LINE__); ERRCHK(a);} while (0)
+
+#define L(tl, foo) do { \
+ tl->indent += INDENT; \
+ foo; \
+ tl->indent -= INDENT; \
+} while (0)
+
+#define C(tl, sep) do { \
+ Fc(tl, 1, "VRT_count(sp, %u)%s\n", ++tl->cnt, sep); \
+ tl->t->cnt = tl->cnt; \
+} while (0)
+
+
+/*--------------------------------------------------------------------
+ * Compare token to token
+ */
+
+int
+vcc_Teq(struct token *t1, struct token *t2)
+{
+ if (t1->e - t1->b != t2->e - t2->b)
+ return (0);
+ return (!memcmp(t1->b, t2->b, t1->e - t1->b));
+}
+
+/*--------------------------------------------------------------------
+ * Compare ID token to string, return true of match
+ */
+
+int
+vcc_IdIs(struct token *t, const char *p)
+{
+ const char *q;
+
+ assert(t->tok == ID);
+ for (q = t->b; q < t->e && *p != '\0'; p++, q++)
+ if (*q != *p)
+ return (0);
+ if (q != t->e || *p != '\0')
+ return (0);
+ return (1);
+}
+
+/*--------------------------------------------------------------------
+ * Add a token to the token list.
+ */
+
+void
+vcc_AddToken(struct tokenlist *tl, unsigned tok, const char *b, const char *e)
+{
+ struct token *t;
+
+ t = calloc(sizeof *t, 1);
+ assert(t != NULL);
+ t->tok = tok;
+ t->b = b;
+ t->e = e;
+ TAILQ_INSERT_TAIL(&tl->tokens, t, list);
+ tl->t = t;
+ if (0) {
+ fprintf(stderr, "[%s %*.*s] ",
+ vcl_tnames[tok],
+ e - b, e - b, b);
+ if (tok == EOI)
+ fprintf(stderr, "\n");
+ }
+}
+
+/*--------------------------------------------------------------------
+ * Lexical analysis and token generation
+ */
+
+void
+vcc_Lexer(struct tokenlist *tl, const char *b, const char *e)
+{
+ const char *p, *q;
+ unsigned u;
+
+ for (p = b; p < e; ) {
+
+ /* Skip any whitespace */
+ if (isspace(*p)) {
+ p++;
+ continue;
+ }
+
+ /* Skip '#.*\n' comments */
+ if (*p == '#') {
+ while (p < e && *p != '\n')
+ p++;
+ continue;
+ }
+
+ /* Skip C-style comments */
+ if (*p == '/' && p[1] == '*') {
+ p += 2;
+ for (p += 2; p < e; p++) {
+ if (*p == '*' && p[1] == '/') {
+ p += 2;
+ break;
+ }
+ }
+ continue;
+ }
+
+ /* Match for the fixed tokens (see token.tcl) */
+ u = vcl_fixed_token(p, &q);
+ if (u != 0) {
+ vcc_AddToken(tl, u, p, q);
+ p = q;
+ continue;
+ }
+
+ /* Match strings, with \\ and \" escapes */
+ if (*p == '"') {
+ for (q = p + 1; q < e; q++) {
+ if (*q == '\\' && q[1] == '\\')
+ q++;
+ else if (*q == '\\' && q[1] == '"')
+ q++;
+ else if (*q == '"') {
+ q++;
+ break;
+ }
+ }
+ vcc_AddToken(tl, CSTR, p, q);
+ p = q;
+ continue;
+ }
+
+ /* Match Identifiers */
+ if (isident1(*p)) {
+ for (q = p; q < e; q++)
+ if (!isident(*q))
+ break;
+ if (isvar(*q)) {
+ for (; q < e; q++)
+ if (!isvar(*q))
+ break;
+ vcc_AddToken(tl, VAR, p, q);
+ } else {
+ vcc_AddToken(tl, ID, p, q);
+ }
+ p = q;
+ continue;
+ }
+
+ /* Match numbers { [0-9]+ } */
+ if (isdigit(*p)) {
+ for (q = p; q < e; q++)
+ if (!isdigit(*q))
+ break;
+ vcc_AddToken(tl, CNUM, p, q);
+ p = q;
+ continue;
+ }
+ vcc_AddToken(tl, EOI, p, p + 1);
+ sbuf_printf(tl->sb, "Syntax error at\n");
+ vcc_ErrWhere(tl, tl->t);
+ return;
+ }
+}
Copied: trunk/varnish-cache/lib/libvcl/vcc_token_defs.h (from rev 480, trunk/varnish-cache/lib/libvcl/vcl_token_defs.h)
===================================================================
--- trunk/varnish-cache/lib/libvcl/vcl_token_defs.h 2006-07-14 13:54:41 UTC (rev 480)
+++ trunk/varnish-cache/lib/libvcl/vcc_token_defs.h 2006-07-21 18:12:56 UTC (rev 544)
@@ -0,0 +1,53 @@
+/*
+ * $Id$
+ *
+ * NB: This file is machine generated, DO NOT EDIT!
+ *
+ * Edit vcc_gen_fixed_token.tcl instead
+ */
+
+#define LOW_TOKEN 128
+#define T_IF 128
+#define T_ELSE 129
+#define T_ELSEIF 130
+#define T_ELSIF 131
+#define T_FUNC 132
+#define T_PROC 133
+#define T_SUB 134
+#define T_ACL 135
+#define T_BACKEND 136
+#define T_CALL 137
+#define T_NO_CACHE 138
+#define T_NO_NEW_CACHE 139
+#define T_SET 140
+#define T_REWRITE 141
+#define T_SWITCH_CONFIG 142
+#define T_ERROR 143
+#define T_LOOKUP 144
+#define T_PIPE 145
+#define T_PASS 146
+#define T_INSERT_PASS 147
+#define T_FETCH 148
+#define T_INSERT 149
+#define T_DELIVER 150
+#define T_DISCARD 151
+#define T_INC 152
+#define T_DEC 153
+#define T_CAND 154
+#define T_COR 155
+#define T_LEQ 156
+#define T_EQ 157
+#define T_NEQ 158
+#define T_GEQ 159
+#define T_SHR 160
+#define T_SHL 161
+#define T_INCR 162
+#define T_DECR 163
+#define T_MUL 164
+#define T_DIV 165
+#define ID 166
+#define VAR 167
+#define CNUM 168
+#define CSTR 169
+#define EOI 170
+#define METHOD 171
Deleted: trunk/varnish-cache/lib/libvcl/vcl_fixed_token.c
===================================================================
--- trunk/varnish-cache/lib/libvcl/vcl_fixed_token.c 2006-07-21 16:25:24 UTC (rev 543)
+++ trunk/varnish-cache/lib/libvcl/vcl_fixed_token.c 2006-07-21 18:12:56 UTC (rev 544)
@@ -1,518 +0,0 @@
-/*
- * $Id$
- *
- * NB: This file is machine generated, DO NOT EDIT!
- *
- * Edit vcl_gen_fixed_token.tcl instead
- */
-
-#include <stdio.h>
-#include <ctype.h>
-#include "vcl_priv.h"
-
-unsigned
-vcl_fixed_token(const char *p, const char **q)
-{
-
- switch (p[0]) {
- case '!':
- if (p[0] == '!' && p[1] == '=') {
- *q = p + 2;
- return (T_NEQ);
- }
- if (p[0] == '!') {
- *q = p + 1;
- return ('!');
- }
- return (0);
- case '%':
- if (p[0] == '%') {
- *q = p + 1;
- return ('%');
- }
- return (0);
- case '&':
- if (p[0] == '&' && p[1] == '&') {
- *q = p + 2;
- return (T_CAND);
- }
- if (p[0] == '&') {
- *q = p + 1;
- return ('&');
- }
- return (0);
- case '(':
- if (p[0] == '(') {
- *q = p + 1;
- return ('(');
- }
- return (0);
- case ')':
- if (p[0] == ')') {
- *q = p + 1;
- return (')');
- }
- return (0);
- case '*':
- if (p[0] == '*' && p[1] == '=') {
- *q = p + 2;
- return (T_MUL);
- }
- if (p[0] == '*') {
- *q = p + 1;
- return ('*');
- }
- return (0);
- case '+':
- if (p[0] == '+' && p[1] == '=') {
- *q = p + 2;
- return (T_INCR);
- }
- if (p[0] == '+' && p[1] == '+') {
- *q = p + 2;
- return (T_INC);
- }
- if (p[0] == '+') {
- *q = p + 1;
- return ('+');
- }
- return (0);
- case ',':
- if (p[0] == ',') {
- *q = p + 1;
- return (',');
- }
- return (0);
- case '-':
- if (p[0] == '-' && p[1] == '-') {
- *q = p + 2;
- return (T_DEC);
- }
- if (p[0] == '-') {
- *q = p + 1;
- return ('-');
- }
- return (0);
- case '.':
- if (p[0] == '.') {
- *q = p + 1;
- return ('.');
- }
- return (0);
- case '/':
- if (p[0] == '/' && p[1] == '=') {
- *q = p + 2;
- return (T_DECR);
- }
- if (p[0] == '/' && p[1] == '=') {
- *q = p + 2;
- return (T_DIV);
- }
- if (p[0] == '/') {
- *q = p + 1;
- return ('/');
- }
- return (0);
- case ';':
- if (p[0] == ';') {
- *q = p + 1;
- return (';');
- }
- return (0);
- case '<':
- if (p[0] == '<' && p[1] == '=') {
- *q = p + 2;
- return (T_LEQ);
- }
- if (p[0] == '<' && p[1] == '<') {
- *q = p + 2;
- return (T_SHL);
- }
- if (p[0] == '<') {
- *q = p + 1;
- return ('<');
- }
- return (0);
- case '=':
- if (p[0] == '=' && p[1] == '=') {
- *q = p + 2;
- return (T_EQ);
- }
- if (p[0] == '=') {
- *q = p + 1;
- return ('=');
- }
- return (0);
- case '>':
- if (p[0] == '>' && p[1] == '>') {
- *q = p + 2;
- return (T_SHR);
- }
- if (p[0] == '>' && p[1] == '=') {
- *q = p + 2;
- return (T_GEQ);
- }
- if (p[0] == '>') {
- *q = p + 1;
- return ('>');
- }
- return (0);
- case 'a':
- if (p[0] == 'a' && p[1] == 'c' && p[2] == 'l'
- && !isvar(p[3])) {
- *q = p + 3;
- return (T_ACL);
- }
- return (0);
- case 'b':
- if (p[0] == 'b' && p[1] == 'a' && p[2] == 'c' &&
- p[3] == 'k' && p[4] == 'e' && p[5] == 'n' &&
- p[6] == 'd' && !isvar(p[7])) {
- *q = p + 7;
- return (T_BACKEND);
- }
- return (0);
- case 'c':
- if (p[0] == 'c' && p[1] == 'a' && p[2] == 'l' &&
- p[3] == 'l' && !isvar(p[4])) {
- *q = p + 4;
- return (T_CALL);
- }
- return (0);
- case 'd':
- if (p[0] == 'd' && p[1] == 'i' && p[2] == 's' &&
- p[3] == 'c' && p[4] == 'a' && p[5] == 'r' &&
- p[6] == 'd' && !isvar(p[7])) {
- *q = p + 7;
- return (T_DISCARD);
- }
- if (p[0] == 'd' && p[1] == 'e' && p[2] == 'l' &&
- p[3] == 'i' && p[4] == 'v' && p[5] == 'e' &&
- p[6] == 'r' && !isvar(p[7])) {
- *q = p + 7;
- return (T_DELIVER);
- }
- return (0);
- case 'e':
- if (p[0] == 'e' && p[1] == 'r' && p[2] == 'r' &&
- p[3] == 'o' && p[4] == 'r' && !isvar(p[5])) {
- *q = p + 5;
- return (T_ERROR);
- }
- if (p[0] == 'e' && p[1] == 'l' && p[2] == 's' &&
- p[3] == 'i' && p[4] == 'f' && !isvar(p[5])) {
- *q = p + 5;
- return (T_ELSIF);
- }
- if (p[0] == 'e' && p[1] == 'l' && p[2] == 's' &&
- p[3] == 'e' && p[4] == 'i' && p[5] == 'f'
- && !isvar(p[6])) {
- *q = p + 6;
- return (T_ELSEIF);
- }
- if (p[0] == 'e' && p[1] == 'l' && p[2] == 's' &&
- p[3] == 'e' && !isvar(p[4])) {
- *q = p + 4;
- return (T_ELSE);
- }
- return (0);
- case 'f':
- if (p[0] == 'f' && p[1] == 'u' && p[2] == 'n' &&
- p[3] == 'c' && !isvar(p[4])) {
- *q = p + 4;
- return (T_FUNC);
- }
- if (p[0] == 'f' && p[1] == 'e' && p[2] == 't' &&
- p[3] == 'c' && p[4] == 'h' && !isvar(p[5])) {
- *q = p + 5;
- return (T_FETCH);
- }
- return (0);
- case 'i':
- if (p[0] == 'i' && p[1] == 'n' && p[2] == 's' &&
- p[3] == 'e' && p[4] == 'r' && p[5] == 't' &&
- p[6] == '_' && p[7] == 'p' && p[8] == 'a' &&
- p[9] == 's' && p[10] == 's' && !isvar(p[11])) {
- *q = p + 11;
- return (T_INSERT_PASS);
- }
- if (p[0] == 'i' && p[1] == 'n' && p[2] == 's' &&
- p[3] == 'e' && p[4] == 'r' && p[5] == 't'
- && !isvar(p[6])) {
- *q = p + 6;
- return (T_INSERT);
- }
- if (p[0] == 'i' && p[1] == 'f' && !isvar(p[2])) {
- *q = p + 2;
- return (T_IF);
- }
- return (0);
- case 'l':
- if (p[0] == 'l' && p[1] == 'o' && p[2] == 'o' &&
- p[3] == 'k' && p[4] == 'u' && p[5] == 'p'
- && !isvar(p[6])) {
- *q = p + 6;
- return (T_LOOKUP);
- }
- return (0);
- case 'n':
- if (p[0] == 'n' && p[1] == 'o' && p[2] == '_' &&
- p[3] == 'n' && p[4] == 'e' && p[5] == 'w' &&
- p[6] == '_' && p[7] == 'c' && p[8] == 'a' &&
- p[9] == 'c' && p[10] == 'h' && p[11] == 'e'
- && !isvar(p[12])) {
- *q = p + 12;
- return (T_NO_NEW_CACHE);
- }
- if (p[0] == 'n' && p[1] == 'o' && p[2] == '_' &&
- p[3] == 'c' && p[4] == 'a' && p[5] == 'c' &&
- p[6] == 'h' && p[7] == 'e' && !isvar(p[8])) {
- *q = p + 8;
- return (T_NO_CACHE);
- }
- return (0);
- case 'p':
- if (p[0] == 'p' && p[1] == 'r' && p[2] == 'o' &&
- p[3] == 'c' && !isvar(p[4])) {
- *q = p + 4;
- return (T_PROC);
- }
- if (p[0] == 'p' && p[1] == 'i' && p[2] == 'p' &&
- p[3] == 'e' && !isvar(p[4])) {
- *q = p + 4;
- return (T_PIPE);
- }
- if (p[0] == 'p' && p[1] == 'a' && p[2] == 's' &&
- p[3] == 's' && !isvar(p[4])) {
- *q = p + 4;
- return (T_PASS);
- }
- return (0);
- case 'r':
- if (p[0] == 'r' && p[1] == 'e' && p[2] == 'w' &&
- p[3] == 'r' && p[4] == 'i' && p[5] == 't' &&
- p[6] == 'e' && !isvar(p[7])) {
- *q = p + 7;
- return (T_REWRITE);
- }
- return (0);
- case 's':
- if (p[0] == 's' && p[1] == 'w' && p[2] == 'i' &&
- p[3] == 't' && p[4] == 'c' && p[5] == 'h' &&
- p[6] == '_' && p[7] == 'c' && p[8] == 'o' &&
- p[9] == 'n' && p[10] == 'f' && p[11] == 'i' &&
- p[12] == 'g' && !isvar(p[13])) {
- *q = p + 13;
- return (T_SWITCH_CONFIG);
- }
- if (p[0] == 's' && p[1] == 'u' && p[2] == 'b'
- && !isvar(p[3])) {
- *q = p + 3;
- return (T_SUB);
- }
- if (p[0] == 's' && p[1] == 'e' && p[2] == 't'
- && !isvar(p[3])) {
- *q = p + 3;
- return (T_SET);
- }
- return (0);
- case '{':
- if (p[0] == '{') {
- *q = p + 1;
- return ('{');
- }
- return (0);
- case '|':
- if (p[0] == '|' && p[1] == '|') {
- *q = p + 2;
- return (T_COR);
- }
- if (p[0] == '|') {
- *q = p + 1;
- return ('|');
- }
- return (0);
- case '}':
- if (p[0] == '}') {
- *q = p + 1;
- return ('}');
- }
- return (0);
- case '~':
- if (p[0] == '~') {
- *q = p + 1;
- return ('~');
- }
- return (0);
- default:
- return (0);
- }
-}
-
-const char *vcl_tnames[256];
-
-void
-vcl_init_tnames(void)
-{
- vcl_tnames['!'] = "'!'";
- vcl_tnames['%'] = "'%'";
- vcl_tnames['&'] = "'&'";
- vcl_tnames['('] = "'('";
- vcl_tnames[')'] = "')'";
- vcl_tnames['*'] = "'*'";
- vcl_tnames['+'] = "'+'";
- vcl_tnames[','] = "','";
- vcl_tnames['-'] = "'-'";
- vcl_tnames['.'] = "'.'";
- vcl_tnames['/'] = "'/'";
- vcl_tnames['<'] = "'<'";
- vcl_tnames['='] = "'='";
- vcl_tnames['>'] = "'>'";
- vcl_tnames['{'] = "'{'";
- vcl_tnames['}'] = "'}'";
- vcl_tnames['|'] = "'|'";
- vcl_tnames['~'] = "'~'";
- vcl_tnames[';'] = "';'";
- vcl_tnames[CNUM] = "CNUM";
- vcl_tnames[CSTR] = "CSTR";
- vcl_tnames[EOI] = "EOI";
- vcl_tnames[ID] = "ID";
- vcl_tnames[METHOD] = "METHOD";
- vcl_tnames[T_ACL] = "acl";
- vcl_tnames[T_BACKEND] = "backend";
- vcl_tnames[T_CALL] = "call";
- vcl_tnames[T_CAND] = "&&";
- vcl_tnames[T_COR] = "||";
- vcl_tnames[T_DEC] = "--";
- vcl_tnames[T_DECR] = "/=";
- vcl_tnames[T_DELIVER] = "deliver";
- vcl_tnames[T_DISCARD] = "discard";
- vcl_tnames[T_DIV] = "/=";
- vcl_tnames[T_ELSE] = "else";
- vcl_tnames[T_ELSEIF] = "elseif";
- vcl_tnames[T_ELSIF] = "elsif";
- vcl_tnames[T_EQ] = "==";
- vcl_tnames[T_ERROR] = "error";
- vcl_tnames[T_FETCH] = "fetch";
- vcl_tnames[T_FUNC] = "func";
- vcl_tnames[T_GEQ] = ">=";
- vcl_tnames[T_IF] = "if";
- vcl_tnames[T_INC] = "++";
- vcl_tnames[T_INCR] = "+=";
- vcl_tnames[T_INSERT] = "insert";
- vcl_tnames[T_INSERT_PASS] = "insert_pass";
- vcl_tnames[T_LEQ] = "<=";
- vcl_tnames[T_LOOKUP] = "lookup";
- vcl_tnames[T_MUL] = "*=";
- vcl_tnames[T_NEQ] = "!=";
- vcl_tnames[T_NO_CACHE] = "no_cache";
- vcl_tnames[T_NO_NEW_CACHE] = "no_new_cache";
- vcl_tnames[T_PASS] = "pass";
- vcl_tnames[T_PIPE] = "pipe";
- vcl_tnames[T_PROC] = "proc";
- vcl_tnames[T_REWRITE] = "rewrite";
- vcl_tnames[T_SET] = "set";
- vcl_tnames[T_SHL] = "<<";
- vcl_tnames[T_SHR] = ">>";
- vcl_tnames[T_SUB] = "sub";
- vcl_tnames[T_SWITCH_CONFIG] = "switch_config";
- vcl_tnames[VAR] = "VAR";
-}
-
-void
-vcl_output_lang_h(FILE *f)
-{
- fputs("#define VCL_RET_ERROR (1 << 0)\n", f);
- fputs("#define VCL_RET_LOOKUP (1 << 1)\n", f);
- fputs("#define VCL_RET_PIPE (1 << 2)\n", f);
- fputs("#define VCL_RET_PASS (1 << 3)\n", f);
- fputs("#define VCL_RET_INSERT_PASS (1 << 4)\n", f);
- fputs("#define VCL_RET_FETCH (1 << 5)\n", f);
- fputs("#define VCL_RET_INSERT (1 << 6)\n", f);
- fputs("#define VCL_RET_DELIVER (1 << 7)\n", f);
- fputs("#define VCL_RET_DISCARD (1 << 8)\n", f);
- fputs("/*\n", f);
- fputs(" * $Id$\n", f);
- fputs(" *\n", f);
- fputs(" * NB: This file is machine generated, DO NOT EDIT!\n", f);
- fputs(" *\n", f);
- fputs(" * Edit vcl_gen_fixed_token.tcl instead\n", f);
- fputs(" */\n", f);
- fputs("\n", f);
- fputs("struct sess;\n", f);
- fputs("\n", f);
- fputs("typedef void vcl_init_f(void);\n", f);
- fputs("typedef int vcl_func_f(struct sess *sp);\n", f);
- fputs("\n", f);
- fputs("struct VCL_conf {\n", f);
- fputs(" unsigned magic;\n", f);
- fputs("#define VCL_CONF_MAGIC 0x7406c509 /* from /dev/random */\n", f);
- fputs("\n", f);
- fputs(" struct backend **backend;\n", f);
- fputs(" unsigned nbackend;\n", f);
- fputs(" struct vrt_ref *ref;\n", f);
- fputs(" unsigned nref;\n", f);
- fputs(" unsigned busy;\n", f);
- fputs("\n", f);
- fputs(" vcl_init_f *init_func;\n", f);
- fputs("\n", f);
- fputs(" vcl_func_f *recv_func;\n", f);
- fputs(" vcl_func_f *miss_func;\n", f);
- fputs(" vcl_func_f *hit_func;\n", f);
- fputs(" vcl_func_f *fetch_func;\n", f);
- fputs(" vcl_func_f *timeout_func;\n", f);
- fputs("};\n", f);
- fputs("/*\n", f);
- fputs(" * $Id$ \n", f);
- fputs(" *\n", f);
- fputs(" * Runtime support for compiled VCL programs.\n", f);
- fputs(" *\n", f);
- fputs(" * XXX: When this file is changed, lib/libvcl/vcl_gen_fixed_token.tcl\n", f);
- fputs(" * XXX: *MUST* be rerun.\n", f);
- fputs(" */\n", f);
- fputs("\n", f);
- fputs("struct sess;\n", f);
- fputs("struct backend;\n", f);
- fputs("struct VCL_conf;\n", f);
- fputs("\n", f);
- fputs("struct vrt_ref {\n", f);
- fputs(" unsigned line;\n", f);
- fputs(" unsigned pos;\n", f);
- fputs(" unsigned count;\n", f);
- fputs(" const char *token;\n", f);
- fputs("};\n", f);
- fputs("\n", f);
- fputs("struct vrt_acl {\n", f);
- fputs(" unsigned ip;\n", f);
- fputs(" unsigned mask;\n", f);
- fputs("};\n", f);
- fputs("\n", f);
- fputs("void VRT_count(struct sess *, unsigned);\n", f);
- fputs("void VRT_no_cache(struct sess *);\n", f);
- fputs("void VRT_no_new_cache(struct sess *);\n", f);
- fputs("#if 0\n", f);
- fputs("int ip_match(unsigned, struct vcl_acl *);\n", f);
- fputs("int string_match(const char *, const char *);\n", f);
- fputs("#endif\n", f);
- fputs("int VRT_rewrite(const char *, const char *);\n", f);
- fputs("void VRT_error(struct sess *, unsigned, const char *);\n", f);
- fputs("int VRT_switch_config(const char *);\n", f);
- fputs("\n", f);
- fputs("char *VRT_GetHdr(struct sess *, const char *);\n", f);
- fputs("char *VRT_GetReq(struct sess *);\n", f);
- fputs("void VRT_handling(struct sess *sp, unsigned hand);\n", f);
- fputs("int VRT_obj_valid(struct sess *);\n", f);
- fputs("int VRT_obj_cacheable(struct sess *);\n", f);
- fputs("\n", f);
- fputs("void VRT_set_backend_name(struct backend *, const char *);\n", f);
- fputs("void VRT_set_backend_hostname(struct backend *, const char *);\n", f);
- fputs("void VRT_set_backend_portname(struct backend *, const char *);\n", f);
- fputs("\n", f);
- fputs("void VRT_alloc_backends(struct VCL_conf *cp);\n", f);
- fputs("\n", f);
- fputs("#define VRT_done(sp, hand) \\\n", f);
- fputs(" do { \\\n", f);
- fputs(" VRT_handling(sp, hand); \\\n", f);
- fputs(" return (1); \\\n", f);
- fputs(" } while (0)\n", f);
-}
Deleted: trunk/varnish-cache/lib/libvcl/vcl_gen_fixed_token.tcl
===================================================================
--- trunk/varnish-cache/lib/libvcl/vcl_gen_fixed_token.tcl 2006-07-21 16:25:24 UTC (rev 543)
+++ trunk/varnish-cache/lib/libvcl/vcl_gen_fixed_token.tcl 2006-07-21 18:12:56 UTC (rev 544)
@@ -1,319 +0,0 @@
-#!/usr/local/bin/tclsh8.4
-#
-# Generate various .c and .h files for the VCL compiler and the interfaces
-# for it.
-
-# These are the metods which can be called in the VCL program.
-# Second element is list of valid return actions.
-#
-set methods {
- {recv {error pass pipe lookup}}
- {miss {error pass pipe fetch}}
- {hit {error pass pipe deliver}}
- {fetch {error pass pipe insert insert_pass}}
- {timeout {fetch discard}}
-}
-
-# These are the return actions
-#
-set returns {
- error
- lookup
- pipe
- pass
- insert_pass
- fetch
- insert
- deliver
- discard
-}
-
-# Language keywords
-#
-set keywords {
- if else elseif elsif
-
- func proc sub
-
- acl
-
- backend
-
- call
- no_cache
- no_new_cache
- set
- rewrite
- switch_config
-}
-
-# Non-word tokens
-#
-set magic {
- {"++" INC}
- {"--" DEC}
- {"&&" CAND}
- {"||" COR}
- {"<=" LEQ}
- {"==" EQ}
- {"!=" NEQ}
- {">=" GEQ}
- {">>" SHR}
- {"<<" SHL}
- {"+=" INCR}
- {"/=" DECR}
- {"*=" MUL}
- {"/=" DIV}
-}
-
-# Single char tokens
-#
-set char {{}()*+-/%><=;!&.|~,}
-
-# Other token identifiers
-#
-set extras {ID VAR CNUM CSTR EOI METHOD}
-
-#----------------------------------------------------------------------
-# Boilerplate warning for all generated files.
-
-proc warns {fd} {
-
- puts $fd "/*"
- puts $fd { * $Id$}
- puts $fd " *"
- puts $fd " * NB: This file is machine generated, DO NOT EDIT!"
- puts $fd " *"
- puts $fd " * Edit vcl_gen_fixed_token.tcl instead"
- puts $fd " */"
- puts $fd ""
-}
-
-#----------------------------------------------------------------------
-# Build the vcl.h #include file
-
-set fo [open ../../include/vcl.h w]
-warns $fo
-puts $fo {struct sess;
-
-typedef void vcl_init_f(void);
-typedef int vcl_func_f(struct sess *sp);
-}
-puts $fo "struct VCL_conf {"
-puts $fo { unsigned magic;
-#define VCL_CONF_MAGIC 0x7406c509 /* from /dev/random */
-
- struct backend **backend;
- unsigned nbackend;
- struct vrt_ref *ref;
- unsigned nref;
- unsigned busy;
-
- vcl_init_f *init_func;
-}
-foreach m $methods {
- puts $fo "\tvcl_func_f\t*[lindex $m 0]_func;"
-}
-puts $fo "};"
-
-close $fo
-
-#----------------------------------------------------------------------
-# Build the vcl_returns.h #include file
-
-set for [open "../../include/vcl_returns.h" w]
-warns $for
-puts $for "#ifdef VCL_RET_MAC"
-set i 0
-foreach k $returns {
- if {$k == "error"} {
- puts $for "#ifdef VCL_RET_MAC_E"
- puts $for "VCL_RET_MAC_E($k, [string toupper $k], $i)"
- puts $for "#endif"
- } else {
- puts $for "VCL_RET_MAC($k, [string toupper $k], (1 << $i))"
- }
- incr i
-}
-puts $for "#else"
-set i 0
-foreach k $returns {
- puts $for "#define VCL_RET_[string toupper $k] (1 << $i)"
- incr i
-}
-puts $for "#define VCL_RET_MAX $i"
-puts $for "#endif"
-puts $for ""
-puts $for "#ifdef VCL_MET_MAC"
-foreach m $methods {
- puts -nonewline $for "VCL_MET_MAC([lindex $m 0]"
- puts -nonewline $for ",[string toupper [lindex $m 0]]"
- set l [lindex $m 1]
- puts -nonewline $for ",(VCL_RET_[string toupper [lindex $l 0]]"
- foreach r [lrange $l 1 end] {
- puts -nonewline $for "|VCL_RET_[string toupper $r]"
- }
- puts -nonewline $for ")"
- puts $for ")"
-}
-puts $for "#endif"
-close $for
-
-#----------------------------------------------------------------------
-# Build the compiler token table and recognizers
-
-set fo [open "vcl_fixed_token.c" w]
-warns $fo
-
-set foh [open "vcl_token_defs.h" w]
-warns $foh
-
-puts $fo "#include <stdio.h>"
-puts $fo "#include <ctype.h>"
-puts $fo "#include \"vcl_priv.h\""
-
-set tn 128
-puts $foh "#define LOW_TOKEN $tn"
-
-
-proc add_token {tok str alpha} {
- global tokens tn fixed foh
-
- lappend tokens [list $tok $str]
- puts $foh "#define $tok $tn"
- incr tn
- lappend fixed [list $str $tok $alpha]
-}
-
-proc mk_token {tok str alpha} {
- set tok T_[string toupper $tok]
- add_token $tok $str $alpha
-}
-
-foreach k $keywords { mk_token $k $k 1 }
-foreach k $returns { mk_token $k $k 1 }
-foreach k $magic { mk_token [lindex $k 1] [lindex $k 0] 0 }
-foreach k $extras {
- set t [string toupper $k]
- lappend tokens [list $t $t]
- puts $foh "#define [string toupper $k] $tn"
- incr tn
-}
-for {set i 0} {$i < [string length $char]} {incr i} {
- set t [string index $char $i]
- lappend token2 [list '$t' T$t]
- lappend fixed [list "$t" '$t' 0]
-}
-
-set tokens [lsort $tokens]
-set token2 [lsort $token2]
-
-# We want to output in ascii order: create sorted first char list
-foreach t $fixed {
- set xx([string index [lindex $t 0] 0]) 1
-}
-set seq [lsort [array names xx]]
-
-set ll 0
-
-puts $fo {
-unsigned
-vcl_fixed_token(const char *p, const char **q)}
-puts $fo "{"
-puts $fo ""
-puts $fo " switch (p\[0\]) {"
-
-foreach ch "$seq" {
- # Now find all tokens starting with ch
- set l ""
- foreach t $fixed {
- if {[string index [lindex $t 0] 0] == $ch} {
- lappend l $t
- }
- }
- # And do then in reverse order to match longest first
- set l [lsort -index 0 -decreasing $l]
- scan "$ch" "%c" cx
- if {$cx != $ll} {
- if {$ll} {
- puts $fo " return (0);"
- }
-
- puts $fo " case '$ch':"
- set ll $cx
- }
- foreach tt $l {
- set k [lindex $tt 0]
- puts -nonewline $fo " if ("
- for {set i 0} {$i < [string length $k]} {incr i} {
- if {$i > 0} {
- puts -nonewline $fo " && "
- if {![expr $i % 3]} {
- puts -nonewline $fo "\n\t\t "
- }
- }
- puts -nonewline $fo "p\[$i\] == '[string index $k $i]'"
- }
- if {[lindex $tt 2]} {
- if {![expr $i % 3]} {
- puts -nonewline $fo "\n\t\t "
- }
- puts -nonewline $fo " && !isvar(p\[$i\])"
- }
- puts $fo ") {"
- puts $fo " *q = p + [string length $k];"
- puts $fo " return ([lindex $tt 1]);"
- puts $fo " }"
- }
-}
-puts $fo " return (0);"
-puts $fo " default:"
-puts $fo " return (0);"
-puts $fo " }"
-puts $fo "}"
-
-puts $fo ""
-puts $fo "const char *vcl_tnames\[256\];\n"
-puts $fo "void"
-puts $fo "vcl_init_tnames(void)"
-puts $fo "{"
-foreach i $token2 {
- puts $fo "\tvcl_tnames\[[lindex $i 0]\] = \"[lindex $i 0]\";"
-}
-foreach i $tokens {
- puts $fo "\tvcl_tnames\[[lindex $i 0]\] = \"[lindex $i 1]\";"
-}
-puts $fo "}"
-
-#----------------------------------------------------------------------
-# Create the C-code which emits the boilerplate definitions for the
-# generated C code output
-
-proc copy_include {n} {
- global fo
-
- set fi [open $n]
- while {[gets $fi a] >= 0} {
- regsub -all {\\} $a {\\\\} a
- puts $fo "\tfputs(\"$a\\n\", f);"
- }
- close $fi
-}
-
-puts $fo ""
-puts $fo "void"
-puts $fo "vcl_output_lang_h(FILE *f)"
-puts $fo "{"
-set i 0
-foreach k $returns {
- puts $fo "\tfputs(\"#define VCL_RET_[string toupper $k] (1 << $i)\\n\", f);"
- incr i
-}
-
-copy_include ../../include/vcl.h
-copy_include ../../include/vrt.h
-
-puts $fo "}"
-
-close $foh
-close $fo
Deleted: trunk/varnish-cache/lib/libvcl/vcl_priv.h
===================================================================
--- trunk/varnish-cache/lib/libvcl/vcl_priv.h 2006-07-21 16:25:24 UTC (rev 543)
+++ trunk/varnish-cache/lib/libvcl/vcl_priv.h 2006-07-21 18:12:56 UTC (rev 544)
@@ -1,13 +0,0 @@
-/*
- * Stuff shared between main.c and fixed_token.c
- */
-
-#include "vcl_token_defs.h"
-
-#define isident1(c) (isalpha(c))
-#define isident(c) (isalpha(c) || isdigit(c) || (c) == '_')
-#define isvar(c) (isident(c) || (c) == '.')
-unsigned vcl_fixed_token(const char *p, const char **q);
-extern const char *vcl_tnames[256];
-void vcl_init_tnames(void);
-void vcl_output_lang_h(FILE *f);
Deleted: trunk/varnish-cache/lib/libvcl/vcl_token_defs.h
===================================================================
--- trunk/varnish-cache/lib/libvcl/vcl_token_defs.h 2006-07-21 16:25:24 UTC (rev 543)
+++ trunk/varnish-cache/lib/libvcl/vcl_token_defs.h 2006-07-21 18:12:56 UTC (rev 544)
@@ -1,53 +0,0 @@
-/*
- * $Id$
- *
- * NB: This file is machine generated, DO NOT EDIT!
- *
- * Edit vcl_gen_fixed_token.tcl instead
- */
-
-#define LOW_TOKEN 128
-#define T_IF 128
-#define T_ELSE 129
-#define T_ELSEIF 130
-#define T_ELSIF 131
-#define T_FUNC 132
-#define T_PROC 133
-#define T_SUB 134
-#define T_ACL 135
-#define T_BACKEND 136
-#define T_CALL 137
-#define T_NO_CACHE 138
-#define T_NO_NEW_CACHE 139
-#define T_SET 140
-#define T_REWRITE 141
-#define T_SWITCH_CONFIG 142
-#define T_ERROR 143
-#define T_LOOKUP 144
-#define T_PIPE 145
-#define T_PASS 146
-#define T_INSERT_PASS 147
-#define T_FETCH 148
-#define T_INSERT 149
-#define T_DELIVER 150
-#define T_DISCARD 151
-#define T_INC 152
-#define T_DEC 153
-#define T_CAND 154
-#define T_COR 155
-#define T_LEQ 156
-#define T_EQ 157
-#define T_NEQ 158
-#define T_GEQ 159
-#define T_SHR 160
-#define T_SHL 161
-#define T_INCR 162
-#define T_DECR 163
-#define T_MUL 164
-#define T_DIV 165
-#define ID 166
-#define VAR 167
-#define CNUM 168
-#define CSTR 169
-#define EOI 170
-#define METHOD 171
More information about the varnish-commit
mailing list